av_read_frame

  • Post author:
  • Post category:其他


ffmpeg中的av_read_frame()的作用是读取码流中的音频若干帧或者视频一帧。例如,解码视频的时候,每解码一个视频帧,需要先调用 av_read_frame()获得一帧视频的压缩数据,然后才能对该数据进行解码(例如H.264中一帧压缩数据通常对应一个NAL)。

对于视频的编解码来说,要对数据进行解码,那么首先要获取视频帧的压缩数据。 av_read_frame()的作用就是获取视频的数据。

注:av_read_frame()获取视频的一帧,不存在半帧说法。但可以获取音频的若干帧。

说明①:av_read_frame()函数是ffmpeg新型的用法,就用法之所以被抛弃,就是因为以前获取的数据可能不是完整的,而av_read_frame()保证了视频数据一帧的完整性。

说明②:查看API的改变可以看到,从2012-03-20开始,Deprecate av_read_packet(), use

av_read_frame()

返回流的下一帧。

*此函数返回存储在文件中的内容,但不验证解码器是否有有效帧。 它将把文件中存储的内容拆分为帧,并为每个调用返回一个帧。 它不会省略有效帧之间的无效数据,以便给解码器最大可能的解码信息。

如果pkt->buf为NULL,那么直到下一个av_read_frame()或直到avformat_close_input(),包都是有效的。

否则数据包将无限期有效。在这两种情况下,当不再需要包时,必须使用av_free_packet释放包。 对于视频,数据包只包含一帧。

对于音频,如果每个帧具有已知的固定大小(例如PCM或ADPCM数据),则它包含整数帧数。

如果音频帧有一个可变的大小(例如MPEG音频),那么它包含一帧。

在AVStream中,pkt->pts、pkt->dts和pkt->持续时间总是被设置为恰当的值。

time_base单元(猜测格式是否不能提供它们)。

如果视频格式为B-frames,pkt->pts可以是AV_NOPTS_VALUE,所以如果不解压缩有效负载,最好依赖pkt->dts。

int av_read_frame(AVFormatContext *s, AVPacket *pkt);

参数说明:

AVFormatContext *s   // 文件格式上下文,输入的AVFormatContext

AVPacket *pkt   // 这个值不能传NULL,必须是一个空间,输出的AVPacket

// 返回值:return 0 is OK, <0 on error or end of file

/**
* 返回流的下一帧。
 * 此函数返回文件中存储的内容,不进行验证
 * 什么是解码器的有效帧。它会分裂什么是
 * 将文件存储为帧并为每次调用返回一个。它不会
 * 省略有效帧之间的无效数据,以便给解码器最大
 * 可用于解码的信息。
 *
 * 如果 pkt->buf 为 NULL,则数据包在下一次之前有效
 * av_read_frame() 或直到 avformat_close_input()。否则包
 * 无限期有效。在这两种情况下,必须使用以下命令释放数据包
 * av_free_packet 不再需要时。对于视频,数据包包含
 *正好一帧。对于音频,它包含整数个帧,如果每个
 * 帧具有已知的固定大小(例如 PCM 或 ADPCM 数据)。如果音频帧
 * 具有可变大小(例如 MPEG 音频),则它包含一帧。
 *
 * pkt->pts、pkt->dts 和 pkt->duration 始终设置为正确
 * AVStream.time_base 单位中的值(如果格式不能,则猜测
 * 提供它们)。 pkt->pts 可以是 AV_NOPTS_VALUE 如果视频格式
 * 有 B 帧,所以如果你没有,最好依靠 pkt->dts
 * 解压有效载荷。

 * @return 0 如果正常,< 0 错误或文件结束
 * 
 * s:输入的AVFormatContext
 * pkt:输出的AVPacket
 */
int av_read_frame(AVFormatContext *s, AVPacket *pkt);

av_read_frame()函数源码位于libavformat\utils.c

int av_read_frame(AVFormatContext *s, AVPacket *pkt)
{
    const int genpts = s->flags & AVFMT_FLAG_GENPTS;
    int eof = 0;
    int ret;
    AVStream *st;

    if (!genpts) {
        ret = s->internal->packet_buffer
              ? ff_packet_list_get(&s->internal->packet_buffer,
                                        &s->internal->packet_buffer_end, pkt)
              : read_frame_internal(s, pkt);
        if (ret < 0)
            return ret;
        goto return_packet;
    }

    for (;;) {
        AVPacketList *pktl = s->internal->packet_buffer;

        if (pktl) {
            AVPacket *next_pkt = &pktl->pkt;

            if (next_pkt->dts != AV_NOPTS_VALUE) {
                int wrap_bits = s->streams[next_pkt->stream_index]->pts_wrap_bits;
                // last dts seen for this stream. if any of packets following
                // current one had no dts, we will set this to AV_NOPTS_VALUE.
                int64_t last_dts = next_pkt->dts;
                av_assert2(wrap_bits <= 64);
                while (pktl && next_pkt->pts == AV_NOPTS_VALUE) {
                    if (pktl->pkt.stream_index == next_pkt->stream_index &&
                        av_compare_mod(next_pkt->dts, pktl->pkt.dts, 2ULL << (wrap_bits - 1)) < 0) {
                        if (av_compare_mod(pktl->pkt.pts, pktl->pkt.dts, 2ULL << (wrap_bits - 1))) {
                            // not B-frame
                            next_pkt->pts = pktl->pkt.dts;
                        }
                        if (last_dts != AV_NOPTS_VALUE) {
                            // Once last dts was set to AV_NOPTS_VALUE, we don't change it.
                            last_dts = pktl->pkt.dts;
                        }
                    }
                    pktl = pktl->next;
                }
                if (eof && next_pkt->pts == AV_NOPTS_VALUE && last_dts != AV_NOPTS_VALUE) {
                    // Fixing the last reference frame had none pts issue (For MXF etc).
                    // We only do this when
                    // 1. eof.
                    // 2. we are not able to resolve a pts value for current packet.
                    // 3. the packets for this stream at the end of the files had valid dts.
                    next_pkt->pts = last_dts + next_pkt->duration;
                }
                pktl = s->internal->packet_buffer;
            }

            /* read packet from packet buffer, if there is data */
            st = s->streams[next_pkt->stream_index];
            if (!(next_pkt->pts == AV_NOPTS_VALUE && st->discard < AVDISCARD_ALL &&
                  next_pkt->dts != AV_NOPTS_VALUE && !eof)) {
                ret = ff_packet_list_get(&s->internal->packet_buffer,
                                               &s->internal->packet_buffer_end, pkt);
                goto return_packet;
            }
        }

        ret = read_frame_internal(s, pkt);
        if (ret < 0) {
            if (pktl && ret != AVERROR(EAGAIN)) {
                eof = 1;
                continue;
            } else
                return ret;
        }

        ret = ff_packet_list_put(&s->internal->packet_buffer,
                                 &s->internal->packet_buffer_end,
                                 pkt, FF_PACKETLIST_FLAG_REF_PACKET);
        av_packet_unref(pkt);
        if (ret < 0)
            return ret;
    }

return_packet:

    st = s->streams[pkt->stream_index];
    if ((s->iformat->flags & AVFMT_GENERIC_INDEX) && pkt->flags & AV_PKT_FLAG_KEY) {
        ff_reduce_index(s, st->index);
        av_add_index_entry(st, pkt->pos, pkt->dts, 0, 0, AVINDEX_KEYFRAME);
    }

    if (is_relative(pkt->dts))
        pkt->dts -= RELATIVE_TS_BASE;
    if (is_relative(pkt->pts))
        pkt->pts -= RELATIVE_TS_BASE;

    return ret;
}

原文链接:https://blog.csdn.net/weixin_38890593/article/details/96310342



版权声明:本文为weixin_42123332原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。