all repos — mgba @ 281f190ae6d372d8e998c9d812c13df9dca43bc2

mGBA Game Boy Advance Emulator

Enhance usability and resiliency of ffmpeg encoder
Jeffrey Pfau jeffrey@endrift.com
Sun, 26 Oct 2014 23:48:34 -0700
commit

281f190ae6d372d8e998c9d812c13df9dca43bc2

parent

21ea47ea9e24a181b460f5973d74a4bd29dcd939

2 files changed, 47 insertions(+), 1 deletions(-)

jump to
M src/platform/ffmpeg/ffmpeg-encoder.csrc/platform/ffmpeg/ffmpeg-encoder.c

@@ -13,11 +13,16 @@

encoder->d.postVideoFrame = _ffmpegPostVideoFrame; encoder->d.postAudioFrame = _ffmpegPostAudioFrame; + encoder->audioCodec = 0; + encoder->videoCodec = 0; + encoder->containerFormat = 0; FFmpegEncoderSetAudio(encoder, "flac", 0); FFmpegEncoderSetVideo(encoder, "png", 0); + FFmpegEncoderSetContainer(encoder, "matroska"); encoder->currentAudioSample = 0; encoder->currentAudioFrame = 0; encoder->currentVideoFrame = 0; + encoder->context = 0; } bool FFmpegEncoderSetAudio(struct FFmpegEncoder* encoder, const char* acodec, unsigned abr) {

@@ -54,15 +59,42 @@ encoder->videoBitrate = vbr;

return true; } +bool FFmpegEncoderSetContainer(struct FFmpegEncoder* encoder, const char* container) { + AVOutputFormat* oformat = av_guess_format(container, 0, 0); + if (!oformat) { + return false; + } + encoder->containerFormat = container; + return true; +} + +bool FFmpegEncoderVerifyContainer(struct FFmpegEncoder* encoder) { + AVOutputFormat* oformat = av_guess_format(encoder->containerFormat, 0, 0); + AVCodec* acodec = avcodec_find_encoder_by_name(encoder->audioCodec); + AVCodec* vcodec = avcodec_find_encoder_by_name(encoder->videoCodec); + if (!acodec || !vcodec || !oformat) { + return false; + } + if (!avformat_query_codec(oformat, acodec->id, FF_COMPLIANCE_EXPERIMENTAL)) { + return false; + } + if (!avformat_query_codec(oformat, vcodec->id, FF_COMPLIANCE_EXPERIMENTAL)) { + return false; + } + return true; +} + bool FFmpegEncoderOpen(struct FFmpegEncoder* encoder, const char* outfile) { AVCodec* acodec = avcodec_find_encoder_by_name(encoder->audioCodec); AVCodec* vcodec = avcodec_find_encoder_by_name(encoder->videoCodec); - if (!acodec || !vcodec) { + if (!acodec || !vcodec || !FFmpegEncoderVerifyContainer(encoder)) { return false; } avformat_alloc_output_context2(&encoder->context, 0, 0, outfile); + encoder->context->oformat = av_guess_format(encoder->containerFormat, 0, 0); + encoder->audioStream = avformat_new_stream(encoder->context, acodec); encoder->audio = encoder->audioStream->codec; encoder->audio->bit_rate = encoder->audioBitrate;

@@ -108,6 +140,9 @@ return true;

} void FFmpegEncoderClose(struct FFmpegEncoder* encoder) { + if (!encoder->context) { + return; + } av_write_trailer(encoder->context); avio_close(encoder->context->pb);

@@ -118,10 +153,14 @@

av_frame_free(&encoder->videoFrame); avcodec_close(encoder->video); avformat_free_context(encoder->context); + encoder->context = 0; } void _ffmpegPostAudioFrame(struct GBAAVStream* stream, int32_t left, int32_t right) { struct FFmpegEncoder* encoder = (struct FFmpegEncoder*) stream; + if (!encoder->context) { + return; + } av_frame_make_writable(encoder->audioFrame); encoder->audioBuffer[encoder->currentAudioSample * 2] = left;

@@ -150,6 +189,9 @@ }

void _ffmpegPostVideoFrame(struct GBAAVStream* stream, struct GBAVideoRenderer* renderer) { struct FFmpegEncoder* encoder = (struct FFmpegEncoder*) stream; + if (!encoder->context) { + return; + } uint32_t* pixels; unsigned stride; renderer->getPixels(renderer, &stride, (void**) &pixels);
M src/platform/ffmpeg/ffmpeg-encoder.hsrc/platform/ffmpeg/ffmpeg-encoder.h

@@ -16,6 +16,8 @@

unsigned videoBitrate; const char* videoCodec; + const char* containerFormat; + AVCodecContext* audio; uint16_t* audioBuffer; size_t audioBufferSize;

@@ -34,6 +36,8 @@

void FFmpegEncoderInit(struct FFmpegEncoder*); bool FFmpegEncoderSetAudio(struct FFmpegEncoder*, const char* acodec, unsigned abr); bool FFmpegEncoderSetVideo(struct FFmpegEncoder*, const char* vcodec, unsigned vbr); +bool FFmpegEncoderSetContainer(struct FFmpegEncoder*, const char* container); +bool FFmpegEncoderVerifyContainer(struct FFmpegEncoder*); bool FFmpegEncoderOpen(struct FFmpegEncoder*, const char* outfile); void FFmpegEncoderClose(struct FFmpegEncoder*);