diff --git a/src/platform/ffmpeg/ffmpeg-encoder.c b/src/platform/ffmpeg/ffmpeg-encoder.c index 5e518179f..0ce81bf0b 100644 --- a/src/platform/ffmpeg/ffmpeg-encoder.c +++ b/src/platform/ffmpeg/ffmpeg-encoder.c @@ -2,6 +2,8 @@ #include "gba-video.h" +#include + #include #include @@ -27,6 +29,8 @@ void FFmpegEncoderInit(struct FFmpegEncoder* encoder) { FFmpegEncoderSetAudio(encoder, "flac", 0); FFmpegEncoderSetVideo(encoder, "png", 0); FFmpegEncoderSetContainer(encoder, "matroska"); + encoder->resampleContext = 0; + encoder->absf = 0; encoder->context = 0; } @@ -200,6 +204,14 @@ bool FFmpegEncoderOpen(struct FFmpegEncoder* encoder, const char* outfile) { encoder->postaudioBuffer = av_malloc(encoder->postaudioBufferSize); avcodec_fill_audio_frame(encoder->audioFrame, encoder->audio->channels, encoder->audio->sample_fmt, (const uint8_t*) encoder->postaudioBuffer, encoder->postaudioBufferSize, 0); + if (encoder->audio->codec->id == AV_CODEC_ID_AAC && + (strcasecmp(encoder->containerFormat, "mp4") || + strcasecmp(encoder->containerFormat, "m4v") || + strcasecmp(encoder->containerFormat, "mov"))) { + // MP4 container doesn't support the raw ADTS AAC format that the encoder spits out + encoder->absf = av_bitstream_filter_init("aac_adtstoasc"); + } + encoder->videoStream = avformat_new_stream(encoder->context, vcodec); encoder->video = encoder->videoStream->codec; encoder->video->bit_rate = encoder->videoBitrate; @@ -252,6 +264,11 @@ void FFmpegEncoderClose(struct FFmpegEncoder* encoder) { avresample_close(encoder->resampleContext); } + if (encoder->absf) { + av_bitstream_filter_close(encoder->absf); + encoder->absf = 0; + } + sws_freeContext(encoder->scaleContext); avformat_free_context(encoder->context); @@ -296,6 +313,17 @@ void _ffmpegPostAudioFrame(struct GBAAVStream* stream, int32_t left, int32_t rig int gotData; avcodec_encode_audio2(encoder->audio, &packet, encoder->audioFrame, &gotData); if (gotData) { + if (encoder->absf) { + AVPacket tempPacket = packet; + int success = av_bitstream_filter_filter(encoder->absf, encoder->audio, 0, + &tempPacket.data, &tempPacket.size, + packet.data, packet.size, 0); + if (success > 0) { + tempPacket.buf = av_buffer_create(tempPacket.data, tempPacket.size, av_buffer_default_free, 0, 0); + av_free_packet(&packet); + } + packet = tempPacket; + } packet.stream_index = encoder->audioStream->index; av_interleaved_write_frame(encoder->context, &packet); } diff --git a/src/platform/ffmpeg/ffmpeg-encoder.h b/src/platform/ffmpeg/ffmpeg-encoder.h index ce8a700f3..ffed42940 100644 --- a/src/platform/ffmpeg/ffmpeg-encoder.h +++ b/src/platform/ffmpeg/ffmpeg-encoder.h @@ -3,12 +3,11 @@ #include "gba-thread.h" -#include #include struct FFmpegEncoder { struct GBAAVStream d; - AVFormatContext* context; + struct AVFormatContext* context; unsigned audioBitrate; const char* audioCodec; @@ -18,7 +17,7 @@ struct FFmpegEncoder { const char* containerFormat; - AVCodecContext* audio; + struct AVCodecContext* audio; enum AVSampleFormat sampleFormat; int sampleRate; uint16_t* audioBuffer; @@ -30,14 +29,15 @@ struct FFmpegEncoder { int64_t currentAudioFrame; int64_t nextAudioPts; struct AVAudioResampleContext* resampleContext; - AVStream* audioStream; + struct AVBitStreamFilterContext* absf; // Needed for AAC in MP4 + struct AVStream* audioStream; - AVCodecContext* video; + struct AVCodecContext* video; enum AVPixelFormat pixFormat; - AVFrame* videoFrame; + struct AVFrame* videoFrame; int64_t currentVideoFrame; struct SwsContext* scaleContext; - AVStream* videoStream; + struct AVStream* videoStream; }; void FFmpegEncoderInit(struct FFmpegEncoder*);