FFMPEG源码分析之媒体打开过程

avformat_open_input

  1. //参数ps包含一切媒体相关的上下文结构,有它就有了一切,本函数如果打开媒体成功,
  2. //会返回一个AVFormatContext的实例.
  3. //参数filename是媒体文件名或URL.
  4. //参数fmt是要打开的媒体格式的操作结构,因为是读,所以是inputFormat.此处可以
  5. //传入一个调用者定义的inputFormat,对应命令行中的-fxxx段,如果指定了它,
  6. //在打开文件中就不会探测文件的实际格式了,以它为准了.
  7. //参数options是对某种格式的一些操作,是为了在命令行中可以对不同的格式传入
  8. //特殊的操作参数而建的,为了了解流程,完全可以无视它.
  9. intavformat_open_input(AVFormatContext**ps,
  10. constchar*filename,
  11. AVInputFormat*fmt,
  12. AVDictionary**options)
  13. {
  14. AVFormatContext*s=*ps;
  15. intret=0;
  16. AVFormatParametersap={{0}};
  17. AVDictionary*tmp=NULL;
  18. //创建上下文结构
  19. if(!s&&!(s=avformat_alloc_context()))
  20. returnAVERROR(ENOMEM);
  21. //如果用户指定了输入格式,直接使用它
  22. if(fmt)
  23. s->iformat=fmt;
  24. //忽略
  25. if(options)
  26. av_dict_copy(&tmp,*options,0);
  27. if((ret=av_opt_set_dict(s,&tmp))<0)
  28. gotofail;
  29. //打开输入媒体(如果需要的话),初始化所有与媒体读写有关的结构们,比如
  30. //AVIOContext,AVInputFormat等等
  31. if((ret=init_input(s,filename))<0)
  32. gotofail;
  33. //执行完此函数后,s->pb和s->iformat都已经指向了有效实例.pb是用于读写数据的,它
  34. //把媒体数据当做流来读写,不管是什么媒体格式,而iformat把pb读出来的流按某种媒体格
  35. //式进行分析,也就是说pb在底层,iformat在上层.
  36. //很多静态图像文件格式,都被当作一个格式处理,比如要打开.jpeg文件,需要的格式
  37. //名为image2.此处还不是很了解具体细节,作不得准哦.
  38. /*checkfilenameincaseanimagenumberisexpected*/
  39. if(s->iformat->flags&AVFMT_NEEDNUMBER){
  40. if(!av_filename_number_test(filename)){
  41. ret=AVERROR(EINVAL);
  42. gotofail;
  43. }
  44. }
  45. s->duration=s->start_time=AV_NOPTS_VALUE;
  46. //上下文中保存下文件名
  47. av_strlcpy(s->filename,filename,sizeof(s->filename));
  48. /*allocateprivatedata*/
  49. //为当前格式分配私有数据,主要用于某格式的读写操作时所用的私有结构.
  50. //此结构的大小在定义AVInputFormat时已指定了.
  51. if(s->iformat->priv_data_size>0){
  52. if(!(s->priv_data=av_mallocz(s->iformat->priv_data_size))){
  53. ret=AVERROR(ENOMEM);
  54. gotofail;
  55. }
  56. //这个可以先不必管它
  57. if(s->iformat->priv_class){
  58. *(constAVClass**)s->priv_data=s->iformat->priv_class;
  59. av_opt_set_defaults(s->priv_data);
  60. if((ret=av_opt_set_dict(s->priv_data,&tmp))<0)
  61. gotofail;
  62. }
  63. }
  64. /*e.g.AVFMT_NOFILEformatswillnothaveaAVIOContext*/
  65. //从mp3文件中读ID3数据并保存之.
  66. if(s->pb)
  67. ff_id3v2_read(s,ID3v2_DEFAULT_MAGIC);
  68. //读一下媒体的头部,在read_header()中主要是做某种格式的初始化工作,比如填充自己的
  69. //私有结构,根据流的数量分配流结构并初始化,把文件指针指向数据区开始处等.
  70. if(!(s->flags&AVFMT_FLAG_PRIV_OPT)&&s->iformat->read_header)
  71. if((ret=s->iformat->read_header(s,&ap))<0)
  72. gotofail;
  73. //保存数据区开始的位置
  74. if(!(s->flags&AVFMT_FLAG_PRIV_OPT)&&s->pb&&!s->data_offset)
  75. s->data_offset=avio_tell(s->pb);
  76. s->raw_packet_buffer_remaining_size=RAW_PACKET_BUFFER_SIZE;
  77. if(options){
  78. av_dict_free(options);
  79. *options=tmp;
  80. }
  81. *ps=s;
  82. //执行成功
  83. return0;
  84. //执行失败
  85. fail:av_dict_free(&tmp);
  86. if(s->pb&&!(s->flags&AVFMT_FLAG_CUSTOM_IO))
  87. avio_close(s->pb);
  88. avformat_free_context(s);
  89. *ps=NULL;
  90. returnret;
  91. }

init_input

  1. //打开输入媒体并填充其AVInputFormat结构
  2. staticintinit_input(AVFormatContext*s,constchar*filename)
  3. {
  4. intret;
  5. AVProbeDatapd={filename,NULL,0};
  6. //当调用者已指定了pb(数据取得的方式)--一般不会这样.
  7. if(s->pb){
  8. s->flags|=AVFMT_FLAG_CUSTOM_IO;
  9. if(!s->iformat)
  10. //如果已指定了pb但没指定iformat,以pb读取媒体数据进行探测,取得.取得iformat.
  11. returnav_probe_input_buffer(s->pb,&s->iformat,filename,s,0,0);
  12. elseif(s->iformat->flags&AVFMT_NOFILE)
  13. //如果已指定pb也指定了iformat,但是又指定了不需要文件(也包括URL指定的地址),这就矛盾了,
  14. //此时应是不需要pb的,因为不需操作文件,提示一下吧,也不算错.
  15. av_log(s,AV_LOG_WARNING,"CustomAVIOContextmakesnosenseand"
  16. "willbeignoredwithAVFMT_NOFILEformat.\n");
  17. return0;
  18. }
  19. //一般会执行到这里
  20. if((s->iformat&&s->iformat->flags&AVFMT_NOFILE)
  21. ||(!s->iformat&&(s->iformat=av_probe_input_format(&pd,0))))
  22. //如果已指定了iformat并且不需要文件,也就不需要pb了,可以直接返回
  23. //如果没指定iformat,但是可以从文件名中猜出iformat,也成功.
  24. return0;
  25. //如果从文件名中也猜不出媒体格式,则只能打开这个文件进行探测了,先打开文件
  26. if((ret=avio_open(&s->pb,filename,AVIO_FLAG_READ))<0)
  27. returnret;
  28. if(s->iformat)
  29. return0;
  30. //再探测之
  31. returnav_probe_input_buffer(s->pb,&s->iformat,filename,s,0,0);
  32. }


avio_open

  1. //打开一个地址指向的媒体
  2. intavio_open(AVIOContext**s,constchar*filename,intflags)
  3. {
  4. //URLContext代表一个URL地址指向的媒体文件,本地路径也算一种.它封装了
  5. //操作一个媒体文件的相关数据,最重要的是prot变量,是URLProtocol型的.
  6. //prot代表一个特定的协义和协议操作函数们,URLContext包含不同的prot,
  7. //就可以通过URLContext使用不同的协议读写媒体数据,比如tcp,http,本地
  8. //文件用file协议.
  9. URLContext*h;
  10. interr;
  11. //创建并初始化URLContext,其prot通过文件名确定.然后打开这个媒体文件
  12. err=ffurl_open(&h,filename,flags);
  13. if(err<0)
  14. returnerr;
  15. //其实文件已经在上边真正打开了.这里只是填充AVIOContext.使它记录下
  16. //URLContext,以及填充读写数据的函数指针.
  17. err=ffio_fdopen(s,h);
  18. if(err<0){
  19. ffurl_close(h);
  20. returnerr;
  21. }
  22. return0;
  23. }


av_probe_input_buffer

  1. intav_probe_input_buffer(AVIOContext*pb,
  2. AVInputFormat**fmt,
  3. constchar*filename,
  4. void*logctx,
  5. unsignedintoffset,
  6. unsignedintmax_probe_size)
  7. {
  8. AVProbeDatapd={filename?filename:"",NULL,-offset};
  9. unsignedchar*buf=NULL;
  10. intret=0,probe_size;
  11. //计算最多探测数据的字节数
  12. if(!max_probe_size){
  13. max_probe_size=PROBE_BUF_MAX;
  14. }elseif(max_probe_size>PROBE_BUF_MAX){
  15. max_probe_size=PROBE_BUF_MAX;
  16. }elseif(max_probe_size<PROBE_BUF_MIN){
  17. returnAVERROR(EINVAL);
  18. }
  19. if(offset>=max_probe_size){
  20. returnAVERROR(EINVAL);
  21. }
  22. //循环直到探测完指定的数据
  23. for(probe_size=PROBE_BUF_MIN;
  24. probe_size<=max_probe_size&&!*fmt;
  25. probe_size=
  26. FFMIN(probe_size<<1,FFMAX(max_probe_size,probe_size+1))){
  27. intscore=probe_size<max_probe_size?AVPROBE_SCORE_MAX/4:0;
  28. intbuf_offset=(probe_size==PROBE_BUF_MIN)?0:probe_size>>1;
  29. void*buftmp;
  30. if(probe_size<offset){
  31. continue;
  32. }
  33. /*readprobedata*/
  34. //分配读取数据存放的缓冲
  35. buftmp=av_realloc(buf,probe_size+AVPROBE_PADDING_SIZE);
  36. if(!buftmp){
  37. av_free(buf);
  38. returnAVERROR(ENOMEM);
  39. }
  40. buf=buftmp;
  41. //利用pb读数据到缓冲的剩余空间中
  42. if((ret=avio_read(pb,buf+buf_offset,probe_size-buf_offset))
  43. <0){
  44. /*failiferrorwasnotendoffile,otherwise,lowerscore*/
  45. if(ret!=AVERROR_EOF){
  46. av_free(buf);
  47. returnret;
  48. }
  49. score=0;
  50. ret=0;/*errorwasendoffile,nothingread*/
  51. }
  52. pd.buf_size+=ret;
  53. pd.buf=&buf[offset];
  54. //缓冲中没有数据的部分要清0
  55. memset(pd.buf+pd.buf_size,0,AVPROBE_PADDING_SIZE);
  56. /*guessfileformat*/
  57. //从一个打开的文件只探测媒体格式
  58. *fmt=av_probe_input_format2(&pd,1,&score);
  59. if(*fmt){
  60. if(score<=AVPROBE_SCORE_MAX/4){//thiscanonlybetrueinthelastiteration
  61. av_log(
  62. logctx,
  63. AV_LOG_WARNING,
  64. "Format%sdetectedonlywithlowscoreof%d,misdetectionpossible!\n",
  65. (*fmt)->name,score);
  66. }else
  67. av_log(logctx,AV_LOG_DEBUG,
  68. "Format%sprobedwithsize=%dandscore=%d\n",
  69. (*fmt)->name,probe_size,score);
  70. }
  71. //不成功,继续
  72. }
  73. if(!*fmt){
  74. av_free(buf);
  75. returnAVERROR_INVALIDDATA;
  76. }
  77. /*rewind.reuseprobebuffertoavoidseeking*/
  78. //把探测时读入的数据保存到pb中,为的是真正读时直接利用之.
  79. if((ret=ffio_rewind_with_probe_data(pb,buf,pd.buf_size))<0)
  80. av_free(buf);
  81. returnret;
  82. }

原文地址:http://wodamazi.iteye.com/blog/1293994

avformat_open_input

  1. //参数ps包含一切媒体相关的上下文结构,有它就有了一切,本函数如果打开媒体成功,
  2. //会返回一个AVFormatContext的实例.
  3. //参数filename是媒体文件名或URL.
  4. //参数fmt是要打开的媒体格式的操作结构,因为是读,所以是inputFormat.此处可以
  5. //传入一个调用者定义的inputFormat,对应命令行中的-fxxx段,如果指定了它,
  6. //在打开文件中就不会探测文件的实际格式了,以它为准了.
  7. //参数options是对某种格式的一些操作,是为了在命令行中可以对不同的格式传入
  8. //特殊的操作参数而建的,为了了解流程,完全可以无视它.
  9. intavformat_open_input(AVFormatContext**ps,
  10. constchar*filename,
  11. AVInputFormat*fmt,
  12. AVDictionary**options)
  13. {
  14. AVFormatContext*s=*ps;
  15. intret=0;
  16. AVFormatParametersap={{0}};
  17. AVDictionary*tmp=NULL;
  18. //创建上下文结构
  19. if(!s&&!(s=avformat_alloc_context()))
  20. returnAVERROR(ENOMEM);
  21. //如果用户指定了输入格式,直接使用它
  22. if(fmt)
  23. s->iformat=fmt;
  24. //忽略
  25. if(options)
  26. av_dict_copy(&tmp,*options,0);
  27. if((ret=av_opt_set_dict(s,&tmp))<0)
  28. gotofail;
  29. //打开输入媒体(如果需要的话),初始化所有与媒体读写有关的结构们,比如
  30. //AVIOContext,AVInputFormat等等
  31. if((ret=init_input(s,filename))<0)
  32. gotofail;
  33. //执行完此函数后,s->pb和s->iformat都已经指向了有效实例.pb是用于读写数据的,它
  34. //把媒体数据当做流来读写,不管是什么媒体格式,而iformat把pb读出来的流按某种媒体格
  35. //式进行分析,也就是说pb在底层,iformat在上层.
  36. //很多静态图像文件格式,都被当作一个格式处理,比如要打开.jpeg文件,需要的格式
  37. //名为image2.此处还不是很了解具体细节,作不得准哦.
  38. /*checkfilenameincaseanimagenumberisexpected*/
  39. if(s->iformat->flags&AVFMT_NEEDNUMBER){
  40. if(!av_filename_number_test(filename)){
  41. ret=AVERROR(EINVAL);
  42. gotofail;
  43. }
  44. }
  45. s->duration=s->start_time=AV_NOPTS_VALUE;
  46. //上下文中保存下文件名
  47. av_strlcpy(s->filename,filename,sizeof(s->filename));
  48. /*allocateprivatedata*/
  49. //为当前格式分配私有数据,主要用于某格式的读写操作时所用的私有结构.
  50. //此结构的大小在定义AVInputFormat时已指定了.
  51. if(s->iformat->priv_data_size>0){
  52. if(!(s->priv_data=av_mallocz(s->iformat->priv_data_size))){
  53. ret=AVERROR(ENOMEM);
  54. gotofail;
  55. }
  56. //这个可以先不必管它
  57. if(s->iformat->priv_class){
  58. *(constAVClass**)s->priv_data=s->iformat->priv_class;
  59. av_opt_set_defaults(s->priv_data);
  60. if((ret=av_opt_set_dict(s->priv_data,&tmp))<0)
  61. gotofail;
  62. }
  63. }
  64. /*e.g.AVFMT_NOFILEformatswillnothaveaAVIOContext*/
  65. //从mp3文件中读ID3数据并保存之.
  66. if(s->pb)
  67. ff_id3v2_read(s,ID3v2_DEFAULT_MAGIC);
  68. //读一下媒体的头部,在read_header()中主要是做某种格式的初始化工作,比如填充自己的
  69. //私有结构,根据流的数量分配流结构并初始化,把文件指针指向数据区开始处等.
  70. if(!(s->flags&AVFMT_FLAG_PRIV_OPT)&&s->iformat->read_header)
  71. if((ret=s->iformat->read_header(s,&ap))<0)
  72. gotofail;
  73. //保存数据区开始的位置
  74. if(!(s->flags&AVFMT_FLAG_PRIV_OPT)&&s->pb&&!s->data_offset)
  75. s->data_offset=avio_tell(s->pb);
  76. s->raw_packet_buffer_remaining_size=RAW_PACKET_BUFFER_SIZE;
  77. if(options){
  78. av_dict_free(options);
  79. *options=tmp;
  80. }
  81. *ps=s;
  82. //执行成功
  83. return0;
  84. //执行失败
  85. fail:av_dict_free(&tmp);
  86. if(s->pb&&!(s->flags&AVFMT_FLAG_CUSTOM_IO))
  87. avio_close(s->pb);
  88. avformat_free_context(s);
  89. *ps=NULL;
  90. returnret;
  91. }

init_input

  1. //打开输入媒体并填充其AVInputFormat结构
  2. staticintinit_input(AVFormatContext*s,constchar*filename)
  3. {
  4. intret;
  5. AVProbeDatapd={filename,NULL,0};
  6. //当调用者已指定了pb(数据取得的方式)--一般不会这样.
  7. if(s->pb){
  8. s->flags|=AVFMT_FLAG_CUSTOM_IO;
  9. if(!s->iformat)
  10. //如果已指定了pb但没指定iformat,以pb读取媒体数据进行探测,取得.取得iformat.
  11. returnav_probe_input_buffer(s->pb,&s->iformat,filename,s,0,0);
  12. elseif(s->iformat->flags&AVFMT_NOFILE)
  13. //如果已指定pb也指定了iformat,但是又指定了不需要文件(也包括URL指定的地址),这就矛盾了,
  14. //此时应是不需要pb的,因为不需操作文件,提示一下吧,也不算错.
  15. av_log(s,AV_LOG_WARNING,"CustomAVIOContextmakesnosenseand"
  16. "willbeignoredwithAVFMT_NOFILEformat.\n");
  17. return0;
  18. }
  19. //一般会执行到这里
  20. if((s->iformat&&s->iformat->flags&AVFMT_NOFILE)
  21. ||(!s->iformat&&(s->iformat=av_probe_input_format(&pd,0))))
  22. //如果已指定了iformat并且不需要文件,也就不需要pb了,可以直接返回
  23. //如果没指定iformat,但是可以从文件名中猜出iformat,也成功.
  24. return0;
  25. //如果从文件名中也猜不出媒体格式,则只能打开这个文件进行探测了,先打开文件
  26. if((ret=avio_open(&s->pb,filename,AVIO_FLAG_READ))<0)
  27. returnret;
  28. if(s->iformat)
  29. return0;
  30. //再探测之
  31. returnav_probe_input_buffer(s->pb,&s->iformat,filename,s,0,0);
  32. }


avio_open

  1. //打开一个地址指向的媒体
  2. intavio_open(AVIOContext**s,constchar*filename,intflags)
  3. {
  4. //URLContext代表一个URL地址指向的媒体文件,本地路径也算一种.它封装了
  5. //操作一个媒体文件的相关数据,最重要的是prot变量,是URLProtocol型的.
  6. //prot代表一个特定的协义和协议操作函数们,URLContext包含不同的prot,
  7. //就可以通过URLContext使用不同的协议读写媒体数据,比如tcp,http,本地
  8. //文件用file协议.
  9. URLContext*h;
  10. interr;
  11. //创建并初始化URLContext,其prot通过文件名确定.然后打开这个媒体文件
  12. err=ffurl_open(&h,filename,flags);
  13. if(err<0)
  14. returnerr;
  15. //其实文件已经在上边真正打开了.这里只是填充AVIOContext.使它记录下
  16. //URLContext,以及填充读写数据的函数指针.
  17. err=ffio_fdopen(s,h);
  18. if(err<0){
  19. ffurl_close(h);
  20. returnerr;
  21. }
  22. return0;
  23. }


av_probe_input_buffer

  1. intav_probe_input_buffer(AVIOContext*pb,
  2. AVInputFormat**fmt,
  3. constchar*filename,
  4. void*logctx,
  5. unsignedintoffset,
  6. unsignedintmax_probe_size)
  7. {
  8. AVProbeDatapd={filename?filename:"",NULL,-offset};
  9. unsignedchar*buf=NULL;
  10. intret=0,probe_size;
  11. //计算最多探测数据的字节数
  12. if(!max_probe_size){
  13. max_probe_size=PROBE_BUF_MAX;
  14. }elseif(max_probe_size>PROBE_BUF_MAX){
  15. max_probe_size=PROBE_BUF_MAX;
  16. }elseif(max_probe_size<PROBE_BUF_MIN){
  17. returnAVERROR(EINVAL);
  18. }
  19. if(offset>=max_probe_size){
  20. returnAVERROR(EINVAL);
  21. }
  22. //循环直到探测完指定的数据
  23. for(probe_size=PROBE_BUF_MIN;
  24. probe_size<=max_probe_size&&!*fmt;
  25. probe_size=
  26. FFMIN(probe_size<<1,FFMAX(max_probe_size,probe_size+1))){
  27. intscore=probe_size<max_probe_size?AVPROBE_SCORE_MAX/4:0;
  28. intbuf_offset=(probe_size==PROBE_BUF_MIN)?0:probe_size>>1;
  29. void*buftmp;
  30. if(probe_size<offset){
  31. continue;
  32. }
  33. /*readprobedata*/
  34. //分配读取数据存放的缓冲
  35. buftmp=av_realloc(buf,probe_size+AVPROBE_PADDING_SIZE);
  36. if(!buftmp){
  37. av_free(buf);
  38. returnAVERROR(ENOMEM);
  39. }
  40. buf=buftmp;
  41. //利用pb读数据到缓冲的剩余空间中
  42. if((ret=avio_read(pb,buf+buf_offset,probe_size-buf_offset))
  43. <0){
  44. /*failiferrorwasnotendoffile,otherwise,lowerscore*/
  45. if(ret!=AVERROR_EOF){
  46. av_free(buf);
  47. returnret;
  48. }
  49. score=0;
  50. ret=0;/*errorwasendoffile,nothingread*/
  51. }
  52. pd.buf_size+=ret;
  53. pd.buf=&buf[offset];
  54. //缓冲中没有数据的部分要清0
  55. memset(pd.buf+pd.buf_size,0,AVPROBE_PADDING_SIZE);
  56. /*guessfileformat*/
  57. //从一个打开的文件只探测媒体格式
  58. *fmt=av_probe_input_format2(&pd,1,&score);
  59. if(*fmt){
  60. if(score<=AVPROBE_SCORE_MAX/4){//thiscanonlybetrueinthelastiteration
  61. av_log(
  62. logctx,
  63. AV_LOG_WARNING,
  64. "Format%sdetectedonlywithlowscoreof%d,misdetectionpossible!\n",
  65. (*fmt)->name,score);
  66. }else
  67. av_log(logctx,AV_LOG_DEBUG,
  68. "Format%sprobedwithsize=%dandscore=%d\n",
  69. (*fmt)->name,probe_size,score);
  70. }
  71. //不成功,继续
  72. }
  73. if(!*fmt){
  74. av_free(buf);
  75. returnAVERROR_INVALIDDATA;
  76. }
  77. /*rewind.reuseprobebuffertoavoidseeking*/
  78. //把探测时读入的数据保存到pb中,为的是真正读时直接利用之.
  79. if((ret=ffio_rewind_with_probe_data(pb,buf,pd.buf_size))<0)
  80. av_free(buf);
  81. returnret;
  82. }

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值