Decoding Video Frames with ffmpeg/libav
Opening the file
AVFormatContext *formatContext;
if (avformat_open_input(&formatContext, "path/to/file.ext", nullptr, nullptr) != 0)
exit(1); // Couldn't open file
/// Retrieve stream information
if (avformat_find_stream_info(formatContext, nullptr) < 0)
exit(2); // Couldn't find stream information
Find the first video stream
int videoStreamIdx = -1;
for (int i = 0; i < (int)formatContext->nb_streams; ++i)
if (formatContext->streams[i]->codecpar->codec_type ==
AVMEDIA_TYPE_VIDEO) {
videoStreamIdx = i;
break;
}
if (videoStreamIdx == -1) exit(3); // Didn't find a video stream
Find the correct codec for decoding
AVCodecContext *codecContext;
AVCodec *codec;
codecContext = avcodec_alloc_context3(codec);
/// Get a pointer to the codec context for the video stream
avcodec_parameters_to_context( codecContext, formatContext->streams[videoStreamIdx]->codecpar);
/// Find the decoder for the video stream
codec = avcodec_find_decoder(codecContext->codec_id);
if (codec == nullptr) {
fprintf(stderr, "Unsupported codec!\n");
exit(4); // Codec not found
}
Initialize buffers and conversion context
AVFrame *inputFrame;
AVFrame *outputFrame;
inputFrame = av_frame_alloc();
outputFrame = av_frame_alloc();
int w = codecContext->width;
int h = codecContext->height;
int numBytes = av_image_get_buffer_size (AV_PIX_FMT_RGBA, w, h, 16);
buffer = (uint8_t *)av_malloc(numBytes * sizeof(uint8_t));
av_image_fill_arrays (outputFrame->data, outputFrame->linesize, buffer, AV_PIX_FMT_RGBA, codecContext->width, codecContext->height, 1);
conversionContext =
sws_getContext(w, h, codecContext->pix_fmt, w, h, AV_PIX_FMT_RGBA,
SWS_FAST_BILINEAR, nullptr, nullptr, nullptr);
Decode a frame
AVPacket packet;
while ((av_read_frame(formatContext, &packet) >= 0)) {
if (packet.stream_index == videoStreamIdx) {
avcodec_send_packet(codecContext, &packet);
int frameFinished = avcodec_receive_frame(codecContext, inputFrame);
// Did we get a video frame?
if (frameFinished == 0) {
sws_scale(conversionContext, (const uint8_t *const *)inputFrame->data,
inputFrame->linesize, 0, codecContext->height, outputFrame->data,
outputFrame->linesize);
av_packet_unref(&packet);
// DO SOMETHING WITH outputFrame
}
}
}
Drain frames
avcodec_send_packet(codecContext, nullptr);
while(avcodec_receive_frame(codecContext, inputFrame) == 0)
sws_scale(conversionContext, (const uint8_t *const *)inputFrame->data,
inputFrame->linesize, 0, codecContext->height, outputFrame->data,
outputFrame->linesize);
// DO SOMETHING WITH outputFrame
}
Clean up
av_free(buffer);
av_free(outputFrame);
av_free(inputFrame);
avcodec_close(codecContext);
avformat_close_input(&formatContext);