Skip to content

Instantly share code, notes, and snippets.

@nlgranger
Created January 12, 2019 19:59
Show Gist options
  • Save nlgranger/377e4309db3bdfd949bf0581b1a4dd99 to your computer and use it in GitHub Desktop.
Save nlgranger/377e4309db3bdfd949bf0581b1a4dd99 to your computer and use it in GitHub Desktop.
ffmpeg demo using modern decoding API
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <libavutil/avutil.h>
#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
char err_str[1024];
int decode_frames(AVCodecContext* decoder_ctx, AVFrame* frame) {
int nb_decoded = 0;
int ret = 0;
while (ret == 0) {
ret = avcodec_receive_frame(decoder_ctx, frame);
if (ret == AVERROR(EAGAIN)) { // no more content in this packet
printf("end of packet, read %2d frames\n", nb_decoded);
return 0;
} else if (ret < 0) { // error
break;
} else {
nb_decoded++;
printf("decoded frame %4d of size %3d x %3d\n",
decoder_ctx->frame_number, frame->width, frame->height);
}
}
return ret;
}
int main(int argc, char* argv[]) {
// Open container
AVFormatContext* fmt_ctx;
fmt_ctx = avformat_alloc_context();
if (fmt_ctx == NULL) {
printf("failed to allocate format context\n");
return 0;
}
int ret = avformat_open_input(&fmt_ctx, argv[argc-1], NULL, NULL);
if (ret != 0) {
printf("failed to open input file %s\n", argv[argc-1]);
goto free_fmt_ctx;
}
// Parse header/probe content
ret = avformat_find_stream_info(fmt_ctx, NULL);
if (ret != 0) {
printf("failed to parse stream info\n");
goto close_fmt_ctx;
}
// Open video stream
int stream_idx = av_find_best_stream(fmt_ctx, AVMEDIA_TYPE_VIDEO, -1, -1, NULL, 0);
if (stream_idx < 0) {
printf("failed to find stream\n");
goto close_fmt_ctx;
}
AVCodecParameters* codecpar = fmt_ctx->streams[stream_idx]->codecpar;
enum AVMediaType media_type = codecpar->codec_type;
// allocate/configure/initialize decoder context
AVCodec* codec;
codec = avcodec_find_decoder(codecpar->codec_id);
if (codec == NULL) {
printf("failed to load codec for stream %d\n", stream_idx);
goto close_fmt_ctx;
}
AVCodecContext* decoder_ctx;
decoder_ctx = avcodec_alloc_context3(codec);
if (decoder_ctx == NULL) {
printf("failed to allocate decoder\n");
goto close_decoder;
};
ret = avcodec_parameters_to_context(decoder_ctx, codecpar);
if (ret < 0) {
printf("failed to configure decoder\n");
goto close_decoder;
}
ret = avcodec_open2(decoder_ctx, codec, NULL);
if (ret < 0) {
printf("failed to initialize decoder\n");
goto close_decoder;
}
// Decode frames
AVPacket pkt;
av_init_packet(&pkt);
pkt.data = NULL;
pkt.size = 0;
AVFrame* frame;
frame = av_frame_alloc();
if (frame == NULL) {
printf("failed to allocate frame\n");
goto close_decoder;
}
while (1) {
// Fetch a packet
ret = av_read_frame(fmt_ctx, &pkt);
while (ret == 0 && pkt.stream_index != stream_idx) {
av_packet_unref(&pkt);
ret = av_read_frame(fmt_ctx, &pkt);
}
if (ret != 0) {
printf("failed to read packet or end of file\n");
goto free_frame;
} else {
printf("decoded packet at timestamp %d\n", pkt.pts);
}
// Send packet to decoder
ret = avcodec_send_packet(decoder_ctx, &pkt);
// process previous packet first
if (ret == AVERROR(EAGAIN)) {
printf("must finish current packet first");
ret = decode_frames(decoder_ctx, frame);
if (ret < 0) {
goto free_frame;
}
ret = avcodec_send_packet(decoder_ctx, &pkt);
}
// error cases
if (ret == AVERROR_EOF) {
printf("no more packets\n");
goto free_frame;
} else if (ret == AVERROR(EINVAL)) {
printf("problem with decoder\n");
goto free_frame;
} else if (ret == AVERROR(ENOMEM)) {
printf("failed to push packet to decoder\n");
goto free_frame;
} else if (ret < 0) {
printf("some packet decoding error\n");
goto free_frame;
}
// Decode frames
ret = decode_frames(decoder_ctx, frame);
if (ret < 0) {
goto free_frame;
}
av_packet_unref(&pkt);
}
// Cleanup
free_frame:
av_packet_unref(&pkt);
av_frame_free(&frame);
close_decoder:
avcodec_flush_buffers(decoder_ctx);
avcodec_free_context(&decoder_ctx);
close_fmt_ctx:
avformat_close_input(&fmt_ctx);
free_fmt_ctx:
avformat_free_context(fmt_ctx);
if (ret != 0) {
err_str[0] = '\n';
av_strerror(ret, err_str, sizeof(err_str));
printf("%s\n", err_str);
}
return 0;
}
// compile with: gcc -lavutil -lavcodec -lavformat decode.c
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment