if (d->queue->serial == d->pkt_serial) { //判断packetqueue的序列号等于Decoder的序列号 //packetqueue的序列号,在发生seek操作后,会+1 do { if (d->queue->abort_request) //如果收到了退出请求,返回-1 return-1;
switch (d->avctx->codec_type) { case AVMEDIA_TYPE_VIDEO: //从解码器读frame ret = avcodec_receive_frame(d->avctx, frame); if (ret >= 0) { //读到了frame, 设置frame的pts //decoder_reorder_pts: let decoder reorder pts 0=off 1=on -1=auto if (decoder_reorder_pts == -1) { frame->pts = frame->best_effort_timestamp; } elseif (!decoder_reorder_pts) { frame->pts = frame->pkt_dts; } } break; case AVMEDIA_TYPE_AUDIO: //从解码器读frame ret = avcodec_receive_frame(d->avctx, frame); if (ret >= 0) { //读到了frame,设置frame的pts AVRational tb = (AVRational){1, frame->sample_rate}; if (frame->pts != AV_NOPTS_VALUE) //pts转换,从编码器的时间基,转换为tb作为时间基 frame->pts = av_rescale_q(frame->pts, d->avctx->pkt_timebase, tb); elseif (d->next_pts != AV_NOPTS_VALUE) //frame的pts没有值,参考d->next_pts,并做时间基的转化 frame->pts = av_rescale_q(d->next_pts, d->next_pts_tb, tb); if (frame->pts != AV_NOPTS_VALUE) { //计算next_pts,会被没有pts的Frame参考 //保存next_pts_tb d->next_pts = frame->pts + frame->nb_samples; d->next_pts_tb = tb; } } break; } if (ret == AVERROR_EOF) { //解码器结束,所有的帧已经被读出 d->finished = d->pkt_serial; //重置解码器内部状态 avcodec_flush_buffers(d->avctx); return0; } if (ret >= 0) return1; } while (ret != AVERROR(EAGAIN)); //需要送入更多的pkts }
一个if条件,内嵌一个do.while循环。
首先 if 判断d->queue->serial == d->pkt_serial,保证当前要处理的pkt与pkt->queue的序列号一致。如果不一致,证明是该pkt和pkt->queue中元素,是两段不连续的数据,进入后续流程,做丢帧处理。
如果序列号一致,进入循环,尝试从解码器获取frame。
我们看下这个循环
判断是否收到退出请求
switch判断解码器的类型,处理audio 和 video 的情况。 调用avcodec_receive_frame 尝试从解码器获取frame。 返回值>=0 代表获取成功,转换frame的pts
处理avcodec_receive_frame的返回值。
ret = AVERROR_EOF 解码器所有的帧已被读出,解码结束,返回0.
ret >= 0, 成功获取了frame, 直接返回 1
ret = AVERROR(EAGAIN), 解码器需要接受更多pkt才可以输出frame,跳出do.while循环。
if (d->avctx->codec_type == AVMEDIA_TYPE_SUBTITLE) { int got_frame = 0; //Return a negative value on error, otherwise return the number of bytes used ret = avcodec_decode_subtitle2(d->avctx, sub, &got_frame, d->pkt); if (ret < 0) { //解码发生了错误,为了和avcodec_send_packet的错误码一起处理,转换为AVERROR(EAGAIN),尝试继续发送pkt ret = AVERROR(EAGAIN); } else { if (got_frame && !d->pkt->data) { //d->pkt->data = NULL 代表给解码器发送flush消息, //需要持续给解码器flush消息,直到无法继续读取到新的frame, //因此将packet_pending设置为1,标记当前pkt为待处理,直到flush完成 d->packet_pending = 1; } ret = got_frame ? 0 : (d->pkt->data ? AVERROR(EAGAIN) : AVERROR_EOF); } av_packet_unref(d->pkt); } else { //给音视频解码器发送pkt if (avcodec_send_packet(d->avctx, d->pkt) == AVERROR(EAGAIN)) { //报错AVERROR(EAGAIN),解码器此时不能接受更多了pkt //需要调用avcodec_receive_frame将解码器中的frame读出才可以继续send pkt av_log(d->avctx, AV_LOG_ERROR, "Receive_frame and send_packet both returned EAGAIN, which is an API violation.\n"); //比较当前pkt未被成功消费,后续需要重新处理 d->packet_pending = 1; } else { //send pkt 成功,引用计数-1 av_packet_unref(d->pkt); } }