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