如何理解给定的ffplay C代码片段?

时间:2015-07-20 09:06:00

标签: ffmpeg

以下代码段来自ffplay

static int decoder_decode_frame(Decoder *d, AVFrame *frame, AVSubtitle *sub) {
    int got_frame = 0;

    do {
        int ret = -1;

        if (d->queue->abort_request)
            return -1;

        if (!d->packet_pending || d->queue->serial != d->pkt_serial) {
            AVPacket pkt;
            do {
                if (d->queue->nb_packets == 0)
                    SDL_CondSignal(d->empty_queue_cond);
                if (packet_queue_get(d->queue, &pkt, 1, &d->pkt_serial) < 0)
                    return -1;
                if (pkt.data == flush_pkt.data) {
                    avcodec_flush_buffers(d->avctx);
                    d->finished = 0;
                    d->next_pts = d->start_pts;
                    d->next_pts_tb = d->start_pts_tb;
                }
            } while (pkt.data == flush_pkt.data || d->queue->serial != d->pkt_serial);
            av_free_packet(&d->pkt);
            d->pkt_temp = d->pkt = pkt;
            d->packet_pending = 1;
        }

        switch (d->avctx->codec_type) {
            case AVMEDIA_TYPE_VIDEO:
                ret = avcodec_decode_video2(d->avctx, frame, &got_frame, &d->pkt_temp);
                if (got_frame) {
                    if (decoder_reorder_pts == -1) {
                        frame->pts = av_frame_get_best_effort_timestamp(frame);
                    } else if (decoder_reorder_pts) {
                        frame->pts = frame->pkt_pts;
                    } else {
                        frame->pts = frame->pkt_dts;
                    }
                }
                break;
            case AVMEDIA_TYPE_AUDIO:
                ret = avcodec_decode_audio4(d->avctx, frame, &got_frame, &d->pkt_temp);
                if (got_frame) {
                    AVRational tb = (AVRational){1, frame->sample_rate};
                    if (frame->pts != AV_NOPTS_VALUE)
                        frame->pts = av_rescale_q(frame->pts, d->avctx->time_base, tb);
                    else if (frame->pkt_pts != AV_NOPTS_VALUE)
                        frame->pts = av_rescale_q(frame->pkt_pts, av_codec_get_pkt_timebase(d->avctx), tb);
                    else if (d->next_pts != AV_NOPTS_VALUE)
                        frame->pts = av_rescale_q(d->next_pts, d->next_pts_tb, tb);
                    if (frame->pts != AV_NOPTS_VALUE) {
                        d->next_pts = frame->pts + frame->nb_samples;
                        d->next_pts_tb = tb;
                    }
                }
                break;
            case AVMEDIA_TYPE_SUBTITLE:
                ret = avcodec_decode_subtitle2(d->avctx, sub, &got_frame, &d->pkt_temp);
                break;
        }

        if (ret < 0) {
            d->packet_pending = 0;
        } else {
            d->pkt_temp.dts =
            d->pkt_temp.pts = AV_NOPTS_VALUE;
            if (d->pkt_temp.data) {
                if (d->avctx->codec_type != AVMEDIA_TYPE_AUDIO)
                    ret = d->pkt_temp.size;
                d->pkt_temp.data += ret;
                d->pkt_temp.size -= ret;
                if (d->pkt_temp.size <= 0)
                    d->packet_pending = 0;
            } else {
                if (!got_frame) {
                    d->packet_pending = 0;
                    d->finished = d->pkt_serial; // FLAG
                }
            }
        }
    } while (!got_frame && !d->finished);

    return got_frame;
}

我很难理解以下代码:

d->finished = d->pkt_serial; // FLAG

任何人都可以帮助我吗?

感谢。

1 个答案:

答案 0 :(得分:1)

请参阅this提交。

Serial现在有两个目的:提交的初始目的是能够区分数据包队列中的数据包与搜索之前和之后的数据包。解复用器(数据包队列的输入)在单独的线程中运行。在搜索之后,我们想要刷新它,但是我们不想因为开销而停止生产者线程。但是,我们也不想要冲洗太少或太多的数据包。因此,串行字段告诉我们哪些数据包是冲洗前和冲洗后的,因此当我们丢弃这些数据包时,哪些数据包将丢弃而不必停止生产者线程。

第二个目的是你的代码行:它告诉我们何时发生EOF。已完成设置为来自用于解码帧的数据包队列的数据包的最后一个序列号。如果该序列号也是数据包队列的尾部(并且不再产生数据包),则意味着我们停止生成数据包解码属于该数据包的帧。换句话说:文件结束。在其他地方,您将沿着这些线找到测试,然后播放停止或(如果启用循环)我们寻找文件的开头(即调用循环行为)。

(这篇文章得到了IRC的几位FFmpeg开发人员的帮助。)