陆小曼超详细解析FFplay之音视频解码线程( 六 )


?频解码线程
数据来源:从read_thread()线程?来 。
数据处理:在audio_thread()进?解码 , 具体调?decoder_decode_frame() 。
数据出?:在sdl_audio_callback()->audio_decode_frame()读取frame进?播放 。
先看audio_thraed() , 对于滤镜部分(CONFIG_AVFILTER定义部分) , 这?不做分析, 简化后的代码如下:
// ?频解码线程static int audio_thread(void *arg){VideoState *is = arg;AVFrame *frame = av_frame_alloc(); // 分配解码帧Frame *af;int got_frame = 0; // 是否读取到帧AVRational tb; // timebaseint ret = 0;if (!frame)return AVERROR(ENOMEM);do {// 1. 读取解码帧if ((got_frame = decoder_decode_frame(&is->auddec, frame, NU LL)) < 0)goto the_end;if (got_frame) {tb = (AVRational){1, frame->sample_rate};// 设置为 sample_rate为timebase// 2. 获取可写Frameif (!(af = frame_queue_peek_writable(&is->sampq))) // 获取可写帧goto the_end;// 3. 设置Frame并放?FrameQueue//填充复制帧 , 线程安全af->pts = (frame->pts == AV_NOPTS_VALUE) ? NAN : fra me->pts * av_q2d(tb);af->pos = frame->pkt_pos;af->serial = is->auddec.pkt_serial;af->duration = av_q2d((AVRational){frame->nb_samples , frame->sample_rate});av_frame_move_ref(af->frame, frame); //转移frame_queue_push(&is->sampq); // 更新写索引}} while (ret >= 0 || ret == AVERROR(EAGAIN) || ret == AVERROR_EO F);the_end:av_frame_free(&frame);return ret;}从简化后的代码来看 , 逻辑和video_thread()基本是类似的且更简单 , 这?主要重点讲解 。
陆小曼超详细解析FFplay之音视频解码线程
本文插图
为什么video_thread()是tb是采?了stream->base_base , audio这?却不是?
static int decoder_decode_frame(Decoder *d, AVFrame *frame, AVSubtit le *sub) {...for (;;) {AVPacket pkt;// 1. 流连续情况下获取解码后的帧if (d->queue->serial == d->pkt_serial) {// 1.1 先判断是否是同 ?播放序列的数据do {.........switch (d->avctx->codec_type) {case AVMEDIA_TYPE_VIDEO:....break;case AVMEDIA_TYPE_AUDIO:ret = avcodec_receive_frame(d->avctx, frame);if (ret >= 0) {AVRational tb = (AVRational){1, frame->sampl e_rate}; //if (frame->pts != AV_NOPTS_VALUE) {// 如果frame->pts正常则先将其从pkt_timebase 转成{1, frame->sample_rate}// pkt_timebase实质就是stream->time_base 2frame->pts = av_rescale_q(frame->pts, d- >avctx->pkt_timebase, tb);}else if (d->next_pts != AV_NOPTS_VALUE) {// 如果frame->pts不正常则使?上?帧更新的next_ pts和next_pts_tb// 转成{1, frame->sample_rate}frame->pts = av_rescale_q(d->next_pts, d ->next_pts_tb, tb);}if (frame->pts != AV_NOPTS_VALUE) {// 根据当前帧的pts和nb_samples预估下?帧的ptsd->next_pts = frame->pts + frame->nb_sam ples;d->next_pts_tb = tb; // 设置timebase}}break;}....} while (ret != AVERROR(EAGAIN)); // 1.5 没帧可读时ret返 回EAGIN , 需要继续送packet}....}从上可以看出来 , 将audio frame从decoder_decode_frame取出来后 , 已由stream->time_base转成了{1, frame->sample_rate}作为time_base 。
本篇文章就分享到这里 , 欢迎关注 , 点赞 , 收藏 , 转发 。


推荐阅读