1 /*
2 * $Id$
3 * Copyright (c) 2008-2010, Matroska (non-profit organisation)
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions are met:
8 * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * * Neither the name of the Matroska assocation nor the
14 * names of its contributors may be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY the Matroska association ``AS IS'' AND ANY
18 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20 * DISCLAIMED. IN NO EVENT SHALL The Matroska Foundation BE LIABLE FOR ANY
21 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
22 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
23 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
24 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
26 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29 #include "MatroskaParser.h"
30
31 #define MAX_TRACKS 32 // safety
32
33 #if defined(TARGET_WIN)
34 #define snprintf _snprintf
35 #endif
36
37 #define HAALI_STREAM_CLASS FOURCC('H','A','L','S')
38 typedef struct haali_stream
39 {
40 stream Base;
41 InputStream *io;
42
43 } haali_stream;
44
45 struct MatroskaFile
46 {
47 haali_stream *Input;
48 ebml_element *Segment;
49 ebml_element *SegmentInfo;
50 ebml_element *TrackList;
51 ebml_element *CueList;
52 SegmentInfo Seg;
53
54 ebml_parser_context L0Context;
55 ebml_parser_context L1Context;
56
57 ebml_element *CurrentCluster;
58 matroska_block *CurrentBlock;
59 size_t CurrentFrame;
60 ebml_parser_context ClusterContext;
61
62 filepos_t pSegmentInfo;
63 filepos_t pTracks;
64 filepos_t pCues;
65 filepos_t pAttachments;
66 filepos_t pChapters;
67 filepos_t pTags;
68 filepos_t pFirstCluster;
69
70 int trackMask;
71 int flags;
72
73 array Tracks;
74 array Tags;
75 array Chapters;
76 array Attachments;
77 };
78
mkv_SetTrackMask(MatroskaFile * File,int Mask)79 void mkv_SetTrackMask(MatroskaFile *File, int Mask)
80 {
81 File->trackMask = Mask;
82 // TODO: the original code is handling a queue
83 }
84
mkv_GetTags(MatroskaFile * File,Tag ** pTags,unsigned * Count)85 void mkv_GetTags(MatroskaFile *File, Tag **pTags, unsigned *Count)
86 {
87 *pTags = ARRAYBEGIN(File->Tags,Tag);
88 *Count = ARRAYCOUNT(File->Tags,Tag);
89 }
90
mkv_GetAttachments(MatroskaFile * File,Attachment ** pAttachements,unsigned * Count)91 void mkv_GetAttachments(MatroskaFile *File, Attachment **pAttachements, unsigned *Count)
92 {
93 *pAttachements = ARRAYBEGIN(File->Attachments,Attachment);
94 *Count = ARRAYCOUNT(File->Attachments,Attachment);
95 }
96
mkv_GetChapters(MatroskaFile * File,Chapter ** pChapters,unsigned * Count)97 void mkv_GetChapters(MatroskaFile *File, Chapter **pChapters, unsigned *Count)
98 {
99 *pChapters = ARRAYBEGIN(File->Chapters,Chapter);
100 *Count = ARRAYCOUNT(File->Chapters,Chapter);
101 }
102
mkv_GetTrackInfo(MatroskaFile * File,size_t n)103 TrackInfo *mkv_GetTrackInfo(MatroskaFile *File, size_t n)
104 {
105 if (n>=ARRAYCOUNT(File->Tracks,TrackInfo))
106 return NULL;
107 return ARRAYBEGIN(File->Tracks,TrackInfo) + n;
108 }
109
mkv_GetFileInfo(MatroskaFile * File)110 SegmentInfo *mkv_GetFileInfo(MatroskaFile *File)
111 {
112 return &File->Seg;
113 }
114
mkv_GetNumTracks(MatroskaFile * File)115 size_t mkv_GetNumTracks(MatroskaFile *File)
116 {
117 return ARRAYCOUNT(File->Tracks,TrackInfo);
118 }
119
CheckMatroskaHead(ebml_element * Head,char * err_msg,size_t err_msgSize)120 static bool_t CheckMatroskaHead(ebml_element *Head, char *err_msg, size_t err_msgSize)
121 {
122 tchar_t DocType[MAXPATH];
123 ebml_element *Elt;
124 Elt = EBML_MasterFindFirstElt(Head,&EBML_ContextReadVersion,1,1);
125 if (!Elt)
126 {
127 strncpy(err_msg,"Out of memory",err_msgSize);
128 return 0;
129 }
130 if (EBML_IntegerValue(Elt) > EBML_MAX_VERSION)
131 {
132 snprintf(err_msg,err_msgSize,"File requires version %d EBML parser",(int)EBML_IntegerValue(Elt));
133 return 0;
134 }
135
136 Elt = EBML_MasterFindFirstElt(Head,&EBML_ContextDocTypeReadVersion,1,1);
137 if (!Elt)
138 {
139 strncpy(err_msg,"Out of memory",err_msgSize);
140 return 0;
141 }
142 if (EBML_IntegerValue(Elt) > MATROSKA_VERSION)
143 {
144 snprintf(err_msg,err_msgSize,"File requires version %d Matroska parser",(int)EBML_IntegerValue(Elt));
145 return 0;
146 }
147
148 Elt = EBML_MasterFindFirstElt(Head,&EBML_ContextMaxIdLength,1,1);
149 if (!Elt)
150 {
151 strncpy(err_msg,"Out of memory",err_msgSize);
152 return 0;
153 }
154 if (EBML_IntegerValue(Elt) > EBML_MAX_ID)
155 {
156 snprintf(err_msg,err_msgSize,"File has identifiers longer than %d",(int)EBML_IntegerValue(Elt));
157 return 0;
158 }
159
160 Elt = EBML_MasterFindFirstElt(Head,&EBML_ContextMaxSizeLength,1,1);
161 if (!Elt)
162 {
163 strncpy(err_msg,"Out of memory",err_msgSize);
164 return 0;
165 }
166 if (EBML_IntegerValue(Elt) > EBML_MAX_SIZE)
167 {
168 snprintf(err_msg,err_msgSize,"File has integers longer than %d",(int)EBML_IntegerValue(Elt));
169 return 0;
170 }
171
172 Elt = EBML_MasterFindFirstElt(Head,&EBML_ContextDocType,1,1);
173 if (!Elt)
174 {
175 strncpy(err_msg,"Out of memory",err_msgSize);
176 return 0;
177 }
178 EBML_StringGet((ebml_string*)Elt,DocType,TSIZEOF(DocType));
179 if (!tcsisame_ascii(DocType,T("matroska")) && !tcsisame_ascii(DocType,T("webm")))
180 {
181 snprintf(err_msg,err_msgSize,"Unsupported DocType: %s",((ebml_string*)Elt)->Buffer);
182 return 0;
183 }
184 return 1;
185 }
186
parseSeekHead(ebml_element * SeekHead,MatroskaFile * File,char * err_msg,size_t err_msgSize)187 static bool_t parseSeekHead(ebml_element *SeekHead, MatroskaFile *File, char *err_msg, size_t err_msgSize)
188 {
189 ebml_parser_context RContext;
190 ebml_element *Elt,*EltId;
191 fourcc_t EltID;
192 filepos_t SegStart = EBML_ElementPositionData(File->Segment);
193 assert(SegStart!=INVALID_FILEPOS_T);
194
195 RContext.Context = SeekHead->Context;
196 if (EBML_ElementIsFiniteSize(SeekHead))
197 RContext.EndPosition = EBML_ElementPositionEnd(SeekHead);
198 else
199 RContext.EndPosition = INVALID_FILEPOS_T;
200 RContext.UpContext = &File->L1Context;
201 if (EBML_ElementReadData(SeekHead,(stream*)File->Input,&RContext,1,SCOPE_ALL_DATA)!=ERR_NONE)
202 {
203 strncpy(err_msg,"Failed to read the EBML head",err_msgSize);
204 return 0;
205 }
206
207 Elt = EBML_MasterFindFirstElt(SeekHead,&MATROSKA_ContextSeek,0,0);
208 while (Elt)
209 {
210 EltId = EBML_MasterFindFirstElt(Elt,&MATROSKA_ContextSeekId,0,0);
211 if (EltId && EltId->DataSize > EBML_MAX_ID)
212 {
213 snprintf(err_msg,err_msgSize,"Invalid ID size in parseSeekEntry: %d",(int)EltId->DataSize);
214 return 0;
215 }
216 EltID = MATROSKA_MetaSeekID((matroska_seekpoint *)Elt);
217 if (EltID == MATROSKA_ContextSegmentInfo.Id)
218 File->pSegmentInfo = MATROSKA_MetaSeekPosInSegment((matroska_seekpoint *)Elt) + SegStart;
219 else if (EltID == MATROSKA_ContextTracks.Id)
220 File->pTracks = MATROSKA_MetaSeekPosInSegment((matroska_seekpoint *)Elt) + SegStart;
221 else if (EltID == MATROSKA_ContextCues.Id)
222 File->pCues = MATROSKA_MetaSeekPosInSegment((matroska_seekpoint *)Elt) + SegStart;
223 else if (EltID == MATROSKA_ContextAttachments.Id)
224 File->pAttachments = MATROSKA_MetaSeekPosInSegment((matroska_seekpoint *)Elt) + SegStart;
225 else if (EltID == MATROSKA_ContextChapters.Id)
226 File->pChapters = MATROSKA_MetaSeekPosInSegment((matroska_seekpoint *)Elt) + SegStart;
227 else if (EltID == MATROSKA_ContextTags.Id)
228 File->pTags = MATROSKA_MetaSeekPosInSegment((matroska_seekpoint *)Elt) + SegStart;
229 Elt = EBML_MasterFindNextElt(SeekHead,Elt,0,0);
230 }
231
232 return 1;
233 }
234
parseSegmentInfo(ebml_element * SegmentInfo,MatroskaFile * File,char * err_msg,size_t err_msgSize)235 static bool_t parseSegmentInfo(ebml_element *SegmentInfo, MatroskaFile *File, char *err_msg, size_t err_msgSize)
236 {
237 ebml_parser_context RContext;
238 ebml_element *Elt;
239 double duration = -1.0;
240
241 RContext.Context = SegmentInfo->Context;
242 if (EBML_ElementIsFiniteSize(SegmentInfo))
243 RContext.EndPosition = EBML_ElementPositionEnd(SegmentInfo);
244 else
245 RContext.EndPosition = INVALID_FILEPOS_T;
246 RContext.UpContext = &File->L1Context;
247 if (EBML_ElementReadData(SegmentInfo,(stream*)File->Input,&RContext,1,SCOPE_ALL_DATA)!=ERR_NONE)
248 {
249 strncpy(err_msg,"Failed to read the Segment Info",err_msgSize);
250 File->pSegmentInfo = INVALID_FILEPOS_T;
251 return 0;
252 }
253 File->pSegmentInfo = SegmentInfo->ElementPosition;
254 File->SegmentInfo = SegmentInfo;
255 File->Seg.TimecodeScale = MATROSKA_ContextTimecodeScale.DefaultValue;
256
257 for (Elt = EBML_MasterChildren(SegmentInfo);Elt;Elt = EBML_MasterNext(Elt))
258 {
259 if (Elt->Context->Id == MATROSKA_ContextTimecodeScale.Id)
260 {
261 File->Seg.TimecodeScale = EBML_IntegerValue(Elt);
262 if (File->Seg.TimecodeScale==0)
263 {
264 strncpy(err_msg,"Segment timecode scale is zero",err_msgSize);
265 return 0;
266 }
267 }
268 else if (Elt->Context->Id == MATROSKA_ContextDuration.Id)
269 {
270 duration = ((ebml_float*)Elt)->Value;
271 }
272 else if (Elt->Context->Id == MATROSKA_ContextSegmentDate.Id)
273 {
274 File->Seg.DateUTC = EBML_DateTime((ebml_date*)Elt);
275 }
276 else if (Elt->Context->Id == MATROSKA_ContextSegmentTitle.Id)
277 {
278 File->Seg.Title = File->Input->io->memalloc(File->Input->io, (size_t)(Elt->DataSize+1));
279 strcpy(File->Seg.Title,((ebml_string*)Elt)->Buffer);
280 }
281 else if (Elt->Context->Id == MATROSKA_ContextMuxingApp.Id)
282 {
283 File->Seg.MuxingApp = File->Input->io->memalloc(File->Input->io, (size_t)(Elt->DataSize+1));
284 strcpy(File->Seg.MuxingApp,((ebml_string*)Elt)->Buffer);
285 }
286 else if (Elt->Context->Id == MATROSKA_ContextWritingApp.Id)
287 {
288 File->Seg.WritingApp = File->Input->io->memalloc(File->Input->io, (size_t)(Elt->DataSize+1));
289 strcpy(File->Seg.WritingApp,((ebml_string*)Elt)->Buffer);
290 }
291 else if (Elt->Context->Id == MATROSKA_ContextSegmentUid.Id)
292 {
293 if (Elt->DataSize!=16)
294 {
295 snprintf(err_msg,err_msgSize,"SegmentUID size is not %d bytes",(int)Elt->DataSize);
296 return 0;
297 }
298 memcpy(File->Seg.UID,EBML_BinaryGetData((ebml_binary*)Elt),sizeof(File->Seg.UID));
299 }
300 else if (Elt->Context->Id == MATROSKA_ContextPrevUid.Id)
301 {
302 if (Elt->DataSize!=16)
303 {
304 snprintf(err_msg,err_msgSize,"PrevUID size is not %d bytes",(int)Elt->DataSize);
305 return 0;
306 }
307 memcpy(File->Seg.PrevUID,EBML_BinaryGetData((ebml_binary*)Elt),sizeof(File->Seg.PrevUID));
308 }
309 else if (Elt->Context->Id == MATROSKA_ContextNextUid.Id)
310 {
311 if (Elt->DataSize!=16)
312 {
313 snprintf(err_msg,err_msgSize,"NextUID size is not %d bytes",(int)Elt->DataSize);
314 return 0;
315 }
316 memcpy(File->Seg.NextUID,EBML_BinaryGetData((ebml_binary*)Elt),sizeof(File->Seg.NextUID));
317 }
318 else if (Elt->Context->Id == MATROSKA_ContextSegmentFilename.Id)
319 {
320 File->Seg.Filename = File->Input->io->memalloc(File->Input->io, (size_t)(Elt->DataSize+1));
321 strcpy(File->Seg.Filename,((ebml_string*)Elt)->Buffer);
322 }
323 else if (Elt->Context->Id == MATROSKA_ContextPrevFilename.Id)
324 {
325 File->Seg.PrevFilename = File->Input->io->memalloc(File->Input->io, (size_t)(Elt->DataSize+1));
326 strcpy(File->Seg.Filename,((ebml_string*)Elt)->Buffer);
327 }
328 else if (Elt->Context->Id == MATROSKA_ContextNextFilename.Id)
329 {
330 File->Seg.NextFilename = File->Input->io->memalloc(File->Input->io, (size_t)(Elt->DataSize+1));
331 strcpy(File->Seg.Filename,((ebml_string*)Elt)->Buffer);
332 }
333 }
334 if (duration > 0.0)
335 File->Seg.Duration = (timecode_t)(duration * File->Seg.TimecodeScale);
336
337 return 1;
338 }
339
releaseTrackEntry(TrackInfo * track,InputStream * io)340 static void releaseTrackEntry(TrackInfo *track, InputStream *io)
341 {
342 if (track->CodecPrivate) io->memfree(io, track->CodecPrivate);
343 if (track->Name) io->memfree(io, track->Name);
344 }
345
parseTrackEntry(ebml_element * Track,MatroskaFile * File,char * err_msg,size_t err_msgSize)346 static bool_t parseTrackEntry(ebml_element *Track, MatroskaFile *File, char *err_msg, size_t err_msgSize)
347 {
348 TrackInfo track,*Tracks;
349 ebml_element *Elt,*TElt;
350
351 if (ARRAYCOUNT(File->Tracks,TrackInfo) >= MAX_TRACKS)
352 return 0;
353
354 memset(&track,0,sizeof(track));
355 track.DefaultDuration = INVALID_TIMECODE_T;
356 track.Enabled = MATROSKA_ContextTrackEnabled.DefaultValue;
357 track.Default = MATROSKA_ContextTrackDefault.DefaultValue;
358 track.Lacing = MATROSKA_ContextTrackLacing.DefaultValue;
359 track.DecodeAll = MATROSKA_ContextTrackCodecDecodeAll.DefaultValue;
360 track.TimecodeScale = (float)MATROSKA_ContextTrackTimecodeScale.DefaultValue;
361 memcpy(track.Language, "eng", 4);
362
363 for (Elt = EBML_MasterChildren(Track);Elt;Elt = EBML_MasterNext(Elt))
364 {
365 if (Elt->Context->Id == MATROSKA_ContextTrackNumber.Id)
366 track.Number = (int)EBML_IntegerValue(Elt);
367 else if (Elt->Context->Id == MATROSKA_ContextTrackNumber.Id)
368 track.UID = EBML_IntegerValue(Elt);
369 else if (Elt->Context->Id == MATROSKA_ContextTrackType.Id)
370 {
371 if (EBML_IntegerValue(Elt)==0 || EBML_IntegerValue(Elt)>254)
372 {
373 snprintf(err_msg,err_msgSize,"Invalid track type: %d",(int)EBML_IntegerValue(Elt));
374 goto fail;
375 }
376 track.Type = (uint8_t)EBML_IntegerValue(Elt);
377 }
378 else if (Elt->Context->Id == MATROSKA_ContextTrackEnabled.Id)
379 track.Enabled = EBML_IntegerValue(Elt)!=0;
380 else if (Elt->Context->Id == MATROSKA_ContextTrackDefault.Id)
381 track.Default = EBML_IntegerValue(Elt)!=0;
382 else if (Elt->Context->Id == MATROSKA_ContextTrackLacing.Id)
383 track.Lacing = EBML_IntegerValue(Elt)!=0;
384 else if (Elt->Context->Id == MATROSKA_ContextTrackCodecDecodeAll.Id)
385 track.DecodeAll = EBML_IntegerValue(Elt)!=0;
386 else if (Elt->Context->Id == MATROSKA_ContextTrackMinCache.Id)
387 {
388 if (EBML_IntegerValue(Elt) > 0xFF)
389 {
390 snprintf(err_msg,err_msgSize,"MinCache is too large: %d",(int)EBML_IntegerValue(Elt));
391 goto fail;
392 }
393 track.MinCache = (uint8_t)EBML_IntegerValue(Elt);
394 }
395 else if (Elt->Context->Id == MATROSKA_ContextTrackMaxCache.Id)
396 {
397 if (EBML_IntegerValue(Elt) > 0x7FFFFFFF)
398 {
399 snprintf(err_msg,err_msgSize,"MaxCache is too large: %d",(int)EBML_IntegerValue(Elt));
400 goto fail;
401 }
402 track.MaxCache = (size_t)EBML_IntegerValue(Elt);
403 }
404 else if (Elt->Context->Id == MATROSKA_ContextTrackDefaultDuration.Id)
405 track.DefaultDuration = EBML_IntegerValue(Elt);
406 else if (Elt->Context->Id == MATROSKA_ContextTrackTimecodeScale.Id)
407 track.TimecodeScale = (float)((ebml_float*)Elt)->Value;
408 else if (Elt->Context->Id == MATROSKA_ContextTrackMaxBlockAdditionID.Id)
409 track.MaxBlockAdditionID = (size_t)EBML_IntegerValue(Elt);
410 else if (Elt->Context->Id == MATROSKA_ContextTrackLanguage.Id)
411 {
412 size_t copy = (Elt->DataSize>3) ? 3 : (size_t)Elt->DataSize;
413 memcpy(track.Language,((ebml_string*)Elt)->Buffer,copy);
414 memset(track.Language + copy,0,4-copy);
415 }
416 else if (Elt->Context->Id == MATROSKA_ContextTrackCodecID.Id)
417 {
418 track.CodecID = File->Input->io->memalloc(File->Input->io, (size_t)(Elt->DataSize+1));
419 strcpy(track.CodecID,((ebml_string*)Elt)->Buffer);
420 }
421 else if (Elt->Context->Id == MATROSKA_ContextTrackCodecPrivate.Id)
422 {
423 if (Elt->DataSize > 256*1024)
424 {
425 snprintf(err_msg,err_msgSize,"CodecPrivate is too large: %d",(int)EBML_IntegerValue(Elt));
426 goto fail;
427 }
428 track.CodecPrivateSize = (size_t)(Elt->DataSize);
429 track.CodecPrivate = File->Input->io->memalloc(File->Input->io, track.CodecPrivateSize);
430 memcpy(track.CodecPrivate,EBML_BinaryGetData((ebml_binary*)Elt),track.CodecPrivateSize);
431 }
432 else if (Elt->Context->Id == MATROSKA_ContextTrackOverlay.Id)
433 {
434 if (EBML_IntegerValue(Elt)==0 || EBML_IntegerValue(Elt)>254)
435 {
436 snprintf(err_msg,err_msgSize,"Track number in TrackOverlay is too large: %d",(int)EBML_IntegerValue(Elt));
437 goto fail;
438 }
439 track.TrackOverlay = (uint8_t)EBML_IntegerValue(Elt);
440 }
441 else if (Elt->Context->Id == MATROSKA_ContextTrackVideo.Id)
442 {
443 for (TElt = EBML_MasterChildren(Elt);TElt;TElt = EBML_MasterNext(TElt))
444 {
445 if (TElt->Context->Id == MATROSKA_ContextTrackVideoInterlaced.Id)
446 track.AV.Video.Interlaced = EBML_IntegerValue(TElt)!=0;
447 else if (TElt->Context->Id == MATROSKA_ContextTrackVideoStereo.Id)
448 {
449 if (TElt->DataSize > 3)
450 {
451 snprintf(err_msg,err_msgSize,"Invalid stereo mode: %d",(int)EBML_IntegerValue(TElt));
452 goto fail;
453 }
454 track.AV.Video.StereoMode = (uint8_t)EBML_IntegerValue(TElt);
455 }
456 else if (TElt->Context->Id == MATROSKA_ContextTrackVideoPixelWidth.Id)
457 {
458 if (EBML_IntegerValue(TElt) > 0xFFFFFFFF)
459 {
460 snprintf(err_msg,err_msgSize,"PixelWidth is too large: %d",(int)EBML_IntegerValue(TElt));
461 goto fail;
462 }
463 track.AV.Video.PixelWidth = (uint32_t)EBML_IntegerValue(TElt);
464 if (!track.AV.Video.DisplayWidth)
465 track.AV.Video.DisplayWidth = track.AV.Video.PixelWidth;
466 }
467 else if (TElt->Context->Id == MATROSKA_ContextTrackVideoPixelHeight.Id)
468 {
469 if (EBML_IntegerValue(TElt) > 0xFFFFFFFF)
470 {
471 snprintf(err_msg,err_msgSize,"PixelHeight is too large: %d",(int)EBML_IntegerValue(TElt));
472 goto fail;
473 }
474 track.AV.Video.PixelHeight = (uint32_t)EBML_IntegerValue(TElt);
475 if (!track.AV.Video.DisplayHeight)
476 track.AV.Video.DisplayHeight = track.AV.Video.PixelHeight;
477 }
478 else if (TElt->Context->Id == MATROSKA_ContextTrackVideoDisplayWidth.Id)
479 {
480 if (EBML_IntegerValue(TElt) > 0xFFFFFFFF)
481 {
482 snprintf(err_msg,err_msgSize,"DisplayWidth is too large: %d",(int)EBML_IntegerValue(TElt));
483 goto fail;
484 }
485 track.AV.Video.DisplayWidth = (uint32_t)EBML_IntegerValue(TElt);
486 }
487 else if (TElt->Context->Id == MATROSKA_ContextTrackVideoDisplayHeight.Id)
488 {
489 if (EBML_IntegerValue(TElt) > 0xFFFFFFFF)
490 {
491 snprintf(err_msg,err_msgSize,"DisplayHeight is too large: %d",(int)EBML_IntegerValue(TElt));
492 goto fail;
493 }
494 track.AV.Video.DisplayHeight = (uint32_t)EBML_IntegerValue(TElt);
495 }
496 else if (TElt->Context->Id == MATROSKA_ContextTrackVideoDisplayUnit.Id)
497 {
498 if (EBML_IntegerValue(TElt) > 2)
499 {
500 snprintf(err_msg,err_msgSize,"DisplayUnit is too large: %d",(int)EBML_IntegerValue(TElt));
501 goto fail;
502 }
503 track.AV.Video.DisplayUnit = (uint8_t)EBML_IntegerValue(TElt);
504 }
505 else if (TElt->Context->Id == MATROSKA_ContextTrackVideoDisplayUnit.Id)
506 {
507 if (EBML_IntegerValue(TElt) > 2)
508 {
509 snprintf(err_msg,err_msgSize,"AspectRatioType is too large: %d",(int)EBML_IntegerValue(TElt));
510 goto fail;
511 }
512 track.AV.Video.AspectRatioType = (uint8_t)EBML_IntegerValue(TElt);
513 }
514 else if (TElt->Context->Id == MATROSKA_ContextTrackVideoPixelCropBottom.Id)
515 {
516 if (EBML_IntegerValue(TElt) > 0xFFFFFFFF)
517 {
518 snprintf(err_msg,err_msgSize,"PixelCropBottom is too large: %d",(int)EBML_IntegerValue(TElt));
519 goto fail;
520 }
521 track.AV.Video.CropB = (uint32_t)EBML_IntegerValue(TElt);
522 }
523 else if (TElt->Context->Id == MATROSKA_ContextTrackVideoPixelCropTop.Id)
524 {
525 if (EBML_IntegerValue(TElt) > 0xFFFFFFFF)
526 {
527 snprintf(err_msg,err_msgSize,"PixelCropTop is too large: %d",(int)EBML_IntegerValue(TElt));
528 goto fail;
529 }
530 track.AV.Video.CropT = (uint32_t)EBML_IntegerValue(TElt);
531 }
532 else if (TElt->Context->Id == MATROSKA_ContextTrackVideoPixelCropLeft.Id)
533 {
534 if (EBML_IntegerValue(TElt) > 0xFFFFFFFF)
535 {
536 snprintf(err_msg,err_msgSize,"PixelCropLeft is too large: %d",(int)EBML_IntegerValue(TElt));
537 goto fail;
538 }
539 track.AV.Video.CropL = (uint32_t)EBML_IntegerValue(TElt);
540 }
541 else if (TElt->Context->Id == MATROSKA_ContextTrackVideoPixelCropRight.Id)
542 {
543 if (EBML_IntegerValue(TElt) > 0xFFFFFFFF)
544 {
545 snprintf(err_msg,err_msgSize,"PixelCropRight is too large: %d",(int)EBML_IntegerValue(TElt));
546 goto fail;
547 }
548 track.AV.Video.CropR = (uint32_t)EBML_IntegerValue(TElt);
549 }
550 else if (TElt->Context->Id == MATROSKA_ContextTrackVideoColourSpace.Id)
551 {
552 if (TElt->DataSize != 4)
553 {
554 snprintf(err_msg,err_msgSize,"ColourSpace is too large: %d",TElt->DataSize);
555 goto fail;
556 }
557 track.AV.Video.ColourSpace = LOAD32LE(EBML_BinaryGetData((ebml_binary*)TElt));
558 }
559 else if (TElt->Context->Id == MATROSKA_ContextTrackVideoGammaValue.Id)
560 track.AV.Video.GammaValue = (float)((ebml_float*)TElt)->Value;
561 }
562 }
563 else if (Elt->Context->Id == MATROSKA_ContextTrackAudio.Id)
564 {
565 track.AV.Audio.Channels = (uint8_t)MATROSKA_ContextTrackAudioChannels.DefaultValue;
566 track.AV.Audio.SamplingFreq = (float)MATROSKA_ContextTrackAudioSamplingFreq.DefaultValue;
567
568 for (TElt = EBML_MasterChildren(Elt);TElt;TElt = EBML_MasterNext(TElt))
569 {
570 if (TElt->Context->Id == MATROSKA_ContextTrackAudioSamplingFreq.Id)
571 {
572 track.AV.Audio.SamplingFreq = (float)((ebml_float*)TElt)->Value;
573 }
574 else if (TElt->Context->Id == MATROSKA_ContextTrackAudioOutputSamplingFreq.Id)
575 track.AV.Audio.OutputSamplingFreq = (float)((ebml_float*)TElt)->Value;
576 else if (TElt->Context->Id == MATROSKA_ContextTrackAudioChannels.Id)
577 {
578 if (EBML_IntegerValue(TElt)==0 || EBML_IntegerValue(TElt)>0xFF)
579 {
580 snprintf(err_msg,err_msgSize,"Invalid Channels value: %d",(int)EBML_IntegerValue(TElt));
581 goto fail;
582 }
583 track.AV.Audio.Channels = (uint8_t)EBML_IntegerValue(TElt);
584 }
585 else if (TElt->Context->Id == MATROSKA_ContextTrackAudioBitDepth.Id)
586 {
587 if (EBML_IntegerValue(TElt)==0 || EBML_IntegerValue(TElt)>0xFF)
588 {
589 snprintf(err_msg,err_msgSize,"Invalid BitDepth value: %d",(int)EBML_IntegerValue(TElt));
590 goto fail;
591 }
592 track.AV.Audio.BitDepth = (uint8_t)EBML_IntegerValue(TElt);
593 }
594 }
595 if (!track.AV.Audio.OutputSamplingFreq)
596 track.AV.Audio.OutputSamplingFreq = track.AV.Audio.SamplingFreq;
597 }
598 // TODO: ContentEncoding
599 }
600
601 if (!track.CodecID)
602 {
603 strncpy(err_msg,"Track has no Codec ID",err_msgSize);
604 goto fail;
605 }
606
607 // check for duplicate track UID entries
608 if (track.UID)
609 {
610 for (Tracks=ARRAYBEGIN(File->Tracks,TrackInfo);Tracks!=ARRAYEND(File->Tracks,TrackInfo);++Tracks)
611 {
612 if (Tracks->UID == track.UID)
613 {
614 snprintf(err_msg,err_msgSize,"A track with UID 0x" PRIx64 " already exists",track.UID);
615 goto fail;
616 }
617 }
618 }
619
620 ArrayAppend(&File->Tracks,&track,sizeof(track),256);
621 return 1;
622
623 fail:
624 releaseTrackEntry(&track, File->Input->io);
625 return 0;
626 }
627
parseTracks(ebml_element * Tracks,MatroskaFile * File,char * err_msg,size_t err_msgSize)628 static bool_t parseTracks(ebml_element *Tracks, MatroskaFile *File, char *err_msg, size_t err_msgSize)
629 {
630 ebml_parser_context RContext;
631 ebml_element *Elt;
632
633 RContext.Context = Tracks->Context;
634 if (EBML_ElementIsFiniteSize(Tracks))
635 RContext.EndPosition = EBML_ElementPositionEnd(Tracks);
636 else
637 RContext.EndPosition = INVALID_FILEPOS_T;
638 RContext.UpContext = &File->L1Context;
639 if (EBML_ElementReadData(Tracks,(stream*)File->Input,&RContext,1,SCOPE_ALL_DATA)!=ERR_NONE)
640 {
641 strncpy(err_msg,"Failed to read the Tracks",err_msgSize);
642 File->pTracks = INVALID_FILEPOS_T;
643 return 0;
644 }
645 File->pTracks = Tracks->ElementPosition;
646
647 for (Elt = EBML_MasterChildren(Tracks);Elt;Elt = EBML_MasterNext(Elt))
648 {
649 if (Elt->Context->Id == MATROSKA_ContextTrackEntry.Id)
650 if (!parseTrackEntry(Elt, File, err_msg, err_msgSize))
651 break;
652 }
653 File->TrackList = Tracks;
654
655 return 1;
656 }
657
parseCues(ebml_element * Cues,MatroskaFile * File,char * err_msg,size_t err_msgSize)658 static bool_t parseCues(ebml_element *Cues, MatroskaFile *File, char *err_msg, size_t err_msgSize)
659 {
660 ebml_parser_context RContext;
661
662 RContext.Context = Cues->Context;
663 if (EBML_ElementIsFiniteSize(Cues))
664 RContext.EndPosition = EBML_ElementPositionEnd(Cues);
665 else
666 RContext.EndPosition = INVALID_FILEPOS_T;
667 RContext.UpContext = &File->L1Context;
668 if (EBML_ElementReadData(Cues,(stream*)File->Input,&RContext,1,SCOPE_ALL_DATA)!=ERR_NONE)
669 {
670 strncpy(err_msg,"Failed to read the Cues",err_msgSize);
671 File->pCues = INVALID_FILEPOS_T;
672 return 0;
673 }
674 File->pCues = Cues->ElementPosition;
675 File->CueList = Cues;
676
677 return 1;
678 }
679
parseAttachments(ebml_element * Attachments,MatroskaFile * File,char * err_msg,size_t err_msgSize)680 static bool_t parseAttachments(ebml_element *Attachments, MatroskaFile *File, char *err_msg, size_t err_msgSize)
681 {
682 ebml_parser_context RContext;
683 ebml_element *Elt, *Elt2;
684 size_t Count;
685 Attachment *At;
686
687 RContext.Context = Attachments->Context;
688 if (EBML_ElementIsFiniteSize(Attachments))
689 RContext.EndPosition = EBML_ElementPositionEnd(Attachments);
690 else
691 RContext.EndPosition = INVALID_FILEPOS_T;
692 RContext.UpContext = &File->L1Context;
693 if (EBML_ElementReadData(Attachments,(stream*)File->Input,&RContext,1,SCOPE_PARTIAL_DATA)!=ERR_NONE)
694 {
695 strncpy(err_msg,"Failed to read the Attachments",err_msgSize);
696 File->pAttachments = INVALID_FILEPOS_T;
697 return 0;
698 }
699 File->pAttachments = Attachments->ElementPosition;
700
701 Count=0;
702 Elt = EBML_MasterFindFirstElt(Attachments, &MATROSKA_ContextAttachedFile, 0,0);
703 while (Elt)
704 {
705 ++Count;
706 Elt = EBML_MasterFindNextElt(Attachments, Elt, 0,0);
707 }
708 ArrayResize(&File->Attachments,Count*sizeof(Attachment),0);
709 ArrayZero(&File->Attachments);
710
711 for (Elt = EBML_MasterFindFirstElt(Attachments, &MATROSKA_ContextAttachedFile, 0,0),At=ARRAYBEGIN(File->Attachments,Attachment);
712 At!=ARRAYEND(File->Attachments,Attachment); ++At, Elt = EBML_MasterFindNextElt(Attachments, Elt, 0,0))
713 {
714 At->Length = INVALID_FILEPOS_T;
715 At->Position = INVALID_FILEPOS_T;
716 for (Elt2=EBML_MasterChildren(Elt);Elt2;Elt2=EBML_MasterNext(Elt2))
717 {
718 if (Elt2->Context->Id == MATROSKA_ContextAttachedFileName.Id)
719 {
720 At->Name = File->Input->io->memalloc(File->Input->io, (size_t)(Elt2->DataSize+1));
721 strcpy(At->Name,((ebml_string*)Elt2)->Buffer);
722 }
723 else if (Elt2->Context->Id == MATROSKA_ContextAttachedFileData.Id)
724 {
725 At->Position = EBML_ElementPositionData(Elt2);
726 At->Length = Elt2->DataSize;
727 }
728 else if (Elt2->Context->Id == MATROSKA_ContextAttachedFileUID.Id)
729 At->UID = EBML_IntegerValue(Elt2);
730 else if (Elt2->Context->Id == MATROSKA_ContextAttachedFileMimeType.Id)
731 {
732 At->MimeType = File->Input->io->memalloc(File->Input->io, (size_t)(Elt2->DataSize+1));
733 strcpy(At->MimeType,((ebml_string*)Elt2)->Buffer);
734 }
735 else if (Elt2->Context->Id == MATROSKA_ContextAttachedFileDescription.Id)
736 {
737 At->Description = File->Input->io->memalloc(File->Input->io, (size_t)(Elt2->DataSize+1));
738 strcpy(At->Description,((ebml_string*)Elt2)->Buffer);
739 }
740 }
741 }
742
743 return 1;
744 }
745
addChapterDisplay(ebml_element * ChapterDisplay,MatroskaFile * File,struct Chapter * Chapter)746 static bool_t addChapterDisplay(ebml_element *ChapterDisplay, MatroskaFile *File, struct Chapter *Chapter)
747 {
748 struct ChapterDisplay *pDisplay,Display;
749 ebml_element *Elt;
750
751 if (!ArrayAppend(&Chapter->aDisplays,&Display,sizeof(struct ChapterDisplay),512))
752 return 0;
753 pDisplay = ARRAYEND(Chapter->aDisplays,struct ChapterDisplay)-1;
754 memset(pDisplay,0,sizeof(*pDisplay));
755 memcpy(pDisplay->Language, (char*)MATROSKA_ContextChapterLanguage.DefaultValue, 4);
756
757 for (Elt=EBML_MasterChildren(ChapterDisplay); Elt; Elt=EBML_MasterNext(Elt))
758 {
759 if (Elt->Context->Id == MATROSKA_ContextChapterString.Id)
760 {
761 pDisplay->String = File->Input->io->memalloc(File->Input->io, (size_t)(Elt->DataSize+1));
762 strcpy(pDisplay->String,((ebml_string*)Elt)->Buffer);
763 }
764 else if (Elt->Context->Id == MATROSKA_ContextChapterLanguage.Id)
765 {
766 size_t copy = (Elt->DataSize>3) ? 3 : (size_t)Elt->DataSize;
767 memcpy(pDisplay->Language,((ebml_string*)Elt)->Buffer,copy);
768 memset(pDisplay->Language + copy,0,4-copy);
769 }
770 else if (Elt->Context->Id == MATROSKA_ContextChapterCountry.Id)
771 {
772 size_t copy = (Elt->DataSize>3) ? 3 : (size_t)Elt->DataSize;
773 memcpy(pDisplay->Country,((ebml_string*)Elt)->Buffer,copy);
774 memset(pDisplay->Country+ copy,0,4-copy);
775 }
776 }
777
778 return 1;
779 }
780
parseChapter(ebml_element * Chapter,MatroskaFile * File,char * err_msg,size_t err_msgSize,struct Chapter * Parent,array * Editions)781 static bool_t parseChapter(ebml_element *Chapter, MatroskaFile *File, char *err_msg, size_t err_msgSize, struct Chapter *Parent, array *Editions)
782 {
783 struct Chapter *pChapter,Chap;
784 ebml_element *Elt;
785
786 pChapter = &Chap;
787 for (Elt=EBML_MasterChildren(Chapter); Elt; Elt=EBML_MasterNext(Elt))
788 {
789 if (Elt->Context->Id == MATROSKA_ContextChapterAtom.Id)
790 {
791 if (!ArrayAppend(&Parent->aChildren,&Chap,sizeof(Chap),512))
792 return 0;
793 pChapter = ARRAYEND(Parent->aChildren,struct Chapter)-1;
794 memset(pChapter,0,sizeof(*pChapter));
795 pChapter->Start = INVALID_TIMECODE_T;
796 if (!parseChapter(Elt,File,err_msg,err_msgSize,pChapter,NULL))
797 ArrayRemove(&Parent->aChildren,struct Chapter,pChapter,NULL,NULL);
798 }
799 // Atom
800 else if (Elt->Context->Id == MATROSKA_ContextChapterUID.Id)
801 Parent->UID = EBML_IntegerValue(Elt);
802 else if (Elt->Context->Id == MATROSKA_ContextChapterTimeStart.Id)
803 Parent->Start = EBML_IntegerValue(Elt);
804 else if (Elt->Context->Id == MATROSKA_ContextChapterTimeEnd.Id)
805 Parent->End = EBML_IntegerValue(Elt);
806 else if (Elt->Context->Id == MATROSKA_ContextChapterHidden.Id)
807 Parent->Hidden = EBML_IntegerValue(Elt)!=0;
808 else if (Elt->Context->Id == MATROSKA_ContextChapterEnabled.Id)
809 Parent->Enabled = EBML_IntegerValue(Elt)!=0;
810 else if (Elt->Context->Id == MATROSKA_ContextChapterDisplay.Id)
811 addChapterDisplay(Elt, File, Parent);
812 // Edition
813 else if (Elt->Context->Id == MATROSKA_ContextEditionUID.Id)
814 Parent->UID = EBML_IntegerValue(Elt);
815 else if (Elt->Context->Id == MATROSKA_ContextEditionHidden.Id)
816 Parent->Hidden = EBML_IntegerValue(Elt)!=0;
817 else if (Elt->Context->Id == MATROSKA_ContextEditionDefault.Id)
818 Parent->Default = EBML_IntegerValue(Elt)!=0;
819 else if (Elt->Context->Id == MATROSKA_ContextEditionOrdered.Id)
820 Parent->Ordered = EBML_IntegerValue(Elt)!=0;
821 }
822
823 Parent->nChildren = ARRAYCOUNT(Parent->aChildren,struct Chapter);
824 Parent->Children = ARRAYBEGIN(Parent->aChildren,struct Chapter);
825 Parent->nDisplay = ARRAYCOUNT(Parent->aDisplays,struct ChapterDisplay);
826 Parent->Display = ARRAYBEGIN(Parent->aDisplays,struct ChapterDisplay);
827
828 return 1;
829 }
830
parseChapters(ebml_element * Chapters,MatroskaFile * File,char * err_msg,size_t err_msgSize)831 static bool_t parseChapters(ebml_element *Chapters, MatroskaFile *File, char *err_msg, size_t err_msgSize)
832 {
833 ebml_parser_context RContext;
834 struct Chapter *pChapter,Chap;
835 ebml_element *Elt;
836
837 RContext.Context = Chapters->Context;
838 if (EBML_ElementIsFiniteSize(Chapters))
839 RContext.EndPosition = EBML_ElementPositionEnd(Chapters);
840 else
841 RContext.EndPosition = INVALID_FILEPOS_T;
842 RContext.UpContext = &File->L1Context;
843 if (EBML_ElementReadData(Chapters,(stream*)File->Input,&RContext,1,SCOPE_ALL_DATA)!=ERR_NONE)
844 {
845 strncpy(err_msg,"Failed to read the Chapters",err_msgSize);
846 File->pChapters = INVALID_FILEPOS_T;
847 return 0;
848 }
849 File->pChapters = Chapters->ElementPosition;
850
851 pChapter = &Chap;
852 memset(pChapter,0,sizeof(*pChapter));
853 Chap.Start = INVALID_TIMECODE_T;
854 Chap.Ordered = MATROSKA_ContextEditionOrdered.DefaultValue;
855 Chap.Hidden = MATROSKA_ContextEditionHidden.DefaultValue;
856 Chap.Default = MATROSKA_ContextEditionDefault.DefaultValue;
857 for (Elt=EBML_MasterChildren(Chapters); Elt; Elt=EBML_MasterNext(Elt))
858 {
859 if (Elt->Context->Id == MATROSKA_ContextChapterEntry.Id)
860 {
861 if (!ArrayAppend(&File->Chapters,&Chap,sizeof(Chap),512))
862 return 0;
863 pChapter = ARRAYEND(File->Chapters,struct Chapter)-1;
864 if (!parseChapter(Elt, File, err_msg, err_msgSize, pChapter, &File->Chapters))
865 ArrayRemove(&File->Chapters,struct Chapter,pChapter,NULL,NULL);
866 }
867 }
868
869 return 1;
870 }
871
parseTargets(ebml_element * Targets,MatroskaFile * File,char * err_msg,size_t err_msgSize,struct Tag * Parent)872 static bool_t parseTargets(ebml_element *Targets, MatroskaFile *File, char *err_msg, size_t err_msgSize, struct Tag *Parent)
873 {
874 ebml_element *Elt;
875 uint8_t Level;
876 struct Target *pTarget,Target;
877
878 Elt = EBML_MasterFindFirstElt(Targets, &MATROSKA_ContextTagTargetTypeValue, 1, 1);
879 if (!Elt || EBML_IntegerValue(Elt) > 0xFF)
880 return 0;
881
882 Level = (uint8_t)EBML_IntegerValue(Elt);
883
884 pTarget = &Target;
885 memset(pTarget,0,sizeof(*pTarget));
886 for (Elt=EBML_MasterChildren(Targets); Elt; Elt=EBML_MasterNext(Elt))
887 {
888 if (Elt->Context->Id == MATROSKA_ContextTagTargetTrackUID.Id)
889 {
890 if (!ArrayAppend(&Parent->aTargets,&Target,sizeof(Target),512))
891 return 0;
892 pTarget = ARRAYEND(Parent->aTargets,struct Target)-1;
893 pTarget->Type = TARGET_TRACK;
894 pTarget->UID = EBML_IntegerValue(Elt);
895 pTarget->Level = Level;
896 }
897 else if (Elt->Context->Id == MATROSKA_ContextTagTargetChapterUID.Id)
898 {
899 if (!ArrayAppend(&Parent->aTargets,&Target,sizeof(Target),512))
900 return 0;
901 pTarget = ARRAYEND(Parent->aTargets,struct Target)-1;
902 pTarget->Type = TARGET_CHAPTER;
903 pTarget->UID = EBML_IntegerValue(Elt);
904 pTarget->Level = Level;
905 }
906 else if (Elt->Context->Id == MATROSKA_ContextTagTargetAttachmentUID.Id)
907 {
908 if (!ArrayAppend(&Parent->aTargets,&Target,sizeof(Target),512))
909 return 0;
910 pTarget = ARRAYEND(Parent->aTargets,struct Target)-1;
911 pTarget->Type = TARGET_ATTACHMENT;
912 pTarget->UID = EBML_IntegerValue(Elt);
913 pTarget->Level = Level;
914 }
915 else if (Elt->Context->Id == MATROSKA_ContextTagTargetEditionUID.Id)
916 {
917 if (!ArrayAppend(&Parent->aTargets,&Target,sizeof(Target),512))
918 return 0;
919 pTarget = ARRAYEND(Parent->aTargets,struct Target)-1;
920 pTarget->Type = TARGET_EDITION;
921 pTarget->UID = EBML_IntegerValue(Elt);
922 pTarget->Level = Level;
923 }
924 }
925
926 return 1;
927 }
928
parseSimpleTag(ebml_element * SimpleTag,MatroskaFile * File,char * err_msg,size_t err_msgSize,struct Tag * Parent)929 static bool_t parseSimpleTag(ebml_element *SimpleTag, MatroskaFile *File, char *err_msg, size_t err_msgSize, struct Tag *Parent)
930 {
931 ebml_element *Elt;
932 struct SimpleTag simpleTag;
933
934 memset(&simpleTag,0,sizeof(simpleTag));
935 simpleTag.Default = MATROSKA_ContextTagDefault.DefaultValue;
936 memcpy(simpleTag.Language, (const char*)MATROSKA_ContextTagLanguage.DefaultValue, 4);
937 for (Elt=EBML_MasterChildren(SimpleTag); Elt; Elt=EBML_MasterNext(Elt))
938 {
939 if (Elt->Context->Id == MATROSKA_ContextTagName.Id)
940 {
941 simpleTag.Name = File->Input->io->memalloc(File->Input->io, (size_t)(Elt->DataSize+1));
942 strcpy(simpleTag.Name,((ebml_string*)Elt)->Buffer);
943 }
944 else if (Elt->Context->Id == MATROSKA_ContextTagString.Id)
945 {
946 simpleTag.Value = File->Input->io->memalloc(File->Input->io, (size_t)(Elt->DataSize+1));
947 strcpy(simpleTag.Value,((ebml_string*)Elt)->Buffer);
948 }
949 else if (Elt->Context->Id == MATROSKA_ContextTagLanguage.Id)
950 {
951 size_t copy = (Elt->DataSize>3) ? 3 : (size_t)Elt->DataSize;
952 memcpy(simpleTag.Language,((ebml_string*)Elt)->Buffer,copy);
953 memset(simpleTag.Language + copy,0,4-copy);
954 }
955 else if (Elt->Context->Id == MATROSKA_ContextTagString.Id)
956 simpleTag.Default = EBML_IntegerValue(Elt)!=0;
957 }
958
959 if (!simpleTag.Value || !simpleTag.Name || !ArrayAppend(&Parent->aSimpleTags,&simpleTag,sizeof(simpleTag),256))
960 {
961 if (simpleTag.Value) File->Input->io->memfree(File->Input->io, simpleTag.Value);
962 if (simpleTag.Name) File->Input->io->memfree(File->Input->io, simpleTag.Name);
963 return 0;
964 }
965
966 Elt = EBML_MasterFindFirstElt(SimpleTag, &MATROSKA_ContextSimpleTag, 0, 0);
967 while (Elt)
968 {
969 parseSimpleTag(Elt, File, err_msg, err_msgSize, Parent);
970 Elt = EBML_MasterFindNextElt(SimpleTag, Elt, 0, 0);
971 }
972
973 return 1;
974 }
975
parseTag(ebml_element * Tag,MatroskaFile * File,char * err_msg,size_t err_msgSize,struct Tag * Parent)976 static bool_t parseTag(ebml_element *Tag, MatroskaFile *File, char *err_msg, size_t err_msgSize, struct Tag *Parent)
977 {
978 ebml_element *Elt;
979
980 for (Elt=EBML_MasterChildren(Tag); Elt; Elt=EBML_MasterNext(Elt))
981 {
982 if (Elt->Context->Id == MATROSKA_ContextTagTargets.Id)
983 parseTargets(Elt,File,err_msg,err_msgSize,Parent);
984 else if (Elt->Context->Id == MATROSKA_ContextSimpleTag.Id)
985 parseSimpleTag(Elt,File,err_msg,err_msgSize,Parent);
986 }
987
988 Parent->Targets = ARRAYBEGIN(Parent->aTargets,struct Target);
989 Parent->nTargets = ARRAYCOUNT(Parent->aTargets,struct Target);
990 Parent->SimpleTags = ARRAYBEGIN(Parent->aSimpleTags,struct SimpleTag);
991 Parent->nSimpleTags = ARRAYCOUNT(Parent->aSimpleTags,struct SimpleTag);
992
993 return 1;
994 }
995
parseTags(ebml_element * Tags,MatroskaFile * File,char * err_msg,size_t err_msgSize)996 static bool_t parseTags(ebml_element *Tags, MatroskaFile *File, char *err_msg, size_t err_msgSize)
997 {
998 ebml_parser_context RContext;
999 struct Tag *pTag,Tag;
1000 ebml_element *Elt;
1001
1002 RContext.Context = Tags->Context;
1003 if (EBML_ElementIsFiniteSize(Tags))
1004 RContext.EndPosition = EBML_ElementPositionEnd(Tags);
1005 else
1006 RContext.EndPosition = INVALID_FILEPOS_T;
1007 RContext.UpContext = &File->L1Context;
1008 if (EBML_ElementReadData(Tags,(stream*)File->Input,&RContext,1,SCOPE_ALL_DATA)!=ERR_NONE)
1009 {
1010 strncpy(err_msg,"Failed to read the Tags",err_msgSize);
1011 File->pTags = INVALID_FILEPOS_T;
1012 return 0;
1013 }
1014 File->pTags = Tags->ElementPosition;
1015
1016 pTag = &Tag;
1017 memset(pTag,0,sizeof(*pTag));
1018 for (Elt=EBML_MasterChildren(Tags); Elt; Elt=EBML_MasterNext(Elt))
1019 {
1020 if (Elt->Context->Id == MATROSKA_ContextTag.Id)
1021 {
1022 if (!ArrayAppend(&File->Tags,&Tag,sizeof(Tag),512))
1023 return 0;
1024 pTag = ARRAYEND(File->Tags,struct Tag)-1;
1025 if (!parseTag(Elt, File, err_msg, err_msgSize, pTag))
1026 ArrayRemove(&File->Tags,struct Tag,pTag,NULL,NULL);
1027 }
1028 }
1029
1030
1031 return 1;
1032 }
1033
mkv_Open(InputStream * io,char * err_msg,size_t err_msgSize)1034 MatroskaFile *mkv_Open(InputStream *io, char *err_msg, size_t err_msgSize)
1035 {
1036 int UpperLevel;
1037 ebml_element *Head, *Elt;
1038
1039 MatroskaFile *File = io->memalloc(io,sizeof(*File));
1040 if (!File)
1041 {
1042 strncpy(err_msg,"Out of memory",err_msgSize);
1043 return NULL;
1044 }
1045
1046 memset(File,0,sizeof(*File));
1047 File->pSegmentInfo = INVALID_FILEPOS_T;
1048 File->pTracks = INVALID_FILEPOS_T;
1049 File->pCues = INVALID_FILEPOS_T;
1050 File->pAttachments = INVALID_FILEPOS_T;
1051 File->pChapters = INVALID_FILEPOS_T;
1052 File->pTags = INVALID_FILEPOS_T;
1053 File->pFirstCluster = INVALID_FILEPOS_T;
1054
1055 io->progress(io,0,0);
1056 io->ioseek(io,0,SEEK_SET);
1057
1058 // find a segment
1059 File->Input = (haali_stream*)NodeCreate(io->AnyNode,HAALI_STREAM_CLASS);
1060 if (!File->Input)
1061 {
1062 strncpy(err_msg,"Out of memory",err_msgSize);
1063 return NULL;
1064 }
1065 File->Input->io = io;
1066
1067 File->L0Context.Context = &MATROSKA_ContextStream;
1068 File->L0Context.EndPosition = File->Input->io->getfilesize(File->Input->io);
1069 File->L0Context.UpContext = NULL;
1070 UpperLevel = 0;
1071 Head = EBML_FindNextElement((stream*)File->Input,&File->L0Context,&UpperLevel,0);
1072 if (!Head)
1073 {
1074 strncpy(err_msg,"Out of memory",err_msgSize);
1075 return NULL;
1076 }
1077
1078 if (Head->Context->Id == MATROSKA_ContextSegment.Id)
1079 {
1080 strncpy(err_msg,"First element in file is not EBML",err_msgSize);
1081 return NULL;
1082 }
1083
1084 if (EBML_ElementReadData(Head,(stream*)File->Input,&File->L0Context,1,SCOPE_ALL_DATA)!=ERR_NONE)
1085 {
1086 strncpy(err_msg,"Failed to read the EBML head",err_msgSize);
1087 NodeDelete((node*)Head);
1088 return NULL;
1089 }
1090 if (!CheckMatroskaHead(Head,err_msg,err_msgSize))
1091 {
1092 NodeDelete((node*)Head);
1093 return NULL;
1094 }
1095 NodeDelete((node*)Head);
1096
1097 File->Segment = EBML_FindNextElement((stream*)File->Input,&File->L0Context,&UpperLevel,0);
1098 if (!File->Segment)
1099 {
1100 strncpy(err_msg,"No segments found in the file",err_msgSize);
1101 return NULL;
1102 }
1103
1104 // we want to read data until we find a seekhead or a trackinfo
1105 File->L1Context.Context = File->Segment->Context;
1106 if (EBML_ElementIsFiniteSize(File->Segment))
1107 File->L1Context.EndPosition = EBML_ElementPositionEnd(File->Segment);
1108 else
1109 File->L1Context.EndPosition = INVALID_FILEPOS_T;
1110 File->L1Context.UpContext = &File->L0Context;
1111 UpperLevel = 0;
1112 Head = EBML_FindNextElement((stream*)File->Input,&File->L1Context,&UpperLevel,0);
1113 while (Head && (!EBML_ElementIsFiniteSize(File->Segment) || EBML_ElementPositionEnd(File->Segment) >= EBML_ElementPositionEnd(Head)))
1114 {
1115 if (Head->Context->Id == MATROSKA_ContextSeekHead.Id)
1116 {
1117 parseSeekHead(Head, File, err_msg, err_msgSize);
1118 NodeDelete((node*)Head);
1119 }
1120 else if (Head->Context->Id == MATROSKA_ContextSegmentInfo.Id)
1121 parseSegmentInfo(Head, File, err_msg, err_msgSize);
1122 else if (Head->Context->Id == MATROSKA_ContextTracks.Id)
1123 parseTracks(Head, File, err_msg, err_msgSize);
1124 else if (Head->Context->Id == MATROSKA_ContextCues.Id)
1125 parseCues(Head, File, err_msg, err_msgSize);
1126 else if (Head->Context->Id == MATROSKA_ContextAttachments.Id)
1127 {
1128 parseAttachments(Head, File, err_msg, err_msgSize);
1129 NodeDelete((node*)Head);
1130 }
1131 else if (Head->Context->Id == MATROSKA_ContextChapters.Id)
1132 {
1133 parseChapters(Head, File, err_msg, err_msgSize);
1134 NodeDelete((node*)Head);
1135 }
1136 else if (Head->Context->Id == MATROSKA_ContextTags.Id)
1137 {
1138 parseTags(Head, File, err_msg, err_msgSize);
1139 NodeDelete((node*)Head);
1140 }
1141 else
1142 {
1143 if (Head->Context->Id==MATROSKA_ContextCluster.Id && File->pFirstCluster==INVALID_FILEPOS_T)
1144 File->pFirstCluster = Head->ElementPosition;
1145 Elt = EBML_ElementSkipData(Head,(stream*)File->Input,&File->L1Context,NULL,1);
1146 NodeDelete((node*)Head);
1147 if (Elt)
1148 {
1149 Head = Elt;
1150 continue;
1151 }
1152 }
1153 Head = EBML_FindNextElement((stream*)File->Input,&File->L1Context,&UpperLevel,0);
1154 }
1155
1156 if (File->CueList && File->SegmentInfo)
1157 {
1158 for (Elt = EBML_MasterChildren(File->CueList);Elt;Elt = EBML_MasterNext(Elt))
1159 {
1160 if (Elt->Context->Id == MATROSKA_ContextCuePoint.Id)
1161 MATROSKA_LinkCueSegmentInfo((matroska_cuepoint*)Elt, File->SegmentInfo);
1162 }
1163
1164 MATROSKA_CuesSort(File->CueList);
1165 }
1166
1167 return File;
1168 }
1169
releaseAttachments(array * Attachments,MatroskaFile * File)1170 static void releaseAttachments(array *Attachments, MatroskaFile *File)
1171 {
1172 Attachment *At;
1173 for (At=ARRAYBEGIN(File->Attachments,Attachment); At!=ARRAYEND(File->Attachments,Attachment); ++At)
1174 {
1175 if (At->Name) File->Input->io->memfree(File->Input->io, At->Name);
1176 if (At->MimeType) File->Input->io->memfree(File->Input->io, At->MimeType);
1177 if (At->Description) File->Input->io->memfree(File->Input->io, At->Description);
1178 }
1179 ArrayClear(Attachments);
1180 }
1181
releaseChapterDisplays(array * ChapterDisplays,MatroskaFile * File)1182 static void releaseChapterDisplays(array *ChapterDisplays, MatroskaFile *File)
1183 {
1184 struct ChapterDisplay *pChapter;
1185
1186 for (pChapter = ARRAYBEGIN(*ChapterDisplays,struct ChapterDisplay); pChapter != ARRAYEND(*ChapterDisplays,struct ChapterDisplay); ++pChapter)
1187 File->Input->io->memfree(File->Input->io, pChapter->String);
1188 ArrayClear(ChapterDisplays);
1189 }
1190
releaseChapters(array * Chapters,MatroskaFile * File)1191 static void releaseChapters(array *Chapters, MatroskaFile *File)
1192 {
1193 struct Chapter *pChapter;
1194
1195 for (pChapter = ARRAYBEGIN(*Chapters,struct Chapter); pChapter != ARRAYEND(*Chapters,struct Chapter); ++pChapter)
1196 {
1197 releaseChapterDisplays(&pChapter->aDisplays, File);
1198 releaseChapters(&pChapter->aChildren,File);
1199 }
1200
1201 ArrayClear(Chapters);
1202 }
1203
releaseSimpleTags(array * SimpleTags,MatroskaFile * File)1204 static void releaseSimpleTags(array *SimpleTags, MatroskaFile *File)
1205 {
1206 struct SimpleTag *pSimpleTag;
1207 for (pSimpleTag = ARRAYBEGIN(*SimpleTags,struct SimpleTag); pSimpleTag != ARRAYEND(*SimpleTags,struct SimpleTag); ++pSimpleTag)
1208 {
1209 if (pSimpleTag->Name) File->Input->io->memfree(File->Input->io, pSimpleTag->Name);
1210 if (pSimpleTag->Value) File->Input->io->memfree(File->Input->io, pSimpleTag->Value);
1211 }
1212 ArrayClear(SimpleTags);
1213 }
1214
releaseTags(array * Tags,MatroskaFile * File)1215 static void releaseTags(array *Tags, MatroskaFile *File)
1216 {
1217 struct Tag *pTag;
1218
1219 for (pTag = ARRAYBEGIN(*Tags,struct Tag); pTag != ARRAYEND(*Tags,struct Tag); ++pTag)
1220 {
1221 releaseSimpleTags(&pTag->aSimpleTags, File);
1222 ArrayClear(&pTag->aTargets);
1223 }
1224
1225 ArrayClear(Tags);
1226 }
1227
mkv_Close(MatroskaFile * File)1228 void mkv_Close(MatroskaFile *File)
1229 {
1230 if (File->Seg.Filename) File->Input->io->memfree(File->Input->io, File->Seg.Filename);
1231 if (File->Seg.PrevFilename) File->Input->io->memfree(File->Input->io, File->Seg.PrevFilename);
1232 if (File->Seg.NextFilename) File->Input->io->memfree(File->Input->io, File->Seg.NextFilename);
1233 if (File->Seg.Title) File->Input->io->memfree(File->Input->io, File->Seg.Title);
1234 if (File->Seg.MuxingApp) File->Input->io->memfree(File->Input->io, File->Seg.MuxingApp);
1235 if (File->Seg.WritingApp) File->Input->io->memfree(File->Input->io, File->Seg.WritingApp);
1236
1237 ArrayClear(&File->Tracks);
1238 releaseAttachments(&File->Attachments, File);
1239 releaseChapters(&File->Chapters, File);
1240 releaseTags(&File->Tags, File);
1241
1242 if (File->TrackList) NodeDelete((node*)File->TrackList);
1243 if (File->CueList) NodeDelete((node*)File->CueList);
1244 if (File->SegmentInfo) NodeDelete((node*)File->SegmentInfo);
1245 if (File->Segment) NodeDelete((node*)File->Segment);
1246 if (File->Input) NodeDelete((node*)File->Input);
1247 }
1248
mkv_ReadFrame(MatroskaFile * File,int mask,unsigned int * track,ulonglong * StartTime,ulonglong * EndTime,ulonglong * FilePos,unsigned int * FrameSize,void ** FrameRef,unsigned int * FrameFlags)1249 int mkv_ReadFrame(MatroskaFile *File, int mask, unsigned int *track, ulonglong *StartTime, ulonglong *EndTime, ulonglong *FilePos, unsigned int *FrameSize,
1250 void** FrameRef, unsigned int *FrameFlags)
1251 {
1252 ebml_element *Elt = NULL,*Elt2;
1253 TrackInfo *tr;
1254 int16_t TrackNum;
1255 matroska_frame Frame;
1256 bool_t Skip;
1257 unsigned int Track;
1258 int UpperLevel = 0;
1259
1260 if (FrameFlags)
1261 *FrameFlags = 0;
1262 if (!track)
1263 track = &Track;
1264 *track = (unsigned int)-1;
1265
1266 for (;;)
1267 {
1268 if (!File->CurrentCluster)
1269 {
1270 for (;;)
1271 {
1272 if (!Elt)
1273 Elt = EBML_FindNextElement((stream*)File->Input,&File->L1Context,&UpperLevel,0);
1274 File->CurrentCluster = Elt;
1275 if (!File->CurrentCluster)
1276 return EOF;
1277 if (UpperLevel)
1278 {
1279 // TODO: changing segments not supported yet
1280 NodeDelete((node*)File->CurrentCluster);
1281 return EOF;
1282 }
1283 if (File->CurrentCluster->Context->Id == MATROSKA_ContextCluster.Id)
1284 break;
1285
1286 Elt = File->CurrentCluster;
1287 File->CurrentCluster = EBML_ElementSkipData(File->CurrentCluster,(stream*)File->Input,&File->L1Context,NULL,1);
1288 NodeDelete((node*)Elt);
1289 Elt = NULL;
1290 }
1291
1292 MATROSKA_LinkClusterReadSegmentInfo((matroska_cluster*)File->CurrentCluster,File->SegmentInfo,1);
1293 File->ClusterContext.Context = &MATROSKA_ContextCluster;
1294 if (EBML_ElementIsFiniteSize(File->CurrentCluster))
1295 File->ClusterContext.EndPosition = EBML_ElementPositionEnd(File->CurrentCluster);
1296 else
1297 File->ClusterContext.EndPosition = INVALID_FILEPOS_T;
1298 File->ClusterContext.UpContext = &File->L1Context;
1299
1300 File->CurrentBlock = NULL;
1301 File->CurrentFrame = 0;
1302 }
1303
1304 Elt = NULL;
1305 while (!File->CurrentBlock)
1306 {
1307 if (!Elt)
1308 {
1309 UpperLevel = 0;
1310 Elt = EBML_FindNextElement((stream*)File->Input,&File->ClusterContext,&UpperLevel,1);
1311 }
1312 if (!Elt || UpperLevel>0)
1313 {
1314 NodeDelete((node*)File->CurrentCluster);
1315 File->CurrentCluster = NULL;
1316 --UpperLevel;
1317 break; // go to the next Cluster
1318 }
1319
1320 Skip = 0;
1321 if (Elt->Context->Id == MATROSKA_ContextClusterTimecode.Id)
1322 {
1323 if (EBML_ElementReadData(Elt,(stream*)File->Input,&File->ClusterContext,1, SCOPE_ALL_DATA)!=ERR_NONE)
1324 return EOF; // TODO: memory leak
1325 Elt2 = EBML_MasterFindFirstElt(File->CurrentCluster,&MATROSKA_ContextClusterTimecode,1,1);
1326 if (!Elt2)
1327 return EOF; // TODO: memory leak
1328 EBML_IntegerSetValue((ebml_integer*)Elt2,EBML_IntegerValue(Elt));
1329 NodeDelete((node*)Elt);
1330 Elt = NULL;
1331 }
1332 else if (Elt->Context->Id == MATROSKA_ContextClusterSimpleBlock.Id)
1333 {
1334 if (EBML_ElementReadData(Elt,(stream*)File->Input,&File->ClusterContext,1, SCOPE_PARTIAL_DATA)!=ERR_NONE)
1335 return EOF; // TODO: memory leak
1336
1337 TrackNum = MATROSKA_BlockTrackNum((matroska_block*)Elt);
1338 for (*track=0, tr=ARRAYBEGIN(File->Tracks,TrackInfo);tr!=ARRAYEND(File->Tracks,TrackInfo);++tr,(*track)++)
1339 if (TrackNum==tr->Number)
1340 break;
1341 if (tr==ARRAYEND(File->Tracks,TrackInfo) || (1<<*track & File->trackMask)!=0)
1342 Skip = 1;
1343 else
1344 {
1345 EBML_MasterAppend(File->CurrentCluster, Elt);
1346 MATROSKA_LinkBlockWithReadTracks((matroska_block*)Elt,File->TrackList,1);
1347 MATROSKA_LinkBlockReadSegmentInfo((matroska_block*)Elt,File->SegmentInfo,1);
1348 File->CurrentBlock = (matroska_block*)Elt;
1349 }
1350 }
1351 else if (Elt->Context->Id == MATROSKA_ContextClusterBlockGroup.Id)
1352 {
1353 if (EBML_ElementReadData(Elt,(stream*)File->Input,&File->ClusterContext,1, SCOPE_PARTIAL_DATA)!=ERR_NONE)
1354 return EOF; // TODO: memory leak
1355
1356 Elt2 = EBML_MasterFindFirstElt(Elt, &MATROSKA_ContextClusterBlock, 0, 0);
1357 if (!Elt2)
1358 Skip = 1;
1359 else
1360 {
1361 TrackNum = MATROSKA_BlockTrackNum((matroska_block*)Elt2);
1362 for (*track=0, tr=ARRAYBEGIN(File->Tracks,TrackInfo);tr!=ARRAYEND(File->Tracks,TrackInfo);++tr,(*track)++)
1363 if (TrackNum==tr->Number)
1364 break;
1365
1366 if (tr==ARRAYEND(File->Tracks,TrackInfo) || (1<<*track & File->trackMask)!=0)
1367 Skip = 1;
1368 else
1369 {
1370 EBML_MasterAppend(File->CurrentCluster, Elt);
1371 MATROSKA_LinkBlockWithReadTracks((matroska_block*)Elt2,File->TrackList,1);
1372 MATROSKA_LinkBlockReadSegmentInfo((matroska_block*)Elt2,File->SegmentInfo,1);
1373 File->CurrentBlock = (matroska_block*)Elt2;
1374 }
1375 }
1376 }
1377 else Skip = 1;
1378
1379 if (Skip)
1380 {
1381 Elt2 = Elt;
1382 Elt = EBML_ElementSkipData(Elt2,(stream*)File->Input,&File->L1Context,NULL,1);
1383 NodeDelete((node*)Elt2);
1384 }
1385 }
1386 if (File->CurrentCluster && File->CurrentBlock)
1387 break;
1388 }
1389
1390 assert(File->CurrentBlock!=NULL);
1391 if (MATROSKA_BlockGetFrame(File->CurrentBlock,File->CurrentFrame,&Frame,0)!=ERR_NONE)
1392 return -1; // TODO: memory leaks
1393
1394 if (*track==(unsigned int)-1)
1395 {
1396 TrackNum = MATROSKA_BlockTrackNum(File->CurrentBlock);
1397 for (*track=0, tr=ARRAYBEGIN(File->Tracks,TrackInfo);tr!=ARRAYEND(File->Tracks,TrackInfo);++tr,(*track)++)
1398 if (TrackNum==tr->Number)
1399 break;
1400 }
1401
1402 if (Frame.Timecode!=INVALID_TIMECODE_T)
1403 {
1404 if (StartTime)
1405 *StartTime = Frame.Timecode;
1406 if (EndTime && Frame.Duration != INVALID_TIMECODE_T)
1407 *EndTime = Frame.Timecode + Frame.Duration;
1408 }
1409
1410 if (FilePos)
1411 *FilePos = ((ebml_element*)File->CurrentBlock)->ElementPosition;
1412 if (FrameFlags)
1413 {
1414 if (Frame.Timecode == INVALID_TIMECODE_T)
1415 *FrameFlags |= FRAME_UNKNOWN_START;
1416 if (Frame.Duration == INVALID_TIMECODE_T)
1417 *FrameFlags |= FRAME_UNKNOWN_END;
1418 if (MATROSKA_BlockKeyframe(File->CurrentBlock))
1419 *FrameFlags |= FRAME_KF;
1420 }
1421 MATROSKA_BlockSkipToFrame(File->CurrentBlock, (stream*)File->Input, File->CurrentFrame);
1422 *FrameRef = File->Input->io->makeref(File->Input->io,MATROSKA_BlockGetLength(File->CurrentBlock,File->CurrentFrame++));
1423
1424 if (File->CurrentFrame >= MATROSKA_BlockGetFrameCount(File->CurrentBlock))
1425 {
1426 File->CurrentBlock = NULL;
1427 File->CurrentFrame = 0;
1428 }
1429
1430 return 0;
1431 }
1432
SeekToPos(MatroskaFile * File,filepos_t SeekPos)1433 static void SeekToPos(MatroskaFile *File, filepos_t SeekPos)
1434 {
1435 if (File->CurrentBlock)
1436 {
1437 NodeDelete((node*)File->CurrentBlock);
1438 File->CurrentBlock = NULL;
1439 }
1440 File->CurrentFrame = 0;
1441 if (File->CurrentCluster && File->CurrentCluster->ElementPosition!=SeekPos)
1442 {
1443 NodeDelete((node*)File->CurrentCluster);
1444 File->CurrentCluster = NULL;
1445 }
1446 File->Input->io->ioseek(File->Input->io,SeekPos,SEEK_SET);
1447 }
1448
mkv_Seek(MatroskaFile * File,timecode_t timecode,int flags)1449 void mkv_Seek(MatroskaFile *File, timecode_t timecode, int flags)
1450 {
1451 matroska_cuepoint *CuePoint;
1452 filepos_t SeekPos;
1453
1454 if (File->flags & MKVF_AVOID_SEEKS || File->pFirstCluster==INVALID_FILEPOS_T || timecode==INVALID_TIMECODE_T)
1455 return;
1456
1457 if (timecode==0)
1458 {
1459 SeekToPos(File, File->pFirstCluster);
1460 return;
1461 }
1462 if (!File->CueList)
1463 return;
1464
1465 CuePoint = MATROSKA_CuesGetTimecodeStart(File->CueList,timecode);
1466 if (CuePoint==NULL)
1467 return;
1468
1469 SeekPos = MATROSKA_CuePosInSegment(CuePoint) + EBML_ElementPositionData(File->Segment);
1470 SeekToPos(File, SeekPos);
1471 }
1472
mkv_TruncFloat(float f)1473 int mkv_TruncFloat(float f)
1474 {
1475 return (int)f;
1476 }
1477
Seek(haali_stream * p,filepos_t Pos,int SeekMode)1478 static filepos_t Seek(haali_stream *p ,filepos_t Pos,int SeekMode)
1479 {
1480 if (!(Pos == 0 && SeekMode==SEEK_CUR))
1481 p->io->ioseek(p->io,Pos,SeekMode);
1482 return p->io->iotell(p->io);
1483 }
1484
Read(haali_stream * p,void * Data,size_t Size,size_t * pReaded)1485 static err_t Read(haali_stream* p,void* Data,size_t Size,size_t* pReaded)
1486 {
1487 size_t Readed;
1488 if (!pReaded)
1489 pReaded = &Readed;
1490 *pReaded = p->io->ioread(p->io,Data,Size);
1491 if (Size && *pReaded!=Size)
1492 return ERR_END_OF_FILE;
1493 return ERR_NONE;
1494 }
1495
1496 META_START(HaaliStream_Class,HAALI_STREAM_CLASS)
1497 META_CLASS(SIZE,sizeof(haali_stream))
1498 META_VMT(TYPE_FUNC,stream_vmt,Seek,Seek)
1499 META_VMT(TYPE_FUNC,stream_vmt,Read,Read)
1500 META_END(STREAM_CLASS)
1501