1 // ***************************************************************** -*- C++ -*- 2 /* 3 * Copyright (C) 2004-2017 Andreas Huggel <ahuggel@gmx.net> 4 * 5 * This program is part of the Exiv2 distribution. 6 * 7 * This program is free software; you can redistribute it and/or 8 * modify it under the terms of the GNU General Public License 9 * as published by the Free Software Foundation; either version 2 10 * of the License, or (at your option) any later version. 11 * 12 * This program is distributed in the hope that it will be useful, 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 * GNU General Public License for more details. 16 * 17 * You should have received a copy of the GNU General Public License 18 * along with this program; if not, write to the Free Software 19 * Foundation, Inc., 51 Franklin Street, 5th Floor, Boston, MA 02110-1301 USA. 20 */ 21 /* 22 File: riffvideo.cpp 23 Version: $Rev: 4736 $ 24 Author(s): Abhinav Badola for GSoC 2012 (AB) <mail.abu.to@gmail.com> 25 History: 18-Jun-12, AB: created 26 Credits: See header file 27 */ 28 // ***************************************************************************** 29 #include "rcsid_int.hpp" 30 EXIV2_RCSID("@(#) $Id: riffvideo.cpp 4736 2017-03-15 21:30:55Z robinwmills $") 31 32 // ***************************************************************************** 33 // included header files 34 #include "config_exiv2.h" 35 36 #ifdef EXV_ENABLE_VIDEO 37 #include "riffvideo.hpp" 38 #include "futils.hpp" 39 #include "basicio.hpp" 40 #include "tags.hpp" 41 #include "tags_int.hpp" 42 #include "types.hpp" 43 #include "tiffimage_int.hpp" 44 #include "image_int.hpp" 45 // + standard includes 46 #include <cmath> 47 48 // ***************************************************************************** 49 // class member definitions 50 namespace Exiv2 { 51 namespace Internal { 52 53 /*! 54 @brief Dummy TIFF header structure. 55 */ 56 class DummyTiffHeader : public TiffHeaderBase { 57 public: 58 //! @name Creators 59 //@{ 60 //! Default constructor 61 DummyTiffHeader(ByteOrder byteOrder); 62 //! Destructor 63 ~DummyTiffHeader(); 64 //@} 65 66 //! @name Manipulators 67 //@{ 68 //! Dummy read function. Does nothing and returns true. 69 bool read(const byte* pData, uint32_t size); 70 //@} 71 72 }; // class TiffHeader 73 DummyTiffHeader(ByteOrder byteOrder)74 DummyTiffHeader::DummyTiffHeader(ByteOrder byteOrder) 75 : TiffHeaderBase(42, 0, byteOrder, 0) 76 { 77 } 78 ~DummyTiffHeader()79 DummyTiffHeader::~DummyTiffHeader() 80 { 81 } 82 read(const byte *,uint32_t)83 bool DummyTiffHeader::read(const byte* /*pData*/, uint32_t /*size*/) 84 { 85 return true; 86 } 87 88 extern const TagVocabulary infoTags[] = { 89 { "AGES", "Xmp.video.Rated" }, 90 { "CMNT", "Xmp.video.Comment" }, 91 { "CODE", "Xmp.video.EncodedBy" }, 92 { "COMM", "Xmp.video.Comment" }, 93 { "DIRC", "Xmp.video.Director" }, 94 { "DISP", "Xmp.audio.SchemeTitle" }, 95 { "DTIM", "Xmp.video.DateTimeOriginal" }, 96 { "GENR", "Xmp.video.Genre" }, 97 { "IARL", "Xmp.video.ArchivalLocation" }, 98 { "IART", "Xmp.video.Artist" }, 99 { "IAS1", "Xmp.video.Edit1" }, 100 { "IAS2", "Xmp.video.Edit2" }, 101 { "IAS3", "Xmp.video.Edit3" }, 102 { "IAS4", "Xmp.video.Edit4" }, 103 { "IAS5", "Xmp.video.Edit5" }, 104 { "IAS6", "Xmp.video.Edit6" }, 105 { "IAS7", "Xmp.video.Edit7" }, 106 { "IAS8", "Xmp.video.Edit8" }, 107 { "IAS9", "Xmp.video.Edit9" }, 108 { "IBSU", "Xmp.video.BaseURL" }, 109 { "ICAS", "Xmp.audio.DefaultStream" }, 110 { "ICDS", "Xmp.video.CostumeDesigner" }, 111 { "ICMS", "Xmp.video.Commissioned" }, 112 { "ICMT", "Xmp.video.Comment" }, 113 { "ICNM", "Xmp.video.Cinematographer" }, 114 { "ICNT", "Xmp.video.Country" }, 115 { "ICOP", "Xmp.video.Copyright" }, 116 { "ICRD", "Xmp.video.DateTimeDigitized" }, 117 { "ICRP", "Xmp.video.Cropped" }, 118 { "IDIM", "Xmp.video.Dimensions" }, 119 { "IDPI", "Xmp.video.DotsPerInch" }, 120 { "IDST", "Xmp.video.DistributedBy" }, 121 { "IEDT", "Xmp.video.EditedBy" }, 122 { "IENC", "Xmp.video.EncodedBy" }, 123 { "IENG", "Xmp.video.Engineer" }, 124 { "IGNR", "Xmp.video.Genre" }, 125 { "IKEY", "Xmp.video.PerformerKeywords" }, 126 { "ILGT", "Xmp.video.Lightness" }, 127 { "ILGU", "Xmp.video.LogoURL" }, 128 { "ILIU", "Xmp.video.LogoIconURL" }, 129 { "ILNG", "Xmp.video.Language" }, 130 { "IMBI", "Xmp.video.InfoBannerImage" }, 131 { "IMBU", "Xmp.video.InfoBannerURL" }, 132 { "IMED", "Xmp.video.Medium" }, 133 { "IMIT", "Xmp.video.InfoText" }, 134 { "IMIU", "Xmp.video.InfoURL" }, 135 { "IMUS", "Xmp.video.MusicBy" }, 136 { "INAM", "Xmp.video.Title" }, 137 { "IPDS", "Xmp.video.ProductionDesigner" }, 138 { "IPLT", "Xmp.video.NumOfColors" }, 139 { "IPRD", "Xmp.video.Product" }, 140 { "IPRO", "Xmp.video.ProducedBy" }, 141 { "IRIP", "Xmp.video.RippedBy" }, 142 { "IRTD", "Xmp.video.Rating" }, 143 { "ISBJ", "Xmp.video.Subject" }, 144 { "ISFT", "Xmp.video.Software" }, 145 { "ISGN", "Xmp.video.SecondaryGenre" }, 146 { "ISHP", "Xmp.video.Sharpness" }, 147 { "ISRC", "Xmp.video.Source" }, 148 { "ISRF", "Xmp.video.SourceForm" }, 149 { "ISTD", "Xmp.video.ProductionStudio" }, 150 { "ISTR", "Xmp.video.Starring" }, 151 { "ITCH", "Xmp.video.Technician" }, 152 { "IWMU", "Xmp.video.WatermarkURL" }, 153 { "IWRI", "Xmp.video.WrittenBy" }, 154 { "LANG", "Xmp.video.Language" }, 155 { "LOCA", "Xmp.video.LocationInfo" }, 156 { "PRT1", "Xmp.video.Part" }, 157 { "PRT2", "Xmp.video.NumOfParts" }, 158 { "RATE", "Xmp.video.Rate" }, 159 { "STAR", "Xmp.video.Starring" }, 160 { "STAT", "Xmp.video.Statistics" }, 161 { "TAPE", "Xmp.video.TapeName" }, 162 { "TCDO", "Xmp.video.EndTimecode" }, 163 { "TCOD", "Xmp.video.StartTimecode" }, 164 { "TITL", "Xmp.video.Title" }, 165 { "TLEN", "Xmp.video.Length" }, 166 { "TORG", "Xmp.video.Organization" }, 167 { "TRCK", "Xmp.video.TrackNumber" }, 168 { "TURL", "Xmp.video.URL" }, 169 { "TVER", "Xmp.video.SoftwareVersion" }, 170 { "VMAJ", "Xmp.video.VegasVersionMajor" }, 171 { "VMIN", "Xmp.video.VegasVersionMinor" }, 172 { "YEAR", "Xmp.video.Year" } 173 }; 174 175 extern const TagDetails audioEncodingValues[] = { 176 { 0x1, "Microsoft PCM" }, 177 { 0x2, "Microsoft ADPCM" }, 178 { 0x3, "Microsoft IEEE float" }, 179 { 0x4, "Compaq VSELP" }, 180 { 0x5, "IBM CVSD" }, 181 { 0x6, "Microsoft a-Law" }, 182 { 0x7, "Microsoft u-Law" }, 183 { 0x8, "Microsoft DTS" }, 184 { 0x9, "DRM" }, 185 { 0xa, "WMA 9 Speech" }, 186 { 0xb, "Microsoft Windows Media RT Voice" }, 187 { 0x10, "OKI-ADPCM" }, 188 { 0x11, "Intel IMA/DVI-ADPCM" }, 189 { 0x12, "Videologic Mediaspace ADPCM" }, 190 { 0x13, "Sierra ADPCM" }, 191 { 0x14, "Antex G.723 ADPCM" }, 192 { 0x15, "DSP Solutions DIGISTD" }, 193 { 0x16, "DSP Solutions DIGIFIX" }, 194 { 0x17, "Dialoic OKI ADPCM" }, 195 { 0x18, "Media Vision ADPCM" }, 196 { 0x19, "HP CU" }, 197 { 0x1a, "HP Dynamic Voice" }, 198 { 0x20, "Yamaha ADPCM" }, 199 { 0x21, "SONARC Speech Compression" }, 200 { 0x22, "DSP Group True Speech" }, 201 { 0x23, "Echo Speech Corp." }, 202 { 0x24, "Virtual Music Audiofile AF36" }, 203 { 0x25, "Audio Processing Tech." }, 204 { 0x26, "Virtual Music Audiofile AF10" }, 205 { 0x27, "Aculab Prosody 1612" }, 206 { 0x28, "Merging Tech. LRC" }, 207 { 0x30, "Dolby AC2" }, 208 { 0x31, "Microsoft GSM610" }, 209 { 0x32, "MSN Audio" }, 210 { 0x33, "Antex ADPCME" }, 211 { 0x34, "Control Resources VQLPC" }, 212 { 0x35, "DSP Solutions DIGIREAL" }, 213 { 0x36, "DSP Solutions DIGIADPCM" }, 214 { 0x37, "Control Resources CR10" }, 215 { 0x38, "Natural MicroSystems VBX ADPCM" }, 216 { 0x39, "Crystal Semiconductor IMA ADPCM" }, 217 { 0x3a, "Echo Speech ECHOSC3" }, 218 { 0x3b, "Rockwell ADPCM" }, 219 { 0x3c, "Rockwell DIGITALK" }, 220 { 0x3d, "Xebec Multimedia" }, 221 { 0x40, "Antex G.721 ADPCM" }, 222 { 0x41, "Antex G.728 CELP" }, 223 { 0x42, "Microsoft MSG723" }, 224 { 0x43, "IBM AVC ADPCM" }, 225 { 0x45, "ITU-T G.726" }, 226 { 0x50, "Microsoft MPEG" }, 227 { 0x51, "RT23 or PAC" }, 228 { 0x52, "InSoft RT24" }, 229 { 0x53, "InSoft PAC" }, 230 { 0x55, "MP3" }, 231 { 0x59, "Cirrus" }, 232 { 0x60, "Cirrus Logic" }, 233 { 0x61, "ESS Tech. PCM" }, 234 { 0x62, "Voxware Inc." }, 235 { 0x63, "Canopus ATRAC" }, 236 { 0x64, "APICOM G.726 ADPCM" }, 237 { 0x65, "APICOM G.722 ADPCM" }, 238 { 0x66, "Microsoft DSAT" }, 239 { 0x67, "Micorsoft DSAT DISPLAY" }, 240 { 0x69, "Voxware Byte Aligned" }, 241 { 0x70, "Voxware AC8" }, 242 { 0x71, "Voxware AC10" }, 243 { 0x72, "Voxware AC16" }, 244 { 0x73, "Voxware AC20" }, 245 { 0x74, "Voxware MetaVoice" }, 246 { 0x75, "Voxware MetaSound" }, 247 { 0x76, "Voxware RT29HW" }, 248 { 0x77, "Voxware VR12" }, 249 { 0x78, "Voxware VR18" }, 250 { 0x79, "Voxware TQ40" }, 251 { 0x7a, "Voxware SC3" }, 252 { 0x7b, "Voxware SC3" }, 253 { 0x80, "Soundsoft" }, 254 { 0x81, "Voxware TQ60" }, 255 { 0x82, "Microsoft MSRT24" }, 256 { 0x83, "AT&T G.729A" }, 257 { 0x84, "Motion Pixels MVI MV12" }, 258 { 0x85, "DataFusion G.726" }, 259 { 0x86, "DataFusion GSM610" }, 260 { 0x88, "Iterated Systems Audio" }, 261 { 0x89, "Onlive" }, 262 { 0x8a, "Multitude, Inc. FT SX20" }, 263 { 0x8b, "Infocom ITS A/S G.721 ADPCM" }, 264 { 0x8c, "Convedia G729" }, 265 { 0x8d, "Not specified congruency, Inc." }, 266 { 0x91, "Siemens SBC24" }, 267 { 0x92, "Sonic Foundry Dolby AC3 APDIF" }, 268 { 0x93, "MediaSonic G.723" }, 269 { 0x94, "Aculab Prosody 8kbps" }, 270 { 0x97, "ZyXEL ADPCM" }, 271 { 0x98, "Philips LPCBB" }, 272 { 0x99, "Studer Professional Audio Packed" }, 273 { 0xa0, "Malden PhonyTalk" }, 274 { 0xa1, "Racal Recorder GSM" }, 275 { 0xa2, "Racal Recorder G720.a" }, 276 { 0xa3, "Racal G723.1" }, 277 { 0xa4, "Racal Tetra ACELP" }, 278 { 0xb0, "NEC AAC NEC Corporation" }, 279 { 0xff, "AAC" }, 280 { 0x100, "Rhetorex ADPCM" }, 281 { 0x101, "IBM u-Law" }, 282 { 0x102, "IBM a-Law" }, 283 { 0x103, "IBM ADPCM" }, 284 { 0x111, "Vivo G.723" }, 285 { 0x112, "Vivo Siren" }, 286 { 0x120, "Philips Speech Processing CELP" }, 287 { 0x121, "Philips Speech Processing GRUNDIG" }, 288 { 0x123, "Digital G.723" }, 289 { 0x125, "Sanyo LD ADPCM" }, 290 { 0x130, "Sipro Lab ACEPLNET" }, 291 { 0x131, "Sipro Lab ACELP4800" }, 292 { 0x132, "Sipro Lab ACELP8V3" }, 293 { 0x133, "Sipro Lab G.729" }, 294 { 0x134, "Sipro Lab G.729A" }, 295 { 0x135, "Sipro Lab Kelvin" }, 296 { 0x136, "VoiceAge AMR" }, 297 { 0x140, "Dictaphone G.726 ADPCM" }, 298 { 0x150, "Qualcomm PureVoice" }, 299 { 0x151, "Qualcomm HalfRate" }, 300 { 0x155, "Ring Zero Systems TUBGSM" }, 301 { 0x160, "Microsoft Audio1" }, 302 { 0x161, "Windows Media Audio V2 V7 V8 V9 / DivX audio (WMA) / Alex AC3 Audio" }, 303 { 0x162, "Windows Media Audio Professional V9" }, 304 { 0x163, "Windows Media Audio Lossless V9" }, 305 { 0x164, "WMA Pro over S/PDIF" }, 306 { 0x170, "UNISYS NAP ADPCM" }, 307 { 0x171, "UNISYS NAP ULAW" }, 308 { 0x172, "UNISYS NAP ALAW" }, 309 { 0x173, "UNISYS NAP 16K" }, 310 { 0x174, "MM SYCOM ACM SYC008 SyCom Technologies" }, 311 { 0x175, "MM SYCOM ACM SYC701 G726L SyCom Technologies" }, 312 { 0x176, "MM SYCOM ACM SYC701 CELP54 SyCom Technologies" }, 313 { 0x177, "MM SYCOM ACM SYC701 CELP68 SyCom Technologies" }, 314 { 0x178, "Knowledge Adventure ADPCM" }, 315 { 0x180, "Fraunhofer IIS MPEG2AAC" }, 316 { 0x190, "Digital Theater Systems DTS DS" }, 317 { 0x200, "Creative Labs ADPCM" }, 318 { 0x202, "Creative Labs FASTSPEECH8" }, 319 { 0x203, "Creative Labs FASTSPEECH10" }, 320 { 0x210, "UHER ADPCM" }, 321 { 0x215, "Ulead DV ACM" }, 322 { 0x216, "Ulead DV ACM" }, 323 { 0x220, "Quarterdeck Corp." }, 324 { 0x230, "I-Link VC" }, 325 { 0x240, "Aureal Semiconductor Raw Sport" }, 326 { 0x241, "ESST AC3" }, 327 { 0x250, "Interactive Products HSX" }, 328 { 0x251, "Interactive Products RPELP" }, 329 { 0x260, "Consistent CS2" }, 330 { 0x270, "Sony SCX" }, 331 { 0x271, "Sony SCY" }, 332 { 0x272, "Sony ATRAC3" }, 333 { 0x273, "Sony SPC" }, 334 { 0x280, "TELUM Telum Inc." }, 335 { 0x281, "TELUMIA Telum Inc." }, 336 { 0x285, "Norcom Voice Systems ADPCM" }, 337 { 0x300, "Fujitsu FM TOWNS SND" }, 338 { 0x301, "Fujitsu (not specified)" }, 339 { 0x302, "Fujitsu (not specified)" }, 340 { 0x303, "Fujitsu (not specified)" }, 341 { 0x304, "Fujitsu (not specified)" }, 342 { 0x305, "Fujitsu (not specified)" }, 343 { 0x306, "Fujitsu (not specified)" }, 344 { 0x307, "Fujitsu (not specified)" }, 345 { 0x308, "Fujitsu (not specified)" }, 346 { 0x350, "Micronas Semiconductors, Inc. Development" }, 347 { 0x351, "Micronas Semiconductors, Inc. CELP833" }, 348 { 0x400, "Brooktree Digital" }, 349 { 0x401, "Intel Music Coder (IMC)" }, 350 { 0x402, "Ligos Indeo Audio" }, 351 { 0x450, "QDesign Music" }, 352 { 0x500, "On2 VP7 On2 Technologies" }, 353 { 0x501, "On2 VP6 On2 Technologies" }, 354 { 0x680, "AT&T VME VMPCM" }, 355 { 0x681, "AT&T TCP" }, 356 { 0x700, "YMPEG Alpha (dummy for MPEG-2 compressor)" }, 357 { 0x8ae, "ClearJump LiteWave (lossless)" }, 358 { 0x1000, "Olivetti GSM" }, 359 { 0x1001, "Olivetti ADPCM" }, 360 { 0x1002, "Olivetti CELP" }, 361 { 0x1003, "Olivetti SBC" }, 362 { 0x1004, "Olivetti OPR" }, 363 { 0x1100, "Lernout & Hauspie" }, 364 { 0x1101, "Lernout & Hauspie CELP codec" }, 365 { 0x1102, "Lernout & Hauspie SBC codec" }, 366 { 0x1103, "Lernout & Hauspie SBC codec" }, 367 { 0x1104, "Lernout & Hauspie SBC codec" }, 368 { 0x1400, "Norris Comm. Inc." }, 369 { 0x1401, "ISIAudio" }, 370 { 0x1500, "AT&T Soundspace Music Compression" }, 371 { 0x181c, "VoxWare RT24 speech codec" }, 372 { 0x181e, "Lucent elemedia AX24000P Music codec" }, 373 { 0x1971, "Sonic Foundry LOSSLESS" }, 374 { 0x1979, "Innings Telecom Inc. ADPCM" }, 375 { 0x1c07, "Lucent SX8300P speech codec" }, 376 { 0x1c0c, "Lucent SX5363S G.723 compliant codec" }, 377 { 0x1f03, "CUseeMe DigiTalk (ex-Rocwell)" }, 378 { 0x1fc4, "NCT Soft ALF2CD ACM" }, 379 { 0x2000, "FAST Multimedia DVM" }, 380 { 0x2001, "Dolby DTS (Digital Theater System)" }, 381 { 0x2002, "RealAudio 1 / 2 14.4" }, 382 { 0x2003, "RealAudio 1 / 2 28.8" }, 383 { 0x2004, "RealAudio G2 / 8 Cook (low bitrate)" }, 384 { 0x2005, "RealAudio 3 / 4 / 5 Music (DNET)" }, 385 { 0x2006, "RealAudio 10 AAC (RAAC)" }, 386 { 0x2007, "RealAudio 10 AAC+ (RACP)" }, 387 { 0x2500, "Reserved range to 0x2600 Microsoft" }, 388 { 0x3313, "makeAVIS (ffvfw fake AVI sound from AviSynth scripts)" }, 389 { 0x4143, "Divio MPEG-4 AAC audio" }, 390 { 0x4201, "Nokia adaptive multirate" }, 391 { 0x4243, "Divio G726 Divio, Inc." }, 392 { 0x434c, "LEAD Speech" }, 393 { 0x564c, "LEAD Vorbis" }, 394 { 0x5756, "WavPack Audio" }, 395 { 0x674f, "Ogg Vorbis (mode 1)" }, 396 { 0x6750, "Ogg Vorbis (mode 2)" }, 397 { 0x6751, "Ogg Vorbis (mode 3)" }, 398 { 0x676f, "Ogg Vorbis (mode 1+)" }, 399 { 0x6770, "Ogg Vorbis (mode 2+)" }, 400 { 0x6771, "Ogg Vorbis (mode 3+)" }, 401 { 0x7000, "3COM NBX 3Com Corporation" }, 402 { 0x706d, "FAAD AAC" }, 403 { 0x7a21, "GSM-AMR (CBR, no SID)" }, 404 { 0x7a22, "GSM-AMR (VBR, including SID)" }, 405 { 0xa100, "Comverse Infosys Ltd. G723 1" }, 406 { 0xa101, "Comverse Infosys Ltd. AVQSBC" }, 407 { 0xa102, "Comverse Infosys Ltd. OLDSBC" }, 408 { 0xa103, "Symbol Technologies G729A" }, 409 { 0xa104, "VoiceAge AMR WB VoiceAge Corporation" }, 410 { 0xa105, "Ingenient Technologies Inc. G726" }, 411 { 0xa106, "ISO/MPEG-4 advanced audio Coding" }, 412 { 0xa107, "Encore Software Ltd G726" }, 413 { 0xa109, "Speex ACM Codec xiph.org" }, 414 { 0xdfac, "DebugMode SonicFoundry Vegas FrameServer ACM Codec" }, 415 { 0xe708, "Unknown -" }, 416 { 0xf1ac, "Free Lossless Audio Codec FLAC" }, 417 { 0xfffe, "Extensible" }, 418 { 0xffff, "Development" } 419 }; 420 421 extern const TagDetails nikonAVITags[] = { 422 { 0x0003, "Xmp.video.Make" }, 423 { 0x0004, "Xmp.video.Model" }, 424 { 0x0005, "Xmp.video.Software" }, 425 { 0x0006, "Xmp.video.Equipment" }, 426 { 0x0007, "Xmp.video.Orientation" }, 427 { 0x0008, "Xmp.video.ExposureTime" }, 428 { 0x0009, "Xmp.video.FNumber" }, 429 { 0x000a, "Xmp.video.ExposureCompensation" }, 430 { 0x000b, "Xmp.video.MaxApertureValue" }, 431 { 0x000c, "Xmp.video.MeteringMode" }, 432 { 0x000f, "Xmp.video.FocalLength" }, 433 { 0x0010, "Xmp.video.XResolution" }, 434 { 0x0011, "Xmp.video.YResolution" }, 435 { 0x0012, "Xmp.video.ResolutionUnit" }, 436 { 0x0013, "Xmp.video.DateTimeOriginal" }, 437 { 0x0014, "Xmp.video.DateTimeDigitized" }, 438 { 0x0016, "Xmp.video.duration" }, 439 { 0x0018, "Xmp.video.FocusMode" }, 440 { 0x001b, "Xmp.video.DigitalZoomRatio" }, 441 { 0x001d, "Xmp.video.ColorMode" }, 442 { 0x001e, "Xmp.video.Sharpness" }, 443 { 0x001f, "Xmp.video.WhiteBalance" }, 444 { 0x0020, "Xmp.video.ColorNoiseReduction" } 445 }; 446 447 /* 448 extern const TagDetails orientation[] = { 449 { 1, "Horizontal (normal)" }, 450 { 2, "Mirror horizontal" }, 451 { 3, "Rotate 180" }, 452 { 4, "Mirror vertical" }, 453 { 5, "Mirror horizontal and rotate 270 CW" }, 454 { 6, "Rotate 90 CW" }, 455 { 7, "Mirror horizontal and rotate 90 CW" }, 456 { 8, "Rotate 270 CW" } 457 }; 458 */ 459 extern const TagDetails meteringMode[] = { 460 { 0, "Unknown" }, 461 { 1, "Average" }, 462 { 2, "Center-weighted average" }, 463 { 3, "Spot" }, 464 { 4, "Multi-spot" }, 465 { 5, "Multi-segment" }, 466 { 6, "Partial" }, 467 { 255, "Other" } 468 }; 469 470 extern const TagDetails resolutionUnit[] = { 471 { 1, "None" }, 472 { 2, "inches" }, 473 { 3, "cm" } 474 }; 475 476 /*! 477 @brief Function used to check equality of a Tags with a 478 particular string (ignores case while comparing). 479 @param buf Data buffer that will contain Tag to compare 480 @param str char* Pointer to string 481 @return Returns true if the buffer value is equal to string. 482 */ equalsRiffTag(Exiv2::DataBuf & buf,const char * str)483 bool equalsRiffTag(Exiv2::DataBuf& buf ,const char* str) { 484 for(int i = 0; i < 4; i++ ) 485 if(toupper(buf.pData_[i]) != str[i]) 486 return false; 487 return true; 488 } 489 490 enum streamTypeInfo { 491 Audio = 1, MIDI, Text, Video 492 }; 493 enum streamHeaderTags { 494 codec = 1, sampleRate = 5, sampleCount = 8, quality = 10, sampleSize 495 }; 496 enum bmptags { 497 imageWidth, imageHeight, planes, bitDepth, compression, imageLength, pixelsPerMeterX, pixelsPerMeterY, numColors, numImportantColors 498 }; 499 enum audioFormatTags { 500 encoding, numberOfChannels, audioSampleRate, avgBytesPerSec = 4, bitsPerSample = 7 501 }; 502 enum aviHeaderTags { 503 frameRate, maxDataRate, frameCount = 4, streamCount = 6, imageWidth_h = 8, imageHeight_h 504 }; 505 }} // namespace Internal, Exiv2 506 507 namespace Exiv2 { 508 using namespace Exiv2::Internal; 509 RiffVideo(BasicIo::AutoPtr io)510 RiffVideo::RiffVideo(BasicIo::AutoPtr io) 511 : Image(ImageType::riff, mdNone, io) 512 { 513 } // RiffVideo::RiffVideo 514 mimeType() const515 std::string RiffVideo::mimeType() const 516 { 517 return "video/riff"; 518 } 519 520 const int RiffVideo::RIFF_TAG_SIZE = 0x4; 521 const char* RiffVideo::RIFF_CHUNK_HEADER_ICCP = "ICCP"; 522 const char* RiffVideo::RIFF_CHUNK_HEADER_EXIF = "EXIF"; 523 const char* RiffVideo::RIFF_CHUNK_HEADER_XMP = "XMP "; 524 525 /*! 526 @brief Function used to check equality of a Tags with a 527 particular string (ignores case while comparing). 528 @param buf Data buffer that will contain Tag to compare 529 @param str char* Pointer to string 530 @return Returns true if the buffer value is equal to string. 531 */ equalsRiffTag(Exiv2::DataBuf & buf,const char * str)532 bool RiffVideo::equalsRiffTag(Exiv2::DataBuf& buf, const char* str) { 533 for(int i = 0; i < 4; i++ ) 534 if(toupper(buf.pData_[i]) != str[i]) 535 return false; 536 return true; 537 } 538 printStructure(std::ostream & out,PrintStructureOption option,int depth)539 void RiffVideo::printStructure(std::ostream& out, PrintStructureOption option, int depth) { 540 if (io_->open() != 0) { 541 throw Error(9, io_->path(), strError()); 542 } 543 // Ensure this is the correct image type 544 if (!isRiffType(*io_, true)) { 545 if (io_->error() || io_->eof()) throw Error(14); 546 throw Error(3, "RIFF"); 547 } 548 549 bool bPrint = option==kpsBasic || option==kpsRecursive; 550 if ( bPrint || option == kpsXMP || option == kpsIccProfile || option == kpsIptcErase ) { 551 byte data [RIFF_TAG_SIZE * 2]; 552 io_->read(data, RIFF_TAG_SIZE * 2); 553 uint64_t filesize = Exiv2::getULong(data + RIFF_TAG_SIZE, littleEndian); 554 DataBuf chunkId(5) ; 555 chunkId.pData_[4] = '\0' ; 556 557 if ( bPrint ) { 558 out << Internal::indent(depth) 559 << "STRUCTURE OF RIFF FILE: " 560 << io().path() 561 << std::endl; 562 out << Internal::indent(depth) 563 << Internal::stringFormat(" Chunk | Length | Offset | Payload") 564 << std::endl; 565 } 566 567 io_->seek(0,BasicIo::beg); // rewind 568 while ( !io_->eof() && (uint64_t) io_->tell() < filesize) { 569 uint64_t offset = (uint64_t) io_->tell(); 570 byte size_buff[RIFF_TAG_SIZE]; 571 io_->read(chunkId.pData_, RIFF_TAG_SIZE); 572 io_->read(size_buff, RIFF_TAG_SIZE); 573 long size = Exiv2::getULong(size_buff, littleEndian); 574 DataBuf payload(offset?size:RIFF_TAG_SIZE); // header is different from chunks 575 io_->read(payload.pData_, payload.size_); 576 577 if ( bPrint ) { 578 out << Internal::indent(depth) 579 << Internal::stringFormat(" %s | %12u | %12u | ", (const char*)chunkId.pData_,size,(uint32_t)offset) 580 << Internal::binaryToString(payload,payload.size_>32?32:payload.size_) 581 << std::endl; 582 } 583 584 if ( equalsRiffTag(chunkId, RIFF_CHUNK_HEADER_EXIF) && option==kpsRecursive ) { 585 // create memio object with the payload, then print the structure 586 BasicIo::AutoPtr p = BasicIo::AutoPtr(new MemIo(payload.pData_,payload.size_)); 587 printTiffStructure(*p,out,option,depth); 588 } 589 590 bool bPrintPayload = (equalsRiffTag(chunkId, RIFF_CHUNK_HEADER_XMP) && option==kpsXMP) 591 || (equalsRiffTag(chunkId, RIFF_CHUNK_HEADER_ICCP) && option==kpsIccProfile) 592 ; 593 if ( bPrintPayload ) { 594 out.write((const char*) payload.pData_,payload.size_); 595 } 596 597 if ( offset && io_->tell() % 2 ) io_->seek(+1, BasicIo::cur); // skip padding byte on sub-chunks 598 } 599 } 600 } // RiffVideo::printStructure 601 writeMetadata()602 void RiffVideo::writeMetadata() 603 { 604 } // RiffVideo::writeMetadata 605 readMetadata()606 void RiffVideo::readMetadata() 607 { 608 if (io_->open() != 0) throw Error(9, io_->path(), strError()); 609 610 // Ensure that this is the correct image type 611 if (!isRiffType(*io_, false)) { 612 if (io_->error() || io_->eof()) throw Error(14); 613 throw Error(3, "RIFF"); 614 } 615 616 IoCloser closer(*io_); 617 clearMetadata(); 618 continueTraversing_ = true; 619 620 xmpData_["Xmp.video.FileSize"] = (double)io_->size()/(double)1048576; 621 xmpData_["Xmp.video.FileName"] = io_->path(); 622 xmpData_["Xmp.video.MimeType"] = mimeType(); 623 624 const long bufMinSize = 4; 625 DataBuf buf(bufMinSize+1); 626 buf.pData_[4] = '\0'; 627 628 io_->read(buf.pData_, bufMinSize); 629 xmpData_["Xmp.video.Container"] = buf.pData_; 630 631 io_->read(buf.pData_, bufMinSize); 632 io_->read(buf.pData_, bufMinSize); 633 xmpData_["Xmp.video.FileType"] = buf.pData_; 634 635 while (continueTraversing_) decodeBlock(); 636 } // RiffVideo::readMetadata 637 decodeBlock()638 void RiffVideo::decodeBlock() 639 { 640 const long bufMinSize = 4; 641 DataBuf buf(bufMinSize+1); 642 DataBuf buf2(bufMinSize+1); 643 unsigned long size = 0; 644 buf.pData_[4] = '\0' ; 645 buf2.pData_[4] = '\0' ; 646 647 io_->read(buf2.pData_, 4); 648 649 if(io_->eof() || equalsRiffTag(buf2, "MOVI") || equalsRiffTag(buf2, "DATA")) { 650 continueTraversing_ = false; 651 return; 652 } 653 else if(equalsRiffTag(buf2, "HDRL") || equalsRiffTag(buf2, "STRL")) { 654 decodeBlock(); 655 } 656 else { 657 io_->read(buf.pData_, 4); 658 size = Exiv2::getULong(buf.pData_, littleEndian); 659 660 tagDecoder(buf2, size); 661 } 662 } // RiffVideo::decodeBlock 663 tagDecoder(Exiv2::DataBuf & buf,unsigned long size)664 void RiffVideo::tagDecoder(Exiv2::DataBuf& buf, unsigned long size) 665 { 666 uint64_t cur_pos = io_->tell(); 667 static bool listFlag = false, listEnd = false; 668 669 if(equalsRiffTag(buf, "LIST")) { 670 listFlag = true; 671 listEnd = false; 672 673 while((uint64_t)(io_->tell()) < cur_pos + size) decodeBlock(); 674 675 listEnd = true; 676 io_->seek(cur_pos + size, BasicIo::beg); 677 } 678 else if(equalsRiffTag(buf, "JUNK") && listEnd) { 679 junkHandler(size); 680 } 681 else if(equalsRiffTag(buf, "AVIH")) { 682 listFlag = false; 683 aviHeaderTagsHandler(size); 684 } 685 else if(equalsRiffTag(buf, "STRH")) { 686 listFlag = false; 687 streamHandler(size); 688 } 689 else if(equalsRiffTag(buf,"STRF") || equalsRiffTag(buf, "FMT ")) { 690 listFlag = false; 691 if(equalsRiffTag(buf,"FMT ")) 692 streamType_ = Audio; 693 streamFormatHandler(size); 694 } 695 else if(equalsRiffTag(buf, "STRN")) { 696 listFlag = false; 697 dateTimeOriginal(size, 1); 698 } 699 else if(equalsRiffTag(buf, "STRD")) { 700 listFlag = false; 701 streamDataTagHandler(size); 702 } 703 else if(equalsRiffTag(buf, "IDIT")) { 704 listFlag = false; 705 dateTimeOriginal(size); 706 } 707 else if(equalsRiffTag(buf, "INFO")) { 708 listFlag = false; 709 infoTagsHandler(); 710 } 711 else if(equalsRiffTag(buf, "NCDT")) { 712 listFlag = false; 713 nikonTagsHandler(); 714 } 715 else if(equalsRiffTag(buf, "ODML")) { 716 listFlag = false; 717 odmlTagsHandler(); 718 } 719 else if (listFlag) { 720 // std::cout<<"|unprocessed|"<<buf.pData_; 721 skipListData(); 722 } 723 else { 724 // std::cout<<"|unprocessed|"<<buf.pData_; 725 io_->seek(cur_pos + size, BasicIo::beg); 726 } 727 } // RiffVideo::tagDecoder 728 streamDataTagHandler(long size)729 void RiffVideo::streamDataTagHandler(long size) 730 { 731 const long bufMinSize = 20000; 732 DataBuf buf(bufMinSize); 733 buf.pData_[4] = '\0'; 734 uint64_t cur_pos = io_->tell(); 735 736 io_->read(buf.pData_, 8); 737 738 if(equalsRiffTag(buf, "AVIF")) { 739 740 if (size - 4 < 0) { 741 #ifndef SUPPRESS_WARNINGS 742 EXV_ERROR << " Exif Tags found in this RIFF file are not of valid size ." 743 << " Entries considered invalid. Not Processed.\n"; 744 #endif 745 } 746 else { 747 io_->read(buf.pData_, size - 4); 748 749 IptcData iptcData; 750 XmpData xmpData; 751 DummyTiffHeader tiffHeader(littleEndian); 752 TiffParserWorker::decode(exifData_, 753 iptcData, 754 xmpData, 755 buf.pData_, 756 buf.size_, 757 Tag::root, 758 TiffMapping::findDecoder, 759 &tiffHeader); 760 761 #ifndef SUPPRESS_WARNINGS 762 if (!iptcData.empty()) { 763 EXV_WARNING << "Ignoring IPTC information encoded in the Exif data.\n"; 764 } 765 if (!xmpData.empty()) { 766 EXV_WARNING << "Ignoring XMP information encoded in the Exif data.\n"; 767 } 768 #endif 769 } 770 } 771 // TODO decode CasioData and ZORA Tag 772 io_->seek(cur_pos + size, BasicIo::beg); 773 774 } // RiffVideo::streamDataTagHandler 775 dateTimeOriginal(long size,int i)776 void RiffVideo::dateTimeOriginal(long size, int i) 777 { 778 uint64_t cur_pos = io_->tell(); 779 const long bufMinSize = 100; 780 DataBuf buf(bufMinSize); 781 io_->read(buf.pData_, size); 782 if(!i) 783 xmpData_["Xmp.video.DateUTC"] = buf.pData_; 784 else 785 xmpData_["Xmp.video.StreamName"] = buf.pData_; 786 io_->seek(cur_pos + size, BasicIo::beg); 787 } // RiffVideo::dateTimeOriginal 788 odmlTagsHandler()789 void RiffVideo::odmlTagsHandler() 790 { 791 const long bufMinSize = 100; 792 DataBuf buf(bufMinSize); 793 buf.pData_[4] = '\0'; 794 io_->seek(-12, BasicIo::cur); 795 io_->read(buf.pData_, 4); 796 unsigned long size = Exiv2::getULong(buf.pData_, littleEndian); 797 unsigned long size2 = size; 798 799 uint64_t cur_pos = io_->tell(); 800 io_->read(buf.pData_, 4); size -= 4; 801 802 while(size > 0) { 803 io_->read(buf.pData_, 4); size -= 4; 804 if(equalsRiffTag(buf,"DMLH")) { 805 io_->read(buf.pData_, 4); size -= 4; 806 io_->read(buf.pData_, 4); size -= 4; 807 xmpData_["Xmp.video.TotalFrameCount"] = Exiv2::getULong(buf.pData_, littleEndian); 808 } 809 } 810 io_->seek(cur_pos + size2, BasicIo::beg); 811 } // RiffVideo::odmlTagsHandler 812 skipListData()813 void RiffVideo::skipListData() 814 { 815 const long bufMinSize = 4; 816 DataBuf buf(bufMinSize+1); 817 buf.pData_[4] = '\0'; 818 io_->seek(-12, BasicIo::cur); 819 io_->read(buf.pData_, 4); 820 unsigned long size = Exiv2::getULong(buf.pData_, littleEndian); 821 822 uint64_t cur_pos = io_->tell(); 823 io_->seek(cur_pos + size, BasicIo::beg); 824 } // RiffVideo::skipListData 825 nikonTagsHandler()826 void RiffVideo::nikonTagsHandler() 827 { 828 const long bufMinSize = 100; 829 DataBuf buf(bufMinSize), buf2(4+1); 830 buf.pData_[4] = '\0'; 831 io_->seek(-12, BasicIo::cur); 832 io_->read(buf.pData_, 4); 833 834 long internal_size = 0, tagID = 0, dataSize = 0, tempSize, size = Exiv2::getULong(buf.pData_, littleEndian); 835 tempSize = size; char str[9] = " . . . "; 836 uint64_t internal_pos, cur_pos; internal_pos = cur_pos = io_->tell(); 837 const TagDetails* td; 838 double denominator = 1; 839 io_->read(buf.pData_, 4); tempSize -= 4; 840 841 while((long)tempSize > 0) { 842 std::memset(buf.pData_, 0x0, buf.size_); 843 io_->read(buf.pData_, 4); 844 io_->read(buf2.pData_, 4); 845 int temp = internal_size = Exiv2::getULong(buf2.pData_, littleEndian); 846 internal_pos = io_->tell(); tempSize -= (internal_size + 8); 847 848 if(equalsRiffTag(buf, "NCVR")) { 849 while((long)temp > 3) { 850 std::memset(buf.pData_, 0x0, buf.size_); 851 io_->read(buf.pData_, 2); 852 tagID = Exiv2::getULong(buf.pData_, littleEndian); 853 io_->read(buf.pData_, 2); 854 dataSize = Exiv2::getULong(buf.pData_, littleEndian); 855 temp -= (4 + dataSize); 856 857 if(tagID == 0x0001) { 858 if (dataSize <= 0) { 859 #ifndef SUPPRESS_WARNINGS 860 EXV_ERROR << " Makernotes found in this RIFF file are not of valid size ." 861 << " Entries considered invalid. Not Processed.\n"; 862 #endif 863 } 864 else { 865 io_->read(buf.pData_, dataSize); 866 xmpData_["Xmp.video.MakerNoteType"] = buf.pData_; 867 } 868 } 869 else if (tagID == 0x0002) { 870 while(dataSize) { 871 std::memset(buf.pData_, 0x0, buf.size_); io_->read(buf.pData_, 1); 872 str[(4 - dataSize) * 2] = (char)(Exiv2::getULong(buf.pData_, littleEndian) + 48); 873 --dataSize; 874 } 875 xmpData_["Xmp.video.MakerNoteVersion"] = str; 876 } 877 } 878 } 879 else if(equalsRiffTag(buf, "NCTG")) { 880 while((long)temp > 3) { 881 std::memset(buf.pData_, 0x0, buf.size_); 882 io_->read(buf.pData_, 2); 883 tagID = Exiv2::getULong(buf.pData_, littleEndian); 884 io_->read(buf.pData_, 2); 885 dataSize = Exiv2::getULong(buf.pData_, littleEndian); 886 temp -= (4 + dataSize); 887 td = find(nikonAVITags , tagID); 888 889 if (dataSize <= 0) { 890 #ifndef SUPPRESS_WARNINGS 891 EXV_ERROR << " Makernotes found in this RIFF file are not of valid size ." 892 << " Entries considered invalid. Not Processed.\n"; 893 #endif 894 } 895 else { 896 io_->read(buf.pData_, dataSize); 897 898 switch (tagID) { 899 case 0x0003: case 0x0004: case 0x0005: case 0x0006: 900 case 0x0013: case 0x0014: case 0x0018: case 0x001d: 901 case 0x001e: case 0x001f: case 0x0020: 902 xmpData_[exvGettext(td->label_)] = buf.pData_; break; 903 904 case 0x0007: case 0x0010: case 0x0011: case 0x000c: 905 case 0x0012: 906 xmpData_[exvGettext(td->label_)] = Exiv2::getULong(buf.pData_, littleEndian); break; 907 908 case 0x0008: case 0x0009: case 0x000a: case 0x000b: 909 case 0x000f: case 0x001b: case 0x0016: 910 buf2.pData_[0] = buf.pData_[4]; buf2.pData_[1] = buf.pData_[5]; 911 buf2.pData_[2] = buf.pData_[6]; buf2.pData_[3] = buf.pData_[7]; 912 denominator = (double)Exiv2::getLong(buf2.pData_, littleEndian); 913 if (denominator != 0) 914 xmpData_[exvGettext(td->label_)] = (double)Exiv2::getLong(buf.pData_, littleEndian) / denominator; 915 else 916 xmpData_[exvGettext(td->label_)] = 0; 917 break; 918 919 default: 920 break; 921 } 922 } 923 } 924 } 925 926 else if(equalsRiffTag(buf, "NCTH")) {//TODO Nikon Thumbnail Image 927 } 928 929 else if(equalsRiffTag(buf, "NCVW")) {//TODO Nikon Preview Image 930 } 931 932 io_->seek(internal_pos + internal_size, BasicIo::beg); 933 } 934 935 if (size ==0) { 936 io_->seek(cur_pos + 4, BasicIo::beg); 937 } 938 else { 939 io_->seek(cur_pos + size, BasicIo::beg); 940 } 941 } // RiffVideo::nikonTagsHandler 942 infoTagsHandler()943 void RiffVideo::infoTagsHandler() 944 { 945 const long bufMinSize = 10000; 946 DataBuf buf(bufMinSize); 947 buf.pData_[4] = '\0'; 948 io_->seek(-12, BasicIo::cur); 949 io_->read(buf.pData_, 4); 950 long infoSize, size = Exiv2::getULong(buf.pData_, littleEndian); 951 long size_external = size; 952 const TagVocabulary* tv; 953 954 uint64_t cur_pos = io_->tell(); 955 io_->read(buf.pData_, 4); size -= 4; 956 957 while(size > 3) { 958 io_->read(buf.pData_, 4); size -= 4; 959 if(!Exiv2::getULong(buf.pData_, littleEndian)) 960 break; 961 tv = find(infoTags , Exiv2::toString( buf.pData_)); 962 io_->read(buf.pData_, 4); size -= 4; 963 infoSize = Exiv2::getULong(buf.pData_, littleEndian); 964 965 if(infoSize >= 0) { 966 size -= infoSize; 967 io_->read(buf.pData_, infoSize); 968 if(infoSize < 4) 969 buf.pData_[infoSize] = '\0'; 970 } 971 972 if(tv) 973 xmpData_[exvGettext(tv->label_)] = buf.pData_; 974 else 975 continue; 976 } 977 io_->seek(cur_pos + size_external, BasicIo::beg); 978 } // RiffVideo::infoTagsHandler 979 junkHandler(long size)980 void RiffVideo::junkHandler(long size) 981 { 982 const long bufMinSize = size; 983 984 if (size < 0) { 985 #ifndef SUPPRESS_WARNINGS 986 EXV_ERROR << " Junk Data found in this RIFF file are not of valid size ." 987 << " Entries considered invalid. Not Processed.\n"; 988 #endif 989 io_->seek(io_->tell() + 4, BasicIo::beg); 990 } 991 992 else { 993 DataBuf buf(bufMinSize+1), buf2(4+1); 994 std::memset(buf.pData_, 0x0, buf.size_); 995 buf2.pData_[4] = '\0'; 996 uint64_t cur_pos = io_->tell(); 997 998 io_->read(buf.pData_, 4); 999 //! Pentax Metadata and Tags 1000 if(equalsRiffTag(buf, "PENT")) { 1001 1002 io_->seek(cur_pos + 18, BasicIo::beg); 1003 io_->read(buf.pData_, 26); 1004 xmpData_["Xmp.video.Make"] = buf.pData_; 1005 1006 io_->read(buf.pData_, 50); 1007 xmpData_["Xmp.video.Model"] = buf.pData_; 1008 1009 std::memset(buf.pData_, 0x0, buf.size_); 1010 io_->read(buf.pData_, 8); 1011 buf2.pData_[0] = buf.pData_[4]; buf2.pData_[1] = buf.pData_[5]; 1012 buf2.pData_[2] = buf.pData_[6]; buf2.pData_[3] = buf.pData_[7]; 1013 xmpData_["Xmp.video.FNumber"] = (double)Exiv2::getLong(buf.pData_, littleEndian) / (double)Exiv2::getLong(buf2.pData_, littleEndian);; 1014 1015 io_->seek(cur_pos + 131, BasicIo::beg); 1016 io_->read(buf.pData_, 26); 1017 xmpData_["Xmp.video.DateTimeOriginal"] = buf.pData_; 1018 1019 io_->read(buf.pData_, 26); 1020 xmpData_["Xmp.video.DateTimeDigitized"] = buf.pData_; 1021 1022 io_->seek(cur_pos + 299, BasicIo::beg); 1023 std::memset(buf.pData_, 0x0, buf.size_); 1024 1025 io_->read(buf.pData_, 2); 1026 Exiv2::XmpTextValue tv(Exiv2::toString(Exiv2::getLong(buf.pData_, littleEndian))); 1027 xmpData_.add(Exiv2::XmpKey("Xmp.xmp.Thumbnails/xmpGImg:width"), &tv); 1028 1029 io_->read(buf.pData_, 2); 1030 tv.read(Exiv2::toString(Exiv2::getLong(buf.pData_, littleEndian))); 1031 xmpData_.add(Exiv2::XmpKey("Xmp.xmp.Thumbnails/xmpGImg:height"), &tv); 1032 1033 io_->read(buf.pData_, 4); 1034 1035 /* TODO - Storing the image Thumbnail in Base64 Format 1036 1037 1038 uint64_t length = Exiv2::getLong(buf.pData_, littleEndian); 1039 io_->read(buf.pData_, length); 1040 1041 char *rawStr = Exiv2::toString(buf.pData_); 1042 char *encodedStr; 1043 1044 SXMPUtils::EncodeToBase64(rawStr, encodedStr); 1045 1046 tv.read(Exiv2::toString(encodedStr)); 1047 xmpData_.add(Exiv2::XmpKey("Xmp.xmp.Thumbnails/xmpGImg:image"), &tv); 1048 */ 1049 } 1050 else { 1051 io_->seek(cur_pos, BasicIo::beg); 1052 io_->read(buf.pData_, size); 1053 xmpData_["Xmp.video.Junk"] = buf.pData_; 1054 } 1055 1056 io_->seek(cur_pos + size, BasicIo::beg); 1057 } 1058 } // RiffVideo::junkHandler 1059 aviHeaderTagsHandler(long size)1060 void RiffVideo::aviHeaderTagsHandler(long size) 1061 { 1062 const long bufMinSize = 4; 1063 DataBuf buf(bufMinSize+1); 1064 buf.pData_[4] = '\0'; 1065 long width = 0, height = 0, frame_count = 0; 1066 double frame_rate = 1; 1067 1068 uint64_t cur_pos = io_->tell(); 1069 1070 for(int i = 0; i <= 9; i++) { 1071 std::memset(buf.pData_, 0x0, buf.size_); 1072 io_->read(buf.pData_, bufMinSize); 1073 1074 switch(i) { 1075 case frameRate: 1076 xmpData_["Xmp.video.MicroSecPerFrame"] = Exiv2::getULong(buf.pData_, littleEndian); 1077 frame_rate = (double)1000000/(double)Exiv2::getULong(buf.pData_, littleEndian); 1078 break; 1079 case (maxDataRate): 1080 xmpData_["Xmp.video.MaxDataRate"] = (double)Exiv2::getULong(buf.pData_, littleEndian)/(double)1024; 1081 break; 1082 case frameCount: 1083 xmpData_["Xmp.video.FrameCount"] = Exiv2::getULong(buf.pData_, littleEndian); 1084 frame_count = Exiv2::getULong(buf.pData_, littleEndian); 1085 break; 1086 case streamCount: 1087 xmpData_["Xmp.video.StreamCount"] = Exiv2::getULong(buf.pData_, littleEndian); 1088 break; 1089 case imageWidth_h: 1090 width = Exiv2::getULong(buf.pData_, littleEndian); 1091 xmpData_["Xmp.video.Width"] = width; 1092 break; 1093 case imageHeight_h: 1094 height = Exiv2::getULong(buf.pData_, littleEndian); 1095 xmpData_["Xmp.video.Height"] = height; 1096 break; 1097 } 1098 } 1099 1100 fillAspectRatio(width, height); 1101 fillDuration(frame_rate, frame_count); 1102 1103 io_->seek(cur_pos + size, BasicIo::beg); 1104 } // RiffVideo::aviHeaderTagsHandler 1105 streamHandler(long size)1106 void RiffVideo::streamHandler(long size) 1107 { 1108 const long bufMinSize = 4; 1109 DataBuf buf(bufMinSize+1); 1110 buf.pData_[4]='\0'; 1111 long divisor = 1; 1112 uint64_t cur_pos = io_->tell(); 1113 1114 io_->read(buf.pData_, bufMinSize); 1115 if(equalsRiffTag(buf, "VIDS")) 1116 streamType_ = Video; 1117 else if (equalsRiffTag(buf, "AUDS")) 1118 streamType_ = Audio; 1119 1120 for(int i=1; i<=25; i++) { 1121 std::memset(buf.pData_, 0x0, buf.size_); 1122 io_->read(buf.pData_, bufMinSize); 1123 1124 switch(i) { 1125 case codec: 1126 if(streamType_ == Video) 1127 xmpData_["Xmp.video.Codec"] = buf.pData_; 1128 else if (streamType_ == Audio) 1129 xmpData_["Xmp.audio.Codec"] = buf.pData_; 1130 else 1131 xmpData_["Xmp.video.Codec"] = buf.pData_; 1132 break; 1133 case sampleRate: 1134 divisor=Exiv2::getULong(buf.pData_, littleEndian); 1135 break; 1136 case (sampleRate+1): 1137 if(streamType_ == Video) 1138 xmpData_["Xmp.video.FrameRate"] = returnSampleRate(buf,divisor); 1139 else if (streamType_ == Audio) 1140 xmpData_["Xmp.audio.SampleRate"] = returnSampleRate(buf,divisor); 1141 else 1142 xmpData_["Xmp.video.StreamSampleRate"] = returnSampleRate(buf,divisor); 1143 break; 1144 case sampleCount: 1145 if(streamType_ == Video) 1146 xmpData_["Xmp.video.FrameCount"] = Exiv2::getULong(buf.pData_, littleEndian); 1147 else if (streamType_ == Audio) 1148 xmpData_["Xmp.audio.SampleCount"] = Exiv2::getULong(buf.pData_, littleEndian); 1149 else 1150 xmpData_["Xmp.video.StreamSampleCount"] = Exiv2::getULong(buf.pData_, littleEndian); 1151 break; 1152 case quality: 1153 if(streamType_ == Video) 1154 xmpData_["Xmp.video.VideoQuality"] = Exiv2::getULong(buf.pData_, littleEndian); 1155 else if(streamType_ != Audio) 1156 xmpData_["Xmp.video.StreamQuality"] = Exiv2::getULong(buf.pData_, littleEndian); 1157 break; 1158 case sampleSize: 1159 if(streamType_ == Video) 1160 xmpData_["Xmp.video.VideoSampleSize"] = Exiv2::getULong(buf.pData_, littleEndian); 1161 else if(streamType_ != Audio) 1162 xmpData_["Xmp.video.StreamSampleSize"] = Exiv2::getULong(buf.pData_, littleEndian); 1163 break; 1164 } 1165 1166 } 1167 io_->seek(cur_pos + size, BasicIo::beg); 1168 } // RiffVideo::streamHandler 1169 streamFormatHandler(long size)1170 void RiffVideo::streamFormatHandler(long size) 1171 { 1172 const long bufMinSize = 4; 1173 DataBuf buf(bufMinSize+1); 1174 buf.pData_[4] = '\0'; 1175 uint64_t cur_pos = io_->tell(); 1176 1177 if(streamType_ == Video) { 1178 io_->read(buf.pData_, bufMinSize); 1179 1180 for(int i = 0; i <= 9; i++) { 1181 std::memset(buf.pData_, 0x0, buf.size_); 1182 1183 switch(i) { 1184 case imageWidth: //Will be used in case of debugging 1185 io_->read(buf.pData_, bufMinSize); break; 1186 case imageHeight: //Will be used in case of debugging 1187 io_->read(buf.pData_, bufMinSize); break; 1188 case planes: 1189 io_->read(buf.pData_, 2); 1190 xmpData_["Xmp.video.Planes"] = Exiv2::getUShort(buf.pData_, littleEndian); break; 1191 case bitDepth: 1192 io_->read(buf.pData_, 2); 1193 xmpData_["Xmp.video.PixelDepth"] = Exiv2::getUShort(buf.pData_, littleEndian); break; 1194 case compression: 1195 io_->read(buf.pData_, bufMinSize); 1196 xmpData_["Xmp.video.Compressor"] = buf.pData_; break; 1197 case imageLength: 1198 io_->read(buf.pData_, bufMinSize); 1199 xmpData_["Xmp.video.ImageLength"] = Exiv2::getULong(buf.pData_, littleEndian); break; 1200 case pixelsPerMeterX: 1201 io_->read(buf.pData_, bufMinSize); 1202 xmpData_["Xmp.video.PixelPerMeterX"] = Exiv2::getULong(buf.pData_, littleEndian); break; 1203 case pixelsPerMeterY: 1204 io_->read(buf.pData_, bufMinSize); 1205 xmpData_["Xmp.video.PixelPerMeterY"] = Exiv2::getULong(buf.pData_, littleEndian); break; 1206 case numColors: 1207 io_->read(buf.pData_, bufMinSize); 1208 if(Exiv2::getULong(buf.pData_, littleEndian) == 0) { 1209 xmpData_["Xmp.video.NumOfColours"] = "Unspecified"; 1210 } 1211 else { 1212 xmpData_["Xmp.video.NumOfColours"] = Exiv2::getULong(buf.pData_, littleEndian); 1213 } 1214 break; 1215 case numImportantColors: 1216 io_->read(buf.pData_, bufMinSize); 1217 if(Exiv2::getULong(buf.pData_, littleEndian)) { 1218 xmpData_["Xmp.video.NumIfImpColours"] = Exiv2::getULong(buf.pData_, littleEndian); 1219 } 1220 else { 1221 xmpData_["Xmp.video.NumOfImpColours"] = "All"; 1222 } 1223 break; 1224 } 1225 } 1226 } 1227 else if(streamType_ == Audio) { 1228 int c = 0; 1229 const TagDetails* td; 1230 for(int i = 0; i <= 7; i++) { 1231 io_->read(buf.pData_, 2); 1232 1233 switch(i) { 1234 case encoding: 1235 td = find(audioEncodingValues , Exiv2::getUShort(buf.pData_, littleEndian)); 1236 if(td) { 1237 xmpData_["Xmp.audio.Compressor"] = exvGettext(td->label_); 1238 } 1239 else { 1240 xmpData_["Xmp.audio.Compressor"] = Exiv2::getUShort(buf.pData_, littleEndian); 1241 } 1242 break; 1243 case numberOfChannels: 1244 c = Exiv2::getUShort(buf.pData_, littleEndian); 1245 if(c == 1) xmpData_["Xmp.audio.ChannelType"] = "Mono"; 1246 else if(c == 2) xmpData_["Xmp.audio.ChannelType"] = "Stereo"; 1247 else if(c == 5) xmpData_["Xmp.audio.ChannelType"] = "5.1 Surround Sound"; 1248 else if(c == 7) xmpData_["Xmp.audio.ChannelType"] = "7.1 Surround Sound"; 1249 else xmpData_["Xmp.audio.ChannelType"] = "Mono"; 1250 break; 1251 case audioSampleRate: 1252 xmpData_["Xmp.audio.SampleRate"] = Exiv2::getUShort(buf.pData_, littleEndian); 1253 break; 1254 case avgBytesPerSec: 1255 xmpData_["Xmp.audio.SampleType"] = Exiv2::getUShort(buf.pData_, littleEndian); 1256 break; 1257 case bitsPerSample: 1258 xmpData_["Xmp.audio.BitsPerSample"] = Exiv2::getUShort(buf.pData_,littleEndian); 1259 io_->read(buf.pData_, 2); 1260 break; 1261 } 1262 } 1263 } 1264 io_->seek(cur_pos + size, BasicIo::beg); 1265 } // RiffVideo::streamFormatHandler 1266 returnSampleRate(Exiv2::DataBuf & buf,long divisor)1267 double RiffVideo::returnSampleRate(Exiv2::DataBuf& buf, long divisor) 1268 { 1269 return ((double)Exiv2::getULong(buf.pData_, littleEndian) / (double)divisor); 1270 } // RiffVideo::returnSampleRate 1271 printAudioEncoding(uint64_t i)1272 const char* RiffVideo::printAudioEncoding(uint64_t i) 1273 { 1274 const TagDetails* td; 1275 td = find(audioEncodingValues , i); 1276 if(td) 1277 return exvGettext(td->label_); 1278 1279 return "Undefined"; 1280 } // RiffVideo::printAudioEncoding 1281 fillAspectRatio(long width,long height)1282 void RiffVideo::fillAspectRatio(long width, long height) 1283 { 1284 double aspectRatio = (double)width / (double)height; 1285 aspectRatio = floor(aspectRatio*10) / 10; 1286 xmpData_["Xmp.video.AspectRatio"] = aspectRatio; 1287 1288 int aR = (int) ((aspectRatio*10.0)+0.1); 1289 1290 switch (aR) { 1291 case 13 : xmpData_["Xmp.video.AspectRatio"] = "4:3" ; break; 1292 case 17 : xmpData_["Xmp.video.AspectRatio"] = "16:9" ; break; 1293 case 10 : xmpData_["Xmp.video.AspectRatio"] = "1:1" ; break; 1294 case 16 : xmpData_["Xmp.video.AspectRatio"] = "16:10" ; break; 1295 case 22 : xmpData_["Xmp.video.AspectRatio"] = "2.21:1" ; break; 1296 case 23 : xmpData_["Xmp.video.AspectRatio"] = "2.35:1" ; break; 1297 case 12 : xmpData_["Xmp.video.AspectRatio"] = "5:4" ; break; 1298 default : xmpData_["Xmp.video.AspectRatio"] = aspectRatio;break; 1299 } 1300 } // RiffVideo::fillAspectRatio 1301 fillDuration(double frame_rate,long frame_count)1302 void RiffVideo::fillDuration(double frame_rate, long frame_count) 1303 { 1304 if(frame_rate == 0) 1305 return; 1306 1307 uint64_t duration = static_cast<uint64_t>((double)frame_count * (double)1000 / (double)frame_rate); 1308 xmpData_["Xmp.video.FileDataRate"] = (double)io_->size()/(double)(1048576*duration); 1309 xmpData_["Xmp.video.Duration"] = duration; //Duration in number of seconds 1310 } // RiffVideo::fillDuration 1311 newRiffInstance(BasicIo::AutoPtr io,bool)1312 Image::AutoPtr newRiffInstance(BasicIo::AutoPtr io, bool /*create*/) 1313 { 1314 Image::AutoPtr image(new RiffVideo(io)); 1315 if (!image->good()) { 1316 image.reset(); 1317 } 1318 return image; 1319 } 1320 isRiffType(BasicIo & iIo,bool advance)1321 bool isRiffType(BasicIo& iIo, bool advance) 1322 { 1323 const int32_t len = 2; 1324 const unsigned char RiffVideoId[4] = { 'R', 'I', 'F' ,'F'}; 1325 byte buf[len]; 1326 iIo.read(buf, len); 1327 if (iIo.error() || iIo.eof()) { 1328 return false; 1329 } 1330 bool matched = (memcmp(buf, RiffVideoId, len) == 0); 1331 if (!advance || !matched) { 1332 iIo.seek(-len, BasicIo::cur); 1333 } 1334 return matched; 1335 } 1336 1337 } // namespace Exiv2 1338 #endif // EXV_ENABLE_VIDEO 1339