|
Packit |
01d647 |
// ***************************************************************** -*- C++ -*-
|
|
Packit |
01d647 |
/*
|
|
Packit |
01d647 |
* Copyright (C) 2004-2018 Exiv2 authors
|
|
Packit |
01d647 |
* This program is part of the Exiv2 distribution.
|
|
Packit |
01d647 |
*
|
|
Packit |
01d647 |
* This program is free software; you can redistribute it and/or
|
|
Packit |
01d647 |
* modify it under the terms of the GNU General Public License
|
|
Packit |
01d647 |
* as published by the Free Software Foundation; either version 2
|
|
Packit |
01d647 |
* of the License, or (at your option) any later version.
|
|
Packit |
01d647 |
*
|
|
Packit |
01d647 |
* This program is distributed in the hope that it will be useful,
|
|
Packit |
01d647 |
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
Packit |
01d647 |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
Packit |
01d647 |
* GNU General Public License for more details.
|
|
Packit |
01d647 |
*
|
|
Packit |
01d647 |
* You should have received a copy of the GNU General Public License
|
|
Packit |
01d647 |
* along with this program; if not, write to the Free Software
|
|
Packit |
01d647 |
* Foundation, Inc., 51 Franklin Street, 5th Floor, Boston, MA 02110-1301 USA.
|
|
Packit |
01d647 |
*/
|
|
Packit |
01d647 |
/*
|
|
Packit |
01d647 |
File: asfvideo.cpp
|
|
Packit |
01d647 |
Author(s): Abhinav Badola for GSoC 2012 (AB) <mail.abu.to@gmail.com>
|
|
Packit |
01d647 |
History: 08-Aug-12, AB: created
|
|
Packit |
01d647 |
Credits: See header file
|
|
Packit |
01d647 |
*/
|
|
Packit |
01d647 |
// *****************************************************************************
|
|
Packit |
01d647 |
// included header files
|
|
Packit |
01d647 |
#include "config.h"
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
#ifdef EXV_ENABLE_VIDEO
|
|
Packit |
01d647 |
#include "error.hpp"
|
|
Packit |
01d647 |
#include "tags.hpp"
|
|
Packit |
01d647 |
#include "tags_int.hpp"
|
|
Packit |
01d647 |
#include "asfvideo.hpp"
|
|
Packit |
01d647 |
#include "futils.hpp"
|
|
Packit |
01d647 |
#include "basicio.hpp"
|
|
Packit |
01d647 |
#include "types.hpp"
|
|
Packit |
01d647 |
#include "riffvideo.hpp"
|
|
Packit |
01d647 |
#include "convert.hpp"
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
// + standard includes
|
|
Packit |
01d647 |
#include <cmath>
|
|
Packit |
01d647 |
#include <cstring>
|
|
Packit |
01d647 |
#include <ctype.h>
|
|
Packit |
01d647 |
#include <cassert>
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
// *****************************************************************************
|
|
Packit |
01d647 |
// class member definitions
|
|
Packit |
01d647 |
namespace Exiv2 {
|
|
Packit |
01d647 |
namespace Internal {
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
/*!
|
|
Packit |
01d647 |
Tag Look-up list for ASF Type Video Files
|
|
Packit |
01d647 |
Associates the GUID of a Tag with its Tag Name(i.e. Human Readable Form)
|
|
Packit |
01d647 |
Tags have been diferentiated into Various Categories.
|
|
Packit |
01d647 |
The categories have been listed above the Tag Groups
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
*/
|
|
Packit |
01d647 |
extern const TagVocabulary GUIDReferenceTags[] = {
|
|
Packit |
01d647 |
/// Top-level ASF object GUIDS
|
|
Packit |
01d647 |
{ "75B22630-668E-11CF-A6D9-00AA0062CE6C", "Header" },
|
|
Packit |
01d647 |
{ "75B22636-668E-11CF-A6D9-00AA0062CE6C", "Data" },
|
|
Packit |
01d647 |
{ "33000890-E5B1-11CF-89F4-00A0C90349CB", "Simple_Index" },
|
|
Packit |
01d647 |
{ "D6E229D3-35DA-11D1-9034-00A0C90349BE", "Index" },
|
|
Packit |
01d647 |
{ "FEB103F8-12AD-4C64-840F-2A1D2F7AD48C", "Media_Index" },
|
|
Packit |
01d647 |
{ "3CB73FD0-0C4A-4803-953D-EDF7B6228F0C", "Timecode_Index" },
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
/// Header Object GUIDs
|
|
Packit |
01d647 |
{ "8CABDCA1-A947-11CF-8EE4-00C00C205365", "File_Properties" },
|
|
Packit |
01d647 |
{ "B7DC0791-A9B7-11CF-8EE6-00C00C205365", "Stream_Properties" },
|
|
Packit |
01d647 |
{ "5FBF03B5-A92E-11CF-8EE3-00C00C205365", "Header_Extension" },
|
|
Packit |
01d647 |
{ "86D15240-311D-11D0-A3A4-00A0C90348F6", "Codec_List" },
|
|
Packit |
01d647 |
{ "1EFB1A30-0B62-11D0-A39B-00A0C90348F6", "Script_Command" },
|
|
Packit |
01d647 |
{ "F487CD01-A951-11CF-8EE6-00C00C205365", "Marker" },
|
|
Packit |
01d647 |
{ "D6E229DC-35DA-11D1-9034-00A0C90349BE", "Bitrate_Mutual_Exclusion" },
|
|
Packit |
01d647 |
{ "75B22635-668E-11CF-A6D9-00AA0062CE6C", "Error_Correction" },
|
|
Packit |
01d647 |
{ "75B22633-668E-11CF-A6D9-00AA0062CE6C", "Content_Description" },
|
|
Packit |
01d647 |
{ "D2D0A440-E307-11D2-97F0-00A0C95EA850", "Extended_Content_Description" },
|
|
Packit |
01d647 |
{ "2211B3FA-BD23-11D2-B4B7-00A0C955FC6E", "Content_Branding" },
|
|
Packit |
01d647 |
{ "7BF875CE-468D-11D1-8D82-006097C9A2B2", "Stream_Bitrate_Properties" },
|
|
Packit |
01d647 |
{ "2211B3FB-BD23-11D2-B4B7-00A0C955FC6E", "Content_Encryption" },
|
|
Packit |
01d647 |
{ "298AE614-2622-4C17-B935-DAE07EE9289C", "Extended_Content_Encryption" },
|
|
Packit |
01d647 |
{ "2211B3FC-BD23-11D2-B4B7-00A0C955FC6E", "Digital_Signature" },
|
|
Packit |
01d647 |
{ "1806D474-CADF-4509-A4BA-9AABCB96AAE8", "Padding" },
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
/// Header Extension Object GUIDs
|
|
Packit |
01d647 |
{ "14E6A5CB-C672-4332-8399-A96952065B5A", "Extended_Stream_Properties" },
|
|
Packit |
01d647 |
{ "A08649CF-4775-4670-8A16-6E35357566CD", "Advanced_Mutual_Exclusion" },
|
|
Packit |
01d647 |
{ "D1465A40-5A79-4338-B71B-E36B8FD6C249", "Group_Mutual_Exclusion" },
|
|
Packit |
01d647 |
{ "D4FED15B-88D3-454F-81F0-ED5C45999E24", "Stream_Prioritization" },
|
|
Packit |
01d647 |
{ "A69609E6-517B-11D2-B6AF-00C04FD908E9", "Bandwidth_Sharing" },
|
|
Packit |
01d647 |
{ "7C4346A9-EFE0-4BFC-B229-393EDE415C85", "Language_List" },
|
|
Packit |
01d647 |
{ "C5F8CBEA-5BAF-4877-8467-AA8C44FA4CCA", "Metadata" },
|
|
Packit |
01d647 |
{ "44231C94-9498-49D1-A141-1D134E457054", "Metadata_Library" },
|
|
Packit |
01d647 |
{ "D6E229DF-35DA-11D1-9034-00A0C90349BE", "Index_Parameters" },
|
|
Packit |
01d647 |
{ "6B203BAD-3F11-48E4-ACA8-D7613DE2CFA7", "Media_Index_Parameters" },
|
|
Packit |
01d647 |
{ "F55E496D-9797-4B5D-8C8B-604DFE9BFB24", "Timecode_Index_Parameters" },
|
|
Packit |
01d647 |
{ "26F18B5D-4584-47EC-9F5F-0E651F0452C9", "Compatibility" },
|
|
Packit |
01d647 |
{ "43058533-6981-49E6-9B74-AD12CB86D58C", "Advanced_Content_Encryption" },
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
/// Stream Properties Object Stream Type GUIDs
|
|
Packit |
01d647 |
{ "F8699E40-5B4D-11CF-A8FD-00805F5C442B", "Audio_Media" },
|
|
Packit |
01d647 |
{ "BC19EFC0-5B4D-11CF-A8FD-00805F5C442B", "Video_Media" },
|
|
Packit |
01d647 |
{ "59DACFC0-59E6-11D0-A3AC-00A0C90348F6", "Command_Media" },
|
|
Packit |
01d647 |
{ "B61BE100-5B4E-11CF-A8FD-00805F5C442B", "JFIF_Media" },
|
|
Packit |
01d647 |
{ "35907DE0-E415-11CF-A917-00805F5C442B", "Degradable_JPEG_Media" },
|
|
Packit |
01d647 |
{ "91BD222C-F21C-497A-8B6D-5AA86BFC0185", "File_Transfer_Media" },
|
|
Packit |
01d647 |
{ "3AFB65E2-47EF-40F2-AC2C-70A90D71D343", "Binary_Media" },
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
/// Web stream Type-Specific Data GUIDs
|
|
Packit |
01d647 |
{ "776257D4-C627-41CB-8F81-7AC7FF1C40CC", "Web_Stream_Media_Subtype" },
|
|
Packit |
01d647 |
{ "DA1E6B13-8359-4050-B398-388E965BF00C", "Web_Stream_Format" },
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
/// Stream Properties Object Error Correction Type GUIDs
|
|
Packit |
01d647 |
{ "20FB5700-5B55-11CF-A8FD-00805F5C442B", "No_Error_Correction" },
|
|
Packit |
01d647 |
{ "BFC3CD50-618F-11CF-8BB2-00AA00B4E220", "Audio_Spread" },
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
/// Header Extension Object GUIDs
|
|
Packit |
01d647 |
{ "ABD3D211-A9BA-11cf-8EE6-00C00C205365", "Reserved_1" },
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
/// Advanced Content Encryption Object System ID GUIDs
|
|
Packit |
01d647 |
{ "7A079BB6-DAA4-4e12-A5CA-91D38DC11A8D", "Content_Encryption_System_Windows_Media_DRM_Network_Devices" },
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
/// Codec List Object GUIDs
|
|
Packit |
01d647 |
{ "86D15241-311D-11D0-A3A4-00A0C90348F6", "Reserved_2" },
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
/// Script Command Object GUIDs
|
|
Packit |
01d647 |
{ "4B1ACBE3-100B-11D0-A39B-00A0C90348F6", "Reserved_3" },
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
/// Marker Object GUIDs
|
|
Packit |
01d647 |
{ "4CFEDB20-75F6-11CF-9C0F-00A0C90349CB", "Reserved_4" },
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
/// Mutual Exclusion Object Exclusion Type GUIDs
|
|
Packit |
01d647 |
{ "D6E22A00-35DA-11D1-9034-00A0C90349BE", "Mutex_Language" },
|
|
Packit |
01d647 |
{ "D6E22A01-35DA-11D1-9034-00A0C90349BE", "Mutex_Bitrate" },
|
|
Packit |
01d647 |
{ "D6E22A02-35DA-11D1-9034-00A0C90349BE", "Mutex_Unknown" },
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
/// Bandwidth Sharing Object GUIDs
|
|
Packit |
01d647 |
{ "AF6060AA-5197-11D2-B6AF-00C04FD908E9", "Bandwidth_Sharing_Exclusive" },
|
|
Packit |
01d647 |
{ "AF6060AB-5197-11D2-B6AF-00C04FD908E9", "Bandwidth_Sharing_Partial" },
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
/// Standard Payload Extension System GUIDs
|
|
Packit |
01d647 |
{ "399595EC-8667-4E2D-8FDB-98814CE76C1E", "Payload_Extension_System_Timecode" },
|
|
Packit |
01d647 |
{ "E165EC0E-19ED-45D7-B4A7-25CBD1E28E9B", "Payload_Extension_System_File_Name" },
|
|
Packit |
01d647 |
{ "D590DC20-07BC-436C-9CF7-F3BBFBF1A4DC", "Payload_Extension_System_Content_Type" },
|
|
Packit |
01d647 |
{ "1B1EE554-F9EA-4BC8-821A-376B74E4C4B8", "Payload_Extension_System_Pixel_Aspect_Ratio" },
|
|
Packit |
01d647 |
{ "C6BD9450-867F-4907-83A3-C77921B733AD", "Payload_Extension_System_Sample_Duration" },
|
|
Packit |
01d647 |
{ "6698B84E-0AFA-4330-AEB2-1C0A98D7A44D", "Payload_Extension_System_Encryption_Sample_ID" },
|
|
Packit |
01d647 |
{ "00E1AF06-7BEC-11D1-A582-00C04FC29CFB", "Payload_Extension_System_Degradable_JPEG" }
|
|
Packit |
01d647 |
};
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
//! Audio codec type-specific data in ASF
|
|
Packit |
01d647 |
extern const TagDetails audioCodec[] = {
|
|
Packit |
01d647 |
{ 0x161, "Windows Media Audio (7, 8, and 9 Series)" },
|
|
Packit |
01d647 |
{ 0x162, "Windows Media Audio 9 Professional" },
|
|
Packit |
01d647 |
{ 0x163, "Windows Media Audio 9 Lossless" },
|
|
Packit |
01d647 |
{ 0x7A21, "GSM-AMR (CBR, no SID)" },
|
|
Packit |
01d647 |
{ 0x7A22, "GSM-AMR (VBR including SID)" }
|
|
Packit |
01d647 |
};
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
extern const TagDetails filePropertiesTags[] = {
|
|
Packit |
01d647 |
{ 7, "Xmp.video.FileLength" },
|
|
Packit |
01d647 |
{ 6, "Xmp.video.CreationDate" },
|
|
Packit |
01d647 |
{ 5, "Xmp.video.DataPackets" },
|
|
Packit |
01d647 |
{ 4, "Xmp.video.Duration" },
|
|
Packit |
01d647 |
{ 3, "Xmp.video.SendDuration" },
|
|
Packit |
01d647 |
{ 2, "Xmp.video.Preroll" },
|
|
Packit |
01d647 |
{ 1, "Xmp.video.MaxBitRate" }
|
|
Packit |
01d647 |
};
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
extern const TagDetails contentDescriptionTags[] = {
|
|
Packit |
01d647 |
{ 0, "Xmp.video.Title" },
|
|
Packit |
01d647 |
{ 1, "Xmp.video.Author" },
|
|
Packit |
01d647 |
{ 2, "Xmp.video.Copyright" },
|
|
Packit |
01d647 |
{ 3, "Xmp.video.Description" },
|
|
Packit |
01d647 |
{ 4, "Xmp.video.Rating" }
|
|
Packit |
01d647 |
};
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
/*!
|
|
Packit |
01d647 |
@brief Function used to read data from data buffer, reads 16-bit character
|
|
Packit |
01d647 |
array and stores it in std::string object.
|
|
Packit |
01d647 |
@param buf Exiv2 data buffer, which stores the information
|
|
Packit |
01d647 |
@return Returns std::string object .
|
|
Packit |
01d647 |
*/
|
|
Packit |
01d647 |
std::string toString16(Exiv2::DataBuf& buf)
|
|
Packit |
01d647 |
{
|
|
Packit |
01d647 |
std::ostringstream os; char t;
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
for(int i = 0; i <= buf.size_; i += 2 ) {
|
|
Packit |
01d647 |
t = buf.pData_[i] + 16 * buf.pData_[i + 1];
|
|
Packit |
01d647 |
if(t == 0) {
|
|
Packit |
01d647 |
if(i)
|
|
Packit |
01d647 |
os << '\0';
|
|
Packit |
01d647 |
break;
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
os<< t;
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
return os.str();
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
/*!
|
|
Packit |
01d647 |
@brief Function used to check equality of two Tags (ignores case).
|
|
Packit |
01d647 |
@param str1 char* Pointer to First Tag
|
|
Packit |
01d647 |
@param str2 char* Pointer to Second Tag
|
|
Packit |
01d647 |
@return Returns true if both are equal.
|
|
Packit |
01d647 |
*/
|
|
Packit |
01d647 |
bool compareTag(const char* str1, const char* str2) {
|
|
Packit |
01d647 |
if ( strlen(str1) != strlen(str2))
|
|
Packit |
01d647 |
return false;
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
for ( uint64_t i = 0 ; i < strlen(str1); ++i )
|
|
Packit |
01d647 |
if (tolower(str1[i]) != tolower(str2[i]))
|
|
Packit |
01d647 |
return false;
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
return true;
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
/*!
|
|
Packit |
01d647 |
@brief Function used to convert a decimal number to its Hexadecimal
|
|
Packit |
01d647 |
equivalent, then parsed into a character
|
|
Packit |
01d647 |
@param n Integer which is to be parsed as Hexadecimal character
|
|
Packit |
01d647 |
@return Return a Hexadecimal number, in character
|
|
Packit |
01d647 |
*/
|
|
Packit |
01d647 |
char returnHEX(int n) {
|
|
Packit |
01d647 |
if(n >= 0 && n <= 9)
|
|
Packit |
01d647 |
return (char)(n + 48);
|
|
Packit |
01d647 |
else
|
|
Packit |
01d647 |
return (char)(n + 55);
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
/*!
|
|
Packit |
01d647 |
@brief Function used to calculate GUID, Tags comprises of 16 bytes.
|
|
Packit |
01d647 |
The Buffer contains the Tag in Binary Form. The information is then
|
|
Packit |
01d647 |
parsed into a character array GUID.
|
|
Packit |
01d647 |
*/
|
|
Packit |
01d647 |
void getGUID (byte buf[], char GUID[]) {
|
|
Packit |
01d647 |
int i;
|
|
Packit |
01d647 |
for (i = 0; i < 4; ++i) {
|
|
Packit |
01d647 |
GUID[(3 - i) * 2] = returnHEX(buf[i] / 0x10);
|
|
Packit |
01d647 |
GUID[(3 - i) * 2 + 1] = returnHEX(buf[i] % 0x10);
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
for (i = 4; i < 6; ++i) {
|
|
Packit |
01d647 |
GUID[(9 - i) * 2 + 1] = returnHEX(buf[i] / 0x10);
|
|
Packit |
01d647 |
GUID[(9 - i) * 2 + 2] = returnHEX(buf[i] % 0x10);
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
for (i = 6; i < 8; ++i) {
|
|
Packit |
01d647 |
GUID[(14 - i) * 2] = returnHEX(buf[i] / 0x10);
|
|
Packit |
01d647 |
GUID[(14 - i) * 2 + 1] = returnHEX(buf[i] % 0x10);
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
for (i = 8; i < 10; ++i) {
|
|
Packit |
01d647 |
GUID[ i * 2 + 3] = returnHEX(buf[i] / 0x10);
|
|
Packit |
01d647 |
GUID[ i * 2 + 4] = returnHEX(buf[i] % 0x10);
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
for (i = 10; i < 16; ++i) {
|
|
Packit |
01d647 |
GUID[ i * 2 + 4] = returnHEX(buf[i] / 0x10);
|
|
Packit |
01d647 |
GUID[ i * 2 + 5] = returnHEX(buf[i] % 0x10);
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
GUID[36] = '\0'; GUID[8] = GUID[13] = GUID[18] = GUID[23] = '-';
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
/*!
|
|
Packit |
01d647 |
@brief Function used to check if data stored in buf is equivalent to
|
|
Packit |
01d647 |
ASF Header Tag's GUID.
|
|
Packit |
01d647 |
@param buf Exiv2 byte buffer
|
|
Packit |
01d647 |
@return Returns true if the buffer data is equivalent to Header GUID.
|
|
Packit |
01d647 |
*/
|
|
Packit |
01d647 |
bool isASFType (byte buf[]) {
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
if(buf[0] == 0x30 && buf[1] == 0x26 && buf[2] == 0xb2 && buf[3] == 0x75 &&
|
|
Packit |
01d647 |
buf[4] == 0x8e && buf[5] == 0x66 && buf[6] == 0xcf && buf[7] == 0x11 &&
|
|
Packit |
01d647 |
buf[8] == 0xa6 && buf[9] == 0xd9 && buf[10] == 0x00 && buf[11] == 0xaa &&
|
|
Packit |
01d647 |
buf[12] == 0x00 && buf[13] == 0x62 && buf[14] == 0xce && buf[15] == 0x6c )
|
|
Packit |
01d647 |
return true;
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
return false;
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
//! Function used to convert buffer data into 64-bit Integer, information stored in littleEndian format
|
|
Packit |
01d647 |
uint64_t getUint64_t(Exiv2::DataBuf& buf) {
|
|
Packit |
01d647 |
uint64_t temp = 0;
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
for(int i = 0; i < 8; ++i){
|
|
Packit |
01d647 |
temp = temp + static_cast<uint64_t>(buf.pData_[i]*(pow(static_cast<float>(256), i)));
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
return temp;
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
}} // namespace Internal, Exiv2
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
namespace Exiv2 {
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
using namespace Exiv2::Internal;
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
AsfVideo::AsfVideo(BasicIo::AutoPtr io)
|
|
Packit |
01d647 |
: Image(ImageType::asf, mdNone, io)
|
|
Packit |
01d647 |
{
|
|
Packit |
01d647 |
} // AsfVideo::AsfVideo
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
std::string AsfVideo::mimeType() const
|
|
Packit |
01d647 |
{
|
|
Packit |
01d647 |
return "video/asf";
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
void AsfVideo::writeMetadata()
|
|
Packit |
01d647 |
{
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
void AsfVideo::readMetadata()
|
|
Packit |
01d647 |
{
|
|
Packit |
01d647 |
if (io_->open() != 0) throw Error(kerDataSourceOpenFailed, io_->path(), strError());
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
// Ensure that this is the correct image type
|
|
Packit |
01d647 |
if (!isAsfType(*io_, false)) {
|
|
Packit |
01d647 |
if (io_->error() || io_->eof()) throw Error(kerFailedToReadImageData);
|
|
Packit |
01d647 |
throw Error(kerNotAnImage, "ASF");
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
IoCloser closer(*io_);
|
|
Packit |
01d647 |
clearMetadata();
|
|
Packit |
01d647 |
continueTraversing_ = true;
|
|
Packit |
01d647 |
io_->seek(0, BasicIo::beg);
|
|
Packit |
01d647 |
height_ = width_ = 1;
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
xmpData_["Xmp.video.FileSize"] = (double)io_->size()/(double)1048576;
|
|
Packit |
01d647 |
xmpData_["Xmp.video.FileName"] = io_->path();
|
|
Packit |
01d647 |
xmpData_["Xmp.video.MimeType"] = mimeType();
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
while (continueTraversing_) decodeBlock();
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
aspectRatio();
|
|
Packit |
01d647 |
} // AsfVideo::readMetadata
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
void AsfVideo::decodeBlock()
|
|
Packit |
01d647 |
{
|
|
Packit |
01d647 |
const long bufMinSize = 9;
|
|
Packit |
01d647 |
DataBuf buf(bufMinSize);
|
|
Packit |
01d647 |
uint64_t size = 0;
|
|
Packit |
01d647 |
buf.pData_[8] = '\0' ;
|
|
Packit |
01d647 |
const TagVocabulary* tv;
|
|
Packit |
01d647 |
uint64_t cur_pos = io_->tell();
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
byte guidBuf[16];
|
|
Packit |
01d647 |
io_->read(guidBuf, 16);
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
if(io_->eof()) {
|
|
Packit |
01d647 |
continueTraversing_ = false;
|
|
Packit |
01d647 |
return;
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
char GUID[37] = ""; //the getGUID function write the GUID[36],
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
getGUID(guidBuf, GUID);
|
|
Packit |
01d647 |
tv = find( GUIDReferenceTags, GUID);
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
std::memset(buf.pData_, 0x0, buf.size_);
|
|
Packit |
01d647 |
io_->read(buf.pData_, 8);
|
|
Packit |
01d647 |
size = getUint64_t(buf);
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
if(tv) {
|
|
Packit |
01d647 |
tagDecoder(tv,size-24);
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
else
|
|
Packit |
01d647 |
io_->seek(cur_pos + size, BasicIo::beg);
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
localPosition_ = io_->tell();
|
|
Packit |
01d647 |
} // AsfVideo::decodeBlock
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
void AsfVideo::tagDecoder(const TagVocabulary *tv, uint64_t size)
|
|
Packit |
01d647 |
{
|
|
Packit |
01d647 |
uint64_t cur_pos = io_->tell();
|
|
Packit |
01d647 |
DataBuf buf(1000);
|
|
Packit |
01d647 |
unsigned long count = 0, tempLength = 0;
|
|
Packit |
01d647 |
buf.pData_[4] = '\0' ;
|
|
Packit |
01d647 |
Exiv2::Value::AutoPtr v = Exiv2::Value::create(Exiv2::xmpSeq);
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
if(compareTag( exvGettext(tv->label_), "Header")) {
|
|
Packit |
01d647 |
localPosition_ = 0;
|
|
Packit |
01d647 |
io_->read(buf.pData_, 4);
|
|
Packit |
01d647 |
io_->read(buf.pData_, 2);
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
while(localPosition_ < cur_pos + size) decodeBlock();
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
else if(compareTag( exvGettext(tv->label_), "File_Properties"))
|
|
Packit |
01d647 |
fileProperties();
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
else if(compareTag( exvGettext(tv->label_), "Stream_Properties"))
|
|
Packit |
01d647 |
streamProperties();
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
else if(compareTag( exvGettext(tv->label_), "Metadata"))
|
|
Packit |
01d647 |
metadataHandler(1);
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
else if(compareTag( exvGettext(tv->label_), "Extended_Content_Description"))
|
|
Packit |
01d647 |
metadataHandler(2);
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
else if(compareTag( exvGettext(tv->label_), "Metadata_Library"))
|
|
Packit |
01d647 |
metadataHandler(3);
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
else if(compareTag( exvGettext(tv->label_), "Codec_List"))
|
|
Packit |
01d647 |
codecList();
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
else if(compareTag( exvGettext(tv->label_), "Content_Description"))
|
|
Packit |
01d647 |
contentDescription(size);
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
else if(compareTag( exvGettext(tv->label_), "Extended_Stream_Properties"))
|
|
Packit |
01d647 |
extendedStreamProperties(size);
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
else if(compareTag( exvGettext(tv->label_), "Header_Extension")) {
|
|
Packit |
01d647 |
localPosition_ = 0;
|
|
Packit |
01d647 |
headerExtension(size);
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
else if(compareTag( exvGettext(tv->label_), "Language_List")) {
|
|
Packit |
01d647 |
std::memset(buf.pData_, 0x0, buf.size_);
|
|
Packit |
01d647 |
io_->read(buf.pData_, 2);
|
|
Packit |
01d647 |
count = Exiv2::getUShort(buf.pData_, littleEndian);
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
while(count--) {
|
|
Packit |
01d647 |
std::memset(buf.pData_, 0x0, buf.size_);
|
|
Packit |
01d647 |
io_->read(buf.pData_, 1); tempLength = (int)buf.pData_[0];
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
io_->read(buf.pData_, tempLength);
|
|
Packit |
01d647 |
v->read(toString16(buf));
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
xmpData_.add(Exiv2::XmpKey("Xmp.video.TrackLang"), v.get());
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
io_->seek(cur_pos + size, BasicIo::beg);
|
|
Packit |
01d647 |
localPosition_ = io_->tell();
|
|
Packit |
01d647 |
} // AsfVideo::tagDecoder
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
void AsfVideo::extendedStreamProperties(uint64_t size)
|
|
Packit |
01d647 |
{
|
|
Packit |
01d647 |
uint64_t cur_pos = io_->tell(), avgTimePerFrame = 0;
|
|
Packit |
01d647 |
DataBuf buf(8);
|
|
Packit |
01d647 |
static int previousStream;
|
|
Packit |
01d647 |
io_->seek(cur_pos + 48, BasicIo::beg);
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
std::memset(buf.pData_, 0x0, buf.size_);
|
|
Packit |
01d647 |
io_->read(buf.pData_, 2);
|
|
Packit |
01d647 |
streamNumber_ = Exiv2::getUShort(buf.pData_, littleEndian);
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
io_->read(buf.pData_, 2);
|
|
Packit |
01d647 |
io_->read(buf.pData_, 8);
|
|
Packit |
01d647 |
avgTimePerFrame = getUint64_t(buf);
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
if(previousStream < streamNumber_ && avgTimePerFrame != 0)
|
|
Packit |
01d647 |
xmpData_["Xmp.video.FrameRate"] = (double)10000000/(double)avgTimePerFrame;
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
previousStream = streamNumber_;
|
|
Packit |
01d647 |
io_->seek(cur_pos + size, BasicIo::beg);
|
|
Packit |
01d647 |
} // AsfVideo::extendedStreamProperties
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
void AsfVideo::contentDescription(uint64_t size)
|
|
Packit |
01d647 |
{
|
|
Packit |
01d647 |
const long pos = io_->tell();
|
|
Packit |
01d647 |
if (pos == -1) throw Error(kerFailedToReadImageData);
|
|
Packit |
01d647 |
long length[5];
|
|
Packit |
01d647 |
for (int i = 0 ; i < 5 ; ++i) {
|
|
Packit |
01d647 |
byte buf[2];
|
|
Packit |
01d647 |
io_->read(buf, 2);
|
|
Packit |
01d647 |
if (io_->error() || io_->eof()) throw Error(kerFailedToReadImageData);
|
|
Packit |
01d647 |
length[i] = getUShort(buf, littleEndian);
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
for (int i = 0 ; i < 5 ; ++i) {
|
|
Packit |
01d647 |
DataBuf buf(length[i]);
|
|
Packit |
01d647 |
std::memset(buf.pData_, 0x0, buf.size_);
|
|
Packit |
01d647 |
io_->read(buf.pData_, length[i]);
|
|
Packit |
01d647 |
if (io_->error() || io_->eof()) throw Error(kerFailedToReadImageData);
|
|
Packit |
01d647 |
const TagDetails* td = find(contentDescriptionTags, i);
|
|
Packit |
01d647 |
assert(td);
|
|
Packit |
01d647 |
std::string str((const char*)buf.pData_, length[i]);
|
|
Packit |
01d647 |
if (convertStringCharset(str, "UCS-2LE", "UTF-8")) {
|
|
Packit |
01d647 |
xmpData_[td->label_] = str;
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
else {
|
|
Packit |
01d647 |
xmpData_[td->label_] = toString16(buf);
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
if (io_->seek(pos + size, BasicIo::beg)) throw Error(kerFailedToReadImageData);
|
|
Packit |
01d647 |
} // AsfVideo::contentDescription
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
void AsfVideo::streamProperties()
|
|
Packit |
01d647 |
{
|
|
Packit |
01d647 |
DataBuf buf(20);
|
|
Packit |
01d647 |
buf.pData_[8] = '\0' ;
|
|
Packit |
01d647 |
byte guidBuf[16]; int stream = 0;
|
|
Packit |
01d647 |
io_->read(guidBuf, 16);
|
|
Packit |
01d647 |
char streamType[37] = "";
|
|
Packit |
01d647 |
Exiv2::RiffVideo *test = NULL;
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
getGUID(guidBuf, streamType);
|
|
Packit |
01d647 |
const TagVocabulary* tv;
|
|
Packit |
01d647 |
tv = find( GUIDReferenceTags, streamType);
|
|
Packit |
01d647 |
io_->read(guidBuf, 16);
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
if(compareTag( exvGettext(tv->label_), "Audio_Media"))
|
|
Packit |
01d647 |
stream = 1;
|
|
Packit |
01d647 |
else if(compareTag( exvGettext(tv->label_), "Video_Media"))
|
|
Packit |
01d647 |
stream = 2;
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
io_->read(buf.pData_, 8);
|
|
Packit |
01d647 |
if(stream == 2)
|
|
Packit |
01d647 |
xmpData_["Xmp.video.TimeOffset"] = getUint64_t(buf);
|
|
Packit |
01d647 |
else if(stream == 1)
|
|
Packit |
01d647 |
xmpData_["Xmp.audio.TimeOffset"] = getUint64_t(buf);
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
io_->read(buf.pData_, 8);
|
|
Packit |
01d647 |
std::memset(buf.pData_, 0x0, buf.size_);
|
|
Packit |
01d647 |
io_->read(buf.pData_, 1);
|
|
Packit |
01d647 |
streamNumber_ = (int)buf.pData_[0] & 127;
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
io_->read(buf.pData_, 5);
|
|
Packit |
01d647 |
std::memset(buf.pData_, 0x0, buf.size_);
|
|
Packit |
01d647 |
io_->read(buf.pData_, 2);
|
|
Packit |
01d647 |
long temp = Exiv2::getUShort(buf.pData_, littleEndian);
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
if(stream == 2) {
|
|
Packit |
01d647 |
xmpData_["Xmp.video.Width"] = temp;
|
|
Packit |
01d647 |
width_ = temp;
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
else if(stream == 1) {
|
|
Packit |
01d647 |
xmpData_["Xmp.audio.Codec"] = test->printAudioEncoding(temp);
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
io_->read(buf.pData_, 2);
|
|
Packit |
01d647 |
temp = Exiv2::getUShort(buf.pData_, littleEndian);
|
|
Packit |
01d647 |
if(stream == 1)
|
|
Packit |
01d647 |
xmpData_["Xmp.audio.ChannelType"] = temp;
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
io_->read(buf.pData_, 4);
|
|
Packit |
01d647 |
temp = Exiv2::getULong(buf.pData_, littleEndian);
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
if(stream == 2) {
|
|
Packit |
01d647 |
xmpData_["Xmp.video.Height"] = temp;
|
|
Packit |
01d647 |
height_ = temp;
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
else if(stream == 1) {
|
|
Packit |
01d647 |
xmpData_["Xmp.audio.SampleRate"] = temp;
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
} // AsfVideo::streamProperties
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
void AsfVideo::codecList()
|
|
Packit |
01d647 |
{
|
|
Packit |
01d647 |
DataBuf buf(200);
|
|
Packit |
01d647 |
io_->read(buf.pData_, 16);
|
|
Packit |
01d647 |
std::memset(buf.pData_, 0x0, buf.size_);
|
|
Packit |
01d647 |
io_->read(buf.pData_, 4);
|
|
Packit |
01d647 |
int codecCount = Exiv2::getULong(buf.pData_, littleEndian), descLength = 0, codecType = 0;
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
while(codecCount--) {
|
|
Packit |
01d647 |
std::memset(buf.pData_, 0x0, buf.size_);
|
|
Packit |
01d647 |
io_->read(buf.pData_, 2);
|
|
Packit |
01d647 |
codecType = Exiv2::getUShort(buf.pData_, littleEndian);
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
io_->read(buf.pData_, 2);
|
|
Packit |
01d647 |
descLength = Exiv2::getUShort(buf.pData_, littleEndian) * 2;
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
if (descLength < 0) {
|
|
Packit |
01d647 |
#ifndef SUPPRESS_WARNINGS
|
|
Packit |
01d647 |
EXV_ERROR << " Description found in this ASF file is not of valid size ."
|
|
Packit |
01d647 |
<< " Entries considered invalid. Not Processed.\n";
|
|
Packit |
01d647 |
#endif
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
else {
|
|
Packit |
01d647 |
io_->read(buf.pData_, descLength);
|
|
Packit |
01d647 |
if(codecType == 1)
|
|
Packit |
01d647 |
xmpData_["Xmp.video.Codec"] = toString16(buf);
|
|
Packit |
01d647 |
else if(codecType == 2)
|
|
Packit |
01d647 |
xmpData_["Xmp.audio.Compressor"] = toString16(buf);
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
std::memset(buf.pData_, 0x0, buf.size_);
|
|
Packit |
01d647 |
io_->read(buf.pData_, 2);
|
|
Packit |
01d647 |
descLength = Exiv2::getUShort(buf.pData_, littleEndian) * 2;
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
if (descLength < 0) {
|
|
Packit |
01d647 |
#ifndef SUPPRESS_WARNINGS
|
|
Packit |
01d647 |
EXV_ERROR << " Description found in this ASF file is not of valid size ."
|
|
Packit |
01d647 |
<< " Entries considered invalid. Not Processed.\n";
|
|
Packit |
01d647 |
#endif
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
else {
|
|
Packit |
01d647 |
io_->read(buf.pData_, descLength);
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
if(codecType == 1)
|
|
Packit |
01d647 |
xmpData_["Xmp.video.CodecDescription"] = toString16(buf);
|
|
Packit |
01d647 |
else if(codecType == 2)
|
|
Packit |
01d647 |
xmpData_["Xmp.audio.CodecDescription"] = toString16(buf);
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
std::memset(buf.pData_, 0x0, buf.size_);
|
|
Packit |
01d647 |
io_->read(buf.pData_, 2);
|
|
Packit |
01d647 |
descLength = Exiv2::getUShort(buf.pData_, littleEndian);
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
if (descLength < 0) {
|
|
Packit |
01d647 |
#ifndef SUPPRESS_WARNINGS
|
|
Packit |
01d647 |
EXV_ERROR << " Description found in this ASF file is not of valid size ."
|
|
Packit |
01d647 |
<< " Entries considered invalid. Not Processed.\n";
|
|
Packit |
01d647 |
#endif
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
else {
|
|
Packit |
01d647 |
io_->read(buf.pData_, descLength);
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
} // AsfVideo::codecList
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
void AsfVideo::headerExtension(uint64_t size)
|
|
Packit |
01d647 |
{
|
|
Packit |
01d647 |
uint64_t cur_pos = io_->tell();
|
|
Packit |
01d647 |
DataBuf buf(20);
|
|
Packit |
01d647 |
io_->read(buf.pData_, 18);
|
|
Packit |
01d647 |
buf.pData_[4] = '\0' ;
|
|
Packit |
01d647 |
io_->read(buf.pData_, 4);
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
while(localPosition_ < cur_pos + size) decodeBlock();
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
io_->seek(cur_pos + size, BasicIo::beg);
|
|
Packit |
01d647 |
} // AsfVideo::headerExtension
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
void AsfVideo::metadataHandler(int meta)
|
|
Packit |
01d647 |
{
|
|
Packit |
01d647 |
DataBuf buf(5000);
|
|
Packit |
01d647 |
io_->read(buf.pData_, 2);
|
|
Packit |
01d647 |
int recordCount = Exiv2::getUShort(buf.pData_, littleEndian), nameLength = 0, dataLength = 0, dataType = 0;
|
|
Packit |
01d647 |
Exiv2::Value::AutoPtr v = Exiv2::Value::create(Exiv2::xmpSeq);
|
|
Packit |
01d647 |
byte guidBuf[16]; char fileID[37] = "";
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
while(recordCount--) {
|
|
Packit |
01d647 |
std::memset(buf.pData_, 0x0, buf.size_);
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
if(meta == 1 || meta == 3) {
|
|
Packit |
01d647 |
io_->read(buf.pData_, 4);
|
|
Packit |
01d647 |
io_->read(buf.pData_, 2);
|
|
Packit |
01d647 |
nameLength = Exiv2::getUShort(buf.pData_, littleEndian);
|
|
Packit |
01d647 |
io_->read(buf.pData_, 2);
|
|
Packit |
01d647 |
dataType = Exiv2::getUShort(buf.pData_, littleEndian);
|
|
Packit |
01d647 |
io_->read(buf.pData_, 4);
|
|
Packit |
01d647 |
dataLength = Exiv2::getULong(buf.pData_, littleEndian);
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
if (nameLength > 5000) {
|
|
Packit |
01d647 |
#ifndef SUPPRESS_WARNINGS
|
|
Packit |
01d647 |
EXV_ERROR << "Xmp.video.Metadata nameLength was found to be larger than 5000 "
|
|
Packit |
01d647 |
<< " entries considered invalid; not read.\n";
|
|
Packit |
01d647 |
#endif
|
|
Packit |
01d647 |
io_->seek(io_->tell() + nameLength, BasicIo::beg);
|
|
Packit |
01d647 |
} else {
|
|
Packit |
01d647 |
io_->read(buf.pData_, nameLength);
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
v->read(toString16(buf));
|
|
Packit |
01d647 |
if(dataType == 6) {
|
|
Packit |
01d647 |
io_->read(guidBuf, 16);
|
|
Packit |
01d647 |
getGUID(guidBuf, fileID);
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
else
|
|
Packit |
01d647 |
// Sanity check with an "unreasonably" large number
|
|
Packit |
01d647 |
if (dataLength > 5000) {
|
|
Packit |
01d647 |
#ifndef SUPPRESS_WARNINGS
|
|
Packit |
01d647 |
EXV_ERROR << "Xmp.video.Metadata dataLength was found to be larger than 5000 "
|
|
Packit |
01d647 |
<< " entries considered invalid; not read.\n";
|
|
Packit |
01d647 |
#endif
|
|
Packit |
01d647 |
io_->seek(io_->tell() + dataLength, BasicIo::beg);
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
else
|
|
Packit |
01d647 |
io_->read(buf.pData_, dataLength);
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
else if(meta == 2) {
|
|
Packit |
01d647 |
io_->read(buf.pData_, 2);
|
|
Packit |
01d647 |
nameLength = Exiv2::getUShort(buf.pData_, littleEndian);
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
if (nameLength > 5000) {
|
|
Packit |
01d647 |
#ifndef SUPPRESS_WARNINGS
|
|
Packit |
01d647 |
EXV_ERROR << "Xmp.video.Metadata nameLength was found to be larger than 5000 "
|
|
Packit |
01d647 |
<< " entries considered invalid; not read.\n";
|
|
Packit |
01d647 |
#endif
|
|
Packit |
01d647 |
io_->seek(io_->tell() + nameLength, BasicIo::beg);
|
|
Packit |
01d647 |
} else {
|
|
Packit |
01d647 |
io_->read(buf.pData_, nameLength);
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
v->read(toString16(buf));
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
io_->read(buf.pData_, 2);
|
|
Packit |
01d647 |
dataType = Exiv2::getUShort(buf.pData_, littleEndian);
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
io_->read(buf.pData_, 2);
|
|
Packit |
01d647 |
dataLength = Exiv2::getUShort(buf.pData_, littleEndian);
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
// Sanity check with an "unreasonably" large number
|
|
Packit |
01d647 |
if (dataLength > 5000) {
|
|
Packit |
01d647 |
#ifndef SUPPRESS_WARNINGS
|
|
Packit |
01d647 |
EXV_ERROR << "Xmp.video.Metadata dataLength was found to be larger than 5000 "
|
|
Packit |
01d647 |
<< " entries considered invalid; not read.\n";
|
|
Packit |
01d647 |
#endif
|
|
Packit |
01d647 |
io_->seek(io_->tell() + dataLength, BasicIo::beg);
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
else
|
|
Packit |
01d647 |
io_->read(buf.pData_, dataLength);
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
if(dataType == 0) { // Unicode String
|
|
Packit |
01d647 |
v->read(toString16(buf));
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
else if(dataType == 2 || dataType == 5) { // 16-bit Unsigned Integer
|
|
Packit |
01d647 |
v->read( Exiv2::toString( Exiv2::getUShort(buf.pData_, littleEndian)));
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
else if(dataType == 3) { // 32-bit Unsigned Integer
|
|
Packit |
01d647 |
v->read( Exiv2::toString( Exiv2::getULong( buf.pData_, littleEndian)));
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
else if(dataType == 4) { // 64-bit Unsigned Integer
|
|
Packit |
01d647 |
v->read(Exiv2::toString(getUint64_t(buf)));
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
else if(dataType == 6) { // 128-bit GUID
|
|
Packit |
01d647 |
v->read(Exiv2::toString(fileID));
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
else { // Byte array
|
|
Packit |
01d647 |
v->read( Exiv2::toString(buf.pData_));
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
if(meta == 1) {
|
|
Packit |
01d647 |
xmpData_.add(Exiv2::XmpKey("Xmp.video.Metadata"), v.get());
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
else if(meta == 2) {
|
|
Packit |
01d647 |
xmpData_.add(Exiv2::XmpKey("Xmp.video.ExtendedContentDescription"), v.get());
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
else {
|
|
Packit |
01d647 |
xmpData_.add(Exiv2::XmpKey("Xmp.video.MetadataLibrary"), v.get());
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
} // AsfVideo::metadataHandler
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
void AsfVideo::fileProperties()
|
|
Packit |
01d647 |
{
|
|
Packit |
01d647 |
DataBuf buf(9);
|
|
Packit |
01d647 |
buf.pData_[8] = '\0' ;
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
byte guidBuf[16];
|
|
Packit |
01d647 |
io_->read(guidBuf, 16);
|
|
Packit |
01d647 |
char fileID[37] = ""; int count = 7;
|
|
Packit |
01d647 |
getGUID(guidBuf, fileID);
|
|
Packit |
01d647 |
xmpData_["Xmp.video.FileID"] = fileID;
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
const TagDetails* td;
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
while(count--) {
|
|
Packit |
01d647 |
td = find(filePropertiesTags , (count + 1));
|
|
Packit |
01d647 |
io_->read(buf.pData_, 8);
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
if(count == 0) {
|
|
Packit |
01d647 |
buf.pData_[4] = '\0' ;
|
|
Packit |
01d647 |
io_->read(buf.pData_, 4); io_->read(buf.pData_, 4);
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
if(count == 3 || count == 2) {
|
|
Packit |
01d647 |
xmpData_[exvGettext(td->label_)] = getUint64_t(buf) / 10000;
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
else {
|
|
Packit |
01d647 |
xmpData_[exvGettext(td->label_)] = getUint64_t(buf);
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
} // AsfVideo::fileProperties
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
void AsfVideo::aspectRatio()
|
|
Packit |
01d647 |
{
|
|
Packit |
01d647 |
//TODO - Make a better unified method to handle all cases of Aspect Ratio
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
double aspectRatio = (double)width_ / (double)height_;
|
|
Packit |
01d647 |
aspectRatio = floor(aspectRatio*10) / 10;
|
|
Packit |
01d647 |
xmpData_["Xmp.video.AspectRatio"] = aspectRatio;
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
int aR = (int) ((aspectRatio*10.0)+0.1);
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
switch (aR) {
|
|
Packit |
01d647 |
case 13 : xmpData_["Xmp.video.AspectRatio"] = "4:3" ; break;
|
|
Packit |
01d647 |
case 17 : xmpData_["Xmp.video.AspectRatio"] = "16:9" ; break;
|
|
Packit |
01d647 |
case 10 : xmpData_["Xmp.video.AspectRatio"] = "1:1" ; break;
|
|
Packit |
01d647 |
case 16 : xmpData_["Xmp.video.AspectRatio"] = "16:10" ; break;
|
|
Packit |
01d647 |
case 22 : xmpData_["Xmp.video.AspectRatio"] = "2.21:1" ; break;
|
|
Packit |
01d647 |
case 23 : xmpData_["Xmp.video.AspectRatio"] = "2.35:1" ; break;
|
|
Packit |
01d647 |
case 12 : xmpData_["Xmp.video.AspectRatio"] = "5:4" ; break;
|
|
Packit |
01d647 |
default : xmpData_["Xmp.video.AspectRatio"] = aspectRatio;break;
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
} // AsfVideo::aspectRatio
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
Image::AutoPtr newAsfInstance(BasicIo::AutoPtr io, bool /*create*/)
|
|
Packit |
01d647 |
{
|
|
Packit |
01d647 |
Image::AutoPtr image(new AsfVideo(io));
|
|
Packit |
01d647 |
if (!image->good()) {
|
|
Packit |
01d647 |
image.reset();
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
return image;
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
bool isAsfType(BasicIo& iIo, bool advance)
|
|
Packit |
01d647 |
{
|
|
Packit |
01d647 |
const int32_t len = 16;
|
|
Packit |
01d647 |
byte buf[len];
|
|
Packit |
01d647 |
iIo.read(buf, len);
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
if (iIo.error() || iIo.eof()) {
|
|
Packit |
01d647 |
return false;
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
bool matched = isASFType(buf);
|
|
Packit |
01d647 |
if (!advance || !matched) {
|
|
Packit |
01d647 |
iIo.seek(0, BasicIo::beg);
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
return matched;
|
|
Packit |
01d647 |
}
|
|
Packit |
01d647 |
|
|
Packit |
01d647 |
} // namespace Exiv2
|
|
Packit |
01d647 |
#endif // EXV_ENABLE_VIDEO
|