src/platform/ffmpeg/ffmpeg-encoder.c (view raw)
1/* Copyright (c) 2013-2015 Jeffrey Pfau
2 *
3 * This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6#include "ffmpeg-encoder.h"
7
8#include "core/core.h"
9#include "gba/video.h"
10
11#include <libavcodec/version.h>
12#include <libavcodec/avcodec.h>
13
14#include <libavutil/version.h>
15#if LIBAVUTIL_VERSION_MAJOR >= 53
16#include <libavutil/buffer.h>
17#endif
18#include <libavutil/imgutils.h>
19#include <libavutil/mathematics.h>
20#include <libavutil/opt.h>
21
22#include <libavresample/avresample.h>
23#include <libswscale/swscale.h>
24
25static void _ffmpegPostVideoFrame(struct GBAAVStream*, struct GBAVideoRenderer* renderer);
26static void _ffmpegPostAudioFrame(struct GBAAVStream*, int16_t left, int16_t right);
27
28enum {
29 PREFERRED_SAMPLE_RATE = 0x8000
30};
31
32void FFmpegEncoderInit(struct FFmpegEncoder* encoder) {
33 av_register_all();
34
35 encoder->d.postVideoFrame = _ffmpegPostVideoFrame;
36 encoder->d.postAudioFrame = _ffmpegPostAudioFrame;
37 encoder->d.postAudioBuffer = 0;
38
39 encoder->audioCodec = 0;
40 encoder->videoCodec = 0;
41 encoder->containerFormat = 0;
42 FFmpegEncoderSetAudio(encoder, "flac", 0);
43 FFmpegEncoderSetVideo(encoder, "png", 0);
44 FFmpegEncoderSetContainer(encoder, "matroska");
45 FFmpegEncoderSetDimensions(encoder, VIDEO_HORIZONTAL_PIXELS, VIDEO_VERTICAL_PIXELS);
46 encoder->resampleContext = 0;
47 encoder->absf = 0;
48 encoder->context = 0;
49}
50
51bool FFmpegEncoderSetAudio(struct FFmpegEncoder* encoder, const char* acodec, unsigned abr) {
52 static const struct {
53 int format;
54 int priority;
55 } priorities[] = {
56 { AV_SAMPLE_FMT_S16, 0 },
57 { AV_SAMPLE_FMT_S16P, 1 },
58 { AV_SAMPLE_FMT_S32, 2 },
59 { AV_SAMPLE_FMT_S32P, 2 },
60 { AV_SAMPLE_FMT_FLT, 3 },
61 { AV_SAMPLE_FMT_FLTP, 3 },
62 { AV_SAMPLE_FMT_DBL, 4 },
63 { AV_SAMPLE_FMT_DBLP, 4 }
64 };
65
66 if (!acodec) {
67 encoder->audioCodec = 0;
68 return true;
69 }
70
71 AVCodec* codec = avcodec_find_encoder_by_name(acodec);
72 if (!codec) {
73 return false;
74 }
75
76 if (!codec->sample_fmts) {
77 return false;
78 }
79 size_t i;
80 size_t j;
81 int priority = INT_MAX;
82 encoder->sampleFormat = AV_SAMPLE_FMT_NONE;
83 for (i = 0; codec->sample_fmts[i] != AV_SAMPLE_FMT_NONE; ++i) {
84 for (j = 0; j < sizeof(priorities) / sizeof(*priorities); ++j) {
85 if (codec->sample_fmts[i] == priorities[j].format && priority > priorities[j].priority) {
86 priority = priorities[j].priority;
87 encoder->sampleFormat = codec->sample_fmts[i];
88 }
89 }
90 }
91 if (encoder->sampleFormat == AV_SAMPLE_FMT_NONE) {
92 return false;
93 }
94 encoder->sampleRate = PREFERRED_SAMPLE_RATE;
95 if (codec->supported_samplerates) {
96 for (i = 0; codec->supported_samplerates[i]; ++i) {
97 if (codec->supported_samplerates[i] < PREFERRED_SAMPLE_RATE) {
98 continue;
99 }
100 if (encoder->sampleRate == PREFERRED_SAMPLE_RATE || encoder->sampleRate > codec->supported_samplerates[i]) {
101 encoder->sampleRate = codec->supported_samplerates[i];
102 }
103 }
104 } else if (codec->id == AV_CODEC_ID_AAC) {
105 // HACK: AAC doesn't support 32768Hz (it rounds to 32000), but libfaac doesn't tell us that
106 encoder->sampleRate = 44100;
107 }
108 encoder->audioCodec = acodec;
109 encoder->audioBitrate = abr;
110 return true;
111}
112
113bool FFmpegEncoderSetVideo(struct FFmpegEncoder* encoder, const char* vcodec, unsigned vbr) {
114 static const struct {
115 enum AVPixelFormat format;
116 int priority;
117 } priorities[] = {
118 { AV_PIX_FMT_RGB555, 0 },
119 { AV_PIX_FMT_BGR555, 0 },
120 { AV_PIX_FMT_RGB565, 1 },
121 { AV_PIX_FMT_BGR565, 1 },
122 { AV_PIX_FMT_RGB24, 2 },
123 { AV_PIX_FMT_BGR24, 2 },
124#ifndef USE_LIBAV
125 { AV_PIX_FMT_BGR0, 3 },
126 { AV_PIX_FMT_RGB0, 3 },
127 { AV_PIX_FMT_0BGR, 3 },
128 { AV_PIX_FMT_0RGB, 3 },
129#endif
130 { AV_PIX_FMT_YUV422P, 4 },
131 { AV_PIX_FMT_YUV444P, 5 },
132 { AV_PIX_FMT_YUV420P, 6 }
133 };
134 AVCodec* codec = avcodec_find_encoder_by_name(vcodec);
135 if (!codec) {
136 return false;
137 }
138
139 size_t i;
140 size_t j;
141 int priority = INT_MAX;
142 encoder->pixFormat = AV_PIX_FMT_NONE;
143 for (i = 0; codec->pix_fmts[i] != AV_PIX_FMT_NONE; ++i) {
144 for (j = 0; j < sizeof(priorities) / sizeof(*priorities); ++j) {
145 if (codec->pix_fmts[i] == priorities[j].format && priority > priorities[j].priority) {
146 priority = priorities[j].priority;
147 encoder->pixFormat = codec->pix_fmts[i];
148 }
149 }
150 }
151 if (encoder->pixFormat == AV_PIX_FMT_NONE) {
152 return false;
153 }
154 encoder->videoCodec = vcodec;
155 encoder->videoBitrate = vbr;
156 return true;
157}
158
159bool FFmpegEncoderSetContainer(struct FFmpegEncoder* encoder, const char* container) {
160 AVOutputFormat* oformat = av_guess_format(container, 0, 0);
161 if (!oformat) {
162 return false;
163 }
164 encoder->containerFormat = container;
165 return true;
166}
167
168void FFmpegEncoderSetDimensions(struct FFmpegEncoder* encoder, int width, int height) {
169 encoder->width = width > 0 ? width : VIDEO_HORIZONTAL_PIXELS;
170 encoder->height = height > 0 ? height : VIDEO_VERTICAL_PIXELS;
171}
172
173bool FFmpegEncoderVerifyContainer(struct FFmpegEncoder* encoder) {
174 AVOutputFormat* oformat = av_guess_format(encoder->containerFormat, 0, 0);
175 AVCodec* acodec = avcodec_find_encoder_by_name(encoder->audioCodec);
176 AVCodec* vcodec = avcodec_find_encoder_by_name(encoder->videoCodec);
177 if ((encoder->audioCodec && !acodec) || !vcodec || !oformat) {
178 return false;
179 }
180 if (encoder->audioCodec && !avformat_query_codec(oformat, acodec->id, FF_COMPLIANCE_EXPERIMENTAL)) {
181 return false;
182 }
183 if (!avformat_query_codec(oformat, vcodec->id, FF_COMPLIANCE_EXPERIMENTAL)) {
184 return false;
185 }
186 return true;
187}
188
189bool FFmpegEncoderOpen(struct FFmpegEncoder* encoder, const char* outfile) {
190 AVCodec* acodec = avcodec_find_encoder_by_name(encoder->audioCodec);
191 AVCodec* vcodec = avcodec_find_encoder_by_name(encoder->videoCodec);
192 if ((encoder->audioCodec && !acodec) || !vcodec || !FFmpegEncoderVerifyContainer(encoder)) {
193 return false;
194 }
195
196 encoder->currentAudioSample = 0;
197 encoder->currentAudioFrame = 0;
198 encoder->currentVideoFrame = 0;
199 encoder->nextAudioPts = 0;
200
201 AVOutputFormat* oformat = av_guess_format(encoder->containerFormat, 0, 0);
202#ifndef USE_LIBAV
203 avformat_alloc_output_context2(&encoder->context, oformat, 0, outfile);
204#else
205 encoder->context = avformat_alloc_context();
206 strncpy(encoder->context->filename, outfile, sizeof(encoder->context->filename) - 1);
207 encoder->context->filename[sizeof(encoder->context->filename) - 1] = '\0';
208 encoder->context->oformat = oformat;
209#endif
210
211 if (acodec) {
212 encoder->audioStream = avformat_new_stream(encoder->context, acodec);
213 encoder->audio = encoder->audioStream->codec;
214 encoder->audio->bit_rate = encoder->audioBitrate;
215 encoder->audio->channels = 2;
216 encoder->audio->channel_layout = AV_CH_LAYOUT_STEREO;
217 encoder->audio->sample_rate = encoder->sampleRate;
218 encoder->audio->sample_fmt = encoder->sampleFormat;
219 AVDictionary* opts = 0;
220 av_dict_set(&opts, "strict", "-2", 0);
221 if (encoder->context->oformat->flags & AVFMT_GLOBALHEADER) {
222 encoder->audio->flags |= CODEC_FLAG_GLOBAL_HEADER;
223 }
224 avcodec_open2(encoder->audio, acodec, &opts);
225 av_dict_free(&opts);
226#if LIBAVCODEC_VERSION_MAJOR >= 55
227 encoder->audioFrame = av_frame_alloc();
228#else
229 encoder->audioFrame = avcodec_alloc_frame();
230#endif
231 if (!encoder->audio->frame_size) {
232 encoder->audio->frame_size = 1;
233 }
234 encoder->audioFrame->nb_samples = encoder->audio->frame_size;
235 encoder->audioFrame->format = encoder->audio->sample_fmt;
236 encoder->audioFrame->pts = 0;
237 encoder->resampleContext = avresample_alloc_context();
238 av_opt_set_int(encoder->resampleContext, "in_channel_layout", AV_CH_LAYOUT_STEREO, 0);
239 av_opt_set_int(encoder->resampleContext, "out_channel_layout", AV_CH_LAYOUT_STEREO, 0);
240 av_opt_set_int(encoder->resampleContext, "in_sample_rate", PREFERRED_SAMPLE_RATE, 0);
241 av_opt_set_int(encoder->resampleContext, "out_sample_rate", encoder->sampleRate, 0);
242 av_opt_set_int(encoder->resampleContext, "in_sample_fmt", AV_SAMPLE_FMT_S16, 0);
243 av_opt_set_int(encoder->resampleContext, "out_sample_fmt", encoder->sampleFormat, 0);
244 avresample_open(encoder->resampleContext);
245 encoder->audioBufferSize = (encoder->audioFrame->nb_samples * PREFERRED_SAMPLE_RATE / encoder->sampleRate) * 4;
246 encoder->audioBuffer = av_malloc(encoder->audioBufferSize);
247 encoder->postaudioBufferSize = av_samples_get_buffer_size(0, encoder->audio->channels, encoder->audio->frame_size, encoder->audio->sample_fmt, 0);
248 encoder->postaudioBuffer = av_malloc(encoder->postaudioBufferSize);
249 avcodec_fill_audio_frame(encoder->audioFrame, encoder->audio->channels, encoder->audio->sample_fmt, (const uint8_t*) encoder->postaudioBuffer, encoder->postaudioBufferSize, 0);
250
251 if (encoder->audio->codec->id == AV_CODEC_ID_AAC &&
252 (strcasecmp(encoder->containerFormat, "mp4") ||
253 strcasecmp(encoder->containerFormat, "m4v") ||
254 strcasecmp(encoder->containerFormat, "mov"))) {
255 // MP4 container doesn't support the raw ADTS AAC format that the encoder spits out
256 encoder->absf = av_bitstream_filter_init("aac_adtstoasc");
257 }
258 }
259
260 encoder->videoStream = avformat_new_stream(encoder->context, vcodec);
261 encoder->video = encoder->videoStream->codec;
262 encoder->video->bit_rate = encoder->videoBitrate;
263 encoder->video->width = encoder->width;
264 encoder->video->height = encoder->height;
265 encoder->video->time_base = (AVRational) { VIDEO_TOTAL_LENGTH, GBA_ARM7TDMI_FREQUENCY };
266 encoder->video->pix_fmt = encoder->pixFormat;
267 encoder->video->gop_size = 60;
268 encoder->video->max_b_frames = 3;
269 if (encoder->context->oformat->flags & AVFMT_GLOBALHEADER) {
270 encoder->video->flags |= CODEC_FLAG_GLOBAL_HEADER;
271 }
272 if (strcmp(vcodec->name, "libx264") == 0) {
273 // Try to adaptively figure out when you can use a slower encoder
274 if (encoder->width * encoder->height > 1000000) {
275 av_opt_set(encoder->video->priv_data, "preset", "superfast", 0);
276 } else if (encoder->width * encoder->height > 500000) {
277 av_opt_set(encoder->video->priv_data, "preset", "veryfast", 0);
278 } else {
279 av_opt_set(encoder->video->priv_data, "preset", "faster", 0);
280 }
281 av_opt_set(encoder->video->priv_data, "tune", "zerolatency", 0);
282 }
283 avcodec_open2(encoder->video, vcodec, 0);
284#if LIBAVCODEC_VERSION_MAJOR >= 55
285 encoder->videoFrame = av_frame_alloc();
286#else
287 encoder->videoFrame = avcodec_alloc_frame();
288#endif
289 encoder->videoFrame->format = encoder->video->pix_fmt;
290 encoder->videoFrame->width = encoder->video->width;
291 encoder->videoFrame->height = encoder->video->height;
292 encoder->videoFrame->pts = 0;
293 encoder->scaleContext = sws_getContext(VIDEO_HORIZONTAL_PIXELS, VIDEO_VERTICAL_PIXELS,
294#ifdef COLOR_16_BIT
295#ifdef COLOR_5_6_5
296 AV_PIX_FMT_RGB565,
297#else
298 AV_PIX_FMT_BGR555,
299#endif
300#else
301#ifndef USE_LIBAV
302 AV_PIX_FMT_0BGR32,
303#else
304 AV_PIX_FMT_BGR32,
305#endif
306#endif
307 encoder->videoFrame->width, encoder->videoFrame->height, encoder->video->pix_fmt,
308 SWS_POINT, 0, 0, 0);
309 av_image_alloc(encoder->videoFrame->data, encoder->videoFrame->linesize, encoder->video->width, encoder->video->height, encoder->video->pix_fmt, 32);
310
311 avio_open(&encoder->context->pb, outfile, AVIO_FLAG_WRITE);
312 avformat_write_header(encoder->context, 0);
313
314 return true;
315}
316
317void FFmpegEncoderClose(struct FFmpegEncoder* encoder) {
318 if (!encoder->context) {
319 return;
320 }
321 av_write_trailer(encoder->context);
322 avio_close(encoder->context->pb);
323
324 if (encoder->audioCodec) {
325 av_free(encoder->postaudioBuffer);
326 if (encoder->audioBuffer) {
327 av_free(encoder->audioBuffer);
328 }
329#if LIBAVCODEC_VERSION_MAJOR >= 55
330 av_frame_free(&encoder->audioFrame);
331#else
332 avcodec_free_frame(&encoder->audioFrame);
333#endif
334 avcodec_close(encoder->audio);
335
336 if (encoder->resampleContext) {
337 avresample_close(encoder->resampleContext);
338 }
339
340 if (encoder->absf) {
341 av_bitstream_filter_close(encoder->absf);
342 encoder->absf = 0;
343 }
344 }
345
346#if LIBAVCODEC_VERSION_MAJOR >= 55
347 av_frame_free(&encoder->videoFrame);
348#else
349 avcodec_free_frame(&encoder->videoFrame);
350#endif
351 avcodec_close(encoder->video);
352
353 sws_freeContext(encoder->scaleContext);
354
355 avformat_free_context(encoder->context);
356 encoder->context = 0;
357}
358
359bool FFmpegEncoderIsOpen(struct FFmpegEncoder* encoder) {
360 return !!encoder->context;
361}
362
363void _ffmpegPostAudioFrame(struct GBAAVStream* stream, int16_t left, int16_t right) {
364 struct FFmpegEncoder* encoder = (struct FFmpegEncoder*) stream;
365 if (!encoder->context || !encoder->audioCodec) {
366 return;
367 }
368
369 encoder->audioBuffer[encoder->currentAudioSample * 2] = left;
370 encoder->audioBuffer[encoder->currentAudioSample * 2 + 1] = right;
371
372 ++encoder->currentAudioFrame;
373 ++encoder->currentAudioSample;
374
375 if ((encoder->currentAudioSample * 4) < encoder->audioBufferSize) {
376 return;
377 }
378 encoder->currentAudioSample = 0;
379
380 int channelSize = 2 * av_get_bytes_per_sample(encoder->audio->sample_fmt);
381 avresample_convert(encoder->resampleContext,
382 0, 0, 0,
383 (uint8_t**) &encoder->audioBuffer, 0, encoder->audioBufferSize / 4);
384 if (avresample_available(encoder->resampleContext) < encoder->audioFrame->nb_samples) {
385 return;
386 }
387#if LIBAVCODEC_VERSION_MAJOR >= 55
388 av_frame_make_writable(encoder->audioFrame);
389#endif
390 avresample_read(encoder->resampleContext, encoder->audioFrame->data, encoder->postaudioBufferSize / channelSize);
391
392 AVRational timeBase = { 1, PREFERRED_SAMPLE_RATE };
393 encoder->audioFrame->pts = encoder->nextAudioPts;
394 encoder->nextAudioPts = av_rescale_q(encoder->currentAudioFrame, timeBase, encoder->audioStream->time_base);
395
396 AVPacket packet;
397 av_init_packet(&packet);
398 packet.data = 0;
399 packet.size = 0;
400 int gotData;
401 avcodec_encode_audio2(encoder->audio, &packet, encoder->audioFrame, &gotData);
402 if (gotData) {
403 if (encoder->absf) {
404 AVPacket tempPacket = packet;
405 int success = av_bitstream_filter_filter(encoder->absf, encoder->audio, 0,
406 &tempPacket.data, &tempPacket.size,
407 packet.data, packet.size, 0);
408 if (success > 0) {
409#if LIBAVUTIL_VERSION_MAJOR >= 53
410 tempPacket.buf = av_buffer_create(tempPacket.data, tempPacket.size, av_buffer_default_free, 0, 0);
411#endif
412 av_free_packet(&packet);
413 }
414 packet = tempPacket;
415 }
416 packet.stream_index = encoder->audioStream->index;
417 av_interleaved_write_frame(encoder->context, &packet);
418 }
419 av_free_packet(&packet);
420}
421
422void _ffmpegPostVideoFrame(struct GBAAVStream* stream, struct GBAVideoRenderer* renderer) {
423 struct FFmpegEncoder* encoder = (struct FFmpegEncoder*) stream;
424 if (!encoder->context) {
425 return;
426 }
427 const uint8_t* pixels;
428 unsigned stride;
429 renderer->getPixels(renderer, &stride, (const void**) &pixels);
430 stride *= BYTES_PER_PIXEL;
431
432 AVPacket packet;
433
434 av_init_packet(&packet);
435 packet.data = 0;
436 packet.size = 0;
437#if LIBAVCODEC_VERSION_MAJOR >= 55
438 av_frame_make_writable(encoder->videoFrame);
439#endif
440 encoder->videoFrame->pts = av_rescale_q(encoder->currentVideoFrame, encoder->video->time_base, encoder->videoStream->time_base);
441 ++encoder->currentVideoFrame;
442
443 sws_scale(encoder->scaleContext, (const uint8_t* const*) &pixels, (const int*) &stride, 0, VIDEO_VERTICAL_PIXELS, encoder->videoFrame->data, encoder->videoFrame->linesize);
444
445 int gotData;
446 avcodec_encode_video2(encoder->video, &packet, encoder->videoFrame, &gotData);
447 if (gotData) {
448 if (encoder->videoStream->codec->coded_frame->key_frame) {
449 packet.flags |= AV_PKT_FLAG_KEY;
450 }
451 packet.stream_index = encoder->videoStream->index;
452 av_interleaved_write_frame(encoder->context, &packet);
453 }
454 av_free_packet(&packet);
455}