namespace
{
- static const ByteVector headerGuid("\x30\x26\xB2\x75\x8E\x66\xCF\x11\xA6\xD9\x00\xAA\x00\x62\xCE\x6C", 16);
- static const ByteVector filePropertiesGuid("\xA1\xDC\xAB\x8C\x47\xA9\xCF\x11\x8E\xE4\x00\xC0\x0C\x20\x53\x65", 16);
- static const ByteVector streamPropertiesGuid("\x91\x07\xDC\xB7\xB7\xA9\xCF\x11\x8E\xE6\x00\xC0\x0C\x20\x53\x65", 16);
- static const ByteVector contentDescriptionGuid("\x33\x26\xB2\x75\x8E\x66\xCF\x11\xA6\xD9\x00\xAA\x00\x62\xCE\x6C", 16);
- static const ByteVector extendedContentDescriptionGuid("\x40\xA4\xD0\xD2\x07\xE3\xD2\x11\x97\xF0\x00\xA0\xC9\x5E\xA8\x50", 16);
- static const ByteVector headerExtensionGuid("\xb5\x03\xbf_.\xa9\xcf\x11\x8e\xe3\x00\xc0\x0c Se", 16);
- static const ByteVector metadataGuid("\xEA\xCB\xF8\xC5\xAF[wH\204g\xAA\214D\xFAL\xCA", 16);
- static const ByteVector metadataLibraryGuid("\224\034#D\230\224\321I\241A\x1d\x13NEpT", 16);
- static const ByteVector contentEncryptionGuid("\xFB\xB3\x11\x22\x23\xBD\xD2\x11\xB4\xB7\x00\xA0\xC9\x55\xFC\x6E", 16);
- static const ByteVector extendedContentEncryptionGuid("\x14\xE6\x8A\x29\x22\x26 \x17\x4C\xB9\x35\xDA\xE0\x7E\xE9\x28\x9C", 16);
- static const ByteVector advancedContentEncryptionGuid("\xB6\x9B\x07\x7A\xA4\xDA\x12\x4E\xA5\xCA\x91\xD3\x8D\xC1\x1A\x8D", 16);
+ const ByteVector headerGuid("\x30\x26\xB2\x75\x8E\x66\xCF\x11\xA6\xD9\x00\xAA\x00\x62\xCE\x6C", 16);
+ const ByteVector filePropertiesGuid("\xA1\xDC\xAB\x8C\x47\xA9\xCF\x11\x8E\xE4\x00\xC0\x0C\x20\x53\x65", 16);
+ const ByteVector streamPropertiesGuid("\x91\x07\xDC\xB7\xB7\xA9\xCF\x11\x8E\xE6\x00\xC0\x0C\x20\x53\x65", 16);
+ const ByteVector contentDescriptionGuid("\x33\x26\xB2\x75\x8E\x66\xCF\x11\xA6\xD9\x00\xAA\x00\x62\xCE\x6C", 16);
+ const ByteVector extendedContentDescriptionGuid("\x40\xA4\xD0\xD2\x07\xE3\xD2\x11\x97\xF0\x00\xA0\xC9\x5E\xA8\x50", 16);
+ const ByteVector headerExtensionGuid("\xb5\x03\xbf_.\xa9\xcf\x11\x8e\xe3\x00\xc0\x0c Se", 16);
+ const ByteVector metadataGuid("\xEA\xCB\xF8\xC5\xAF[wH\204g\xAA\214D\xFAL\xCA", 16);
+ const ByteVector metadataLibraryGuid("\224\034#D\230\224\321I\241A\x1d\x13NEpT", 16);
+ const ByteVector codecListGuid("\x40\x52\xd1\x86\x1d\x31\xd0\x11\xa3\xa4\x00\xa0\xc9\x03\x48\xf6", 16);
+ const ByteVector contentEncryptionGuid("\xFB\xB3\x11\x22\x23\xBD\xD2\x11\xB4\xB7\x00\xA0\xC9\x55\xFC\x6E", 16);
+ const ByteVector extendedContentEncryptionGuid("\x14\xE6\x8A\x29\x22\x26 \x17\x4C\xB9\x35\xDA\xE0\x7E\xE9\x28\x9C", 16);
+ const ByteVector advancedContentEncryptionGuid("\xB6\x9B\x07\x7A\xA4\xDA\x12\x4E\xA5\xCA\x91\xD3\x8D\xC1\x1A\x8D", 16);
}
class ASF::File::BaseObject
ByteVector render(ASF::File *file);
};
+class ASF::File::CodecListObject : public ASF::File::BaseObject
+{
+public:
+ ByteVector guid();
+ void parse(ASF::File *file, uint size);
+};
+
ASF::File::HeaderExtensionObject::~HeaderExtensionObject()
{
for(unsigned int i = 0; i < objects.size(); i++) {
return;
}
+ file->d->properties->setCodec(data.toUShort(54, false));
file->d->properties->setChannels(data.toUShort(56, false));
file->d->properties->setSampleRate(data.toUInt(58, false));
file->d->properties->setBitrate(static_cast<int>(data.toUInt(62, false) * 8.0 / 1000.0 + 0.5));
return BaseObject::render(file);
}
+ByteVector ASF::File::CodecListObject::guid()
+{
+ return codecListGuid;
+}
+
+void ASF::File::CodecListObject::parse(ASF::File *file, uint size)
+{
+ BaseObject::parse(file, size);
+ if(data.size() <= 20) {
+ debug("ASF::File::CodecListObject::parse() -- data is too short.");
+ return;
+ }
+
+ uint pos = 16;
+
+ const int count = data.toUInt(pos, false);
+ pos += 4;
+
+ for(int i = 0; i < count; ++i) {
+
+ if(pos >= data.size())
+ break;
+
+ const int type = data.toUShort(pos, false);
+ pos += 2;
+
+ int nameLength = data.toUShort(pos, false);
+ pos += 2;
+
+ const uint namePos = pos;
+ pos += nameLength * 2;
+
+ const int descLength = data.toUShort(pos, false);
+ pos += 2;
+
+ const uint descPos = pos;
+ pos += descLength * 2;
+
+ const int infoLength = data.toUShort(pos, false);
+ pos += 2 + infoLength * 2;
+
+ if(type == 2) {
+ // First audio codec found.
+
+ const String name(data.mid(namePos, nameLength * 2), String::UTF16LE);
+ file->d->properties->setCodecName(name.stripWhiteSpace());
+
+ const String desc(data.mid(descPos, descLength * 2), String::UTF16LE);
+ file->d->properties->setCodecDescription(desc.stripWhiteSpace());
+
+ break;
+ }
+ }
+}
+
////////////////////////////////////////////////////////////////////////////////
// public members
////////////////////////////////////////////////////////////////////////////////
else if(guid == headerExtensionGuid) {
obj = new HeaderExtensionObject();
}
+ else if(guid == codecListGuid) {
+ obj = new CodecListObject();
+ }
else {
if(guid == contentEncryptionGuid ||
guid == extendedContentEncryptionGuid ||
class ContentDescriptionObject;
class ExtendedContentDescriptionObject;
class HeaderExtensionObject;
+ class CodecListObject;
class MetadataObject;
class MetadataLibraryObject;
sampleRate(0),
channels(0),
bitsPerSample(0),
+ codec(ASF::Properties::Unknown),
encrypted(false) {}
int length;
int sampleRate;
int channels;
int bitsPerSample;
+ ASF::Properties::Codec codec;
+ String codecName;
+ String codecDescription;
bool encrypted;
};
return d->bitsPerSample;
}
+ASF::Properties::Codec ASF::Properties::codec() const
+{
+ return d->codec;
+}
+
+String ASF::Properties::codecName() const
+{
+ return d->codecName;
+}
+
+String ASF::Properties::codecDescription() const
+{
+ return d->codecDescription;
+}
+
bool ASF::Properties::isEncrypted() const
{
return d->encrypted;
d->bitsPerSample = value;
}
+void ASF::Properties::setCodec(int value)
+{
+ switch(value)
+ {
+ case 0x0160:
+ d->codec = WMA1;
+ break;
+ case 0x0161:
+ d->codec = WMA2;
+ break;
+ case 0x0162:
+ d->codec = WMA9Pro;
+ break;
+ case 0x0163:
+ d->codec = WMA9Lossless;
+ break;
+ default:
+ d->codec = Unknown;
+ break;
+ }
+}
+
+void ASF::Properties::setCodecName(const String &value)
+{
+ d->codecName = value;
+}
+
+void ASF::Properties::setCodecDescription(const String &value)
+{
+ d->codecDescription = value;
+}
+
void ASF::Properties::setEncrypted(bool value)
{
d->encrypted = value;
public:
/*!
- * Create an instance of ASF::Properties.
+ * Audio codec types can be used in ASF file.
+ */
+ enum Codec
+ {
+ /*!
+ * Couldn't detect the codec.
+ */
+ Unknown = 0,
+
+ /*!
+ * Windows Media Audio 1
+ */
+ WMA1,
+
+ /*!
+ * Windows Media Audio 2 or above
+ */
+ WMA2,
+
+ /*!
+ * Windows Media Audio 9 Professional
+ */
+ WMA9Pro,
+
+ /*!
+ * Windows Media Audio 9 Lossless
+ */
+ WMA9Lossless,
+ };
+
+ /*!
+ * Creates an instance of ASF::Properties.
*/
Properties();
* Returns the sample rate in Hz.
*/
virtual int sampleRate() const;
+
/*!
* Returns the number of audio channels.
*/
*/
int bitsPerSample() const;
+ /*!
+ * Returns the codec used in the file.
+ *
+ * \see codecName()
+ * \see codecDescription()
+ */
+ Codec codec() const;
+
+ /*!
+ * Returns the concrete codec name, for example "Windows Media Audio 9.1"
+ * used in the file if available, otherwise an empty string.
+ *
+ * \see codec()
+ * \see codecDescription()
+ */
+ String codecName() const;
+
+ /*!
+ * Returns the codec description, typically contains the encoder settings,
+ * for example "VBR Quality 50, 44kHz, stereo 1-pass VBR" if available,
+ * otherwise an empty string.
+ *
+ * \see codec()
+ * \see codecName()
+ */
+ String codecDescription() const;
+
/*!
* Returns whether or not the file is encrypted.
*/
void setSampleRate(int value);
void setChannels(int value);
void setBitsPerSample(int value);
+ void setCodec(int value);
+ void setCodecName(const String &value);
+ void setCodecDescription(const String &value);
void setEncrypted(bool value);
#endif
{
CPPUNIT_TEST_SUITE(TestASF);
CPPUNIT_TEST(testAudioProperties);
+ CPPUNIT_TEST(testLosslessProperties);
CPPUNIT_TEST(testRead);
CPPUNIT_TEST(testSaveMultipleValues);
CPPUNIT_TEST(testSaveStream);
CPPUNIT_ASSERT_EQUAL(2, f.audioProperties()->channels());
CPPUNIT_ASSERT_EQUAL(48000, f.audioProperties()->sampleRate());
CPPUNIT_ASSERT_EQUAL(16, f.audioProperties()->bitsPerSample());
+ CPPUNIT_ASSERT_EQUAL(ASF::Properties::WMA2, f.audioProperties()->codec());
+ CPPUNIT_ASSERT_EQUAL(String("Windows Media Audio 9.1"), f.audioProperties()->codecName());
+ CPPUNIT_ASSERT_EQUAL(String("64 kbps, 48 kHz, stereo 2-pass CBR"), f.audioProperties()->codecDescription());
+ CPPUNIT_ASSERT_EQUAL(false, f.audioProperties()->isEncrypted());
+ }
+
+ void testLosslessProperties()
+ {
+ ASF::File f(TEST_FILE_PATH_C("lossless.wma"));
+ CPPUNIT_ASSERT(f.audioProperties());
+ CPPUNIT_ASSERT_EQUAL(3, f.audioProperties()->length());
+ CPPUNIT_ASSERT_EQUAL(3, f.audioProperties()->lengthInSeconds());
+ CPPUNIT_ASSERT_EQUAL(3549, f.audioProperties()->lengthInMilliseconds());
+ CPPUNIT_ASSERT_EQUAL(1152, f.audioProperties()->bitrate());
+ CPPUNIT_ASSERT_EQUAL(2, f.audioProperties()->channels());
+ CPPUNIT_ASSERT_EQUAL(44100, f.audioProperties()->sampleRate());
+ CPPUNIT_ASSERT_EQUAL(16, f.audioProperties()->bitsPerSample());
+ CPPUNIT_ASSERT_EQUAL(ASF::Properties::WMA9Lossless, f.audioProperties()->codec());
+ CPPUNIT_ASSERT_EQUAL(String("Windows Media Audio 9.2 Lossless"), f.audioProperties()->codecName());
+ CPPUNIT_ASSERT_EQUAL(String("VBR Quality 100, 44 kHz, 2 channel 16 bit 1-pass VBR"), f.audioProperties()->codecDescription());
CPPUNIT_ASSERT_EQUAL(false, f.audioProperties()->isEncrypted());
}