/src/exiv2/src/matroskavideo.cpp
Line | Count | Source |
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 "matroskavideo.hpp" |
23 | | #include "basicio.hpp" |
24 | | #include "config.h" |
25 | | #include "enforce.hpp" |
26 | | #include "error.hpp" |
27 | | #include "futils.hpp" |
28 | | #include "helper_functions.hpp" |
29 | | |
30 | | // + standard includes |
31 | | #include <cmath> |
32 | | #include <cstdlib> |
33 | | #include <iostream> |
34 | | // ***************************************************************************** |
35 | | // class member definitions |
36 | | namespace Exiv2::Internal { |
37 | | |
38 | | /*! |
39 | | Tag Look-up list for Matroska Type Video Files |
40 | | The Tags have been categorized in 4 categories. Which are |
41 | | mentioned as a comment in front of them. |
42 | | s -- Tag to be Skipped |
43 | | sd -- Tag to be Skipped along with its data |
44 | | u -- Tag used directly for storing metadata |
45 | | ui -- Tag used only internally |
46 | | |
47 | | see : https://www.matroska.org/technical/elements.html |
48 | | https://matroska.sourceforge.net/technical/specs/chapters/index.html |
49 | | */ |
50 | | |
51 | | enum matroskaEnum : uint64_t { |
52 | | ChapterDisplay = 0x0000, |
53 | | TrackType = 0x0003, |
54 | | ChapterString = 0x0005, |
55 | | Video_Audio_CodecID = 0x0006, |
56 | | TrackDefault = 0x0008, |
57 | | ChapterTrackNumber = 0x0009, |
58 | | Slices = 0x000e, |
59 | | ChapterTrack = 0x000f, |
60 | | ChapterTimeStart = 0x0011, |
61 | | ChapterTimeEnd = 0x0012, |
62 | | CueRefTime = 0x0016, |
63 | | CueRefCluster = 0x0017, |
64 | | ChapterFlagHidden = 0x0018, |
65 | | Xmp_video_VideoScanTpye = 0x001a, |
66 | | BlockDuration = 0x001b, |
67 | | TrackLacing = 0x001c, |
68 | | Xmp_audio_ChannelType = 0x001f, |
69 | | BlockGroup = 0x0020, |
70 | | Block = 0x0021, |
71 | | BlockVirtual = 0x0022, |
72 | | SimpleBlock = 0x0023, |
73 | | CodecState = 0x0024, |
74 | | BlockAdditional = 0x0025, |
75 | | BlockMore = 0x0026, |
76 | | Position = 0x0027, |
77 | | CodecDecodeAll = 0x002a, |
78 | | PrevSize = 0x002b, |
79 | | TrackEntry = 0x002e, |
80 | | EncryptedBlock = 0x002f, |
81 | | Xmp_video_Width_1 = 0x0030, |
82 | | CueTime = 0x0033, |
83 | | Xmp_audio_SampleRate = 0x0035, |
84 | | ChapterAtom = 0x0036, |
85 | | CueTrackPositions = 0x0037, |
86 | | TrackUsed = 0x0039, |
87 | | Xmp_video_Height_1 = 0x003a, |
88 | | CuePoint = 0x003b, |
89 | | CRC_32 = 0x003f, |
90 | | BlockAdditionalID = 0x004b, |
91 | | LaceNumber = 0x004c, |
92 | | FrameNumber = 0x004d, |
93 | | Delay = 0x004e, |
94 | | ClusterDuration = 0x004f, |
95 | | TrackNumber = 0x0057, |
96 | | CueReference = 0x005b, |
97 | | Video = 0x0060, |
98 | | Audio = 0x0061, |
99 | | Timecode = 0x0067, |
100 | | TimeSlice = 0x0068, |
101 | | CueCodecState = 0x006a, |
102 | | CueRefCodecState = 0x006b, |
103 | | Void = 0x006c, |
104 | | BlockAddID = 0x006e, |
105 | | CueClusterPosition = 0x0071, |
106 | | CueTrack = 0x0077, |
107 | | ReferencePriority = 0x007a, |
108 | | ReferenceBlock = 0x007b, |
109 | | ReferenceVirtual = 0x007d, |
110 | | Xmp_video_ContentCompressAlgo = 0x0254, |
111 | | ContentCompressionSettings = 0x0255, |
112 | | Xmp_video_DocType = 0x0282, |
113 | | Xmp_video_DocTypeReadVersion = 0x0285, |
114 | | Xmp_video_EBMLVersion = 0x0286, |
115 | | Xmp_video_DocTypeVersion = 0x0287, |
116 | | EBMLMaxIDLength = 0x02f2, |
117 | | EBMLMaxSizeLength = 0x02f3, |
118 | | Xmp_video_EBMLReadVersion = 0x02f7, |
119 | | ChapterLanguage = 0x037c, |
120 | | ChapterCountry = 0x037e, |
121 | | SegmentFamily = 0x0444, |
122 | | Xmp_video_DateUTC = 0x0461, |
123 | | Xmp_video_TagLanguage = 0x047a, |
124 | | Xmp_video_TagDefault = 0x0484, |
125 | | TagBinary = 0x0485, |
126 | | Xmp_video_TagString = 0x0487, |
127 | | Xmp_video_Duration = 0x0489, |
128 | | ChapterProcessPrivate = 0x050d, |
129 | | ChapterFlagEnabled = 0x0598, |
130 | | Xmp_video_TagName = 0x05a3, |
131 | | EditionEntry = 0x05b9, |
132 | | EditionUID = 0x05bc, |
133 | | EditionFlagHidden = 0x05bd, |
134 | | EditionFlagDefault = 0x05db, |
135 | | EditionFlagOrdered = 0x05dd, |
136 | | Xmp_video_AttachFileData = 0x065c, |
137 | | Xmp_video_AttachFileMIME = 0x0660, |
138 | | Xmp_video_AttachFileName = 0x066e, |
139 | | AttachedFileReferral = 0x0675, |
140 | | Xmp_video_AttachFileDesc = 0x067e, |
141 | | Xmp_video_AttachFileUID = 0x06ae, |
142 | | Xmp_video_ContentEncryptAlgo = 0x07e1, |
143 | | ContentEncryptionKeyID = 0x07e2, |
144 | | ContentSignature = 0x07e3, |
145 | | ContentSignatureKeyID = 0x07e4, |
146 | | Xmp_video_ContentSignAlgo_1 = 0x07e5, |
147 | | Xmp_video_ContentSignHashAlgo_1 = 0x07e6, |
148 | | Xmp_video_MuxingApp = 0x0d80, |
149 | | Seek = 0x0dbb, |
150 | | ContentEncodingOrder = 0x1031, |
151 | | ContentEncodingScope = 0x1032, |
152 | | Xmp_video_ContentEncodingType = 0x1033, |
153 | | ContentCompression = 0x1034, |
154 | | ContentEncryption = 0x1035, |
155 | | CueRefNumber = 0x135f, |
156 | | Xmp_video_TrackName = 0x136e, |
157 | | CueBlockNumber = 0x1378, |
158 | | TrackOffset = 0x137f, |
159 | | SeekID = 0x13ab, |
160 | | SeekPosition = 0x13ac, |
161 | | Stereo3DMode = 0x13b8, |
162 | | Xmp_video_CropBottom = 0x14aa, |
163 | | Xmp_video_Width_2 = 0x14b0, |
164 | | Xmp_video_DisplayUnit = 0x14b2, |
165 | | Xmp_video_AspectRatioType = 0x14b3, |
166 | | Xmp_video_Height_2 = 0x14ba, |
167 | | Xmp_video_CropTop = 0x14bb, |
168 | | Xmp_video_CropLeft = 0x14cc, |
169 | | Xmp_video_CropRight = 0x14dd, |
170 | | TrackForced = 0x15aa, |
171 | | MaxBlockAdditionID = 0x15ee, |
172 | | Xmp_video_WritingApp = 0x1741, |
173 | | SilentTracks = 0x1854, |
174 | | SilentTrackNumber = 0x18d7, |
175 | | AttachedFile = 0x21a7, |
176 | | ContentEncoding = 0x2240, |
177 | | Xmp_audio_BitsPerSample = 0x2264, |
178 | | CodecPrivate = 0x23a2, |
179 | | Targets = 0x23c0, |
180 | | Xmp_video_PhysicalEquivalent = 0x23c3, |
181 | | TagChapterUID = 0x23c4, |
182 | | TagTrackUID = 0x23c5, |
183 | | TagAttachmentUID = 0x23c6, |
184 | | TagEditionUID = 0x23c9, |
185 | | Xmp_video_TargetType = 0x23ca, |
186 | | SignedElement = 0x2532, |
187 | | TrackTranslate = 0x2624, |
188 | | TrackTranslateTrackID = 0x26a5, |
189 | | TrackTranslateCodec = 0x26bf, |
190 | | TrackTranslateEditionUID = 0x26fc, |
191 | | SimpleTag = 0x27c8, |
192 | | TargetTypeValue = 0x28ca, |
193 | | ChapterProcessCommand = 0x2911, |
194 | | ChapterProcessTime = 0x2922, |
195 | | ChapterTranslate = 0x2924, |
196 | | ChapterProcessData = 0x2933, |
197 | | ChapterProcess = 0x2944, |
198 | | ChapterProcessCodecID = 0x2955, |
199 | | ChapterTranslateID = 0x29a5, |
200 | | Xmp_video_TranslateCodec = 0x29bf, |
201 | | ChapterTranslateEditionUID = 0x29fc, |
202 | | ContentEncodings = 0x2d80, |
203 | | MinCache = 0x2de7, |
204 | | MaxCache = 0x2df8, |
205 | | ChapterSegmentUID = 0x2e67, |
206 | | ChapterSegmentEditionUID = 0x2ebc, |
207 | | TrackOverlay = 0x2fab, |
208 | | Tag = 0x3373, |
209 | | SegmentFileName = 0x3384, |
210 | | SegmentUID = 0x33a4, |
211 | | ChapterUID = 0x33c4, |
212 | | TrackUID = 0x33c5, |
213 | | TrackAttachmentUID = 0x3446, |
214 | | BlockAdditions = 0x35a1, |
215 | | Xmp_audio_OutputSampleRate = 0x38b5, |
216 | | Xmp_video_Title = 0x3ba9, |
217 | | ChannelPositions = 0x3d7b, |
218 | | SignatureElements = 0x3e5b, |
219 | | SignatureElementList = 0x3e7b, |
220 | | Xmp_video_ContentSignAlgo_2 = 0x3e8a, |
221 | | Xmp_video_ContentSignHashAlgo_2 = 0x3e9a, |
222 | | SignaturePublicKey = 0x3ea5, |
223 | | Signature = 0x3eb5, |
224 | | TrackLanguage = 0x2b59c, |
225 | | TrackTimecodeScale = 0x3314f, |
226 | | Xmp_video_FrameRate = 0x383e3, |
227 | | VideoFrameRate_DefaultDuration = 0x3e383, |
228 | | Video_Audio_CodecName = 0x58688, |
229 | | CodecDownloadURL = 0x6b240, |
230 | | TimecodeScale = 0xad7b1, |
231 | | ColorSpace = 0xeb524, |
232 | | Xmp_video_OpColor = 0xfb523, |
233 | | CodecSettings = 0x1a9697, |
234 | | CodecInfoURL = 0x1b4040, |
235 | | PrevFileName = 0x1c83ab, |
236 | | PrevUID = 0x1cb923, |
237 | | NextFileName = 0x1e83bb, |
238 | | NextUID = 0x1eb923, |
239 | | Chapters = 0x43a770, |
240 | | SeekHead = 0x14d9b74, |
241 | | Tags = 0x254c367, |
242 | | Info = 0x549a966, |
243 | | Tracks = 0x654ae6b, |
244 | | SegmentHeader = 0x8538067, |
245 | | Attachments = 0x941a469, |
246 | | EBMLHeader = 0xa45dfa3, |
247 | | SignatureSlot = 0xb538667, |
248 | | Cues = 0xc53bb6b, |
249 | | Cluster = 0xf43b675 |
250 | | }; |
251 | | |
252 | | const MatroskaTag matroskaTags[]{ |
253 | | {ChapterDisplay, "ChapterDisplay", Master, Composite}, |
254 | | {TrackType, "TrackType", Boolean, Process}, |
255 | | {ChapterString, "ChapterString", String, Skip}, |
256 | | {Video_Audio_CodecID, "Video.Audio.CodecID", InternalField, Skip}, // process |
257 | | {TrackDefault, "TrackDefault", Boolean, Process}, |
258 | | {ChapterTrackNumber, "ChapterTrackNumber", UInteger, Skip}, |
259 | | {Slices, "Slices", Master, Composite}, |
260 | | {ChapterTrack, "ChapterTrack", Master, Composite}, |
261 | | {ChapterTimeStart, "ChapterTimeStart", UInteger, Skip}, |
262 | | {ChapterTimeEnd, "ChapterTimeEnd", UInteger, Skip}, |
263 | | {CueRefTime, "CueRefTime", UInteger, Skip}, |
264 | | {CueRefCluster, "CueRefCluster", UInteger, Skip}, |
265 | | {ChapterFlagHidden, "ChapterFlagHidden", UInteger, Skip}, |
266 | | {Xmp_video_VideoScanTpye, "Xmp.video.VideoScanTpye", InternalField, Process}, |
267 | | {BlockDuration, "BlockDuration", UInteger, Skip}, |
268 | | {TrackLacing, "TrackLacing", Boolean, Process}, |
269 | | {Xmp_audio_ChannelType, "Xmp.audio.ChannelType", InternalField, Process}, |
270 | | {BlockGroup, "BlockGroup", Master, Composite}, |
271 | | {Block, "Block", Binary, Skip}, |
272 | | {BlockVirtual, "BlockVirtual", Binary, Skip}, |
273 | | {SimpleBlock, "SimpleBlock", Binary, Skip}, |
274 | | {CodecState, "CodecState", Binary, Skip}, |
275 | | {BlockAdditional, "BlockAdditional", UInteger, Skip}, |
276 | | {BlockMore, "BlockMore", Master, Composite}, |
277 | | {Position, "Position", UInteger, Skip}, |
278 | | {CodecDecodeAll, "CodecDecodeAll", Boolean, Process}, |
279 | | {PrevSize, "PrevSize", UInteger, Skip}, |
280 | | {TrackEntry, "TrackEntry", Master, Composite}, |
281 | | {EncryptedBlock, "EncryptedBlock", Binary, Skip}, |
282 | | {Xmp_video_Width_1, "Xmp.video.Width", UInteger, Process}, |
283 | | {CueTime, "CueTime", UInteger, Skip}, |
284 | | {Xmp_audio_SampleRate, "Xmp.audio.SampleRate", Float, Process}, |
285 | | {ChapterAtom, "ChapterAtom", Master, Composite}, |
286 | | {CueTrackPositions, "CueTrackPositions", Master, Composite}, |
287 | | {TrackUsed, "TrackUsed", Boolean, Process}, |
288 | | {Xmp_video_Height_1, "Xmp.video.Height", Integer, Process}, |
289 | | {CuePoint, "CuePoint", Master, Composite}, |
290 | | {CRC_32, "CRC_32", Binary, Skip}, |
291 | | {BlockAdditionalID, "BlockAdditionalID", UInteger, Skip}, |
292 | | {LaceNumber, "LaceNumber", UInteger, Skip}, |
293 | | {FrameNumber, "FrameNumber", UInteger, Skip}, |
294 | | {Delay, "Delay", UInteger, Skip}, |
295 | | {ClusterDuration, "ClusterDuration", Float, Skip}, |
296 | | {TrackNumber, "Xmp.video.TotalStream", String, Process}, |
297 | | {CueReference, "CueReference", Master, Composite}, |
298 | | {Video, "Video", Master, Composite}, |
299 | | {Audio, "Audio", Master, Composite}, |
300 | | {Timecode, "Timecode", UInteger, Skip}, |
301 | | {TimeSlice, "TimeSlice", Master, Composite}, |
302 | | {CueCodecState, "CueCodecState", UInteger, Skip}, |
303 | | {CueRefCodecState, "CueRefCodecState", UInteger, Skip}, |
304 | | {Void, "Void", Binary, Skip}, |
305 | | {BlockAddID, "BlockAddID", UInteger, Skip}, |
306 | | {CueClusterPosition, "CueClusterPosition", UInteger, Skip}, |
307 | | {CueTrack, "CueTrack", UInteger, Skip}, |
308 | | {ReferencePriority, "ReferencePriority", UInteger, Skip}, |
309 | | {ReferenceBlock, "ReferenceBlock", Integer, Skip}, |
310 | | {ReferenceVirtual, "ReferenceVirtual", Integer, Skip}, |
311 | | {Xmp_video_ContentCompressAlgo, "Xmp.video.ContentCompressAlgo", InternalField, Process}, |
312 | | {ContentCompressionSettings, "ContentCompressionSettings", Binary, Skip}, |
313 | | {Xmp_video_DocType, "Xmp.video.DocType", String, Process}, |
314 | | {Xmp_video_DocTypeReadVersion, "Xmp.video.DocTypeReadVersion", Integer, Process}, |
315 | | {Xmp_video_EBMLVersion, "Xmp.video.EBMLVersion", Integer, Process}, |
316 | | {Xmp_video_DocTypeVersion, "Xmp.video.DocTypeVersion", Integer, Process}, |
317 | | {EBMLMaxIDLength, "EBMLMaxIDLength", UInteger, Skip}, |
318 | | {EBMLMaxSizeLength, "EBMLMaxSizeLength", UInteger, Skip}, |
319 | | {Xmp_video_EBMLReadVersion, "Xmp.video.EBMLReadVersion", UInteger, Process}, |
320 | | {ChapterLanguage, "ChapterLanguage", String, Skip}, |
321 | | {ChapterCountry, "ChapterCountry", Utf8, Skip}, |
322 | | {SegmentFamily, "SegmentFamily", Binary, Skip}, |
323 | | {Xmp_video_DateUTC, "Xmp.video.DateUTC", Date, Process}, |
324 | | {Xmp_video_TagLanguage, "Xmp.video.TagLanguage", String, Process}, |
325 | | {Xmp_video_TagDefault, "Xmp.video.TagDefault", Boolean, Process}, |
326 | | {TagBinary, "TagBinary", Binary, Skip}, |
327 | | {Xmp_video_TagString, "Xmp.video.TagString", String, Process}, |
328 | | {Xmp_video_Duration, "Xmp.video.Duration", Date, Process}, |
329 | | {ChapterProcessPrivate, "ChapterProcessPrivate", Master, Skip}, |
330 | | {ChapterFlagEnabled, "ChapterFlagEnabled", Boolean, Skip}, |
331 | | {Xmp_video_TagName, "Xmp.video.TagName", String, Process}, |
332 | | {EditionEntry, "EditionEntry", Master, Composite}, |
333 | | {EditionUID, "EditionUID", UInteger, Skip}, |
334 | | {EditionFlagHidden, "EditionFlagHidden", Boolean, Skip}, |
335 | | {EditionFlagDefault, "EditionFlagDefault", Boolean, Skip}, |
336 | | {EditionFlagOrdered, "EditionFlagOrdered", Boolean, Skip}, |
337 | | {Xmp_video_AttachFileData, "Xmp.video.AttachFileData", String, Process}, |
338 | | {Xmp_video_AttachFileMIME, "Xmp.video.AttachFileMIME", String, Process}, |
339 | | {Xmp_video_AttachFileName, "Xmp.video.AttachFileName", String, Process}, |
340 | | {AttachedFileReferral, "AttachedFileReferral", Binary, Skip}, |
341 | | {Xmp_video_AttachFileDesc, "Xmp.video.AttachFileDesc", String, Process}, |
342 | | {Xmp_video_AttachFileUID, "Xmp.video.AttachFileUID", UInteger, Process}, |
343 | | {Xmp_video_ContentEncryptAlgo, "Xmp.video.ContentEncryptAlgo", InternalField, Process}, |
344 | | {ContentEncryptionKeyID, "ContentEncryptionKeyID", Binary, Skip}, |
345 | | {ContentSignature, "ContentSignature", Binary, Skip}, |
346 | | {ContentSignatureKeyID, "ContentSignatureKeyID", Binary, Skip}, |
347 | | {Xmp_video_ContentSignAlgo_1, "Xmp.video.ContentSignAlgo", InternalField, Process}, |
348 | | {Xmp_video_ContentSignHashAlgo_1, "Xmp.video.ContentSignHashAlgo", InternalField, Process}, |
349 | | {Xmp_video_MuxingApp, "Xmp.video.MuxingApp", String, Process}, |
350 | | {Seek, "Seek", Master, Composite}, |
351 | | {ContentEncodingOrder, "ContentEncodingOrder", UInteger, Skip}, |
352 | | {ContentEncodingScope, "ContentEncodingScope", UInteger, Skip}, |
353 | | {Xmp_video_ContentEncodingType, "Xmp.video.ContentEncodingType", InternalField, Process}, |
354 | | {ContentCompression, "ContentCompression", Master, Composite}, |
355 | | {ContentEncryption, "ContentEncryption", Master, Composite}, |
356 | | {CueRefNumber, "CueRefNumber", UInteger, Skip}, |
357 | | {Xmp_video_TrackName, "Xmp.video.TrackName", String, Process}, |
358 | | {CueBlockNumber, "CueBlockNumber", UInteger, Skip}, |
359 | | {TrackOffset, "TrackOffset", Integer, Skip}, |
360 | | {SeekID, "SeekID", Binary, Skip}, |
361 | | {SeekPosition, "SeekPosition", UInteger, Skip}, |
362 | | {Stereo3DMode, "Stereo3DMode", UInteger, Skip}, |
363 | | {Xmp_video_CropBottom, "Xmp.video.CropBottom", Integer, Process}, |
364 | | {Xmp_video_Width_2, "Xmp.video.Width", Integer, Process}, |
365 | | {Xmp_video_DisplayUnit, "Xmp.video.DisplayUnit", InternalField, Process}, |
366 | | {Xmp_video_AspectRatioType, "Xmp.video.AspectRatioType", InternalField, Process}, |
367 | | {Xmp_video_Height_2, "Xmp.video.Height", Integer, Process}, |
368 | | {Xmp_video_CropTop, "Xmp.video.CropTop", Integer, Process}, |
369 | | {Xmp_video_CropLeft, "Xmp.video.CropLeft", Integer, Process}, |
370 | | {Xmp_video_CropRight, "Xmp.video.CropRight", Integer, Process}, |
371 | | {TrackForced, "TrackForced", Boolean, Process}, |
372 | | {MaxBlockAdditionID, "MaxBlockAdditionID", UInteger, Skip}, |
373 | | {Xmp_video_WritingApp, "Xmp.video.WritingApp", String, Process}, |
374 | | {SilentTracks, "SilentTracks", Master, Composite}, |
375 | | {SilentTrackNumber, "SilentTrackNumber", UInteger, Skip}, |
376 | | {AttachedFile, "AttachedFile", Master, Composite}, |
377 | | {ContentEncoding, "ContentEncoding", Master, Composite}, |
378 | | {Xmp_audio_BitsPerSample, "Xmp.audio.BitsPerSample", Integer, Process}, |
379 | | {CodecPrivate, "CodecPrivate", Binary, Skip}, |
380 | | {Targets, "Targets", Master, Composite}, |
381 | | {Xmp_video_PhysicalEquivalent, "Xmp.video.PhysicalEquivalent", InternalField, Process}, |
382 | | {TagChapterUID, "TagChapterUID", UInteger, Skip}, |
383 | | {TagTrackUID, "TagTrackUID", UInteger, Skip}, |
384 | | {TagAttachmentUID, "TagAttachmentUID", UInteger, Skip}, |
385 | | {TagEditionUID, "TagEditionUID", UInteger, Skip}, |
386 | | {Xmp_video_TargetType, "Xmp.video.TargetType", String, Process}, |
387 | | {SignedElement, "SignedElement", Binary, Skip}, |
388 | | {TrackTranslate, "TrackTranslate", Master, Composite}, |
389 | | {TrackTranslateTrackID, "TrackTranslateTrackID", Binary, Skip}, |
390 | | {TrackTranslateCodec, "TrackTranslateCodec", UInteger, Skip}, |
391 | | {TrackTranslateEditionUID, "TrackTranslateEditionUID", UInteger, Skip}, |
392 | | {SimpleTag, "SimpleTag", Master, Composite}, |
393 | | {TargetTypeValue, "TargetTypeValue", UInteger, Skip}, |
394 | | {ChapterProcessCommand, "ChapterProcessCommand", Master, Composite}, |
395 | | {ChapterProcessTime, "ChapterProcessTime", UInteger, Skip}, |
396 | | {ChapterTranslate, "ChapterTranslate", Master, Composite}, |
397 | | {ChapterProcessData, "ChapterProcessData", Binary, Skip}, |
398 | | {ChapterProcess, "ChapterProcess", Master, Composite}, |
399 | | {ChapterProcessCodecID, "ChapterProcessCodecID", UInteger, Skip}, |
400 | | {ChapterTranslateID, "ChapterTranslateID", Binary, Skip}, |
401 | | {Xmp_video_TranslateCodec, "Xmp.video.TranslateCodec", InternalField, Process}, |
402 | | {ChapterTranslateEditionUID, "ChapterTranslateEditionUID", UInteger, Skip}, |
403 | | {ContentEncodings, "ContentEncodings", Master, Composite}, |
404 | | {MinCache, "MinCache", UInteger, Skip}, |
405 | | {MaxCache, "MaxCache", UInteger, Skip}, |
406 | | {ChapterSegmentUID, "ChapterSegmentUID", Binary, Skip}, |
407 | | {ChapterSegmentEditionUID, "ChapterSegmentEditionUID", UInteger, Skip}, |
408 | | {TrackOverlay, "TrackOverlay", UInteger, Skip}, |
409 | | {Tag, "Tag", Master, Composite}, |
410 | | {SegmentFileName, "SegmentFileName", Utf8, Skip}, |
411 | | {SegmentUID, "SegmentUID", Binary, Skip}, |
412 | | {ChapterUID, "ChapterUID", UInteger, Skip}, |
413 | | {TrackUID, "TrackUID", UInteger, Skip}, |
414 | | {TrackAttachmentUID, "TrackAttachmentUID", UInteger, Skip}, |
415 | | {BlockAdditions, "BlockAdditions", Master, Composite}, |
416 | | {Xmp_audio_OutputSampleRate, "Xmp.audio.OutputSampleRate", Float, Process}, |
417 | | {Xmp_video_Title, "Xmp.video.Title", String, Process}, |
418 | | {ChannelPositions, "ChannelPositions", Binary, Skip}, |
419 | | {SignatureElements, "SignatureElements", Master, Composite}, |
420 | | {SignatureElementList, "SignatureElementList", Master, Composite}, |
421 | | {Xmp_video_ContentSignAlgo_2, "Xmp.video.ContentSignAlgo", InternalField, Process}, |
422 | | {Xmp_video_ContentSignHashAlgo_2, "Xmp.video.ContentSignHashAlgo", InternalField, Process}, |
423 | | {SignaturePublicKey, "SignaturePublicKey", Binary, Skip}, |
424 | | {Signature, "Signature", Binary, Skip}, |
425 | | {TrackLanguage, "TrackLanguage", String, |
426 | | Skip}, // Process : see values here https://www.loc.gov/standards/iso639-2/php/code_list.php |
427 | | {TrackTimecodeScale, "TrackTimecodeScale", Float, Skip}, |
428 | | {Xmp_video_FrameRate, "Xmp.video.FrameRate", Float, Process}, |
429 | | {VideoFrameRate_DefaultDuration, "VideoFrameRate.DefaultDuration", Float, Skip}, |
430 | | {Video_Audio_CodecName, "Video.Audio.CodecName", InternalField, Process}, |
431 | | {CodecDownloadURL, "CodecDownloadURL", InternalField, Process}, |
432 | | {TimecodeScale, "Xmp.video.TimecodeScale", Date, Process}, |
433 | | {ColorSpace, "ColorSpace", String, Process}, |
434 | | {Xmp_video_OpColor, "Xmp.video.OpColor", Float, Skip}, |
435 | | {CodecSettings, "CodecSettings", Boolean, Process}, |
436 | | {CodecInfoURL, "CodecInfoURL", InternalField, Process}, |
437 | | {PrevFileName, "PrevFileName", Utf8, Skip}, |
438 | | {PrevUID, "PrevUID", Binary, Skip}, |
439 | | {NextFileName, "NextFileName", Utf8, Skip}, |
440 | | {NextUID, "NextUID", Binary, Skip}, |
441 | | {Chapters, "Chapters", Master, Skip}, |
442 | | {SeekHead, "SeekHead", Master, Composite}, |
443 | | {Tags, "Tags", Master, Composite}, |
444 | | {Info, "Info", Master, Composite}, |
445 | | {Tracks, "Tracks", Master, Composite}, |
446 | | {SegmentHeader, "SegmentHeader", Master, Composite}, |
447 | | {Attachments, "Attachments", Master, Composite}, |
448 | | {EBMLHeader, "EBMLHeader", Master, Composite}, |
449 | | {SignatureSlot, "SignatureSlot", Master, Composite}, |
450 | | {Cues, "Cues", Master, Composite}, |
451 | | {Cluster, "Cluster", Master, Composite}, |
452 | | }; |
453 | | |
454 | | const MatroskaTag matroskaTrackType[] = { |
455 | | {0x1, "Video"}, {0x2, "Audio"}, {0x3, "Complex"}, {0x10, "Logo"}, |
456 | | {0x11, "Subtitle"}, {0x12, "Buttons"}, {0x20, "Control"}, |
457 | | }; |
458 | | |
459 | | const MatroskaTag compressionAlgorithm[] = { |
460 | | {0, "zlib "}, |
461 | | {1, "bzlib"}, |
462 | | {2, "lzo1x"}, |
463 | | {3, "Header Stripping"}, |
464 | | }; |
465 | | |
466 | | const MatroskaTag audioChannels[] = { |
467 | | {1, "Mono"}, |
468 | | {2, "Stereo"}, |
469 | | {5, "5.1 Surround Sound"}, |
470 | | {7, "7.1 Surround Sound"}, |
471 | | }; |
472 | | |
473 | | const MatroskaTag displayUnit[] = { |
474 | | {0x0, "Pixels"}, {0x1, "cm"}, {0x2, "inches"}, {0x3, "display aspect ratio"}, {0x2, "unknown"}, |
475 | | }; |
476 | | |
477 | | const MatroskaTag encryptionAlgorithm[] = { |
478 | | {0, "Not Encrypted"}, {1, "DES"}, {2, "3DES"}, {3, "Twofish"}, {4, "Blowfish"}, {5, "AES"}, |
479 | | }; |
480 | | |
481 | | const MatroskaTag chapterPhysicalEquivalent[] = { |
482 | | {10, "Index"}, {20, "Track"}, {30, "Session"}, {40, "Layer"}, {50, "Side"}, {60, "CD / DVD"}, {70, "Set / Package"}, |
483 | | }; |
484 | | |
485 | | const MatroskaTag encodingType[] = { |
486 | | {0, "Compression"}, |
487 | | {1, "Encryption"}, |
488 | | }; |
489 | | |
490 | | const MatroskaTag videoScanType[] = { |
491 | | {0, "Progressive"}, |
492 | | {1, "Interlaced"}, |
493 | | }; |
494 | | |
495 | | const MatroskaTag chapterTranslateCodec[] = { |
496 | | {0, "Matroska Script"}, |
497 | | {1, "DVD Menu"}, |
498 | | }; |
499 | | |
500 | | const MatroskaTag aspectRatioType[] = { |
501 | | {0, "Free Resizing"}, |
502 | | {1, "Keep Aspect Ratio"}, |
503 | | {2, "Fixed"}, |
504 | | }; |
505 | | |
506 | | const MatroskaTag contentSignatureAlgorithm[] = { |
507 | | {0, "Not Signed"}, |
508 | | {1, "RSA"}, |
509 | | }; |
510 | | |
511 | | const MatroskaTag contentSignatureHashAlgorithm[] = { |
512 | | {0, "Not Signed"}, |
513 | | {1, "SHA1-160"}, |
514 | | {2, "MD5"}, |
515 | | }; |
516 | | |
517 | | const MatroskaTag trackEnable[] = { |
518 | | {0x1, "Xmp.video.Enabled"}, |
519 | | {0x2, "Xmp.audio.Enabled"}, |
520 | | {0x11, "Xmp.video.SubTEnabled"}, |
521 | | }; |
522 | | |
523 | | const MatroskaTag defaultOn[] = { |
524 | | {0x1, "Xmp.video.DefaultOn"}, |
525 | | {0x2, "Xmp.audio.DefaultOn"}, |
526 | | {0x11, "Xmp.video.SubTDefaultOn"}, |
527 | | }; |
528 | | |
529 | | const MatroskaTag trackForced[] = { |
530 | | {0x1, "Xmp.video.TrackForced"}, |
531 | | {0x2, "Xmp.audio.TrackForced"}, |
532 | | {0x11, "Xmp.video.SubTTrackForced"}, |
533 | | }; |
534 | | |
535 | | const MatroskaTag trackLacing[] = { |
536 | | {0x1, "Xmp.video.TrackLacing"}, |
537 | | {0x2, "Xmp.audio.TrackLacing"}, |
538 | | {0x11, "Xmp.video.SubTTrackLacing"}, |
539 | | }; |
540 | | |
541 | | const MatroskaTag codecDecodeAll[] = { |
542 | | {0x1, "Xmp.video.CodecDecodeAll"}, |
543 | | {0x2, "Xmp.audio.CodecDecodeAll"}, |
544 | | {0x11, "Xmp.video.SubTCodecDecodeAll"}, |
545 | | }; |
546 | | |
547 | | const MatroskaTag codecDownloadUrl[] = { |
548 | | {0x1, "Xmp.video.CodecDownloadUrl"}, |
549 | | {0x2, "Xmp.audio.CodecDownloadUrl"}, |
550 | | {0x11, "Xmp.video.SubTCodecDownloadUrl"}, |
551 | | }; |
552 | | |
553 | | const MatroskaTag codecSettings[] = { |
554 | | {0x1, "Xmp.video.CodecSettings"}, |
555 | | {0x2, "Xmp.audio.CodecSettings"}, |
556 | | {0x11, "Xmp.video.SubTCodecSettings"}, |
557 | | }; |
558 | | |
559 | | const MatroskaTag trackCodec[] = { |
560 | | {0x1, "Xmp.video.Codec"}, |
561 | | {0x2, "Xmp.audio.Compressor"}, |
562 | | {0x11, "Xmp.video.SubTCodec"}, |
563 | | }; |
564 | | |
565 | | const MatroskaTag codecInfo[] = { |
566 | | {0x1, "Xmp.video.CodecInfo"}, |
567 | | {0x2, "Xmp.audio.CodecInfo"}, |
568 | | {0x11, "Xmp.video.SubTCodecInfo"}, |
569 | | }; |
570 | | |
571 | | const MatroskaTag streamRate[] = { |
572 | | {0x1, "Xmp.video.FrameRate"}, |
573 | | {0x2, "Xmp.audio.DefaultDuration"}, |
574 | | }; |
575 | | |
576 | | /*! |
577 | | @brief Function used to calculate Tags, Tags may comprise of more than |
578 | | one byte. The first byte calculates size of the Tag and the remaining |
579 | | bytes are used to calculate the rest of the Tag. |
580 | | Returns Tag Value. |
581 | | */ |
582 | 14.8k | [[nodiscard]] static size_t returnTagValue(const byte* buf, size_t size) { |
583 | 14.8k | enforce(size > 0 && size <= 8, Exiv2::ErrorCode::kerCorruptedMetadata); |
584 | | |
585 | 14.8k | size_t b0 = buf[0] & (0xff >> size); |
586 | 14.8k | size_t tag = b0 << ((size - 1) * 8); |
587 | 17.4k | for (size_t i = 1; i < size; ++i) { |
588 | 2.63k | tag |= static_cast<size_t>(buf[i]) << ((size - i - 1) * 8); |
589 | 2.63k | } |
590 | | |
591 | 14.8k | return tag; |
592 | 14.8k | } |
593 | | } // namespace Exiv2::Internal |
594 | | |
595 | | namespace Exiv2 { |
596 | | |
597 | | using namespace Exiv2::Internal; |
598 | | |
599 | | MatroskaVideo::MatroskaVideo(BasicIo::UniquePtr io, const ImageCtorParams& params) : |
600 | 142 | Image(ImageType::mkv, mdNone, std::move(io), params) { |
601 | 142 | } // MatroskaVideo::MatroskaVideo |
602 | | |
603 | 142 | std::string MatroskaVideo::mimeType() const { |
604 | 142 | return "video/matroska"; |
605 | 142 | } |
606 | | |
607 | 0 | void MatroskaVideo::writeMetadata() { |
608 | 0 | } |
609 | | |
610 | 142 | void MatroskaVideo::readMetadata() { |
611 | 142 | if (io_->open() != 0) |
612 | 0 | throw Error(ErrorCode::kerDataSourceOpenFailed, io_->path(), strError()); |
613 | | |
614 | | // Ensure that this is the correct image type |
615 | 142 | if (!isMkvType(*io_, false)) { |
616 | 0 | if (io_->error() || io_->eof()) |
617 | 0 | throw Error(ErrorCode::kerFailedToReadImageData); |
618 | 0 | throw Error(ErrorCode::kerNotAnImage, "Matroska"); |
619 | 0 | } |
620 | | |
621 | 142 | IoCloser closer(*io_); |
622 | 142 | clearMetadata(); |
623 | 142 | continueTraversing_ = true; |
624 | 142 | height_ = width_ = 1; |
625 | | |
626 | 142 | xmpData_["Xmp.video.FileSize"] = io_->size() / bytesMB; |
627 | 142 | xmpData_["Xmp.video.MimeType"] = mimeType(); |
628 | | |
629 | 7.63k | while (continueTraversing_) |
630 | 7.49k | decodeBlock(); |
631 | | |
632 | 142 | xmpData_["Xmp.video.AspectRatio"] = getAspectRatio(width_, height_); |
633 | 142 | } |
634 | | |
635 | 7.49k | void MatroskaVideo::decodeBlock() { |
636 | 7.49k | byte buf[8]; |
637 | 7.49k | io_->read(buf, 1); |
638 | | |
639 | 7.49k | if (io_->eof()) { |
640 | 5 | continueTraversing_ = false; |
641 | 5 | return; |
642 | 5 | } |
643 | | |
644 | 7.48k | uint32_t block_size = findBlockSize(buf[0]); // 0-8 |
645 | 7.48k | if (block_size > 0) |
646 | 7.46k | io_->readOrThrow(buf + 1, block_size - 1, ErrorCode::kerCorruptedMetadata); |
647 | | |
648 | 7.48k | auto tag_id = returnTagValue(buf, block_size); |
649 | 7.48k | const MatroskaTag* tag = Exiv2::find(matroskaTags, tag_id); |
650 | | |
651 | 7.48k | if (!tag) { |
652 | 82 | continueTraversing_ = false; |
653 | 82 | return; |
654 | 82 | } |
655 | | |
656 | | // tag->dump(std::cout); |
657 | | |
658 | 7.40k | if (tag->_id == Cues || tag->_id == Cluster) { |
659 | 9 | continueTraversing_ = false; |
660 | 9 | return; |
661 | 9 | } |
662 | | |
663 | 7.39k | io_->readOrThrow(buf, 1, ErrorCode::kerCorruptedMetadata); |
664 | 7.39k | block_size = findBlockSize(buf[0]); // 0-8 |
665 | | |
666 | 7.39k | if (block_size > 0) |
667 | 7.37k | io_->readOrThrow(buf + 1, block_size - 1, ErrorCode::kerCorruptedMetadata); |
668 | 7.39k | size_t size = returnTagValue(buf, block_size); |
669 | | |
670 | 7.39k | if (tag->isComposite() && !tag->isSkipped()) |
671 | 3.62k | return; |
672 | | |
673 | 3.77k | const size_t bufMaxSize = 200; |
674 | | |
675 | 3.77k | #ifndef SUPPRESS_WARNINGS |
676 | 3.77k | if (!tag->isSkipped() && size > bufMaxSize) { |
677 | 17 | EXV_WARNING << "Size " << size << " of Matroska tag 0x" << std::hex << tag->_id << std::dec << " is greater than " |
678 | 17 | << bufMaxSize << ": ignoring it.\n"; |
679 | 17 | } |
680 | 3.77k | #endif |
681 | 3.77k | if (tag->isSkipped() || size > bufMaxSize) { |
682 | 483 | io_->seek(size, BasicIo::cur); |
683 | 483 | return; |
684 | 483 | } |
685 | | |
686 | 3.29k | DataBuf buf2(bufMaxSize + 1); |
687 | 3.29k | io_->readOrThrow(buf2.data(), size, ErrorCode::kerCorruptedMetadata); |
688 | 3.29k | switch (tag->_type) { |
689 | 559 | case InternalField: |
690 | 559 | decodeInternalTags(tag, buf2.data()); |
691 | 559 | break; |
692 | 351 | case String: |
693 | 351 | case Utf8: |
694 | 351 | decodeStringTags(tag, buf2.data()); |
695 | 351 | break; |
696 | 146 | case Integer: |
697 | 176 | case UInteger: |
698 | 176 | decodeIntegerTags(tag, buf2.data()); |
699 | 176 | break; |
700 | 1.02k | case Boolean: |
701 | 1.02k | decodeBooleanTags(tag, buf2.data()); |
702 | 1.02k | break; |
703 | 31 | case Date: |
704 | 31 | decodeDateTags(tag, buf2.data(), size); |
705 | 31 | break; |
706 | 1.10k | case Float: |
707 | 1.10k | decodeFloatTags(tag, buf2.data()); |
708 | 1.10k | break; |
709 | 0 | case Binary: |
710 | 0 | break; |
711 | 0 | case Master: |
712 | 0 | break; |
713 | 0 | default: |
714 | 0 | break; |
715 | 3.29k | } |
716 | 3.29k | } // MatroskaVideo::decodeBlock |
717 | | |
718 | 559 | void MatroskaVideo::decodeInternalTags(const MatroskaTag* tag, const byte* buf) { |
719 | 559 | uint64_t key = getULongLong(buf, bigEndian); |
720 | 559 | if (!key) |
721 | 1 | return; |
722 | | |
723 | 558 | auto internalMt = [=]() -> const MatroskaTag* { |
724 | 558 | switch (tag->_id) { |
725 | 32 | case Xmp_video_VideoScanTpye: |
726 | 32 | return Exiv2::find(videoScanType, key); |
727 | 79 | case Xmp_audio_ChannelType: |
728 | 79 | return Exiv2::find(audioChannels, key); |
729 | 2 | case Xmp_video_ContentCompressAlgo: |
730 | 2 | return Exiv2::find(compressionAlgorithm, key); |
731 | 2 | case Xmp_video_ContentEncryptAlgo: |
732 | 2 | return Exiv2::find(encryptionAlgorithm, key); |
733 | 0 | case Xmp_video_ContentSignAlgo_1: |
734 | 0 | case Xmp_video_ContentSignAlgo_2: |
735 | 0 | return Exiv2::find(contentSignatureAlgorithm, key); |
736 | 0 | case Xmp_video_ContentSignHashAlgo_1: |
737 | 1 | case Xmp_video_ContentSignHashAlgo_2: |
738 | 1 | return Exiv2::find(contentSignatureHashAlgorithm, key); |
739 | 2 | case Xmp_video_ContentEncodingType: |
740 | 2 | return Exiv2::find(encodingType, key); |
741 | 2 | case Xmp_video_DisplayUnit: |
742 | 2 | return Exiv2::find(displayUnit, key); |
743 | 3 | case Xmp_video_AspectRatioType: |
744 | 3 | return Exiv2::find(aspectRatioType, key); |
745 | 435 | case Xmp_video_PhysicalEquivalent: |
746 | 435 | return Exiv2::find(chapterPhysicalEquivalent, key); |
747 | 0 | case Xmp_video_TranslateCodec: |
748 | 0 | return Exiv2::find(chapterTranslateCodec, key); |
749 | 0 | case Video_Audio_CodecID: |
750 | 0 | return Exiv2::find(trackCodec, key); |
751 | 0 | case Video_Audio_CodecName: |
752 | 0 | return Exiv2::find(codecInfo, key); |
753 | 0 | case CodecDownloadURL: |
754 | 0 | case CodecInfoURL: |
755 | 0 | return Exiv2::find(codecDownloadUrl, key); |
756 | 558 | } |
757 | 0 | return nullptr; |
758 | 558 | }(); |
759 | 558 | if (internalMt) { |
760 | 416 | xmpData_[tag->_label] = internalMt->_label; |
761 | 416 | } else { |
762 | 142 | xmpData_[tag->_label] = key; |
763 | 142 | } |
764 | 558 | } |
765 | | |
766 | 351 | void MatroskaVideo::decodeStringTags(const MatroskaTag* tag, const byte* buf) { |
767 | 351 | if (tag->_id == TrackNumber) { |
768 | 248 | track_count_++; |
769 | 248 | xmpData_[tag->_label] = track_count_; |
770 | 248 | } else { |
771 | 103 | xmpData_[tag->_label] = buf; |
772 | 103 | } |
773 | 351 | } |
774 | | |
775 | 176 | void MatroskaVideo::decodeIntegerTags(const MatroskaTag* tag, const byte* buf) { |
776 | 176 | uint64_t value = getULongLong(buf, bigEndian); |
777 | 176 | if (!value) |
778 | 0 | return; |
779 | | |
780 | 176 | if (tag->_id == Xmp_video_Width_1 || tag->_id == Xmp_video_Width_2) |
781 | 22 | width_ = value; |
782 | 176 | if (tag->_id == Xmp_video_Height_1 || tag->_id == Xmp_video_Height_2) |
783 | 108 | height_ = value; |
784 | 176 | xmpData_[tag->_label] = value; |
785 | 176 | } |
786 | | |
787 | 1.02k | void MatroskaVideo::decodeBooleanTags(const MatroskaTag* tag, const byte* buf) { |
788 | 1.02k | const MatroskaTag* internalMt = nullptr; |
789 | 1.02k | uint64_t key = getULongLong(buf, bigEndian); |
790 | 1.02k | if (!key) |
791 | 60 | return; |
792 | | |
793 | 969 | switch (tag->_id) { |
794 | 341 | case TrackType: // this tags is used internally only to deduce the type of track (video or audio) |
795 | 341 | if (auto f = Exiv2::find(matroskaTrackType, key)) { |
796 | 149 | stream_ = f->_id; |
797 | 149 | } |
798 | 341 | break; |
799 | 274 | case TrackUsed: |
800 | 274 | internalMt = Exiv2::find(trackEnable, key); |
801 | 274 | break; |
802 | 1 | case TrackDefault: |
803 | 1 | internalMt = Exiv2::find(defaultOn, key); |
804 | 1 | break; |
805 | 7 | case TrackForced: |
806 | 7 | internalMt = Exiv2::find(trackForced, key); |
807 | 7 | break; |
808 | 153 | case TrackLacing: |
809 | 153 | internalMt = Exiv2::find(trackLacing, key); |
810 | 153 | break; |
811 | 193 | case CodecDecodeAll: |
812 | 193 | internalMt = Exiv2::find(codecDecodeAll, key); |
813 | 193 | break; |
814 | 0 | case CodecSettings: |
815 | 0 | internalMt = Exiv2::find(codecSettings, key); |
816 | 0 | break; |
817 | 0 | case Xmp_video_TagDefault: |
818 | 0 | internalMt = tag; |
819 | 0 | break; |
820 | 0 | default: |
821 | 0 | break; |
822 | 969 | } |
823 | | |
824 | 969 | if (internalMt) { |
825 | 0 | xmpData_[internalMt->_label] = "Yes"; |
826 | 0 | } |
827 | 969 | } |
828 | | |
829 | 31 | void MatroskaVideo::decodeDateTags(const MatroskaTag* tag, const byte* buf, size_t size) { |
830 | 31 | int64_t duration_in_ms = 0; |
831 | 31 | uint64_t value; |
832 | 31 | switch (tag->_id) { |
833 | 7 | case Xmp_video_Duration: |
834 | 7 | if (size <= 4) { |
835 | 4 | duration_in_ms = std::llround(getFloat(buf, bigEndian) * time_code_scale_ * 1000.0); |
836 | 4 | } else { |
837 | 3 | duration_in_ms = std::llround(getDouble(buf, bigEndian) * time_code_scale_ * 1000); |
838 | 3 | } |
839 | 7 | xmpData_[tag->_label] = duration_in_ms; |
840 | 7 | break; |
841 | 16 | case Xmp_video_DateUTC: |
842 | 16 | value = getULongLong(buf, bigEndian); |
843 | 16 | if (!value) |
844 | 0 | return; |
845 | 16 | duration_in_ms = value / 1000000000; |
846 | 16 | xmpData_[tag->_label] = duration_in_ms; |
847 | 16 | break; |
848 | | |
849 | 8 | case TimecodeScale: |
850 | 8 | value = getULongLong(buf, bigEndian); |
851 | 8 | if (!value) |
852 | 2 | return; |
853 | 6 | time_code_scale_ = static_cast<double>(value) / static_cast<double>(1000000000); |
854 | 6 | xmpData_[tag->_label] = time_code_scale_; |
855 | 6 | break; |
856 | 0 | default: |
857 | 0 | break; |
858 | 31 | } |
859 | 31 | } |
860 | | |
861 | 1.10k | void MatroskaVideo::decodeFloatTags(const MatroskaTag* tag, const byte* buf) { |
862 | 1.10k | xmpData_[tag->_label] = getFloat(buf, bigEndian); |
863 | | |
864 | 1.10k | switch (tag->_id) { |
865 | 1.10k | case Xmp_audio_SampleRate: |
866 | 1.10k | case Xmp_audio_OutputSampleRate: |
867 | 1.10k | xmpData_[tag->_label] = getFloat(buf, bigEndian); |
868 | 1.10k | break; |
869 | 0 | case VideoFrameRate_DefaultDuration: |
870 | 0 | case Xmp_video_FrameRate: { |
871 | 0 | uint64_t key = getULongLong(buf, bigEndian); |
872 | 0 | if (!key) |
873 | 0 | return; |
874 | 0 | if (auto internalMt = Exiv2::find(streamRate, key)) { |
875 | 0 | double frame_rate = 0; |
876 | 0 | switch (stream_) { |
877 | 0 | case 1: // video |
878 | 0 | frame_rate = 1000000000.0 / static_cast<double>(key); |
879 | 0 | break; |
880 | 0 | case 2: // audio |
881 | 0 | frame_rate = static_cast<double>(key) / 1000; |
882 | 0 | break; |
883 | 0 | default: |
884 | 0 | break; |
885 | 0 | } |
886 | 0 | if (std::isgreater(frame_rate, 0.0)) |
887 | 0 | xmpData_[internalMt->_label] = frame_rate; |
888 | 0 | } else |
889 | 0 | xmpData_[tag->_label] = "Variable Bit Rate"; |
890 | 0 | } break; |
891 | 0 | default: |
892 | 0 | xmpData_[tag->_label] = getFloat(buf, bigEndian); |
893 | 0 | break; |
894 | 1.10k | } |
895 | 1.10k | } |
896 | | |
897 | 14.8k | uint32_t MatroskaVideo::findBlockSize(byte b) { |
898 | 14.8k | if (b & 128) |
899 | 13.2k | return 1; |
900 | 1.60k | if (b & 64) |
901 | 1.09k | return 2; |
902 | 511 | if (b & 32) |
903 | 195 | return 3; |
904 | 316 | if (b & 16) |
905 | 200 | return 4; |
906 | 116 | if (b & 8) |
907 | 4 | return 5; |
908 | 112 | if (b & 4) |
909 | 45 | return 6; |
910 | 67 | if (b & 2) |
911 | 1 | return 7; |
912 | 66 | if (b & 1) |
913 | 43 | return 8; |
914 | 23 | return 0; |
915 | 66 | } |
916 | | |
917 | 142 | Image::UniquePtr newMkvInstance(BasicIo::UniquePtr io, const ImageCtorParams& params) { |
918 | 142 | auto image = std::make_unique<MatroskaVideo>(std::move(io), params); |
919 | 142 | if (!image->good()) { |
920 | 0 | return nullptr; |
921 | 0 | } |
922 | 142 | return image; |
923 | 142 | } |
924 | | |
925 | 2.42k | bool isMkvType(BasicIo& iIo, bool advance) { |
926 | 2.42k | bool result = true; |
927 | 2.42k | byte tmpBuf[4]; |
928 | 2.42k | iIo.read(tmpBuf, 4); |
929 | | |
930 | 2.42k | if (iIo.error() || iIo.eof()) |
931 | 0 | return false; |
932 | | |
933 | 2.42k | if (0x1a != tmpBuf[0] || 0x45 != tmpBuf[1] || 0xdf != tmpBuf[2] || 0xa3 != tmpBuf[3]) { |
934 | 2.00k | result = false; |
935 | 2.00k | } |
936 | | |
937 | 2.42k | if (!advance || !result) |
938 | 2.42k | iIo.seek(0, BasicIo::beg); |
939 | 2.42k | return result; |
940 | 2.42k | } |
941 | | |
942 | | } // namespace Exiv2 |