陆小曼超详细解析FFplay之音视频解码线程( 二 )
在该流程中 , 当调?函数返回值?于<0时则退出线程 。 线程的步骤如下:
(1). 获取stream timebase , 以便将frame的pts转成秒为单位
(2). 获取帧率 , 以便计算每帧picture的duration
(3). 获取解码后的视频帧 , 具体调?get_video_frame()实现
(4). 计算帧持续时间和换算pts值为秒
(5). 将解码后的视频帧插?队列 , 具体调?queue_picture()实现
(6). 释放frame对应的数据
下面重点说说get_video_frame()和queue_picture() 。
get_video_frame 简化如下:
static int get_video_frame(VideoState *is, AVFrame *frame) {int got_picture;// 1. 获取解码后的视频帧if ((got_picture = decoder_decode_frame(&is->viddec, frame, NULL )) < 0) {// 返回-1意味着要退出解码线程return -1;}if (got_picture) {// 2. 分析获取到的该帧是否要drop掉.....}return got_picture; }主要流程:
(1)调? decoder_decode_frame 解码并获取解码后的视频帧 。
(2)分析如果获取到帧是否需要drop掉 。 逻辑就是如果刚解出来就落后主时钟 , 那就没有必要放?Frame队列 , 再拿去播放 , 但是也是有?定的条件的 , ?下?分析 。
被简化的部分主要是针对丢帧的?个处理:
if (got_picture) {2 // 2. 分析获取到的该帧是否要drop掉, 该机制的?的是在放?帧队列前先drop掉过时 的视频帧3 double dpts = NAN;45 if (frame->pts != AV_NOPTS_VALUE)6 dpts = av_q2d(is->video_st->time_base) * frame->pts;//计 算出秒为单位的pts78 frame->sample_aspect_ratio = av_guess_sample_aspect_ratio(is->ic , is->video_st, frame);910 if (framedrop>0 ||// 允许drop帧11 (framedrop && get_master_sync_type(is) != AV_SYNC_VIDEO_MAST ER))//?视频同步模式12 { 13 if (frame->pts != AV_NOPTS_VALUE) { // pts值有效
先确定进?丢帧检测流程 , 控制是否进?丢帧检测有3种情况:
(1)控制是否丢帧的开关变量是 framedrop, 为1 , 则始终判断是丢帧 。
(2)framedrop 为0 , 则始终不丢帧 。
(3)framedrop 为-1(默认值) , 则在主时钟不是video的时候 , 判断是否丢帧 。
如果进?丢帧检测流程 , drop帧需要下列因素都成?:
(1)!isnan(diff):当前pts和主时钟的差值是有效值 。
(2)fabs(diff) < AV_NOSYNC_THRESHOLD:差值在可同步范围内 , 这?设置的是10秒 , 意思是如果差值太?这?就不管了了 , 可能流本身录制的时候就有问题 , 这?不能随便把帧都drop掉 。
(3)diff - is->frame_last_filter_delay < 0:和过滤器有关系 , 不设置过滤器时简化为 diff < 0 。
(4)is->viddec.pkt_serial == is->vidclk.serial:解码器的serial和时钟的serial相同 , 即是?少显示了?帧图像 , 因为只有显示的时候才调?update_video_pts()设置到video clk的serial 。
(5)is->videoq.nb_packets:?少packetqueue有1个包 。
接下来看下真正解码的过程—— decoder_decode_frame, 这个函数也包含了对audio和subtitle的解码 , 其返回值:
-1:请求退出解码器线程
0:解码器已经完全冲刷 , 没有帧可读 , 这?也说明对应码流播放结束 。
1:正常解码获取到帧 。
先看简化后的主?代码(注意for(;;)这个?循环):
static int decoder_decode_frame(Decoder *d, AVFrame *frame, AVSubtit le *sub) {for (;;) {// ?循环//1. 流连续情况下获取解码后的帧4 if (d->queue->serial == d->pkt_serial) {do {if (d->queue->abort_request)return -1; // 是否请求退出ret = avcodec_receive_frame(d->avctx, frame);if (ret == AVERROR_EOF) {return 0; // 解码器已完全冲刷 , 没有帧可读了}if (ret >= 0)return 1; // 读取到解码帧} while (ret != AVERROR(EAGAIN));}//2. 获取?个packet , 如果播放序列不?致(数据不连续)则过滤掉“过时”的packetdo {if (d->queue->nb_packets == 0)//如果没有数据可读则唤醒read_th readSDL_CondSignal(d->empty_queue_cond);if (packet_queue_get(d->queue, &pkt, 1, &d->pkt_serial) < 0)// 阻塞?式读packetreturn -1;} while (d->queue->serial != d->pkt_serial); // 播放序列的判断//3. 将packet送?解码器avcodec_send_packet(d->avctx, &pkt);}}decoder_decode_frame 的主?代码是?个循环 , 要拿到?帧解码数据 , 或解码出错、?件结束 , 才会 返回 。
推荐阅读
- 龙导说车|宝马X3奔驰GLC和奥迪Q5L,详细选车指南,豪华中型SUV
- 利兹联|周一精彩3C1:01荷乙恐爆冷、狼队有望大胜,另附一场瑞典超解析
- 前沿分析局|那美国会遵守吗?金灿荣解析,基辛格希望设立“交战规则”
- 登海种业|10月19日龙虎榜解析:若羽臣净买入额最多,还有19只个股被机构扫货
- 青年|《原神》“断罪皇女”菲谢尔全方位解析指南
- 九游网|《鸿图之下》益州怎么样 益州地形影响解析
- 央视新闻客户端|如何看待前三季度中国经济的基本态势?杨禹详细解读
- 杜兰特|NBA实力榜解析:掘金热火谁更强 勇士配不配进前5
- 穿搭|基础款怎么穿?通过"针织衫+半裙"解析,简单背后总是暗藏玄机
- 博森科技苏闻衫|CCR炒币机器人和手动炒币的优缺点解析
