diff --git a/source/blender/blenkernel/intern/writeffmpeg.c b/source/blender/blenkernel/intern/writeffmpeg.c index a88a9e4954b..f671a3cfc05 100644 --- a/source/blender/blenkernel/intern/writeffmpeg.c +++ b/source/blender/blenkernel/intern/writeffmpeg.c @@ -88,10 +88,11 @@ static uint8_t *video_buffer = 0; static int video_buffersize = 0; static uint8_t *audio_input_buffer = 0; +static uint8_t *audio_deinterleave_buffer = 0; static int audio_input_samples = 0; -static uint8_t *audio_output_buffer = 0; -static int audio_outbuf_size = 0; static double audio_time = 0.0f; +static bool audio_deinterleave = false; +static int audio_sample_size = 0; #ifdef WITH_AUDASPACE static AUD_Device *audio_mixdown_device = 0; @@ -122,37 +123,67 @@ static int write_audio_frame(void) { AVCodecContext *c = NULL; AVPacket pkt; + AVFrame* frame; + int got_output = 0; c = audio_stream->codec; av_init_packet(&pkt); pkt.size = 0; + pkt.data = NULL; + + frame = avcodec_alloc_frame(); + frame->nb_samples = audio_input_samples; + frame->format = c->sample_fmt; + frame->channel_layout = c->channel_layout; AUD_readDevice(audio_mixdown_device, audio_input_buffer, audio_input_samples); audio_time += (double) audio_input_samples / (double) c->sample_rate; - pkt.size = avcodec_encode_audio(c, audio_output_buffer, audio_outbuf_size, (short *) audio_input_buffer); + if(audio_deinterleave) { + int channel, i; + uint8_t* temp; - if (pkt.size < 0) { + for(channel = 0; channel < c->channels; channel++) { + for(i = 0; i < frame->nb_samples; i++) { + memcpy(audio_deinterleave_buffer + (i + channel * frame->nb_samples) * audio_sample_size, + audio_input_buffer + (c->channels * i + channel) * audio_sample_size, audio_sample_size); + } + } + + temp = audio_deinterleave_buffer; + audio_deinterleave_buffer = audio_input_buffer; + audio_input_buffer = temp; + } + + avcodec_fill_audio_frame(frame, c->channels, c->sample_fmt, audio_input_buffer, + audio_input_samples * c->channels * audio_sample_size, 0); + + if(avcodec_encode_audio2(c, &pkt, frame, &got_output) < 0) { // XXX error("Error writing audio packet"); return -1; } - pkt.data = audio_output_buffer; + if(got_output) { + if (c->coded_frame && c->coded_frame->pts != AV_NOPTS_VALUE) { + pkt.pts = av_rescale_q(c->coded_frame->pts, c->time_base, audio_stream->time_base); + PRINT("Audio Frame PTS: %d\n", (int) pkt.pts); + } - if (c->coded_frame && c->coded_frame->pts != AV_NOPTS_VALUE) { - pkt.pts = av_rescale_q(c->coded_frame->pts, c->time_base, audio_stream->time_base); - PRINT("Audio Frame PTS: %d\n", (int) pkt.pts); + pkt.stream_index = audio_stream->index; + + pkt.flags |= AV_PKT_FLAG_KEY; + + if (av_interleaved_write_frame(outfile, &pkt) != 0) { + fprintf(stderr, "Error writing audio packet!\n"); + return -1; + } + + av_free_packet(&pkt); } - pkt.stream_index = audio_stream->index; + avcodec_free_frame(&frame); - pkt.flags |= AV_PKT_FLAG_KEY; - - if (av_interleaved_write_frame(outfile, &pkt) != 0) { - fprintf(stderr, "Error writing audio packet!\n"); - return -1; - } return 0; } #endif // #ifdef WITH_AUDASPACE @@ -608,8 +639,6 @@ static AVStream *alloc_video_stream(RenderData *rd, int codec_id, AVFormatContex return st; } -/* Prepare an audio stream for the output file */ - static AVStream *alloc_audio_stream(RenderData *rd, int codec_id, AVFormatContext *of, char *error, int error_size) { AVStream *st; @@ -659,11 +688,6 @@ static AVStream *alloc_audio_stream(RenderData *rd, int codec_id, AVFormatContex } } - 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; @@ -692,24 +716,23 @@ static AVStream *alloc_audio_stream(RenderData *rd, int codec_id, AVFormatContex st->codec->time_base.num = 1; st->codec->time_base.den = st->codec->sample_rate; - audio_outbuf_size = FF_MIN_BUFFER_SIZE; - - if ((c->codec_id >= CODEC_ID_PCM_S16LE) && (c->codec_id <= CODEC_ID_PCM_DVD)) - audio_input_samples = audio_outbuf_size * 8 / c->bits_per_coded_sample / c->channels; + if (c->frame_size == 0) + // used to be if((c->codec_id >= CODEC_ID_PCM_S16LE) && (c->codec_id <= CODEC_ID_PCM_DVD)) + // not sure if that is needed anymore, so let's try out if there are any + // complaints regarding some ffmpeg versions users might have + audio_input_samples = FF_MIN_BUFFER_SIZE * 8 / c->bits_per_coded_sample / c->channels; else { audio_input_samples = c->frame_size; - if (c->frame_size * c->channels * sizeof(int16_t) * 4 > audio_outbuf_size) - audio_outbuf_size = c->frame_size * c->channels * sizeof(int16_t) * 4; } - audio_output_buffer = (uint8_t *) av_malloc(audio_outbuf_size); + audio_deinterleave = av_sample_fmt_is_planar(c->sample_fmt); - 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(int16_t)); - } + audio_sample_size = av_get_bytes_per_sample(c->sample_fmt); + + audio_input_buffer = (uint8_t *) av_malloc(audio_input_samples * c->channels * audio_sample_size); + + if(audio_deinterleave) + audio_deinterleave_buffer = (uint8_t *) av_malloc(audio_input_samples * c->channels * audio_sample_size); audio_time = 0.0f; @@ -1010,12 +1033,28 @@ 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; - if (c->sample_fmt == AV_SAMPLE_FMT_FLT) { - specs.format = AUD_FORMAT_FLOAT32; - } - else { + + switch(av_get_packed_sample_fmt(c->sample_fmt)) + { + case AV_SAMPLE_FMT_U8: + specs.format = AUD_FORMAT_U8; + break; + case AV_SAMPLE_FMT_S16: specs.format = AUD_FORMAT_S16; + break; + case AV_SAMPLE_FMT_S32: + specs.format = AUD_FORMAT_S32; + break; + case AV_SAMPLE_FMT_FLT: + specs.format = AUD_FORMAT_FLOAT32; + break; + case AV_SAMPLE_FMT_DBL: + specs.format = AUD_FORMAT_FLOAT64; + break; + default: + return -31415; } + specs.rate = rd->ffcodecdata.audio_mixrate; audio_mixdown_device = sound_mixdown(scene, specs, rd->sfra, rd->ffcodecdata.audio_volume); #ifdef FFMPEG_CODEC_TIME_BASE @@ -1138,15 +1177,16 @@ static void end_ffmpeg_impl(int is_autosplit) MEM_freeN(video_buffer); video_buffer = 0; } - if (audio_output_buffer) { - av_free(audio_output_buffer); - audio_output_buffer = 0; - } if (audio_input_buffer) { av_free(audio_input_buffer); audio_input_buffer = 0; } + if (audio_deinterleave_buffer) { + av_free(audio_deinterleave_buffer); + audio_deinterleave_buffer = 0; + } + if (img_convert_ctx) { sws_freeContext(img_convert_ctx); img_convert_ctx = 0;