超详细解析FFplay之数据读取线程( 七 )

 
(5)检测队列是否已经有?够数据 。
?频、视频、字幕队列都不是?限?的,如果不加以限制?直往队列放?packet,那将导致队列占??量的内存空间,影响系统的性能,所以必须对队列的缓存??进?控制 。PacketQueue默认情况下会有??限制,达到这个??后,就需要等待10ms,以让消费者——解码线程能有时间消耗 。
// 检测队列是否已经有?够数据/* if the queue are full, no need to read more *//* 缓存队列有?够的包,不需要继续读取数据 */ // 缓冲区不是?限? if (infinite_buffer<1 &&(is->audioq.size + is->videoq.size + is->subtitleq.size > MAX_QU EUE_SIZE|| (stream_has_enough_packets(is->audio_st, is->audio_st ream, &is->audioq) &&stream_has_enough_packets(is->video_st, is->video_st ream, &is->videoq) &&stream_has_enough_packets(is->subtitle_st, is->subti tle_stream, &is->subtitleq)))){/* wait 10 ms */SDL_LockMutex(wait_mutex);// 如果没有唤醒则超时10ms退出,?如在seek操作时这?会被唤醒SDL_CondWaitTimeout(is->continue_read_thread, wait_mutex, 10);SDL_UnlockMutex(wait_mutex);continue;}缓冲区满有两种可能:
第一,audioq,videoq,subtitleq三个PacketQueue的总字节数达到了MAX_QUEUE_SIZE(15M,为什么是15M?这?只是?个经验计算值,?如4K视频的码率以50Mbps计算,则15MB可以缓存2.4秒,从这么计算实际上如果我们真的是播放4K?源,15MB是偏?的数值,有些?源?较坑 同?个?件位置附近的pts差值超过5秒,此时如果视频要缓存5秒才能做同步,那15MB的缓存??就不够了) 。所以要根据实际的情况进行调整 。
第二,等待10ms的条件是,?频、视频、字幕流都已有够?的包(stream_has_enough_packets),三者要同时成立才行 。
第?种好理解,看下第?种中的stream_has_enough_packets 。这是好多种情况的组合 。
static int stream_has_enough_packets(AVStream *st, int stream_id, Pac ketQueue *queue){return stream_id < 0 || // 没有该流queue->abort_request || // 请求退出(st->disposition & AV_DISPOSITION_ATTACHED_PIC) || // 是ATTACHED_PICqueue->nb_packets > MIN_FRAMES // packet数>25&& (!queue->duration || // 满?PacketQueue总时?为0av_q2d(st->time_base) * queue->duration > 1.0);//或总时?超过1s}有这么?种情况包是够?的,也就是说可以足够去用,不用担心空包问题:
第一,流没有打开(stream_id < 0),没有相应的流返回逻辑true 。
第二,有退出请求(queue->abort_request) 。
第三,配置了AV_DISPOSITION_ATTACHED_PIC 。
第四,packet队列内包个数?于MIN_FRAMES(>25),并满?PacketQueue总时?为0或总时?超过1s 。
包是否足够思路:
第一,看总数据?? 。
第二,每个packet队列的情况 。
 
(6)检测码流是否已经播放结束 。
是否循环播放 。
是否?动退出 。
?暂停状态才进?步检测码流是否已经播放完毕,注意:数据播放完毕和码流数据读取完毕是两个概念 。只有,PacketQueue和FrameQueue都消耗完毕,才是真正的播放完毕 。
//检测码流是否已经播放结束 if (!is->paused// ?暂停&& // 这?的执?是因为码流读取完毕后 插?空包所致(!is->audio_st // 没有?频流|| (is->auddec.finished == is->audioq.serial // 或者?频播放完毕&& frame_queue_nb_remaining(&is->sampq) == 0))&& (!is->video_st // 没有视频流|| (is->viddec.finished == is->videoq.serial // 或者视频播放完毕&& frame_queue_nb_remaining(&is->pictq) == 0))) {if (loop != 1 // a 是否循环播放&& (!loop || --loop)) {//循环播放,自动从头开始stream_seek(is, start_time != AV_NOPTS_VALUE ? start_time : 0, 0, 0);} else if (autoexit) { // b 是否?动退出ret = AVERROR_EOF;goto fail;}}这?判断播放已完成的条件需要同时满?这几个条件:
第一,不在暂停状态
第二,?频未打开;或者打开了,但是解码已解完所有packet,?定义的解码器(decoder)serial等于PacketQueue的serial,并且FrameQueue中没有数据帧,音频数据已经消耗完毕 。
PacketQueue.serial -> packet.serail -> decoder.pkt_serial
decoder.finished = decoder.pkt_serial
is->auddec.finished == is->audioq.serial 最新的播放序列的packet都解码完毕 。
frame_queue_nb_remaining(&is->sampq) == 0 对应解码后的数据也播放完毕 。
第三,视频未打开;或者打开了,但是解码已解完所有packet,?定义的解码器(decoder)serial等于PacketQueue的serial,并且FrameQueue中没有数据帧 。视频数据已经播放完毕 。
在确认?前码流已播放结束的情况下,?户有两个变量可以控制播放器?为:


推荐阅读