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
This commit is contained in:
2010-02-07 23:41:17 +00:00
parent 2f72b91a54
commit 9827a3e9ea
37 changed files with 1108 additions and 514 deletions

View File

@@ -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(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);
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;
}
}