18. return 0; 19. } 20.
21. //一般会执行到这里
22. if ((s->iformat && s->iformat->flags & AVFMT_NOFILE)
23. || (!s->iformat && (s->iformat = av_probe_input_format(&pd, 0)))
)
24. //如果已指定了iformat并且不需要文件,也就不需要pb了,可以直接返回 25. //如果没指定iformat,但是可以从文件名中猜出iformat,也成功. 26. return 0; 27.
28. //如果从文件名中也猜不出媒体格式,则只能打开这个文件进行探测了,先打开文件 29. if ((ret = avio_open(&s->pb, filename, AVIO_FLAG_READ)) < 0) 30. return ret; 31. if (s->iformat) 32. return 0; 33. //再探测之
34. return av_probe_input_buffer(s->pb, &s->iformat, filename, s, 0, 0); 35. }
avio_open
[cpp] view plaincopy
1. //打开一个地址指向的媒体
2. int avio_open(AVIOContext **s, const char *filename, int flags) 3. {
4. //URLContext代表一个URL地址指向的媒体文件,本地路径也算一种.它封装了 5. //操作一个媒体文件的相关数据,最重要的是prot变量,是URLProtocol型的. 6. //prot代表一个特定的协义和协议操作函数们,URLContext包含不同的prot, 7. //就可以通过URLContext使用不同的协议读写媒体数据,比如tcp,http,本地 8. //文件用file协议. 9. URLContext *h; 10. int err; 11.
12. //创建并初始化URLContext,其prot通过文件名确定.然后打开这个媒体文件 13. err = ffurl_open(&h, filename, flags); 14. if (err < 0) 15. return err;
16. //其实文件已经在上边真正打开了.这里只是填充AVIOContext.使它记录下 17. //URLContext,以及填充读写数据的函数指针. 18. err = ffio_fdopen(s, h); 19. if (err < 0) {
20. ffurl_close(h); 21. return err; 22. }
23. return 0; 24. }
av_probe_input_buffer
[cpp] view plaincopy
1. int av_probe_input_buffer(AVIOContext *pb, 2. AVInputFormat **fmt, 3. const char *filename, 4. void *logctx, 5. unsigned int offset,
6. unsigned int max_probe_size) 7. {
8. AVProbeData pd = { filename ? filename : \, NULL, -offset }; 9. unsigned char *buf = NULL; 10. int ret = 0, probe_size; 11.
12. //计算最多探测数据的字节数 13. if (!max_probe_size) {
14. max_probe_size = PROBE_BUF_MAX;
15. } else if (max_probe_size > PROBE_BUF_MAX) { 16. max_probe_size = PROBE_BUF_MAX;
17. } else if (max_probe_size < PROBE_BUF_MIN) { 18. return AVERROR(EINVAL); 19. } 20.
21. if (offset >= max_probe_size) { 22. return AVERROR(EINVAL); 23. } 24.
25. //循环直到探测完指定的数据
26. for (probe_size = PROBE_BUF_MIN;
27. probe_size <= max_probe_size && !*fmt; 28. probe_size =
29. FFMIN(probe_size<<1, FFMAX(max_probe_size, probe_size+1)
)) {
30. int score = probe_size < max_probe_size ? AVPROBE_SCORE_MAX / 4 : 0;
31. int buf_offset = (probe_size == PROBE_BUF_MIN) ? 0 : probe_size >> 1
;
32. void *buftmp; 33.
34. if (probe_size < offset) { 35. continue; 36. } 37.
38. /* read probe data */ 39. //分配读取数据存放的缓冲
40. buftmp = av_realloc(buf, probe_size + AVPROBE_PADDING_SIZE); 41. if (!buftmp) { 42. av_free(buf);
43. return AVERROR(ENOMEM); 44. }
45. buf = buftmp;
46. //利用pb读数据到缓冲的剩余空间中
47. if ((ret = avio_read(pb, buf + buf_offset, probe_size - buf_offset))
48. < 0) {
49. /* fail if error was not end of file, otherwise, lower score */
50. if (ret != AVERROR_EOF) { 51. av_free(buf); 52. return ret; 53. }
54. score = 0;
55. ret = 0; /* error was end of file, nothing read */ 56. }
57. pd.buf_size += ret; 58. pd.buf = &buf[offset]; 59.
60. //缓冲中没有数据的部分要清0
61. memset(pd.buf + pd.buf_size, 0, AVPROBE_PADDING_SIZE); 62.
63. /* guess file format */ 64. //从一个打开的文件只探测媒体格式
65. *fmt = av_probe_input_format2(&pd, 1, &score); 66. if (*fmt) {
67. if (score <= AVPROBE_SCORE_MAX / 4) { //this can only be true in
the last iteration 68. av_log(
69. logctx,
70. AV_LOG_WARNING,
71. \
tection possible!\\n\,
72. (*fmt)->name, score); 73. } else
74. av_log(logctx, AV_LOG_DEBUG,
75. \, 76. (*fmt)->name, probe_size, score); 77. }
78. //不成功,继续 79. } 80.
81. if (!*fmt) { 82. av_free(buf);
83. return AVERROR_INVALIDDATA; 84. } 85.
86. /* rewind. reuse probe buffer to avoid seeking */ 87. //把探测时读入的数据保存到pb中,为的是真正读时直接利用之.
88. if ((ret = ffio_rewind_with_probe_data(pb, buf, pd.buf_size)) < 0) 89. av_free(buf); 90.
91. return ret; 92. }
7.获取流信息
int videoStreamIndex = 0;
for (; videoStreamIndex < pFormatCtx->nb_streams; ++videoStreamIndex) { }
if (videoStreamIndex == pFormatCtx->nb_streams) { }
//没有找到视频流 abort();
if (pFormatCtx->streams[videoStreamIndex]->codec->coder_type == { }
break;
AVMEDIA_TYPE_VIDEO)
8.解码视频
AVCodecContext *pCodeCtx =
pFormatCtx->streams[videoStreamIndex]->codec;
//获?取¨?解a码?器??
AVCodec * pCodec = avcodec_find_decoder(pCodeCtx->codec_id); if (pCodec == NULL) { }
if (pCodec->capabilities & CODEC_CAP_TRUNCATED) { }
if (avcodec_open2(pCodeCtx,pCodec,NULL)<0) { }
//给解码后视频帧预分配存储空间? AVFrame *pFrame = NULL;
pFrame = avcodec_alloc_frame(); //预分配存储空间用来存储转换后的帧? AVFrame *pFrameRGB = NULL;
pFrameRGB = avcodec_alloc_frame();
int numBytes = avpicture_get_size(PIX_FMT_RGB24,
abort();
pCodeCtx->flags |= CODEC_FLAG_TRUNCATED; abort();
pCodeCtx->width,pCodeCtx->height);
//指向的内存关联起来
uint8_t *buffer = (uint8_t*)av_malloc(numBytes); avpicture_fill( (AVPicture *)pFrameRGB, buffer,
PIX_FMT_RGB24,pCodeCtx->width, pCodeCtx->height);
AVPacket pPacket; int num = 0;
char *fileEx = \;
while(av_read_frame(pFormatCtx,&pPacket)>=0) {
//判断是否为视频流
if (pPacket.stream_index == videoStreamIndex) {
int decFinished;
avcodec_decode_video2(pCodeCtx,pFrame,&decFinished,&pPacket); if (decFinished) {
struct SwsContext * img_convert_ctx = NULL;