Patch #34204: [Render Animation] Fails with "Error: Specified sample_fmt is not suppo...
[blender.git] / source / blender / blenkernel / intern / writeffmpeg.c
index af8b32a..082ae38 100644 (file)
@@ -111,8 +111,9 @@ static void delete_picture(AVFrame *f)
        }
 }
 
        }
 }
 
-static int use_float_audio_buffer(int codec_id)
+static int request_float_audio_buffer(int codec_id)
 {
 {
+       /* If any of these codecs, we prefer the float sample format (if supported) */
        return codec_id == CODEC_ID_AAC || codec_id == CODEC_ID_AC3 || codec_id == CODEC_ID_VORBIS;
 }
 
        return codec_id == CODEC_ID_AAC || codec_id == CODEC_ID_AC3 || codec_id == CODEC_ID_VORBIS;
 }
 
@@ -629,16 +630,55 @@ static AVStream *alloc_audio_stream(RenderData *rd, int codec_id, AVFormatContex
        c->bit_rate = ffmpeg_audio_bitrate * 1000;
        c->sample_fmt = AV_SAMPLE_FMT_S16;
        c->channels = rd->ffcodecdata.audio_channels;
        c->bit_rate = ffmpeg_audio_bitrate * 1000;
        c->sample_fmt = AV_SAMPLE_FMT_S16;
        c->channels = rd->ffcodecdata.audio_channels;
-       if (use_float_audio_buffer(codec_id)) {
+
+       if (request_float_audio_buffer(codec_id)) {
+               /* mainly for AAC codec which is experimental */
                c->strict_std_compliance = FF_COMPLIANCE_EXPERIMENTAL;
                c->sample_fmt = AV_SAMPLE_FMT_FLT;
        }
                c->strict_std_compliance = FF_COMPLIANCE_EXPERIMENTAL;
                c->sample_fmt = AV_SAMPLE_FMT_FLT;
        }
+
        codec = avcodec_find_encoder(c->codec_id);
        if (!codec) {
                //XXX error("Couldn't find a valid audio codec");
                return NULL;
        }
 
        codec = avcodec_find_encoder(c->codec_id);
        if (!codec) {
                //XXX error("Couldn't find a valid audio codec");
                return NULL;
        }
 
+       if (codec->sample_fmts) {
+               /* check if the prefered sample format for this codec is supported.
+                * this is because, depending on the version of libav, and with the whole ffmpeg/libav fork situation,
+                * you have various implementations around. float samples in particular are not always supported.
+                */
+               const enum AVSampleFormat *p = codec->sample_fmts;
+               for (; *p!=-1; p++) {
+                       if (*p == st->codec->sample_fmt)
+                               break;
+               }
+               if (*p == -1) {
+                       /* sample format incompatible with codec. Defaulting to a format known to work */
+                       st->codec->sample_fmt = codec->sample_fmts[0];
+               }
+       }
+
+       if (c->sample_fmt == AV_SAMPLE_FMT_FLTP) {
+               BLI_strncpy(error, "Requested audio codec requires planar float sample format, which is not supported yet", error_size);
+               return NULL;
+       }
+
+       if (codec->supported_samplerates) {
+               const int *p = codec->supported_samplerates;
+               int best = 0;
+               int best_dist = INT_MAX;
+               for (; *p; p++){
+                       int dist = abs(st->codec->sample_rate - *p);
+                       if (dist < best_dist){
+                               best_dist = dist;
+                               best = *p;
+                       }
+               }
+               /* best is the closest supported sample rate (same as selected if best_dist == 0) */
+               st->codec->sample_rate = best;
+       }
+
        set_ffmpeg_properties(rd, c, "audio");
 
        if (avcodec_open2(c, codec, NULL) < 0) {
        set_ffmpeg_properties(rd, c, "audio");
 
        if (avcodec_open2(c, codec, NULL) < 0) {
@@ -664,7 +704,7 @@ static AVStream *alloc_audio_stream(RenderData *rd, int codec_id, AVFormatContex
 
        audio_output_buffer = (uint8_t *) av_malloc(audio_outbuf_size);
 
 
        audio_output_buffer = (uint8_t *) av_malloc(audio_outbuf_size);
 
-       if (use_float_audio_buffer(codec_id)) {
+       if (c->sample_fmt == AV_SAMPLE_FMT_FLT) {
                audio_input_buffer = (uint8_t *) av_malloc(audio_input_samples * c->channels * sizeof(float));
        }
        else {
                audio_input_buffer = (uint8_t *) av_malloc(audio_input_samples * c->channels * sizeof(float));
        }
        else {
@@ -970,7 +1010,7 @@ int BKE_ffmpeg_start(struct Scene *scene, RenderData *rd, int rectx, int recty,
                AVCodecContext *c = audio_stream->codec;
                AUD_DeviceSpecs specs;
                specs.channels = c->channels;
                AVCodecContext *c = audio_stream->codec;
                AUD_DeviceSpecs specs;
                specs.channels = c->channels;
-               if (use_float_audio_buffer(c->codec_id)) {
+               if (c->sample_fmt == AV_SAMPLE_FMT_FLT) {
                        specs.format = AUD_FORMAT_FLOAT32;
                }
                else {
                        specs.format = AUD_FORMAT_FLOAT32;
                }
                else {