diff options
21 files changed, 117 insertions, 30 deletions
diff --git a/intern/audaspace/intern/AUD_C-API.cpp b/intern/audaspace/intern/AUD_C-API.cpp index b52243c3fe0..db76b9b4faf 100644 --- a/intern/audaspace/intern/AUD_C-API.cpp +++ b/intern/audaspace/intern/AUD_C-API.cpp @@ -882,16 +882,11 @@ AUD_Handle* AUD_pauseAfter(AUD_Handle* handle, float seconds) AUD_Sound* AUD_createSequencer(int muted, void* data, AUD_volumeFunction volume) { -/* AUD_XXX should be this: but AUD_createSequencer is called before the device - * is initialized. - - return new AUD_SequencerFactory(AUD_device->getSpecs().specs, data, volume); -*/ + // specs are changed at a later point! AUD_Specs specs; specs.channels = AUD_CHANNELS_STEREO; specs.rate = AUD_RATE_44100; AUD_Reference<AUD_SequencerFactory>* sequencer = new AUD_Reference<AUD_SequencerFactory>(new AUD_SequencerFactory(specs, muted, data, volume)); - (*sequencer)->setThis(sequencer); return reinterpret_cast<AUD_Sound*>(sequencer); } @@ -928,6 +923,16 @@ void AUD_muteSequencer(AUD_Sound* sequencer, AUD_Reference<AUD_SequencerEntry>* ((AUD_SequencerFactory*)sequencer->get())->mute(*entry, mute); } +void AUD_setSequencerDeviceSpecs(AUD_Sound* sequencer) +{ + ((AUD_SequencerFactory*)sequencer->get())->setSpecs(AUD_device->getSpecs().specs); +} + +void AUD_setSequencerSpecs(AUD_Sound* sequencer, AUD_Specs specs) +{ + ((AUD_SequencerFactory*)sequencer->get())->setSpecs(specs); +} + int AUD_readSound(AUD_Sound* sound, sample_t* buffer, int length) { AUD_DeviceSpecs specs; diff --git a/intern/audaspace/intern/AUD_C-API.h b/intern/audaspace/intern/AUD_C-API.h index b818140a571..72d423e847b 100644 --- a/intern/audaspace/intern/AUD_C-API.h +++ b/intern/audaspace/intern/AUD_C-API.h @@ -469,6 +469,10 @@ extern void AUD_moveSequencer(AUD_Sound* sequencer, AUD_SEntry* entry, extern void AUD_muteSequencer(AUD_Sound* sequencer, AUD_SEntry* entry, char mute); +extern void AUD_setSequencerDeviceSpecs(AUD_Sound* sequencer); + +extern void AUD_setSequencerSpecs(AUD_Sound* sequencer, AUD_Specs specs); + extern int AUD_readSound(AUD_Sound* sound, sample_t* buffer, int length); extern void AUD_startPlayback(void); diff --git a/intern/audaspace/intern/AUD_ChannelMapperReader.cpp b/intern/audaspace/intern/AUD_ChannelMapperReader.cpp index ab7b5317be1..4ac1982e32c 100644 --- a/intern/audaspace/intern/AUD_ChannelMapperReader.cpp +++ b/intern/audaspace/intern/AUD_ChannelMapperReader.cpp @@ -44,6 +44,12 @@ AUD_ChannelMapperReader::~AUD_ChannelMapperReader() delete[] m_mapping; } +void AUD_ChannelMapperReader::setChannels(AUD_Channels channels) +{ + m_target_channels = channels; + calculateMapping(); +} + float AUD_ChannelMapperReader::angleDistance(float alpha, float beta) { alpha = fabs(alpha - beta); diff --git a/intern/audaspace/intern/AUD_ChannelMapperReader.h b/intern/audaspace/intern/AUD_ChannelMapperReader.h index 949bb4427e2..3da34ed85ce 100644 --- a/intern/audaspace/intern/AUD_ChannelMapperReader.h +++ b/intern/audaspace/intern/AUD_ChannelMapperReader.h @@ -109,6 +109,8 @@ public: */ ~AUD_ChannelMapperReader(); + void setChannels(AUD_Channels channels); + virtual AUD_Specs getSpecs() const; virtual void read(int& length, bool& eos, sample_t* buffer); }; diff --git a/intern/audaspace/intern/AUD_Mixer.cpp b/intern/audaspace/intern/AUD_Mixer.cpp index e6699811344..cfdf2b0e60a 100644 --- a/intern/audaspace/intern/AUD_Mixer.cpp +++ b/intern/audaspace/intern/AUD_Mixer.cpp @@ -73,6 +73,11 @@ AUD_DeviceSpecs AUD_Mixer::getSpecs() const return m_specs; } +void AUD_Mixer::setSpecs(AUD_Specs specs) +{ + m_specs.specs = specs; +} + void AUD_Mixer::clear(int length) { m_buffer.assureSize(length * m_specs.channels * AUD_SAMPLE_SIZE(m_specs)); diff --git a/intern/audaspace/intern/AUD_Mixer.h b/intern/audaspace/intern/AUD_Mixer.h index a68d86dcb83..5ca801b1690 100644 --- a/intern/audaspace/intern/AUD_Mixer.h +++ b/intern/audaspace/intern/AUD_Mixer.h @@ -47,7 +47,7 @@ protected: /** * The output specification. */ - const AUD_DeviceSpecs m_specs; + AUD_DeviceSpecs m_specs; /** * The length of the mixing buffer. @@ -82,6 +82,12 @@ public: AUD_DeviceSpecs getSpecs() const; /** + * Sets the target specification for superposing. + * \param specs The target specification. + */ + void setSpecs(AUD_Specs specs); + + /** * Mixes a buffer. * \param buffer The buffer to superpose. * \param start The start sample of the buffer. diff --git a/intern/audaspace/intern/AUD_SequencerFactory.cpp b/intern/audaspace/intern/AUD_SequencerFactory.cpp index 1787dea0ebb..6907d7683c9 100644 --- a/intern/audaspace/intern/AUD_SequencerFactory.cpp +++ b/intern/audaspace/intern/AUD_SequencerFactory.cpp @@ -48,9 +48,12 @@ AUD_SequencerFactory::~AUD_SequencerFactory() { } -void AUD_SequencerFactory::setThis(AUD_Reference<AUD_SequencerFactory>* self) +void AUD_SequencerFactory::setSpecs(AUD_Specs specs) { - m_this = self; + m_specs = specs; + + for(AUD_ReaderIterator i = m_readers.begin(); i != m_readers.end(); i++) + (*i)->setSpecs(m_specs); } void AUD_SequencerFactory::mute(bool muted) @@ -103,7 +106,7 @@ void AUD_SequencerFactory::mute(AUD_Reference<AUD_SequencerEntry> entry, bool mu AUD_Reference<AUD_IReader> AUD_SequencerFactory::createReader() { - AUD_Reference<AUD_SequencerReader> reader = new AUD_SequencerReader(*m_this, m_entries, + AUD_Reference<AUD_SequencerReader> reader = new AUD_SequencerReader(this, m_entries, m_specs, m_data, m_volume); m_readers.push_front(reader); diff --git a/intern/audaspace/intern/AUD_SequencerFactory.h b/intern/audaspace/intern/AUD_SequencerFactory.h index 37a332bc9ff..4e57a224c65 100644 --- a/intern/audaspace/intern/AUD_SequencerFactory.h +++ b/intern/audaspace/intern/AUD_SequencerFactory.h @@ -66,7 +66,6 @@ private: bool m_muted; void* m_data; AUD_volumeFunction m_volume; - AUD_Reference<AUD_SequencerFactory>* m_this; // hide copy constructor and operator= AUD_SequencerFactory(const AUD_SequencerFactory&); @@ -76,7 +75,7 @@ public: AUD_SequencerFactory(AUD_Specs specs, bool muted, void* data, AUD_volumeFunction volume); ~AUD_SequencerFactory(); - void setThis(AUD_Reference<AUD_SequencerFactory>* self); + void setSpecs(AUD_Specs specs); void mute(bool muted); bool getMute() const; diff --git a/intern/audaspace/intern/AUD_SequencerReader.cpp b/intern/audaspace/intern/AUD_SequencerReader.cpp index 9ee0b39c50d..a9309311d6a 100644 --- a/intern/audaspace/intern/AUD_SequencerReader.cpp +++ b/intern/audaspace/intern/AUD_SequencerReader.cpp @@ -95,6 +95,22 @@ void AUD_SequencerReader::remove(AUD_Reference<AUD_SequencerEntry> entry) } } +void AUD_SequencerReader::setSpecs(AUD_Specs specs) +{ + m_mixer->setSpecs(specs); + + AUD_Reference<AUD_SequencerStrip> strip; + for(AUD_StripIterator i = m_strips.begin(); i != m_strips.end(); i++) + { + strip = *i; + if(!strip->mapper.isNull()) + { + strip->mapper->setChannels(specs.channels); + strip->resampler->setRate(specs.rate); + } + } +} + bool AUD_SequencerReader::isSeekable() const { return true; @@ -149,24 +165,30 @@ void AUD_SequencerReader::read(int& length, bool& eos, sample_t* buffer) strip->reader = (*strip->old_sound)->createReader(); // resample #ifdef WITH_SAMPLERATE - strip->reader = new AUD_SRCResampleReader(strip->reader, m_mixer->getSpecs().specs); + strip->resampler = new AUD_SRCResampleReader(strip->reader, m_mixer->getSpecs().specs); #else - strip->reader = new AUD_LinearResampleReader(strip->reader, m_mixer->getSpecs().specs); + strip->resampler = new AUD_LinearResampleReader(strip->reader, m_mixer->getSpecs().specs); #endif // rechannel - strip->reader = new AUD_ChannelMapperReader(strip->reader, m_mixer->getSpecs().channels); + strip->mapper = new AUD_ChannelMapperReader(AUD_Reference<AUD_IReader>(strip->resampler), m_mixer->getSpecs().channels); } catch(AUD_Exception) { strip->reader = NULL; + strip->resampler = NULL; + strip->mapper = NULL; } } else + { strip->reader = NULL; + strip->resampler = NULL; + strip->mapper = NULL; + } } - if(!strip->reader.isNull()) + if(!strip->mapper.isNull()) { end = floor(strip->entry->end * rate); if(m_position < end) @@ -185,9 +207,9 @@ void AUD_SequencerReader::read(int& length, bool& eos, sample_t* buffer) current += strip->entry->skip * rate; len = length > end - m_position ? end - m_position : length; len -= skip; - if(strip->reader->getPosition() != current) - strip->reader->seek(current); - strip->reader->read(len, eos, m_buffer.getBuffer()); + if(strip->mapper->getPosition() != current) + strip->mapper->seek(current); + strip->mapper->read(len, eos, m_buffer.getBuffer()); m_mixer->mix(m_buffer.getBuffer(), skip, len, m_volume(m_data, strip->entry->data, (float)m_position / (float)rate)); } } diff --git a/intern/audaspace/intern/AUD_SequencerReader.h b/intern/audaspace/intern/AUD_SequencerReader.h index e769b342d1b..625bad3c3ae 100644 --- a/intern/audaspace/intern/AUD_SequencerReader.h +++ b/intern/audaspace/intern/AUD_SequencerReader.h @@ -35,11 +35,15 @@ #include "AUD_IReader.h" #include "AUD_SequencerFactory.h" #include "AUD_Buffer.h" -class AUD_Mixer; +#include "AUD_Mixer.h" +#include "AUD_ResampleReader.h" +#include "AUD_ChannelMapperReader.h" struct AUD_SequencerStrip { AUD_Reference<AUD_IReader> reader; + AUD_Reference<AUD_ResampleReader> resampler; + AUD_Reference<AUD_ChannelMapperReader> mapper; AUD_Reference<AUD_SequencerEntry> entry; AUD_Reference<AUD_IFactory>* old_sound; }; @@ -94,6 +98,7 @@ public: void add(AUD_Reference<AUD_SequencerEntry> entry); void remove(AUD_Reference<AUD_SequencerEntry> entry); + void setSpecs(AUD_Specs specs); virtual bool isSeekable() const; virtual void seek(int position); diff --git a/release/scripts/presets/ffmpeg/DV.py b/release/scripts/presets/ffmpeg/DV.py index 46d2a0a4a2f..926fb241747 100644 --- a/release/scripts/presets/ffmpeg/DV.py +++ b/release/scripts/presets/ffmpeg/DV.py @@ -11,3 +11,4 @@ else: bpy.context.scene.render.ffmpeg_audio_mixrate = 48000 bpy.context.scene.render.ffmpeg_audio_codec = "PCM" +bpy.context.scene.render.ffmpeg_audio_channels = 2 diff --git a/release/scripts/presets/ffmpeg/DVD.py b/release/scripts/presets/ffmpeg/DVD.py index e18ec9f817b..196b5d68406 100644 --- a/release/scripts/presets/ffmpeg/DVD.py +++ b/release/scripts/presets/ffmpeg/DVD.py @@ -21,3 +21,4 @@ bpy.context.scene.render.ffmpeg_muxrate = 10080000 bpy.context.scene.render.ffmpeg_audio_codec = "AC3" bpy.context.scene.render.ffmpeg_audio_bitrate = 448 bpy.context.scene.render.ffmpeg_audio_mixrate = 48000 +bpy.context.scene.render.ffmpeg_audio_channels = 6 diff --git a/release/scripts/presets/ffmpeg/SVCD.py b/release/scripts/presets/ffmpeg/SVCD.py index c71a3851af0..e4459ab5c5c 100644 --- a/release/scripts/presets/ffmpeg/SVCD.py +++ b/release/scripts/presets/ffmpeg/SVCD.py @@ -21,3 +21,4 @@ bpy.context.scene.render.ffmpeg_muxrate = 0 bpy.context.scene.render.ffmpeg_audio_bitrate = 224 bpy.context.scene.render.ffmpeg_audio_mixrate = 44100 bpy.context.scene.render.ffmpeg_audio_codec = "MP2" +bpy.context.scene.render.ffmpeg_audio_channels = 2 diff --git a/release/scripts/presets/ffmpeg/VCD.py b/release/scripts/presets/ffmpeg/VCD.py index faf27efe9e6..c2b73e682a2 100644 --- a/release/scripts/presets/ffmpeg/VCD.py +++ b/release/scripts/presets/ffmpeg/VCD.py @@ -21,3 +21,4 @@ bpy.context.scene.render.ffmpeg_muxrate = 2352 * 75 * 8 bpy.context.scene.render.ffmpeg_audio_bitrate = 224 bpy.context.scene.render.ffmpeg_audio_mixrate = 44100 bpy.context.scene.render.ffmpeg_audio_codec = "MP2" +bpy.context.scene.render.ffmpeg_audio_channels = 2 diff --git a/release/scripts/startup/bl_ui/properties_render.py b/release/scripts/startup/bl_ui/properties_render.py index 54ca18ef828..9ff4470641b 100644 --- a/release/scripts/startup/bl_ui/properties_render.py +++ b/release/scripts/startup/bl_ui/properties_render.py @@ -596,7 +596,9 @@ class RENDER_PT_encoding(RenderButtonsPanel, bpy.types.Panel): col.prop(rd, "ffmpeg_audio_bitrate") col.prop(rd, "ffmpeg_audio_mixrate") - split.prop(rd, "ffmpeg_audio_volume", slider=True) + col = split.column() + col.prop(rd, "ffmpeg_audio_volume", slider=True) + col.prop(rd, "ffmpeg_audio_channels") class RENDER_PT_bake(RenderButtonsPanel, bpy.types.Panel): diff --git a/source/blender/blenkernel/intern/scene.c b/source/blender/blenkernel/intern/scene.c index 51eaba3c05b..e045bd0fb82 100644 --- a/source/blender/blenkernel/intern/scene.c +++ b/source/blender/blenkernel/intern/scene.c @@ -469,6 +469,7 @@ Scene *add_scene(const char *name) sce->r.ffcodecdata.audio_mixrate = 44100; sce->r.ffcodecdata.audio_volume = 1.0f; sce->r.ffcodecdata.audio_bitrate = 192; + sce->r.ffcodecdata.audio_channels = 2; BLI_strncpy(sce->r.engine, "BLENDER_RENDER", sizeof(sce->r.engine)); diff --git a/source/blender/blenkernel/intern/sound.c b/source/blender/blenkernel/intern/sound.c index 60a24c2eace..9b86b8752db 100644 --- a/source/blender/blenkernel/intern/sound.c +++ b/source/blender/blenkernel/intern/sound.c @@ -346,6 +346,7 @@ AUD_Device* sound_mixdown(struct Scene *scene, AUD_DeviceSpecs specs, int start, AUD_setDeviceVolume(mixdown, volume); + AUD_setSequencerSpecs(scene->sound_scene, specs.specs); AUD_freeHandle(AUD_playDevice(mixdown, scene->sound_scene, start / FPS)); return mixdown; @@ -405,6 +406,9 @@ static void sound_start_play_scene(struct Scene *scene) { if(scene->sound_scene_handle) AUD_stop(scene->sound_scene_handle); + + AUD_setSequencerDeviceSpecs(scene->sound_scene); + if((scene->sound_scene_handle = AUD_play(scene->sound_scene, 1))) AUD_setLoop(scene->sound_scene_handle, -1); } diff --git a/source/blender/blenkernel/intern/writeffmpeg.c b/source/blender/blenkernel/intern/writeffmpeg.c index c729565533f..26de31b2b03 100644 --- a/source/blender/blenkernel/intern/writeffmpeg.c +++ b/source/blender/blenkernel/intern/writeffmpeg.c @@ -549,7 +549,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; + c->channels = rd->ffcodecdata.audio_channels; codec = avcodec_find_encoder(c->codec_id); if (!codec) { //XXX error("Couldn't find a valid audio codec"); @@ -574,12 +574,11 @@ static AVStream* alloc_audio_stream(RenderData *rd, int codec_id, AVFormatContex audio_outbuf_size = c->frame_size * c->channels * sizeof(int16_t) * 4; } - audio_output_buffer = (uint8_t*)MEM_mallocN( - audio_outbuf_size, "FFMPEG audio encoder input buffer"); + audio_output_buffer = (uint8_t*)av_malloc( + audio_outbuf_size); - audio_input_buffer = (uint8_t*)MEM_mallocN( - audio_input_samples * c->channels * sizeof(int16_t), - "FFMPEG audio encoder output buffer"); + audio_input_buffer = (uint8_t*)av_malloc( + audio_input_samples * c->channels * sizeof(int16_t)); audio_time = 0.0f; @@ -701,7 +700,7 @@ static int start_ffmpeg_impl(struct RenderData *rd, int rectx, int recty, Report if (ffmpeg_type == FFMPEG_DV) { fmt->audio_codec = CODEC_ID_PCM_S16LE; - if (ffmpeg_audio_codec != CODEC_ID_NONE && rd->ffcodecdata.audio_mixrate != 48000) { + if (ffmpeg_audio_codec != CODEC_ID_NONE && rd->ffcodecdata.audio_mixrate != 48000 && rd->ffcodecdata.audio_channels != 2) { BKE_report(reports, RPT_ERROR, "FFMPEG only supports 48khz / stereo audio for DV!"); return 0; } @@ -971,11 +970,11 @@ void end_ffmpeg(void) video_buffer = 0; } if (audio_output_buffer) { - MEM_freeN(audio_output_buffer); + av_free(audio_output_buffer); audio_output_buffer = 0; } if (audio_input_buffer) { - MEM_freeN(audio_input_buffer); + av_free(audio_input_buffer); audio_input_buffer = 0; } diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c index b8a72616593..50be7b83484 100644 --- a/source/blender/blenloader/intern/readfile.c +++ b/source/blender/blenloader/intern/readfile.c @@ -11474,6 +11474,12 @@ static void do_versions(FileData *fd, Library *lib, Main *main) kb->slidermax = kb->slidermin + 1.0f; } } + + { + Scene *scene; + for (scene=main->scene.first; scene; scene=scene->id.next) + scene->r.ffcodecdata.audio_channels = 2; + } } if (main->versionfile < 256 || (main->versionfile == 256 && main->subversionfile < 1)) { diff --git a/source/blender/makesdna/DNA_scene_types.h b/source/blender/makesdna/DNA_scene_types.h index 100a66d209f..2fc92aa12c4 100644 --- a/source/blender/makesdna/DNA_scene_types.h +++ b/source/blender/makesdna/DNA_scene_types.h @@ -126,6 +126,8 @@ typedef struct FFMpegCodecData { int video_bitrate; int audio_bitrate; int audio_mixrate; + int audio_channels; + int audio_pad; float audio_volume; int gop_size; int flags; diff --git a/source/blender/makesrna/intern/rna_scene.c b/source/blender/makesrna/intern/rna_scene.c index 1322a18421b..a8d8d875ec4 100644 --- a/source/blender/makesrna/intern/rna_scene.c +++ b/source/blender/makesrna/intern/rna_scene.c @@ -98,6 +98,14 @@ EnumPropertyItem snap_element_items[] = { {SCE_SNAP_MODE_VOLUME, "VOLUME", ICON_SNAP_VOLUME, "Volume", "Snap to volume"}, {0, NULL, 0, NULL, NULL}}; +static EnumPropertyItem audio_channel_items[] = { + {1, "MONO", 0, "Mono", "Set audio channels to mono"}, + {2, "STEREO", 0, "Stereo", "Set audio channels to stereo"}, + {4, "SURROUND4", 0, "4 Channels", "Set audio channels to 4 channels"}, + {6, "SURROUND51", 0, "5.1 Surround", "Set audio channels to 5.1 surround sound"}, + {8, "SURROUND71", 0, "7.1 Surround", "Set audio channels to 7.1 surround sound"}, + {0, NULL, 0, NULL, NULL}}; + EnumPropertyItem image_type_items[] = { {0, "", 0, "Image", NULL}, {R_BMP, "BMP", ICON_FILE_IMAGE, "BMP", "Output image in bitmap format"}, @@ -2468,6 +2476,10 @@ static void rna_def_scene_render_data(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Volume", "Audio volume"); RNA_def_property_update(prop, NC_SCENE|ND_RENDER_OPTIONS, NULL); + prop= RNA_def_property(srna, "ffmpeg_audio_channels", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_sdna(prop, NULL, "ffcodecdata.audio_channels"); + RNA_def_property_enum_items(prop, audio_channel_items); + RNA_def_property_ui_text(prop, "Audio Channels", "Sets the audio channel count"); #endif prop= RNA_def_property(srna, "fps", PROP_INT, PROP_NONE); |