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);

Related Posts