/src/exiv2/src/riffvideo.cpp
Line | Count | Source |
1 | | // ***************************************************************** -*- C++ -*- |
2 | | /* Spec: |
3 | | * https://learn.microsoft.com/fr-fr/windows/win32/directshow/avi-riff-file-reference |
4 | | * https://cdn.hackaday.io/files/274271173436768/avi.pdf |
5 | | * http://abcavi.kibi.ru/docs/odml1.pdf |
6 | | */ |
7 | | // ***************************************************************************** |
8 | | |
9 | | // included header files |
10 | | #include "riffvideo.hpp" |
11 | | #include "basicio.hpp" |
12 | | #include "config.h" |
13 | | #include "enforce.hpp" |
14 | | #include "error.hpp" |
15 | | #include "futils.hpp" |
16 | | #include "helper_functions.hpp" |
17 | | #include "utils.hpp" |
18 | | |
19 | | #include <array> |
20 | | |
21 | | namespace Exiv2::Internal { |
22 | | |
23 | | const std::map<std::string, std::string> infoTags = { |
24 | | {"AGES", "Xmp.video.Rated"}, |
25 | | {"CMNT", "Xmp.video.Comment"}, |
26 | | {"CODE", "Xmp.video.EncodedBy"}, |
27 | | {"COMM", "Xmp.video.Comment"}, |
28 | | {"DIRC", "Xmp.video.Director"}, |
29 | | {"DISP", "Xmp.audio.SchemeTitle"}, |
30 | | {"DTIM", "Xmp.video.DateTimeOriginal"}, |
31 | | {"GENR", "Xmp.video.Genre"}, |
32 | | {"IARL", "Xmp.video.ArchivalLocation"}, |
33 | | {"IART", "Xmp.video.Artist"}, |
34 | | {"IAS1", "Xmp.video.Edit1"}, |
35 | | {"IAS2", "Xmp.video.Edit2"}, |
36 | | {"IAS3", "Xmp.video.Edit3"}, |
37 | | {"IAS4", "Xmp.video.Edit4"}, |
38 | | {"IAS5", "Xmp.video.Edit5"}, |
39 | | {"IAS6", "Xmp.video.Edit6"}, |
40 | | {"IAS7", "Xmp.video.Edit7"}, |
41 | | {"IAS8", "Xmp.video.Edit8"}, |
42 | | {"IAS9", "Xmp.video.Edit9"}, |
43 | | {"IBSU", "Xmp.video.BaseURL"}, |
44 | | {"ICAS", "Xmp.audio.DefaultStream"}, |
45 | | {"ICDS", "Xmp.video.CostumeDesigner"}, |
46 | | {"ICMS", "Xmp.video.Commissioned"}, |
47 | | {"ICMT", "Xmp.video.Comment"}, |
48 | | {"ICNM", "Xmp.video.Cinematographer"}, |
49 | | {"ICNT", "Xmp.video.Country"}, |
50 | | {"ICOP", "Xmp.video.Copyright"}, |
51 | | {"ICRD", "Xmp.video.DateTimeDigitized"}, |
52 | | {"ICRP", "Xmp.video.Cropped"}, |
53 | | {"IDIM", "Xmp.video.Dimensions"}, |
54 | | {"IDPI", "Xmp.video.DotsPerInch"}, |
55 | | {"IDST", "Xmp.video.DistributedBy"}, |
56 | | {"IEDT", "Xmp.video.EditedBy"}, |
57 | | {"IENC", "Xmp.video.EncodedBy"}, |
58 | | {"IENG", "Xmp.video.Engineer"}, |
59 | | {"IGNR", "Xmp.video.Genre"}, |
60 | | {"IKEY", "Xmp.video.PerformerKeywords"}, |
61 | | {"ILGT", "Xmp.video.Lightness"}, |
62 | | {"ILGU", "Xmp.video.LogoURL"}, |
63 | | {"ILIU", "Xmp.video.LogoIconURL"}, |
64 | | {"ILNG", "Xmp.video.Language"}, |
65 | | {"IMBI", "Xmp.video.InfoBannerImage"}, |
66 | | {"IMBU", "Xmp.video.InfoBannerURL"}, |
67 | | {"IMED", "Xmp.video.Medium"}, |
68 | | {"IMIT", "Xmp.video.InfoText"}, |
69 | | {"IMIU", "Xmp.video.InfoURL"}, |
70 | | {"IMUS", "Xmp.video.MusicBy"}, |
71 | | {"INAM", "Xmp.video.Title"}, |
72 | | {"IPDS", "Xmp.video.ProductionDesigner"}, |
73 | | {"IPLT", "Xmp.video.NumOfColors"}, |
74 | | {"IPRD", "Xmp.video.Product"}, |
75 | | {"IPRO", "Xmp.video.ProducedBy"}, |
76 | | {"IRIP", "Xmp.video.RippedBy"}, |
77 | | {"IRTD", "Xmp.video.Rating"}, |
78 | | {"ISBJ", "Xmp.video.Subject"}, |
79 | | {"ISFT", "Xmp.video.Software"}, |
80 | | {"ISGN", "Xmp.video.SecondaryGenre"}, |
81 | | {"ISHP", "Xmp.video.Sharpness"}, |
82 | | {"ISRC", "Xmp.video.Source"}, |
83 | | {"ISRF", "Xmp.video.SourceForm"}, |
84 | | {"ISTD", "Xmp.video.ProductionStudio"}, |
85 | | {"ISTR", "Xmp.video.Starring"}, |
86 | | {"ITCH", "Xmp.video.Technician"}, |
87 | | {"IWMU", "Xmp.video.WatermarkURL"}, |
88 | | {"IWRI", "Xmp.video.WrittenBy"}, |
89 | | {"LANG", "Xmp.video.Language"}, |
90 | | {"LOCA", "Xmp.video.LocationInfo"}, |
91 | | {"PRT1", "Xmp.video.Part"}, |
92 | | {"PRT2", "Xmp.video.NumOfParts"}, |
93 | | {"RATE", "Xmp.video.Rate"}, |
94 | | {"STAR", "Xmp.video.Starring"}, |
95 | | {"STAT", "Xmp.video.Statistics"}, |
96 | | {"TAPE", "Xmp.video.TapeName"}, |
97 | | {"TCDO", "Xmp.video.EndTimecode"}, |
98 | | {"TCOD", "Xmp.video.StartTimecode"}, |
99 | | {"TITL", "Xmp.video.Title"}, |
100 | | {"TLEN", "Xmp.video.Length"}, |
101 | | {"TORG", "Xmp.video.Organization"}, |
102 | | {"TRCK", "Xmp.video.TrackNumber"}, |
103 | | {"TURL", "Xmp.video.URL"}, |
104 | | {"TVER", "Xmp.video.SoftwareVersion"}, |
105 | | {"VMAJ", "Xmp.video.VegasVersionMajor"}, |
106 | | {"VMIN", "Xmp.video.VegasVersionMinor"}, |
107 | | {"YEAR", "Xmp.video.Year"}, |
108 | | }; |
109 | | |
110 | | const std::map<uint16_t, std::string> audioEncodingValues = { |
111 | | {0x1, "Microsoft PCM"}, |
112 | | {0x2, "Microsoft ADPCM"}, |
113 | | {0x3, "Microsoft IEEE float"}, |
114 | | {0x4, "Compaq VSELP"}, |
115 | | {0x5, "IBM CVSD"}, |
116 | | {0x6, "Microsoft a-Law"}, |
117 | | {0x7, "Microsoft u-Law"}, |
118 | | {0x8, "Microsoft DTS"}, |
119 | | {0x9, "DRM"}, |
120 | | {0xa, "WMA 9 Speech"}, |
121 | | {0xb, "Microsoft Windows Media RT Voice"}, |
122 | | {0x10, "OKI-ADPCM"}, |
123 | | {0x11, "Intel IMA/DVI-ADPCM"}, |
124 | | {0x12, "Videologic Mediaspace ADPCM"}, |
125 | | {0x13, "Sierra ADPCM"}, |
126 | | {0x14, "Antex G.723 ADPCM"}, |
127 | | {0x15, "DSP Solutions DIGISTD"}, |
128 | | {0x16, "DSP Solutions DIGIFIX"}, |
129 | | {0x17, "Dialoic OKI ADPCM"}, |
130 | | {0x18, "Media Vision ADPCM"}, |
131 | | {0x19, "HP CU"}, |
132 | | {0x1a, "HP Dynamic Voice"}, |
133 | | {0x20, "Yamaha ADPCM"}, |
134 | | {0x21, "SONARC Speech Compression"}, |
135 | | {0x22, "DSP Group True Speech"}, |
136 | | {0x23, "Echo Speech Corp."}, |
137 | | {0x24, "Virtual Music Audiofile AF36"}, |
138 | | {0x25, "Audio Processing Tech."}, |
139 | | {0x26, "Virtual Music Audiofile AF10"}, |
140 | | {0x27, "Aculab Prosody 1612"}, |
141 | | {0x28, "Merging Tech. LRC"}, |
142 | | {0x30, "Dolby AC2"}, |
143 | | {0x31, "Microsoft GSM610"}, |
144 | | {0x32, "MSN Audio"}, |
145 | | {0x33, "Antex ADPCME"}, |
146 | | {0x34, "Control Resources VQLPC"}, |
147 | | {0x35, "DSP Solutions DIGIREAL"}, |
148 | | {0x36, "DSP Solutions DIGIADPCM"}, |
149 | | {0x37, "Control Resources CR10"}, |
150 | | {0x38, "Natural MicroSystems VBX ADPCM"}, |
151 | | {0x39, "Crystal Semiconductor IMA ADPCM"}, |
152 | | {0x3a, "Echo Speech ECHOSC3"}, |
153 | | {0x3b, "Rockwell ADPCM"}, |
154 | | {0x3c, "Rockwell DIGITALK"}, |
155 | | {0x3d, "Xebec Multimedia"}, |
156 | | {0x40, "Antex G.721 ADPCM"}, |
157 | | {0x41, "Antex G.728 CELP"}, |
158 | | {0x42, "Microsoft MSG723"}, |
159 | | {0x43, "IBM AVC ADPCM"}, |
160 | | {0x45, "ITU-T G.726"}, |
161 | | {0x50, "Microsoft MPEG"}, |
162 | | {0x51, "RT23 or PAC"}, |
163 | | {0x52, "InSoft RT24"}, |
164 | | {0x53, "InSoft PAC"}, |
165 | | {0x55, "MP3"}, |
166 | | {0x59, "Cirrus"}, |
167 | | {0x60, "Cirrus Logic"}, |
168 | | {0x61, "ESS Tech. PCM"}, |
169 | | {0x62, "Voxware Inc."}, |
170 | | {0x63, "Canopus ATRAC"}, |
171 | | {0x64, "APICOM G.726 ADPCM"}, |
172 | | {0x65, "APICOM G.722 ADPCM"}, |
173 | | {0x66, "Microsoft DSAT"}, |
174 | | {0x67, "Microsoft DSAT DISPLAY"}, |
175 | | {0x69, "Voxware Byte Aligned"}, |
176 | | {0x70, "Voxware AC8"}, |
177 | | {0x71, "Voxware AC10"}, |
178 | | {0x72, "Voxware AC16"}, |
179 | | {0x73, "Voxware AC20"}, |
180 | | {0x74, "Voxware MetaVoice"}, |
181 | | {0x75, "Voxware MetaSound"}, |
182 | | {0x76, "Voxware RT29HW"}, |
183 | | {0x77, "Voxware VR12"}, |
184 | | {0x78, "Voxware VR18"}, |
185 | | {0x79, "Voxware TQ40"}, |
186 | | {0x7a, "Voxware SC3"}, |
187 | | {0x7b, "Voxware SC3"}, |
188 | | {0x80, "Soundsoft"}, |
189 | | {0x81, "Voxware TQ60"}, |
190 | | {0x82, "Microsoft MSRT24"}, |
191 | | {0x83, "AT&T G.729A"}, |
192 | | {0x84, "Motion Pixels MVI MV12"}, |
193 | | {0x85, "DataFusion G.726"}, |
194 | | {0x86, "DataFusion GSM610"}, |
195 | | {0x88, "Iterated Systems Audio"}, |
196 | | {0x89, "Onlive"}, |
197 | | {0x8a, "Multitude, Inc. FT SX20"}, |
198 | | {0x8b, "Infocom ITS A/S G.721 ADPCM"}, |
199 | | {0x8c, "Convedia G729"}, |
200 | | {0x8d, "Not specified congruency, Inc."}, |
201 | | {0x91, "Siemens SBC24"}, |
202 | | {0x92, "Sonic Foundry Dolby AC3 APDIF"}, |
203 | | {0x93, "MediaSonic G.723"}, |
204 | | {0x94, "Aculab Prosody 8kbps"}, |
205 | | {0x97, "ZyXEL ADPCM"}, |
206 | | {0x98, "Philips LPCBB"}, |
207 | | {0x99, "Studer Professional Audio Packed"}, |
208 | | {0xa0, "Malden PhonyTalk"}, |
209 | | {0xa1, "Racal Recorder GSM"}, |
210 | | {0xa2, "Racal Recorder G720.a"}, |
211 | | {0xa3, "Racal G723.1"}, |
212 | | {0xa4, "Racal Tetra ACELP"}, |
213 | | {0xb0, "NEC AAC NEC Corporation"}, |
214 | | {0xff, "AAC"}, |
215 | | {0x100, "Rhetorex ADPCM"}, |
216 | | {0x101, "IBM u-Law"}, |
217 | | {0x102, "IBM a-Law"}, |
218 | | {0x103, "IBM ADPCM"}, |
219 | | {0x111, "Vivo G.723"}, |
220 | | {0x112, "Vivo Siren"}, |
221 | | {0x120, "Philips Speech Processing CELP"}, |
222 | | {0x121, "Philips Speech Processing GRUNDIG"}, |
223 | | {0x123, "Digital G.723"}, |
224 | | {0x125, "Sanyo LD ADPCM"}, |
225 | | {0x130, "Sipro Lab ACEPLNET"}, |
226 | | {0x131, "Sipro Lab ACELP4800"}, |
227 | | {0x132, "Sipro Lab ACELP8V3"}, |
228 | | {0x133, "Sipro Lab G.729"}, |
229 | | {0x134, "Sipro Lab G.729A"}, |
230 | | {0x135, "Sipro Lab Kelvin"}, |
231 | | {0x136, "VoiceAge AMR"}, |
232 | | {0x140, "Dictaphone G.726 ADPCM"}, |
233 | | {0x150, "Qualcomm PureVoice"}, |
234 | | {0x151, "Qualcomm HalfRate"}, |
235 | | {0x155, "Ring Zero Systems TUBGSM"}, |
236 | | {0x160, "Microsoft Audio1"}, |
237 | | {0x161, "Windows Media Audio V2 V7 V8 V9 / DivX audio (WMA) / Alex AC3 Audio"}, |
238 | | {0x162, "Windows Media Audio Professional V9"}, |
239 | | {0x163, "Windows Media Audio Lossless V9"}, |
240 | | {0x164, "WMA Pro over S/PDIF"}, |
241 | | {0x170, "UNISYS NAP ADPCM"}, |
242 | | {0x171, "UNISYS NAP ULAW"}, |
243 | | {0x172, "UNISYS NAP ALAW"}, |
244 | | {0x173, "UNISYS NAP 16K"}, |
245 | | {0x174, "MM SYCOM ACM SYC008 SyCom Technologies"}, |
246 | | {0x175, "MM SYCOM ACM SYC701 G726L SyCom Technologies"}, |
247 | | {0x176, "MM SYCOM ACM SYC701 CELP54 SyCom Technologies"}, |
248 | | {0x177, "MM SYCOM ACM SYC701 CELP68 SyCom Technologies"}, |
249 | | {0x178, "Knowledge Adventure ADPCM"}, |
250 | | {0x180, "Fraunhofer IIS MPEG2AAC"}, |
251 | | {0x190, "Digital Theater Systems DTS DS"}, |
252 | | {0x200, "Creative Labs ADPCM"}, |
253 | | {0x202, "Creative Labs FASTSPEECH8"}, |
254 | | {0x203, "Creative Labs FASTSPEECH10"}, |
255 | | {0x210, "UHER ADPCM"}, |
256 | | {0x215, "Ulead DV ACM"}, |
257 | | {0x216, "Ulead DV ACM"}, |
258 | | {0x220, "Quarterdeck Corp."}, |
259 | | {0x230, "I-Link VC"}, |
260 | | {0x240, "Aureal Semiconductor Raw Sport"}, |
261 | | {0x241, "ESST AC3"}, |
262 | | {0x250, "Interactive Products HSX"}, |
263 | | {0x251, "Interactive Products RPELP"}, |
264 | | {0x260, "Consistent CS2"}, |
265 | | {0x270, "Sony SCX"}, |
266 | | {0x271, "Sony SCY"}, |
267 | | {0x272, "Sony ATRAC3"}, |
268 | | {0x273, "Sony SPC"}, |
269 | | {0x280, "TELUM Telum Inc."}, |
270 | | {0x281, "TELUMIA Telum Inc."}, |
271 | | {0x285, "Norcom Voice Systems ADPCM"}, |
272 | | {0x300, "Fujitsu FM TOWNS SND"}, |
273 | | {0x301, "Fujitsu (not specified)"}, |
274 | | {0x302, "Fujitsu (not specified)"}, |
275 | | {0x303, "Fujitsu (not specified)"}, |
276 | | {0x304, "Fujitsu (not specified)"}, |
277 | | {0x305, "Fujitsu (not specified)"}, |
278 | | {0x306, "Fujitsu (not specified)"}, |
279 | | {0x307, "Fujitsu (not specified)"}, |
280 | | {0x308, "Fujitsu (not specified)"}, |
281 | | {0x350, "Micronas Semiconductors, Inc. Development"}, |
282 | | {0x351, "Micronas Semiconductors, Inc. CELP833"}, |
283 | | {0x400, "Brooktree Digital"}, |
284 | | {0x401, "Intel Music Coder (IMC)"}, |
285 | | {0x402, "Ligos Indeo Audio"}, |
286 | | {0x450, "QDesign Music"}, |
287 | | {0x500, "On2 VP7 On2 Technologies"}, |
288 | | {0x501, "On2 VP6 On2 Technologies"}, |
289 | | {0x680, "AT&T VME VMPCM"}, |
290 | | {0x681, "AT&T TCP"}, |
291 | | {0x700, "YMPEG Alpha (dummy for MPEG-2 compressor)"}, |
292 | | {0x8ae, "ClearJump LiteWave (lossless)"}, |
293 | | {0x1000, "Olivetti GSM"}, |
294 | | {0x1001, "Olivetti ADPCM"}, |
295 | | {0x1002, "Olivetti CELP"}, |
296 | | {0x1003, "Olivetti SBC"}, |
297 | | {0x1004, "Olivetti OPR"}, |
298 | | {0x1100, "Lernout & Hauspie"}, |
299 | | {0x1101, "Lernout & Hauspie CELP codec"}, |
300 | | {0x1102, "Lernout & Hauspie SBC codec"}, |
301 | | {0x1103, "Lernout & Hauspie SBC codec"}, |
302 | | {0x1104, "Lernout & Hauspie SBC codec"}, |
303 | | {0x1400, "Norris Comm. Inc."}, |
304 | | {0x1401, "ISIAudio"}, |
305 | | {0x1500, "AT&T Soundspace Music Compression"}, |
306 | | {0x181c, "VoxWare RT24 speech codec"}, |
307 | | {0x181e, "Lucent elemedia AX24000P Music codec"}, |
308 | | {0x1971, "Sonic Foundry LOSSLESS"}, |
309 | | {0x1979, "Innings Telecom Inc. ADPCM"}, |
310 | | {0x1c07, "Lucent SX8300P speech codec"}, |
311 | | {0x1c0c, "Lucent SX5363S G.723 compliant codec"}, |
312 | | {0x1f03, "CUseeMe DigiTalk (ex-Rocwell)"}, |
313 | | {0x1fc4, "NCT Soft ALF2CD ACM"}, |
314 | | {0x2000, "FAST Multimedia DVM"}, |
315 | | {0x2001, "Dolby DTS (Digital Theater System)"}, |
316 | | {0x2002, "RealAudio 1 / 2 14.4"}, |
317 | | {0x2003, "RealAudio 1 / 2 28.8"}, |
318 | | {0x2004, "RealAudio G2 / 8 Cook (low bitrate)"}, |
319 | | {0x2005, "RealAudio 3 / 4 / 5 Music (DNET)"}, |
320 | | {0x2006, "RealAudio 10 AAC (RAAC)"}, |
321 | | {0x2007, "RealAudio 10 AAC+ (RACP)"}, |
322 | | {0x2500, "Reserved range to 0x2600 Microsoft"}, |
323 | | {0x3313, "makeAVIS (ffvfw fake AVI sound from AviSynth scripts)"}, |
324 | | {0x4143, "Divio MPEG-4 AAC audio"}, |
325 | | {0x4201, "Nokia adaptive multirate"}, |
326 | | {0x4243, "Divio G726 Divio, Inc."}, |
327 | | {0x434c, "LEAD Speech"}, |
328 | | {0x564c, "LEAD Vorbis"}, |
329 | | {0x5756, "WavPack Audio"}, |
330 | | {0x674f, "Ogg Vorbis (mode 1)"}, |
331 | | {0x6750, "Ogg Vorbis (mode 2)"}, |
332 | | {0x6751, "Ogg Vorbis (mode 3)"}, |
333 | | {0x676f, "Ogg Vorbis (mode 1+)"}, |
334 | | {0x6770, "Ogg Vorbis (mode 2+)"}, |
335 | | {0x6771, "Ogg Vorbis (mode 3+)"}, |
336 | | {0x7000, "3COM NBX 3Com Corporation"}, |
337 | | {0x706d, "FAAD AAC"}, |
338 | | {0x7a21, "GSM-AMR (CBR, no SID)"}, |
339 | | {0x7a22, "GSM-AMR (VBR, including SID)"}, |
340 | | {0xa100, "Comverse Infosys Ltd. G723 1"}, |
341 | | {0xa101, "Comverse Infosys Ltd. AVQSBC"}, |
342 | | {0xa102, "Comverse Infosys Ltd. OLDSBC"}, |
343 | | {0xa103, "Symbol Technologies G729A"}, |
344 | | {0xa104, "VoiceAge AMR WB VoiceAge Corporation"}, |
345 | | {0xa105, "Ingenient Technologies Inc. G726"}, |
346 | | {0xa106, "ISO/MPEG-4 advanced audio Coding"}, |
347 | | {0xa107, "Encore Software Ltd G726"}, |
348 | | {0xa109, "Speex ACM Codec xiph.org"}, |
349 | | {0xdfac, "DebugMode SonicFoundry Vegas FrameServer ACM Codec"}, |
350 | | {0xe708, "Unknown -"}, |
351 | | {0xf1ac, "Free Lossless Audio Codec FLAC"}, |
352 | | {0xfffe, "Extensible"}, |
353 | | {0xffff, "Development"}, |
354 | | }; |
355 | | |
356 | | } // namespace Exiv2::Internal |
357 | | // ***************************************************************************** |
358 | | // class member definitions |
359 | | |
360 | | namespace Exiv2 { |
361 | | |
362 | | enum streamTypeInfo { Audio = 1, MIDI, Text, Video }; |
363 | | |
364 | | RiffVideo::RiffVideo(BasicIo::UniquePtr io, const ImageCtorParams& params) : |
365 | 432 | Image(ImageType::riff, mdNone, std::move(io), params) { |
366 | 432 | } // RiffVideo::RiffVideo |
367 | | |
368 | 432 | std::string RiffVideo::mimeType() const { |
369 | 432 | return "video/riff"; |
370 | 432 | } |
371 | | |
372 | 0 | void RiffVideo::writeMetadata() { |
373 | 0 | } // RiffVideo::writeMetadata |
374 | | |
375 | 432 | void RiffVideo::readMetadata() { |
376 | 432 | if (io_->open() != 0) |
377 | 0 | throw Error(ErrorCode::kerDataSourceOpenFailed, io_->path(), strError()); |
378 | | |
379 | | // Ensure that this is the correct image type |
380 | 432 | if (!isRiffType(*io_, false)) { |
381 | 0 | if (io_->error() || io_->eof()) |
382 | 0 | throw Error(ErrorCode::kerFailedToReadImageData); |
383 | 0 | throw Error(ErrorCode::kerNotAnImage, "RIFF"); |
384 | 0 | } |
385 | | |
386 | 432 | IoCloser closer(*io_); |
387 | 432 | clearMetadata(); |
388 | | |
389 | 432 | xmpData_["Xmp.video.FileSize"] = io_->size(); |
390 | 432 | xmpData_["Xmp.video.MimeType"] = mimeType(); |
391 | | |
392 | 432 | HeaderReader header(io_); |
393 | 432 | xmpData_["Xmp.video.Container"] = header.getId(); |
394 | | |
395 | 432 | xmpData_["Xmp.video.FileType"] = readStringTag(io_); |
396 | | |
397 | 432 | decodeBlocks(); |
398 | 432 | } // RiffVideo::readMetadata |
399 | | |
400 | 30.0k | RiffVideo::HeaderReader::HeaderReader(const BasicIo::UniquePtr& io) { |
401 | 30.0k | Internal::enforce(io->size() > io->tell() + DWORD + DWORD, Exiv2::ErrorCode::kerCorruptedMetadata); |
402 | 30.0k | id_ = readStringTag(io); |
403 | 30.0k | size_ = readDWORDTag(io); |
404 | 30.0k | } |
405 | | |
406 | 312k | bool RiffVideo::equal(const std::string& str1, const std::string& str2) { |
407 | 312k | if (str1.size() != str2.size()) |
408 | 304k | return false; |
409 | | |
410 | 8.01k | return Internal::upper(str1) == str2; |
411 | 312k | } |
412 | | |
413 | 458 | void RiffVideo::readList(const HeaderReader& header_) { |
414 | 458 | std::string chunk_type = readStringTag(io_); |
415 | | |
416 | | #ifdef EXIV2_DEBUG_MESSAGES |
417 | | EXV_INFO << "-> Reading list : id= " << header_.getId() << " type= " << chunk_type << " size= " << header_.getSize() |
418 | | << "(" << io_->tell() << "/" << io_->size() << ")" << '\n'; |
419 | | #endif |
420 | | |
421 | 458 | if (equal(chunk_type, CHUNK_ID_INFO)) |
422 | 241 | readInfoListChunk(header_.getSize()); |
423 | 217 | else if (equal(chunk_type, CHUNK_ID_MOVI)) { |
424 | 7 | readMoviList(header_.getSize()); |
425 | 7 | } |
426 | 458 | } |
427 | | |
428 | 29.0k | void RiffVideo::readChunk(const HeaderReader& header_) { |
429 | | #ifdef EXIV2_DEBUG_MESSAGES |
430 | | if (header_.getSize()) |
431 | | EXV_INFO << "--> Reading Chunk : [" << header_.getId() << "] size= " << header_.getSize() << "(" << io_->tell() |
432 | | << "/" << io_->size() << ")" << '\n'; |
433 | | #endif |
434 | | |
435 | 29.0k | if (equal(header_.getId(), CHUNK_ID_AVIH)) |
436 | 244 | readAviHeader(); |
437 | 28.8k | else if (equal(header_.getId(), CHUNK_ID_STRH)) |
438 | 162 | readStreamHeader(); |
439 | 28.6k | else if (equal(header_.getId(), CHUNK_ID_STRF)) |
440 | 78 | readStreamFormat(header_.getSize()); |
441 | 28.6k | else if (equal(header_.getId(), CHUNK_ID_FMT)) { |
442 | 721 | streamType_ = Audio; |
443 | 721 | readStreamFormat(header_.getSize()); |
444 | 27.8k | } else if (equal(header_.getId(), CHUNK_ID_STRD)) |
445 | 20 | readStreamData(header_.getSize()); |
446 | 27.8k | else if (equal(header_.getId(), CHUNK_ID_STRN)) |
447 | 2 | StreamName(header_.getSize()); |
448 | 27.8k | else if (equal(header_.getId(), CHUNK_ID_VPRP)) |
449 | 10 | readVPRPChunk(header_.getSize()); |
450 | 27.8k | else if (equal(header_.getId(), CHUNK_ID_IDX1)) |
451 | 10 | readIndexChunk(header_.getSize()); |
452 | 27.8k | else if (equal(header_.getId(), CHUNK_ID_DATA)) |
453 | 48 | readDataChunk(header_.getSize()); |
454 | 27.7k | else if (equal(header_.getId(), CHUNK_ID_JUNK)) |
455 | 18 | readJunk(header_.getSize()); |
456 | 27.7k | else { |
457 | | #ifdef EXIV2_DEBUG_MESSAGES |
458 | | if (header_.getSize()) |
459 | | EXV_WARNING << "--> Ignoring Chunk : " << header_.getId() << "] size= " << header_.getSize() << "(" << io_->tell() |
460 | | << "/" << io_->size() << ")" << '\n'; |
461 | | #endif |
462 | 27.7k | io_->seekOrThrow(io_->tell() + header_.getSize(), BasicIo::beg, ErrorCode::kerFailedToReadImageData); |
463 | 27.7k | } |
464 | 29.0k | } |
465 | | |
466 | 432 | void RiffVideo::decodeBlocks() { |
467 | 29.6k | do { |
468 | 29.6k | if (HeaderReader header(io_); equal(header.getId(), CHUNK_ID_LIST)) { |
469 | 458 | readList(header); |
470 | 29.1k | } else { |
471 | 29.1k | readChunk(header); |
472 | 29.1k | } |
473 | 29.6k | } while (!io_->eof() && io_->tell() < io_->size()); |
474 | 432 | } // RiffVideo::decodeBlock |
475 | | |
476 | 244 | void RiffVideo::readAviHeader() { |
477 | | #ifdef EXIV2_DEBUG_MESSAGES |
478 | | EXV_INFO << "--> dwMicroSecPerFrame = " << readDWORDTag(io_) << '\n'; |
479 | | EXV_INFO << "--> dwMaxBytesPerSec = " << readDWORDTag(io_) << '\n'; |
480 | | EXV_INFO << "--> dwPaddingGranularity = " << readDWORDTag(io_) << '\n'; |
481 | | EXV_INFO << "--> dwFlags = " << readDWORDTag(io_) << '\n'; |
482 | | EXV_INFO << "--> dwTotalFrames = " << readDWORDTag(io_) << '\n'; |
483 | | EXV_INFO << "--> dwInitialFrames = " << readDWORDTag(io_) << '\n'; |
484 | | EXV_INFO << "--> dwStreams = " << readDWORDTag(io_) << '\n'; |
485 | | EXV_INFO << "--> dwSuggestedBufferSize = " << readDWORDTag(io_) << '\n'; |
486 | | EXV_INFO << "--> dwWidth = " << readDWORDTag(io_) << '\n'; |
487 | | EXV_INFO << "--> dwHeight = " << readDWORDTag(io_) << '\n'; |
488 | | EXV_INFO << "--> dwReserved1 = " << readDWORDTag(io_) << '\n'; |
489 | | EXV_INFO << "--> dwReserved2 = " << readDWORDTag(io_) << '\n'; |
490 | | EXV_INFO << "--> dwReserved3 = " << readDWORDTag(io_) << '\n'; |
491 | | EXV_INFO << "--> dwReserved4 = " << readDWORDTag(io_) << '\n'; |
492 | | if (LogMsg::info >= LogMsg::level() && LogMsg::handler()) |
493 | | io_->seekOrThrow(io_->tell() - DWORD * 14, BasicIo::beg, ErrorCode::kerFailedToReadImageData); |
494 | | #endif |
495 | | |
496 | 244 | uint32_t TimeBetweenFrames = readDWORDTag(io_); |
497 | 244 | xmpData_["Xmp.video.MicroSecPerFrame"] = TimeBetweenFrames; |
498 | 244 | double frame_rate = 1000000. / TimeBetweenFrames; |
499 | | |
500 | 244 | xmpData_["Xmp.video.MaxDataRate"] = readDWORDTag(io_); // MaximumDataRate |
501 | | |
502 | 244 | io_->seekOrThrow(io_->tell() + (DWORD * 2), BasicIo::beg, |
503 | 244 | ErrorCode::kerFailedToReadImageData); // ignore PaddingGranularity and Flags |
504 | | |
505 | 244 | uint32_t frame_count = readDWORDTag(io_); // TotalNumberOfFrames |
506 | 244 | xmpData_["Xmp.video.FrameCount"] = frame_count; |
507 | | |
508 | 244 | io_->seekOrThrow(io_->tell() + DWORD, BasicIo::beg, |
509 | 244 | ErrorCode::kerFailedToReadImageData); // ignore NumberOfInitialFrames |
510 | | |
511 | 244 | xmpData_["Xmp.audio.ChannelType"] = getStreamType(readDWORDTag(io_)); // NumberOfStreams |
512 | | |
513 | 244 | xmpData_["Xmp.video.StreamCount"] = readDWORDTag(io_); // SuggestedBufferSize |
514 | | |
515 | 244 | uint32_t width = readDWORDTag(io_); |
516 | 244 | xmpData_["Xmp.video.Width"] = width; |
517 | | |
518 | 244 | uint32_t height = readDWORDTag(io_); |
519 | 244 | xmpData_["Xmp.video.Height"] = height; |
520 | | |
521 | 244 | io_->seekOrThrow(io_->tell() + (DWORD * 4), BasicIo::beg, |
522 | 244 | ErrorCode::kerFailedToReadImageData); // TimeScale, DataRate, StartTime, DataLength |
523 | | |
524 | 244 | xmpData_["Xmp.video.AspectRatio"] = getAspectRatio(width, height); |
525 | | |
526 | 244 | fillDuration(frame_rate, frame_count); |
527 | 244 | } |
528 | | |
529 | 162 | void RiffVideo::readStreamHeader() { |
530 | 162 | std::string stream = readStringTag(io_); |
531 | 162 | streamType_ = (equal(stream, "VIDS")) ? Video : Audio; |
532 | | |
533 | | #ifdef EXIV2_DEBUG_MESSAGES |
534 | | EXV_INFO << "--> fccType = " << stream << '\n'; |
535 | | EXV_INFO << "--> fccHandler = " << readStringTag(io_) << '\n'; |
536 | | EXV_INFO << "--> dwFlags = " << readDWORDTag(io_) << '\n'; |
537 | | EXV_INFO << "--> wPriority = " << readWORDTag(io_) << '\n'; |
538 | | EXV_INFO << "--> wLanguage = " << readWORDTag(io_) << '\n'; |
539 | | EXV_INFO << "--> dwInitialFrames = " << readDWORDTag(io_) << '\n'; // 20 |
540 | | EXV_INFO << "--> dwScale = " << readDWORDTag(io_) << '\n'; |
541 | | EXV_INFO << "--> dwRate = " << readDWORDTag(io_) << '\n'; |
542 | | EXV_INFO << "--> dwStart = " << readDWORDTag(io_) << '\n'; |
543 | | EXV_INFO << "--> dwLength = " << readDWORDTag(io_) << '\n'; |
544 | | EXV_INFO << "--> dwSuggestedBufferSize = " << readDWORDTag(io_) << '\n'; // 40 |
545 | | EXV_INFO << "--> dwSampleSize = " << readDWORDTag(io_) << '\n'; |
546 | | EXV_INFO << "--> Left = " << readWORDTag(io_) << '\n'; |
547 | | EXV_INFO << "--> top = " << readWORDTag(io_) << '\n'; |
548 | | EXV_INFO << "--> right = " << readWORDTag(io_) << '\n'; |
549 | | EXV_INFO << "--> bottom = " << readWORDTag(io_) << '\n'; |
550 | | EXV_INFO << "--> XXXXXX = " << readDWORDTag(io_) << '\n'; // 56 |
551 | | if (LogMsg::info >= LogMsg::level() && LogMsg::handler()) |
552 | | io_->seekOrThrow(io_->tell() - DWORD * 13, BasicIo::beg, ErrorCode::kerFailedToReadImageData); |
553 | | #endif |
554 | | |
555 | 162 | xmpData_["Xmp.video.Codec"] = readStringTag(io_); // DataHandler |
556 | | |
557 | 162 | io_->seekOrThrow(io_->tell() + (DWORD * 2) + (WORD * 2), BasicIo::beg, |
558 | 162 | ErrorCode::kerFailedToReadImageData); // dwFlags, wPriority, wLanguage, dwInitialFrames |
559 | | |
560 | 162 | uint32_t divisor = readDWORDTag(io_); // TimeScale |
561 | | |
562 | 162 | if (divisor) { |
563 | 135 | auto rate = static_cast<double>(readDWORDTag(io_)) / divisor; |
564 | 135 | xmpData_[(streamType_ == Video) ? "Xmp.video.FrameRate" : "Xmp.audio.SampleRate"] = rate; |
565 | 135 | } |
566 | 162 | io_->seekOrThrow(io_->tell() + DWORD, BasicIo::beg, ErrorCode::kerFailedToReadImageData); // dwStart |
567 | | |
568 | 162 | if (divisor) { |
569 | 133 | auto frame_count = static_cast<double>(readDWORDTag(io_)) / divisor; // DataLength |
570 | 133 | xmpData_[(streamType_ == Video) ? "Xmp.video.FrameCount" : "Xmp.audio.FrameCount"] = frame_count; |
571 | 133 | } |
572 | | |
573 | 162 | io_->seekOrThrow(io_->tell() + DWORD, BasicIo::beg, ErrorCode::kerFailedToReadImageData); // dwSuggestedBufferSize |
574 | | |
575 | 162 | xmpData_[(streamType_ == Video) ? "Xmp.video.VideoQuality" : "Xmp.video.StreamQuality"] = readDWORDTag(io_); |
576 | | |
577 | 162 | xmpData_[(streamType_ == Video) ? "Xmp.video.VideoSampleSize" : "Xmp.video.StreamSampleSize"] = readDWORDTag(io_); |
578 | 162 | io_->seekOrThrow(io_->tell() + (DWORD * 2), BasicIo::beg, ErrorCode::kerFailedToReadImageData); |
579 | 162 | } |
580 | | |
581 | 799 | void RiffVideo::readStreamFormat(uint64_t size_) { |
582 | | // The structure of the strf chunk depends on the media type. Video streams use the BITMAPINFOHEADER structure, |
583 | | // whereas audio streams use the WAVEFORMATEX structure. |
584 | | |
585 | | #ifdef EXIV2_DEBUG_MESSAGES |
586 | | if (streamType_ == Audio) { |
587 | | EXV_INFO << "--> wFormatTag = " << readWORDTag(io_) << '\n'; |
588 | | EXV_INFO << "--> nChannels = " << readWORDTag(io_) << '\n'; |
589 | | EXV_INFO << "--> nSamplesPerSec = " << readDWORDTag(io_) << '\n'; |
590 | | EXV_INFO << "--> nAvgBytesPerSec = " << readDWORDTag(io_) << '\n'; |
591 | | EXV_INFO << "--> nBlockAlign = " << readWORDTag(io_) << '\n'; |
592 | | EXV_INFO << "--> wBitsPerSample = " << readWORDTag(io_) << '\n'; |
593 | | if (LogMsg::info >= LogMsg::level() && LogMsg::handler()) |
594 | | io_->seekOrThrow(io_->tell() - DWORD * 4, BasicIo::beg, ErrorCode::kerFailedToReadImageData); |
595 | | } else if (streamType_ == Video) { |
596 | | EXV_INFO << "--> biSize = " << readDWORDTag(io_) << '\n'; |
597 | | EXV_INFO << "--> biWidth = " << readDWORDTag(io_) << '\n'; |
598 | | EXV_INFO << "--> biHeight = " << readDWORDTag(io_) << '\n'; |
599 | | EXV_INFO << "--> biPlanes = " << readWORDTag(io_) << '\n'; |
600 | | EXV_INFO << "--> biBitCount = " << readWORDTag(io_) << '\n'; |
601 | | EXV_INFO << "--> biCompression = " << readDWORDTag(io_) << '\n'; |
602 | | EXV_INFO << "--> biSizeImage = " << readDWORDTag(io_) << '\n'; |
603 | | EXV_INFO << "--> biXPelsPerMeter = " << readDWORDTag(io_) << '\n'; |
604 | | EXV_INFO << "--> biYPelsPerMeter = " << readDWORDTag(io_) << '\n'; |
605 | | EXV_INFO << "--> biClrUsed = " << readDWORDTag(io_) << '\n'; |
606 | | EXV_INFO << "--> biClrImportant = " << readDWORDTag(io_) << '\n'; |
607 | | if (LogMsg::info >= LogMsg::level() && LogMsg::handler()) |
608 | | io_->seekOrThrow(io_->tell() - DWORD * 10, BasicIo::beg, ErrorCode::kerFailedToReadImageData); |
609 | | } |
610 | | #endif |
611 | | |
612 | 799 | if (streamType_ == Video) { |
613 | 66 | io_->seekOrThrow(io_->tell() + (DWORD * 3), BasicIo::beg, |
614 | 66 | ErrorCode::kerFailedToReadImageData); // ignore biSize, biWidth, biHeight |
615 | 66 | xmpData_["Xmp.video.Planes"] = readWORDTag(io_); |
616 | 66 | xmpData_["Xmp.video.PixelDepth"] = readWORDTag(io_); |
617 | 66 | xmpData_["Xmp.video.Compressor"] = readStringTag(io_); |
618 | 66 | xmpData_["Xmp.video.ImageLength"] = readDWORDTag(io_); |
619 | 66 | xmpData_["Xmp.video.PixelPerMeterX"] = readQWORDTag(io_); |
620 | 66 | xmpData_["Xmp.video.PixelPerMeterY"] = readQWORDTag(io_); |
621 | 66 | if (uint32_t NumOfColours = readDWORDTag(io_)) |
622 | 31 | xmpData_["Xmp.video.NumOfColours"] = NumOfColours; |
623 | 35 | else |
624 | 35 | xmpData_["Xmp.video.NumOfColours"] = "Unspecified"; |
625 | 66 | if (uint32_t NumIfImpColours = readDWORDTag(io_)) |
626 | 29 | xmpData_["Xmp.video.NumIfImpColours"] = NumIfImpColours; |
627 | 37 | else |
628 | 37 | xmpData_["Xmp.video.NumIfImpColours"] = "All"; |
629 | 733 | } else if (streamType_ == Audio) { |
630 | 723 | uint16_t format_tag = readWORDTag(io_); |
631 | 723 | if (auto it = Internal::audioEncodingValues.find(format_tag); it != Internal::audioEncodingValues.end()) |
632 | 123 | xmpData_["Xmp.audio.Compressor"] = it->second; |
633 | 600 | else |
634 | 600 | xmpData_["Xmp.audio.Compressor"] = format_tag; |
635 | | |
636 | 723 | xmpData_["Xmp.audio.ChannelType"] = getStreamType(readDWORDTag(io_)); |
637 | 723 | xmpData_["Xmp.audio.SampleRate"] = readDWORDTag(io_); // nSamplesPerSec |
638 | 723 | io_->seekOrThrow(io_->tell() + DWORD, BasicIo::beg, ErrorCode::kerFailedToReadImageData); // nAvgBytesPerSec |
639 | 723 | xmpData_["Xmp.audio.SampleType"] = readDWORDTag(io_); // nBlockAlign |
640 | 723 | xmpData_["Xmp.audio.BitsPerSample"] = readDWORDTag(io_); // wBitsPerSample |
641 | 723 | if (xmpData_["Xmp.video.FileType"].toString() == "AVI ") |
642 | 60 | io_->seekOrThrow(io_->tell() + DWORD, BasicIo::beg, ErrorCode::kerFailedToReadImageData); // cbSize |
643 | 723 | } else { |
644 | 10 | io_->seekOrThrow(io_->tell() + size_, BasicIo::beg, ErrorCode::kerFailedToReadImageData); |
645 | 10 | } |
646 | 799 | } |
647 | | |
648 | 20 | void RiffVideo::readStreamData(uint64_t size_) const { |
649 | 20 | io_->seekOrThrow(io_->tell() + size_, BasicIo::beg, ErrorCode::kerFailedToReadImageData); |
650 | 20 | } |
651 | | |
652 | 2 | void RiffVideo::StreamName(uint64_t size_) const { |
653 | | // This element contains a name for the stream. That stream name should only use plain ASCII, especially not UTF-8. |
654 | 2 | io_->seekOrThrow(io_->tell() + size_, BasicIo::beg, ErrorCode::kerFailedToReadImageData); |
655 | 2 | } |
656 | | |
657 | 241 | void RiffVideo::readInfoListChunk(uint64_t size_) { |
658 | 241 | uint64_t current_size = DWORD; |
659 | | |
660 | | // Add the elements to a temporary table first, so that we can check |
661 | | // for duplicates before adding them to xmpData_. |
662 | 241 | std::map<std::string, std::string> table; |
663 | 1.34k | while (current_size < size_) { |
664 | 1.10k | std::string type = readStringTag(io_); |
665 | 1.10k | size_t size = readDWORDTag(io_); |
666 | 1.10k | std::string content = readStringTag(io_, size); |
667 | 1.10k | if (auto it = Internal::infoTags.find(type); it != Internal::infoTags.end()) { |
668 | | // Check that it isn't a duplicate. |
669 | 11 | Internal::enforce(table.find(it->second) == table.end(), ErrorCode::kerCorruptedMetadata); |
670 | 11 | table[it->second] = content; |
671 | 11 | } |
672 | 1.10k | current_size += DWORD * 2; |
673 | 1.10k | current_size += size; |
674 | 1.10k | } |
675 | | // Copy the elements from the temporary table to xmpData_. |
676 | 241 | for (const auto& it : table) { |
677 | 6 | xmpData_[it.first] = it.second; |
678 | 6 | } |
679 | 241 | } |
680 | | |
681 | 7 | void RiffVideo::readMoviList(uint64_t size_) const { |
682 | 7 | io_->seekOrThrow(io_->tell() + size_ - DWORD, BasicIo::beg, ErrorCode::kerFailedToReadImageData); |
683 | 7 | } |
684 | | |
685 | 10 | void RiffVideo::readVPRPChunk(uint64_t size_) const { |
686 | | #ifdef EXIV2_DEBUG_MESSAGES |
687 | | EXV_INFO << "--> VideoFormatToken = " << readDWORDTag(io_) << '\n'; |
688 | | EXV_INFO << "--> VideoStandard = " << readDWORDTag(io_) << '\n'; |
689 | | EXV_INFO << "--> VerticalRefreshRate = " << readDWORDTag(io_) << '\n'; |
690 | | EXV_INFO << "--> HTotalInT = " << readDWORDTag(io_) << '\n'; |
691 | | EXV_INFO << "--> VTotalInLines = " << readDWORDTag(io_) << '\n'; |
692 | | EXV_INFO << "--> FrameAspectRatio Height = " << readWORDTag(io_) << '\n'; |
693 | | EXV_INFO << "--> FrameAspectRatio Width = " << readWORDTag(io_) << '\n'; |
694 | | EXV_INFO << "--> FrameWidthInPixels = " << readDWORDTag(io_) << '\n'; |
695 | | EXV_INFO << "--> FrameHeightInLines = " << readDWORDTag(io_) << '\n'; |
696 | | EXV_INFO << "--> CompressedBMHeight = " << readDWORDTag(io_) << '\n'; |
697 | | EXV_INFO << "--> FieldPerFrame = " << readDWORDTag(io_) << '\n'; |
698 | | EXV_INFO << "--> CompressedBMWidth = " << readDWORDTag(io_) << '\n'; |
699 | | EXV_INFO << "--> ValidBMHeight = " << readDWORDTag(io_) << '\n'; |
700 | | EXV_INFO << "--> ValidBMWidth = " << readDWORDTag(io_) << '\n'; |
701 | | EXV_INFO << "--> ValidBMXOffset = " << readDWORDTag(io_) << '\n'; |
702 | | EXV_INFO << "--> ValidBMYOffset = " << readDWORDTag(io_) << '\n'; |
703 | | EXV_INFO << "--> VideoXOffsetInT = " << readDWORDTag(io_) << '\n'; |
704 | | EXV_INFO << "--> VideoYValidStartLine = " << readDWORDTag(io_) << '\n'; |
705 | | if (LogMsg::info >= LogMsg::level() && LogMsg::handler()) |
706 | | io_->seekOrThrow(io_->tell() - DWORD * 17, BasicIo::beg, ErrorCode::kerFailedToReadImageData); |
707 | | #endif |
708 | 10 | io_->seekOrThrow(io_->tell() + size_, BasicIo::beg, ErrorCode::kerFailedToReadImageData); |
709 | 10 | } |
710 | | |
711 | 10 | void RiffVideo::readIndexChunk(uint64_t size_) const { |
712 | | #ifdef EXIV2_DEBUG_MESSAGES |
713 | | uint64_t current_size = 0; |
714 | | while (current_size < size_) { |
715 | | EXV_DEBUG << "--> Identifier = " << readStringTag(io_) << "\t(" << current_size << "/" << size_ << ")" |
716 | | << '\n'; |
717 | | EXV_DEBUG << "--> Flags = " << readDWORDTag(io_) << "\t(" << current_size << "/" << size_ << ")" |
718 | | << '\n'; |
719 | | EXV_DEBUG << "--> Offset = " << readDWORDTag(io_) << "\t(" << current_size << "/" << size_ << ")" |
720 | | << '\n'; |
721 | | EXV_DEBUG << "--> Length = " << readDWORDTag(io_) << "\t(" << current_size << "/" << size_ << ")" |
722 | | << '\n'; |
723 | | current_size += DWORD * 4; |
724 | | } |
725 | | if (LogMsg::debug >= LogMsg::level() && LogMsg::handler()) |
726 | | io_->seekOrThrow(io_->tell() - size_, BasicIo::beg, ErrorCode::kerFailedToReadImageData); |
727 | | #endif |
728 | 10 | io_->seekOrThrow(io_->tell() + size_, BasicIo::beg, ErrorCode::kerFailedToReadImageData); |
729 | 10 | } |
730 | | |
731 | 48 | void RiffVideo::readDataChunk(uint64_t size_) const { |
732 | | #ifdef EXIV2_DEBUG_MESSAGES |
733 | | EXV_INFO << "--> Data = " << readStringTag(io_, static_cast<size_t>(size_)) << '\n'; |
734 | | uint64_t readed_size = size_; |
735 | | if (size_ % 2 != 0) { |
736 | | EXV_INFO << "--> pad byte = " << readStringTag(io_, 1) << '\n'; |
737 | | readed_size += 1; |
738 | | } |
739 | | if (LogMsg::info >= LogMsg::level() && LogMsg::handler()) |
740 | | io_->seekOrThrow(io_->tell() - readed_size, BasicIo::beg, ErrorCode::kerFailedToReadImageData); |
741 | | #endif |
742 | 48 | io_->seekOrThrow(io_->tell() + size_, BasicIo::beg, ErrorCode::kerFailedToReadImageData); |
743 | 48 | if (size_ % 2 != 0) |
744 | 41 | io_->seekOrThrow(io_->tell() + 1, BasicIo::beg, ErrorCode::kerFailedToReadImageData); |
745 | 48 | } |
746 | | |
747 | 18 | void RiffVideo::readJunk(uint64_t size_) const { |
748 | 18 | io_->seekOrThrow(io_->tell() + size_, BasicIo::beg, ErrorCode::kerFailedToReadImageData); |
749 | 18 | } |
750 | | |
751 | 959 | std::string RiffVideo::getStreamType(uint32_t stream) { |
752 | 959 | if (stream == 1) |
753 | 55 | return "Mono"; |
754 | 904 | if (stream == 2) |
755 | 7 | return "Stereo"; |
756 | 897 | if (stream == 5) |
757 | 175 | return "5.1 Surround Sound"; |
758 | 722 | if (stream == 7) |
759 | 7 | return "7.1 Surround Sound"; |
760 | 715 | return "Mono"; |
761 | 722 | } |
762 | | |
763 | 225 | void RiffVideo::fillDuration(double frame_rate, size_t frame_count) { |
764 | 225 | if (frame_rate == 0) |
765 | 0 | return; |
766 | | |
767 | 225 | auto duration = static_cast<uint64_t>(frame_count * 1000. / frame_rate); |
768 | 225 | xmpData_["Xmp.video.FileDataRate"] = io_->size() / (1048576. * duration); |
769 | 225 | xmpData_["Xmp.video.Duration"] = duration; // Duration in number of seconds |
770 | 225 | } // RiffVideo::fillDuration |
771 | | |
772 | 432 | Image::UniquePtr newRiffInstance(BasicIo::UniquePtr io, const ImageCtorParams& params) { |
773 | 432 | auto image = std::make_unique<RiffVideo>(std::move(io), params); |
774 | 432 | if (!image->good()) { |
775 | 0 | return nullptr; |
776 | 0 | } |
777 | 432 | return image; |
778 | 432 | } |
779 | | |
780 | 11.6k | bool isRiffType(BasicIo& iIo, bool advance) { |
781 | 11.6k | constexpr int len = 4; |
782 | 11.6k | const std::array<byte, len> RiffVideoId{'R', 'I', 'F', 'F'}; |
783 | 11.6k | std::array<byte, len> buf; |
784 | 11.6k | iIo.read(buf.data(), len); |
785 | 11.6k | if (iIo.error() || iIo.eof()) { |
786 | 325 | return false; |
787 | 325 | } |
788 | 11.3k | bool matched = buf == RiffVideoId; |
789 | 11.3k | if (!advance || !matched) { |
790 | 11.3k | iIo.seek(-1 * len, BasicIo::cur); |
791 | 11.3k | } |
792 | 11.3k | return matched; |
793 | 11.6k | } |
794 | | } // namespace Exiv2 |