1 /*
2 * $Id: matroskamain.c 830 2012-05-12 15:44:37Z robux4 $
3 * Copyright (c) 2008-2011, 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 #include "matroska/matroska.h"
29 #include "matroska/matroska_sem.h"
30 #include "matroska/matroska_internal.h"
31 #if defined(HAVE_ZLIB)
32 #include "zlib/zlib.h"
33 #elif defined(CONFIG_ZLIB)
34 #include "zlib.h"
35 #endif
36 #if defined(CONFIG_BZLIB)
37 #include <bzlib.h>
38 #endif
39 #if defined(CONFIG_LZO1X)
40 #include "minilzo.h"
41 #endif
42 #if defined(MATROSKA_LIBRARY)
43 #include "matroska2_project.h"
44 #endif
45
46 const ebml_semantic EBML_SemanticMatroska[] = {
47 {1, 0, &EBML_ContextHead ,0},
48 {1, 0, &MATROSKA_ContextSegment ,0},
49 {0, 0, NULL ,0} // end of the table
50 };
51 const ebml_context MATROSKA_ContextStream = {FOURCC('M','K','X','_'), EBML_MASTER_CLASS, 0, 0, "Matroska Stream", EBML_SemanticMatroska, EBML_SemanticGlobals, NULL};
52
MATROSKA_Init(nodecontext * p)53 err_t MATROSKA_Init(nodecontext *p)
54 {
55 #if defined(MATROSKA_LIBRARY)
56 tchar_t LibName[MAXPATH];
57 #endif
58 err_t Err = EBML_Init(p);
59 if (Err == ERR_NONE)
60 {
61 #if defined(MATROSKA_LIBRARY)
62 tcscpy_s(LibName,TSIZEOF(LibName),PROJECT_NAME T(" v") PROJECT_VERSION);
63 Node_SetData(p,CONTEXT_LIBMATROSKA_VERSION,TYPE_STRING,LibName);
64 #endif
65 }
66 return Err;
67 }
68
MATROSKA_Done(nodecontext * p)69 err_t MATROSKA_Done(nodecontext *p)
70 {
71 return EBML_Done(p);
72 }
73
74
75 #define MATROSKA_CUE_SEGMENTINFO 0x100
76 #define MATROSKA_CUE_BLOCK 0x101
77
78 #define MATROSKA_CLUSTER_READ_SEGMENTINFO 0x100
79 #define MATROSKA_CLUSTER_WRITE_SEGMENTINFO 0x101
80
81 #define MATROSKA_SEEKPOINT_ELEMENT 0x100
82
83 #define LACING_NONE 0
84 #define LACING_XIPH 1
85 #define LACING_FIXED 2
86 #define LACING_EBML 3
87 #define LACING_AUTO 4
88
89 struct matroska_cuepoint
90 {
91 ebml_master Base;
92 ebml_master *SegInfo;
93 matroska_block *Block;
94 };
95
96 struct matroska_cluster
97 {
98 ebml_master Base;
99 ebml_master *ReadSegInfo;
100 ebml_master *WriteSegInfo;
101 timecode_t GlobalTimecode;
102 };
103
104 struct matroska_seekpoint
105 {
106 ebml_master Base;
107 ebml_element *Link;
108 };
109
110 struct matroska_trackentry
111 {
112 ebml_master Base;
113 bool_t CodecPrivateCompressed;
114 };
115
BlockTrackChanged(matroska_block * Block)116 static err_t BlockTrackChanged(matroska_block *Block)
117 {
118 Block->Base.Base.bNeedDataSizeUpdate = 1;
119 return ERR_NONE;
120 }
121
ClusterTimeChanged(matroska_cluster * Cluster)122 static err_t ClusterTimeChanged(matroska_cluster *Cluster)
123 {
124 timecode_t ClusterTimecode;
125 #if defined(CONFIG_EBML_WRITING)
126 timecode_t BlockTimecode;
127 ebml_element *Elt, *GBlock;
128 #endif
129
130 Cluster->Base.Base.bNeedDataSizeUpdate = 1;
131 ClusterTimecode = MATROSKA_ClusterTimecode(Cluster);
132 MATROSKA_ClusterSetTimecode(Cluster, ClusterTimecode);
133 #if defined(CONFIG_EBML_WRITING)
134 for (Elt = EBML_MasterChildren(Cluster); Elt; Elt = EBML_MasterNext(Elt))
135 {
136 if (EBML_ElementIsType(Elt, &MATROSKA_ContextBlockGroup))
137 {
138 for (GBlock = EBML_MasterChildren(Elt);GBlock;GBlock=EBML_MasterNext(GBlock))
139 {
140 if (EBML_ElementIsType(GBlock, &MATROSKA_ContextBlock))
141 {
142 BlockTimecode = MATROSKA_BlockTimecode((matroska_block*)GBlock);
143 if (BlockTimecode!=INVALID_TIMECODE_T)
144 MATROSKA_BlockSetTimecode((matroska_block*)GBlock, BlockTimecode, ClusterTimecode);
145 break;
146 }
147 }
148 }
149 else if (EBML_ElementIsType(Elt, &MATROSKA_ContextSimpleBlock))
150 {
151 BlockTimecode = MATROSKA_BlockTimecode((matroska_block*)Elt);
152 if (BlockTimecode!=INVALID_TIMECODE_T)
153 MATROSKA_BlockSetTimecode((matroska_block*)Elt, BlockTimecode, ClusterTimecode);
154 }
155 }
156 #endif
157 return ERR_NONE;
158 }
159
CheckCompression(matroska_block * Block)160 static err_t CheckCompression(matroska_block *Block)
161 {
162 ebml_master *Elt, *Header;
163 assert(Block->ReadTrack!=NULL);
164 Elt = (ebml_master*)EBML_MasterFindChild(Block->ReadTrack, &MATROSKA_ContextContentEncodings);
165 if (Elt)
166 {
167 if (ARRAYCOUNT(Block->Data,uint8_t))
168 return ERR_INVALID_PARAM; // we cannot adjust sizes if the data are already read
169
170 Elt = (ebml_master*)EBML_MasterFindChild(Elt, &MATROSKA_ContextContentEncoding);
171 if (EBML_MasterChildren(Elt))
172 {
173 if (EBML_MasterNext(Elt))
174 return ERR_INVALID_DATA; // TODO support cascaded compression/encryption
175
176 Elt = (ebml_master*)EBML_MasterFindChild(Elt, &MATROSKA_ContextContentCompression);
177 if (!Elt)
178 return ERR_INVALID_DATA; // TODO: support encryption
179
180 Header = (ebml_master*)EBML_MasterGetChild(Elt, &MATROSKA_ContextContentCompAlgo);
181 #if defined(CONFIG_ZLIB) || defined(CONFIG_LZO1X) || defined(CONFIG_BZLIB)
182 if (EBML_IntegerValue((ebml_integer*)Header)!=MATROSKA_BLOCK_COMPR_HEADER)
183 #if defined(CONFIG_ZLIB)
184 if (EBML_IntegerValue((ebml_integer*)Header)!=MATROSKA_BLOCK_COMPR_ZLIB)
185 #endif
186 #if defined(CONFIG_LZO1X)
187 if (EBML_IntegerValue((ebml_integer*)Header)!=MATROSKA_BLOCK_COMPR_LZO1X)
188 #endif
189 #if defined(CONFIG_BZLIB)
190 if (EBML_IntegerValue((ebml_integer*)Header)!=MATROSKA_BLOCK_COMPR_BZLIB)
191 #endif
192 #else
193 if (EBML_IntegerValue((ebml_integer*)Header)!=MATROSKA_BLOCK_COMPR_HEADER)
194 #endif
195 return ERR_INVALID_DATA;
196
197 if (EBML_IntegerValue((ebml_integer*)Header)==MATROSKA_BLOCK_COMPR_HEADER)
198 {
199 Header = (ebml_master*)EBML_MasterFindChild(Elt, &MATROSKA_ContextContentCompSettings);
200 if (Header)
201 {
202 uint32_t *i;
203 for (i=ARRAYBEGIN(Block->SizeList,uint32_t);i!=ARRAYEND(Block->SizeList,uint32_t);++i)
204 *i += (uint32_t)Header->Base.DataSize;
205 }
206 }
207 }
208 }
209 return ERR_NONE;
210 }
211
MATROSKA_LinkBlockWithReadTracks(matroska_block * Block,ebml_master * Tracks,bool_t UseForWriteToo)212 err_t MATROSKA_LinkBlockWithReadTracks(matroska_block *Block, ebml_master *Tracks, bool_t UseForWriteToo)
213 {
214 ebml_element *Track;
215 ebml_integer *TrackNum;
216 bool_t WasLinked = Block->ReadTrack!=NULL;
217
218 assert(EBML_ElementIsType((ebml_element*)Tracks, &MATROSKA_ContextTracks));
219 assert(Node_IsPartOf(Block,MATROSKA_BLOCK_CLASS));
220 for (Track=EBML_MasterChildren(Tracks);Track;Track=EBML_MasterNext(Track))
221 {
222 TrackNum = (ebml_integer*)EBML_MasterFindChild((ebml_master*)Track,&MATROSKA_ContextTrackNumber);
223 if (TrackNum && ((ebml_element*)TrackNum)->bValueIsSet && EBML_IntegerValue(TrackNum)==Block->TrackNumber)
224 {
225 Node_SET(Block,MATROSKA_BLOCK_READ_TRACK,&Track);
226 #if defined(CONFIG_EBML_WRITING)
227 if (UseForWriteToo)
228 Node_SET(Block,MATROSKA_BLOCK_WRITE_TRACK,&Track);
229 #endif
230 if (WasLinked)
231 return ERR_NONE;
232 return CheckCompression(Block);
233 }
234 }
235 return ERR_INVALID_DATA;
236 }
237
MATROSKA_LinkBlockReadTrack(matroska_block * Block,ebml_master * Track,bool_t UseForWriteToo)238 err_t MATROSKA_LinkBlockReadTrack(matroska_block *Block, ebml_master *Track, bool_t UseForWriteToo)
239 {
240 ebml_integer *TrackNum;
241 bool_t WasLinked = Block->ReadTrack!=NULL;
242
243 assert(EBML_ElementIsType((ebml_element*)Track, &MATROSKA_ContextTrackEntry));
244 assert(Node_IsPartOf(Block,MATROSKA_BLOCK_CLASS));
245 TrackNum = (ebml_integer*)EBML_MasterFindChild(Track,&MATROSKA_ContextTrackNumber);
246 if (TrackNum && ((ebml_element*)TrackNum)->bValueIsSet)
247 {
248 Block->TrackNumber = (uint16_t)EBML_IntegerValue(TrackNum);
249 Node_SET(Block,MATROSKA_BLOCK_READ_TRACK,&Track);
250 #if defined(CONFIG_EBML_WRITING)
251 if (UseForWriteToo)
252 Node_SET(Block,MATROSKA_BLOCK_WRITE_TRACK,&Track);
253 #endif
254 if (WasLinked)
255 return ERR_NONE;
256 return CheckCompression(Block);
257 }
258 return ERR_INVALID_DATA;
259 }
260
261 #if defined(CONFIG_EBML_WRITING)
MATROSKA_LinkBlockWithWriteTracks(matroska_block * Block,ebml_master * Tracks)262 err_t MATROSKA_LinkBlockWithWriteTracks(matroska_block *Block, ebml_master *Tracks)
263 {
264 ebml_master *Track;
265 ebml_integer *TrackNum;
266 bool_t WasLinked = Block->WriteTrack!=NULL;
267
268 assert(EBML_ElementIsType((ebml_element*)Tracks, &MATROSKA_ContextTracks));
269 assert(Node_IsPartOf(Block,MATROSKA_BLOCK_CLASS));
270 for (Track=(ebml_master*)EBML_MasterChildren(Tracks);Track;Track=(ebml_master*)EBML_MasterNext(Track))
271 {
272 TrackNum = (ebml_integer*)EBML_MasterFindChild(Track,&MATROSKA_ContextTrackNumber);
273 if (TrackNum && ((ebml_element*)TrackNum)->bValueIsSet && EBML_IntegerValue(TrackNum)==Block->TrackNumber)
274 {
275 Node_SET(Block,MATROSKA_BLOCK_WRITE_TRACK,&Track);
276 if (WasLinked)
277 return ERR_NONE;
278 return CheckCompression(Block);
279 }
280 }
281 return ERR_INVALID_DATA;
282 }
283
MATROSKA_LinkBlockWriteTrack(matroska_block * Block,ebml_master * Track)284 err_t MATROSKA_LinkBlockWriteTrack(matroska_block *Block, ebml_master *Track)
285 {
286 ebml_integer *TrackNum;
287 bool_t WasLinked = Block->WriteTrack!=NULL;
288
289 assert(EBML_ElementIsType((ebml_element*)Track, &MATROSKA_ContextTrackEntry));
290 assert(Node_IsPartOf(Block,MATROSKA_BLOCK_CLASS));
291 TrackNum = (ebml_integer*)EBML_MasterFindChild(Track,&MATROSKA_ContextTrackNumber);
292 if (TrackNum && ((ebml_element*)TrackNum)->bValueIsSet)
293 {
294 Block->TrackNumber = (uint16_t)EBML_IntegerValue(TrackNum);
295 Node_SET(Block,MATROSKA_BLOCK_WRITE_TRACK,&Track);
296 if (WasLinked)
297 return ERR_NONE;
298 return CheckCompression(Block);
299 }
300 return ERR_INVALID_DATA;
301 }
302 #endif
303
MATROSKA_BlockReadTrack(const matroska_block * Block)304 ebml_element *MATROSKA_BlockReadTrack(const matroska_block *Block)
305 {
306 ebml_element *Track;
307 if (Node_GET((node*)Block,MATROSKA_BLOCK_READ_TRACK,&Track)!=ERR_NONE)
308 return NULL;
309 return Track;
310 }
311
312 #if defined(CONFIG_EBML_WRITING)
MATROSKA_BlockWriteTrack(const matroska_block * Block)313 ebml_element *MATROSKA_BlockWriteTrack(const matroska_block *Block)
314 {
315 ebml_element *Track;
316 if (Node_GET((node*)Block,MATROSKA_BLOCK_WRITE_TRACK,&Track)!=ERR_NONE)
317 return NULL;
318 return Track;
319 }
320 #endif
321
MATROSKA_LinkMetaSeekElement(matroska_seekpoint * MetaSeek,ebml_element * Link)322 err_t MATROSKA_LinkMetaSeekElement(matroska_seekpoint *MetaSeek, ebml_element *Link)
323 {
324 assert(EBML_ElementIsType((ebml_element*)MetaSeek, &MATROSKA_ContextSeek));
325 Node_SET(MetaSeek,MATROSKA_SEEKPOINT_ELEMENT,&Link);
326 return ERR_NONE;
327 }
328
MATROSKA_MetaSeekID(const matroska_seekpoint * MetaSeek)329 fourcc_t MATROSKA_MetaSeekID(const matroska_seekpoint *MetaSeek)
330 {
331 ebml_element *SeekID;
332 assert(EBML_ElementIsType((ebml_element*)MetaSeek, &MATROSKA_ContextSeek));
333 SeekID = EBML_MasterFindChild((ebml_master*)MetaSeek, &MATROSKA_ContextSeekID);
334 if (!SeekID)
335 return 0;
336 return EBML_BufferToID(EBML_BinaryGetData((ebml_binary*)SeekID));
337 }
338
MATROSKA_MetaSeekIsClass(const matroska_seekpoint * MetaSeek,const ebml_context * Class)339 bool_t MATROSKA_MetaSeekIsClass(const matroska_seekpoint *MetaSeek, const ebml_context *Class)
340 {
341 return MATROSKA_MetaSeekID(MetaSeek) == Class->Id;
342 }
343
MATROSKA_MetaSeekPosInSegment(const matroska_seekpoint * MetaSeek)344 filepos_t MATROSKA_MetaSeekPosInSegment(const matroska_seekpoint *MetaSeek)
345 {
346 ebml_integer *SeekPos;
347 assert(EBML_ElementIsType((ebml_element*)MetaSeek, &MATROSKA_ContextSeek));
348 SeekPos = (ebml_integer*)EBML_MasterFindChild((ebml_master*)MetaSeek, &MATROSKA_ContextSeekPosition);
349 if (!SeekPos)
350 return INVALID_FILEPOS_T;
351 return EBML_IntegerValue(SeekPos);
352 }
353
MATROSKA_MetaSeekAbsolutePos(const matroska_seekpoint * MetaSeek)354 filepos_t MATROSKA_MetaSeekAbsolutePos(const matroska_seekpoint *MetaSeek)
355 {
356 filepos_t RelPos = MATROSKA_MetaSeekPosInSegment(MetaSeek);
357 ebml_element *RSegment;
358 if (RelPos==INVALID_FILEPOS_T)
359 return INVALID_FILEPOS_T;
360
361 RSegment = EBML_ElementParent(MetaSeek);
362 while (RSegment && !EBML_ElementIsType(RSegment, &MATROSKA_ContextSegment))
363 RSegment = EBML_ElementParent(RSegment);
364 if (!RSegment)
365 return INVALID_FILEPOS_T;
366
367 return RelPos + EBML_ElementPositionData(RSegment);
368 }
369
MATROSKA_MetaSeekUpdate(matroska_seekpoint * MetaSeek)370 err_t MATROSKA_MetaSeekUpdate(matroska_seekpoint *MetaSeek)
371 {
372 ebml_element *WSeekID, *WSeekPosSegmentInfo, *RSegment, *Link = NULL;
373 size_t IdSize;
374 err_t Err;
375 uint8_t IdBuffer[4];
376
377 if (Node_IsPartOf(MetaSeek,EBML_VOID_CLASS))
378 return ERR_NONE;
379
380 assert(EBML_ElementIsType((ebml_element*)MetaSeek, &MATROSKA_ContextSeek));
381 RSegment = EBML_ElementParent(MetaSeek);
382 while (RSegment && !EBML_ElementIsType(RSegment, &MATROSKA_ContextSegment))
383 RSegment = EBML_ElementParent(RSegment);
384 if (!RSegment)
385 return ERR_INVALID_DATA;
386
387 Err = Node_GET(MetaSeek,MATROSKA_SEEKPOINT_ELEMENT,&Link);
388 if (Err != ERR_NONE)
389 return Err;
390 if (Link==NULL)
391 return ERR_INVALID_DATA;
392
393 WSeekID = EBML_MasterFindFirstElt((ebml_master*)MetaSeek,&MATROSKA_ContextSeekID,1,0);
394 IdSize = EBML_FillBufferID(IdBuffer,sizeof(IdBuffer),Link->Context->Id);
395 EBML_BinarySetData((ebml_binary*)WSeekID,IdBuffer,IdSize);
396
397 WSeekPosSegmentInfo = EBML_MasterFindFirstElt((ebml_master*)MetaSeek,&MATROSKA_ContextSeekPosition,1,0);
398 EBML_IntegerSetValue((ebml_integer*)WSeekPosSegmentInfo, Link->ElementPosition - EBML_ElementPositionData(RSegment));
399
400 return Err;
401 }
402
MATROSKA_LinkClusterReadSegmentInfo(matroska_cluster * Cluster,ebml_master * SegmentInfo,bool_t UseForWriteToo)403 err_t MATROSKA_LinkClusterReadSegmentInfo(matroska_cluster *Cluster, ebml_master *SegmentInfo, bool_t UseForWriteToo)
404 {
405 assert(EBML_ElementIsType((ebml_element*)Cluster, &MATROSKA_ContextCluster));
406 assert(EBML_ElementIsType((ebml_element*)SegmentInfo, &MATROSKA_ContextInfo));
407 Node_SET(Cluster,MATROSKA_CLUSTER_READ_SEGMENTINFO,&SegmentInfo);
408 if (UseForWriteToo)
409 Node_SET(Cluster,MATROSKA_CLUSTER_WRITE_SEGMENTINFO,&SegmentInfo);
410 return ERR_NONE;
411 }
412
413 #if defined(CONFIG_EBML_WRITING)
MATROSKA_LinkClusterWriteSegmentInfo(matroska_cluster * Cluster,ebml_master * SegmentInfo)414 err_t MATROSKA_LinkClusterWriteSegmentInfo(matroska_cluster *Cluster, ebml_master *SegmentInfo)
415 {
416 assert(EBML_ElementIsType((ebml_element*)Cluster, &MATROSKA_ContextCluster));
417 assert(EBML_ElementIsType((ebml_element*)SegmentInfo, &MATROSKA_ContextInfo));
418 Node_SET(Cluster,MATROSKA_CLUSTER_WRITE_SEGMENTINFO,&SegmentInfo);
419 return ERR_NONE;
420 }
421 #endif
422
MATROSKA_LinkBlockReadSegmentInfo(matroska_block * Block,ebml_master * SegmentInfo,bool_t UseForWriteToo)423 err_t MATROSKA_LinkBlockReadSegmentInfo(matroska_block *Block, ebml_master *SegmentInfo, bool_t UseForWriteToo)
424 {
425 assert(EBML_ElementIsType((ebml_element*)SegmentInfo, &MATROSKA_ContextInfo));
426 assert(Node_IsPartOf(Block,MATROSKA_BLOCK_CLASS));
427 Node_SET(Block,MATROSKA_BLOCK_READ_SEGMENTINFO,&SegmentInfo);
428 #if defined(CONFIG_EBML_WRITING)
429 if (UseForWriteToo)
430 Node_SET(Block,MATROSKA_BLOCK_WRITE_SEGMENTINFO,&SegmentInfo);
431 #endif
432 return ERR_NONE;
433 }
434
435 #if defined(CONFIG_EBML_WRITING)
MATROSKA_LinkBlockWriteSegmentInfo(matroska_block * Block,ebml_master * SegmentInfo)436 err_t MATROSKA_LinkBlockWriteSegmentInfo(matroska_block *Block, ebml_master *SegmentInfo)
437 {
438 assert(EBML_ElementIsType((ebml_element*)SegmentInfo, &MATROSKA_ContextInfo));
439 assert(Node_IsPartOf(Block,MATROSKA_BLOCK_CLASS));
440 Node_SET(Block,MATROSKA_BLOCK_WRITE_SEGMENTINFO,&SegmentInfo);
441 return ERR_NONE;
442 }
443 #endif
444
MATROSKA_BlockReadSegmentInfo(const matroska_block * Block)445 ebml_element *MATROSKA_BlockReadSegmentInfo(const matroska_block *Block)
446 {
447 ebml_element *SegmentInfo;
448 if (Node_GET((node*)Block,MATROSKA_BLOCK_READ_SEGMENTINFO,&SegmentInfo)!=ERR_NONE)
449 return NULL;
450 return SegmentInfo;
451 }
452
453 #if defined(CONFIG_EBML_WRITING)
MATROSKA_BlockWriteSegmentInfo(const matroska_block * Block)454 ebml_element *MATROSKA_BlockWriteSegmentInfo(const matroska_block *Block)
455 {
456 ebml_element *SegmentInfo;
457 if (Node_GET((node*)Block,MATROSKA_BLOCK_WRITE_SEGMENTINFO,&SegmentInfo)!=ERR_NONE)
458 return NULL;
459 return SegmentInfo;
460 }
461 #endif
462
MATROSKA_LinkCueSegmentInfo(matroska_cuepoint * Cue,ebml_master * SegmentInfo)463 err_t MATROSKA_LinkCueSegmentInfo(matroska_cuepoint *Cue, ebml_master *SegmentInfo)
464 {
465 assert(EBML_ElementIsType((ebml_element*)Cue, &MATROSKA_ContextCuePoint));
466 assert(EBML_ElementIsType((ebml_element*)SegmentInfo, &MATROSKA_ContextInfo));
467 Node_SET(Cue,MATROSKA_CUE_SEGMENTINFO,&SegmentInfo);
468 return ERR_NONE;
469 }
470
MATROSKA_LinkCuePointBlock(matroska_cuepoint * CuePoint,matroska_block * Block)471 err_t MATROSKA_LinkCuePointBlock(matroska_cuepoint *CuePoint, matroska_block *Block)
472 {
473 assert(EBML_ElementIsType((ebml_element*)CuePoint, &MATROSKA_ContextCuePoint));
474 assert(Node_IsPartOf(Block,MATROSKA_BLOCK_CLASS));
475 Node_SET(CuePoint,MATROSKA_CUE_BLOCK,&Block);
476 return ERR_NONE;
477 }
478
MATROSKA_BlockCmp(const matroska_block * BlockA,const matroska_block * BlockB)479 static int MATROSKA_BlockCmp(const matroska_block *BlockA, const matroska_block *BlockB)
480 {
481 timecode_t TimeA = MATROSKA_BlockTimecode((matroska_block*)BlockA);
482 timecode_t TimeB = MATROSKA_BlockTimecode((matroska_block*)BlockB);
483 if (TimeA != TimeB)
484 return (int)((TimeA - TimeB)/100000);
485 return MATROSKA_BlockTrackNum(BlockB) - MATROSKA_BlockTrackNum(BlockA); // usually the first track is video, so put audio/subs first
486 }
487
ClusterEltCmp(const matroska_cluster * Cluster,const ebml_element ** a,const ebml_element ** b)488 static int ClusterEltCmp(const matroska_cluster* Cluster, const ebml_element** a,const ebml_element** b)
489 {
490 const matroska_block *BlockA = NULL,*BlockB = NULL;
491 if (EBML_ElementIsType(*a, &MATROSKA_ContextTimecode))
492 return -1;
493 if (EBML_ElementIsType(*b, &MATROSKA_ContextTimecode))
494 return 1;
495
496 if (EBML_ElementIsType(*a, &MATROSKA_ContextSimpleBlock))
497 BlockA = (const matroska_block *)*a;
498 else if (EBML_ElementIsType(*a, &MATROSKA_ContextBlockGroup))
499 BlockA = (const matroska_block *)EBML_MasterFindChild((ebml_master*)*a,&MATROSKA_ContextBlock);
500 if (EBML_ElementIsType(*b, &MATROSKA_ContextSimpleBlock))
501 BlockB = (const matroska_block *)*b;
502 else if (EBML_ElementIsType(*a, &MATROSKA_ContextBlockGroup))
503 BlockB = (const matroska_block *)EBML_MasterFindChild((ebml_master*)*b,&MATROSKA_ContextBlock);
504 if (BlockA != NULL && BlockB != NULL)
505 return MATROSKA_BlockCmp(BlockA,BlockB);
506
507 assert(0); // unsupported comparison
508 return 0;
509 }
510
MATROSKA_ClusterSort(matroska_cluster * Cluster)511 void MATROSKA_ClusterSort(matroska_cluster *Cluster)
512 {
513 EBML_MasterSort((ebml_master*)Cluster,(arraycmp)ClusterEltCmp,Cluster);
514 }
515
MATROSKA_ClusterSetTimecode(matroska_cluster * Cluster,timecode_t Timecode)516 void MATROSKA_ClusterSetTimecode(matroska_cluster *Cluster, timecode_t Timecode)
517 {
518 ebml_integer *TimecodeElt;
519 #if defined(CONFIG_EBML_WRITING)
520 ebml_element *Elt, *GBlock;
521 timecode_t BlockTimeCode;
522 #endif
523
524 assert(EBML_ElementIsType((ebml_element*)Cluster, &MATROSKA_ContextCluster));
525 Cluster->GlobalTimecode = Timecode;
526 TimecodeElt = (ebml_integer*)EBML_MasterGetChild((ebml_master*)Cluster,&MATROSKA_ContextTimecode);
527 #if defined(CONFIG_EBML_WRITING)
528 assert(Cluster->WriteSegInfo);
529 EBML_IntegerSetValue(TimecodeElt, Scale64(Timecode,1,MATROSKA_SegmentInfoTimecodeScale(Cluster->WriteSegInfo)));
530 // update all the blocks LocalTimecode
531 for (Elt = EBML_MasterChildren(Cluster); Elt; Elt = EBML_MasterNext(Elt))
532 {
533 if (EBML_ElementIsType(Elt, &MATROSKA_ContextBlockGroup))
534 {
535 for (GBlock = EBML_MasterChildren(Elt);GBlock;GBlock=EBML_MasterNext(GBlock))
536 {
537 if (EBML_ElementIsType(GBlock, &MATROSKA_ContextBlock))
538 {
539 BlockTimeCode = MATROSKA_BlockTimecode((matroska_block*)GBlock);
540 if (BlockTimeCode!=INVALID_TIMECODE_T)
541 MATROSKA_BlockSetTimecode((matroska_block*)GBlock, BlockTimeCode, Timecode);
542 break;
543 }
544 }
545 }
546 else if (EBML_ElementIsType(Elt, &MATROSKA_ContextSimpleBlock))
547 {
548 BlockTimeCode = MATROSKA_BlockTimecode((matroska_block*)Elt);
549 if (BlockTimeCode!=INVALID_TIMECODE_T)
550 MATROSKA_BlockSetTimecode((matroska_block*)Elt, BlockTimeCode, Timecode);
551 }
552 }
553 #else
554 assert(Cluster->ReadSegInfo);
555 EBML_IntegerSetValue(TimecodeElt, Scale64(Timecode,1,MATROSKA_SegmentInfoTimecodeScale(Cluster->ReadSegInfo)));
556 #endif
557 }
558
MATROSKA_ClusterTimecode(matroska_cluster * Cluster)559 timecode_t MATROSKA_ClusterTimecode(matroska_cluster *Cluster)
560 {
561 assert(EBML_ElementIsType((ebml_element*)Cluster, &MATROSKA_ContextCluster));
562 if (Cluster->GlobalTimecode == INVALID_TIMECODE_T)
563 {
564 ebml_integer *Timecode = (ebml_integer*)EBML_MasterFindChild((ebml_master*)Cluster,&MATROSKA_ContextTimecode);
565 if (Timecode)
566 Cluster->GlobalTimecode = EBML_IntegerValue(Timecode) * MATROSKA_SegmentInfoTimecodeScale(Cluster->ReadSegInfo);
567 }
568 return Cluster->GlobalTimecode;
569 }
570
MATROSKA_ClusterTimecodeScale(matroska_cluster * Cluster,bool_t Read)571 timecode_t MATROSKA_ClusterTimecodeScale(matroska_cluster *Cluster, bool_t Read)
572 {
573 #if defined(CONFIG_EBML_WRITING)
574 if (!Read)
575 return MATROSKA_SegmentInfoTimecodeScale(Cluster->WriteSegInfo);
576 #endif
577 return MATROSKA_SegmentInfoTimecodeScale(Cluster->ReadSegInfo);
578 }
579
MATROSKA_BlockSetTimecode(matroska_block * Block,timecode_t Timecode,timecode_t ClusterTimecode)580 err_t MATROSKA_BlockSetTimecode(matroska_block *Block, timecode_t Timecode, timecode_t ClusterTimecode)
581 {
582 int64_t InternalTimecode;
583 assert(Node_IsPartOf(Block,MATROSKA_BLOCK_CLASS));
584 assert(Timecode!=INVALID_TIMECODE_T);
585 #if defined(CONFIG_EBML_WRITING)
586 InternalTimecode = Scale64(Timecode - ClusterTimecode,1,(int64_t)(MATROSKA_SegmentInfoTimecodeScale(Block->WriteSegInfo) * MATROSKA_TrackTimecodeScale(Block->WriteTrack)));
587 #else
588 InternalTimecode = Scale64(Timecode - ClusterTimecode,1,(int64_t)(MATROSKA_SegmentInfoTimecodeScale(Block->ReadSegInfo) * MATROSKA_TrackTimecodeScale(Block->ReadTrack)));
589 #endif
590 if (InternalTimecode > 32767 || InternalTimecode < -32768)
591 return ERR_INVALID_DATA;
592 Block->LocalTimecode = (int16_t)InternalTimecode;
593 Block->LocalTimecodeUsed = 1;
594 return ERR_NONE;
595 }
596
MATROSKA_BlockTimecode(matroska_block * Block)597 timecode_t MATROSKA_BlockTimecode(matroska_block *Block)
598 {
599 ebml_element *Cluster;
600 assert(Node_IsPartOf(Block,MATROSKA_BLOCK_CLASS));
601 if (Block->GlobalTimecode!=INVALID_TIMECODE_T)
602 return Block->GlobalTimecode;
603 if (Block->ReadTrack==NULL)
604 return INVALID_TIMECODE_T;
605 assert(Block->LocalTimecodeUsed);
606 Cluster = EBML_ElementParent(Block);
607 while (Cluster && !EBML_ElementIsType(Cluster, &MATROSKA_ContextCluster))
608 Cluster = EBML_ElementParent(Cluster);
609 if (!Cluster)
610 return INVALID_TIMECODE_T;
611 Block->GlobalTimecode = MATROSKA_ClusterTimecode((matroska_cluster*)Cluster) + (timecode_t)(Block->LocalTimecode * MATROSKA_SegmentInfoTimecodeScale(Block->ReadSegInfo) * MATROSKA_TrackTimecodeScale(Block->ReadTrack));
612 MATROSKA_BlockSetTimecode(Block, Block->GlobalTimecode, MATROSKA_ClusterTimecode((matroska_cluster*)Cluster));
613 return Block->GlobalTimecode;
614 }
615
MATROSKA_BlockTrackNum(const matroska_block * Block)616 int16_t MATROSKA_BlockTrackNum(const matroska_block *Block)
617 {
618 assert(Node_IsPartOf(Block,MATROSKA_BLOCK_CLASS));
619 assert(Block->LocalTimecodeUsed);
620 return Block->TrackNumber;
621 }
622
MATROSKA_BlockKeyframe(const matroska_block * Block)623 bool_t MATROSKA_BlockKeyframe(const matroska_block *Block)
624 {
625 ebml_master *BlockGroup;
626 ebml_integer *Duration;
627
628 assert(Node_IsPartOf(Block,MATROSKA_BLOCK_CLASS));
629 if (Block->IsKeyframe)
630 return 1;
631
632 if (!EBML_ElementIsType((const ebml_element*)Block, &MATROSKA_ContextBlock))
633 return 0;
634
635 BlockGroup = (ebml_master*)EBML_ElementParent(Block);
636 if (!BlockGroup || !Node_IsPartOf(BlockGroup,MATROSKA_BLOCKGROUP_CLASS))
637 return 0;
638
639 if (EBML_MasterFindChild(BlockGroup,&MATROSKA_ContextReferenceBlock))
640 return 0;
641
642 Duration = (ebml_integer*)EBML_MasterFindChild(BlockGroup,&MATROSKA_ContextBlockDuration);
643 if (Duration!=NULL && EBML_IntegerValue(Duration)==0)
644 return 0;
645
646 return 1;
647 }
648
MATROSKA_BlockDiscardable(const matroska_block * Block)649 bool_t MATROSKA_BlockDiscardable(const matroska_block *Block)
650 {
651 assert(Node_IsPartOf(Block,MATROSKA_BLOCK_CLASS));
652 if (EBML_ElementIsType((const ebml_element*)Block, &MATROSKA_ContextBlock))
653 return 0;
654 return Block->IsDiscardable;
655 }
656
MATROSKA_BlockSetKeyframe(matroska_block * Block,bool_t Set)657 void MATROSKA_BlockSetKeyframe(matroska_block *Block, bool_t Set)
658 {
659 assert(Node_IsPartOf(Block,MATROSKA_BLOCK_CLASS));
660 Block->IsKeyframe = Set;
661 }
662
MATROSKA_BlockSetDiscardable(matroska_block * Block,bool_t Set)663 void MATROSKA_BlockSetDiscardable(matroska_block *Block, bool_t Set)
664 {
665 assert(Node_IsPartOf(Block,MATROSKA_BLOCK_CLASS));
666 if (EBML_ElementIsType((const ebml_element*)Block, &MATROSKA_ContextSimpleBlock))
667 Block->IsDiscardable = Set;
668 }
669
MATROSKA_BlockLaced(const matroska_block * Block)670 bool_t MATROSKA_BlockLaced(const matroska_block *Block)
671 {
672 assert(Node_IsPartOf(Block,MATROSKA_BLOCK_CLASS));
673 assert(Block->LocalTimecodeUsed);
674 return Block->Lacing != LACING_NONE;
675 }
676
MATROSKA_CueTrackNum(const matroska_cuepoint * Cue)677 int16_t MATROSKA_CueTrackNum(const matroska_cuepoint *Cue)
678 {
679 ebml_master *Position;
680 ebml_integer *CueTrack;
681 assert(EBML_ElementIsType((ebml_element*)Cue, &MATROSKA_ContextCuePoint));
682 Position = (ebml_master*)EBML_MasterFindChild((ebml_master*)Cue,&MATROSKA_ContextCueTrackPositions);
683 if (!Position)
684 return -1;
685 CueTrack = (ebml_integer*)EBML_MasterFindChild(Position,&MATROSKA_ContextCueTrack);
686 if (!CueTrack)
687 return -1;
688 return (int16_t)EBML_IntegerValue(CueTrack);
689 }
690
MATROSKA_CuesSort(ebml_master * Cues)691 void MATROSKA_CuesSort(ebml_master *Cues)
692 {
693 assert(EBML_ElementIsType((ebml_element*)Cues, &MATROSKA_ContextCues));
694 EBML_MasterSort(Cues,NULL,NULL);
695 }
696
MATROSKA_AttachmentSort(ebml_master * Attachments)697 void MATROSKA_AttachmentSort(ebml_master *Attachments)
698 {
699 assert(EBML_ElementIsType((ebml_element*)Attachments, &MATROSKA_ContextAttachments));
700 EBML_MasterSort(Attachments,NULL,NULL);
701 }
702
MATROSKA_SegmentInfoTimecodeScale(const ebml_master * SegmentInfo)703 timecode_t MATROSKA_SegmentInfoTimecodeScale(const ebml_master *SegmentInfo)
704 {
705 ebml_integer *TimecodeScale = NULL;
706 if (SegmentInfo)
707 {
708 assert(EBML_ElementIsType((ebml_element*)SegmentInfo, &MATROSKA_ContextInfo));
709 TimecodeScale = (ebml_integer*)EBML_MasterFindChild((ebml_master*)SegmentInfo,&MATROSKA_ContextTimecodeScale);
710 }
711 if (!TimecodeScale)
712 return MATROSKA_ContextTimecodeScale.DefaultValue;
713 return EBML_IntegerValue(TimecodeScale);
714 }
715
MATROSKA_TrackTimecodeScale(const ebml_master * Track)716 double MATROSKA_TrackTimecodeScale(const ebml_master *Track)
717 {
718 ebml_element *TimecodeScale;
719 assert(EBML_ElementIsType((ebml_element*)Track, &MATROSKA_ContextTrackEntry));
720 TimecodeScale = EBML_MasterFindChild((ebml_master*)Track,&MATROSKA_ContextTrackTimecodeScale);
721 if (!TimecodeScale)
722 return MATROSKA_ContextTrackTimecodeScale.DefaultValue;
723 return ((ebml_float*)TimecodeScale)->Value;
724 }
725
MATROSKA_CueTimecode(const matroska_cuepoint * Cue)726 timecode_t MATROSKA_CueTimecode(const matroska_cuepoint *Cue)
727 {
728 ebml_integer *TimeCode;
729 assert(EBML_ElementIsType((ebml_element*)Cue, &MATROSKA_ContextCuePoint));
730 TimeCode = (ebml_integer*) EBML_MasterFindChild((ebml_master*)Cue,&MATROSKA_ContextCueTime);
731 if (!TimeCode)
732 return INVALID_TIMECODE_T;
733 return EBML_IntegerValue(TimeCode) * MATROSKA_SegmentInfoTimecodeScale(Cue->SegInfo);
734 }
735
MATROSKA_CuePosInSegment(const matroska_cuepoint * Cue)736 filepos_t MATROSKA_CuePosInSegment(const matroska_cuepoint *Cue)
737 {
738 ebml_element *TimeCode;
739 assert(EBML_ElementIsType((ebml_element*)Cue, &MATROSKA_ContextCuePoint));
740 TimeCode = EBML_MasterFindChild((ebml_master*)Cue,&MATROSKA_ContextCueTrackPositions);
741 if (!TimeCode)
742 return INVALID_TIMECODE_T;
743 TimeCode = EBML_MasterFindChild((ebml_master*)TimeCode,&MATROSKA_ContextCueClusterPosition);
744 if (!TimeCode)
745 return INVALID_TIMECODE_T;
746 return EBML_IntegerValue((ebml_integer*)TimeCode);
747 }
748
MATROSKA_CuePointUpdate(matroska_cuepoint * Cue,ebml_element * Segment)749 err_t MATROSKA_CuePointUpdate(matroska_cuepoint *Cue, ebml_element *Segment)
750 {
751 ebml_element *TimecodeElt, *Elt, *PosInCluster;
752 ebml_integer *TrackNum;
753 assert(EBML_ElementIsType((ebml_element*)Cue, &MATROSKA_ContextCuePoint));
754 assert(Cue->Block);
755 assert(Cue->SegInfo);
756 assert(Segment); // we need the segment location
757 EBML_MasterErase((ebml_master*)Cue);
758 EBML_MasterAddMandatory((ebml_master*)Cue,1);
759 TimecodeElt = EBML_MasterGetChild((ebml_master*)Cue,&MATROSKA_ContextCueTime);
760 if (!TimecodeElt)
761 return ERR_OUT_OF_MEMORY;
762 EBML_IntegerSetValue((ebml_integer*)TimecodeElt, Scale64(MATROSKA_BlockTimecode(Cue->Block),1,MATROSKA_SegmentInfoTimecodeScale(Cue->SegInfo)));
763
764 Elt = EBML_MasterGetChild((ebml_master*)Cue,&MATROSKA_ContextCueTrackPositions);
765 if (!Elt)
766 return ERR_OUT_OF_MEMORY;
767 TrackNum = (ebml_integer*)EBML_MasterGetChild((ebml_master*)Elt,&MATROSKA_ContextCueTrack);
768 if (!TrackNum)
769 return ERR_OUT_OF_MEMORY;
770 EBML_IntegerSetValue(TrackNum, MATROSKA_BlockTrackNum(Cue->Block));
771
772 PosInCluster = EBML_MasterGetChild((ebml_master*)Elt,&MATROSKA_ContextCueClusterPosition);
773 if (!PosInCluster)
774 return ERR_OUT_OF_MEMORY;
775 Elt = EBML_ElementParent(Cue->Block);
776 while (Elt && !EBML_ElementIsType(Elt, &MATROSKA_ContextCluster))
777 Elt = EBML_ElementParent(Elt);
778 if (!Elt)
779 return ERR_INVALID_DATA;
780
781 assert(Elt->ElementPosition != INVALID_FILEPOS_T);
782
783 EBML_IntegerSetValue((ebml_integer*)PosInCluster, Elt->ElementPosition - EBML_ElementPositionData(Segment));
784
785 return ERR_NONE;
786 }
787
MATROSKA_GetBlockForTimecode(matroska_cluster * Cluster,timecode_t Timecode,int16_t Track)788 matroska_block *MATROSKA_GetBlockForTimecode(matroska_cluster *Cluster, timecode_t Timecode, int16_t Track)
789 {
790 ebml_element *Block, *GBlock;
791 for (Block = EBML_MasterChildren(Cluster);Block;Block=EBML_MasterNext(Block))
792 {
793 if (EBML_ElementIsType(Block, &MATROSKA_ContextBlockGroup))
794 {
795 for (GBlock = EBML_MasterChildren(Block);GBlock;GBlock=EBML_MasterNext(GBlock))
796 {
797 if (EBML_ElementIsType(GBlock, &MATROSKA_ContextBlock))
798 {
799 if (MATROSKA_BlockTrackNum((matroska_block*)GBlock) == Track &&
800 MATROSKA_BlockTimecode((matroska_block*)GBlock) == Timecode)
801 {
802 return (matroska_block*)GBlock;
803 }
804 }
805 }
806 }
807 else if (EBML_ElementIsType(Block, &MATROSKA_ContextSimpleBlock))
808 {
809 if (MATROSKA_BlockTrackNum((matroska_block*)Block) == Track &&
810 MATROSKA_BlockTimecode((matroska_block*)Block) == Timecode)
811 {
812 return (matroska_block*)Block;
813 }
814 }
815 }
816 return NULL;
817 }
818
MATROSKA_LinkClusterBlocks(matroska_cluster * Cluster,ebml_master * RSegmentInfo,ebml_master * Tracks,bool_t KeepUnmatched)819 void MATROSKA_LinkClusterBlocks(matroska_cluster *Cluster, ebml_master *RSegmentInfo, ebml_master *Tracks, bool_t KeepUnmatched)
820 {
821 ebml_element *Block, *GBlock,*NextBlock;
822
823 assert(Node_IsPartOf(Cluster,MATROSKA_CLUSTER_CLASS));
824 assert(EBML_ElementIsType((ebml_element*)RSegmentInfo, &MATROSKA_ContextInfo));
825 assert(EBML_ElementIsType((ebml_element*)Tracks, &MATROSKA_ContextTracks));
826
827 // link each Block/SimpleBlock with its Track and SegmentInfo
828 MATROSKA_LinkClusterReadSegmentInfo(Cluster,RSegmentInfo,1);
829 for (Block = EBML_MasterChildren(Cluster);Block;Block=NextBlock)
830 {
831 NextBlock = EBML_MasterNext(Block);
832 if (EBML_ElementIsType(Block, &MATROSKA_ContextBlockGroup))
833 {
834 for (GBlock = EBML_MasterChildren(Block);GBlock;GBlock=EBML_MasterNext(GBlock))
835 {
836 if (EBML_ElementIsType(GBlock, &MATROSKA_ContextBlock))
837 {
838 if (MATROSKA_LinkBlockWithReadTracks((matroska_block*)GBlock,Tracks,1)!=ERR_NONE && !KeepUnmatched)
839 NodeDelete((node*)Block);
840 else
841 MATROSKA_LinkBlockReadSegmentInfo((matroska_block*)GBlock,RSegmentInfo,1);
842 break;
843 }
844 }
845 }
846 else if (EBML_ElementIsType(Block, &MATROSKA_ContextSimpleBlock))
847 {
848 if (MATROSKA_LinkBlockWithReadTracks((matroska_block*)Block,Tracks,1)!=ERR_NONE && !KeepUnmatched)
849 NodeDelete((node*)Block);
850 else
851 MATROSKA_LinkBlockReadSegmentInfo((matroska_block*)Block,RSegmentInfo,1);
852 }
853 }
854 }
855
856
GetBlockHeadSize(const matroska_block * Element)857 static size_t GetBlockHeadSize(const matroska_block *Element)
858 {
859 assert(Element->TrackNumber < 0x4000);
860 if (Element->TrackNumber < 0x80)
861 return 4;
862 else
863 return 5;
864 }
865
MATROSKA_BlockReleaseData(matroska_block * Block,bool_t IncludingNotRead)866 err_t MATROSKA_BlockReleaseData(matroska_block *Block, bool_t IncludingNotRead)
867 {
868 if (!IncludingNotRead && Block->GlobalTimecode==INVALID_TIMECODE_T)
869 return ERR_NONE;
870 ArrayClear(&Block->Data);
871 Block->Base.Base.bValueIsSet = 0;
872 if (ARRAYCOUNT(Block->SizeListIn,int32_t))
873 {
874 // recover the size of each lace in SizeList for later reading
875 int32_t *i,*o;
876 assert(ARRAYCOUNT(Block->SizeListIn,int32_t) == ARRAYCOUNT(Block->SizeList,int32_t));
877 for (i=ARRAYBEGIN(Block->SizeListIn,int32_t),o=ARRAYBEGIN(Block->SizeList,int32_t);i!=ARRAYEND(Block->SizeListIn,int32_t);++i,++o)
878 *o = *i;
879 ArrayClear(&Block->SizeListIn);
880 }
881 return ERR_NONE;
882 }
883
MATROSKA_BlockSkipToFrame(const matroska_block * Block,stream * Input,size_t FrameNum)884 err_t MATROSKA_BlockSkipToFrame(const matroska_block *Block, stream *Input, size_t FrameNum)
885 {
886 uint32_t *i;
887 filepos_t SeekPos = EBML_ElementPositionData((ebml_element*)Block);
888 if (FrameNum >= ARRAYCOUNT(Block->SizeList,uint32_t))
889 return ERR_INVALID_PARAM;
890 if (Block->Lacing == LACING_NONE)
891 SeekPos += GetBlockHeadSize(Block);
892 else
893 {
894 SeekPos = Block->FirstFrameLocation;
895 for (i=ARRAYBEGIN(Block->SizeList,uint32_t);FrameNum;--FrameNum,++i)
896 SeekPos += *i;
897 }
898 if (Stream_Seek(Input,SeekPos,SEEK_SET) != SeekPos)
899 return ERR_READ;
900 return ERR_NONE;
901 }
902
903 // TODO: support zero copy reading (read the frames directly into a buffer with a callback per frame)
904 // pass the Input stream and the amount to read per frame, give the timecode of the frame and get the end timecode in return, get an error code if reading failed
MATROSKA_BlockReadData(matroska_block * Element,stream * Input)905 err_t MATROSKA_BlockReadData(matroska_block *Element, stream *Input)
906 {
907 size_t Read,BufSize;
908 size_t NumFrame;
909 err_t Err = ERR_NONE;
910 ebml_element *Elt, *Elt2, *Header = NULL;
911 uint8_t *InBuf;
912 int CompressionScope = MATROSKA_COMPR_SCOPE_BLOCK;
913
914 if (!Element->Base.Base.bValueIsSet)
915 {
916 // find out if compressed headers are used
917 assert(Element->ReadTrack!=NULL);
918 Elt = EBML_MasterFindChild(Element->ReadTrack, &MATROSKA_ContextContentEncodings);
919 if (Elt)
920 {
921 Elt = EBML_MasterFindChild((ebml_master*)Elt, &MATROSKA_ContextContentEncoding);
922 if (EBML_MasterChildren(Elt))
923 {
924 if (EBML_MasterNext(Elt))
925 return ERR_NOT_SUPPORTED; // TODO support cascaded compression/encryption
926
927 Elt2 = EBML_MasterFindChild((ebml_master*)Elt, &MATROSKA_ContextContentEncodingScope);
928 if (Elt2)
929 CompressionScope = (int)EBML_IntegerValue((ebml_integer*)Elt2);
930
931 Elt = EBML_MasterFindChild((ebml_master*)Elt, &MATROSKA_ContextContentCompression);
932 if (!Elt)
933 return ERR_NOT_SUPPORTED; // TODO: support encryption
934
935 Header = EBML_MasterGetChild((ebml_master*)Elt, &MATROSKA_ContextContentCompAlgo);
936 #if defined(CONFIG_ZLIB) || defined(CONFIG_LZO1X) || defined(CONFIG_BZLIB)
937 if (EBML_IntegerValue((ebml_integer*)Header)!=MATROSKA_BLOCK_COMPR_HEADER)
938 #if defined(CONFIG_ZLIB)
939 if (EBML_IntegerValue((ebml_integer*)Header)!=MATROSKA_BLOCK_COMPR_ZLIB)
940 #endif
941 #if defined(CONFIG_LZO1X)
942 if (EBML_IntegerValue((ebml_integer*)Header)!=MATROSKA_BLOCK_COMPR_LZO1X)
943 #endif
944 #if defined(CONFIG_BZLIB)
945 if (EBML_IntegerValue((ebml_integer*)Header)!=MATROSKA_BLOCK_COMPR_BZLIB)
946 #endif
947 #else
948 if (EBML_IntegerValue((ebml_integer*)Header)!=MATROSKA_BLOCK_COMPR_HEADER)
949 #endif
950 return ERR_INVALID_DATA;
951
952 if (EBML_IntegerValue((ebml_integer*)Header)==MATROSKA_BLOCK_COMPR_HEADER)
953 Header = EBML_MasterFindChild((ebml_master*)Elt, &MATROSKA_ContextContentCompSettings);
954 }
955 }
956
957 #if !defined(CONFIG_ZLIB) && !defined(CONFIG_LZO1X) && !defined(CONFIG_BZLIB)
958 if (Header && Header->Context==&MATROSKA_ContextContentCompAlgo)
959 return ERR_NOT_SUPPORTED;
960 #endif
961
962 if (Header && Header->Context==&MATROSKA_ContextContentCompAlgo && !(CompressionScope & MATROSKA_COMPR_SCOPE_BLOCK))
963 Header = NULL;
964
965 Stream_Seek(Input,Element->FirstFrameLocation,SEEK_SET);
966 if (Header)
967 ArrayCopy(&Element->SizeListIn, &Element->SizeList);
968 switch (Element->Lacing)
969 {
970 case LACING_NONE:
971 #if defined(CONFIG_ZLIB) || defined(CONFIG_LZO1X) || defined(CONFIG_BZLIB)
972 if (Header && Header->Context==&MATROSKA_ContextContentCompAlgo)
973 {
974 // zlib handling, read the buffer in temp memory
975 array TmpBuf;
976 ArrayInit(&TmpBuf);
977 if (!ArrayResize(&TmpBuf,(size_t)ARRAYBEGIN(Element->SizeList,int32_t)[0],0))
978 Err = ERR_OUT_OF_MEMORY;
979 InBuf = ARRAYBEGIN(TmpBuf,uint8_t);
980 Err = Stream_Read(Input,InBuf,(size_t)ARRAYBEGIN(Element->SizeList,int32_t)[0],&Read);
981 if (Err==ERR_NONE)
982 {
983 if (Read!=(size_t)ARRAYBEGIN(Element->SizeList,int32_t)[0])
984 Err = ERR_READ;
985 else
986 {
987 #if defined(CONFIG_ZLIB)
988 if (EBML_IntegerValue((ebml_integer*)Header)==MATROSKA_BLOCK_COMPR_ZLIB)
989 {
990 // get the ouput size, adjust the Element->SizeList value, write in Element->Data
991 z_stream stream;
992 int Res;
993 memset(&stream,0,sizeof(stream));
994 Res = inflateInit(&stream);
995 if (Res != Z_OK)
996 Err = ERR_INVALID_DATA;
997 else
998 {
999 size_t Count = 0;
1000 stream.next_in = InBuf;
1001 stream.avail_in = ARRAYBEGIN(Element->SizeList,int32_t)[0];
1002 stream.next_out = ARRAYBEGIN(Element->Data,uint8_t);
1003 do {
1004 Count = stream.next_out - ARRAYBEGIN(Element->Data,uint8_t);
1005 stream.avail_out = 1024;
1006 if (!ArrayResize(&Element->Data, Count + stream.avail_out, 0))
1007 {
1008 Res = Z_MEM_ERROR;
1009 break;
1010 }
1011 stream.next_out = ARRAYBEGIN(Element->Data,uint8_t) + Count;
1012 Res = inflate(&stream, Z_NO_FLUSH);
1013 if (Res!=Z_STREAM_END && Res!=Z_OK)
1014 break;
1015 } while (Res!=Z_STREAM_END && stream.avail_in && !stream.avail_out);
1016 ArrayResize(&Element->Data, stream.total_out, 0);
1017 ARRAYBEGIN(Element->SizeList,int32_t)[0] = stream.total_out;
1018 inflateEnd(&stream);
1019 if (Res != Z_STREAM_END)
1020 Err = ERR_INVALID_DATA;
1021 }
1022 }
1023 #endif
1024 #if defined(CONFIG_LZO1X)
1025 if (EBML_IntegerValue((ebml_integer*)Header)==MATROSKA_BLOCK_COMPR_LZO1X)
1026 {
1027 if (lzo_init() != LZO_E_OK)
1028 Err = ERR_INVALID_DATA;
1029 else
1030 {
1031 lzo_uint outSize = max(2048, ARRAYBEGIN(Element->SizeList,int32_t)[0] << 2);
1032 if (!ArrayResize(&Element->Data, outSize, 0))
1033 Err = ERR_OUT_OF_MEMORY;
1034 else
1035 {
1036 if (lzo1x_decompress_safe(InBuf, ARRAYBEGIN(Element->SizeList,int32_t)[0], ARRAYBEGIN(Element->Data,uint8_t), &outSize, NULL) != LZO_E_OK)
1037 Err = ERR_INVALID_DATA;
1038 else
1039 {
1040 ARRAYBEGIN(Element->SizeList,int32_t)[0] = outSize;
1041 ArrayResize(&Element->Data,outSize,0);
1042 }
1043 }
1044 }
1045 }
1046 #endif
1047 #if defined(CONFIG_BZLIB)
1048 if (EBML_IntegerValue((ebml_integer*)Header)==MATROSKA_BLOCK_COMPR_BZLIB)
1049 {
1050 unsigned int outSize = ARRAYBEGIN(Element->SizeList,int32_t)[0] << 2;
1051 bz_stream strm;
1052 int Res;
1053
1054 if (!ArrayResize(&Element->Data, outSize, 0))
1055 Err = ERR_OUT_OF_MEMORY;
1056 else
1057 {
1058 strm.bzalloc = NULL;
1059 strm.bzfree = NULL;
1060 strm.opaque = NULL;
1061 if (BZ2_bzDecompressInit (&strm, 0, 1) != BZ_OK)
1062 Err = ERR_INVALID_DATA;
1063 else
1064 {
1065 size_t Count = 0;
1066 strm.next_in = (char*)InBuf;
1067 strm.avail_in = ARRAYBEGIN(Element->SizeList,int32_t)[0];
1068 strm.next_out = ARRAYBEGIN(Element->Data,char);
1069 strm.avail_out = 0;
1070
1071 do {
1072 Count = strm.next_out - ARRAYBEGIN(Element->Data,char);
1073 strm.avail_out = 1024;
1074 if (!ArrayResize(&Element->Data, Count + strm.avail_out, 0))
1075 {
1076 Res = BZ_MEM_ERROR;
1077 break;
1078 }
1079 strm.next_out = ARRAYBEGIN(Element->Data,char) + Count;
1080 Res = BZ2_bzDecompress(&strm);
1081 if (Res!=BZ_STREAM_END && Res!=BZ_OK)
1082 break;
1083 } while (Res!=BZ_STREAM_END && strm.avail_in && !strm.avail_out);
1084 ArrayResize(&Element->Data, strm.total_out_lo32, 0);
1085 ARRAYBEGIN(Element->SizeList,int32_t)[0] = strm.total_out_lo32;
1086 BZ2_bzDecompressEnd(&strm);
1087 if (Res != BZ_STREAM_END)
1088 Err = ERR_INVALID_DATA;
1089 }
1090 }
1091 }
1092 #endif
1093 }
1094 }
1095 ArrayClear(&TmpBuf);
1096 }
1097 else
1098 #endif
1099 {
1100 if (!ArrayResize(&Element->Data,(size_t)ARRAYBEGIN(Element->SizeList,int32_t)[0],0))
1101 {
1102 Err = ERR_OUT_OF_MEMORY;
1103 goto failed;
1104 }
1105 InBuf = ARRAYBEGIN(Element->Data,uint8_t);
1106 if (Header)
1107 {
1108 memcpy(InBuf,ARRAYBEGIN(((ebml_binary*)Header)->Data,uint8_t),(size_t)Header->DataSize);
1109 InBuf += (size_t)Header->DataSize;
1110 }
1111 Err = Stream_Read(Input,InBuf,(size_t)(ARRAYBEGIN(Element->SizeList,int32_t)[0] - (Header?Header->DataSize:0)),&Read);
1112 if (Err != ERR_NONE)
1113 goto failed;
1114 if (Read + (Header?Header->DataSize:0) != (size_t)ARRAYBEGIN(Element->SizeList,int32_t)[0])
1115 {
1116 Err = ERR_READ;
1117 goto failed;
1118 }
1119 }
1120 break;
1121 case LACING_EBML:
1122 case LACING_XIPH:
1123 case LACING_FIXED:
1124 Read = 0;
1125 BufSize = 0;
1126 for (NumFrame=0;NumFrame<ARRAYCOUNT(Element->SizeList,int32_t);++NumFrame)
1127 BufSize += ARRAYBEGIN(Element->SizeList,int32_t)[NumFrame];
1128 #if defined(CONFIG_ZLIB) || defined(CONFIG_LZO1X) || defined(CONFIG_BZLIB)
1129 if (Header && Header->Context==&MATROSKA_ContextContentCompAlgo)
1130 {
1131 // zlib handling, read the buffer in temp memory
1132 // get the ouput size, adjust the Element->SizeList value, write in Element->Data
1133 array TmpBuf;
1134 int32_t FrameSize;
1135 size_t OutSize = 0;
1136
1137 ArrayInit(&TmpBuf);
1138 if (!ArrayResize(&TmpBuf,BufSize,0))
1139 {
1140 Err = ERR_OUT_OF_MEMORY;
1141 goto failed;
1142 }
1143 InBuf = ARRAYBEGIN(TmpBuf,uint8_t);
1144 Err = Stream_Read(Input,InBuf,BufSize,&Read);
1145 if (Err != ERR_NONE || Read!=BufSize)
1146 {
1147 if (Err==ERR_NONE)
1148 Err = ERR_READ;
1149 ArrayClear(&TmpBuf);
1150 goto failed;
1151 }
1152 for (NumFrame=0;Err==ERR_NONE && NumFrame<ARRAYCOUNT(Element->SizeList,int32_t);++NumFrame)
1153 {
1154 #if defined(CONFIG_ZLIB)
1155 if (EBML_IntegerValue((ebml_integer*)Header)==MATROSKA_BLOCK_COMPR_ZLIB)
1156 {
1157 z_stream stream;
1158 int Res;
1159 memset(&stream,0,sizeof(stream));
1160 Res = inflateInit(&stream);
1161 if (Res != Z_OK)
1162 Err = ERR_INVALID_DATA;
1163 else
1164 {
1165 size_t Count;
1166 stream.next_in = InBuf;
1167 stream.avail_in = FrameSize = ARRAYBEGIN(Element->SizeList,int32_t)[NumFrame];
1168 stream.next_out = ARRAYBEGIN(Element->Data,uint8_t) + OutSize;
1169 do {
1170 Count = stream.next_out - ARRAYBEGIN(Element->Data,uint8_t);
1171 if (!ArrayResize(&Element->Data, Count + 1024, 0))
1172 {
1173 Res = Z_MEM_ERROR;
1174 break;
1175 }
1176 stream.avail_out = ARRAYCOUNT(Element->Data,uint8_t) - Count;
1177 stream.next_out = ARRAYBEGIN(Element->Data,uint8_t) + Count;
1178 Res = inflate(&stream, Z_NO_FLUSH);
1179 if (Res!=Z_STREAM_END && Res!=Z_OK)
1180 break;
1181 } while (Res!=Z_STREAM_END && stream.avail_in && !stream.avail_out);
1182 ARRAYBEGIN(Element->SizeList,int32_t)[NumFrame] = stream.total_out;
1183 OutSize += stream.total_out;
1184 inflateEnd(&stream);
1185 if (Res != Z_STREAM_END)
1186 Err = ERR_INVALID_DATA;
1187 }
1188 }
1189 #endif
1190 #if defined(CONFIG_LZO1X)
1191 if (EBML_IntegerValue((ebml_integer*)Header)==MATROSKA_BLOCK_COMPR_LZO1X)
1192 {
1193 if (lzo_init() != LZO_E_OK)
1194 Err = ERR_INVALID_DATA;
1195 else
1196 {
1197 lzo_uint outSize = max(2048, ARRAYBEGIN(Element->SizeList,int32_t)[NumFrame] << 2);
1198 FrameSize = ARRAYBEGIN(Element->SizeList,int32_t)[NumFrame];
1199 if (!ArrayResize(&Element->Data, OutSize + outSize, 0))
1200 Err = ERR_OUT_OF_MEMORY;
1201 else
1202 {
1203 if (lzo1x_decompress_safe(InBuf, ARRAYBEGIN(Element->SizeList,int32_t)[NumFrame], ARRAYBEGIN(Element->Data,uint8_t) + OutSize, &outSize, NULL) != LZO_E_OK)
1204 Err = ERR_INVALID_DATA;
1205 else
1206 {
1207 OutSize += outSize;
1208 ARRAYBEGIN(Element->SizeList,int32_t)[NumFrame] = outSize;
1209 ArrayResize(&Element->Data,OutSize,0);
1210 }
1211 }
1212 }
1213 }
1214 #endif
1215 #if defined(CONFIG_BZLIB)
1216 if (EBML_IntegerValue((ebml_integer*)Header)==MATROSKA_BLOCK_COMPR_BZLIB)
1217 {
1218 bz_stream stream;
1219 int Res;
1220 memset(&stream,0,sizeof(stream));
1221 Res = BZ2_bzDecompressInit (&stream, 0, 1);
1222 if (Res != BZ_OK)
1223 Err = ERR_INVALID_DATA;
1224 else
1225 {
1226 size_t Count;
1227 stream.next_in = (char*)InBuf;
1228 stream.avail_in = FrameSize = ARRAYBEGIN(Element->SizeList,int32_t)[NumFrame];
1229 stream.next_out = ARRAYBEGIN(Element->Data,char) + OutSize;
1230 do {
1231 Count = stream.next_out - ARRAYBEGIN(Element->Data,char);
1232 if (!ArrayResize(&Element->Data, Count + 1024, 0))
1233 {
1234 Res = BZ_MEM_ERROR;
1235 break;
1236 }
1237 stream.avail_out = ARRAYCOUNT(Element->Data,uint8_t) - Count;
1238 stream.next_out = ARRAYBEGIN(Element->Data,char) + Count;
1239 Res = BZ2_bzDecompress(&stream);
1240 if (Res!=BZ_STREAM_END && Res!=BZ_OK)
1241 break;
1242 } while (Res!=BZ_STREAM_END && stream.avail_in && !stream.avail_out);
1243 ARRAYBEGIN(Element->SizeList,int32_t)[NumFrame] = stream.total_out_lo32;
1244 OutSize += stream.total_out_lo32;
1245 BZ2_bzDecompressEnd(&stream);
1246 if (Res != BZ_STREAM_END)
1247 Err = ERR_INVALID_DATA;
1248 }
1249 }
1250 #endif
1251 InBuf += FrameSize;
1252 }
1253 ArrayResize(&Element->Data, OutSize, 0); // shrink the buffer
1254 ArrayClear(&TmpBuf);
1255 }
1256 else
1257 #endif
1258 {
1259 if (!ArrayResize(&Element->Data,BufSize,0))
1260 {
1261 Err = ERR_OUT_OF_MEMORY;
1262 goto failed;
1263 }
1264 if (!Header)
1265 {
1266 //assert(BufSize + Element->FirstFrameLocation == Element->Base.Base.DataSize);
1267 Err = Stream_Read(Input,ARRAYBEGIN(Element->Data,uint8_t),BufSize,&BufSize);
1268 }
1269 else
1270 {
1271 InBuf = ARRAYBEGIN(Element->Data,uint8_t);
1272 for (NumFrame=0;NumFrame<ARRAYCOUNT(Element->SizeList,int32_t);++NumFrame)
1273 {
1274 memcpy(InBuf,ARRAYBEGIN(((ebml_binary*)Header)->Data,uint8_t),(size_t)Header->DataSize);
1275 InBuf += (size_t)Header->DataSize;
1276 Read = ARRAYBEGIN(Element->SizeList,int32_t)[NumFrame] - (int32_t)Header->DataSize;
1277 BufSize = Read;
1278 assert(InBuf + Read <= ARRAYEND(Element->Data,uint8_t));
1279 Err = Stream_Read(Input,InBuf,BufSize,&Read);
1280 if (Err != ERR_NONE || Read!=BufSize)
1281 goto failed;
1282 InBuf += Read;
1283 }
1284 }
1285 }
1286 if (Err != ERR_NONE)
1287 goto failed;
1288 break;
1289 default:
1290 assert(0); // we should support the other lacing modes
1291 Err = ERR_NOT_SUPPORTED;
1292 goto failed;
1293 }
1294 Element->Base.Base.bValueIsSet = 1;
1295 }
1296
1297 #if defined(CONFIG_EBML_WRITING)
1298 if (Element->ReadTrack != Element->WriteTrack || Element->ReadSegInfo != Element->WriteSegInfo)
1299 // TODO: only if the track compression/timecode scale is different
1300 Element->Base.Base.bNeedDataSizeUpdate = 1;
1301 #endif
1302
1303 failed:
1304 return Err;
1305 }
1306
SetBlockParent(matroska_block * Block,void * Parent,void * Before)1307 static err_t SetBlockParent(matroska_block *Block, void* Parent, void* Before)
1308 {
1309 // update the timecode
1310 timecode_t AbsTimeCode;
1311 err_t Result = ERR_NONE;
1312 if (Block->LocalTimecodeUsed && Parent && NodeTree_Parent(Block))
1313 {
1314 assert(Node_IsPartOf(Parent,MATROSKA_CLUSTER_CLASS));
1315 AbsTimeCode = MATROSKA_BlockTimecode(Block);
1316 assert(AbsTimeCode != INVALID_TIMECODE_T);
1317 Result = MATROSKA_BlockSetTimecode(Block,AbsTimeCode,MATROSKA_ClusterTimecode((matroska_cluster*)Parent));
1318 }
1319 if (Result==ERR_NONE)
1320 Result = INHERITED(Block,nodetree_vmt,MATROSKA_BLOCK_CLASS)->SetParent(Block, Parent, Before);
1321 return Result;
1322 }
1323
SetBlockGroupParent(ebml_master * Element,void * Parent,void * Before)1324 static err_t SetBlockGroupParent(ebml_master *Element, void* Parent, void* Before)
1325 {
1326 // update the timecode
1327 err_t Result = ERR_NONE;
1328 matroska_block *Block = (matroska_block*)EBML_MasterFindChild(Element, &MATROSKA_ContextBlock);
1329 timecode_t AbsTimeCode;
1330 if (Block && Block->LocalTimecodeUsed && Parent && NodeTree_Parent(Block) && NodeTree_Parent(NodeTree_Parent(Block)))
1331 {
1332 assert(Node_IsPartOf(Parent,MATROSKA_CLUSTER_CLASS));
1333 AbsTimeCode = MATROSKA_BlockTimecode(Block);
1334 assert(AbsTimeCode != INVALID_TIMECODE_T);
1335 Result = MATROSKA_BlockSetTimecode(Block,AbsTimeCode,MATROSKA_ClusterTimecode((matroska_cluster*)Parent));
1336 }
1337 if (Result==ERR_NONE)
1338 Result = INHERITED(Element,nodetree_vmt,MATROSKA_BLOCKGROUP_CLASS)->SetParent(Element, Parent, Before);
1339 return Result;
1340 }
1341
ReadBigBinaryData(ebml_binary * Element,stream * Input,const ebml_parser_context * ParserContext,bool_t AllowDummyElt,int Scope,size_t DepthCheckCRC)1342 static err_t ReadBigBinaryData(ebml_binary *Element, stream *Input, const ebml_parser_context *ParserContext, bool_t AllowDummyElt, int Scope, size_t DepthCheckCRC)
1343 {
1344 if (Scope == SCOPE_PARTIAL_DATA)
1345 {
1346 EBML_ElementSkipData((ebml_element*)Element,Input,ParserContext,NULL,AllowDummyElt);
1347 return ERR_NONE;
1348 }
1349 return INHERITED(Element,ebml_element_vmt,MATROSKA_BIGBINARY_CLASS)->ReadData(Element, Input, ParserContext, AllowDummyElt, Scope, DepthCheckCRC);
1350 }
1351
ReadBlockData(matroska_block * Element,stream * Input,const ebml_parser_context * ParserContext,bool_t AllowDummyElt,int Scope)1352 static err_t ReadBlockData(matroska_block *Element, stream *Input, const ebml_parser_context *ParserContext, bool_t AllowDummyElt, int Scope)
1353 {
1354 err_t Result;
1355 uint8_t _TempHead[5];
1356 uint8_t *cursor = _TempHead;
1357 uint8_t *_tmpBuf;
1358 uint8_t BlockHeadSize = 4; // default when the TrackNumber is < 16
1359
1360 assert(!Element->Base.Base.bValueIsSet);
1361 Element->Base.Base.bValueIsSet = 0;
1362
1363 if (Scope == SCOPE_NO_DATA)
1364 return ERR_NONE;
1365
1366 if (Stream_Seek(Input,EBML_ElementPositionData((ebml_element*)Element),SEEK_SET)==INVALID_FILEPOS_T)
1367 {
1368 Result = ERR_READ;
1369 goto failed;
1370 }
1371
1372 Result = Stream_Read(Input,_TempHead, 5, NULL);
1373 if (Result != ERR_NONE)
1374 goto failed;
1375 // update internal values
1376 Element->TrackNumber = *cursor++;
1377 if (Element->TrackNumber & 0x80)
1378 Element->TrackNumber &= 0x7F;
1379 else
1380 {
1381 // there is extra data
1382 if ((Element->TrackNumber & 0x40) == 0)
1383 {
1384 // We don't support track numbers that large !
1385 Result = ERR_INVALID_DATA;
1386 goto failed;
1387 }
1388 Element->TrackNumber = (Element->TrackNumber & 0x3F) << 8;
1389 Element->TrackNumber += *cursor++;
1390 BlockHeadSize++;
1391 }
1392
1393 Element->LocalTimecode = LOAD16BE(cursor);
1394 Element->LocalTimecodeUsed = 1;
1395 cursor += 2;
1396
1397 if (EBML_ElementIsType((ebml_element*)Element, &MATROSKA_ContextSimpleBlock))
1398 {
1399 Element->IsKeyframe = (*cursor & 0x80) != 0;
1400 Element->IsDiscardable = (*cursor & 0x01) != 0;
1401 }
1402 Element->Invisible = (*cursor & 0x08) >> 3;
1403 Element->Lacing = (*cursor++ & 0x06) >> 1;
1404
1405 Element->FirstFrameLocation = EBML_ElementPositionData((ebml_element*)Element) + BlockHeadSize;
1406
1407 if (cursor == &_TempHead[4])
1408 _TempHead[0] = _TempHead[4];
1409 else
1410 Result += Stream_Read(Input,_TempHead, 1, NULL);
1411
1412 // put all Frames in the list
1413 if (Element->Lacing == LACING_NONE)
1414 {
1415 ArrayResize(&Element->SizeList,sizeof(int32_t),0);
1416 ARRAYBEGIN(Element->SizeList,int32_t)[0] = (size_t)Element->Base.Base.DataSize - BlockHeadSize;
1417 }
1418 else
1419 {
1420 // read the number of frames in the lace
1421 uint32_t LastBufferSize = (size_t)Element->Base.Base.DataSize - BlockHeadSize - 1; // 1 for number of frame
1422 uint8_t FrameNum = _TempHead[0]; // number of frames in the lace - 1
1423 // read the list of frame sizes
1424 uint8_t Index;
1425 int32_t FrameSize;
1426 size_t SizeRead;
1427 filepos_t SizeUnknown;
1428
1429 Element->FirstFrameLocation++; // for the number of frame
1430 ArrayResize(&Element->SizeList,sizeof(int32_t)*(FrameNum + 1),0);
1431
1432 switch (Element->Lacing)
1433 {
1434 case LACING_XIPH:
1435 for (Index=0; Index<FrameNum; Index++)
1436 {
1437 // get the size of the frame
1438 FrameSize = 0;
1439 do {
1440 Result += Stream_Read(Input,_TempHead, 1, NULL);
1441 FrameSize += _TempHead[0];
1442 LastBufferSize--;
1443
1444 Element->FirstFrameLocation++;
1445 } while (_TempHead[0] == 0xFF);
1446
1447 ARRAYBEGIN(Element->SizeList,int32_t)[Index] = FrameSize;
1448 LastBufferSize -= FrameSize;
1449 }
1450 ARRAYBEGIN(Element->SizeList,int32_t)[Index] = LastBufferSize;
1451 break;
1452 case LACING_EBML:
1453 SizeRead = LastBufferSize;
1454 _tmpBuf = malloc(FrameNum*4);
1455 cursor = _tmpBuf; /// \warning assume the mean size will be coded in less than 4 bytes
1456 Result += Stream_Read(Input,cursor, FrameNum*4,NULL);
1457 FrameSize = (int32_t)EBML_ReadCodedSizeValue(cursor, &SizeRead, &SizeUnknown);
1458 ARRAYBEGIN(Element->SizeList,int32_t)[0] = FrameSize;
1459 cursor += SizeRead;
1460 LastBufferSize -= FrameSize + SizeRead;
1461
1462 for (Index=1; Index<FrameNum; Index++)
1463 {
1464 // get the size of the frame
1465 SizeRead = LastBufferSize;
1466 FrameSize += (int32_t)EBML_ReadCodedSizeSignedValue(cursor, &SizeRead, &SizeUnknown);
1467 ARRAYBEGIN(Element->SizeList,int32_t)[Index] = FrameSize;
1468 cursor += SizeRead;
1469 LastBufferSize -= FrameSize + SizeRead;
1470 }
1471
1472 Element->FirstFrameLocation += cursor - _tmpBuf;
1473
1474 ARRAYBEGIN(Element->SizeList,int32_t)[Index] = LastBufferSize;
1475 free(_tmpBuf);
1476 break;
1477 case LACING_FIXED:
1478 for (Index=0; Index<=FrameNum; Index++)
1479 // get the size of the frame
1480 ARRAYBEGIN(Element->SizeList,int32_t)[Index] = LastBufferSize / (FrameNum + 1);
1481 break;
1482 default: // other lacing not supported
1483 assert(0);
1484 }
1485 }
1486
1487 if (Scope == SCOPE_PARTIAL_DATA)
1488 {
1489 if (Stream_Seek(Input,Element->Lacing==LACING_NONE ? (EBML_ElementPositionData((ebml_element*)Element) + BlockHeadSize) : Element->FirstFrameLocation,SEEK_SET)==INVALID_FILEPOS_T)
1490 Result = ERR_READ;
1491 else
1492 Result = ERR_NONE;
1493 }
1494 else
1495 Result = MATROSKA_BlockReadData(Element, Input);
1496
1497 failed:
1498 return Result;
1499 }
1500
MATROSKA_BlockGetFrame(const matroska_block * Block,size_t FrameNum,matroska_frame * Frame,bool_t WithData)1501 err_t MATROSKA_BlockGetFrame(const matroska_block *Block, size_t FrameNum, matroska_frame *Frame, bool_t WithData)
1502 {
1503 size_t i;
1504
1505 assert(!WithData || Block->Base.Base.bValueIsSet);
1506 if (WithData && !ARRAYCOUNT(Block->Data,uint8_t))
1507 return ERR_READ;
1508 if (FrameNum >= ARRAYCOUNT(Block->SizeList,uint32_t))
1509 return ERR_INVALID_PARAM;
1510
1511 Frame->Data = WithData ? ARRAYBEGIN(Block->Data,uint8_t) : NULL;
1512 Frame->Timecode = MATROSKA_BlockTimecode((matroska_block*)Block);
1513 for (i=0;i<FrameNum;++i)
1514 {
1515 if (WithData) Frame->Data += ARRAYBEGIN(Block->SizeList,uint32_t)[i];
1516 if (Frame->Timecode != INVALID_TIMECODE_T)
1517 {
1518 if (i < ARRAYCOUNT(Block->Durations,timecode_t) && ARRAYBEGIN(Block->Durations,timecode_t)[i] != INVALID_TIMECODE_T)
1519 Frame->Timecode += ARRAYBEGIN(Block->Durations,timecode_t)[i];
1520 else
1521 Frame->Timecode = INVALID_TIMECODE_T;
1522 }
1523 }
1524
1525 Frame->Size = ARRAYBEGIN(Block->SizeList,uint32_t)[i];
1526 if (FrameNum < ARRAYCOUNT(Block->Durations,timecode_t))
1527 Frame->Duration = ARRAYBEGIN(Block->Durations,timecode_t)[i];
1528 else
1529 Frame->Duration = INVALID_TIMECODE_T;
1530 return ERR_NONE;
1531 }
1532
MATROSKA_BlockAppendFrame(matroska_block * Block,const matroska_frame * Frame,timecode_t ClusterTimecode)1533 err_t MATROSKA_BlockAppendFrame(matroska_block *Block, const matroska_frame *Frame, timecode_t ClusterTimecode)
1534 {
1535 if (!Block->Base.Base.bValueIsSet && Frame->Timecode!=INVALID_TIMECODE_T)
1536 MATROSKA_BlockSetTimecode(Block,Frame->Timecode,ClusterTimecode);
1537 ArrayAppend(&Block->Data,Frame->Data,Frame->Size,0);
1538 ArrayAppend(&Block->Durations,&Frame->Duration,sizeof(Frame->Duration),0);
1539 ArrayAppend(&Block->SizeList,&Frame->Size,sizeof(Frame->Size),0);
1540 Block->Base.Base.bValueIsSet = 1;
1541 Block->Base.Base.bNeedDataSizeUpdate = 1;
1542 Block->Lacing = LACING_AUTO;
1543 return ERR_NONE;
1544 }
1545
1546 #if defined(CONFIG_ZLIB)
UnCompressFrameZLib(const uint8_t * Cursor,size_t CursorSize,array * OutBuf,size_t * FrameSize,size_t * ArrayOffset)1547 err_t UnCompressFrameZLib(const uint8_t *Cursor, size_t CursorSize, array *OutBuf, size_t *FrameSize, size_t *ArrayOffset)
1548 {
1549 z_stream stream;
1550 int Res;
1551 err_t Err = ERR_NONE;
1552
1553 memset(&stream,0,sizeof(stream));
1554 Res = inflateInit(&stream);
1555 if (Res != Z_OK)
1556 Err = ERR_INVALID_DATA;
1557 else
1558 {
1559 size_t Count;
1560 stream.next_in = Cursor;
1561 stream.avail_in = CursorSize;
1562 stream.next_out = ARRAYBEGIN(*OutBuf,uint8_t) + *ArrayOffset;
1563 do {
1564 Count = stream.next_out - ARRAYBEGIN(*OutBuf,uint8_t);
1565 if (!ArrayResize(OutBuf, Count + 1024, 0))
1566 {
1567 Res = Z_MEM_ERROR;
1568 break;
1569 }
1570 stream.avail_out = ARRAYCOUNT(*OutBuf,uint8_t) - Count;
1571 stream.next_out = ARRAYBEGIN(*OutBuf,uint8_t) + Count;
1572 Res = inflate(&stream, Z_NO_FLUSH);
1573 if (Res!=Z_STREAM_END && Res!=Z_OK)
1574 break;
1575 } while (Res!=Z_STREAM_END && stream.avail_in && !stream.avail_out);
1576 *FrameSize = stream.total_out;
1577 *ArrayOffset = *ArrayOffset + stream.total_out;
1578 inflateEnd(&stream);
1579 if (Res != Z_STREAM_END)
1580 Err = ERR_INVALID_DATA;
1581 }
1582 return Err;
1583 }
1584
1585 #if defined(CONFIG_EBML_WRITING)
CompressFrameZLib(const uint8_t * Cursor,size_t CursorSize,uint8_t ** OutBuf,size_t * OutSize)1586 err_t CompressFrameZLib(const uint8_t *Cursor, size_t CursorSize, uint8_t **OutBuf, size_t *OutSize)
1587 {
1588 err_t Err = ERR_NONE;
1589 z_stream stream;
1590 size_t Count;
1591 array TmpBuf;
1592 int Res;
1593
1594 memset(&stream,0,sizeof(stream));
1595 if (deflateInit(&stream, 9)!=Z_OK)
1596 return ERR_INVALID_DATA;
1597 stream.next_in = (Bytef*)Cursor;
1598 stream.avail_in = CursorSize;
1599 Count = 0;
1600 ArrayInit(&TmpBuf);
1601 stream.next_out = ARRAYBEGIN(TmpBuf,uint8_t);
1602 do {
1603 Count = stream.next_out - ARRAYBEGIN(TmpBuf,uint8_t);
1604 if (!ArrayResize(&TmpBuf,CursorSize + Count,0))
1605 {
1606 ArrayClear(&TmpBuf);
1607 Err = ERR_OUT_OF_MEMORY;
1608 break;
1609 }
1610 stream.avail_out = ARRAYCOUNT(TmpBuf,uint8_t) - Count;
1611 stream.next_out = ARRAYBEGIN(TmpBuf,uint8_t) + Count;
1612 Res = deflate(&stream, Z_FINISH);
1613 } while (stream.avail_out==0 && Res!=Z_STREAM_END);
1614
1615 if (OutBuf && OutSize)
1616 // TODO: write directly in the output buffer
1617 memcpy(*OutBuf, ARRAYBEGIN(TmpBuf,uint8_t), min(*OutSize, stream.total_out));
1618 ArrayClear(&TmpBuf);
1619
1620 if (OutSize)
1621 *OutSize = stream.total_out;
1622
1623 deflateEnd(&stream);
1624
1625 return Err;
1626 }
1627 #endif // CONFIG_EBML_WRITING
1628 #endif // CONFIG_ZLIB
1629
GetBlockFrameSize(const matroska_block * Element,size_t Frame,const ebml_element * Header,int CompScope)1630 static filepos_t GetBlockFrameSize(const matroska_block *Element, size_t Frame, const ebml_element *Header, int CompScope)
1631 {
1632 if (Frame >= ARRAYCOUNT(Element->SizeList,int32_t))
1633 return 0;
1634
1635 if (!Header || (CompScope & MATROSKA_COMPR_SCOPE_BLOCK)==0)
1636 return ARRAYBEGIN(Element->SizeList,int32_t)[Frame];
1637 if (Header->Context==&MATROSKA_ContextContentCompAlgo)
1638 {
1639 // handle zlib
1640 size_t OutSize;
1641 const int32_t *Size = ARRAYBEGIN(Element->SizeList,int32_t);
1642 const uint8_t *Data = ARRAYBEGIN(Element->Data,uint8_t);
1643 while (Frame)
1644 {
1645 Data += *Size;
1646 ++Size;
1647 --Frame;
1648 }
1649 OutSize = *Size;
1650 assert(Element->Base.Base.bValueIsSet);
1651 #if defined(CONFIG_EBML_WRITING) && defined(CONFIG_ZLIB)
1652 if (!Element->Base.Base.bValueIsSet || CompressFrameZLib(Data,*Size,NULL,&OutSize)!=ERR_NONE)
1653 #else
1654 if (!Element->Base.Base.bValueIsSet)
1655 #endif
1656 return *Size; // we can't tell the final size without decoding the data
1657 return OutSize;
1658 }
1659 return ARRAYBEGIN(Element->SizeList,int32_t)[Frame] - Header->DataSize; // header stripping
1660 }
1661
1662 #if defined(CONFIG_EBML_WRITING)
GetBestLacingType(const matroska_block * Element)1663 static char GetBestLacingType(const matroska_block *Element)
1664 {
1665 int XiphLacingSize, EbmlLacingSize;
1666 size_t i;
1667 int32_t DataSize;
1668 ebml_element *Elt, *Elt2, *Header = NULL;
1669 int CompressionScope = MATROSKA_COMPR_SCOPE_BLOCK;
1670
1671 if (ARRAYCOUNT(Element->SizeList,int32_t) <= 1)
1672 return LACING_NONE;
1673
1674 DataSize = ARRAYBEGIN(Element->SizeList,int32_t)[0];
1675 for (i=1;i<ARRAYCOUNT(Element->SizeList,int32_t);++i)
1676 {
1677 if (ARRAYBEGIN(Element->SizeList,int32_t)[i]!=DataSize)
1678 break;
1679 }
1680 if (i==ARRAYCOUNT(Element->SizeList,int32_t))
1681 return LACING_FIXED;
1682
1683 // find out if compressed headers are used
1684 assert(Element->WriteTrack!=NULL);
1685 Elt = EBML_MasterFindChild(Element->WriteTrack, &MATROSKA_ContextContentEncodings);
1686 if (Elt)
1687 {
1688 Elt = EBML_MasterFindChild((ebml_master*)Elt, &MATROSKA_ContextContentEncoding);
1689 if (EBML_MasterChildren(Elt))
1690 {
1691 if (EBML_MasterNext(Elt))
1692 return 0; // TODO support cascaded compression/encryption
1693
1694 Elt2 = EBML_MasterFindChild((ebml_master*)Elt, &MATROSKA_ContextContentEncodingScope);
1695 if (Elt2)
1696 CompressionScope = EBML_IntegerValue((ebml_integer*)Elt2);
1697
1698 Elt = EBML_MasterFindChild((ebml_master*)Elt, &MATROSKA_ContextContentCompression);
1699 if (!Elt)
1700 return 0; // TODO: support encryption
1701
1702 Header = EBML_MasterGetChild((ebml_master*)Elt, &MATROSKA_ContextContentCompAlgo);
1703 #if defined(CONFIG_ZLIB)
1704 if (EBML_IntegerValue((ebml_integer*)Header)!=MATROSKA_BLOCK_COMPR_HEADER && EBML_IntegerValue((ebml_integer*)Header)!=MATROSKA_BLOCK_COMPR_ZLIB)
1705 #else
1706 if (EBML_IntegerValue((ebml_integer*)Header)!=MATROSKA_BLOCK_COMPR_HEADER)
1707 #endif
1708 return 0;
1709
1710 if (EBML_IntegerValue((ebml_integer*)Header)==MATROSKA_BLOCK_COMPR_HEADER)
1711 Header = EBML_MasterFindChild((ebml_master*)Elt, &MATROSKA_ContextContentCompSettings);
1712 }
1713 }
1714
1715 XiphLacingSize = 0;
1716 for (i=0;i<ARRAYCOUNT(Element->SizeList,int32_t)-1;++i)
1717 {
1718 DataSize = (int32_t)GetBlockFrameSize(Element, i, Header, CompressionScope);
1719 while (DataSize >= 0xFF)
1720 {
1721 XiphLacingSize++;
1722 DataSize -= 0xFF;
1723 }
1724 XiphLacingSize++;
1725 }
1726
1727 EbmlLacingSize = EBML_CodedSizeLength(GetBlockFrameSize(Element, 0, Header, CompressionScope),0,1);
1728 for (i=1;i<ARRAYCOUNT(Element->SizeList,int32_t)-1;++i)
1729 {
1730 DataSize = (int32_t)GetBlockFrameSize(Element, i, Header, CompressionScope) - DataSize;
1731 EbmlLacingSize += EBML_CodedSizeLengthSigned(DataSize,0);
1732 }
1733
1734 if (XiphLacingSize < EbmlLacingSize)
1735 return LACING_XIPH;
1736 else
1737 return LACING_EBML;
1738 }
1739
RenderBlockData(matroska_block * Element,stream * Output,bool_t bForceWithoutMandatory,bool_t bWithDefault,filepos_t * Rendered)1740 static err_t RenderBlockData(matroska_block *Element, stream *Output, bool_t bForceWithoutMandatory, bool_t bWithDefault, filepos_t *Rendered)
1741 {
1742 err_t Err = ERR_NONE;
1743 uint8_t BlockHead[5], *Cursor;
1744 size_t ToWrite, Written, BlockHeadSize = 4;
1745 ebml_element *Elt, *Elt2, *Header = NULL;
1746 int32_t *i;
1747 int CompressionScope = MATROSKA_COMPR_SCOPE_BLOCK;
1748 assert(Element->Lacing != LACING_AUTO);
1749
1750 if (Element->TrackNumber < 0x80)
1751 {
1752 BlockHead[0] = 0x80 | (Element->TrackNumber & 0xFF);
1753 Cursor = &BlockHead[1];
1754 }
1755 else if (Element->TrackNumber < 0x4000)
1756 {
1757 BlockHead[0] = 0x40 | (Element->TrackNumber >> 8);
1758 BlockHead[1] = Element->TrackNumber & 0xFF;
1759 Cursor = &BlockHead[2];
1760 BlockHeadSize = 5;
1761 }
1762 else
1763 return ERR_INVALID_DATA;
1764
1765 STORE16BE(Cursor,Element->LocalTimecode);
1766 Cursor += 2;
1767
1768 *Cursor = 0;
1769 if (Element->Invisible)
1770 *Cursor |= 0x08;
1771 *Cursor |= Element->Lacing << 1;
1772 if (EBML_ElementIsType((ebml_element*)Element, &MATROSKA_ContextSimpleBlock))
1773 {
1774 if (Element->IsKeyframe)
1775 *Cursor |= 0x80;
1776 if (Element->IsDiscardable)
1777 *Cursor |= 0x01;
1778 }
1779
1780 Err = Stream_Write(Output,BlockHead,BlockHeadSize,&Written);
1781 if (Err != ERR_NONE)
1782 goto failed;
1783 if (Written != BlockHeadSize)
1784 {
1785 Err = ERR_WRITE;
1786 goto failed;
1787 }
1788 if (Rendered)
1789 *Rendered = Written;
1790
1791 assert(Element->WriteTrack!=NULL);
1792 Elt = EBML_MasterFindChild(Element->WriteTrack, &MATROSKA_ContextContentEncodings);
1793 if (Elt)
1794 {
1795 Elt = EBML_MasterFindChild((ebml_master*)Elt, &MATROSKA_ContextContentEncoding);
1796 if (EBML_MasterChildren(Elt))
1797 {
1798 if (EBML_MasterNext(Elt))
1799 return ERR_INVALID_DATA; // TODO support cascaded compression/encryption
1800
1801 Elt2 = EBML_MasterFindChild((ebml_master*)Elt, &MATROSKA_ContextContentEncodingScope);
1802 if (Elt2)
1803 CompressionScope = EBML_IntegerValue((ebml_integer*)Elt2);
1804
1805 Elt = EBML_MasterFindChild((ebml_master*)Elt, &MATROSKA_ContextContentCompression);
1806 if (!Elt)
1807 return ERR_INVALID_DATA; // TODO: support encryption
1808
1809 Header = EBML_MasterGetChild((ebml_master*)Elt, &MATROSKA_ContextContentCompAlgo);
1810 #if defined(CONFIG_ZLIB)
1811 if (EBML_IntegerValue((ebml_integer*)Header)!=MATROSKA_BLOCK_COMPR_HEADER && EBML_IntegerValue((ebml_integer*)Header)!=MATROSKA_BLOCK_COMPR_ZLIB)
1812 #else
1813 if (EBML_IntegerValue((ebml_integer*)Header)!=MATROSKA_BLOCK_COMPR_HEADER)
1814 #endif
1815 {
1816 Err = ERR_NOT_SUPPORTED;
1817 goto failed;
1818 }
1819
1820 if (EBML_IntegerValue((ebml_integer*)Header)==MATROSKA_BLOCK_COMPR_HEADER)
1821 Header = EBML_MasterFindChild((ebml_master*)Elt, &MATROSKA_ContextContentCompSettings);
1822 }
1823 }
1824
1825 #if !defined(CONFIG_ZLIB)
1826 if (Header && Header->Context==&MATROSKA_ContextContentCompAlgo)
1827 {
1828 Err = ERR_NOT_SUPPORTED;
1829 goto failed;
1830 }
1831 #endif
1832
1833 if (Element->Lacing == LACING_AUTO)
1834 Element->Lacing = GetBestLacingType(Element);
1835 if (Element->Lacing != LACING_NONE)
1836 {
1837 uint8_t *LaceHead = malloc(1 + ARRAYCOUNT(Element->SizeList,int32_t)*4);
1838 size_t i,LaceSize = 1;
1839 int32_t DataSize, PrevSize;
1840 if (!LaceHead)
1841 {
1842 Err = ERR_OUT_OF_MEMORY;
1843 goto failed;
1844 }
1845 LaceHead[0] = (ARRAYCOUNT(Element->SizeList,int32_t)-1) & 0xFF; // number of elements in the lace
1846 if (Element->Lacing == LACING_EBML)
1847 {
1848 DataSize = (int32_t)GetBlockFrameSize(Element, 0, Header, CompressionScope);
1849 LaceSize += EBML_CodedValueLength(DataSize,EBML_CodedSizeLength(DataSize,0,1),LaceHead+LaceSize, 1);
1850 for (i=1;i<ARRAYCOUNT(Element->SizeList,int32_t)-1;++i)
1851 {
1852 PrevSize = DataSize;
1853 DataSize = (int32_t)GetBlockFrameSize(Element, i, Header, CompressionScope);
1854 LaceSize += EBML_CodedValueLengthSigned(DataSize-PrevSize,EBML_CodedSizeLengthSigned(DataSize-PrevSize,0),LaceHead+LaceSize);
1855 }
1856 }
1857 else if (Element->Lacing == LACING_XIPH)
1858 {
1859 for (i=0;i<ARRAYCOUNT(Element->SizeList,int32_t)-1;++i)
1860 {
1861 DataSize = (int32_t)GetBlockFrameSize(Element, i, Header, CompressionScope);
1862 while (DataSize >= 0xFF)
1863 {
1864 LaceHead[LaceSize++] = 0xFF;
1865 DataSize -= 0xFF;
1866 }
1867 LaceHead[LaceSize++] = (uint8_t)DataSize;
1868 }
1869 }
1870 else if (Element->Lacing == LACING_FIXED)
1871 {
1872 // nothing to write
1873 }
1874 assert(LaceSize <= (1 + ARRAYCOUNT(Element->SizeList,int32_t)*4));
1875 Err = Stream_Write(Output,LaceHead,LaceSize,&Written);
1876 if (Err != ERR_NONE)
1877 goto failed;
1878 if (Rendered)
1879 *Rendered += Written;
1880 free(LaceHead);
1881 }
1882 Node_SET(Element,MATROSKA_BLOCK_READ_TRACK,&Element->WriteTrack); // now use the write track for consecutive read of the same element
1883
1884 Cursor = ARRAYBEGIN(Element->Data,uint8_t);
1885 if (Header && (CompressionScope & MATROSKA_COMPR_SCOPE_BLOCK))
1886 {
1887 if (Header && Header->Context==&MATROSKA_ContextContentCompAlgo)
1888 {
1889 #if defined(CONFIG_ZLIB)
1890 uint8_t *OutBuf;
1891 array TmpBuf;
1892 ArrayInit(&TmpBuf);
1893 for (i=ARRAYBEGIN(Element->SizeList,int32_t);i!=ARRAYEND(Element->SizeList,int32_t);++i)
1894 {
1895 if (!ArrayResize(&TmpBuf,*i + 100,0))
1896 {
1897 ArrayClear(&TmpBuf);
1898 Err = ERR_OUT_OF_MEMORY;
1899 break;
1900 }
1901 OutBuf = ARRAYBEGIN(TmpBuf,uint8_t);
1902 ToWrite = ARRAYCOUNT(TmpBuf,uint8_t);
1903 if (CompressFrameZLib(Cursor, *i, &OutBuf, &ToWrite) != ERR_NONE)
1904 {
1905 ArrayClear(&TmpBuf);
1906 Err = ERR_OUT_OF_MEMORY;
1907 break;
1908 }
1909
1910 Err = Stream_Write(Output,OutBuf,ToWrite,&Written);
1911 ArrayClear(&TmpBuf);
1912 if (Rendered)
1913 *Rendered += Written;
1914 Cursor += *i;
1915 if (Err!=ERR_NONE)
1916 break;
1917 }
1918 #endif
1919 }
1920 else
1921 {
1922 // header compression
1923 for (i=ARRAYBEGIN(Element->SizeList,int32_t);i!=ARRAYEND(Element->SizeList,int32_t);++i)
1924 {
1925 assert(memcmp(Cursor,ARRAYBEGIN(((ebml_binary*)Header)->Data,uint8_t),(size_t)Header->DataSize)==0);
1926 if (memcmp(Cursor,ARRAYBEGIN(((ebml_binary*)Header)->Data,uint8_t),(size_t)Header->DataSize)!=0)
1927 {
1928 Err = ERR_INVALID_DATA;
1929 goto failed;
1930 }
1931 Cursor += Header->DataSize;
1932 ToWrite = *i - (size_t)Header->DataSize;
1933 Err = Stream_Write(Output,Cursor,ToWrite,&Written);
1934 if (Rendered)
1935 *Rendered += Written;
1936 Cursor += Written;
1937 }
1938 }
1939 }
1940 else
1941 {
1942 ToWrite = ARRAYCOUNT(Element->Data,uint8_t);
1943 Err = Stream_Write(Output,Cursor,ToWrite,&Written);
1944 if (Rendered)
1945 *Rendered += Written;
1946 }
1947
1948 failed:
1949 return Err;
1950 }
1951 #endif
1952
CopyBlockInfo(const matroska_block * Element,const void * Cookie)1953 static matroska_block *CopyBlockInfo(const matroska_block *Element, const void *Cookie)
1954 {
1955 matroska_block *Result = (matroska_block*)INHERITED(Element,ebml_element_vmt,Node_ClassId(Element))->Copy(Element,Cookie);
1956 if (Result)
1957 {
1958 Result->TrackNumber = Element->TrackNumber;
1959 Result->IsKeyframe = Element->IsKeyframe;
1960 Result->IsDiscardable = Element->IsDiscardable;
1961 Result->Invisible = Element->Invisible;
1962 #if 0 // computed once blocks are added
1963 Result->LocalTimecode = Element->LocalTimecode;
1964 Result->LocalTimecodeUsed = Element->LocalTimecodeUsed;
1965 Result->GlobalTimecode = Element->GlobalTimecode;
1966 Result->Lacing = Element->Lacing;
1967 Result->FirstFrameLocation = Element->FirstFrameLocation;
1968 array SizeList = Element->; // int32_t
1969 array Data = Element->; // uint8_t
1970 array Durations = Element->; // timecode_t
1971 #else
1972 Result->Base.Base.bValueIsSet = 0;
1973 #endif
1974 Node_SET(Result,MATROSKA_BLOCK_READ_TRACK,&Element->ReadTrack);
1975 Node_SET(Result,MATROSKA_BLOCK_READ_SEGMENTINFO,&Element->ReadSegInfo);
1976 #if defined(CONFIG_EBML_WRITING)
1977 Node_SET(Result,MATROSKA_BLOCK_WRITE_TRACK,&Element->WriteTrack);
1978 Node_SET(Result,MATROSKA_BLOCK_WRITE_SEGMENTINFO,&Element->WriteSegInfo);
1979 #endif
1980 }
1981 return Result;
1982 }
1983
UpdateBlockSize(matroska_block * Element,bool_t bWithDefault,bool_t bForceWithoutMandatory)1984 static filepos_t UpdateBlockSize(matroska_block *Element, bool_t bWithDefault, bool_t bForceWithoutMandatory)
1985 {
1986 int CompressionScope = MATROSKA_COMPR_SCOPE_BLOCK;
1987 if (EBML_ElementNeedsDataSizeUpdate(Element, bWithDefault))
1988 {
1989 ebml_element *Header = NULL;
1990 #if defined(CONFIG_EBML_WRITING)
1991 ebml_element *Elt, *Elt2;
1992 if (Element->Lacing == LACING_AUTO)
1993 Element->Lacing = GetBestLacingType(Element);
1994
1995 assert(Element->WriteTrack!=NULL);
1996 Elt = EBML_MasterFindChild(Element->WriteTrack, &MATROSKA_ContextContentEncodings);
1997 if (Elt)
1998 {
1999 Elt = EBML_MasterFindChild((ebml_master*)Elt, &MATROSKA_ContextContentEncoding);
2000 if (EBML_MasterChildren(Elt))
2001 {
2002 if (EBML_MasterNext(Elt))
2003 return ERR_INVALID_DATA; // TODO support cascaded compression/encryption
2004
2005 Elt2 = EBML_MasterFindChild((ebml_master*)Elt, &MATROSKA_ContextContentEncodingScope);
2006 if (Elt2)
2007 CompressionScope = EBML_IntegerValue((ebml_integer*)Elt2);
2008
2009 Elt = EBML_MasterFindChild((ebml_master*)Elt, &MATROSKA_ContextContentCompression);
2010 if (!Elt)
2011 return ERR_INVALID_DATA; // TODO: support encryption
2012
2013 Header = EBML_MasterGetChild((ebml_master*)Elt, &MATROSKA_ContextContentCompAlgo);
2014 #if defined(CONFIG_ZLIB)
2015 if (EBML_IntegerValue((ebml_integer*)Header)!=MATROSKA_BLOCK_COMPR_HEADER && EBML_IntegerValue((ebml_integer*)Header)!=MATROSKA_BLOCK_COMPR_ZLIB)
2016 #else
2017 if (EBML_IntegerValue((ebml_integer*)Header)!=MATROSKA_BLOCK_COMPR_HEADER)
2018 #endif
2019 return ERR_INVALID_DATA;
2020
2021 if (EBML_IntegerValue((ebml_integer*)Header)==MATROSKA_BLOCK_COMPR_HEADER)
2022 Header = EBML_MasterFindChild((ebml_master*)Elt, &MATROSKA_ContextContentCompSettings);
2023 }
2024 }
2025 #else
2026 assert(Element->Lacing!=LACING_AUTO);
2027 #endif
2028
2029 if (Element->Lacing == LACING_NONE)
2030 {
2031 assert(ARRAYCOUNT(Element->SizeList,int32_t) == 1);
2032 Element->Base.Base.DataSize = GetBlockHeadSize(Element) + GetBlockFrameSize(Element,0,Header, CompressionScope);
2033 }
2034 else if (Element->Lacing == LACING_EBML)
2035 {
2036 size_t i;
2037 filepos_t PrevSize, Size;
2038 filepos_t Result = GetBlockHeadSize(Element) + 1; // 1 for the number of frames
2039 Size = GetBlockFrameSize(Element,0,Header, CompressionScope);
2040 Result += EBML_CodedSizeLength(Size,0,1) + Size;
2041 for (i=1;i<ARRAYCOUNT(Element->SizeList,int32_t)-1;++i)
2042 {
2043 PrevSize = Size;
2044 Size = GetBlockFrameSize(Element,i,Header, CompressionScope);
2045 Result += Size + EBML_CodedSizeLengthSigned(Size - PrevSize,0);
2046 }
2047 Result += GetBlockFrameSize(Element,i,Header, CompressionScope);
2048 Element->Base.Base.DataSize = Result;
2049 }
2050 else if (Element->Lacing == LACING_XIPH)
2051 {
2052 size_t i;
2053 filepos_t Size;
2054 filepos_t Result = GetBlockHeadSize(Element) + 1; // 1 for the number of frames
2055 for (i=0;i<ARRAYCOUNT(Element->SizeList,int32_t)-1;++i)
2056 {
2057 Size = GetBlockFrameSize(Element,i,Header, CompressionScope);
2058 Result += (Size / 0xFF + 1) + Size;
2059 }
2060 Result += GetBlockFrameSize(Element,i,Header, CompressionScope);
2061 Element->Base.Base.DataSize = Result;
2062 }
2063 else if (Element->Lacing == LACING_FIXED)
2064 {
2065 size_t i;
2066 filepos_t Result = GetBlockHeadSize(Element) + 1; // 1 for the number of frames
2067 for (i=0;i<ARRAYCOUNT(Element->SizeList,int32_t);++i)
2068 Result += GetBlockFrameSize(Element,i,Header, CompressionScope);
2069 Element->Base.Base.DataSize = Result;
2070 }
2071 #ifdef TODO
2072 char LacingHere;
2073 // compute the final size of the data
2074 switch (ARRAYCOUNT(Element->SizeList,int32_t))
2075 {
2076 case 0:
2077 Element->Base.Base.DataSize = 0;
2078 break;
2079 case 1:
2080 Element->Base.Base.DataSize = 4 + *ARRAYBEGIN(Element->SizeList,int32_t);
2081 break;
2082 default:
2083 Element->Base.Base.DataSize = 4 + 1; // 1 for the lacing head
2084 if (Element->Lacing == LACING_AUTO)
2085 LacingHere = GetBestLacingType(Element);
2086 else
2087 LacingHere = Element->Lacing;
2088 switch (LacingHere)
2089 {
2090 case LACING_XIPH:
2091 for (i=0; i<myBuffers.size()-1; i++) {
2092 SetSize_(GetSize() + myBuffers[i]->DataSize() + (myBuffers[i]->DataSize() / 0xFF + 1));
2093 }
2094 break;
2095 case LACING_EBML:
2096 SetSize_(GetSize() + myBuffers[0]->DataSize() + CodedSizeLength(myBuffers[0]->DataSize(), 0, IsFiniteSize()));
2097 for (i=1; i<myBuffers.size()-1; i++) {
2098 SetSize_(GetSize() + myBuffers[i]->DataSize() + CodedSizeLengthSigned(int64(myBuffers[i]->DataSize()) - int64(myBuffers[i-1]->DataSize()), 0));
2099 }
2100 break;
2101 case LACING_FIXED:
2102 for (i=0; i<myBuffers.size()-1; i++) {
2103 SetSize_(GetSize() + myBuffers[i]->DataSize());
2104 }
2105 break;
2106 default:
2107 assert(0);
2108 }
2109 // DataSize of the last frame (not in lace)
2110 SetSize_(GetSize() + myBuffers[i]->DataSize());
2111 break;
2112 }
2113
2114 if (Element->Base.Base.DataSize && Element->TrackNumber >= 0x80)
2115 ++Element->Base.Base.DataSize; // the size will be coded with one more octet
2116 #endif
2117 }
2118
2119 // skip the EBML_BINARY_CLASS version as we have another internal buffer
2120 return INHERITED(Element,ebml_element_vmt,EBML_BINARY_CLASS)->UpdateDataSize(Element, bWithDefault, bForceWithoutMandatory);
2121 }
2122
CmpCuePoint(const matroska_cuepoint * a,const matroska_cuepoint * b)2123 static int CmpCuePoint(const matroska_cuepoint* a,const matroska_cuepoint* b)
2124 {
2125 // returns a > b
2126 timecode_t TA = MATROSKA_CueTimecode(a);
2127 timecode_t TB = MATROSKA_CueTimecode(b);
2128 int NA,NB;
2129 if (TB < TA)
2130 return 1;
2131 if (TB > TA)
2132 return -1;
2133 NA = MATROSKA_CueTrackNum(a);
2134 NB = MATROSKA_CueTrackNum(b);
2135 if (NB < NA)
2136 return 1;
2137 if (NB > NA)
2138 return -1;
2139 return 0;
2140 }
2141
CmpAttachedFile(const ebml_master * a,const ebml_master * b)2142 static int CmpAttachedFile(const ebml_master* a,const ebml_master* b)
2143 {
2144 // returns a > b
2145 // sort cover art names according to http://www.matroska.org/technical/cover_art/index.html
2146 tchar_t FilenameA[MAXPATH];
2147 tchar_t FilenameB[MAXPATH];
2148 bool_t CoverA=0,CoverB=0;
2149 bool_t LandCoverA=0,LandCoverB=0;
2150 bool_t SmallCoverA=0,SmallCoverB=0;
2151 ebml_element *NameA = EBML_MasterFindChild(a,&MATROSKA_ContextFileName);
2152 ebml_element *NameB = EBML_MasterFindChild(b,&MATROSKA_ContextFileName);
2153
2154 if (NameB==NULL)
2155 return -1;
2156 if (NameA==NULL)
2157 return 1;
2158
2159 EBML_StringGet((ebml_string*)NameA,FilenameA,TSIZEOF(FilenameA));
2160 EBML_StringGet((ebml_string*)NameB,FilenameB,TSIZEOF(FilenameB));
2161
2162 if (tcsisame_ascii(FilenameA, T("cover.jpg")) || tcsisame_ascii(FilenameA, T("cover.png")))
2163 CoverA = 1;
2164 else if (tcsisame_ascii(FilenameA, T("cover_land.jpg")) || tcsisame_ascii(FilenameA, T("cover_land.png")))
2165 LandCoverA = 1;
2166 else if (tcsisame_ascii(FilenameA, T("small_cover.jpg")) || tcsisame_ascii(FilenameA, T("small_cover.png")))
2167 {
2168 CoverA = 1;
2169 SmallCoverA = 1;
2170 }
2171 else if (tcsisame_ascii(FilenameA, T("small_cover_land.jpg")) || tcsisame_ascii(FilenameA, T("small_cover_land.png")))
2172 {
2173 LandCoverA = 1;
2174 SmallCoverA = 1;
2175 }
2176
2177 if (tcsisame_ascii(FilenameB, T("cover.jpg")) || tcsisame_ascii(FilenameB, T("cover.png")))
2178 CoverB = 1;
2179 else if (tcsisame_ascii(FilenameB, T("cover_land.jpg")) || tcsisame_ascii(FilenameB, T("cover_land.png")))
2180 LandCoverB = 1;
2181 else if (tcsisame_ascii(FilenameB, T("small_cover.jpg")) || tcsisame_ascii(FilenameB, T("small_cover.png")))
2182 {
2183 CoverB = 1;
2184 SmallCoverB = 1;
2185 }
2186 else if (tcsisame_ascii(FilenameB, T("small_cover_land.jpg")) || tcsisame_ascii(FilenameB, T("small_cover_land.png")))
2187 {
2188 LandCoverB = 1;
2189 SmallCoverB = 1;
2190 }
2191
2192 if (!CoverA && !CoverB && !LandCoverA && !LandCoverB)
2193 return tcscmp(FilenameA,FilenameB);
2194
2195 // cover.jpg comes first
2196 if (CoverA && !SmallCoverA)
2197 return -1;
2198 if (CoverB && !SmallCoverB)
2199 return 1;
2200 if (CoverA == CoverB || LandCoverA == LandCoverB)
2201 return SmallCoverA - SmallCoverB;
2202 if (CoverA || LandCoverA)
2203 {
2204 if (CoverB)
2205 return 1;
2206 return -1;
2207 }
2208
2209 if (CoverA)
2210 return -1;
2211 return 1;
2212 }
2213
MATROSKA_CuesGetTimecodeStart(const ebml_element * Cues,timecode_t Timecode)2214 matroska_cuepoint *MATROSKA_CuesGetTimecodeStart(const ebml_element *Cues, timecode_t Timecode)
2215 {
2216 matroska_cuepoint *Elt,*Prev=NULL;
2217
2218 assert(Cues!=NULL);
2219 assert(EBML_ElementIsType(Cues, &MATROSKA_ContextCues));
2220 if (Timecode==INVALID_TIMECODE_T)
2221 return NULL;
2222
2223 for (Elt=(matroska_cuepoint*)EBML_MasterChildren(Cues);Elt;Prev=Elt, Elt=(matroska_cuepoint*)EBML_MasterNext(Elt))
2224 {
2225 if (MATROSKA_CueTimecode(Elt) > Timecode)
2226 break;
2227 }
2228
2229 return Prev ? Prev : (matroska_cuepoint*)EBML_MasterChildren(Cues);
2230 }
2231
ValidateSizeSegUID(const ebml_binary * p)2232 static bool_t ValidateSizeSegUID(const ebml_binary *p)
2233 {
2234 uint8_t test[16];
2235 if (p->Base.DataSize != 16 || !EBML_ElementIsFiniteSize((const ebml_element *)p))
2236 return 0;
2237 if (!p->Base.bValueIsSet)
2238 return 1;
2239 memset(test,0,sizeof(test));
2240 return memcmp(ARRAYBEGIN(p->Data,uint8_t),test,16)!=0; // make sure the value is not 0
2241 }
2242
CreateBlock(matroska_block * p)2243 static err_t CreateBlock(matroska_block *p)
2244 {
2245 p->GlobalTimecode = INVALID_TIMECODE_T;
2246 return ERR_NONE;
2247 }
2248
CreateCluster(matroska_cluster * p)2249 static err_t CreateCluster(matroska_cluster *p)
2250 {
2251 p->GlobalTimecode = INVALID_TIMECODE_T;
2252 return ERR_NONE;
2253 }
2254
ReadTrackEntry(matroska_trackentry * Element,stream * Input,const ebml_parser_context * ParserContext,bool_t AllowDummyElt,int Scope,size_t DepthCheckCRC)2255 static err_t ReadTrackEntry(matroska_trackentry *Element, stream *Input, const ebml_parser_context *ParserContext, bool_t AllowDummyElt, int Scope, size_t DepthCheckCRC)
2256 {
2257 err_t Result = INHERITED(Element,ebml_element_vmt,MATROSKA_TRACKENTRY_CLASS)->ReadData(Element, Input, ParserContext, AllowDummyElt, Scope, DepthCheckCRC);
2258 if (Result==ERR_NONE)
2259 {
2260 ebml_element *Encodings = EBML_MasterFindChild(Element,&MATROSKA_ContextContentEncodings);
2261 if (Encodings)
2262 {
2263 ebml_element *Elt2 = EBML_MasterFindChild((ebml_master*)Encodings,&MATROSKA_ContextContentEncoding);
2264 if (Elt2)
2265 {
2266 ebml_element *Elt = EBML_MasterFindChild((ebml_master*)Elt2,&MATROSKA_ContextContentCompression);
2267 if (Elt)
2268 {
2269 ebml_integer *Scope = (ebml_integer*)EBML_MasterFindChild((ebml_master*)Elt2,&MATROSKA_ContextContentEncodingScope);
2270 Element->CodecPrivateCompressed = Scope && (EBML_IntegerValue(Scope) & MATROSKA_COMPR_SCOPE_PRIVATE)!=0;
2271 }
2272 }
2273 }
2274 }
2275 return Result;
2276 }
2277
UpdateDataSizeTrackEntry(matroska_trackentry * Element,bool_t bWithDefault,bool_t bForceWithoutMandatory)2278 static filepos_t UpdateDataSizeTrackEntry(matroska_trackentry *Element, bool_t bWithDefault, bool_t bForceWithoutMandatory)
2279 {
2280 #if defined(CONFIG_ZLIB)
2281 bool_t CodecPrivateCompressed = 0;
2282 ebml_integer *Scope = NULL;
2283 ebml_element *Encodings = EBML_MasterFindChild(Element,&MATROSKA_ContextContentEncodings);
2284 if (Encodings)
2285 {
2286 ebml_element *Elt2 = EBML_MasterFindChild((ebml_master*)Encodings,&MATROSKA_ContextContentEncoding);
2287 if (Elt2)
2288 {
2289 ebml_element *Elt = EBML_MasterFindChild((ebml_master*)Elt2,&MATROSKA_ContextContentCompression);
2290 if (Elt)
2291 {
2292 Scope = (ebml_integer*)EBML_MasterFindChild((ebml_master*)Elt2,&MATROSKA_ContextContentEncodingScope);
2293 CodecPrivateCompressed = Scope && (EBML_IntegerValue(Scope) & MATROSKA_COMPR_SCOPE_PRIVATE)!=0;
2294 }
2295 }
2296 }
2297
2298 if (CodecPrivateCompressed != Element->CodecPrivateCompressed)
2299 {
2300 ebml_binary *CodecPrivate = (ebml_binary*)EBML_MasterFindChild(Element,&MATROSKA_ContextCodecPrivate);
2301 if (!Element->CodecPrivateCompressed)
2302 {
2303 // compress the codec private
2304 if (CodecPrivate)
2305 {
2306 size_t CompressedSize = ARRAYCOUNT(CodecPrivate->Data,uint8_t);
2307 uint8_t *Compressed = malloc(CompressedSize);
2308 if (CompressFrameZLib(ARRAYBEGIN(CodecPrivate->Data,uint8_t), (size_t)CodecPrivate->Base.DataSize, &Compressed, &CompressedSize)==ERR_NONE)
2309 {
2310 if (EBML_BinarySetData(CodecPrivate, Compressed, CompressedSize)==ERR_NONE)
2311 Element->CodecPrivateCompressed = 1;
2312 }
2313 free(Compressed);
2314 }
2315 if (!Element->CodecPrivateCompressed)
2316 EBML_IntegerSetValue(Scope, EBML_IntegerValue(Scope) ^ MATROSKA_COMPR_SCOPE_PRIVATE);
2317 }
2318 else
2319 {
2320 if (CodecPrivate)
2321 {
2322 size_t CompressedSize = ARRAYCOUNT(CodecPrivate->Data,uint8_t);
2323 size_t Offset = 0;
2324 array Compressed;
2325
2326 ArrayInit(&Compressed);
2327 if (UnCompressFrameZLib(ARRAYBEGIN(CodecPrivate->Data,uint8_t), (size_t)CodecPrivate->Base.DataSize, &Compressed, &CompressedSize, &Offset)==ERR_NONE)
2328 {
2329 if (EBML_BinarySetData(CodecPrivate, ARRAYBEGIN(Compressed,uint8_t), CompressedSize)==ERR_NONE)
2330 Element->CodecPrivateCompressed = 0;
2331 }
2332 ArrayClear(&Compressed);
2333 }
2334 else
2335 Element->CodecPrivateCompressed = 0;
2336 if (Element->CodecPrivateCompressed)
2337 {
2338 // TODO: add in the Compression header that the header is still compressed
2339 }
2340 }
2341 }
2342 #endif
2343 return INHERITED(Element,ebml_element_vmt,MATROSKA_TRACKENTRY_CLASS)->UpdateDataSize(Element, bWithDefault, bForceWithoutMandatory);
2344 }
2345
CopyTrackEntry(const matroska_trackentry * Element,const void * Cookie)2346 static matroska_trackentry *CopyTrackEntry(const matroska_trackentry *Element, const void *Cookie)
2347 {
2348 matroska_trackentry *Result = (matroska_trackentry*)INHERITED(Element,ebml_element_vmt,MATROSKA_TRACKENTRY_CLASS)->Copy(Element, Cookie);
2349 if (Result)
2350 Result->CodecPrivateCompressed = Element->CodecPrivateCompressed;
2351 return Result;
2352 }
2353
2354
MATROSKA_TrackGetBlockCompression(const matroska_trackentry * TrackEntry)2355 int MATROSKA_TrackGetBlockCompression(const matroska_trackentry *TrackEntry)
2356 {
2357 ebml_element *Encodings, *Elt, *Elt2;
2358 assert(Node_IsPartOf(TrackEntry, MATROSKA_TRACKENTRY_CLASS));
2359 Encodings = EBML_MasterFindChild(TrackEntry,&MATROSKA_ContextContentEncodings);
2360 if (!Encodings)
2361 return MATROSKA_BLOCK_COMPR_NONE;
2362 Elt2 = EBML_MasterFindChild((ebml_master*)Encodings,&MATROSKA_ContextContentEncoding);
2363 if (!Elt2)
2364 return MATROSKA_BLOCK_COMPR_NONE;
2365 Elt = EBML_MasterGetChild((ebml_master*)Elt2,&MATROSKA_ContextContentEncodingScope);
2366 if (!(EBML_IntegerValue((ebml_integer*)Elt) & MATROSKA_COMPR_SCOPE_BLOCK))
2367 return MATROSKA_BLOCK_COMPR_NONE;
2368 Elt = EBML_MasterFindChild((ebml_master*)Elt2,&MATROSKA_ContextContentCompression);
2369 if (!Elt)
2370 return MATROSKA_BLOCK_COMPR_NONE;
2371 Elt2 = EBML_MasterGetChild((ebml_master*)Elt,&MATROSKA_ContextContentCompAlgo);
2372 return (int)EBML_IntegerValue((ebml_integer*)Elt2);
2373 }
2374
MATROSKA_TrackSetCompressionZlib(matroska_trackentry * TrackEntry,int Scope)2375 bool_t MATROSKA_TrackSetCompressionZlib(matroska_trackentry *TrackEntry, int Scope)
2376 {
2377 // force zlib compression
2378 bool_t HadEncoding;
2379 ebml_element *Encodings, *Elt, *Elt2;
2380 assert(Node_IsPartOf(TrackEntry, MATROSKA_TRACKENTRY_CLASS));
2381 // remove the previous compression and the new optimized one
2382 Encodings = EBML_MasterFindChild(TrackEntry,&MATROSKA_ContextContentEncodings);
2383 HadEncoding = Encodings!=NULL;
2384 if (Encodings!=NULL)
2385 NodeDelete((node*)Encodings);
2386
2387 if (Scope!=0)
2388 {
2389 Encodings = EBML_MasterGetChild((ebml_master*)TrackEntry,&MATROSKA_ContextContentEncodings);
2390 Elt2 = EBML_MasterGetChild((ebml_master*)Encodings,&MATROSKA_ContextContentEncoding);
2391
2392 Elt = EBML_MasterGetChild((ebml_master*)Elt2,&MATROSKA_ContextContentEncodingScope);
2393 EBML_IntegerSetValue((ebml_integer*)Elt, Scope);
2394
2395 Elt = EBML_MasterGetChild((ebml_master*)Elt2,&MATROSKA_ContextContentCompression);
2396 Elt2 = EBML_MasterGetChild((ebml_master*)Elt,&MATROSKA_ContextContentCompAlgo);
2397 EBML_IntegerSetValue((ebml_integer*)Elt2, MATROSKA_BLOCK_COMPR_ZLIB);
2398 }
2399 return HadEncoding;
2400 }
2401
MATROSKA_TrackSetCompressionHeader(matroska_trackentry * TrackEntry,const uint8_t * Header,size_t HeaderSize)2402 bool_t MATROSKA_TrackSetCompressionHeader(matroska_trackentry *TrackEntry, const uint8_t *Header, size_t HeaderSize)
2403 {
2404 bool_t HadEncoding;
2405 ebml_element *Encodings, *Elt, *Elt2;
2406 assert(Node_IsPartOf(TrackEntry, MATROSKA_TRACKENTRY_CLASS));
2407 // remove the previous compression and the new optimized one
2408 Encodings = EBML_MasterFindChild(TrackEntry,&MATROSKA_ContextContentEncodings);
2409 HadEncoding = Encodings!=NULL;
2410 if (Encodings!=NULL)
2411 NodeDelete((node*)Encodings);
2412
2413 if (Header && HeaderSize)
2414 {
2415 Encodings = EBML_MasterGetChild((ebml_master*)TrackEntry,&MATROSKA_ContextContentEncodings);
2416 Elt2 = EBML_MasterGetChild((ebml_master*)Encodings,&MATROSKA_ContextContentEncoding);
2417
2418 Elt = EBML_MasterGetChild((ebml_master*)Elt2,&MATROSKA_ContextContentCompression);
2419 Elt2 = EBML_MasterGetChild((ebml_master*)Elt,&MATROSKA_ContextContentCompAlgo);
2420 EBML_IntegerSetValue((ebml_integer*)Elt2, MATROSKA_BLOCK_COMPR_HEADER);
2421 Elt2 = EBML_MasterGetChild((ebml_master*)Elt,&MATROSKA_ContextContentCompSettings);
2422 EBML_BinarySetData((ebml_binary*)Elt2, Header, HeaderSize);
2423 }
2424 return HadEncoding;
2425 }
2426
MATROSKA_TrackSetCompressionNone(matroska_trackentry * TrackEntry)2427 bool_t MATROSKA_TrackSetCompressionNone(matroska_trackentry *TrackEntry)
2428 {
2429 ebml_element *Encodings = EBML_MasterFindChild(TrackEntry,&MATROSKA_ContextContentEncodings);
2430 assert(Node_IsPartOf(TrackEntry, MATROSKA_TRACKENTRY_CLASS));
2431 if (!Encodings)
2432 return 0;
2433 NodeDelete((node*)Encodings);
2434 return 1;
2435 }
2436
2437
2438 META_START(Matroska_Class,MATROSKA_BLOCK_CLASS)
2439 META_CLASS(SIZE,sizeof(matroska_block))
2440 META_CLASS(CREATE,CreateBlock)
2441 META_VMT(TYPE_FUNC,nodetree_vmt,SetParent,SetBlockParent)
2442 META_VMT(TYPE_FUNC,ebml_element_vmt,ReadData,ReadBlockData)
2443 META_VMT(TYPE_FUNC,ebml_element_vmt,UpdateDataSize,UpdateBlockSize)
2444 #if defined(CONFIG_EBML_WRITING)
2445 META_VMT(TYPE_FUNC,ebml_element_vmt,RenderData,RenderBlockData)
2446 #endif
2447 META_VMT(TYPE_FUNC,ebml_element_vmt,Copy,CopyBlockInfo)
2448 META_DATA(TYPE_ARRAY,0,matroska_block,SizeList)
2449 META_DATA(TYPE_ARRAY,0,matroska_block,SizeListIn)
2450 META_DATA(TYPE_ARRAY,0,matroska_block,Data)
2451 META_DATA(TYPE_ARRAY,0,matroska_block,Durations)
2452 META_PARAM(TYPE,MATROSKA_BLOCK_READ_TRACK,TYPE_NODE)
2453 META_DATA_UPDATE_CMP(TYPE_NODE_REF,MATROSKA_BLOCK_READ_TRACK,matroska_block,ReadTrack,BlockTrackChanged)
2454 META_PARAM(TYPE,MATROSKA_BLOCK_READ_SEGMENTINFO,TYPE_NODE)
2455 META_DATA_UPDATE_CMP(TYPE_NODE_REF,MATROSKA_BLOCK_READ_SEGMENTINFO,matroska_block,ReadSegInfo,BlockTrackChanged)
2456 #if defined(CONFIG_EBML_WRITING)
2457 META_PARAM(TYPE,MATROSKA_BLOCK_WRITE_TRACK,TYPE_NODE)
2458 META_DATA_UPDATE_CMP(TYPE_NODE_REF,MATROSKA_BLOCK_WRITE_TRACK,matroska_block,WriteTrack,BlockTrackChanged)
2459 META_PARAM(TYPE,MATROSKA_BLOCK_WRITE_SEGMENTINFO,TYPE_NODE)
2460 META_DATA_UPDATE_CMP(TYPE_NODE_REF,MATROSKA_BLOCK_WRITE_SEGMENTINFO,matroska_block,WriteSegInfo,BlockTrackChanged)
2461 #endif
2462 META_END_CONTINUE(EBML_BINARY_CLASS)
2463
2464 META_START_CONTINUE(MATROSKA_BLOCKGROUP_CLASS)
2465 META_VMT(TYPE_FUNC,nodetree_vmt,SetParent,SetBlockGroupParent)
2466 META_END_CONTINUE(EBML_MASTER_CLASS)
2467
2468 META_START_CONTINUE(MATROSKA_BIGBINARY_CLASS)
2469 META_VMT(TYPE_FUNC,ebml_element_vmt,ReadData,ReadBigBinaryData)
2470 META_END_CONTINUE(EBML_BINARY_CLASS)
2471
2472 META_START_CONTINUE(MATROSKA_CUEPOINT_CLASS)
2473 META_CLASS(SIZE,sizeof(matroska_cuepoint))
2474 META_VMT(TYPE_FUNC,ebml_element_vmt,Cmp,CmpCuePoint)
2475 META_PARAM(TYPE,MATROSKA_CUE_SEGMENTINFO,TYPE_NODE)
2476 META_DATA(TYPE_NODE_REF,MATROSKA_CUE_SEGMENTINFO,matroska_cuepoint,SegInfo)
2477 META_PARAM(TYPE,MATROSKA_CUE_BLOCK,TYPE_NODE)
2478 META_DATA(TYPE_NODE_REF,MATROSKA_CUE_BLOCK,matroska_cuepoint,Block)
2479 META_END_CONTINUE(EBML_MASTER_CLASS)
2480
2481 META_START_CONTINUE(MATROSKA_CLUSTER_CLASS)
2482 META_CLASS(SIZE,sizeof(matroska_cluster))
2483 META_CLASS(CREATE,CreateCluster)
2484 META_PARAM(TYPE,MATROSKA_CLUSTER_READ_SEGMENTINFO,TYPE_NODE)
2485 META_DATA(TYPE_NODE_REF,MATROSKA_CLUSTER_READ_SEGMENTINFO,matroska_cluster,ReadSegInfo)
2486 META_PARAM(TYPE,MATROSKA_CLUSTER_WRITE_SEGMENTINFO,TYPE_NODE)
2487 META_DATA_UPDATE_CMP(TYPE_NODE_REF,MATROSKA_CLUSTER_WRITE_SEGMENTINFO,matroska_cluster,WriteSegInfo,ClusterTimeChanged)
2488 META_END_CONTINUE(EBML_MASTER_CLASS)
2489
2490 META_START_CONTINUE(MATROSKA_SEEKPOINT_CLASS)
2491 META_CLASS(SIZE,sizeof(matroska_seekpoint))
2492 META_PARAM(TYPE,MATROSKA_SEEKPOINT_ELEMENT,TYPE_NODE)
2493 META_DATA(TYPE_NODE_REF,MATROSKA_SEEKPOINT_ELEMENT,matroska_seekpoint,Link)
2494 META_END_CONTINUE(EBML_MASTER_CLASS)
2495
2496 META_START_CONTINUE(MATROSKA_TRACKENTRY_CLASS)
2497 META_CLASS(SIZE,sizeof(matroska_trackentry))
2498 META_VMT(TYPE_FUNC,ebml_element_vmt,ReadData,ReadTrackEntry)
2499 META_VMT(TYPE_FUNC,ebml_element_vmt,UpdateDataSize,UpdateDataSizeTrackEntry)
2500 META_VMT(TYPE_FUNC,ebml_element_vmt,Copy,CopyTrackEntry)
2501 META_END_CONTINUE(EBML_MASTER_CLASS)
2502
2503 META_START_CONTINUE(MATROSKA_SEGMENTUID_CLASS)
2504 META_VMT(TYPE_FUNC,ebml_element_vmt,ValidateSize,ValidateSizeSegUID)
2505 META_END_CONTINUE(EBML_BINARY_CLASS)
2506
2507 META_START_CONTINUE(MATROSKA_ATTACHMENT_CLASS)
2508 META_VMT(TYPE_FUNC,ebml_element_vmt,Cmp,CmpAttachedFile)
2509 META_END(EBML_MASTER_CLASS)
2510