1. ホーム
  2. ffmpeg

ffmpeg 関数: av_read_frame() の解析。

2022-02-25 09:53:43
<パス

ビデオのエンコードとデコードの場合、データをデコードするために、まずビデオフレームの圧縮データを取得します。
av_read_frame() の役割を果たします。 動画のデータを取得する .
注意:av_read_frame()は映像の1フレームを取得します、ハーフフレームというものはありません。しかし、音声の数フレームを取得することはできます。
注1: av_read_frame() 関数は、ffmpeg の新しい使用法です。この使い方が放棄された理由は、以前に取得したデータが完全でない可能性があり、一方 av_read_frame() はビデオデータの 1 フレームの完全性を保証するためです。
注2.API の変更点を見ると、2012-03-20 から av_read_packet() を廃止し、av_read_frame() を使用するようになったことが分かります。

Returns the next frame of the stream.
*This function returns what is stored in the file, but does not verify that the decoder has a valid frame.
It will split the content stored in the file into frames and return one frame for each call.
It will not omit invalid data between valid frames in order to give the decoder the maximum possible decoding information.
If pkt->buf is NULL, then the packet is valid until the next av_read_frame() or until avformat_close_input().
Otherwise the packet will be valid indefinitely. In both cases, the packet must be released using av_free_packet when the packet is no longer needed.
For video, the packet contains only one frame.
For audio, if each frame has a known fixed size (e.g. PCM or ADPCM data), it contains an integer number of frames.
If the audio frame has a variable size (e.g. MPEG audio), then it contains one frame.
In AVStream, pkt->pts, pkt->dts and pkt->duration are always set to the appropriate values.
time_base unit (guess if the format cannot provide them).
If the video format is B-frames, pkt->pts can be AV_NOPTS_VALUE, so it is better to rely on pkt->dts if the payload is not decompressed.


int av_read_frame(AVFormatContext *s, AVPacket *pkt);
パラメータの説明です。
AVFormatContext *s // ファイルフォーマットコンテキスト、入力 AVFormatContext
AVPacket *pkt // この値はNULLで渡すことはできず、スペースである必要があります、出力AVPacket
            // 返り値:OKなら0、エラーまたはファイル終了なら<0を返す

av_read_frame()関数のソースコードはlibavformatutils.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->