
本章主要是分析 数据读取线程read_thread 中的工作。如上图红色框框的部分
 
 从ffplay框架分析我们可以看到,ffplay有专⻔的线程read_thread()读取数据, 
 
 
 且在调⽤av_read_frame 读取数据包之前需要做: 
 
 
 1.例如打开⽂件, 
 
 
 2.查找配置解码器, 
 
 
 3.初始化⾳视频输出等准备阶段, 
 
 
 
 主要包括三⼤步骤: 
 
- 准备⼯作
- For循环读取数据
- 退出线程处理
一 准备⼯作
 
 准备⼯作主要包括以下步骤:  
 
 
 1.  
 avformat_alloc_context 创建上下⽂  
 
 
 2.  
 ic 
 -> 
 interrupt_callback 
 . 
 callback  
 = decode_interrupt_cb;  
 
 
 3.  
 avformat_open_input打开媒体⽂件  
 
 
 4. avformat_find_stream_info 读取媒体⽂件的包获取更多的stream信息  
 
 
 5. 检测是否指定播放起始时间,如果指定时间则seek到指定位置 
 avformat_seek_file  
 
 
 6.  
 查找 
 查找AVStream,讲对应的index值记录到 
 st_index 
 [ 
 AVMEDIA_TYPE_NB 
 ];  
 
 
         a.  
 根据⽤户指定来查找流 
 avformat_match_stream_specifier  
 
 
         b.  
 使⽤av_find_best_stream查找流  
 
 
 7. 通过 
 AVCodecParameters和 
 av_guess_sample_aspect_ratio 
 计算出显示窗⼝的宽、⾼  
 
 
 8.  
 stream_component_open打开⾳频、视频、字幕解码器,并创建相应的解码线程以及进⾏对应输出参数的初始化。 
 
 
 
 
1. avformat_alloc_context 创建上下⽂
 
 调⽤ 
 avformat_alloc_context创建解复⽤器上下⽂ 
 
 
// 1. 创建上下⽂结构体,这个结构体是最上层的结构体,表示输⼊上下⽂
ic = avformat_alloc_context(); 
 最终该ic 赋值给VideoState的ic变量 
 
 
is->ic = ic; // videoState的ic指向分配的ic2 ic->interrupt_callback
ic 这里是AVFormatContext ,
    /* 2.设置中断回调函数,如果出错或者退出,就根据目前程序设置的状态选择继续check或者直接退出 */
    /* 当open出现阻塞的时候时候,会调用interrupt_callback.callback
     * 回调函数中返回1则代表ffmpeg结束阻塞可以将操纵权交给用户线程并返回错误码
     * 回调函数中返回0则代表ffmpeg继续阻塞直到ffmpeg正常工作为止,所以要退出死等则需要返回1
     */
    ic->interrupt_callback.callback = decode_interrupt_cb;
    ic->interrupt_callback.opaque = is; 
  那么这个  
  interrupt_callback 是个啥? 
 
 
  
  interrupt_callback⽤于ffmpeg内部在执⾏耗时操作时检查调⽤者是否有退出请求,避免⽤户退出请求没 有及时响应。 
 
 
  
 
   在什么时候触发这个 callback 呢? 
 
 
  
  
   avformat_open_input的触发 
  
 
   
   avformat_find_stream_info的触发 
  
 
   
   av_read_frame的触发 
  
 
   
   
   
  3.avformat_open_input()打开媒体⽂件
 
   avformat_open_input⽤于打开输⼊⽂件(对于RTMP/RTSP/HTTP⽹络流也是⼀样,在ffmpeg内部都 抽象为URLProtocol,这⾥描述为⽂件是为了⽅便与后续提到的AVStream的流作区分),读取视频⽂件 的基本信息。  
  
 
   
  
   需要提到的两个参数是fmt和options。通过fmt可以强制指定视频⽂件的封装,options可以传递额外参数 给封装(AVInputFormat)。  
  
 
   
   
    主要代码: 
   
 
    
    
       //特定选项处理
    if (!av_dict_get(format_opts, "scan_all_pmts", NULL, AV_DICT_MATCH_CASE)) {
        av_dict_set(&format_opts, "scan_all_pmts", "1", AV_DICT_DONT_OVERWRITE);
        scan_all_pmts_set = 1;
    }
     /* 3.打开文件,主要是探测协议类型,如果是网络文件则创建网络链接等 */
    err = avformat_open_input(&ic, is->filename, is->iformat, &format_opts); 
  scan_all_pmts是mpegts的⼀个选项,表示扫描全部的ts流的"Program Map Table"表。这⾥在没有设定 该选项的时候,强制设为1。最后执⾏avformat_open_input。  
 
 
 
 参数的设置最终都是设置到对应的解复⽤器,⽐如:  
 
 
 
 




















