forked from bartvdbraak/blender
QTKit (OSX 64bit): Add audio export to Quicktime
Supports default OSX codecs : Linear PCM, Apple Lossless and AAC Note that AAC codec doesn't support sample rates above 48kHz. If a python/rna guru knows how to easily enforce this limit, he is welcome! Enjoy making Quicktime movies now with audio!
This commit is contained in:
parent
c3ab6bc509
commit
c939331a6c
@ -362,14 +362,38 @@ class RENDER_PT_output(RenderButtonsPanel):
|
||||
|
||||
elif rd.file_format == 'QUICKTIME_CARBON':
|
||||
split = layout.split()
|
||||
split.operator("scene.render_set_quicktime_codec")
|
||||
split.operator("scene.render_data_set_quicktime_codec")
|
||||
|
||||
elif rd.file_format == 'QUICKTIME_QTKIT':
|
||||
split = layout.split()
|
||||
col = split.column()
|
||||
col.prop(rd, "quicktime_codec_type")
|
||||
col.prop(rd, "quicktime_codec_type", text="Video Codec")
|
||||
col.prop(rd, "quicktime_codec_spatial_quality", text="Quality")
|
||||
|
||||
#Audio
|
||||
col.prop(rd,"quicktime_audiocodec_type", text="Audio Codec")
|
||||
if rd.quicktime_audiocodec_type != 'No audio':
|
||||
split = layout.split()
|
||||
col = split.column()
|
||||
if rd.quicktime_audiocodec_type == 'LPCM':
|
||||
col.prop(rd,"quicktime_audio_bitdepth", text="")
|
||||
if wide_ui:
|
||||
col = split.column()
|
||||
col.prop(rd,"quicktime_audio_samplerate", text="")
|
||||
|
||||
split = layout.split()
|
||||
col = split.column()
|
||||
if rd.quicktime_audiocodec_type == 'AAC':
|
||||
col.prop(rd,"quicktime_audio_bitrate")
|
||||
if wide_ui:
|
||||
subsplit = split.split()
|
||||
col = subsplit.column()
|
||||
if rd.quicktime_audiocodec_type == 'AAC':
|
||||
col.prop(rd,"quicktime_audio_codec_isvbr")
|
||||
if wide_ui:
|
||||
col = subsplit.column()
|
||||
col.prop(rd,"quicktime_audio_resampling_hq")
|
||||
|
||||
|
||||
class RENDER_PT_encoding(RenderButtonsPanel):
|
||||
bl_label = "Encoding"
|
||||
|
@ -104,6 +104,15 @@ typedef struct QuicktimeCodecSettings {
|
||||
int minTemporalQuality; /* in 0-100 scale, to be translated in 0-1024 for qt use */
|
||||
int keyFrameRate;
|
||||
int bitRate; /* bitrate in bps */
|
||||
|
||||
/* Audio Codec settings */
|
||||
int audiocodecType;
|
||||
int audioSampleRate;
|
||||
short audioBitDepth;
|
||||
short audioChannels;
|
||||
int audioCodecFlags;
|
||||
int audioBitRate;
|
||||
int pad1;
|
||||
} QuicktimeCodecSettings;
|
||||
|
||||
typedef struct FFMpegCodecData {
|
||||
|
@ -6,7 +6,7 @@ objs = []
|
||||
o = SConscript('intern/SConscript')
|
||||
objs += o
|
||||
|
||||
incs = '#/intern/guardedalloc ../blenkernel ../blenlib ../makesdna intern .'
|
||||
incs = '#/intern/guardedalloc #/intern/audaspace/intern ../blenkernel ../blenlib ../makesdna intern .'
|
||||
incs += ' ../windowmanager ../editors/include ../gpu ../imbuf ../ikplugin'
|
||||
incs += ' ../render/extern/include'
|
||||
|
||||
|
@ -39,7 +39,7 @@ SET(SRC
|
||||
../../../../intern/guardedalloc/intern/mallocn.c
|
||||
../../../../intern/guardedalloc/intern/mmap_win.c)
|
||||
|
||||
INCLUDE_DIRECTORIES(../../../../intern/guardedalloc .. ../../makesdna ../../blenkernel ../../blenlib ../../ikplugin ../../windowmanager ../../editors/include ../../gpu ../../imbuf ../../render/extern/include .)
|
||||
INCLUDE_DIRECTORIES(../../../../intern/audaspace/intern ../../../../intern/guardedalloc .. ../../makesdna ../../blenkernel ../../blenlib ../../ikplugin ../../windowmanager ../../editors/include ../../gpu ../../imbuf ../../render/extern/include .)
|
||||
FILE(GLOB INC_FILES ../*.h ../../makesdna/*.h)
|
||||
|
||||
IF(NOT WITH_PYTHON)
|
||||
|
@ -46,6 +46,7 @@ endif
|
||||
CFLAGS += $(LEVEL_1_C_WARNINGS)
|
||||
|
||||
CPPFLAGS += -I$(NAN_GUARDEDALLOC)/include
|
||||
CPPFLAGS += -I../../../../intern/audaspace/intern
|
||||
CPPFLAGS += -I../../blenlib
|
||||
CPPFLAGS += -I../../blenkernel
|
||||
CPPFLAGS += -I../../imbuf
|
||||
|
@ -33,6 +33,7 @@ incs = '#/intern/guardedalloc ../../blenlib ../../blenkernel'
|
||||
incs += ' ../../imbuf ../../makesdna ../../makesrna ../../ikplugin'
|
||||
incs += ' ../../windowmanager ../../editors/include'
|
||||
incs += ' ../../render/extern/include'
|
||||
incs += ' #/intern/audaspace/intern'
|
||||
|
||||
if env['WITH_BF_OPENEXR']:
|
||||
defs.append('WITH_OPENEXR')
|
||||
|
@ -39,6 +39,7 @@
|
||||
|
||||
#ifdef WITH_QUICKTIME
|
||||
#include "quicktime_export.h"
|
||||
#include "AUD_C-API.h"
|
||||
#endif
|
||||
|
||||
#ifdef WITH_FFMPEG
|
||||
@ -523,14 +524,14 @@ static int rna_RenderSettings_qtcodecsettings_codecType_get(PointerRNA *ptr)
|
||||
{
|
||||
RenderData *rd= (RenderData*)ptr->data;
|
||||
|
||||
return quicktime_rnatmpvalue_from_codectype(rd->qtcodecsettings.codecType);
|
||||
return quicktime_rnatmpvalue_from_videocodectype(rd->qtcodecsettings.codecType);
|
||||
}
|
||||
|
||||
static void rna_RenderSettings_qtcodecsettings_codecType_set(PointerRNA *ptr, int value)
|
||||
{
|
||||
RenderData *rd= (RenderData*)ptr->data;
|
||||
|
||||
rd->qtcodecsettings.codecType = quicktime_codecType_from_rnatmpvalue(value);
|
||||
rd->qtcodecsettings.codecType = quicktime_videocodecType_from_rnatmpvalue(value);
|
||||
}
|
||||
|
||||
static EnumPropertyItem *rna_RenderSettings_qtcodecsettings_codecType_itemf(bContext *C, PointerRNA *ptr, int *free)
|
||||
@ -541,8 +542,8 @@ static EnumPropertyItem *rna_RenderSettings_qtcodecsettings_codecType_itemf(bCon
|
||||
int i=1, totitem= 0;
|
||||
char id[5];
|
||||
|
||||
for(i=0;i<quicktime_get_num_codecs();i++) {
|
||||
codecTypeDesc = quicktime_get_codecType_desc(i);
|
||||
for(i=0;i<quicktime_get_num_videocodecs();i++) {
|
||||
codecTypeDesc = quicktime_get_videocodecType_desc(i);
|
||||
if (!codecTypeDesc) break;
|
||||
|
||||
tmp.value= codecTypeDesc->rnatmpvalue;
|
||||
@ -558,6 +559,45 @@ static EnumPropertyItem *rna_RenderSettings_qtcodecsettings_codecType_itemf(bCon
|
||||
|
||||
return item;
|
||||
}
|
||||
|
||||
#ifdef USE_QTKIT
|
||||
static int rna_RenderSettings_qtcodecsettings_audiocodecType_get(PointerRNA *ptr)
|
||||
{
|
||||
RenderData *rd= (RenderData*)ptr->data;
|
||||
|
||||
return quicktime_rnatmpvalue_from_audiocodectype(rd->qtcodecsettings.audiocodecType);
|
||||
}
|
||||
|
||||
static void rna_RenderSettings_qtcodecsettings_audiocodecType_set(PointerRNA *ptr, int value)
|
||||
{
|
||||
RenderData *rd= (RenderData*)ptr->data;
|
||||
|
||||
rd->qtcodecsettings.audiocodecType = quicktime_audiocodecType_from_rnatmpvalue(value);
|
||||
}
|
||||
|
||||
static EnumPropertyItem *rna_RenderSettings_qtcodecsettings_audiocodecType_itemf(bContext *C, PointerRNA *ptr, int *free)
|
||||
{
|
||||
EnumPropertyItem *item= NULL;
|
||||
EnumPropertyItem tmp = {0, "", 0, "", ""};
|
||||
QuicktimeCodecTypeDesc *codecTypeDesc;
|
||||
int i=1, totitem= 0;
|
||||
|
||||
for(i=0;i<quicktime_get_num_audiocodecs();i++) {
|
||||
codecTypeDesc = quicktime_get_audiocodecType_desc(i);
|
||||
if (!codecTypeDesc) break;
|
||||
|
||||
tmp.value= codecTypeDesc->rnatmpvalue;
|
||||
tmp.identifier= codecTypeDesc->codecName;
|
||||
tmp.name= codecTypeDesc->codecName;
|
||||
RNA_enum_item_add(&item, &totitem, &tmp);
|
||||
}
|
||||
|
||||
RNA_enum_item_end(&item, &totitem);
|
||||
*free= 1;
|
||||
|
||||
return item;
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
static int rna_RenderSettings_active_layer_index_get(PointerRNA *ptr)
|
||||
@ -1824,6 +1864,35 @@ static void rna_def_scene_render_data(BlenderRNA *brna)
|
||||
static EnumPropertyItem quicktime_codec_type_items[] = {
|
||||
{0, "codec", 0, "codec", ""},
|
||||
{0, NULL, 0, NULL, NULL}};
|
||||
|
||||
#ifdef USE_QTKIT
|
||||
static EnumPropertyItem quicktime_audio_samplerate_items[] = {
|
||||
{22050, "22050", 0, "22kHz", ""},
|
||||
{44100, "44100", 0, "44.1kHz", ""},
|
||||
{48000, "48000", 0, "48kHz", ""},
|
||||
{88200, "88200", 0, "88.2kHz", ""},
|
||||
{96000, "96000", 0, "96kHz", ""},
|
||||
{192000, "192000", 0, "192kHz", ""},
|
||||
{0, NULL, 0, NULL, NULL}};
|
||||
|
||||
static EnumPropertyItem quicktime_audio_bitdepth_items[] = {
|
||||
{AUD_FORMAT_U8, "8BIT", 0, "8bit", ""},
|
||||
{AUD_FORMAT_S16, "16BIT", 0, "16bit", ""},
|
||||
{AUD_FORMAT_S24, "24BIT", 0, "24bit", ""},
|
||||
{AUD_FORMAT_S32, "32BIT", 0, "32bit", ""},
|
||||
{AUD_FORMAT_FLOAT32, "FLOAT32", 0, "float32", ""},
|
||||
{AUD_FORMAT_FLOAT64, "FLOAT64", 0, "float64", ""},
|
||||
{0, NULL, 0, NULL, NULL}};
|
||||
|
||||
static EnumPropertyItem quicktime_audio_bitrate_items[] = {
|
||||
{64000, "64000", 0, "64kbps", ""},
|
||||
{112000, "112000", 0, "112kpbs", ""},
|
||||
{128000, "128000", 0, "128kbps", ""},
|
||||
{192000, "192000", 0, "192kbps", ""},
|
||||
{256000, "256000", 0, "256kbps", ""},
|
||||
{320000, "320000", 0, "320kbps", ""},
|
||||
{0, NULL, 0, NULL, NULL}};
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef WITH_FFMPEG
|
||||
@ -2032,6 +2101,45 @@ static void rna_def_scene_render_data(BlenderRNA *brna)
|
||||
RNA_def_property_range(prop, 0, 100);
|
||||
RNA_def_property_ui_text(prop, "Spatial quality", "Intra-frame spatial quality level");
|
||||
RNA_def_property_update(prop, NC_SCENE|ND_RENDER_OPTIONS, NULL);
|
||||
|
||||
#ifdef USE_QTKIT
|
||||
prop= RNA_def_property(srna, "quicktime_audiocodec_type", PROP_ENUM, PROP_NONE);
|
||||
RNA_def_property_enum_bitflag_sdna(prop, NULL, "qtcodecsettings.audiocodecType");
|
||||
RNA_def_property_enum_items(prop, quicktime_codec_type_items);
|
||||
RNA_def_property_enum_funcs(prop, "rna_RenderSettings_qtcodecsettings_audiocodecType_get",
|
||||
"rna_RenderSettings_qtcodecsettings_audiocodecType_set",
|
||||
"rna_RenderSettings_qtcodecsettings_audiocodecType_itemf");
|
||||
RNA_def_property_ui_text(prop, "Audio Codec", "QuickTime audio codec type");
|
||||
RNA_def_property_update(prop, NC_SCENE|ND_RENDER_OPTIONS, NULL);
|
||||
|
||||
prop= RNA_def_property(srna, "quicktime_audio_samplerate", PROP_ENUM, PROP_NONE);
|
||||
RNA_def_property_enum_bitflag_sdna(prop, NULL, "qtcodecsettings.audioSampleRate");
|
||||
RNA_def_property_enum_items(prop, quicktime_audio_samplerate_items);
|
||||
RNA_def_property_ui_text(prop, "Smp Rate", "Sample Rate");
|
||||
RNA_def_property_update(prop, NC_SCENE|ND_RENDER_OPTIONS, NULL);
|
||||
|
||||
prop= RNA_def_property(srna, "quicktime_audio_bitdepth", PROP_ENUM, PROP_NONE);
|
||||
RNA_def_property_enum_bitflag_sdna(prop, NULL, "qtcodecsettings.audioBitDepth");
|
||||
RNA_def_property_enum_items(prop, quicktime_audio_bitdepth_items);
|
||||
RNA_def_property_ui_text(prop, "Bit Depth", "Bit Depth");
|
||||
RNA_def_property_update(prop, NC_SCENE|ND_RENDER_OPTIONS, NULL);
|
||||
|
||||
prop= RNA_def_property(srna, "quicktime_audio_resampling_hq", PROP_BOOLEAN, PROP_NONE);
|
||||
RNA_def_property_boolean_negative_sdna(prop, NULL, "qtcodecsettings.audioCodecFlags", QTAUDIO_FLAG_RESAMPLE_NOHQ);
|
||||
RNA_def_property_ui_text(prop, "HQ", "Use High Quality resampling algorithm");
|
||||
RNA_def_property_update(prop, NC_SCENE|ND_RENDER_OPTIONS, NULL);
|
||||
|
||||
prop= RNA_def_property(srna, "quicktime_audio_codec_isvbr", PROP_BOOLEAN, PROP_NONE);
|
||||
RNA_def_property_boolean_negative_sdna(prop, NULL, "qtcodecsettings.audioCodecFlags", QTAUDIO_FLAG_CODEC_ISCBR);
|
||||
RNA_def_property_ui_text(prop, "VBR", "Use Variable Bit Rate compression (improves quality at same bitrate)");
|
||||
RNA_def_property_update(prop, NC_SCENE|ND_RENDER_OPTIONS, NULL);
|
||||
|
||||
prop= RNA_def_property(srna, "quicktime_audio_bitrate", PROP_ENUM, PROP_NONE);
|
||||
RNA_def_property_enum_bitflag_sdna(prop, NULL, "qtcodecsettings.audioBitRate");
|
||||
RNA_def_property_enum_items(prop, quicktime_audio_bitrate_items);
|
||||
RNA_def_property_ui_text(prop, "Bitrate", "Compressed audio bitrate");
|
||||
RNA_def_property_update(prop, NC_SCENE|ND_RENDER_OPTIONS, NULL);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef WITH_FFMPEG
|
||||
|
@ -45,6 +45,7 @@ SET(INC
|
||||
../render/extern/include
|
||||
../include
|
||||
../windowmanager
|
||||
../../../intern/audaspace/intern
|
||||
)
|
||||
|
||||
SET(INC ${INC} ${QUICKTIME_INC})
|
||||
|
@ -23,7 +23,8 @@ incs = ['.',
|
||||
'../imbuf/intern',
|
||||
'../blenloader',
|
||||
'../render/extern/include',
|
||||
'../editors/include']
|
||||
'../editors/include',
|
||||
'#/intern/audaspace/intern']
|
||||
|
||||
incs.append(env['BF_QUICKTIME_INC'])
|
||||
|
||||
|
@ -59,4 +59,5 @@ CPPFLAGS += -I..
|
||||
CPPFLAGS += -I../../blenloader -I../../imbuf/intern -I../../imbuf
|
||||
CPPFLAGS += -I../../blenlib -I../../makesdna -I../../editors/include -I../../avi
|
||||
CPPFLAGS += -I../../blenkernel -I../../render/extern/include -I../../windowmanager -I../../makesrna
|
||||
CPPFLAGS += -I../../../intern/audaspace/intern
|
||||
|
||||
|
@ -36,6 +36,9 @@
|
||||
#include <string.h>
|
||||
|
||||
#include "DNA_scene_types.h"
|
||||
#include "DNA_userdef_types.h"
|
||||
|
||||
#include "AUD_C-API.h"
|
||||
|
||||
#include "BKE_global.h"
|
||||
#include "BKE_scene.h"
|
||||
@ -57,6 +60,7 @@
|
||||
#endif
|
||||
#import <Cocoa/Cocoa.h>
|
||||
#import <QTKit/QTKit.h>
|
||||
#include <AudioToolbox/AudioToolbox.h>
|
||||
|
||||
#if (MAC_OS_X_VERSION_MIN_REQUIRED <= MAC_OS_X_VERSION_10_4) || !__LP64__
|
||||
#error 64 bit build & OSX 10.5 minimum are needed for QTKit
|
||||
@ -74,14 +78,34 @@ typedef struct QuicktimeExport {
|
||||
|
||||
QTTime frameDuration;
|
||||
NSDictionary *frameAttributes;
|
||||
|
||||
NSString *videoTempFileName;
|
||||
/* Audio section */
|
||||
AUD_Device *audioInputDevice;
|
||||
AudioFileID audioFile;
|
||||
NSString *audioFileName;
|
||||
AudioConverterRef audioConverter;
|
||||
AudioBufferList audioBufferList;
|
||||
AudioStreamBasicDescription audioInputFormat, audioOutputFormat;
|
||||
AudioStreamPacketDescription *audioOutputPktDesc;
|
||||
SInt64 audioFilePos;
|
||||
char* audioInputBuffer;
|
||||
char* audioOutputBuffer;
|
||||
UInt32 audioCodecMaxOutputPacketSize;
|
||||
UInt64 audioTotalExportedFrames, audioTotalSavedFrames;
|
||||
UInt64 audioLastFrame;
|
||||
SInt64 audioOutputPktPos;
|
||||
|
||||
} QuicktimeExport;
|
||||
|
||||
static struct QuicktimeExport *qtexport;
|
||||
|
||||
#define AUDIOOUTPUTBUFFERSIZE 65536
|
||||
|
||||
#pragma mark rna helper functions
|
||||
|
||||
|
||||
static QuicktimeCodecTypeDesc qtCodecList[] = {
|
||||
/* Video codec */
|
||||
static QuicktimeCodecTypeDesc qtVideoCodecList[] = {
|
||||
{kRawCodecType, 1, "Uncompressed"},
|
||||
{kJPEGCodecType, 2, "JPEG"},
|
||||
{kMotionJPEGACodecType, 3, "M-JPEG A"},
|
||||
@ -96,34 +120,75 @@ static QuicktimeCodecTypeDesc qtCodecList[] = {
|
||||
{kH264CodecType, 12, "H.264"},
|
||||
{0,0,NULL}};
|
||||
|
||||
static int qtCodecCount = 12;
|
||||
static int qtVideoCodecCount = 12;
|
||||
|
||||
int quicktime_get_num_codecs() {
|
||||
return qtCodecCount;
|
||||
int quicktime_get_num_videocodecs() {
|
||||
return qtVideoCodecCount;
|
||||
}
|
||||
|
||||
QuicktimeCodecTypeDesc* quicktime_get_codecType_desc(int indexValue) {
|
||||
if ((indexValue>=0) && (indexValue < qtCodecCount))
|
||||
return &qtCodecList[indexValue];
|
||||
QuicktimeCodecTypeDesc* quicktime_get_videocodecType_desc(int indexValue) {
|
||||
if ((indexValue>=0) && (indexValue < qtVideoCodecCount))
|
||||
return &qtVideoCodecList[indexValue];
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int quicktime_rnatmpvalue_from_codectype(int codecType) {
|
||||
int quicktime_rnatmpvalue_from_videocodectype(int codecType) {
|
||||
int i;
|
||||
for (i=0;i<qtCodecCount;i++) {
|
||||
if (qtCodecList[i].codecType == codecType)
|
||||
return qtCodecList[i].rnatmpvalue;
|
||||
for (i=0;i<qtVideoCodecCount;i++) {
|
||||
if (qtVideoCodecList[i].codecType == codecType)
|
||||
return qtVideoCodecList[i].rnatmpvalue;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int quicktime_codecType_from_rnatmpvalue(int rnatmpvalue) {
|
||||
int quicktime_videocodecType_from_rnatmpvalue(int rnatmpvalue) {
|
||||
int i;
|
||||
for (i=0;i<qtCodecCount;i++) {
|
||||
if (qtCodecList[i].rnatmpvalue == rnatmpvalue)
|
||||
return qtCodecList[i].codecType;
|
||||
for (i=0;i<qtVideoCodecCount;i++) {
|
||||
if (qtVideoCodecList[i].rnatmpvalue == rnatmpvalue)
|
||||
return qtVideoCodecList[i].codecType;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Audio codec */
|
||||
static QuicktimeCodecTypeDesc qtAudioCodecList[] = {
|
||||
{0, 0, "No audio"},
|
||||
{kAudioFormatLinearPCM, 1, "LPCM"},
|
||||
{kAudioFormatAppleLossless, 2, "Apple Lossless"},
|
||||
{kAudioFormatMPEG4AAC, 3, "AAC"},
|
||||
{0,0,NULL}};
|
||||
|
||||
static int qtAudioCodecCount = 4;
|
||||
|
||||
int quicktime_get_num_audiocodecs() {
|
||||
return qtAudioCodecCount;
|
||||
}
|
||||
|
||||
QuicktimeCodecTypeDesc* quicktime_get_audiocodecType_desc(int indexValue) {
|
||||
if ((indexValue>=0) && (indexValue < qtAudioCodecCount))
|
||||
return &qtAudioCodecList[indexValue];
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int quicktime_rnatmpvalue_from_audiocodectype(int codecType) {
|
||||
int i;
|
||||
for (i=0;i<qtAudioCodecCount;i++) {
|
||||
if (qtAudioCodecList[i].codecType == codecType)
|
||||
return qtAudioCodecList[i].rnatmpvalue;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int quicktime_audiocodecType_from_rnatmpvalue(int rnatmpvalue) {
|
||||
int i;
|
||||
for (i=0;i<qtAudioCodecCount;i++) {
|
||||
if (qtAudioCodecList[i].rnatmpvalue == rnatmpvalue)
|
||||
return qtAudioCodecList[i].codecType;
|
||||
}
|
||||
|
||||
return 0;
|
||||
@ -172,14 +237,68 @@ void filepath_qt(char *string, RenderData *rd) {
|
||||
}
|
||||
|
||||
|
||||
#pragma mark audio export functions
|
||||
|
||||
static OSStatus write_cookie(AudioConverterRef converter, AudioFileID outfile)
|
||||
{
|
||||
// grab the cookie from the converter and write it to the file
|
||||
UInt32 cookieSize = 0;
|
||||
OSStatus err = AudioConverterGetPropertyInfo(converter, kAudioConverterCompressionMagicCookie, &cookieSize, NULL);
|
||||
// if there is an error here, then the format doesn't have a cookie, so on we go
|
||||
if (!err && cookieSize) {
|
||||
char* cookie = malloc(cookieSize);
|
||||
|
||||
err = AudioConverterGetProperty(converter, kAudioConverterCompressionMagicCookie, &cookieSize, cookie);
|
||||
|
||||
if (!err)
|
||||
err = AudioFileSetProperty (outfile, kAudioFilePropertyMagicCookieData, cookieSize, cookie);
|
||||
// even though some formats have cookies, some files don't take them
|
||||
|
||||
free(cookie);
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
/* AudioConverter input stream callback */
|
||||
static OSStatus AudioConverterInputCallback(AudioConverterRef inAudioConverter,
|
||||
UInt32* ioNumberDataPackets,
|
||||
AudioBufferList* ioData,
|
||||
AudioStreamPacketDescription** outDataPacketDescription,
|
||||
void* inUserData)
|
||||
{
|
||||
if (qtexport->audioTotalExportedFrames >= qtexport->audioLastFrame) { /* EOF */
|
||||
*ioNumberDataPackets = 0;
|
||||
return noErr;
|
||||
}
|
||||
|
||||
if (qtexport->audioInputFormat.mBytesPerPacket * *ioNumberDataPackets > AUDIOOUTPUTBUFFERSIZE)
|
||||
*ioNumberDataPackets = AUDIOOUTPUTBUFFERSIZE / qtexport->audioInputFormat.mBytesPerPacket;
|
||||
|
||||
if ((qtexport->audioTotalExportedFrames + *ioNumberDataPackets) > qtexport->audioLastFrame)
|
||||
*ioNumberDataPackets += qtexport->audioLastFrame - qtexport->audioTotalExportedFrames;
|
||||
|
||||
qtexport->audioTotalExportedFrames += *ioNumberDataPackets;
|
||||
|
||||
AUD_readDevice(qtexport->audioInputDevice, (UInt8*)qtexport->audioInputBuffer,
|
||||
qtexport->audioInputFormat.mFramesPerPacket * *ioNumberDataPackets);
|
||||
|
||||
ioData->mBuffers[0].mDataByteSize = qtexport->audioInputFormat.mBytesPerPacket * *ioNumberDataPackets;
|
||||
ioData->mBuffers[0].mData = qtexport->audioInputBuffer;
|
||||
ioData->mBuffers[0].mNumberChannels = qtexport->audioInputFormat.mChannelsPerFrame;
|
||||
|
||||
return noErr;
|
||||
}
|
||||
|
||||
|
||||
#pragma mark export functions
|
||||
|
||||
int start_qt(struct Scene *scene, struct RenderData *rd, int rectx, int recty, ReportList *reports)
|
||||
{
|
||||
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
|
||||
NSError *error;
|
||||
char name[2048];
|
||||
char name[1024];
|
||||
int success= 1;
|
||||
OSStatus err=noErr;
|
||||
|
||||
if(qtexport == NULL) qtexport = MEM_callocN(sizeof(QuicktimeExport), "QuicktimeExport");
|
||||
|
||||
@ -192,14 +311,223 @@ int start_qt(struct Scene *scene, struct RenderData *rd, int rectx, int recty, R
|
||||
}
|
||||
else {
|
||||
makeqtstring(rd, name);
|
||||
qtexport->filename = [NSString stringWithCString:name
|
||||
qtexport->filename = [[NSString alloc] initWithCString:name
|
||||
encoding:[NSString defaultCStringEncoding]];
|
||||
qtexport->movie = nil;
|
||||
qtexport->audioFile = NULL;
|
||||
|
||||
if (rd->qtcodecsettings.audiocodecType) {
|
||||
// generate a name for our video & audio files
|
||||
/* Init audio file */
|
||||
CFURLRef outputFileURL;
|
||||
char extension[32];
|
||||
AudioFileTypeID audioFileType;
|
||||
|
||||
switch (rd->qtcodecsettings.audiocodecType) {
|
||||
case kAudioFormatLinearPCM:
|
||||
audioFileType = kAudioFileWAVEType;
|
||||
strcpy(extension,".wav");
|
||||
break;
|
||||
case kAudioFormatMPEG4AAC:
|
||||
case kAudioFormatAppleLossless:
|
||||
audioFileType = kAudioFileM4AType;
|
||||
strcpy(extension, ".m4a");
|
||||
break;
|
||||
default:
|
||||
audioFileType = kAudioFileAIFFType;
|
||||
strcpy(extension,".aiff");
|
||||
break;
|
||||
}
|
||||
|
||||
tmpnam(name);
|
||||
strcat(name, extension);
|
||||
outputFileURL = CFURLCreateFromFileSystemRepresentation(kCFAllocatorDefault,(UInt8*) name, strlen(name), false);
|
||||
|
||||
if (outputFileURL) {
|
||||
|
||||
qtexport->audioFileName = [[NSString alloc] initWithCString:name
|
||||
encoding:[NSString defaultCStringEncoding]];
|
||||
|
||||
qtexport->audioInputFormat.mSampleRate = U.audiorate;
|
||||
qtexport->audioInputFormat.mFormatID = kAudioFormatLinearPCM;
|
||||
qtexport->audioInputFormat.mChannelsPerFrame = U.audiochannels;
|
||||
switch (U.audioformat) {
|
||||
case AUD_FORMAT_U8:
|
||||
qtexport->audioInputFormat.mBitsPerChannel = 8;
|
||||
qtexport->audioInputFormat.mFormatFlags = 0;
|
||||
break;
|
||||
case AUD_FORMAT_S24:
|
||||
qtexport->audioInputFormat.mBitsPerChannel = 24;
|
||||
qtexport->audioInputFormat.mFormatFlags = kLinearPCMFormatFlagIsSignedInteger;
|
||||
break;
|
||||
case AUD_FORMAT_S32:
|
||||
qtexport->audioInputFormat.mBitsPerChannel = 32;
|
||||
qtexport->audioInputFormat.mFormatFlags = kLinearPCMFormatFlagIsSignedInteger;
|
||||
break;
|
||||
case AUD_FORMAT_FLOAT32:
|
||||
qtexport->audioInputFormat.mBitsPerChannel = 32;
|
||||
qtexport->audioInputFormat.mFormatFlags = kLinearPCMFormatFlagIsFloat;
|
||||
break;
|
||||
case AUD_FORMAT_FLOAT64:
|
||||
qtexport->audioInputFormat.mBitsPerChannel = 64;
|
||||
qtexport->audioInputFormat.mFormatFlags = kLinearPCMFormatFlagIsFloat;
|
||||
break;
|
||||
case AUD_FORMAT_S16:
|
||||
default:
|
||||
qtexport->audioInputFormat.mBitsPerChannel = 16;
|
||||
qtexport->audioInputFormat.mFormatFlags = kLinearPCMFormatFlagIsSignedInteger;
|
||||
break;
|
||||
}
|
||||
qtexport->audioInputFormat.mBytesPerFrame = qtexport->audioInputFormat.mChannelsPerFrame * qtexport->audioInputFormat.mBitsPerChannel / 8;
|
||||
qtexport->audioInputFormat.mFramesPerPacket = 1;
|
||||
qtexport->audioInputFormat.mBytesPerPacket = qtexport->audioInputFormat.mBytesPerFrame;
|
||||
qtexport->audioInputFormat.mFormatFlags |= kLinearPCMFormatFlagIsPacked;
|
||||
|
||||
|
||||
/*Ouput format*/
|
||||
qtexport->audioOutputFormat.mFormatID = rd->qtcodecsettings.audiocodecType;
|
||||
//TODO: set audio channels
|
||||
qtexport->audioOutputFormat.mChannelsPerFrame = 2;
|
||||
qtexport->audioOutputFormat.mSampleRate = rd->qtcodecsettings.audioSampleRate;
|
||||
|
||||
/* Default value for compressed formats, overriden after if not the case */
|
||||
qtexport->audioOutputFormat.mFramesPerPacket = 0;
|
||||
qtexport->audioOutputFormat.mBytesPerFrame = 0;
|
||||
qtexport->audioOutputFormat.mBytesPerPacket = 0;
|
||||
qtexport->audioOutputFormat.mBitsPerChannel = 0;
|
||||
|
||||
switch (rd->qtcodecsettings.audiocodecType) {
|
||||
case kAudioFormatMPEG4AAC:
|
||||
qtexport->audioOutputFormat.mFormatFlags = kMPEG4Object_AAC_Main;
|
||||
case kAudioFormatAppleLossless:
|
||||
switch (U.audioformat) {
|
||||
case AUD_FORMAT_S16:
|
||||
qtexport->audioOutputFormat.mFormatFlags = kAppleLosslessFormatFlag_16BitSourceData;
|
||||
break;
|
||||
case AUD_FORMAT_S24:
|
||||
qtexport->audioOutputFormat.mFormatFlags = kAppleLosslessFormatFlag_24BitSourceData;
|
||||
break;
|
||||
case AUD_FORMAT_S32:
|
||||
qtexport->audioOutputFormat.mFormatFlags = kAppleLosslessFormatFlag_32BitSourceData;
|
||||
break;
|
||||
case AUD_FORMAT_U8:
|
||||
case AUD_FORMAT_FLOAT32:
|
||||
case AUD_FORMAT_FLOAT64:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case kAudioFormatLinearPCM:
|
||||
default:
|
||||
switch (rd->qtcodecsettings.audioBitDepth) {
|
||||
case AUD_FORMAT_U8:
|
||||
qtexport->audioOutputFormat.mBitsPerChannel = 8;
|
||||
qtexport->audioOutputFormat.mFormatFlags = 0;
|
||||
break;
|
||||
case AUD_FORMAT_S24:
|
||||
qtexport->audioOutputFormat.mBitsPerChannel = 24;
|
||||
qtexport->audioOutputFormat.mFormatFlags = kLinearPCMFormatFlagIsSignedInteger;
|
||||
break;
|
||||
case AUD_FORMAT_S32:
|
||||
qtexport->audioOutputFormat.mBitsPerChannel = 32;
|
||||
qtexport->audioOutputFormat.mFormatFlags = kLinearPCMFormatFlagIsSignedInteger;
|
||||
break;
|
||||
case AUD_FORMAT_FLOAT32:
|
||||
qtexport->audioOutputFormat.mBitsPerChannel = 32;
|
||||
qtexport->audioOutputFormat.mFormatFlags = kLinearPCMFormatFlagIsFloat;
|
||||
break;
|
||||
case AUD_FORMAT_FLOAT64:
|
||||
qtexport->audioOutputFormat.mBitsPerChannel = 64;
|
||||
qtexport->audioOutputFormat.mFormatFlags = kLinearPCMFormatFlagIsFloat;
|
||||
break;
|
||||
case AUD_FORMAT_S16:
|
||||
default:
|
||||
qtexport->audioOutputFormat.mBitsPerChannel = 16;
|
||||
qtexport->audioOutputFormat.mFormatFlags = kLinearPCMFormatFlagIsSignedInteger;
|
||||
break;
|
||||
}
|
||||
qtexport->audioOutputFormat.mFormatFlags |= kLinearPCMFormatFlagIsPacked;
|
||||
qtexport->audioOutputFormat.mBytesPerPacket = qtexport->audioOutputFormat.mChannelsPerFrame * (qtexport->audioOutputFormat.mBitsPerChannel / 8);
|
||||
qtexport->audioOutputFormat.mFramesPerPacket = 1;
|
||||
qtexport->audioOutputFormat.mBytesPerFrame = qtexport->audioOutputFormat.mBytesPerPacket;
|
||||
break;
|
||||
}
|
||||
|
||||
err = AudioFileCreateWithURL(outputFileURL, audioFileType, &qtexport->audioOutputFormat, kAudioFileFlags_EraseFile, &qtexport->audioFile);
|
||||
CFRelease(outputFileURL);
|
||||
|
||||
if(err)
|
||||
BKE_report(reports, RPT_ERROR, "\nQuicktime: unable to create temporary audio file. Format error ?");
|
||||
else {
|
||||
err = AudioConverterNew(&qtexport->audioInputFormat, &qtexport->audioOutputFormat, &qtexport->audioConverter);
|
||||
if (err) {
|
||||
BKE_report(reports, RPT_ERROR, "\nQuicktime: unable to initialize audio codec converter. Format error ?");
|
||||
AudioFileClose(qtexport->audioFile);
|
||||
qtexport->audioFile = NULL;
|
||||
[qtexport->audioFileName release];
|
||||
qtexport->audioFileName = nil;
|
||||
} else {
|
||||
UInt32 prop,propSize;
|
||||
/* Set up codec properties */
|
||||
if (rd->qtcodecsettings.audiocodecType == kAudioFormatMPEG4AAC) { /*Lossy compressed format*/
|
||||
prop = rd->qtcodecsettings.audioBitRate;
|
||||
AudioConverterSetProperty(qtexport->audioConverter, kAudioConverterEncodeBitRate,
|
||||
sizeof(prop), &prop);
|
||||
|
||||
if (rd->qtcodecsettings.audioCodecFlags & QTAUDIO_FLAG_CODEC_ISCBR)
|
||||
prop = kAudioCodecBitRateControlMode_Constant;
|
||||
else
|
||||
prop = kAudioCodecBitRateControlMode_LongTermAverage;
|
||||
AudioConverterSetProperty(qtexport->audioConverter, kAudioCodecPropertyBitRateControlMode,
|
||||
sizeof(prop), &prop);
|
||||
}
|
||||
/* Conversion quality : if performance impact then offer degraded option */
|
||||
if ((rd->qtcodecsettings.audioCodecFlags & QTAUDIO_FLAG_RESAMPLE_NOHQ) == 0) {
|
||||
prop = kAudioConverterSampleRateConverterComplexity_Mastering;
|
||||
AudioConverterSetProperty(qtexport->audioConverter, kAudioConverterSampleRateConverterComplexity,
|
||||
sizeof(prop), &prop);
|
||||
|
||||
prop = kAudioConverterQuality_Max;
|
||||
AudioConverterSetProperty(qtexport->audioConverter, kAudioConverterSampleRateConverterQuality,
|
||||
sizeof(prop), &prop);
|
||||
}
|
||||
|
||||
write_cookie(qtexport->audioConverter, qtexport->audioFile);
|
||||
|
||||
/* Allocate output buffer */
|
||||
if (qtexport->audioOutputFormat.mBytesPerPacket ==0) /* VBR */
|
||||
AudioConverterGetProperty(qtexport->audioConverter, kAudioConverterPropertyMaximumOutputPacketSize,
|
||||
&propSize, &qtexport->audioCodecMaxOutputPacketSize);
|
||||
else
|
||||
qtexport->audioCodecMaxOutputPacketSize = qtexport->audioOutputFormat.mBytesPerPacket;
|
||||
|
||||
qtexport->audioInputBuffer = MEM_mallocN(AUDIOOUTPUTBUFFERSIZE, "qt_audio_inputPacket");
|
||||
qtexport->audioOutputBuffer = MEM_mallocN(AUDIOOUTPUTBUFFERSIZE, "qt_audio_outputPacket");
|
||||
qtexport->audioOutputPktDesc = MEM_mallocN(sizeof(AudioStreamPacketDescription)*AUDIOOUTPUTBUFFERSIZE/qtexport->audioCodecMaxOutputPacketSize,
|
||||
"qt_audio_pktdesc");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (err == noErr) {
|
||||
qtexport->videoTempFileName = [[NSString alloc] initWithCString:tmpnam(nil)
|
||||
encoding:[NSString defaultCStringEncoding]];
|
||||
if (qtexport->videoTempFileName)
|
||||
qtexport->movie = [[QTMovie alloc] initToWritableFile:qtexport->videoTempFileName error:&error];
|
||||
|
||||
}
|
||||
} else
|
||||
qtexport->movie = [[QTMovie alloc] initToWritableFile:qtexport->filename error:&error];
|
||||
|
||||
if(qtexport->movie == nil) {
|
||||
BKE_report(reports, RPT_ERROR, "Unable to create quicktime movie.");
|
||||
success= 0;
|
||||
NSLog(@"Unable to create quicktime movie : %@",[error localizedDescription]);
|
||||
if (qtexport->filename) [qtexport->filename release];
|
||||
qtexport->filename = nil;
|
||||
if (qtexport->audioFileName) [qtexport->audioFileName release];
|
||||
qtexport->audioFileName = nil;
|
||||
if (qtexport->videoTempFileName) [qtexport->videoTempFileName release];
|
||||
qtexport->videoTempFileName = nil;
|
||||
[QTMovie exitQTKitOnThread];
|
||||
} else {
|
||||
[qtexport->movie retain];
|
||||
@ -226,6 +554,23 @@ int start_qt(struct Scene *scene, struct RenderData *rd, int rectx, int recty, R
|
||||
nil];
|
||||
}
|
||||
[qtexport->frameAttributes retain];
|
||||
|
||||
if (qtexport->audioFile) {
|
||||
/* Init audio input stream */
|
||||
AUD_DeviceSpecs specs;
|
||||
|
||||
specs.channels = U.audiochannels;
|
||||
specs.format = U.audioformat;
|
||||
specs.rate = U.audiorate;
|
||||
qtexport->audioInputDevice = AUD_openReadDevice(specs);
|
||||
AUD_playDevice(qtexport->audioInputDevice, scene->sound_scene, rd->sfra * rd->frs_sec_base / rd->frs_sec);
|
||||
|
||||
qtexport->audioOutputPktPos = 0;
|
||||
qtexport->audioTotalExportedFrames = 0;
|
||||
qtexport->audioTotalSavedFrames = 0;
|
||||
|
||||
qtexport->audioLastFrame = (rd->efra - rd->sfra) * qtexport->audioInputFormat.mSampleRate * rd->frs_sec_base / rd->frs_sec;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -276,6 +621,41 @@ int append_qt(struct RenderData *rd, int frame, int *pixels, int rectx, int rect
|
||||
|
||||
[blBitmapFormatImage release];
|
||||
[frameImage release];
|
||||
|
||||
|
||||
if (qtexport->audioFile) {
|
||||
UInt32 audioPacketsConverted;
|
||||
/* Append audio */
|
||||
while (((double)qtexport->audioTotalExportedFrames / (double) qtexport->audioInputFormat.mSampleRate)
|
||||
< ((double)(frame - rd->sfra)) / (((double)rd->frs_sec) / rd->frs_sec_base)) {
|
||||
|
||||
qtexport->audioBufferList.mNumberBuffers = 1;
|
||||
qtexport->audioBufferList.mBuffers[0].mNumberChannels = qtexport->audioOutputFormat.mChannelsPerFrame;
|
||||
qtexport->audioBufferList.mBuffers[0].mDataByteSize = AUDIOOUTPUTBUFFERSIZE;
|
||||
qtexport->audioBufferList.mBuffers[0].mData = qtexport->audioOutputBuffer;
|
||||
audioPacketsConverted = AUDIOOUTPUTBUFFERSIZE / qtexport->audioCodecMaxOutputPacketSize;
|
||||
|
||||
AudioConverterFillComplexBuffer(qtexport->audioConverter, AudioConverterInputCallback,
|
||||
NULL, &audioPacketsConverted, &qtexport->audioBufferList, qtexport->audioOutputPktDesc);
|
||||
if (audioPacketsConverted) {
|
||||
AudioFileWritePackets(qtexport->audioFile, false, qtexport->audioBufferList.mBuffers[0].mDataByteSize,
|
||||
qtexport->audioOutputPktDesc, qtexport->audioOutputPktPos, &audioPacketsConverted, qtexport->audioOutputBuffer);
|
||||
qtexport->audioOutputPktPos += audioPacketsConverted;
|
||||
|
||||
if (qtexport->audioOutputFormat.mFramesPerPacket) {
|
||||
// this is the common case: format has constant frames per packet
|
||||
qtexport->audioTotalSavedFrames += (audioPacketsConverted * qtexport->audioOutputFormat.mFramesPerPacket);
|
||||
} else {
|
||||
unsigned int i;
|
||||
// if there are variable frames per packet, then we have to do this for each packeet
|
||||
for (i = 0; i < audioPacketsConverted; ++i)
|
||||
qtexport->audioTotalSavedFrames += qtexport->audioOutputPktDesc[i].mVariableFramesInPacket;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
[pool drain];
|
||||
|
||||
return 1;
|
||||
@ -284,14 +664,93 @@ int append_qt(struct RenderData *rd, int frame, int *pixels, int rectx, int rect
|
||||
|
||||
void end_qt(void)
|
||||
{
|
||||
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
|
||||
if (qtexport->movie) {
|
||||
|
||||
if (qtexport->audioFile)
|
||||
{
|
||||
NSDictionary *dict = nil;
|
||||
QTMovie *audioTmpMovie = nil;
|
||||
NSError *error;
|
||||
NSFileManager *fileManager;
|
||||
|
||||
/* Mux video and audio then save file */
|
||||
|
||||
/* Write last frames for VBR files */
|
||||
if (qtexport->audioOutputFormat.mBitsPerChannel == 0) {
|
||||
OSStatus err = noErr;
|
||||
AudioConverterPrimeInfo primeInfo;
|
||||
UInt32 primeSize = sizeof(primeInfo);
|
||||
|
||||
err = AudioConverterGetProperty(qtexport->audioConverter, kAudioConverterPrimeInfo, &primeSize, &primeInfo);
|
||||
if (err == noErr) {
|
||||
// there's priming to write out to the file
|
||||
AudioFilePacketTableInfo pti;
|
||||
pti.mPrimingFrames = primeInfo.leadingFrames;
|
||||
pti.mRemainderFrames = primeInfo.trailingFrames;
|
||||
pti.mNumberValidFrames = qtexport->audioTotalSavedFrames - pti.mPrimingFrames - pti.mRemainderFrames;
|
||||
AudioFileSetProperty(qtexport->audioFile, kAudioFilePropertyPacketTableInfo, sizeof(pti), &pti);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
write_cookie(qtexport->audioConverter, qtexport->audioFile);
|
||||
AudioConverterDispose(qtexport->audioConverter);
|
||||
AudioFileClose(qtexport->audioFile);
|
||||
AUD_closeReadDevice(qtexport->audioInputDevice);
|
||||
qtexport->audioFile = NULL;
|
||||
qtexport->audioInputDevice = NULL;
|
||||
MEM_freeN(qtexport->audioInputBuffer);
|
||||
MEM_freeN(qtexport->audioOutputBuffer);
|
||||
MEM_freeN(qtexport->audioOutputPktDesc);
|
||||
|
||||
/* Reopen audio file and merge it */
|
||||
audioTmpMovie = [QTMovie movieWithFile:qtexport->audioFileName error:&error];
|
||||
if (audioTmpMovie) {
|
||||
NSArray *audioTracks = [audioTmpMovie tracksOfMediaType:QTMediaTypeSound];
|
||||
QTTrack *audioTrack = nil;
|
||||
if( [audioTracks count] > 0 )
|
||||
{
|
||||
audioTrack = [audioTracks objectAtIndex:0];
|
||||
}
|
||||
|
||||
if( audioTrack )
|
||||
{
|
||||
QTTimeRange totalRange;
|
||||
totalRange.time = QTZeroTime;
|
||||
totalRange.duration = [[audioTmpMovie attributeForKey:QTMovieDurationAttribute] QTTimeValue];
|
||||
|
||||
[qtexport->movie insertSegmentOfTrack:audioTrack timeRange:totalRange atTime:QTZeroTime];
|
||||
}
|
||||
}
|
||||
|
||||
/* Save file */
|
||||
dict = [NSDictionary dictionaryWithObject:[NSNumber numberWithBool:YES]
|
||||
forKey:QTMovieFlatten];
|
||||
|
||||
if (dict) {
|
||||
[qtexport->movie writeToFile:qtexport->filename withAttributes:dict];
|
||||
}
|
||||
|
||||
/* Delete temp files */
|
||||
fileManager = [[NSFileManager alloc] init];
|
||||
[fileManager removeItemAtPath:qtexport->audioFileName error:&error];
|
||||
[fileManager removeItemAtPath:qtexport->videoTempFileName error:&error];
|
||||
}
|
||||
else {
|
||||
/* Flush update of the movie file */
|
||||
[qtexport->movie updateMovieFile];
|
||||
|
||||
[qtexport->movie invalidate];
|
||||
}
|
||||
|
||||
/* Clean up movie structure */
|
||||
[qtexport->filename release];
|
||||
if (qtexport->filename) [qtexport->filename release];
|
||||
qtexport->filename = nil;
|
||||
if (qtexport->audioFileName) [qtexport->audioFileName release];
|
||||
qtexport->audioFileName = nil;
|
||||
if (qtexport->videoTempFileName) [qtexport->videoTempFileName release];
|
||||
qtexport->videoTempFileName = nil;
|
||||
[qtexport->frameAttributes release];
|
||||
[qtexport->movie release];
|
||||
}
|
||||
@ -302,6 +761,7 @@ void end_qt(void)
|
||||
MEM_freeN(qtexport);
|
||||
qtexport = NULL;
|
||||
}
|
||||
[pool drain];
|
||||
}
|
||||
|
||||
|
||||
@ -318,6 +778,15 @@ void quicktime_verify_image_type(RenderData *rd)
|
||||
rd->qtcodecsettings.codecType = kJPEGCodecType;
|
||||
rd->qtcodecsettings.codecSpatialQuality = (codecHighQuality*100)/codecLosslessQuality;
|
||||
}
|
||||
if ((rd->qtcodecsettings.audioSampleRate < 21000) ||
|
||||
(rd->qtcodecsettings.audioSampleRate > 193000))
|
||||
rd->qtcodecsettings.audioSampleRate = 48000;
|
||||
|
||||
if (rd->qtcodecsettings.audioBitDepth == 0)
|
||||
rd->qtcodecsettings.audioBitDepth = AUD_FORMAT_S16;
|
||||
|
||||
if (rd->qtcodecsettings.audioBitRate == 0)
|
||||
rd->qtcodecsettings.audioBitRate = 256000;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -123,7 +123,7 @@ static int sframe;
|
||||
|
||||
/* RNA functions */
|
||||
|
||||
static QuicktimeCodecTypeDesc qtCodecList[] = {
|
||||
static QuicktimeCodecTypeDesc qtVideoCodecList[] = {
|
||||
{kRawCodecType, 1, "Uncompressed"},
|
||||
{kJPEGCodecType, 2, "JPEG"},
|
||||
{kMotionJPEGACodecType, 3, "M-JPEG A"},
|
||||
@ -138,34 +138,34 @@ static QuicktimeCodecTypeDesc qtCodecList[] = {
|
||||
{kH264CodecType, 12, "H.264"},
|
||||
{0,0,NULL}};
|
||||
|
||||
static int qtCodecCount = 12;
|
||||
static int qtVideoCodecCount = 12;
|
||||
|
||||
int quicktime_get_num_codecs() {
|
||||
return qtCodecCount;
|
||||
int quicktime_get_num_videocodecs() {
|
||||
return qtVideoCodecCount;
|
||||
}
|
||||
|
||||
QuicktimeCodecTypeDesc* quicktime_get_codecType_desc(int indexValue) {
|
||||
if ((indexValue>=0) && (indexValue < qtCodecCount))
|
||||
return &qtCodecList[indexValue];
|
||||
QuicktimeCodecTypeDesc* quicktime_get_videocodecType_desc(int indexValue) {
|
||||
if ((indexValue>=0) && (indexValue < qtVideoCodecCount))
|
||||
return &qtVideoCodecList[indexValue];
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int quicktime_rnatmpvalue_from_codectype(int codecType) {
|
||||
int quicktime_rnatmpvalue_from_videocodectype(int codecType) {
|
||||
int i;
|
||||
for (i=0;i<qtCodecCount;i++) {
|
||||
if (qtCodecList[i].codecType == codecType)
|
||||
return qtCodecList[i].rnatmpvalue;
|
||||
for (i=0;i<qtVideoCodecCount;i++) {
|
||||
if (qtVideoCodecList[i].codecType == codecType)
|
||||
return qtVideoCodecList[i].rnatmpvalue;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int quicktime_codecType_from_rnatmpvalue(int rnatmpvalue) {
|
||||
int quicktime_videocodecType_from_rnatmpvalue(int rnatmpvalue) {
|
||||
int i;
|
||||
for (i=0;i<qtCodecCount;i++) {
|
||||
if (qtCodecList[i].rnatmpvalue == rnatmpvalue)
|
||||
return qtCodecList[i].codecType;
|
||||
for (i=0;i<qtVideoCodecCount;i++) {
|
||||
if (qtVideoCodecList[i].rnatmpvalue == rnatmpvalue)
|
||||
return qtVideoCodecList[i].codecType;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
@ -34,6 +34,10 @@
|
||||
#define __AIFF__
|
||||
|
||||
|
||||
#define QTAUDIO_FLAG_RESAMPLE_NOHQ 1
|
||||
#define QTAUDIO_FLAG_CODEC_ISCBR 2
|
||||
|
||||
|
||||
/*Codec list*/
|
||||
typedef struct QuicktimeCodecTypeDesc {
|
||||
int codecType;
|
||||
@ -54,10 +58,19 @@ void filepath_qt(char *string, struct RenderData *rd);
|
||||
|
||||
/*RNA helper functions */
|
||||
void quicktime_verify_image_type(struct RenderData *rd); //used by RNA for defaults values init, if needed
|
||||
int quicktime_get_num_codecs();
|
||||
QuicktimeCodecTypeDesc* quicktime_get_codecType_desc(int indexValue);
|
||||
int quicktime_rnatmpvalue_from_codectype(int codecType);
|
||||
int quicktime_codecType_from_rnatmpvalue(int rnatmpvalue);
|
||||
/*Video codec type*/
|
||||
int quicktime_get_num_videocodecs();
|
||||
QuicktimeCodecTypeDesc* quicktime_get_videocodecType_desc(int indexValue);
|
||||
int quicktime_rnatmpvalue_from_videocodectype(int codecType);
|
||||
int quicktime_videocodecType_from_rnatmpvalue(int rnatmpvalue);
|
||||
|
||||
#ifdef USE_QTKIT
|
||||
/*Audio codec type*/
|
||||
int quicktime_get_num_audiocodecs();
|
||||
QuicktimeCodecTypeDesc* quicktime_get_audiocodecType_desc(int indexValue);
|
||||
int quicktime_rnatmpvalue_from_audiocodectype(int codecType);
|
||||
int quicktime_audiocodecType_from_rnatmpvalue(int rnatmpvalue);
|
||||
#endif
|
||||
|
||||
#ifndef USE_QTKIT
|
||||
void SCENE_OT_render_data_set_quicktime_codec(struct wmOperatorType *ot); //Operator to raise quicktime standard dialog to request codec settings
|
||||
|
Loading…
Reference in New Issue
Block a user