How to Read Video Packet Headers Using libavformat

Reading video packet headers using FFmpeg's libavformat library is a fundamental process for demuxing multimedia containers, inspecting stream layouts, and analyzing compressed data without decoding the frames. This guide demonstrates how to initialize the library, open a media container, retrieve stream information, and read each packet's header fields—such as presentation timestamps, stream indexes, and payload sizes—using standard C code.

Essential Workflow

To read packet headers without decoding frame payloads, follow this sequence:

  1. Allocate a format context and open the input file with avformat_open_input().
  2. Inspect the stream metadata using avformat_find_stream_info().
  3. Allocate an AVPacket structure using av_packet_alloc().
  4. Loop through the container by repeatedly calling av_read_frame().
  5. Access the packet header members directly from the AVPacket struct.
  6. Release memory using av_packet_unref(), av_packet_free(), and avformat_close_input().

Complete Implementation Example

The following C program opens a media file and prints the header properties for each packet read from the container:

#include <stdio.h>
#include <libavformat/avformat.h>

int main(int argc, char *argv[]) {
    if (argc < 2) {
        fprintf(stderr, "Usage: %s <input_file>\n", argv[0]);
        return 1;
    }

    const char *filename = argv[1];
    AVFormatContext *fmt_ctx = NULL;

    // 1. Open the file and read the container header
    if (avformat_open_input(&fmt_ctx, filename, NULL, NULL) < 0) {
        fprintf(stderr, "Could not open source file %s\n", filename);
        return 1;
    }

    // 2. Retrieve stream information
    if (avformat_find_stream_info(fmt_ctx, NULL) < 0) {
        fprintf(stderr, "Could not find stream information\n");
        avformat_close_input(&fmt_ctx);
        return 1;
    }

    // 3. Allocate the packet structure
    AVPacket *pkt = av_packet_alloc();
    if (!pkt) {
        fprintf(stderr, "Could not allocate AVPacket\n");
        avformat_close_input(&fmt_ctx);
        return 1;
    }

    // 4. Read packets sequentially
    while (av_read_frame(fmt_ctx, pkt) >= 0) {
        AVStream *stream = fmt_ctx->streams[pkt->stream_index];

        // 5. Inspect packet header properties
        const char *type = (stream->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) ? "Video" :
                           (stream->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) ? "Audio" : "Other";

        int is_keyframe = (pkt->flags & AV_PKT_FLAG_KEY) != 0;

        printf("[%s] Stream Index: %2d | PTS: %8lld | DTS: %8lld | Size: %6d bytes | Keyframe: %s\n",
               type,
               pkt->stream_index,
               (long long)pkt->pts,
               (long long)pkt->dts,
               pkt->size,
               is_keyframe ? "Yes" : "No");

        // Clear references to data for the next read
        av_packet_unref(pkt);
    }

    // 6. Cleanup resources
    av_packet_free(&pkt);
    avformat_close_input(&fmt_ctx);

    return 0;
}

Key Packet Header Fields

When av_read_frame() returns successfully, the AVPacket struct contains the compressed payload alongside metadata describing how the packet relates to the overall media timeline:

  • stream_index: Identifies which stream inside the container the packet belongs to (matches an index in fmt_ctx->streams).
  • pts (Presentation Timestamp): The time at which the decompressed frame should be presented to the user, calculated in the stream's timebase units (stream->time_base).
  • dts (Decoding Timestamp): The time at which the packet must be passed to the decoder. For streams with B-frames, dts may diverge from pts.
  • size: The byte length of the compressed frame payload stored in pkt->data.
  • pos: The byte offset of the packet within the container file, which is useful for seeking or demuxer debugging.
  • flags: Bitmask providing state information about the packet. Checking pkt->flags & AV_PKT_FLAG_KEY indicates whether the packet is an independent keyframe (such as an IDR frame in H.264/HEVC).

Compilation

To compile the application using gcc and pkg-config, run:

gcc read_packets.c -o read_packets $(pkg-config --cflags --libs libavformat libavutil)