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:
- Allocate a format context and open the input file with
avformat_open_input(). - Inspect the stream metadata using
avformat_find_stream_info(). - Allocate an
AVPacketstructure usingav_packet_alloc(). - Loop through the container by repeatedly calling
av_read_frame(). - Access the packet header members directly from the
AVPacketstruct. - Release memory using
av_packet_unref(),av_packet_free(), andavformat_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 infmt_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,dtsmay diverge frompts.size: The byte length of the compressed frame payload stored inpkt->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. Checkingpkt->flags & AV_PKT_FLAG_KEYindicates 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)