Merge branch 'gsoc2012'
parent
233f0dd986
commit
9b131f3c61
@ -0,0 +1,746 @@
|
||||
// ***************************************************************** -*- C++ -*-
|
||||
/*
|
||||
* Copyright (C) 2004-2012 Andreas Huggel <ahuggel@gmx.net>
|
||||
*
|
||||
* This program is part of the Exiv2 distribution.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, 5th Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
/*
|
||||
File: asfvideo.cpp
|
||||
Version: $Rev$
|
||||
Author(s): Abhinav Badola for GSoC 2012 (AB) <mail.abu.to@gmail.com>
|
||||
History: 08-Aug-12, AB: created
|
||||
Credits: See header file
|
||||
*/
|
||||
// *****************************************************************************
|
||||
#include "rcsid_int.hpp"
|
||||
EXIV2_RCSID("@(#) $Id$")
|
||||
|
||||
// *****************************************************************************
|
||||
// included header files
|
||||
#include "asfvideo.hpp"
|
||||
#include "futils.hpp"
|
||||
#include "basicio.hpp"
|
||||
#include "tags.hpp"
|
||||
#include "tags_int.hpp"
|
||||
#include "types.hpp"
|
||||
#include "riffvideo.hpp"
|
||||
#include "convert.hpp"
|
||||
|
||||
// + standard includes
|
||||
#include <cmath>
|
||||
#include <cstring>
|
||||
#include <ctype.h>
|
||||
|
||||
// *****************************************************************************
|
||||
// class member definitions
|
||||
namespace Exiv2 {
|
||||
namespace Internal {
|
||||
|
||||
/*!
|
||||
Tag Look-up list for ASF Type Video Files
|
||||
Associates the GUID of a Tag with its Tag Name(i.e. Human Readable Form)
|
||||
Tags have been diferentiated into Various Categories.
|
||||
The categories have been listed above the Tag Groups
|
||||
|
||||
*/
|
||||
extern const TagVocabulary GUIDReferenceTags[] = {
|
||||
/// Top-level ASF object GUIDS
|
||||
{ "75B22630-668E-11CF-A6D9-00AA0062CE6C", "Header" },
|
||||
{ "75B22636-668E-11CF-A6D9-00AA0062CE6C", "Data" },
|
||||
{ "33000890-E5B1-11CF-89F4-00A0C90349CB", "Simple_Index" },
|
||||
{ "D6E229D3-35DA-11D1-9034-00A0C90349BE", "Index" },
|
||||
{ "FEB103F8-12AD-4C64-840F-2A1D2F7AD48C", "Media_Index" },
|
||||
{ "3CB73FD0-0C4A-4803-953D-EDF7B6228F0C", "Timecode_Index" },
|
||||
|
||||
/// Header Object GUIDs
|
||||
{ "8CABDCA1-A947-11CF-8EE4-00C00C205365", "File_Properties" },
|
||||
{ "B7DC0791-A9B7-11CF-8EE6-00C00C205365", "Stream_Properties" },
|
||||
{ "5FBF03B5-A92E-11CF-8EE3-00C00C205365", "Header_Extension" },
|
||||
{ "86D15240-311D-11D0-A3A4-00A0C90348F6", "Codec_List" },
|
||||
{ "1EFB1A30-0B62-11D0-A39B-00A0C90348F6", "Script_Command" },
|
||||
{ "F487CD01-A951-11CF-8EE6-00C00C205365", "Marker" },
|
||||
{ "D6E229DC-35DA-11D1-9034-00A0C90349BE", "Bitrate_Mutual_Exclusion" },
|
||||
{ "75B22635-668E-11CF-A6D9-00AA0062CE6C", "Error_Correction" },
|
||||
{ "75B22633-668E-11CF-A6D9-00AA0062CE6C", "Content_Description" },
|
||||
{ "D2D0A440-E307-11D2-97F0-00A0C95EA850", "Extended_Content_Description" },
|
||||
{ "2211B3FA-BD23-11D2-B4B7-00A0C955FC6E", "Content_Branding" },
|
||||
{ "7BF875CE-468D-11D1-8D82-006097C9A2B2", "Stream_Bitrate_Properties" },
|
||||
{ "2211B3FB-BD23-11D2-B4B7-00A0C955FC6E", "Content_Encryption" },
|
||||
{ "298AE614-2622-4C17-B935-DAE07EE9289C", "Extended_Content_Encryption" },
|
||||
{ "2211B3FC-BD23-11D2-B4B7-00A0C955FC6E", "Digital_Signature" },
|
||||
{ "1806D474-CADF-4509-A4BA-9AABCB96AAE8", "Padding" },
|
||||
|
||||
/// Header Extension Object GUIDs
|
||||
{ "14E6A5CB-C672-4332-8399-A96952065B5A", "Extended_Stream_Properties" },
|
||||
{ "A08649CF-4775-4670-8A16-6E35357566CD", "Advanced_Mutual_Exclusion" },
|
||||
{ "D1465A40-5A79-4338-B71B-E36B8FD6C249", "Group_Mutual_Exclusion" },
|
||||
{ "D4FED15B-88D3-454F-81F0-ED5C45999E24", "Stream_Prioritization" },
|
||||
{ "A69609E6-517B-11D2-B6AF-00C04FD908E9", "Bandwidth_Sharing" },
|
||||
{ "7C4346A9-EFE0-4BFC-B229-393EDE415C85", "Language_List" },
|
||||
{ "C5F8CBEA-5BAF-4877-8467-AA8C44FA4CCA", "Metadata" },
|
||||
{ "44231C94-9498-49D1-A141-1D134E457054", "Metadata_Library" },
|
||||
{ "D6E229DF-35DA-11D1-9034-00A0C90349BE", "Index_Parameters" },
|
||||
{ "6B203BAD-3F11-48E4-ACA8-D7613DE2CFA7", "Media_Index_Parameters" },
|
||||
{ "F55E496D-9797-4B5D-8C8B-604DFE9BFB24", "Timecode_Index_Parameters" },
|
||||
{ "26F18B5D-4584-47EC-9F5F-0E651F0452C9", "Compatibility" },
|
||||
{ "43058533-6981-49E6-9B74-AD12CB86D58C", "Advanced_Content_Encryption" },
|
||||
|
||||
/// Stream Properties Object Stream Type GUIDs
|
||||
{ "F8699E40-5B4D-11CF-A8FD-00805F5C442B", "Audio_Media" },
|
||||
{ "BC19EFC0-5B4D-11CF-A8FD-00805F5C442B", "Video_Media" },
|
||||
{ "59DACFC0-59E6-11D0-A3AC-00A0C90348F6", "Command_Media" },
|
||||
{ "B61BE100-5B4E-11CF-A8FD-00805F5C442B", "JFIF_Media" },
|
||||
{ "35907DE0-E415-11CF-A917-00805F5C442B", "Degradable_JPEG_Media" },
|
||||
{ "91BD222C-F21C-497A-8B6D-5AA86BFC0185", "File_Transfer_Media" },
|
||||
{ "3AFB65E2-47EF-40F2-AC2C-70A90D71D343", "Binary_Media" },
|
||||
|
||||
/// Web stream Type-Specific Data GUIDs
|
||||
{ "776257D4-C627-41CB-8F81-7AC7FF1C40CC", "Web_Stream_Media_Subtype" },
|
||||
{ "DA1E6B13-8359-4050-B398-388E965BF00C", "Web_Stream_Format" },
|
||||
|
||||
/// Stream Properties Object Error Correction Type GUIDs
|
||||
{ "20FB5700-5B55-11CF-A8FD-00805F5C442B", "No_Error_Correction" },
|
||||
{ "BFC3CD50-618F-11CF-8BB2-00AA00B4E220", "Audio_Spread" },
|
||||
|
||||
/// Header Extension Object GUIDs
|
||||
{ "ABD3D211-A9BA-11cf-8EE6-00C00C205365", "Reserved_1" },
|
||||
|
||||
/// Advanced Content Encryption Object System ID GUIDs
|
||||
{ "7A079BB6-DAA4-4e12-A5CA-91D38DC11A8D", "Content_Encryption_System_Windows_Media_DRM_Network_Devices" },
|
||||
|
||||
/// Codec List Object GUIDs
|
||||
{ "86D15241-311D-11D0-A3A4-00A0C90348F6", "Reserved_2" },
|
||||
|
||||
/// Script Command Object GUIDs
|
||||
{ "4B1ACBE3-100B-11D0-A39B-00A0C90348F6", "Reserved_3" },
|
||||
|
||||
/// Marker Object GUIDs
|
||||
{ "4CFEDB20-75F6-11CF-9C0F-00A0C90349CB", "Reserved_4" },
|
||||
|
||||
/// Mutual Exclusion Object Exclusion Type GUIDs
|
||||
{ "D6E22A00-35DA-11D1-9034-00A0C90349BE", "Mutex_Language" },
|
||||
{ "D6E22A01-35DA-11D1-9034-00A0C90349BE", "Mutex_Bitrate" },
|
||||
{ "D6E22A02-35DA-11D1-9034-00A0C90349BE", "Mutex_Unknown" },
|
||||
|
||||
/// Bandwidth Sharing Object GUIDs
|
||||
{ "AF6060AA-5197-11D2-B6AF-00C04FD908E9", "Bandwidth_Sharing_Exclusive" },
|
||||
{ "AF6060AB-5197-11D2-B6AF-00C04FD908E9", "Bandwidth_Sharing_Partial" },
|
||||
|
||||
/// Standard Payload Extension System GUIDs
|
||||
{ "399595EC-8667-4E2D-8FDB-98814CE76C1E", "Payload_Extension_System_Timecode" },
|
||||
{ "E165EC0E-19ED-45D7-B4A7-25CBD1E28E9B", "Payload_Extension_System_File_Name" },
|
||||
{ "D590DC20-07BC-436C-9CF7-F3BBFBF1A4DC", "Payload_Extension_System_Content_Type" },
|
||||
{ "1B1EE554-F9EA-4BC8-821A-376B74E4C4B8", "Payload_Extension_System_Pixel_Aspect_Ratio" },
|
||||
{ "C6BD9450-867F-4907-83A3-C77921B733AD", "Payload_Extension_System_Sample_Duration" },
|
||||
{ "6698B84E-0AFA-4330-AEB2-1C0A98D7A44D", "Payload_Extension_System_Encryption_Sample_ID" },
|
||||
{ "00E1AF06-7BEC-11D1-A582-00C04FC29CFB", "Payload_Extension_System_Degradable_JPEG" }
|
||||
};
|
||||
|
||||
//! Audio codec type-specific data in ASF
|
||||
extern const TagDetails audioCodec[] = {
|
||||
{ 0x161, "Windows Media Audio (7, 8, and 9 Series)" },
|
||||
{ 0x162, "Windows Media Audio 9 Professional" },
|
||||
{ 0x163, "Windows Media Audio 9 Lossless" },
|
||||
{ 0x7A21, "GSM-AMR (CBR, no SID)" },
|
||||
{ 0x7A22, "GSM-AMR (VBR including SID)" }
|
||||
};
|
||||
|
||||
extern const TagDetails filePropertiesTags[] = {
|
||||
{ 7, "Xmp.video.FileLength" },
|
||||
{ 6, "Xmp.video.CreationDate" },
|
||||
{ 5, "Xmp.video.DataPackets" },
|
||||
{ 4, "Xmp.video.Duration" },
|
||||
{ 3, "Xmp.video.SendDuration" },
|
||||
{ 2, "Xmp.video.Preroll" },
|
||||
{ 1, "Xmp.video.MaxBitRate" }
|
||||
};
|
||||
|
||||
extern const TagDetails contentDescriptionTags[] = {
|
||||
{ 1, "Xmp.video.Title" },
|
||||
{ 2, "Xmp.video.Author" },
|
||||
{ 3, "Xmp.video.Copyright" },
|
||||
{ 4, "Xmp.video.Description" },
|
||||
{ 5, "Xmp.video.Rating" }
|
||||
};
|
||||
|
||||
/*!
|
||||
@brief Function used to read data from data buffer, reads 16-bit character
|
||||
array and stores it in std::string object.
|
||||
@param buf Exiv2 data buffer, which stores the information
|
||||
@return Returns std::string object .
|
||||
*/
|
||||
std::string toString16(Exiv2::DataBuf& buf)
|
||||
{
|
||||
std::ostringstream os; char t;
|
||||
|
||||
for(int i = 0; i <= buf.size_; i += 2 ) {
|
||||
t = buf.pData_[i] + 16 * buf.pData_[i + 1];
|
||||
if(t == 0) {
|
||||
if(i)
|
||||
os << '\0';
|
||||
break;
|
||||
}
|
||||
os<< t;
|
||||
}
|
||||
return os.str();
|
||||
}
|
||||
|
||||
/*!
|
||||
@brief Function used to check equality of two Tags (ignores case).
|
||||
@param str1 char* Pointer to First Tag
|
||||
@param str2 char* Pointer to Second Tag
|
||||
@return Returns true if both are equal.
|
||||
*/
|
||||
bool compareTag(const char* str1, const char* str2) {
|
||||
if ( strlen(str1) != strlen(str2))
|
||||
return false;
|
||||
|
||||
for ( uint64_t i = 0 ; i < strlen(str1); ++i )
|
||||
if (tolower(str1[i]) != tolower(str2[i]))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*!
|
||||
@brief Function used to convert a decimal number to its Hexadecimal
|
||||
equivalent, then parsed into a character
|
||||
@param n Integer which is to be parsed as Hexadecimal character
|
||||
@return Return a Hexadecimal number, in character
|
||||
*/
|
||||
char returnHEX(int n) {
|
||||
if(n >= 0 && n <= 9)
|
||||
return (char)(n + 48);
|
||||
else
|
||||
return (char)(n + 55);
|
||||
}
|
||||
|
||||
/*!
|
||||
@brief Function used to calulate GUID, Tags comprises of 16 bytes.
|
||||
The Buffer contains the Tag in Binary Form. The information is then
|
||||
parsed into a character array GUID.
|
||||
*/
|
||||
void getGUID (byte buf[], char GUID[]) {
|
||||
int i;
|
||||
for (i = 0; i < 4; ++i) {
|
||||
GUID[(3 - i) * 2] = returnHEX(buf[i] / 0x10);
|
||||
GUID[(3 - i) * 2 + 1] = returnHEX(buf[i] % 0x10);
|
||||
}
|
||||
for (i = 4; i < 6; ++i) {
|
||||
GUID[(9 - i) * 2 + 1] = returnHEX(buf[i] / 0x10);
|
||||
GUID[(9 - i) * 2 + 2] = returnHEX(buf[i] % 0x10);
|
||||
}
|
||||
for (i = 6; i < 8; ++i) {
|
||||
GUID[(14 - i) * 2] = returnHEX(buf[i] / 0x10);
|
||||
GUID[(14 - i) * 2 + 1] = returnHEX(buf[i] % 0x10);
|
||||
}
|
||||
for (i = 8; i < 10; ++i) {
|
||||
GUID[ i * 2 + 3] = returnHEX(buf[i] / 0x10);
|
||||
GUID[ i * 2 + 4] = returnHEX(buf[i] % 0x10);
|
||||
}
|
||||
for (i = 10; i < 16; ++i) {
|
||||
GUID[ i * 2 + 4] = returnHEX(buf[i] / 0x10);
|
||||
GUID[ i * 2 + 5] = returnHEX(buf[i] % 0x10);
|
||||
}
|
||||
GUID[36] = '\0'; GUID[8] = GUID[13] = GUID[18] = GUID[23] = '-';
|
||||
}
|
||||
|
||||
/*!
|
||||
@brief Function used to check if data stored in buf is equivalent to
|
||||
ASF Header Tag's GUID.
|
||||
@param buf Exiv2 byte buffer
|
||||
@return Returns true if the buffer data is equivalent to Header GUID.
|
||||
*/
|
||||
bool isASFType (byte buf[]) {
|
||||
|
||||
if(buf[0] == 0x30 && buf[1] == 0x26 && buf[2] == 0xb2 && buf[3] == 0x75 &&
|
||||
buf[4] == 0x8e && buf[5] == 0x66 && buf[6] == 0xcf && buf[7] == 0x11 &&
|
||||
buf[8] == 0xa6 && buf[9] == 0xd9 && buf[10] == 0x00 && buf[11] == 0xaa &&
|
||||
buf[12] == 0x00 && buf[13] == 0x62 && buf[14] == 0xce && buf[15] == 0x6c )
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
//! Function used to convert buffer data into 64-bit Integer, information stored in littleEndian format
|
||||
uint64_t getUint64_t(Exiv2::DataBuf& buf) {
|
||||
uint64_t temp = 0;
|
||||
|
||||
for(int i = 0; i < 8; ++i)
|
||||
temp = temp + buf.pData_[i]*(pow(256,i));
|
||||
|
||||
return temp;
|
||||
}
|
||||
|
||||
}} // namespace Internal, Exiv2
|
||||
|
||||
namespace Exiv2 {
|
||||
|
||||
using namespace Exiv2::Internal;
|
||||
|
||||
AsfVideo::AsfVideo(BasicIo::AutoPtr io)
|
||||
: Image(ImageType::asf, mdNone, io)
|
||||
{
|
||||
} // AsfVideo::AsfVideo
|
||||
|
||||
std::string AsfVideo::mimeType() const
|
||||
{
|
||||
return "video/asf";
|
||||
}
|
||||
|
||||
void AsfVideo::writeMetadata()
|
||||
{
|
||||
}
|
||||
|
||||
void AsfVideo::readMetadata()
|
||||
{
|
||||
if (io_->open() != 0) throw Error(9, io_->path(), strError());
|
||||
|
||||
// Ensure that this is the correct image type
|
||||
if (!isAsfType(*io_, false)) {
|
||||
if (io_->error() || io_->eof()) throw Error(14);
|
||||
throw Error(3, "ASF");
|
||||
}
|
||||
|
||||
IoCloser closer(*io_);
|
||||
clearMetadata();
|
||||
continueTraversing_ = true;
|
||||
io_->seek(0, BasicIo::beg);
|
||||
height_ = width_ = 1;
|
||||
|
||||
xmpData_["Xmp.video.FileSize"] = (double)io_->size()/(double)1048576;
|
||||
xmpData_["Xmp.video.FileName"] = io_->path();
|
||||
xmpData_["Xmp.video.MimeType"] = mimeType();
|
||||
|
||||
while (continueTraversing_) decodeBlock();
|
||||
|
||||
aspectRatio();
|
||||
} // AsfVideo::readMetadata
|
||||
|
||||
void AsfVideo::decodeBlock()
|
||||
{
|
||||
const long bufMinSize = 8;
|
||||
DataBuf buf(bufMinSize);
|
||||
unsigned long size = 0;
|
||||
buf.pData_[8] = '\0' ;
|
||||
const TagVocabulary* tv;
|
||||
uint64_t cur_pos = io_->tell();
|
||||
|
||||
byte guidBuf[16];
|
||||
io_->read(guidBuf, 16);
|
||||
|
||||
if(io_->eof()) {
|
||||
continueTraversing_ = false;
|
||||
return;
|
||||
}
|
||||
|
||||
char GUID[33] = "";
|
||||
|
||||
getGUID(guidBuf, GUID);
|
||||
tv = find( GUIDReferenceTags, GUID);
|
||||
|
||||
std::memset(buf.pData_, 0x0, buf.size_);
|
||||
io_->read(buf.pData_, 8);
|
||||
size = getUint64_t(buf);
|
||||
|
||||
if(tv)
|
||||
tagDecoder(tv,size-24);
|
||||
else
|
||||
io_->seek(cur_pos + size, BasicIo::beg);
|
||||
|
||||
localPosition_ = io_->tell();
|
||||
} // AsfVideo::decodeBlock
|
||||
|
||||
void AsfVideo::tagDecoder(const TagVocabulary *tv, uint64_t size)
|
||||
{
|
||||
uint64_t cur_pos = io_->tell();
|
||||
DataBuf buf(1000);
|
||||
unsigned long count = 0, tempLength = 0;
|
||||
buf.pData_[4] = '\0' ;
|
||||
Exiv2::Value::AutoPtr v = Exiv2::Value::create(Exiv2::xmpSeq);
|
||||
|
||||
if(compareTag( exvGettext(tv->label_), "Header")) {
|
||||
localPosition_ = 0;
|
||||
io_->read(buf.pData_, 4);
|
||||
io_->read(buf.pData_, 2);
|
||||
|
||||
while(localPosition_ < cur_pos + size) decodeBlock();
|
||||
}
|
||||
|
||||
else if(compareTag( exvGettext(tv->label_), "File_Properties"))
|
||||
fileProperties();
|
||||
|
||||
else if(compareTag( exvGettext(tv->label_), "Stream_Properties"))
|
||||
streamProperties();
|
||||
|
||||
else if(compareTag( exvGettext(tv->label_), "Metadata"))
|
||||
metadataHandler(1);
|
||||
|
||||
else if(compareTag( exvGettext(tv->label_), "Extended_Content_Description"))
|
||||
metadataHandler(2);
|
||||
|
||||
else if(compareTag( exvGettext(tv->label_), "Metadata_Library"))
|
||||
metadataHandler(3);
|
||||
|
||||
else if(compareTag( exvGettext(tv->label_), "Codec_List"))
|
||||
codecList();
|
||||
|
||||
else if(compareTag( exvGettext(tv->label_), "Content_Description"))
|
||||
contentDescription(size);
|
||||
|
||||
else if(compareTag( exvGettext(tv->label_), "Extended_Stream_Properties"))
|
||||
extendedStreamProperties(size);
|
||||
|
||||
else if(compareTag( exvGettext(tv->label_), "Header_Extension")) {
|
||||
localPosition_ = 0;
|
||||
headerExtension(size);
|
||||
}
|
||||
|
||||
else if(compareTag( exvGettext(tv->label_), "Language_List")) {
|
||||
std::memset(buf.pData_, 0x0, buf.size_);
|
||||
io_->read(buf.pData_, 2);
|
||||
count = Exiv2::getUShort(buf.pData_, littleEndian);
|
||||
|
||||
while(count--) {
|
||||
std::memset(buf.pData_, 0x0, buf.size_);
|
||||
io_->read(buf.pData_, 1); tempLength = (int)buf.pData_[0];
|
||||
|
||||
io_->read(buf.pData_, tempLength);
|
||||
v->read(toString16(buf));
|
||||
}
|
||||
xmpData_.add(Exiv2::XmpKey("Xmp.video.TrackLang"), v.get());
|
||||
}
|
||||
|
||||
io_->seek(cur_pos + size, BasicIo::beg);
|
||||
localPosition_ = io_->tell();
|
||||
} // AsfVideo::tagDecoder
|
||||
|
||||
void AsfVideo::extendedStreamProperties(uint64_t size)
|
||||
{
|
||||
uint64_t cur_pos = io_->tell(), avgTimePerFrame = 0;
|
||||
DataBuf buf(8);
|
||||
static int previousStream;
|
||||
io_->seek(cur_pos + 48, BasicIo::beg);
|
||||
|
||||
std::memset(buf.pData_, 0x0, buf.size_);
|
||||
io_->read(buf.pData_, 2);
|
||||
streamNumber_ = Exiv2::getUShort(buf.pData_, littleEndian);
|
||||
|
||||
io_->read(buf.pData_, 2);
|
||||
io_->read(buf.pData_, 8);
|
||||
avgTimePerFrame = getUint64_t(buf);
|
||||
|
||||
if(previousStream < streamNumber_ && avgTimePerFrame != 0)
|
||||
xmpData_["Xmp.video.FrameRate"] = (double)10000000/(double)avgTimePerFrame;
|
||||
|
||||
previousStream = streamNumber_;
|
||||
io_->seek(cur_pos + size, BasicIo::beg);
|
||||
} // AsfVideo::extendedStreamProperties
|
||||
|
||||
void AsfVideo::contentDescription(uint64_t size)
|
||||
{
|
||||
long pos = io_->tell();
|
||||
long length[5];
|
||||
const TagDetails* td;
|
||||
|
||||
for (int i = 0 ; i < 5 ; ++i) {
|
||||
byte buf[2];
|
||||
io_->read(buf, 2);
|
||||
length[i] = (long)buf[0] + 16 * (long)buf[1];
|
||||
}
|
||||
|
||||
for (int i = 0 ; i < 5 ; ++i) {
|
||||
DataBuf buf(length[i]);
|
||||
std::memset(buf.pData_, 0x0, buf.size_);
|
||||
io_->read(buf.pData_, length[i]);
|
||||
td = find(contentDescriptionTags, i + 1);
|
||||
std::string str((const char*)buf.pData_, length[i]);
|
||||
if (convertStringCharset(str, "UCS-2LE", "UTF-8")) {
|
||||
xmpData_[td->label_] = str;
|
||||
}
|
||||
else {
|
||||
xmpData_[td->label_] = toString16(buf);
|
||||
}
|
||||
}
|
||||
io_->seek(pos + size, BasicIo::beg);
|
||||
} // AsfVideo::contentDescription
|
||||
|
||||
void AsfVideo::streamProperties()
|
||||
{
|
||||
DataBuf buf(20);
|
||||
buf.pData_[8] = '\0' ;
|
||||
byte guidBuf[16]; int stream = 0;
|
||||
io_->read(guidBuf, 16);
|
||||
char streamType[33] = "";
|
||||
Exiv2::RiffVideo *test = NULL;
|
||||
|
||||
getGUID(guidBuf, streamType);
|
||||
const TagVocabulary* tv;
|
||||
tv = find( GUIDReferenceTags, streamType);
|
||||
io_->read(guidBuf, 16);
|
||||
|
||||
if(compareTag( exvGettext(tv->label_), "Audio_Media"))
|
||||
stream = 1;
|
||||
else if(compareTag( exvGettext(tv->label_), "Video_Media"))
|
||||
stream = 2;
|
||||
|
||||
io_->read(buf.pData_, 8);
|
||||
if(stream == 2)
|
||||
xmpData_["Xmp.video.TimeOffset"] = getUint64_t(buf);
|
||||
else if(stream == 1)
|
||||
xmpData_["Xmp.audio.TimeOffset"] = getUint64_t(buf);
|
||||
|
||||
io_->read(buf.pData_, 8);
|
||||
std::memset(buf.pData_, 0x0, buf.size_);
|
||||
io_->read(buf.pData_, 1);
|
||||
streamNumber_ = (int)buf.pData_[0] & 127;
|
||||
|
||||
io_->read(buf.pData_, 5);
|
||||
std::memset(buf.pData_, 0x0, buf.size_);
|
||||
io_->read(buf.pData_, 2);
|
||||
long temp = Exiv2::getUShort(buf.pData_, littleEndian);
|
||||
|
||||
if(stream == 2) {
|
||||
xmpData_["Xmp.video.Width"] = temp;
|
||||
width_ = temp;
|
||||
}
|
||||
else if(stream == 1) {
|
||||
xmpData_["Xmp.audio.Codec"] = test->printAudioEncoding(temp);
|
||||
}
|
||||
|
||||
io_->read(buf.pData_, 2);
|
||||
temp = Exiv2::getUShort(buf.pData_, littleEndian);
|
||||
if(stream == 1)
|
||||
xmpData_["Xmp.audio.ChannelType"] = temp;
|
||||
|
||||
io_->read(buf.pData_, 4);
|
||||
temp = Exiv2::getULong(buf.pData_, littleEndian);
|
||||
|
||||
if(stream == 2) {
|
||||
xmpData_["Xmp.video.Height"] = temp;
|
||||
height_ = temp;
|
||||
}
|
||||
else if(stream == 1) {
|
||||
xmpData_["Xmp.audio.SampleRate"] = temp;
|
||||
}
|
||||
} // AsfVideo::streamProperties
|
||||
|
||||
void AsfVideo::codecList()
|
||||
{
|
||||
DataBuf buf(200);
|
||||
io_->read(buf.pData_, 16);
|
||||
std::memset(buf.pData_, 0x0, buf.size_);
|
||||
io_->read(buf.pData_, 4);
|
||||
int codecCount = Exiv2::getULong(buf.pData_, littleEndian), descLength = 0, codecType = 0;
|
||||
|
||||
while(codecCount--) {
|
||||
std::memset(buf.pData_, 0x0, buf.size_);
|
||||
io_->read(buf.pData_, 2);
|
||||
codecType = Exiv2::getUShort(buf.pData_, littleEndian);
|
||||
|
||||
io_->read(buf.pData_, 2);
|
||||
descLength = Exiv2::getUShort(buf.pData_, littleEndian) * 2;
|
||||
io_->read(buf.pData_, descLength);
|
||||
|
||||
if(codecType == 1)
|
||||
xmpData_["Xmp.video.Codec"] = toString16(buf);
|
||||
else if(codecType == 2)
|
||||
xmpData_["Xmp.audio.Compressor"] = toString16(buf);
|
||||
|
||||
std::memset(buf.pData_, 0x0, buf.size_);
|
||||
io_->read(buf.pData_, 2);
|
||||
descLength = Exiv2::getUShort(buf.pData_, littleEndian) * 2;
|
||||
io_->read(buf.pData_, descLength);
|
||||
|
||||
if(codecType == 1)
|
||||
xmpData_["Xmp.video.CodecDescription"] = toString16(buf);
|
||||
else if(codecType == 2)
|
||||
xmpData_["Xmp.audio.CodecDescription"] = toString16(buf);
|
||||
|
||||
std::memset(buf.pData_, 0x0, buf.size_);
|
||||
io_->read(buf.pData_, 2);
|
||||
descLength = Exiv2::getUShort(buf.pData_, littleEndian);
|
||||
io_->read(buf.pData_, descLength);
|
||||
}
|
||||
} // AsfVideo::codecList
|
||||
|
||||
void AsfVideo::headerExtension(uint64_t size)
|
||||
{
|
||||
uint64_t cur_pos = io_->tell();
|
||||
DataBuf buf(20);
|
||||
io_->read(buf.pData_, 18);
|
||||
buf.pData_[4] = '\0' ;
|
||||
io_->read(buf.pData_, 4);
|
||||
|
||||
while(localPosition_ < cur_pos + size) decodeBlock();
|
||||
|
||||
io_->seek(cur_pos + size, BasicIo::beg);
|
||||
} // AsfVideo::headerExtension
|
||||
|
||||
void AsfVideo::metadataHandler(int meta)
|
||||
{
|
||||
DataBuf buf(500);
|
||||
io_->read(buf.pData_, 2);
|
||||
int recordCount = Exiv2::getUShort(buf.pData_, littleEndian), nameLength = 0, dataLength = 0, dataType = 0;
|
||||
Exiv2::Value::AutoPtr v = Exiv2::Value::create(Exiv2::xmpSeq);
|
||||
byte guidBuf[16]; char fileID[33] = "";
|
||||
|
||||
while(recordCount--) {
|
||||
std::memset(buf.pData_, 0x0, buf.size_);
|
||||
|
||||
if(meta == 1 || meta == 3) {
|
||||
io_->read(buf.pData_, 4);
|
||||
io_->read(buf.pData_, 2);
|
||||
nameLength = Exiv2::getUShort(buf.pData_, littleEndian);
|
||||
io_->read(buf.pData_, 2);
|
||||
dataType = Exiv2::getUShort(buf.pData_, littleEndian);
|
||||
io_->read(buf.pData_, 4);
|
||||
dataLength = Exiv2::getULong(buf.pData_, littleEndian);
|
||||
|
||||
io_->read(buf.pData_, nameLength);
|
||||
v->read(toString16(buf));
|
||||
if(dataType == 6) {
|
||||
io_->read(guidBuf, 16);
|
||||
getGUID(guidBuf, fileID);
|
||||
}
|
||||
else
|
||||
io_->read(buf.pData_, dataLength);
|
||||
}
|
||||
|
||||
else if(meta == 2) {
|
||||
io_->read(buf.pData_, 2);
|
||||
nameLength = Exiv2::getUShort(buf.pData_, littleEndian);
|
||||
io_->read(buf.pData_, nameLength);
|
||||
v->read(toString16(buf));
|
||||
|
||||
io_->read(buf.pData_, 2);
|
||||
dataType = Exiv2::getUShort(buf.pData_, littleEndian);
|
||||
|
||||
io_->read(buf.pData_, 2);
|
||||
dataLength = Exiv2::getUShort(buf.pData_, littleEndian);
|
||||
io_->read(buf.pData_, dataLength);
|
||||
}
|
||||
|
||||
if(dataType == 0) { // Unicode String
|
||||
v->read(toString16(buf));
|
||||
}
|
||||
else if(dataType == 2 || dataType == 5) { // 16-bit Unsigned Integer
|
||||
v->read( Exiv2::toString( Exiv2::getUShort(buf.pData_, littleEndian)));
|
||||
}
|
||||
else if(dataType == 3) { // 32-bit Unsigned Integer
|
||||
v->read( Exiv2::toString( Exiv2::getULong( buf.pData_, littleEndian)));
|
||||
}
|
||||
else if(dataType == 4) { // 64-bit Unsigned Integer
|
||||
v->read(Exiv2::toString(getUint64_t(buf)));
|
||||
}
|
||||
else if(dataType == 6) { // 128-bit GUID
|
||||
v->read(Exiv2::toString(fileID));
|
||||
}
|
||||
else { // Byte array
|
||||
v->read( Exiv2::toString(buf.pData_));
|
||||
}
|
||||
}
|
||||
|
||||
if(meta == 1) {
|
||||
xmpData_.add(Exiv2::XmpKey("Xmp.video.Metadata"), v.get());
|
||||
}
|
||||
else if(meta == 2) {
|
||||
xmpData_.add(Exiv2::XmpKey("Xmp.video.ExtendedContentDescription"), v.get());
|
||||
}
|
||||
else {
|
||||
xmpData_.add(Exiv2::XmpKey("Xmp.video.MetadataLibrary"), v.get());
|
||||
}
|
||||
} // AsfVideo::metadataHandler
|
||||
|
||||
void AsfVideo::fileProperties()
|
||||
{
|
||||
DataBuf buf(8);
|
||||
buf.pData_[8] = '\0' ;
|
||||
|
||||
byte guidBuf[16];
|
||||
io_->read(guidBuf, 16);
|
||||
char fileID[33] = ""; int count = 7;
|
||||
getGUID(guidBuf, fileID);
|
||||
xmpData_["Xmp.video.FileID"] = fileID;
|
||||
|
||||
const TagDetails* td;
|
||||
|
||||
while(count--) {
|
||||
td = find(filePropertiesTags , (count + 1));
|
||||
io_->read(buf.pData_, 8);
|
||||
|
||||
if(count == 0) {
|
||||
buf.pData_[4] = '\0' ;
|
||||
io_->read(buf.pData_, 4); io_->read(buf.pData_, 4);
|
||||
}
|
||||
|
||||
if(count == 3 || count == 2) {
|
||||
xmpData_[exvGettext(td->label_)] = getUint64_t(buf) / 10000;
|
||||
}
|
||||
else {
|
||||
xmpData_[exvGettext(td->label_)] = getUint64_t(buf);
|
||||
}
|
||||
}
|
||||
} // AsfVideo::fileProperties
|
||||
|
||||
void AsfVideo::aspectRatio()
|
||||
{
|
||||
//TODO - Make a better unified method to handle all cases of Aspect Ratio
|
||||
|
||||
double aspectRatio = (double)width_ / (double)height_;
|
||||
aspectRatio = floor(aspectRatio*10) / 10;
|
||||
xmpData_["Xmp.video.AspectRatio"] = aspectRatio;
|
||||
|
||||
if(aspectRatio == 1.3) xmpData_["Xmp.video.AspectRatio"] = "4:3";
|
||||
else if(aspectRatio == 1.7) xmpData_["Xmp.video.AspectRatio"] = "16:9";
|
||||
else if(aspectRatio == 1.0) xmpData_["Xmp.video.AspectRatio"] = "1:1";
|
||||
else if(aspectRatio == 1.6) xmpData_["Xmp.video.AspectRatio"] = "16:10";
|
||||
else if(aspectRatio == 2.2) xmpData_["Xmp.video.AspectRatio"] = "2.21:1";
|
||||
else if(aspectRatio == 2.3) xmpData_["Xmp.video.AspectRatio"] = "2.35:1";
|
||||
else if(aspectRatio == 1.2) xmpData_["Xmp.video.AspectRatio"] = "5:4";
|
||||
else xmpData_["Xmp.video.AspectRatio"] = aspectRatio;
|
||||
} // AsfVideo::aspectRatio
|
||||
|
||||
|
||||
Image::AutoPtr newAsfInstance(BasicIo::AutoPtr io, bool /*create*/)
|
||||
{
|
||||
Image::AutoPtr image(new AsfVideo(io));
|
||||
if (!image->good()) {
|
||||
image.reset();
|
||||
}
|
||||
return image;
|
||||
}
|
||||
|
||||
bool isAsfType(BasicIo& iIo, bool advance)
|
||||
{
|
||||
const int32_t len = 16;
|
||||
byte buf[len];
|
||||
iIo.read(buf, len);
|
||||
|
||||
if (iIo.error() || iIo.eof()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool matched = isASFType(buf);
|
||||
if (!advance || !matched) {
|
||||
iIo.seek(0, BasicIo::beg);
|
||||
}
|
||||
|
||||
return matched;
|
||||
}
|
||||
|
||||
} // namespace Exiv2
|
@ -0,0 +1,185 @@
|
||||
// ***************************************************************** -*- C++ -*-
|
||||
/*
|
||||
* Copyright (C) 2004-2012 Andreas Huggel <ahuggel@gmx.net>
|
||||
*
|
||||
* This program is part of the Exiv2 distribution.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, 5th Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
/*!
|
||||
@file asfvideo.hpp
|
||||
@brief An Image subclass to support ASF video files
|
||||
@version $Rev$
|
||||
@author Abhinav Badola for GSoC 2012
|
||||
<a href="mailto:mail.abu.to@gmail.com">mail.abu.to@gmail.com</a>
|
||||
@date 08-Aug-12, AB: created
|
||||
*/
|
||||
#ifndef ASFVIDEO_HPP
|
||||
#define ASFVIDEO_HPP
|
||||
|
||||
// *****************************************************************************
|
||||
// included header files
|
||||
#include "exif.hpp"
|
||||
#include "image.hpp"
|
||||
#include "tags_int.hpp"
|
||||
|
||||
// *****************************************************************************
|
||||
// namespace extensions
|
||||
using namespace Exiv2::Internal;
|
||||
|
||||
namespace Exiv2 {
|
||||
|
||||
// *****************************************************************************
|
||||
// class definitions
|
||||
|
||||
// Add ASF to the supported image formats
|
||||
namespace ImageType {
|
||||
const int asf = 24; //!< Treating asf as an image type>
|
||||
}
|
||||
|
||||
/*!
|
||||
@brief Class to access ASF video files.
|
||||
*/
|
||||
class EXIV2API AsfVideo:public Image
|
||||
{
|
||||
public:
|
||||
//! @name Creators
|
||||
//@{
|
||||
/*!
|
||||
@brief Constructor for a ASF video. Since the constructor
|
||||
can not return a result, callers should check the good() method
|
||||
after object construction to determine success or failure.
|
||||
@param io An auto-pointer that owns a BasicIo instance used for
|
||||
reading and writing image metadata. \b Important: The constructor
|
||||
takes ownership of the passed in BasicIo instance through the
|
||||
auto-pointer. Callers should not continue to use the BasicIo
|
||||
instance after it is passed to this method. Use the Image::io()
|
||||
method to get a temporary reference.
|
||||
*/
|
||||
AsfVideo(BasicIo::AutoPtr io);
|
||||
//@}
|
||||
|
||||
//! @name Manipulators
|
||||
//@{
|
||||
void readMetadata();
|
||||
void writeMetadata();
|
||||
//@}
|
||||
|
||||
//! @name Accessors
|
||||
//@{
|
||||
std::string mimeType() const;
|
||||
//@}
|
||||
|
||||
protected:
|
||||
/*!
|
||||
@brief Check for a valid tag and decode the block at the current IO
|
||||
position. Calls tagDecoder() or skips to next tag, if required.
|
||||
*/
|
||||
void decodeBlock();
|
||||
/*!
|
||||
@brief Interpret tag information, and call the respective function
|
||||
to save it in the respective XMP container. Decodes a Tag
|
||||
Information and saves it in the respective XMP container, if
|
||||
the block size is small.
|
||||
@param tv Pointer to current tag,
|
||||
@param size Size of the data block used to store Tag Information.
|
||||
*/
|
||||
void tagDecoder(const TagVocabulary* tv, uint64_t size);
|
||||
/*!
|
||||
@brief Interpret File_Properties tag information, and save it in
|
||||
the respective XMP container.
|
||||
*/
|
||||
void fileProperties();
|
||||
/*!
|
||||
@brief Interpret Stream_Properties tag information, and save it
|
||||
in the respective XMP container.
|
||||
*/
|
||||
void streamProperties();
|
||||
/*!
|
||||
@brief Interpret Codec_List tag information, and save it in
|
||||
the respective XMP container.
|
||||
*/
|
||||
void codecList();
|
||||
/*!
|
||||
@brief Interpret Content_Description tag information, and save it
|
||||
in the respective XMP container.
|
||||
@param size Size of the data block used to store Tag Data.
|
||||
*/
|
||||
void contentDescription(uint64_t size);
|
||||
/*!
|
||||
@brief Interpret Extended_Stream_Properties tag information, and
|
||||
save it in the respective XMP container.
|
||||
@param size Size of the data block used to store Tag Data.
|
||||
*/
|
||||
void extendedStreamProperties(uint64_t size);
|
||||
/*!
|
||||
@brief Interpret Header_Extension tag information, and save it in
|
||||
the respective XMP container.
|
||||
@param size Size of the data block used to store Tag Data.
|
||||
*/
|
||||
void headerExtension(uint64_t size);
|
||||
/*!
|
||||
@brief Interpret Metadata, Extended_Content_Description,
|
||||
Metadata_Library tag information, and save it in the respective
|
||||
XMP container.
|
||||
@param meta A default integer which helps to overload the function
|
||||
for various Tags that have a similar method of decoding.
|
||||
*/
|
||||
void metadataHandler(int meta = 1);
|
||||
/*!
|
||||
@brief Calculates Aspect Ratio of a video, and stores it in the
|
||||
respective XMP container.
|
||||
*/
|
||||
void aspectRatio();
|
||||
|
||||
private:
|
||||
//! @name NOT Implemented
|
||||
//@{
|
||||
//! Copy constructor
|
||||
AsfVideo(const AsfVideo& rhs);
|
||||
//! Assignment operator
|
||||
AsfVideo& operator=(const AsfVideo& rhs);
|
||||
//@}
|
||||
|
||||
private:
|
||||
//! Variable to check the end of metadata traversing.
|
||||
bool continueTraversing_;
|
||||
//! Variable which stores current position of the read pointer.
|
||||
uint64_t localPosition_;
|
||||
//! Variable which stores current stream being processsed.
|
||||
int streamNumber_;
|
||||
//! Variable to store height and width of a video frame.
|
||||
uint64_t height_, width_;
|
||||
|
||||
}; //Class AsfVideo
|
||||
|
||||
// *****************************************************************************
|
||||
// template, inline and free functions
|
||||
|
||||
// These could be static private functions on Image subclasses but then
|
||||
// ImageFactory needs to be made a friend.
|
||||
/*!
|
||||
@brief Create a new AsfVideo instance and return an auto-pointer to it.
|
||||
Caller owns the returned object and the auto-pointer ensures that
|
||||
it will be deleted.
|
||||
*/
|
||||
EXIV2API Image::AutoPtr newAsfInstance(BasicIo::AutoPtr io, bool create);
|
||||
|
||||
//! Check if the file iIo is a Windows Asf Video.
|
||||
EXIV2API bool isAsfType(BasicIo& iIo, bool advance);
|
||||
|
||||
} // namespace Exiv2
|
||||
|
||||
#endif // #ifndef ASFVIDEO_HPP_
|
@ -0,0 +1,731 @@
|
||||
// ***************************************************************** -*- C++ -*-
|
||||
/*
|
||||
* Copyright (C) 2004-2012 Andreas Huggel <ahuggel@gmx.net>
|
||||
*
|
||||
* This program is part of the Exiv2 distribution.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, 5th Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
/*
|
||||
File: matroskavideo.cpp
|
||||
Version: $Rev$
|
||||
Author(s): Abhinav Badola for GSoC 2012 (AB) <mail.abu.to@gmail.com>
|
||||
History: 18-Jun-12, AB: created
|
||||
Credits: See header file
|
||||
*/
|
||||
// *****************************************************************************
|
||||
#include "rcsid_int.hpp"
|
||||
EXIV2_RCSID("@(#) $Id$")
|
||||
|
||||
// *****************************************************************************
|
||||
// included header files
|
||||
#include "matroskavideo.hpp"
|
||||
#include "futils.hpp"
|
||||
#include "basicio.hpp"
|
||||
#include "tags.hpp"
|
||||
#include "tags_int.hpp"
|
||||
|
||||
// + standard includes
|
||||
#include <cmath>
|
||||
|
||||
// *****************************************************************************
|
||||
// class member definitions
|
||||
namespace Exiv2 {
|
||||
namespace Internal {
|
||||
|
||||
//! List of composite tags. They are skipped and the child tags are read immediately
|
||||
uint32_t compositeTagsList[] = {
|
||||
0x0000, 0x000e, 0x000f, 0x0020, 0x0026, 0x002e, 0x0036,
|
||||
0x0037, 0x003b, 0x005b, 0x0060, 0x0061, 0x0068, 0x05b9,
|
||||
0x0dbb, 0x1034, 0x1035, 0x1854, 0x21a7, 0x2240, 0x23c0,
|
||||
0x2624, 0x27c8, 0x2911, 0x2924, 0x2944, 0x2d80, 0x3373,
|
||||
0x35a1, 0x3e5b, 0x3e7b,
|
||||
0x14d9b74, 0x254c367, 0x549a966, 0x654ae6b, 0x8538067,
|
||||
0x941a469, 0xa45dfa3, 0xb538667, 0xc53bb6b, 0xf43b675
|
||||
};
|
||||
|
||||
//! List of tags which are ignored, i.e., tag and value won't be read
|
||||
uint32_t ignoredTagsList[] = {
|
||||
0x0021, 0x0023, 0x0033, 0x0071, 0x0077, 0x006c, 0x0067, 0x007b, 0x02f2, 0x02f3,
|
||||
0x1031, 0x1032, 0x13ab, 0x13ac, 0x15ee, 0x23a2, 0x23c6, 0x2e67, 0x33a4, 0x33c5,
|
||||
0x3446, 0x2de7, 0x2df8, 0x26bf, 0x28ca, 0x3384, 0x13b8, 0x037e, 0x0485, 0x18d7,
|
||||
0x0005, 0x0009, 0x0011, 0x0012, 0x0016, 0x0017, 0x0018, 0x0022, 0x0024, 0x0025,
|
||||
0x0027, 0x002b, 0x002f, 0x003f, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f, 0x006a,
|
||||
0x006b, 0x006e, 0x007a, 0x007d, 0x0255, 0x3eb5, 0x3ea5, 0x3d7b, 0x33c4, 0x2fab,
|
||||
0x2ebc, 0x29fc, 0x29a5, 0x2955, 0x2933, 0x135f, 0x2922, 0x26a5, 0x26fc, 0x2532,
|
||||
0x23c9, 0x23c4, 0x23c5, 0x137f, 0x1378, 0x07e2, 0x07e3, 0x07e4, 0x0675, 0x05bc,
|
||||
0x05bd, 0x05db, 0x05dd, 0x0598, 0x050d, 0x0444, 0x037c,
|
||||
|
||||
0x3314f, 0x43a770, 0x1eb923, 0x1cb923, 0xeb524, 0x1c83ab, 0x1e83bb
|
||||
};
|
||||
|
||||
/*!
|
||||
Tag Look-up list for Matroska Type Video Files
|
||||
The Tags have been categorized in 4 categories. Which are
|
||||
mentioned as a comment in front of them.
|
||||
s -- Tag to be Skipped
|
||||
sd -- Tag to be Skipped along with its data
|
||||
u -- Tag used directly for storing metadata
|
||||
ui -- Tag used only internally
|
||||
*/
|
||||
extern const TagDetails matroskaTags[] = {
|
||||
{ 0x0000, "ChapterDisplay" }, //s
|
||||
{ 0x0003, "TrackType" }, //ui
|
||||
{ 0x0005, "ChapterString" }, //sd
|
||||
{ 0x0006, "VideoCodecID/AudioCodecID/CodecID" }, //ui
|
||||
{ 0x0008, "TrackDefault" }, //ui
|
||||
{ 0x0009, "ChapterTrackNumber" }, //sd
|
||||
{ 0x000e, "Slices" }, //s
|
||||
{ 0x000f, "ChapterTrack" }, //s
|
||||
{ 0x0011, "ChapterTimeStart" }, //sd
|
||||
{ 0x0012, "ChapterTimeEnd" }, //sd
|
||||
{ 0x0016, "CueRefTime" }, //sd
|
||||
{ 0x0017, "CueRefCluster" }, //sd
|
||||
{ 0x0018, "ChapterFlagHidden" }, //sd
|
||||
{ 0x001a, "Xmp.video.VideoScanTpye" }, //u
|
||||
{ 0x001b, "BlockDuration" }, //s
|
||||
{ 0x001c, "TrackLacing" }, //ui
|
||||
{ 0x001f, "Xmp.audio.ChannelType" }, //u
|
||||
{ 0x0020, "BlockGroup" }, //s
|
||||
{ 0x0021, "Block" }, //sd
|
||||
{ 0x0022, "BlockVirtual" }, //sd
|
||||
{ 0x0023, "SimpleBlock" }, //sd
|
||||
{ 0x0024, "CodecState" }, //sd
|
||||
{ 0x0025, "BlockAdditional" }, //sd
|
||||
{ 0x0026, "BlockMore" }, //s
|
||||
{ 0x0027, "Position" }, //sd
|
||||
{ 0x002a, "CodecDecodeAll" }, //ui
|
||||
{ 0x002b, "PrevSize" }, //sd
|
||||
{ 0x002e, "TrackEntry" }, //s
|
||||
{ 0x002f, "EncryptedBlock" }, //sd
|
||||
{ 0x0030, "Xmp.video.Width" }, //u
|
||||
{ 0x0033, "CueTime" }, //sd
|
||||
{ 0x0035, "Xmp.audio.SampleRate" }, //u
|
||||
{ 0x0036, "ChapterAtom" }, //s
|
||||
{ 0x0037, "CueTrackPositions" }, //s
|
||||
{ 0x0039, "TrackUsed" }, //ui
|
||||
{ 0x003a, "Xmp.video.Height" }, //u
|
||||
{ 0x003b, "CuePoint" }, //s
|
||||
{ 0x003f, "CRC-32" }, //sd
|
||||
{ 0x004b, "BlockAdditionalID" }, //sd
|
||||
{ 0x004c, "LaceNumber" }, //sd
|
||||
{ 0x004d, "FrameNumber" }, //sd
|
||||
{ 0x004e, "Delay" }, //sd
|
||||
{ 0x004f, "ClusterDuration" }, //sd
|
||||
{ 0x0057, "TrackNumber" }, //ui
|
||||
{ 0x005b, "CueReference" }, //s
|
||||
{ 0x0060, "Video" }, //s
|
||||
{ 0x0061, "Audio" }, //s
|
||||
{ 0x0067, "Timecode" }, //sd
|
||||
{ 0x0068, "TimeSlice" }, //s
|
||||
{ 0x006a, "CueCodecState" }, //sd
|
||||
{ 0x006b, "CueRefCodecState" }, //sd
|
||||
{ 0x006c, "Void" }, //sd
|
||||
{ 0x006e, "BlockAddID" }, //sd
|
||||
{ 0x0071, "CueClusterPosition" }, //sd
|
||||
{ 0x0077, "CueTrack" }, //sd
|
||||
{ 0x007a, "ReferencePriority" }, //sd
|
||||
{ 0x007b, "ReferenceBlock" }, //sd
|
||||
{ 0x007d, "ReferenceVirtual" }, //sd
|
||||
{ 0x0254, "Xmp.video.ContentCompressAlgo" }, //u
|
||||
{ 0x0255, "ContentCompressionSettings" }, //sd
|
||||
{ 0x0282, "Xmp.video.DocType" }, //u
|
||||
{ 0x0285, "Xmp.video.DocTypeReadVersion" }, //u
|
||||
{ 0x0286, "Xmp.video.EBMLVersion" }, //u
|
||||
{ 0x0287, "Xmp.video.DocTypeVersion" }, //u
|
||||
{ 0x02f2, "EBMLMaxIDLength" }, //sd
|
||||
{ 0x02f3, "EBMLMaxSizeLength" }, //sd
|
||||
{ 0x02f7, "Xmp.video.EBMLReadVersion" }, //u
|
||||
{ 0x037c, "ChapterLanguage" }, //sd
|
||||
{ 0x037e, "ChapterCountry" }, //sd
|
||||
{ 0x0444, "SegmentFamily" }, //sd
|
||||
{ 0x0461, "Xmp.video.DateUTC" }, //Date Time Original - measured in seconds relatively to Jan 01, 2001, 0:00:00 GMT+0h
|
||||
{ 0x047a, "Xmp.video.TagLanguage" }, //u
|
||||
{ 0x0484, "Xmp.video.TagDefault" }, //u
|
||||
{ 0x0485, "TagBinary" }, //sd
|
||||
{ 0x0487, "Xmp.video.TagString" }, //u
|
||||
{ 0x0489, "Xmp.video.Duration" }, //u
|
||||
{ 0x050d, "ChapterProcessPrivate" }, //sd
|
||||
{ 0x0598, "ChapterFlagEnabled" }, //sd
|
||||
{ 0x05a3, "Xmp.video.TagName" }, //u
|
||||
{ 0x05b9, "EditionEntry" }, //s
|
||||
{ 0x05bc, "EditionUID" }, //sd
|
||||
{ 0x05bd, "EditionFlagHidden" }, //sd
|
||||
{ 0x05db, "EditionFlagDefault" }, //sd
|
||||
{ 0x05dd, "EditionFlagOrdered" }, //sd
|
||||
{ 0x065c, "Xmp.video.AttachFileData" }, //u
|
||||
{ 0x0660, "Xmp.video.AttachFileMIME" }, //u
|
||||
{ 0x066e, "Xmp.video.AttachFileName" }, //u
|
||||
{ 0x0675, "AttachedFileReferral" }, //sd
|
||||
{ 0x067e, "Xmp.video.AttachFileDesc" }, //u
|
||||
{ 0x06ae, "Xmp.video.AttachFileUID" }, //u
|
||||
{ 0x07e1, "Xmp.video.ContentEncryptAlgo" }, //u
|
||||
{ 0x07e2, "ContentEncryptionKeyID" }, //sd
|
||||
{ 0x07e3, "ContentSignature" }, //sd
|
||||
{ 0x07e4, "ContentSignatureKeyID" }, //sd
|
||||
{ 0x07e5, "Xmp.video.ContentSignAlgo" }, //u
|
||||
{ 0x07e6, "Xmp.video.ContentSignHashAlgo" }, //u
|
||||
{ 0x0d80, "Xmp.video.MuxingApp" }, //u
|
||||
{ 0x0dbb, "Seek" }, //s
|
||||
{ 0x1031, "ContentEncodingOrder" }, //sd
|
||||
{ 0x1032, "ContentEncodingScope" }, //sd
|
||||
{ 0x1033, "Xmp.video.ContentEncodingType" }, //u
|
||||
{ 0x1034, "ContentCompression" }, //s
|
||||
{ 0x1035, "ContentEncryption" }, //s
|
||||
{ 0x135f, "CueRefNumber" }, //sd
|
||||
{ 0x136e, "Xmp.video.TrackName" }, //u
|
||||
{ 0x1378, "CueBlockNumber" }, //sd
|
||||
{ 0x137f, "TrackOffset" }, //sd
|
||||
{ 0x13ab, "SeekID" }, //sd
|
||||
{ 0x13ac, "SeekPosition" }, //sd
|
||||
{ 0x13b8, "Stereo3DMode" }, //sd
|
||||
{ 0x14aa, "Xmp.video.CropBottom" }, //ui
|
||||
{ 0x14b0, "Xmp.video.Width" }, //u
|
||||
{ 0x14b2, "Xmp.video.DisplayUnit" }, //u
|
||||
{ 0x14b3, "Xmp.video.AspectRatioType" }, //u
|
||||
{ 0x14ba, "Xmp.video.Height" }, //u
|
||||
{ 0x14bb, "Xmp.video.CropTop" }, //ui
|
||||
{ 0x14cc, "Xmp.video.CropLeft" }, //ui
|
||||
{ 0x14dd, "Xmp.video.CropRight" }, //ui
|
||||
{ 0x15aa, "TrackForced" }, //ui
|
||||
{ 0x15ee, "MaxBlockAdditionID" }, //sd
|
||||
{ 0x1741, "Xmp.video.WritingApp" }, //u
|
||||
{ 0x1854, "SilentTracks" }, //s
|
||||
{ 0x18d7, "SilentTrackNumber" }, //sd
|
||||
{ 0x21a7, "AttachedFile" }, //s
|
||||
{ 0x2240, "ContentEncoding" }, //s
|
||||
{ 0x2264, "Xmp.audio.BitsPerSample" }, //u
|
||||
{ 0x23a2, "CodecPrivate" }, //sd
|
||||
{ 0x23c0, "Targets" }, //s
|
||||
{ 0x23c3, "Xmp.video.PhysicalEquivalent" }, //u
|
||||
{ 0x23c4, "TagChapterUID" }, //sd
|
||||
{ 0x23c5, "TagTrackUID" }, //sd
|
||||
{ 0x23c6, "TagAttachmentUID" }, //sd
|
||||
{ 0x23c9, "TagEditionUID" }, //sd
|
||||
{ 0x23ca, "Xmp.video.TargetType" }, //u
|
||||
{ 0x2532, "SignedElement" }, //sd
|
||||
{ 0x2624, "TrackTranslate" }, //s
|
||||
{ 0x26a5, "TrackTranslateTrackID" }, //sd
|
||||
{ 0x26bf, "TrackTranslateCodec" }, //sd
|
||||
{ 0x26fc, "TrackTranslateEditionUID" }, //sd
|
||||
{ 0x27c8, "SimpleTag" }, //s
|
||||
{ 0x28ca, "TargetTypeValue" }, //sd
|
||||
{ 0x2911, "ChapterProcessCommand" }, //s
|
||||
{ 0x2922, "ChapterProcessTime" }, //sd
|
||||
{ 0x2924, "ChapterTranslate" }, //s
|
||||
{ 0x2933, "ChapterProcessData" }, //sd
|
||||
{ 0x2944, "ChapterProcess" }, //s
|
||||
{ 0x2955, "ChapterProcessCodecID" }, //sd
|
||||
{ 0x29a5, "ChapterTranslateID" }, //sd
|
||||
{ 0x29bf, "Xmp.video.TranslateCodec" }, //u
|
||||
{ 0x29fc, "ChapterTranslateEditionUID" }, //sd
|
||||
{ 0x2d80, "ContentEncodings" }, //s
|
||||
{ 0x2de7, "MinCache" }, //sd
|
||||
{ 0x2df8, "MaxCache" }, //sd
|
||||
{ 0x2e67, "ChapterSegmentUID" }, //sd
|
||||
{ 0x2ebc, "ChapterSegmentEditionUID" }, //sd
|
||||
{ 0x2fab, "TrackOverlay" }, //sd
|
||||
{ 0x3373, "Tag" }, //s
|
||||
{ 0x3384, "SegmentFileName" }, //sd
|
||||
{ 0x33a4, "SegmentUID" }, //sd
|
||||
{ 0x33c4, "ChapterUID" }, //sd
|
||||
{ 0x33c5, "TrackUID" }, //sd
|
||||
{ 0x3446, "TrackAttachmentUID" }, //sd
|
||||
{ 0x35a1, "BlockAdditions" }, //s
|
||||
{ 0x38b5, "Xmp.audio.OutputSampleRate" }, //u
|
||||
{ 0x3ba9, "Xmp.video.Title" }, //u
|
||||
{ 0x3d7b, "ChannelPositions" }, //sd
|
||||
{ 0x3e5b, "SignatureElements" }, //s
|
||||
{ 0x3e7b, "SignatureElementList" }, //s
|
||||
{ 0x3e8a, "Xmp.video.ContentSignAlgo" }, //u
|
||||
{ 0x3e9a, "Xmp.video.ContentSignHashAlgo" }, //u
|
||||
{ 0x3ea5, "SignaturePublicKey" }, //sd
|
||||
{ 0x3eb5, "Signature" }, //sd
|
||||
{ 0x2b59c, "TrackLanguage" }, //ui
|
||||
{ 0x3314f, "TrackTimecodeScale" }, //sd
|
||||
{ 0x383e3, "Xmp.video.FrameRate" }, //u
|
||||
{ 0x3e383, "VideoFrameRate/DefaultDuration" }, //ui
|
||||
{ 0x58688, "VideoCodecName/AudioCodecName/CodecName" }, //ui
|
||||
{ 0x6b240, "CodecDownloadURL" }, //ui
|
||||
{ 0xad7b1, "TimecodeScale" }, //ui
|
||||
{ 0xeb524, "ColorSpace" }, //sd
|
||||
{ 0xfb523, "Xmp.video.OpColor" }, //u
|
||||
{ 0x1a9697, "CodecSettings" }, //ui
|
||||
{ 0x1b4040, "CodecInfoURL" }, //ui
|
||||
{ 0x1c83ab, "PrevFileName" }, //sd
|
||||
{ 0x1cb923, "PrevUID" }, //sd
|
||||
{ 0x1e83bb, "NextFileName" }, //sd
|
||||
{ 0x1eb923, "NextUID" }, //sd
|
||||
{ 0x43a770, "Chapters" }, //sd
|
||||
{ 0x14d9b74, "SeekHead" }, //s
|
||||
{ 0x254c367, "Tags" }, //s
|
||||
{ 0x549a966, "Info" }, //s
|
||||
{ 0x654ae6b, "Tracks" }, //s
|
||||
{ 0x8538067, "SegmentHeader" }, //s
|
||||
{ 0x941a469, "Attachments" }, //s
|
||||
{ 0xa45dfa3, "EBMLHeader" }, //s
|
||||
{ 0xb538667, "SignatureSlot" }, //s
|
||||
{ 0xc53bb6b, "Cues" }, //s
|
||||
{ 0xf43b675, "Cluster" }, //s
|
||||
};
|
||||
|
||||
extern const TagDetails matroskaTrackType[] = {
|
||||
{ 0x1, "Video" },
|
||||
{ 0x2, "Audio" },
|
||||
{ 0x3, "Complex" },
|
||||
{ 0x10, "Logo" },
|
||||
{ 0x11, "Subtitle" },
|
||||
{ 0x12, "Buttons" },
|
||||
{ 0x20, "Control" }
|
||||
};
|
||||
|
||||
extern const TagDetails compressionAlgorithm[] = {
|
||||
{ 0, "zlib " },
|
||||
{ 1, "bzlib" },
|
||||
{ 2, "lzo1x" },
|
||||
{ 3, "Header Stripping" }
|
||||
};
|
||||
|
||||
extern const TagDetails audioChannels[] = {
|
||||
{ 1, "Mono" },
|
||||
{ 2, "Stereo" },
|
||||
{ 5, "5.1 Surround Sound" },
|
||||
{ 7, "7.1 Surround Sound" }
|
||||
};
|
||||
|
||||
extern const TagDetails displayUnit[] = {
|
||||
{ 0x0, "Pixels" },
|
||||
{ 0x1, "cm" },
|
||||
{ 0x2, "inches" }
|
||||
};
|
||||
|
||||
extern const TagDetails encryptionAlgorithm[] = {
|
||||
{ 0, "Not Encrypted" },
|
||||
{ 1, "DES" },
|
||||
{ 2, "3DES" },
|
||||
{ 3, "Twofish" },
|
||||
{ 4, "Blowfish" },
|
||||
{ 5, "AES" }
|
||||
};
|
||||
|
||||
extern const TagDetails chapterPhysicalEquivalent[] = {
|
||||
{ 10, "Index" },
|
||||
{ 20, "Track" },
|
||||
{ 30, "Session" },
|
||||
{ 40, "Layer" },
|
||||
{ 50, "Side" },
|
||||
{ 60, "CD / DVD" },
|
||||
{ 70, "Set / Package" },
|
||||
};
|
||||
|
||||
extern const TagDetails encodingType[] = {
|
||||
{ 0, "Compression" },
|
||||
{ 1, "Encryption" }
|
||||
};
|
||||
|
||||
extern const TagDetails videoScanType[] = {
|
||||
{ 0, "Progressive" },
|
||||
{ 1, "Interlaced" }
|
||||
};
|
||||
|
||||
extern const TagDetails chapterTranslateCodec[] = {
|
||||
{ 0, "Matroska Script" },
|
||||
{ 1, "DVD Menu" }
|
||||
};
|
||||
|
||||
extern const TagDetails aspectRatioType[] = {
|
||||
{ 0, "Free Resizing" },
|
||||
{ 1, "Keep Aspect Ratio" },
|
||||
{ 2, "Fixed" }
|
||||
};
|
||||
|
||||
extern const TagDetails contentSignatureAlgorithm[] = {
|
||||
{ 0, "Not Signed" },
|
||||
{ 1, "RSA" }
|
||||
};
|
||||
|
||||
extern const TagDetails contentSignatureHashAlgorithm[] = {
|
||||
{ 0, "Not Signed" },
|
||||
{ 1, "SHA1-160" },
|
||||
{ 2, "MD5" }
|
||||
};
|
||||
|
||||
extern const TagDetails trackEnable[] = {
|
||||
{ 0x1, "Xmp.video.Enabled" },
|
||||
{ 0x2, "Xmp.audio.Enabled" },
|
||||
{ 0x11, "Xmp.video.SubTEnabled" }
|
||||
};
|
||||
|
||||
extern const TagDetails defaultOn[] = {
|
||||
{ 0x1, "Xmp.video.DefaultOn" },
|
||||
{ 0x2, "Xmp.audio.DefaultOn" },
|
||||
{ 0x11, "Xmp.video.SubTDefaultOn" }
|
||||
};
|
||||
|
||||
extern const TagDetails trackForced[] = {
|
||||
{ 0x1, "Xmp.video.TrackForced" },
|
||||
{ 0x2, "Xmp.audio.TrackForced" },
|
||||
{ 0x11, "Xmp.video.SubTTrackForced" }
|
||||
};
|
||||
|
||||
extern const TagDetails trackLacing[] = {
|
||||
{ 0x1, "Xmp.video.TrackLacing" },
|
||||
{ 0x2, "Xmp.audio.TrackLacing" },
|
||||
{ 0x11, "Xmp.video.SubTTrackLacing" }
|
||||
};
|
||||
|
||||
extern const TagDetails codecDecodeAll[] = {
|
||||
{ 0x1, "Xmp.video.CodecDecodeAll" },
|
||||
{ 0x2, "Xmp.audio.CodecDecodeAll" },
|
||||
{ 0x11, "Xmp.video.SubTCodecDecodeAll" }
|
||||
};
|
||||
|
||||
extern const TagDetails codecDownloadUrl[] = {
|
||||
{ 0x1, "Xmp.video.CodecDownloadUrl" },
|
||||
{ 0x2, "Xmp.audio.CodecDownloadUrl" },
|
||||
{ 0x11, "Xmp.video.SubTCodecDownloadUrl" }
|
||||
};
|
||||
|
||||
extern const TagDetails codecSettings[] = {
|
||||
{ 0x1, "Xmp.video.CodecSettings" },
|
||||
{ 0x2, "Xmp.audio.CodecSettings" },
|
||||
{ 0x11, "Xmp.video.SubTCodecSettings" }
|
||||
};
|
||||
|
||||
extern const TagDetails trackCodec[] = {
|
||||
{ 0x1, "Xmp.video.Codec" },
|
||||
{ 0x2, "Xmp.audio.Compressor" },
|
||||
{ 0x11, "Xmp.video.SubTCodec" }
|
||||
};
|
||||
|
||||
extern const TagDetails trackLanguage[] = {
|
||||
{ 0x1, "Xmp.video.TrackLang" },
|
||||
{ 0x2, "Xmp.audio.TrackLang" },
|
||||
{ 0x11, "Xmp.video.SubTLang" }
|
||||
};
|
||||
|
||||
extern const TagDetails codecInfo[] = {
|
||||
{ 0x1, "Xmp.video.CodecInfo" },
|
||||
{ 0x2, "Xmp.audio.CodecInfo" },
|
||||
{ 0x11, "Xmp.video.SubTCodecInfo" }
|
||||
};
|
||||
|
||||
extern const TagDetails streamRate[] = {
|
||||
{ 0x1, "Xmp.video.FrameRate" },
|
||||
{ 0x2, "Xmp.audio.DefaultDuration" }
|
||||
};
|
||||
|
||||
/*!
|
||||
@brief Function used to calulate Tags, Tags may comprise of more than
|
||||
one byte, that is why two buffers are to be provided.
|
||||
The first buffer calculates size of the Tag and the second buffer
|
||||
is used to calculate the rest of the Tag.
|
||||
Returns Tag Value in unsinged long.
|
||||
*/
|
||||
unsigned long returnTagValue(byte b, Exiv2::DataBuf& buf2, int n ) {
|
||||
long temp = 0;
|
||||
long reg1 = 0;
|
||||
reg1 = (b & (int)(pow(2,8-n)-1));
|
||||
|
||||
for(int i = n-2; i >= 0; i--) {
|
||||
temp = temp + buf2.pData_[i]*(pow(256,n-i-2));
|
||||
}
|
||||
temp += reg1 * pow(256,n-1);
|
||||
return temp;
|
||||
}
|
||||
|
||||
//! Function used to convert buffer data into numerical information, information stored in BigEndian format
|
||||
int64_t returnValue(Exiv2::DataBuf& buf, int n ) {
|
||||
int64_t temp = 0;
|
||||
|
||||
for(int i = n-1; i >= 0; i--) {
|
||||
temp = temp + buf.pData_[i]*(pow(256,n-i-1));
|
||||
}
|
||||
return temp;
|
||||
}
|
||||
|
||||
}} // namespace Internal, Exiv2
|
||||
|
||||
namespace Exiv2 {
|
||||
|
||||
using namespace Exiv2::Internal;
|
||||
|
||||
MatroskaVideo::MatroskaVideo(BasicIo::AutoPtr io)
|
||||
: Image(ImageType::mkv, mdNone, io)
|
||||
{
|
||||
} // MatroskaVideo::MatroskaVideo
|
||||
|
||||
std::string MatroskaVideo::mimeType() const
|
||||
{
|
||||
return "video/matroska";
|
||||
}
|
||||
|
||||
void MatroskaVideo::writeMetadata()
|
||||
{
|
||||
}
|
||||
|
||||
void MatroskaVideo::readMetadata()
|
||||
{
|
||||
if (io_->open() != 0) throw Error(9, io_->path(), strError());
|
||||
|
||||
// Ensure that this is the correct image type
|
||||
if (!isMkvType(*io_, false)) {
|
||||
if (io_->error() || io_->eof()) throw Error(14);
|
||||
throw Error(3, "Matroska");
|
||||
}
|
||||
|
||||
IoCloser closer(*io_);
|
||||
clearMetadata();
|
||||
height_ = width_ = 1;
|
||||
|
||||
xmpData_["Xmp.video.FileName"] = io_->path();
|
||||
xmpData_["Xmp.video.FileSize"] = (double)io_->size()/(double)1048576;
|
||||
xmpData_["Xmp.video.MimeType"] = mimeType();
|
||||
|
||||
while (continueTraversing_) decodeBlock();
|
||||
|
||||
aspectRatio();
|
||||
} // MatroskaVideo::readMetadata
|
||||
|
||||
void MatroskaVideo::decodeBlock()
|
||||
{
|
||||
const long bufMinSize = 200;
|
||||
DataBuf buf2(bufMinSize);
|
||||
|
||||
byte b;
|
||||
io_->read(&b, 1);
|
||||
|
||||
if(io_->eof()) {
|
||||
continueTraversing_ = false;
|
||||
return;
|
||||
}
|
||||
|
||||
long sz = findBlockSize(b);
|
||||
if (sz > 0) io_->read(buf2.pData_, sz - 1);
|
||||
|
||||
const TagDetails* td;
|
||||
td = find(matroskaTags, returnTagValue(b, buf2, sz));
|
||||
|
||||
if(td->val_ == 0xc53bb6b || td->val_ == 0xf43b675) {
|
||||
continueTraversing_ = false;
|
||||
return;
|
||||
}
|
||||
|
||||
bool skip = find(compositeTagsList, (uint32_t)td->val_);
|
||||
bool ignore = find(ignoredTagsList, (uint32_t)td->val_);
|
||||
|
||||
io_->read(&b, 1);
|
||||
sz = findBlockSize(b);
|
||||
|
||||
if (sz > 0) io_->read(buf2.pData_, sz - 1);
|
||||
long size = returnTagValue(b, buf2, sz);
|
||||
|
||||
if (skip && !ignore) return;
|
||||
|
||||
if (ignore || size > bufMinSize) {
|
||||
io_->seek(size, BasicIo::cur);
|
||||
return;
|
||||
}
|
||||
|
||||
DataBuf buf(bufMinSize);
|
||||
std::memset(buf.pData_, 0x0, buf.size_);
|
||||
io_->read(buf.pData_, size);
|
||||
contentManagement(td, buf, size);
|
||||
} // MatroskaVideo::decodeBlock
|
||||
|
||||
void MatroskaVideo::contentManagement(const TagDetails* td, Exiv2::DataBuf& buf, long size)
|
||||
{
|
||||
int64_t duration_in_ms = 0;
|
||||
static double time_code_scale = 1.0, temp = 0;
|
||||
static long stream = 0, track_count = 0;
|
||||
char str[4] = "No";
|
||||
const TagDetails* internal_td = NULL;
|
||||
|
||||
switch (td->val_) {
|
||||
|
||||
case 0x0282: case 0x0d80: case 0x1741: case 0x3ba9: case 0x066e: case 0x0660:
|
||||
case 0x065c: case 0x067e: case 0x047a: case 0x0487: case 0x05a3: case 0x136e:
|
||||
case 0x23ca: case 0xeb524:
|
||||
xmpData_[exvGettext(td->label_)] = buf.pData_;
|
||||
break;
|
||||
|
||||
case 0x0030: case 0x003a: case 0x0287: case 0x14b0: case 0x14ba: case 0x285:
|
||||
case 0x06ae: case 0x0286: case 0x02f7: case 0x2264: case 0x14aa: case 0x14bb:
|
||||
case 0x14cc: case 0x14dd:
|
||||
xmpData_[exvGettext(td->label_)] = returnValue(buf, size);
|
||||
|
||||
if(td->val_ == 0x0030 || td->val_ == 0x14b0)
|
||||
width_ = returnValue(buf, size);
|
||||
else if(td->val_ == 0x003a || td->val_ == 0x14ba)
|
||||
height_ = returnValue(buf, size);
|
||||
break;
|
||||
|
||||
case 0x001a: case 0x001f: case 0x0254: case 0x07e1: case 0x07e5: case 0x07e6:
|
||||
case 0x1033: case 0x14b2: case 0x14b3: case 0x23c3: case 0x29bf: case 0x3e8a:
|
||||
case 0x3e9a:
|
||||
switch (td->val_) {
|
||||
case 0x001a: internal_td = find(videoScanType, returnValue(buf, size)); break;
|
||||
case 0x001f: internal_td = find(audioChannels, returnValue(buf, size)); break;
|
||||
case 0x0254: internal_td = find(compressionAlgorithm, returnValue(buf, size)); break;
|
||||
case 0x07e1: internal_td = find(encryptionAlgorithm, returnValue(buf, size)); break;
|
||||
case 0x1033: internal_td = find(encodingType, returnValue(buf, size)); break;
|
||||
case 0x3e8a:
|
||||
case 0x07e5: internal_td = find(contentSignatureAlgorithm, returnValue(buf, size)); break;
|
||||
case 0x3e9a:
|
||||
case 0x07e6: internal_td = find(contentSignatureHashAlgorithm, returnValue(buf, size)); break;
|
||||
case 0x14b2: internal_td = find(displayUnit, returnValue(buf, size)); break;
|
||||
case 0x14b3: internal_td = find(aspectRatioType, returnValue(buf, size)); break;
|
||||
case 0x23c3: internal_td = find(chapterPhysicalEquivalent, returnValue(buf, size)); break;
|
||||
case 0x29bf: internal_td = find(chapterTranslateCodec, returnValue(buf, size)); break;
|
||||
}
|
||||
if(internal_td)
|
||||
xmpData_[exvGettext(td->label_)] = exvGettext(internal_td->label_);
|
||||
break;
|
||||
|
||||
case 0x0035: case 0x38b5:
|
||||
xmpData_[exvGettext(td->label_)] = Exiv2::getFloat(buf.pData_, bigEndian);
|
||||
break;
|
||||
|
||||
case 0x0039: case 0x0008: case 0x15aa: case 0x001c: case 0x002a: case 0x1a9697:
|
||||
case 0x0484:
|
||||
if (returnValue(buf, size)) strcpy(str, "Yes");
|
||||
switch (td->val_) {
|
||||
case 0x0039: internal_td = find(trackEnable, stream); break;
|
||||
case 0x0008: internal_td = find(defaultOn, stream); break;
|
||||
case 0x15aa: internal_td = find(trackForced, stream); break;
|
||||
case 0x001c: internal_td = find(trackLacing, stream); break;
|
||||
case 0x002a: internal_td = find(codecDecodeAll, stream); break;
|
||||
case 0x1a9697: internal_td = find(codecSettings, stream); break;
|
||||
case 0x0484: internal_td = td; break;
|
||||
}
|
||||
if (internal_td) xmpData_[exvGettext(internal_td->label_)] = str;
|
||||
break;
|
||||
|
||||
case 0x0006: case 0x2b59c: case 0x58688: case 0x6b240: case 0x1b4040:
|
||||
switch (td->val_) {
|
||||
case 0x0006: internal_td = find(trackCodec, stream); break;
|
||||
case 0x2b59c: internal_td = find(trackLanguage, stream); break;
|
||||
case 0x58688: internal_td = find(codecInfo, stream); break;
|
||||
case 0x6b240:
|
||||
case 0x1b4040: internal_td = find(codecDownloadUrl, stream); break;
|
||||
}
|
||||
if (internal_td) xmpData_[exvGettext(internal_td->label_)] = buf.pData_;
|
||||
break;
|
||||
|
||||
case 0x0489: case 0x0461:
|
||||
switch (td->val_) {
|
||||
case 0x0489:
|
||||
if(size <= 4) {
|
||||
duration_in_ms = Exiv2::getFloat(buf.pData_, bigEndian) * time_code_scale * 1000;
|
||||
}
|
||||
else {
|
||||
duration_in_ms = Exiv2::getDouble(buf.pData_, bigEndian) * time_code_scale * 1000;
|
||||
}
|
||||
break;
|
||||
case 0x0461: duration_in_ms = returnValue(buf, size)/1000000000; break;
|
||||
}
|
||||
xmpData_[exvGettext(td->label_)] = duration_in_ms;
|
||||
break;
|
||||
|
||||
case 0x0057:
|
||||
track_count++;
|
||||
xmpData_["Xmp.video.TotalStream"] = track_count;
|
||||
break;
|
||||
|
||||
case 0xad7b1:
|
||||
time_code_scale = (double)returnValue(buf, size)/(double)1000000000;
|
||||
xmpData_["Xmp.video.TimecodeScale"] = time_code_scale;
|
||||
break;
|
||||
|
||||
case 0x0003:
|
||||
internal_td = find(matroskaTrackType, returnValue(buf, size));
|
||||
stream = internal_td->val_;
|
||||
break;
|
||||
|
||||
case 0x3e383: case 0x383e3:
|
||||
internal_td = find(streamRate, stream);
|
||||
if (returnValue(buf, size)) {
|
||||
switch (stream) {
|
||||
case 1: temp = (double)1000000000/(double)returnValue(buf, size); break;
|
||||
case 2: temp = returnValue(buf, size)/1000; break;
|
||||
}
|
||||
if (internal_td) xmpData_[exvGettext(internal_td->label_)] = temp;
|
||||
}
|
||||
else
|
||||
if (internal_td) xmpData_[exvGettext(internal_td->label_)] = "Variable Bit Rate";
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
} // MatroskaVideo::contentManagement
|
||||
|
||||
void MatroskaVideo::aspectRatio()
|
||||
{
|
||||
//TODO - Make a better unified method to handle all cases of Aspect Ratio
|
||||
|
||||
double aspectRatio = (double)width_ / (double)height_;
|
||||
aspectRatio = floor(aspectRatio*10) / 10;
|
||||
xmpData_["Xmp.video.AspectRatio"] = aspectRatio;
|
||||
|
||||
if(aspectRatio == 1.3) xmpData_["Xmp.video.AspectRatio"] = "4:3";
|
||||
else if(aspectRatio == 1.7) xmpData_["Xmp.video.AspectRatio"] = "16:9";
|
||||
else if(aspectRatio == 1.0) xmpData_["Xmp.video.AspectRatio"] = "1:1";
|
||||
else if(aspectRatio == 1.6) xmpData_["Xmp.video.AspectRatio"] = "16:10";
|
||||
else if(aspectRatio == 2.2) xmpData_["Xmp.video.AspectRatio"] = "2.21:1";
|
||||
else if(aspectRatio == 2.3) xmpData_["Xmp.video.AspectRatio"] = "2.35:1";
|
||||
else if(aspectRatio == 1.2) xmpData_["Xmp.video.AspectRatio"] = "5:4";
|
||||
else xmpData_["Xmp.video.AspectRatio"] = aspectRatio;
|
||||
} // MatroskaVideo::aspectRatio
|
||||
|
||||
long MatroskaVideo::findBlockSize(byte b)
|
||||
{
|
||||
if (b & 128) return 1;
|
||||
else if (b & 64) return 2;
|
||||
else if (b & 32) return 3;
|
||||
else if (b & 16) return 4;
|
||||
else if (b & 8) return 5;
|
||||
else if (b & 4) return 6;
|
||||
else if (b & 2) return 7;
|
||||
else if (b & 1) return 8;
|
||||
else return 0;
|
||||
} // MatroskaVideo::findBlockSize
|
||||
|
||||
Image::AutoPtr newMkvInstance(BasicIo::AutoPtr io, bool /*create*/)
|
||||
{
|
||||
Image::AutoPtr image(new MatroskaVideo(io));
|
||||
if (!image->good()) {
|
||||
image.reset();
|
||||
}
|
||||
return image;
|
||||
}
|
||||
|
||||
bool isMkvType(BasicIo& iIo, bool advance)
|
||||
{
|
||||
bool result = true;
|
||||
byte tmpBuf[4];
|
||||
iIo.read(tmpBuf, 4);
|
||||
|
||||
if (iIo.error() || iIo.eof()) return false;
|
||||
|
||||
if (0x1a != tmpBuf[0] || 0x45 != tmpBuf[1] || 0xdf != tmpBuf[2] || 0xa3 != tmpBuf[3]) {
|
||||
result = false;
|
||||
}
|
||||
|
||||
if (!advance || !result ) iIo.seek(0, BasicIo::beg);
|
||||
return result;
|
||||
}
|
||||
|
||||
} // namespace Exiv2
|
@ -0,0 +1,145 @@
|
||||
// ***************************************************************** -*- C++ -*-
|
||||
/*
|
||||
* Copyright (C) 2004-2012 Andreas Huggel <ahuggel@gmx.net>
|
||||
*
|
||||
* This program is part of the Exiv2 distribution.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, 5th Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
/*!
|
||||
@file matroskavideo.hpp
|
||||
@brief An Image subclass to support Matroska video files
|
||||
@version $Rev$
|
||||
@author Abhinav Badola for GSoC 2012
|
||||
<a href="mailto:mail.abu.to@gmail.com">mail.abu.to@gmail.com</a>
|
||||
@date 18-Jun-12, AB: created
|
||||
*/
|
||||
#ifndef MATROSKAVIDEO_HPP_
|
||||
#define MATROSKAVIDEO_HPP_
|
||||
|
||||
// *****************************************************************************
|
||||
// included header files
|
||||
#include "exif.hpp"
|
||||
#include "image.hpp"
|
||||
#include "tags_int.hpp"
|
||||
|
||||
// *****************************************************************************
|
||||
// namespace extensions
|
||||
namespace Exiv2 {
|
||||
|
||||
// *****************************************************************************
|
||||
// class definitions
|
||||
|
||||
// Add MKV to the supported image formats
|
||||
namespace ImageType {
|
||||
const int mkv = 21; //!< Treating mkv as an image type>
|
||||
}
|
||||
|
||||
/*!
|
||||
@brief Class to access Matroska video files.
|
||||
*/
|
||||
class EXIV2API MatroskaVideo : public Image {
|
||||
public:
|
||||
//! @name Creators
|
||||
//@{
|
||||
/*!
|
||||
@brief Constructor for a Matroska video. Since the constructor
|
||||
can not return a result, callers should check the good() method
|
||||
after object construction to determine success or failure.
|
||||
@param io An auto-pointer that owns a BasicIo instance used for
|
||||
reading and writing image metadata. \b Important: The constructor
|
||||
takes ownership of the passed in BasicIo instance through the
|
||||
auto-pointer. Callers should not continue to use the BasicIo
|
||||
instance after it is passed to this method. Use the Image::io()
|
||||
method to get a temporary reference.
|
||||
*/
|
||||
MatroskaVideo(BasicIo::AutoPtr io);
|
||||
//@}
|
||||
|
||||
//! @name Manipulators
|
||||
//@{
|
||||
void readMetadata();
|
||||
void writeMetadata();
|
||||
//@}
|
||||
|
||||
//! @name Accessors
|
||||
//@{
|
||||
std::string mimeType() const;
|
||||
//@}
|
||||
|
||||
protected:
|
||||
/*!
|
||||
@brief Function used to calulate the size of a block.
|
||||
This information is only stored in one byte.
|
||||
The size of the block is calculated by counting
|
||||
the number of leading zeros in the binary code of the byte.
|
||||
Size = (No. of leading zeros + 1) bytes
|
||||
@param b The byte, which stores the information to calculate the size
|
||||
@return Return the size of the block.
|
||||
*/
|
||||
long findBlockSize(byte b);
|
||||
/*!
|
||||
@brief Check for a valid tag and decode the block at the current IO position.
|
||||
Calls contentManagement() or skips to next tag, if required.
|
||||
*/
|
||||
void decodeBlock();
|
||||
/*!
|
||||
@brief Interpret tag information, and save it in the respective XMP container.
|
||||
@param td Pointer to current tag,
|
||||
@param buf Data buffer with the tag information.
|
||||
@param size Size of buf.
|
||||
*/
|
||||
void contentManagement(const Exiv2::Internal::TagDetails* td, Exiv2::DataBuf& buf, long size);
|
||||
/*!
|
||||
@brief Calculates Aspect Ratio of a video, and stores it in the
|
||||
respective XMP container.
|
||||
*/
|
||||
void aspectRatio();
|
||||
|
||||
private:
|
||||
//! @name NOT Implemented
|
||||
//@{
|
||||
//! Copy constructor
|
||||
MatroskaVideo(const MatroskaVideo& rhs);
|
||||
//! Assignment operator
|
||||
MatroskaVideo& operator=(const MatroskaVideo& rhs);
|
||||
//@}
|
||||
|
||||
private:
|
||||
//! Variable to check the end of metadata traversing.
|
||||
bool continueTraversing_;
|
||||
//! Variable to store height and width of a video frame.
|
||||
uint64_t height_, width_;
|
||||
|
||||
}; // class MatroskaVideo
|
||||
|
||||
// *****************************************************************************
|
||||
// template, inline and free functions
|
||||
|
||||
// These could be static private functions on Image subclasses but then
|
||||
// ImageFactory needs to be made a friend.
|
||||
/*!
|
||||
@brief Create a new MatroskaVideo instance and return an auto-pointer to it.
|
||||
Caller owns the returned object and the auto-pointer ensures that
|
||||
it will be deleted.
|
||||
*/
|
||||
EXIV2API Image::AutoPtr newMkvInstance(BasicIo::AutoPtr io, bool create);
|
||||
|
||||
//! Check if the file iIo is a Matroska Video.
|
||||
EXIV2API bool isMkvType(BasicIo& iIo, bool advance);
|
||||
|
||||
} // namespace Exiv2
|
||||
|
||||
#endif // #ifndef MATROSKAVIDEO_HPP_
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,229 @@
|
||||
// ***************************************************************** -*- C++ -*-
|
||||
/*
|
||||
* Copyright (C) 2004-2012 Andreas Huggel <ahuggel@gmx.net>
|
||||
*
|
||||
* This program is part of the Exiv2 distribution.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, 5th Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
/*!
|
||||
@file quicktimevideo.hpp
|
||||
@brief An Image subclass to support Quick Time video files
|
||||
@version $Rev$
|
||||
@author Abhinav Badola for GSoC 2012
|
||||
<a href="mailto:mail.abu.to@gmail.com">mail.abu.to@gmail.com</a>
|
||||
@date 28-Jun-12, AB: created
|
||||
*/
|
||||
#ifndef QUICKTIMEVIDEO_HPP
|
||||
#define QUICKTIMEVIDEO_HPP
|
||||
|
||||
// *****************************************************************************
|
||||
// included header files
|
||||
#include "exif.hpp"
|
||||
#include "image.hpp"
|
||||
#include "tags_int.hpp"
|
||||
|
||||
// *****************************************************************************
|
||||
// namespace extensions
|
||||
namespace Exiv2 {
|
||||
|
||||
// *****************************************************************************
|
||||
// class definitions
|
||||
|
||||
// Add qtime to the supported image formats
|
||||
namespace ImageType {
|
||||
const int qtime = 22; //!< Treating qtime as an image type>
|
||||
}
|
||||
|
||||
/*!
|
||||
@brief Class to access QuickTime video files.
|
||||
*/
|
||||
class EXIV2API QuickTimeVideo:public Image
|
||||
{
|
||||
public:
|
||||
//! @name Creators
|
||||
//@{
|
||||
/*!
|
||||
@brief Constructor for a QuickTime video. Since the constructor
|
||||
can not return a result, callers should check the good() method
|
||||
after object construction to determine success or failure.
|
||||
@param io An auto-pointer that owns a BasicIo instance used for
|
||||
reading and writing image metadata. \b Important: The constructor
|
||||
takes ownership of the passed in BasicIo instance through the
|
||||
auto-pointer. Callers should not continue to use the BasicIo
|
||||
instance after it is passed to this method. Use the Image::io()
|
||||
method to get a temporary reference.
|
||||
*/
|
||||
QuickTimeVideo(BasicIo::AutoPtr io);
|
||||
//@}
|
||||
|
||||
//! @name Manipulators
|
||||
//@{
|
||||
void readMetadata();
|
||||
void writeMetadata();
|
||||
//@}
|
||||
|
||||
//! @name Accessors
|
||||
//@{
|
||||
std::string mimeType() const;
|
||||
//@}
|
||||
|
||||
protected:
|
||||
/*!
|
||||
@brief Check for a valid tag and decode the block at the current IO
|
||||
position. Calls tagDecoder() or skips to next tag, if required.
|
||||
*/
|
||||
void decodeBlock();
|
||||
/*!
|
||||
@brief Interpret tag information, and call the respective function
|
||||
to save it in the respective XMP container. Decodes a Tag
|
||||
Information and saves it in the respective XMP container, if
|
||||
the block size is small.
|
||||
@param buf Data buffer which cotains tag ID.
|
||||
@param size Size of the data block used to store Tag Information.
|
||||
*/
|
||||
void tagDecoder(Exiv2::DataBuf & buf, unsigned long size);
|
||||
|
||||
private:
|
||||
/*!
|
||||
@brief Interpret file type of the video, and save it
|
||||
in the respective XMP container.
|
||||
@param size Size of the data block used to store Tag Information.
|
||||
*/
|
||||
void fileTypeDecoder(unsigned long size);
|
||||
/*!
|
||||
@brief Interpret Media Header Tag, and save it
|
||||
in the respective XMP container.
|
||||
@param size Size of the data block used to store Tag Information.
|
||||
*/
|
||||
void mediaHeaderDecoder(unsigned long size);
|
||||
/*!
|
||||
@brief Interpret Video Header Tag, and save it
|
||||
in the respective XMP container.
|
||||
@param size Size of the data block used to store Tag Information.
|
||||
*/
|
||||
void videoHeaderDecoder(unsigned long size);
|
||||
/*!
|
||||
@brief Interpret Movie Header Tag, and save it
|
||||
in the respective XMP container.
|
||||
@param size Size of the data block used to store Tag Information.
|
||||
*/
|
||||
void movieHeaderDecoder(unsigned long size);
|
||||
/*!
|
||||
@brief Interpret Track Header Tag, and save it
|
||||
in the respective XMP container.
|
||||
@param size Size of the data block used to store Tag Information.
|
||||
*/
|
||||
void trackHeaderDecoder(unsigned long size);
|
||||
/*!
|
||||
@brief Interpret Handler Tag, and save it
|
||||
in the respective XMP container.
|
||||
@param size Size of the data block used to store Tag Information.
|
||||
*/
|
||||
void handlerDecoder(unsigned long size);
|
||||
/*!
|
||||
@brief Interpret Tag which contain other sub-tags,
|
||||
and save it in the respective XMP container.
|
||||
*/
|
||||
void multipleEntriesDecoder();
|
||||
/*!
|
||||
@brief Interpret Sample Description Tag, and save it
|
||||
in the respective XMP container.
|
||||
@param size Size of the data block used to store Tag Information.
|
||||
*/
|
||||
void sampleDesc(unsigned long size);
|
||||
/*!
|
||||
@brief Interpret Image Description Tag, and save it
|
||||
in the respective XMP container.
|
||||
*/
|
||||
void imageDescDecoder();
|
||||
/*!
|
||||
@brief Interpret User Data Tag, and save it
|
||||
in the respective XMP container.
|
||||
@param size Size of the data block used to store Tag Information.
|
||||
*/
|
||||
void userDataDecoder(unsigned long size);
|
||||
/*!
|
||||
@brief Interpret Nikon Tag, and save it
|
||||
in the respective XMP container.
|
||||
@param size Size of the data block used to store Tag Information.
|
||||
*/
|
||||
void NikonTagsDecoder(unsigned long size);
|
||||
/*!
|
||||
@brief Interpret Audio Description Tag, and save it
|
||||
in the respective XMP container.
|
||||
*/
|
||||
void audioDescDecoder();
|
||||
/*!
|
||||
@brief Helps to calculate Frame Rate from timeToSample chunk,
|
||||
and save it in the respective XMP container.
|
||||
*/
|
||||
void timeToSampleDecoder();
|
||||
/*!
|
||||
@brief Recognizes which stream is currently under processing,
|
||||
and save its information in currentStream_ .
|
||||
*/
|
||||
void setMediaStream();
|
||||
/*!
|
||||
@brief Used to discard a tag along with its data. The Tag will
|
||||
be skipped and not decoded.
|
||||
@param size Size of the data block that is to skipped.
|
||||
*/
|
||||
void discard(unsigned long size);
|
||||
/*!
|
||||
@brief Calculates Aspect Ratio of a video, and stores it in the
|
||||
respective XMP container.
|
||||
*/
|
||||
void aspectRatio();
|
||||
|
||||
private:
|
||||
//! @name NOT Implemented
|
||||
//@{
|
||||
//! Copy constructor
|
||||
QuickTimeVideo(const QuickTimeVideo& rhs);
|
||||
//! Assignment operator
|
||||
QuickTimeVideo& operator=(const QuickTimeVideo& rhs);
|
||||
//@}
|
||||
|
||||
private:
|
||||
//! Variable which stores Time Scale unit, used to calculate time.
|
||||
uint64_t timeScale_;
|
||||
//! Variable which stores current stream being processsed.
|
||||
int currentStream_;
|
||||
//! Variable to check the end of metadata traversing.
|
||||
bool continueTraversing_;
|
||||
//! Variable to store height and width of a video frame.
|
||||
uint64_t height_, width_;
|
||||
|
||||
}; //QuickTimeVideo End
|
||||
|
||||
// *****************************************************************************
|
||||
// template, inline and free functions
|
||||
|
||||
// These could be static private functions on Image subclasses but then
|
||||
// ImageFactory needs to be made a friend.
|
||||
/*!
|
||||
@brief Create a new QuicktimeVideo instance and return an auto-pointer to it.
|
||||
Caller owns the returned object and the auto-pointer ensures that
|
||||
it will be deleted.
|
||||
*/
|
||||
EXIV2API Image::AutoPtr newQTimeInstance(BasicIo::AutoPtr io, bool create);
|
||||
|
||||
//! Check if the file iIo is a Quick Time Video.
|
||||
EXIV2API bool isQTimeType(BasicIo& iIo, bool advance);
|
||||
|
||||
} // namespace Exiv2
|
||||
|
||||
#endif // QUICKTIMEVIDEO_HPP
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,215 @@
|
||||
// ***************************************************************** -*- C++ -*-
|
||||
/*
|
||||
* Copyright (C) 2004-2012 Andreas Huggel <ahuggel@gmx.net>
|
||||
*
|
||||
* This program is part of the Exiv2 distribution.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, 5th Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
/*!
|
||||
@file riffvideo.hpp
|
||||
@brief An Image subclass to support RIFF video files
|
||||
@version $Rev$
|
||||
@author Abhinav Badola for GSoC 2012
|
||||
<a href="mailto:mail.abu.to@gmail.com">mail.abu.to@gmail.com</a>
|
||||
@date 18-Jun-12, AB: created
|
||||
*/
|
||||
#ifndef RIFFVIDEO_HPP
|
||||
#define RIFFVIDEO_HPP
|
||||
|
||||
// *****************************************************************************
|
||||
// included header files
|
||||
#include "exif.hpp"
|
||||
#include "image.hpp"
|
||||
#include "tags_int.hpp"
|
||||
|
||||
// *****************************************************************************
|
||||
// namespace extensions
|
||||
namespace Exiv2 {
|
||||
|
||||
// *****************************************************************************
|
||||
// class definitions
|
||||
|
||||
// Add RIFF to the supported image formats
|
||||
namespace ImageType {
|
||||
const int riff = 20; //!< Treating riff as an image type>
|
||||
}
|
||||
|
||||
/*!
|
||||
@brief Class to access RIFF video files.
|
||||
*/
|
||||
class EXIV2API RiffVideo:public Image
|
||||
{
|
||||
public:
|
||||
//! @name Creators
|
||||
//@{
|
||||
/*!
|
||||
@brief Constructor for a Riff video. Since the constructor
|
||||
can not return a result, callers should check the good() method
|
||||
after object construction to determine success or failure.
|
||||
@param io An auto-pointer that owns a BasicIo instance used for
|
||||
reading and writing image metadata. \b Important: The constructor
|
||||
takes ownership of the passed in BasicIo instance through the
|
||||
auto-pointer. Callers should not continue to use the BasicIo
|
||||
instance after it is passed to this method. Use the Image::io()
|
||||
method to get a temporary reference.
|
||||
*/
|
||||
RiffVideo(BasicIo::AutoPtr io);
|
||||
//@}
|
||||
|
||||
//! @name Manipulators
|
||||
//@{
|
||||
void readMetadata();
|
||||
void writeMetadata();
|
||||
//@}
|
||||
|
||||
//! @name Accessors
|
||||
//@{
|
||||
std::string mimeType() const;
|
||||
const char* printAudioEncoding(uint64_t i);
|
||||
//@}
|
||||
|
||||
protected:
|
||||
/*!
|
||||
@brief Check for a valid tag and decode the block at the current IO
|
||||
position. Calls tagDecoder() or skips to next tag, if required.
|
||||
*/
|
||||
void decodeBlock();
|
||||
/*!
|
||||
@brief Interpret tag information, and call the respective function
|
||||
to save it in the respective XMP container. Decodes a Tag
|
||||
Information and saves it in the respective XMP container, if
|
||||
the block size is small.
|
||||
@param buf Data buffer which cotains tag ID.
|
||||
@param size Size of the data block used to store Tag Information.
|
||||
*/
|
||||
void tagDecoder(Exiv2::DataBuf& buf, unsigned long size);
|
||||
/*!
|
||||
@brief Interpret Junk tag information, and save it
|
||||
in the respective XMP container.
|
||||
@param size Size of the data block used to store Tag Information.
|
||||
*/
|
||||
void junkHandler(long size);
|
||||
/*!
|
||||
@brief Interpret Stream tag information, and save it
|
||||
in the respective XMP container.
|
||||
@param size Size of the data block used to store Tag Information.
|
||||
*/
|
||||
void streamHandler(long size);
|
||||
/*!
|
||||
@brief Interpret Stream Format tag information, and save it
|
||||
in the respective XMP container.
|
||||
@param size Size of the data block used to store Tag Information.
|
||||
*/
|
||||
void streamFormatHandler(long size);
|
||||
/*!
|
||||
@brief Interpret Riff Header tag information, and save it
|
||||
in the respective XMP container.
|
||||
@param size Size of the data block used to store Tag Information.
|
||||
*/
|
||||
void aviHeaderTagsHandler(long size);
|
||||
/*!
|
||||
@brief Interpret Riff List tag information, and save it
|
||||
in the respective XMP container.
|
||||
@param size Size of the data block used to store Tag Information.
|
||||
*/
|
||||
void listHandler(long size);
|
||||
/*!
|
||||
@brief Interpret Riff Stream Data tag information, and save it
|
||||
in the respective XMP container.
|
||||
@param size Size of the data block used to store Tag Information.
|
||||
*/
|
||||
void streamDataTagHandler(long size);
|
||||
/*!
|
||||
@brief Interpret INFO tag information, and save it
|
||||
in the respective XMP container.
|
||||
*/
|
||||
void infoTagsHandler();
|
||||
/*!
|
||||
@brief Interpret Nikon Tags related to Video information, and
|
||||
save it in the respective XMP container.
|
||||
*/
|
||||
void nikonTagsHandler();
|
||||
/*!
|
||||
@brief Interpret OpenDML tag information, and save it
|
||||
in the respective XMP container.
|
||||
*/
|
||||
void odmlTagsHandler();
|
||||
//! @brief Skips Particular Blocks of Metadata List.
|
||||
void skipListData();
|
||||
/*!
|
||||
@brief Interprets DateTimeOriginal tag or stream name tag
|
||||
information, and save it in the respective XMP container.
|
||||
@param size Size of the data block used to store Tag Information.
|
||||
@param i parameter used to overload function
|
||||
*/
|
||||
void dateTimeOriginal(long size, int i = 0);
|
||||
/*!
|
||||
@brief Calculates Sample Rate of a particular stream.
|
||||
@param buf Data buffer with the dividend.
|
||||
@param divisor The Divisor required to calculate sample rate.
|
||||
@return Return the sample rate of the stream.
|
||||
*/
|
||||
double returnSampleRate(Exiv2::DataBuf& buf, long divisor = 1);
|
||||
/*!
|
||||
@brief Calculates Aspect Ratio of a video, and stores it in the
|
||||
respective XMP container.
|
||||
@param width Width of the video.
|
||||
@param height Height of the video.
|
||||
*/
|
||||
void fillAspectRatio(long width = 1,long height = 1);
|
||||
/*!
|
||||
@brief Calculates Duration of a video, and stores it in the
|
||||
respective XMP container.
|
||||
@param frame_rate Frame rate of the video.
|
||||
@param frame_count Total number of frames present in the video.
|
||||
*/
|
||||
void fillDuration(double frame_rate, long frame_count);
|
||||
|
||||
private:
|
||||
//! @name NOT Implemented
|
||||
//@{
|
||||
//! Copy constructor
|
||||
RiffVideo(const RiffVideo& rhs);
|
||||
//! Assignment operator
|
||||
RiffVideo& operator=(const RiffVideo& rhs);
|
||||
//@}
|
||||
|
||||
private:
|
||||
//! Variable to check the end of metadata traversing.
|
||||
bool continueTraversing_;
|
||||
//! Variable which stores current stream being processsed.
|
||||
int streamType_;
|
||||
|
||||
}; //Class RiffVideo
|
||||
|
||||
// *****************************************************************************
|
||||
// template, inline and free functions
|
||||
|
||||
// These could be static private functions on Image subclasses but then
|
||||
// ImageFactory needs to be made a friend.
|
||||
/*!
|
||||
@brief Create a new RiffVideo instance and return an auto-pointer to it.
|
||||
Caller owns the returned object and the auto-pointer ensures that
|
||||
it will be deleted.
|
||||
*/
|
||||
EXIV2API Image::AutoPtr newRiffInstance(BasicIo::AutoPtr io, bool create);
|
||||
|
||||
//! Check if the file iIo is a Riff Video.
|
||||
EXIV2API bool isRiffType(BasicIo& iIo, bool advance);
|
||||
|
||||
} // namespace Exiv2
|
||||
|
||||
#endif // RIFFVIDEO_HPP
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -0,0 +1,62 @@
|
||||
#! /bin/sh
|
||||
# Test driver for video files
|
||||
#
|
||||
# video-asf.wmv http://www.educationalquestions.com/video/DLP_PART_2_768k.wmv
|
||||
# video-avi.avi http://redmine.yorba.org/attachments/631/Nikon_Coolpix_S3000.AVI
|
||||
# video-matroska.mkv http://www.bunkus.org/videotools/mkvtoolnix/samples/vsshort-vorbis-subs.mkv
|
||||
# video-quicktime.mp4 http://dev.exiv2.org/attachments/362/20100709_002.mp4
|
||||
|
||||
# ----------------------------------------------------------------------
|
||||
# Setup
|
||||
export LC_ALL=C
|
||||
cd tmp/
|
||||
if [ -z "$EXIV2_BINDIR" ] ; then
|
||||
bin="$VALGRIND ../../src"
|
||||
samples="$VALGRIND ../../samples"
|
||||
else
|
||||
bin="$VALGRIND $EXIV2_BINDIR"
|
||||
samples="$VALGRIND $EXIV2_BINDIR"
|
||||
fi
|
||||
diffargs="--strip-trailing-cr"
|
||||
if ! diff -q $diffargs /dev/null /dev/null 2>/dev/null ; then
|
||||
diffargs=""
|
||||
fi
|
||||
|
||||
# ----------------------------------------------------------------------
|
||||
# Tests
|
||||
(
|
||||
for file in ../data/video/video-*; do
|
||||
video="`basename "$file"`"
|
||||
if [ $video = "video-test.out" ] ; then
|
||||
continue
|
||||
fi
|
||||
|
||||
printf "." >&3
|
||||
|
||||
echo
|
||||
echo "-----> $video <-----"
|
||||
|
||||
cp "../data/video/$video" ./
|
||||
|
||||
echo
|
||||
echo "Command: exiv2 -u -pa $video"
|
||||
$bin/exiv2 -u -pa "$video"
|
||||
exitcode="$?"
|
||||
echo "Exit code: $exitcode"
|
||||
|
||||
if [ "$exitcode" -ne 0 -a "$exitcode" -ne 253 ] ; then
|
||||
continue
|
||||
fi
|
||||
|
||||
done
|
||||
) 3>&1 > "video-test.out" 2>&1
|
||||
|
||||
echo "."
|
||||
|
||||
# ----------------------------------------------------------------------
|
||||
# Result
|
||||
if ! diff -q $diffargs "../data/video/video-test.out" "video-test.out" ; then
|
||||
diff -u -a $diffargs "../data/video/video-test.out" "video-test.out"
|
||||
exit 1
|
||||
fi
|
||||
echo "All testcases passed."
|
Loading…
Reference in New Issue