Add check for presence of XiphQT in exporter.
Prevents creation of empty audio track when the Xiph Vorbis encoder
component is not installed.
BUG=http://code.google.com/p/webm/issues/detail?id=386
TEST=Exporting from iMovie without a Vorbis encoder does not
produce a WebM file with an audio track that contains no
audio samples.
Change-Id: I7a9f1b161c96dc229e2284aa8c8640ff75eb72fa
diff --git a/WebM.xcodeproj/project.pbxproj b/WebM.xcodeproj/project.pbxproj
index d3b0360..5ce9d32 100644
--- a/WebM.xcodeproj/project.pbxproj
+++ b/WebM.xcodeproj/project.pbxproj
@@ -13,6 +13,7 @@
374E201D13FD898300A14F1C /* libwebm.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 374E201813FD891100A14F1C /* libwebm.a */; };
374E203513FD8B4400A14F1C /* libvpx.a in Frameworks */ = {isa = PBXBuildFile; fileRef = BB98158C11FF19600031AA75 /* libvpx.a */; };
6A0610C114F72EFB003AC5D2 /* keystone_util.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 6A0610C014F72EFB003AC5D2 /* keystone_util.cpp */; };
+ 6A22654C150566BF007BE07A /* quicktime_util.cc in Sources */ = {isa = PBXBuildFile; fileRef = 6A22654B150566BF007BE07A /* quicktime_util.cc */; };
8D01CCCA0486CAD60068D4B7 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 089C167DFE841241C02AAC07 /* InfoPlist.strings */; };
8D01CCCE0486CAD60068D4B7 /* Carbon.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 08EA7FFBFE8413EDC02AAC07 /* Carbon.framework */; };
BB124AE012392B0300A26F24 /* VP8EncoderGui.c in Sources */ = {isa = PBXBuildFile; fileRef = BB124ADF12392B0300A26F24 /* VP8EncoderGui.c */; };
@@ -80,6 +81,8 @@
6A0610BF14F72EFB003AC5D2 /* keystone_util.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = keystone_util.h; sourceTree = "<group>"; };
6A0610C014F72EFB003AC5D2 /* keystone_util.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = keystone_util.cpp; sourceTree = "<group>"; };
6A0610C214F731A4003AC5D2 /* bundle_info.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = bundle_info.h; sourceTree = "<group>"; };
+ 6A22654A150566BF007BE07A /* quicktime_util.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = quicktime_util.h; sourceTree = "<group>"; };
+ 6A22654B150566BF007BE07A /* quicktime_util.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = quicktime_util.cc; sourceTree = "<group>"; };
8D01CCD10486CAD60068D4B7 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist; path = Info.plist; sourceTree = "<group>"; };
8D01CCD20486CAD60068D4B7 /* AWebM.component */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = AWebM.component; sourceTree = BUILT_PRODUCTS_DIR; };
BB124ADE12392B0300A26F24 /* VP8EncoderGui.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = VP8EncoderGui.h; sourceTree = "<group>"; };
@@ -321,6 +324,8 @@
BB9817C811FF47060031AA75 /* Mux */ = {
isa = PBXGroup;
children = (
+ 6A22654A150566BF007BE07A /* quicktime_util.h */,
+ 6A22654B150566BF007BE07A /* quicktime_util.cc */,
BB98159411FF1BCF0031AA75 /* WebMAudioStream.h */,
BB98159311FF1BCF0031AA75 /* WebMAudioStream.c */,
BB9815A611FF1BCF0031AA75 /* WebMVideoStream.h */,
@@ -463,6 +468,7 @@
103EF9A5128B2DC60032CEE6 /* WebMImport.cpp in Sources */,
103EF9A6128B2DCB0032CEE6 /* mkvreaderqt.cpp in Sources */,
6A0610C114F72EFB003AC5D2 /* keystone_util.cpp in Sources */,
+ 6A22654C150566BF007BE07A /* quicktime_util.cc in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
diff --git a/WebMExport.c b/WebMExport.c
index f9644ba..8341f59 100644
--- a/WebMExport.c
+++ b/WebMExport.c
@@ -15,14 +15,13 @@
#include "keystone_util.h"
#include "log.h"
+#include "quicktime_util.h"
#include "WebMExportStructs.h"
#include "WebMExportVersions.h"
#include "VP8CodecVersion.h"
#include "WebMExport.h"
-
-
-
#include "WebMExportGui.h"
+
/* component selector methods, TODO find out why only these 3 need to be declared */
pascal ComponentResult WebMExportGetComponentPropertyInfo(WebMExportGlobalsPtr store,
ComponentPropertyClass inPropClass,
@@ -116,6 +115,10 @@
store->webmTimeCodeScale = 1000000; ///TODO figure out about how to use this
+ store->bCanExportAudio = CanExportVorbisAudio();
+ dbg_printf("[WebMExport:%s] bCanExportAudio=%s\n", __func__,
+ (store->bCanExportAudio ? "true" : "false"));
+
SetComponentInstanceStorage(self, (Handle) store);
cd.componentType = MovieExportType;
diff --git a/WebMExportStructs.h b/WebMExportStructs.h
index 4959279..df7f538 100644
--- a/WebMExportStructs.h
+++ b/WebMExportStructs.h
@@ -116,6 +116,8 @@
Movie setdlg_movie;
Track setdlg_track;
+ Boolean bCanExportAudio;
+
} WebMExportGlobals, *WebMExportGlobalsPtr;
#endif /* __exporter_types_h__ */
diff --git a/WebMMux.c b/WebMMux.c
index fb229b0..0bec8b5 100644
--- a/WebMMux.c
+++ b/WebMMux.c
@@ -102,7 +102,7 @@
0, /*flag lacing*/
"V_VP8", id->width, id->height, fps);
}
- else if (gs->trackType == SoundMediaType)
+ else if (gs->trackType == SoundMediaType && globals->bCanExportAudio)
{
AudioStreamPtr as = &gs->aud;
unsigned int trackNumber;
diff --git a/quicktime_util.cc b/quicktime_util.cc
new file mode 100644
index 0000000..d94e344
--- /dev/null
+++ b/quicktime_util.cc
@@ -0,0 +1,132 @@
+// Copyright (c) 2012 The WebM project authors. All Rights Reserved.
+//
+// Use of this source code is governed by a BSD-style license
+// that can be found in the LICENSE file in the root of the source
+// tree. An additional intellectual property rights grant can be found
+// in the file PATENTS. All contributing project authors may
+// be found in the AUTHORS file in the root of the source tree.
+
+#include "quicktime_util.h"
+
+#include <QuickTime/QuickTime.h>
+
+#include <new>
+
+#include "log.h"
+#include "WebMExportVersions.h"
+
+// TODO(tomfinegan): Move this, it doesn't belong here.
+#define WEBMQT_DISALLOW_COPY_AND_ASSIGN(TypeName) \
+ TypeName(const TypeName&); \
+ void operator=(const TypeName&)
+
+namespace {
+// Utility class for managing the list of |FourCharCode|s returned from
+// |QTGetComponentPropertyInfo| when the available compression formats list
+// (|kQTSCAudioPropertyID_AvailableCompressionFormatList|) is requested.
+class CompressionFormats {
+ public:
+ CompressionFormats(const FourCharCode* ptr_formats, int format_count)
+ : formats_(ptr_formats),
+ num_formats_(format_count) {}
+ ~CompressionFormats() {
+ delete[] formats_;
+ }
+
+ const FourCharCode* formats() const { return formats_; }
+ int num_formats() const { return num_formats_; }
+
+ private:
+ const FourCharCode* formats_;
+ const int num_formats_;
+ WEBMQT_DISALLOW_COPY_AND_ASSIGN(CompressionFormats);
+};
+} // namespace
+
+// Returns list of compression formats available to QuickTime. Caller owns
+// memory allocated via new for |CompressionFormats*|. Returns NULL on failure.
+const CompressionFormats* AudioCompressionFormatsList(
+ ComponentInstance component) {
+ if (!component) {
+ dbg_printf("[webm:%s] NULL component.\n", __func__);
+ return NULL;
+ }
+
+ // Request number of bytes required to store compression format list.
+ ByteCount format_list_size = 0;
+ int err = QTGetComponentPropertyInfo(
+ component,
+ kQTPropertyClass_SCAudio,
+ kQTSCAudioPropertyID_AvailableCompressionFormatList,
+ NULL,
+ &format_list_size,
+ NULL);
+ if (err != noErr) {
+ dbg_printf("[webm:%s] cannot get format list size (%d).\n", __func__, err);
+ return NULL;
+ }
+
+ // Convert byte count to number of |FourCharCode|s.
+ const int num_formats =
+ (format_list_size + (sizeof(FourCharCode) - 1)) / sizeof(FourCharCode);
+
+ // Allocate the format list storage.
+ FourCharCode* const ptr_format_list =
+ new (std::nothrow) FourCharCode[num_formats];
+
+ if (ptr_format_list) {
+ // Request the format list from QuickTime.
+ err = QTGetComponentProperty(
+ component,
+ kQTPropertyClass_SCAudio,
+ kQTSCAudioPropertyID_AvailableCompressionFormatList,
+ format_list_size,
+ ptr_format_list,
+ NULL); // NULL, ignore amount of storage consumed.
+ if (err != noErr) {
+ dbg_printf("[webm:%s] format list read failed (%d).\n", __func__, err);
+ delete[] ptr_format_list;
+ return NULL;
+ }
+ }
+
+ const CompressionFormats* const ptr_formats =
+ new (std::nothrow) CompressionFormats(ptr_format_list, num_formats);
+ if (!ptr_formats) {
+ delete[] ptr_format_list;
+ }
+ return ptr_formats;
+}
+
+// Returns true when the XiphQT Vorbis |FourCharCode| format identifier,
+// |kAudioFormatXiphVorbis|, is included in the list of formats returned by
+// |AudioCompressionFormatsList()|.
+bool CanExportVorbisAudio() {
+ bool can_export_vorbis = false;
+ ComponentInstance vorbis_component = NULL;
+ const OSType compression_type = StandardCompressionType;
+ const OSType sub_type = StandardCompressionSubTypeAudio;
+
+ if (!OpenADefaultComponent(compression_type, sub_type, &vorbis_component)) {
+ // |ptr_formats| is owned by this function, and must be |delete|d.
+ const CompressionFormats* ptr_formats =
+ AudioCompressionFormatsList(vorbis_component);
+ if (ptr_formats && ptr_formats->formats()) {
+ const FourCharCode* const ptr_format_list = ptr_formats->formats();
+ for (int i = 0; i < ptr_formats->num_formats(); ++i) {
+ if (ptr_format_list[i] == kAudioFormatXiphVorbis) {
+ can_export_vorbis = true;
+ break;
+ }
+ }
+ }
+ delete ptr_formats;
+
+ // Close the component-- just probing capabilities here.
+ CloseComponent(vorbis_component);
+ }
+
+ dbg_printf("[webm:%s] can_export_vorbis=%s.\n", __func__,
+ (can_export_vorbis ? "true" : "false"));
+ return can_export_vorbis;
+}
diff --git a/quicktime_util.h b/quicktime_util.h
new file mode 100644
index 0000000..3ec19bd
--- /dev/null
+++ b/quicktime_util.h
@@ -0,0 +1,24 @@
+// Copyright (c) 2012 The WebM project authors. All Rights Reserved.
+//
+// Use of this source code is governed by a BSD-style license
+// that can be found in the LICENSE file in the root of the source
+// tree. An additional intellectual property rights grant can be found
+// in the file PATENTS. All contributing project authors may
+// be found in the AUTHORS file in the root of the source tree.
+
+#if !defined WEBMQUICKTIME_QUICKTIME_UTIL_H_
+#define WEBMQUICKTIME_QUICKTIME_UTIL_H_
+
+#if defined __cplusplus
+extern "C" {
+#endif
+
+// Returns true when the XiphQT Vorbis component is accessible through the
+// QuickTime component management interface.
+bool CanExportVorbisAudio();
+
+#if defined __cplusplus
+} // extern "C"
+#endif
+
+#endif // WEBMQUICKTIME_QUICKTIME_UTIL_H_