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