ffmpeg中关于ffplay部分的概要分析-1

ffplay是ffmpeg中的一个播放音视频流的功能,现简要对其进行分析:

1. 图1是ffplay的主干代码流程

1)在stream_open函数之前,主要是对入参的一些分析,所有codec,demux以及相关protocool的注册

  注册两个信号量:一个是给中断使用,一个是给终端操作使用(比如键盘,鼠标等的一些动作)

2)在stream_open函数中,先是对video,audio,subtitle三个format的消息队列进行初始化,

  再对收发数据的队列进行初始化。然后调用SDL_CreateThread函数开启 read_thread()线程。

3)在创建完线程后,进入event_loop函数中,开始等待来自终端设备的事件,比如,鼠标,键盘的一些操作,以及推出等命令,

  具体哪些事件可以详见代码中的switch中每个case的分之。

4)在event_loop函数中,会通过refresh_loop_wait_event()函数等待来自外部一些事件,然后对相应的事件进行响应。

5)其实event_loop就是ffplay的一个线程,它并没有退出,而是一直在这里loop。

 

2. 图2是read_thread线程的主要流程:

1) 通过调用avformat_open_input()函数来确认要用哪种demux来处理到来的data stream,主要就是读取一段数据流,

    对该流进行分析看它与哪种demux最为匹配,具体怎么做没有细看。

2) avformat_find_stream_info()函数根据最前端的一段数据流来分析该流是 视频,音频或字幕,若是音频或者视频是哪种

  格式的,是编码还是解码(这个根据输入输出的格式来确认),同时找到对应的编码器或者解码器。不是很清楚为什么需要

  在这里调用函数try_decode_frame()对新来的数据流进行解码。

3) av_find_best_stream()函数是找到对应的编码器或解码器。

4) 函数stream_component_open()主要分别打开audio, video, subtitle这三个模式的各自的线程

  audio_thread, video_thread, subtitle_thread。

5) 线程read_thread()在完成上述任务后,开始循环处理来自外界的一些信息:

      a) abort 退出请求

  b) pause 暂停请求

  c) seek 跳转请求 (视频的前进后退等的请求)

  d) 判断如何缓冲buffer满了,休息等待10ms后再准备向各个模式的缓冲buffer中放数据

  e) 调用av_read_frame() 获取data packet后,再通过调用packet_queue_put()函数将数据放倒对应的缓冲buffer中。

    调用packet_queue_put函数放置packet,没有经过copy而是直接将packet的指针赋给对应模式的缓冲链表中的队尾,

    这样减少了copy,节省了时间。

Notes:

  1)结构体VideoState{}开辟的这段内存对于后续的所有线程 read_thread, audio_thread,video_thread以及main_thread

    来讲就是全局的内存,可以被他们所共用,所以在使用的时候一定要格外的小心,防止多个线程向同一数据去写操作。

  2)后面所有的线程所用的全局内存都是VideoState{}中的一小部分。

 

第一天开始看ffplay的代码,现在已经离开音频这个行业了,但是还是对这个行业非常感兴趣。

为了不失去自己的技术敏感度,只能自己业余时间来读读代码,锻炼锻炼脑袋了。

很感谢网上哪些技术大牛的博客以及文章,迅速的在自己的mac上搭建好了eclipse的环境以及

ffmpeg编译顺利通过。

 

posted on 2016-08-27 21:25  hello dsp  阅读(845)  评论(0编辑  收藏  举报

导航