Blender V5.0
movie_write_audio.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2024 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
8
9#ifdef _MSC_VER
10/* This needs to be included first to prevent ffmpegs headers adding defines for various math
11 * constants leading to duplicate definitions. */
12# define _USE_MATH_DEFINES
13# include <cmath>
14#endif
15
16#include "movie_util.hh"
17#include "movie_write.hh"
18
19#ifdef WITH_FFMPEG
20
21# include <cstdio>
22# include <cstring>
23
24# ifdef WITH_AUDASPACE
25# include <AUD_Device.h>
26# include <AUD_Special.h>
27# endif
28
29# include "DNA_scene_types.h"
30
31# include "BLI_string.h"
32# include "BLI_utildefines.h"
33
34# include "BKE_report.hh"
35# include "BKE_sound.h"
36
37# include "CLG_log.h"
38
39static CLG_LogRef LOG = {"video.write"};
40
41/* If any of these codecs, we prefer the float sample format (if supported) */
42static bool request_float_audio_buffer(int codec_id)
43{
44 return ELEM(codec_id, AV_CODEC_ID_AAC, AV_CODEC_ID_AC3, AV_CODEC_ID_VORBIS);
45}
46
47# ifdef WITH_AUDASPACE
48
49static int write_audio_frame(MovieWriter *context)
50{
51 AVFrame *frame = nullptr;
52 AVCodecContext *c = context->audio_codec;
53
54 AUD_Device_read(
55 context->audio_mixdown_device, context->audio_input_buffer, context->audio_input_samples);
56
57 frame = av_frame_alloc();
58 frame->pts = context->audio_time / av_q2d(c->time_base);
59 frame->nb_samples = context->audio_input_samples;
60 frame->format = c->sample_fmt;
61# ifdef FFMPEG_USE_OLD_CHANNEL_VARS
62 frame->channels = c->channels;
63 frame->channel_layout = c->channel_layout;
64 const int num_channels = c->channels;
65# else
66 av_channel_layout_copy(&frame->ch_layout, &c->ch_layout);
67 const int num_channels = c->ch_layout.nb_channels;
68# endif
69
70 if (context->audio_deinterleave) {
71 int channel, i;
72 uint8_t *temp;
73
74 for (channel = 0; channel < num_channels; channel++) {
75 for (i = 0; i < frame->nb_samples; i++) {
76 memcpy(context->audio_deinterleave_buffer +
77 (i + channel * frame->nb_samples) * context->audio_sample_size,
78 context->audio_input_buffer +
79 (num_channels * i + channel) * context->audio_sample_size,
80 context->audio_sample_size);
81 }
82 }
83
84 temp = context->audio_deinterleave_buffer;
85 context->audio_deinterleave_buffer = context->audio_input_buffer;
86 context->audio_input_buffer = temp;
87 }
88
89 avcodec_fill_audio_frame(frame,
90 num_channels,
91 c->sample_fmt,
92 context->audio_input_buffer,
93 context->audio_input_samples * num_channels *
94 context->audio_sample_size,
95 1);
96
97 int success = 1;
98
99 char error_str[AV_ERROR_MAX_STRING_SIZE];
100 int ret = avcodec_send_frame(c, frame);
101 if (ret < 0) {
102 /* Can't send frame to encoder. This shouldn't happen. */
103 av_make_error_string(error_str, AV_ERROR_MAX_STRING_SIZE, ret);
104 CLOG_ERROR(&LOG, "Can't send audio frame: %s", error_str);
105 success = -1;
106 }
107
108 AVPacket *pkt = av_packet_alloc();
109
110 while (ret >= 0) {
111
112 ret = avcodec_receive_packet(c, pkt);
113 if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) {
114 break;
115 }
116 if (ret < 0) {
117 av_make_error_string(error_str, AV_ERROR_MAX_STRING_SIZE, ret);
118 CLOG_ERROR(&LOG, "Error encoding audio frame: %s", error_str);
119 success = -1;
120 }
121
122 pkt->stream_index = context->audio_stream->index;
123 av_packet_rescale_ts(pkt, c->time_base, context->audio_stream->time_base);
124# ifdef FFMPEG_USE_DURATION_WORKAROUND
125 my_guess_pkt_duration(context->outfile, context->audio_stream, pkt);
126# endif
127
128 pkt->flags |= AV_PKT_FLAG_KEY;
129
130 int write_ret = av_interleaved_write_frame(context->outfile, pkt);
131 if (write_ret != 0) {
132 av_make_error_string(error_str, AV_ERROR_MAX_STRING_SIZE, ret);
133 CLOG_ERROR(&LOG, "Error writing audio packet: %s", error_str);
134 success = -1;
135 break;
136 }
137 }
138
139 av_packet_free(&pkt);
140 av_frame_free(&frame);
141
142 return success;
143}
144# endif /* #ifdef WITH_AUDASPACE */
145
146bool movie_audio_open(MovieWriter *context,
147 const Scene *scene,
148 int start_frame,
149 int mixrate,
150 float volume,
151 ReportList *reports)
152{
153 bool success = true;
154# ifdef WITH_AUDASPACE
155 if (context->audio_stream) {
156 AVCodecContext *c = context->audio_codec;
157
158 AUD_DeviceSpecs specs;
159# ifdef FFMPEG_USE_OLD_CHANNEL_VARS
160 specs.channels = AUD_Channels(c->channels);
161# else
162 specs.channels = AUD_Channels(c->ch_layout.nb_channels);
163# endif
164
165 switch (av_get_packed_sample_fmt(c->sample_fmt)) {
166 case AV_SAMPLE_FMT_U8:
167 specs.format = AUD_FORMAT_U8;
168 break;
169 case AV_SAMPLE_FMT_S16:
170 specs.format = AUD_FORMAT_S16;
171 break;
172 case AV_SAMPLE_FMT_S32:
173 specs.format = AUD_FORMAT_S32;
174 break;
175 case AV_SAMPLE_FMT_FLT:
176 specs.format = AUD_FORMAT_FLOAT32;
177 break;
178 case AV_SAMPLE_FMT_DBL:
179 specs.format = AUD_FORMAT_FLOAT64;
180 break;
181 default:
182 BKE_report(reports, RPT_ERROR, "Audio sample format unsupported");
183 success = false;
184 break;
185 }
186
187 specs.rate = mixrate;
188 if (success) {
189 context->audio_mixdown_device = BKE_sound_mixdown(scene, specs, start_frame, volume);
190 }
191 }
192# else
193 UNUSED_VARS(context, scene, start_frame, mixrate, volume, reports);
194# endif
195 return success;
196}
197
198void movie_audio_close(MovieWriter *context, bool is_autosplit)
199{
200# ifdef WITH_AUDASPACE
201 if (!is_autosplit) {
202 if (context->audio_mixdown_device) {
203 AUD_Device_free(context->audio_mixdown_device);
204 context->audio_mixdown_device = nullptr;
205 }
206 }
207# else
208 UNUSED_VARS(context, is_autosplit);
209# endif
210}
211
212AVStream *alloc_audio_stream(MovieWriter *context,
213 int audio_mixrate,
214 int audio_channels,
215 AVCodecID codec_id,
216 AVFormatContext *of,
217 char *error,
218 int error_size)
219{
220 AVStream *st;
221 const AVCodec *codec;
222
223 error[0] = '\0';
224
225 st = avformat_new_stream(of, nullptr);
226 if (!st) {
227 return nullptr;
228 }
229 st->id = 1;
230
231 codec = avcodec_find_encoder(codec_id);
232 if (!codec) {
233 CLOG_ERROR(&LOG, "Couldn't find valid audio codec");
234 context->audio_codec = nullptr;
235 return nullptr;
236 }
237
238 context->audio_codec = avcodec_alloc_context3(codec);
239 AVCodecContext *c = context->audio_codec;
240 c->thread_count = MOV_thread_count();
241 c->thread_type = FF_THREAD_SLICE;
242
243 c->sample_rate = audio_mixrate;
244 c->bit_rate = context->ffmpeg_audio_bitrate * 1000;
245 c->sample_fmt = AV_SAMPLE_FMT_S16;
246
247 int channel_layout_mask = 0;
248 switch (audio_channels) {
250 channel_layout_mask = AV_CH_LAYOUT_MONO;
251 break;
253 channel_layout_mask = AV_CH_LAYOUT_STEREO;
254 break;
256 channel_layout_mask = AV_CH_LAYOUT_QUAD;
257 break;
259 channel_layout_mask = AV_CH_LAYOUT_5POINT1_BACK;
260 break;
262 channel_layout_mask = AV_CH_LAYOUT_7POINT1;
263 break;
264 }
265 BLI_assert(channel_layout_mask != 0);
266
267# ifdef FFMPEG_USE_OLD_CHANNEL_VARS
268 c->channels = audio_channels;
269 c->channel_layout = channel_layout_mask;
270# else
271 av_channel_layout_from_mask(&c->ch_layout, channel_layout_mask);
272# endif
273
274 if (request_float_audio_buffer(codec_id)) {
275 /* mainly for AAC codec which is experimental */
276 c->strict_std_compliance = FF_COMPLIANCE_EXPERIMENTAL;
277 c->sample_fmt = AV_SAMPLE_FMT_FLT;
278 }
279
280 const enum AVSampleFormat *sample_fmts = ffmpeg_get_sample_fmts(c, codec);
281 if (sample_fmts) {
282 /* Check if the preferred sample format for this codec is supported.
283 * this is because, depending on the version of LIBAV,
284 * and with the whole FFMPEG/LIBAV fork situation,
285 * you have various implementations around.
286 * Float samples in particular are not always supported. */
287 const enum AVSampleFormat *p = sample_fmts;
288 for (; *p != -1; p++) {
289 if (*p == c->sample_fmt) {
290 break;
291 }
292 }
293 if (*p == -1) {
294 /* sample format incompatible with codec. Defaulting to a format known to work */
295 c->sample_fmt = sample_fmts[0];
296 }
297 }
298
299 const int *supported_samplerates = ffmpeg_get_sample_rates(c, codec);
300 if (supported_samplerates) {
301 const int *p = supported_samplerates;
302 int best = 0;
303 int best_dist = INT_MAX;
304 for (; *p; p++) {
305 int dist = abs(c->sample_rate - *p);
306 if (dist < best_dist) {
307 best_dist = dist;
308 best = *p;
309 }
310 }
311 /* best is the closest supported sample rate (same as selected if best_dist == 0) */
312 c->sample_rate = best;
313 }
314
315 if (of->oformat->flags & AVFMT_GLOBALHEADER) {
316 c->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;
317 }
318
319 int ret = avcodec_open2(c, codec, nullptr);
320
321 if (ret < 0) {
322 char error_str[AV_ERROR_MAX_STRING_SIZE];
323 av_make_error_string(error_str, AV_ERROR_MAX_STRING_SIZE, ret);
324 CLOG_ERROR(&LOG, "Couldn't initialize audio codec: %s", error_str);
325 BLI_strncpy(error, ffmpeg_last_error(), error_size);
326 avcodec_free_context(&c);
327 context->audio_codec = nullptr;
328 return nullptr;
329 }
330
331 /* Need to prevent floating point exception when using VORBIS audio codec,
332 * initialize this value in the same way as it's done in FFMPEG itself (sergey) */
333 c->time_base.num = 1;
334 c->time_base.den = c->sample_rate;
335
336 if (c->codec->capabilities & AV_CODEC_CAP_VARIABLE_FRAME_SIZE) {
337 /* If the audio format has a variable frame size, default to 1024.
338 * This is because we won't try to encode any variable frame size.
339 * 1024 seems to be a good compromize between size and speed.
340 */
341 context->audio_input_samples = 1024;
342 }
343 else {
344 context->audio_input_samples = c->frame_size;
345 }
346
347 context->audio_deinterleave = av_sample_fmt_is_planar(c->sample_fmt);
348
349 context->audio_sample_size = av_get_bytes_per_sample(c->sample_fmt);
350
351 context->audio_input_buffer = (uint8_t *)av_malloc(context->audio_input_samples *
352 audio_channels * context->audio_sample_size);
353 if (context->audio_deinterleave) {
354 context->audio_deinterleave_buffer = (uint8_t *)av_malloc(
355 context->audio_input_samples * audio_channels * context->audio_sample_size);
356 }
357
358 context->audio_time = 0.0f;
359
360 avcodec_parameters_from_context(st->codecpar, c);
361
362 return st;
363}
364
365void write_audio_frames(MovieWriter *context, double to_pts)
366{
367# ifdef WITH_AUDASPACE
368 AVCodecContext *c = context->audio_codec;
369
370 while (context->audio_stream) {
371 if ((context->audio_time_total >= to_pts) || !write_audio_frame(context)) {
372 break;
373 }
374 context->audio_time_total += double(context->audio_input_samples) / double(c->sample_rate);
375 context->audio_time += double(context->audio_input_samples) / double(c->sample_rate);
376 }
377# else
378 UNUSED_VARS(context, to_pts);
379# endif
380}
381
382#endif /* WITH_FFMPEG */
@ RPT_ERROR
Definition BKE_report.hh:39
void BKE_report(ReportList *reports, eReportType type, const char *message)
Definition report.cc:153
#define BLI_assert(a)
Definition BLI_assert.h:46
char * BLI_strncpy(char *__restrict dst, const char *__restrict src, size_t dst_maxncpy) ATTR_NONNULL(1
#define UNUSED_VARS(...)
#define ELEM(...)
#define CLOG_ERROR(clg_ref,...)
Definition CLG_log.h:188
@ FFM_CHANNELS_SURROUND4
@ FFM_CHANNELS_STEREO
@ FFM_CHANNELS_SURROUND51
@ FFM_CHANNELS_SURROUND71
@ FFM_CHANNELS_MONO
FFMPEG_INLINE enum AVSampleFormat * ffmpeg_get_sample_fmts(struct AVCodecContext *context, const AVCodec *codec)
FFMPEG_INLINE const int * ffmpeg_get_sample_rates(struct AVCodecContext *context, const AVCodec *codec)
FFMPEG_INLINE void my_guess_pkt_duration(AVFormatContext *s, AVStream *st, AVPacket *pkt)
#define abs
#define LOG(level)
Definition log.h:97
static void error(const char *str)
int context(const bContext *C, const char *member, bContextDataResult *result)
return ret
i
Definition text_draw.cc:230