diff options
author | Joerg Mueller <nexyon@gmail.com> | 2010-02-08 02:41:17 +0300 |
---|---|---|
committer | Joerg Mueller <nexyon@gmail.com> | 2010-02-08 02:41:17 +0300 |
commit | 9827a3e9eac70f68db6dc16d03016c51b7ece3f0 (patch) | |
tree | 8825b454008d3b97a64018884c179ea94874af44 /source/blender/blenkernel/intern/writeffmpeg.c | |
parent | 2f72b91a54faa7cfbdfd97eff608c8911df1d221 (diff) |
2.5 Audio:
- recode of the whole sequencer audio handling
- encode audio flag removed, instead you choose None as audio codec, added None for video codec too
- ffmpeg formats/codecs: enabled: theora, ogg, vorbis; added: matroska, flac (not working, who can fix?), mp3, wav
- sequencer wave drawing
- volume animation (now also working when mixing down to a file!)
- made sequencer strip position and length values unanimatable
Diffstat (limited to 'source/blender/blenkernel/intern/writeffmpeg.c')
-rw-r--r-- | source/blender/blenkernel/intern/writeffmpeg.c | 170 |
1 files changed, 87 insertions, 83 deletions
diff --git a/source/blender/blenkernel/intern/writeffmpeg.c b/source/blender/blenkernel/intern/writeffmpeg.c index 9c38f84aa26..3aca9ffb4e7 100644 --- a/source/blender/blenkernel/intern/writeffmpeg.c +++ b/source/blender/blenkernel/intern/writeffmpeg.c @@ -15,7 +15,6 @@ * */ - #ifdef WITH_FFMPEG #include <string.h> #include <stdio.h> @@ -78,11 +77,10 @@ extern void do_init_ffmpeg(); static int ffmpeg_type = 0; static int ffmpeg_codec = CODEC_ID_MPEG4; -static int ffmpeg_audio_codec = CODEC_ID_MP2; +static int ffmpeg_audio_codec = CODEC_ID_NONE; static int ffmpeg_video_bitrate = 1150; static int ffmpeg_audio_bitrate = 128; static int ffmpeg_gop_size = 12; -static int ffmpeg_multiplex_audio = 1; static int ffmpeg_autosplit = 0; static int ffmpeg_autosplit_count = 0; @@ -99,6 +97,7 @@ static uint8_t* audio_input_buffer = 0; static int audio_input_frame_size = 0; static uint8_t* audio_output_buffer = 0; static int audio_outbuf_size = 0; +static double audio_time = 0.0f; static AUD_Device* audio_mixdown_device = 0; @@ -130,30 +129,43 @@ static int write_audio_frame(void) { AVCodecContext* c = NULL; AVPacket pkt; + AVStream* str = audio_stream; c = get_codec_from_stream(audio_stream); - if(audio_mixdown_device) - AUD_readDevice(audio_mixdown_device, audio_input_buffer, audio_input_frame_size); - av_init_packet(&pkt); + pkt.size = 0; + + AUD_readDevice(audio_mixdown_device, audio_input_buffer, audio_input_frame_size); + audio_time += (double) audio_input_frame_size / (double) c->sample_rate; pkt.size = avcodec_encode_audio(c, audio_output_buffer, - audio_outbuf_size, + audio_outbuf_size, (short*) audio_input_buffer); + + if(pkt.size <= 0) + { + // XXX error("Error writing audio packet"); + return -1; + } + pkt.data = audio_output_buffer; + + if(c->coded_frame && c->coded_frame->pts != AV_NOPTS_VALUE) + { #ifdef FFMPEG_CODEC_TIME_BASE - pkt.pts = av_rescale_q(c->coded_frame->pts, - c->time_base, audio_stream->time_base); + pkt.pts = av_rescale_q(c->coded_frame->pts, + c->time_base, audio_stream->time_base); #else - pkt.pts = c->coded_frame->pts; + pkt.pts = c->coded_frame->pts; #endif - fprintf(stderr, "Audio Frame PTS: %d\n", (int)pkt.pts); + fprintf(stderr, "Audio Frame PTS: %d\n", (int)pkt.pts); + } pkt.stream_index = audio_stream->index; pkt.flags |= PKT_FLAG_KEY; if (av_interleaved_write_frame(outfile, &pkt) != 0) { - //XXX error("Error writing audio packet"); + // XXX error("Error writing audio packet"); return -1; } return 0; @@ -233,6 +245,14 @@ static const char** get_file_extensions(int format) static const char * rv[] = { ".ogg", ".ogv", NULL }; return rv; } + case FFMPEG_MP3: { + static const char * rv[] = { ".mp3", NULL }; + return rv; + } + case FFMPEG_WAV: { + static const char * rv[] = { ".wav", NULL }; + return rv; + } default: return NULL; } @@ -563,6 +583,7 @@ static AVStream* alloc_audio_stream(RenderData *rd, int codec_id, AVFormatContex c->sample_rate = rd->ffcodecdata.audio_mixrate; c->bit_rate = ffmpeg_audio_bitrate*1000; + c->sample_fmt = SAMPLE_FMT_S16; c->channels = 2; codec = avcodec_find_encoder(c->codec_id); if (!codec) { @@ -577,40 +598,22 @@ static AVStream* alloc_audio_stream(RenderData *rd, int codec_id, AVFormatContex return NULL; } - /* FIXME: Should be user configurable */ - if (ffmpeg_type == FFMPEG_DV) { - /* this is a hack around the poor ffmpeg dv multiplexer. */ - /* only fixes PAL for now - (NTSC is a lot more complicated here...)! */ - audio_outbuf_size = 7680; - } else { - audio_outbuf_size = 10000; - } + audio_outbuf_size = FF_MIN_BUFFER_SIZE; + audio_output_buffer = (uint8_t*)MEM_mallocN( audio_outbuf_size, "FFMPEG audio encoder input buffer"); - /* ugly hack for PCM codecs */ - - if (c->frame_size <= 1) { - audio_input_frame_size = audio_outbuf_size / c->channels; - switch(c->codec_id) { - case CODEC_ID_PCM_S16LE: - case CODEC_ID_PCM_S16BE: - case CODEC_ID_PCM_U16LE: - case CODEC_ID_PCM_U16BE: - audio_input_frame_size >>= 1; - break; - default: - break; - } - } else { + if((c->codec_id >= CODEC_ID_PCM_S16LE) && (c->codec_id <= CODEC_ID_PCM_DVD)) + audio_input_frame_size = audio_outbuf_size * 8 / c->bits_per_coded_sample / c->channels; + else audio_input_frame_size = c->frame_size; - } audio_input_buffer = (uint8_t*)MEM_mallocN( - audio_input_frame_size * sizeof(short) * c->channels, + audio_input_frame_size * c->channels * sizeof(int16_t), "FFMPEG audio encoder output buffer"); + audio_time = 0.0f; + return st; } /* essential functions -- start, append, end */ @@ -629,8 +632,6 @@ static int start_ffmpeg_impl(struct RenderData *rd, int rectx, int recty, Report ffmpeg_video_bitrate = rd->ffcodecdata.video_bitrate; ffmpeg_audio_bitrate = rd->ffcodecdata.audio_bitrate; ffmpeg_gop_size = rd->ffcodecdata.gop_size; - ffmpeg_multiplex_audio = rd->ffcodecdata.flags - & FFMPEG_MULTIPLEX_AUDIO; ffmpeg_autosplit = rd->ffcodecdata.flags & FFMPEG_AUTOSPLIT_OUTPUT; @@ -641,12 +642,11 @@ static int start_ffmpeg_impl(struct RenderData *rd, int rectx, int recty, Report fprintf(stderr, "Starting output to %s(ffmpeg)...\n" " Using type=%d, codec=%d, audio_codec=%d,\n" " video_bitrate=%d, audio_bitrate=%d,\n" - " gop_size=%d, multiplex=%d, autosplit=%d\n" + " gop_size=%d, autosplit=%d\n" " render width=%d, render height=%d\n", name, ffmpeg_type, ffmpeg_codec, ffmpeg_audio_codec, ffmpeg_video_bitrate, ffmpeg_audio_bitrate, - ffmpeg_gop_size, ffmpeg_multiplex_audio, - ffmpeg_autosplit, rectx, recty); + ffmpeg_gop_size, ffmpeg_autosplit, rectx, recty); exts = get_file_extensions(ffmpeg_type); if (!exts) { @@ -667,7 +667,7 @@ static int start_ffmpeg_impl(struct RenderData *rd, int rectx, int recty, Report of->oformat = fmt; of->packet_size= rd->ffcodecdata.mux_packet_size; - if (ffmpeg_multiplex_audio) { + if (ffmpeg_audio_codec != CODEC_ID_NONE) { of->mux_rate = rd->ffcodecdata.mux_rate; } else { of->mux_rate = 0; @@ -676,6 +676,8 @@ static int start_ffmpeg_impl(struct RenderData *rd, int rectx, int recty, Report of->preload = (int)(0.5*AV_TIME_BASE); of->max_delay = (int)(0.7*AV_TIME_BASE); + fmt->audio_codec = ffmpeg_audio_codec; + snprintf(of->filename, sizeof(of->filename), "%s", name); /* set the codec to the user's selection */ switch(ffmpeg_type) { @@ -703,6 +705,11 @@ static int start_ffmpeg_impl(struct RenderData *rd, int rectx, int recty, Report case FFMPEG_FLV: fmt->video_codec = CODEC_ID_FLV1; break; + case FFMPEG_MP3: + fmt->audio_codec = CODEC_ID_MP3; + case FFMPEG_WAV: + fmt->video_codec = CODEC_ID_NONE; + break; case FFMPEG_MPEG4: default: fmt->video_codec = CODEC_ID_MPEG4; @@ -723,30 +730,29 @@ static int start_ffmpeg_impl(struct RenderData *rd, int rectx, int recty, Report } } - fmt->audio_codec = ffmpeg_audio_codec; - if (ffmpeg_type == FFMPEG_DV) { fmt->audio_codec = CODEC_ID_PCM_S16LE; - if (ffmpeg_multiplex_audio && rd->ffcodecdata.audio_mixrate != 48000) { + if (ffmpeg_audio_codec != CODEC_ID_NONE && rd->ffcodecdata.audio_mixrate != 48000) { BKE_report(reports, RPT_ERROR, "FFMPEG only supports 48khz / stereo audio for DV!"); return 0; } } - video_stream = alloc_video_stream(rd, fmt->video_codec, of, rectx, recty); - printf("alloc video stream %p\n", video_stream); - if (!video_stream) { - BKE_report(reports, RPT_ERROR, "Error initializing video stream."); - return 0; + if (fmt->video_codec != CODEC_ID_NONE) { + video_stream = alloc_video_stream(rd, fmt->video_codec, of, rectx, recty); + printf("alloc video stream %p\n", video_stream); + if (!video_stream) { + BKE_report(reports, RPT_ERROR, "Error initializing video stream."); + return 0; + } } - - if (ffmpeg_multiplex_audio) { + + if (ffmpeg_audio_codec != CODEC_ID_NONE) { audio_stream = alloc_audio_stream(rd, fmt->audio_codec, of); if (!audio_stream) { BKE_report(reports, RPT_ERROR, "Error initializing audio stream."); return 0; } - //XXX audiostream_play(SFRA, 0, 1); } if (av_set_parameters(of, NULL) < 0) { BKE_report(reports, RPT_ERROR, "Error setting output parameters."); @@ -818,14 +824,14 @@ int start_ffmpeg(struct Scene *scene, RenderData *rd, int rectx, int recty, Repo success = start_ffmpeg_impl(rd, rectx, recty, reports); - if(ffmpeg_multiplex_audio && audio_stream) + if(audio_stream) { AVCodecContext* c = get_codec_from_stream(audio_stream); AUD_DeviceSpecs specs; specs.channels = c->channels; specs.format = AUD_FORMAT_S16; specs.rate = rd->ffcodecdata.audio_mixrate; - audio_mixdown_device = sound_mixdown(scene, specs, rd->sfra, rd->efra, rd->ffcodecdata.audio_volume); + audio_mixdown_device = sound_mixdown(scene, specs, rd->sfra, rd->ffcodecdata.audio_volume); } return success; @@ -833,21 +839,13 @@ int start_ffmpeg(struct Scene *scene, RenderData *rd, int rectx, int recty, Repo void end_ffmpeg(void); -static void write_audio_frames() +static void write_audio_frames(double to_pts) { int finished = 0; - while (ffmpeg_multiplex_audio && !finished) { - double a_pts = ((double)audio_stream->pts.val - * audio_stream->time_base.num - / audio_stream->time_base.den); - double v_pts = ((double)video_stream->pts.val - * video_stream->time_base.num - / video_stream->time_base.den); - - if (a_pts < v_pts) { - write_audio_frame(); - } else { + while (audio_stream && !finished) { + if((audio_time >= to_pts) || + (write_audio_frame())) { finished = 1; } } @@ -856,25 +854,31 @@ static void write_audio_frames() int append_ffmpeg(RenderData *rd, int frame, int *pixels, int rectx, int recty, ReportList *reports) { AVFrame* avframe; - int success; + int success = 1; fprintf(stderr, "Writing frame %i, " "render width=%d, render height=%d\n", frame, rectx, recty); - write_audio_frames(); +// why is this done before writing the video frame and again at end_ffmpeg? +// write_audio_frames(frame / (((double)rd->frs_sec) / rd->frs_sec_base)); - avframe= generate_video_frame((unsigned char*) pixels, reports); - success= (avframe && write_video_frame(rd, avframe, reports)); - - if (ffmpeg_autosplit) { - if (url_ftell(OUTFILE_PB) > FFMPEG_AUTOSPLIT_SIZE) { - end_ffmpeg(); - ffmpeg_autosplit_count++; - success &= start_ffmpeg_impl(rd, rectx, recty, reports); + if(video_stream) + { + avframe= generate_video_frame((unsigned char*) pixels, reports); + success= (avframe && write_video_frame(rd, avframe, reports)); + + if (ffmpeg_autosplit) { + if (url_ftell(OUTFILE_PB) > FFMPEG_AUTOSPLIT_SIZE) { + end_ffmpeg(); + ffmpeg_autosplit_count++; + success &= start_ffmpeg_impl(rd, rectx, recty, reports); + } } } + write_audio_frames(frame / (((double)rd->frs_sec) / rd->frs_sec_base)); + return success; } @@ -885,9 +889,9 @@ void end_ffmpeg(void) fprintf(stderr, "Closing ffmpeg...\n"); - if (audio_stream && video_stream) { +/* if (audio_stream) { SEE UPPER write_audio_frames(); - } + }*/ if(audio_mixdown_device) { @@ -1259,8 +1263,8 @@ void ffmpeg_verify_image_type(RenderData *rd) } } - if(audio && rd->ffcodecdata.audio_codec <= 0) { - rd->ffcodecdata.audio_codec = CODEC_ID_MP2; + if(audio && rd->ffcodecdata.audio_codec < 0) { + rd->ffcodecdata.audio_codec = CODEC_ID_NONE; rd->ffcodecdata.audio_bitrate = 128; } } |