matroskamain.c 95.6 KB
Newer Older
1
/*
Steve Lhomme's avatar
Steve Lhomme committed
2
 * $Id$
3
 * Copyright (c) 2008-2011, Matroska (non-profit organisation)
4 5 6 7 8 9 10 11 12
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *     * Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above copyright
 *       notice, this list of conditions and the following disclaimer in the
 *       documentation and/or other materials provided with the distribution.
13
 *     * Neither the name of the Matroska assocation nor the
14 15 16
 *       names of its contributors may be used to endorse or promote products
 *       derived from this software without specific prior written permission.
 *
17
 * THIS SOFTWARE IS PROVIDED BY the Matroska association ``AS IS'' AND ANY
18 19 20 21 22 23 24 25 26 27 28
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL The Matroska Foundation BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
#include "matroska/matroska.h"
29
#include "matroska/matroska_sem.h"
30
#include "matroska/matroska_internal.h"
31 32 33
#if defined(HAVE_ZLIB)
#include "zlib/zlib.h"
#elif defined(CONFIG_ZLIB)
34 35
#include "zlib.h"
#endif
36 37 38 39 40 41
#if defined(CONFIG_BZLIB)
#include <bzlib.h>
#endif
#if defined(CONFIG_LZO1X)
#include "minilzo.h"
#endif
42
#if defined(MATROSKA_LIBRARY)
43
#include "matroska2_project.h"
44
#endif
45 46

const ebml_semantic EBML_SemanticMatroska[] = {
47 48 49
    {1, 0, &EBML_ContextHead        ,0},
    {1, 0, &MATROSKA_ContextSegment ,0},
    {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 53 54

err_t MATROSKA_Init(nodecontext *p)
{
55
#if defined(MATROSKA_LIBRARY)
56
    tchar_t LibName[MAXPATH];
57
#endif
58 59 60
    err_t Err = EBML_Init(p);
    if (Err == ERR_NONE)
    {
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 69 70 71 72
}

err_t MATROSKA_Done(nodecontext *p)
{
    return EBML_Done(p);
}
73 74 75 76 77


#define MATROSKA_CUE_SEGMENTINFO     0x100
#define MATROSKA_CUE_BLOCK           0x101

78 79
#define MATROSKA_CLUSTER_READ_SEGMENTINFO  0x100
#define MATROSKA_CLUSTER_WRITE_SEGMENTINFO 0x101
80

81 82
#define MATROSKA_SEEKPOINT_ELEMENT   0x100

83 84 85 86
#define LACING_NONE  0
#define LACING_XIPH  1
#define LACING_FIXED 2
#define LACING_EBML  3
87
#define LACING_AUTO  4
88

89
struct matroska_cuepoint
90
{
91 92
    ebml_master Base;
    ebml_master *SegInfo;
93
    matroska_block *Block;
94
};
95

96
struct matroska_cluster
97
{
98 99 100
    ebml_master Base;
    ebml_master *ReadSegInfo;
    ebml_master *WriteSegInfo;
101
    timecode_t GlobalTimecode;
102
};
103

104 105
struct matroska_seekpoint
{
106
    ebml_master Base;
107 108 109
    ebml_element *Link;
};

110 111 112 113 114 115
struct matroska_trackentry
{
    ebml_master Base;
    bool_t CodecPrivateCompressed;
};

116 117 118 119 120 121
static err_t BlockTrackChanged(matroska_block *Block)
{
	Block->Base.Base.bNeedDataSizeUpdate = 1;
	return ERR_NONE;
}

122 123
static err_t ClusterTimeChanged(matroska_cluster *Cluster)
{
124 125 126
    timecode_t ClusterTimecode;
#if defined(CONFIG_EBML_WRITING)
    timecode_t BlockTimecode;
127
    ebml_element *Elt, *GBlock;
128
#endif
129 130 131 132 133 134 135

	Cluster->Base.Base.bNeedDataSizeUpdate = 1;
    ClusterTimecode = MATROSKA_ClusterTimecode(Cluster);
    MATROSKA_ClusterSetTimecode(Cluster, ClusterTimecode);
#if defined(CONFIG_EBML_WRITING)
    for (Elt = EBML_MasterChildren(Cluster); Elt; Elt = EBML_MasterNext(Elt))
    {
136
        if (EBML_ElementIsType(Elt, &MATROSKA_ContextBlockGroup))
137 138 139
        {
            for (GBlock = EBML_MasterChildren(Elt);GBlock;GBlock=EBML_MasterNext(GBlock))
            {
140
                if (EBML_ElementIsType(GBlock, &MATROSKA_ContextBlock))
141 142 143 144 145 146 147 148
                {
                    BlockTimecode = MATROSKA_BlockTimecode((matroska_block*)GBlock);
                    if (BlockTimecode!=INVALID_TIMECODE_T)
                        MATROSKA_BlockSetTimecode((matroska_block*)GBlock, BlockTimecode, ClusterTimecode);
                    break;
                }
            }
        }
149
        else if (EBML_ElementIsType(Elt, &MATROSKA_ContextSimpleBlock))
150 151 152 153 154 155 156 157 158 159
        {
            BlockTimecode = MATROSKA_BlockTimecode((matroska_block*)Elt);
            if (BlockTimecode!=INVALID_TIMECODE_T)
                MATROSKA_BlockSetTimecode((matroska_block*)Elt, BlockTimecode, ClusterTimecode);
        }
    }
#endif
    return ERR_NONE;
}

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 166 167 168 169
    if (Elt)
    {
        if (ARRAYCOUNT(Block->Data,uint8_t))
            return ERR_INVALID_PARAM; // we cannot adjust sizes if the data are already read

170
        Elt = (ebml_master*)EBML_MasterFindChild(Elt, &MATROSKA_ContextContentEncoding);
171 172 173 174 175
        if (EBML_MasterChildren(Elt))
        {
            if (EBML_MasterNext(Elt))
                return ERR_INVALID_DATA; // TODO support cascaded compression/encryption

176
            Elt = (ebml_master*)EBML_MasterFindChild(Elt, &MATROSKA_ContextContentCompression);
177 178 179
            if (!Elt)
                return ERR_INVALID_DATA; // TODO: support encryption

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 186
#endif
#if defined(CONFIG_LZO1X)
187
                    if (EBML_IntegerValue((ebml_integer*)Header)!=MATROSKA_BLOCK_COMPR_LZO1X)
188 189
#endif
#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 195
#endif
                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 201 202 203
                if (Header)
                {
                    uint32_t *i;
        		    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 210 211
            }
        }
    }
    return ERR_NONE;
}

212
err_t MATROSKA_LinkBlockWithReadTracks(matroska_block *Block, ebml_master *Tracks, bool_t UseForWriteToo)
213
{
214 215
    ebml_element *Track;
    ebml_integer *TrackNum;
216
    bool_t WasLinked = Block->ReadTrack!=NULL;
217

218
    assert(EBML_ElementIsType((ebml_element*)Tracks, &MATROSKA_ContextTracks));
219 220 221
    assert(Node_IsPartOf(Block,MATROSKA_BLOCK_CLASS));
    for (Track=EBML_MasterChildren(Tracks);Track;Track=EBML_MasterNext(Track))
    {
222 223
        TrackNum = (ebml_integer*)EBML_MasterFindChild((ebml_master*)Track,&MATROSKA_ContextTrackNumber);
        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 228
            if (UseForWriteToo)
                Node_SET(Block,MATROSKA_BLOCK_WRITE_TRACK,&Track);
229
#endif
230 231
            if (WasLinked)
                return ERR_NONE;
232
            return CheckCompression(Block);
233 234 235 236 237
        }
    }
    return ERR_INVALID_DATA;
}

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 246
    TrackNum = (ebml_integer*)EBML_MasterFindChild(Track,&MATROSKA_ContextTrackNumber);
    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 252
        if (UseForWriteToo)
            Node_SET(Block,MATROSKA_BLOCK_WRITE_TRACK,&Track);
253
#endif
254 255
        if (WasLinked)
            return ERR_NONE;
256
        return CheckCompression(Block);
257 258 259 260
    }
    return ERR_INVALID_DATA;
}

261
#if defined(CONFIG_EBML_WRITING)
262
err_t MATROSKA_LinkBlockWithWriteTracks(matroska_block *Block, ebml_master *Tracks)
263
{
264
    ebml_master *Track;
265
    ebml_integer *TrackNum;
266 267
    bool_t WasLinked = Block->WriteTrack!=NULL;

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 273
        TrackNum = (ebml_integer*)EBML_MasterFindChild(Track,&MATROSKA_ContextTrackNumber);
        if (TrackNum && ((ebml_element*)TrackNum)->bValueIsSet && EBML_IntegerValue(TrackNum)==Block->TrackNumber)
274 275 276 277
        {
            Node_SET(Block,MATROSKA_BLOCK_WRITE_TRACK,&Track);
            if (WasLinked)
                return ERR_NONE;
278
            return CheckCompression(Block);
279 280 281 282 283
        }
    }
    return ERR_INVALID_DATA;
}

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 292
    TrackNum = (ebml_integer*)EBML_MasterFindChild(Track,&MATROSKA_ContextTrackNumber);
    if (TrackNum && ((ebml_element*)TrackNum)->bValueIsSet)
293 294 295 296 297
    {
        Block->TrackNumber = (uint16_t)EBML_IntegerValue(TrackNum);
        Node_SET(Block,MATROSKA_BLOCK_WRITE_TRACK,&Track);
        if (WasLinked)
            return ERR_NONE;
298
        return CheckCompression(Block);
299 300 301
    }
    return ERR_INVALID_DATA;
}
302
#endif
303 304 305 306 307 308 309 310 311

ebml_element *MATROSKA_BlockReadTrack(const matroska_block *Block)
{
    ebml_element *Track;
    if (Node_GET((node*)Block,MATROSKA_BLOCK_READ_TRACK,&Track)!=ERR_NONE)
        return NULL;
    return Track;
}

312
#if defined(CONFIG_EBML_WRITING)
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 318 319
        return NULL;
    return Track;
}
320
#endif
321

322 323
err_t MATROSKA_LinkMetaSeekElement(matroska_seekpoint *MetaSeek, ebml_element *Link)
{
324
    assert(EBML_ElementIsType((ebml_element*)MetaSeek, &MATROSKA_ContextSeek));
325 326 327 328
    Node_SET(MetaSeek,MATROSKA_SEEKPOINT_ELEMENT,&Link);
    return ERR_NONE;
}

329 330 331
fourcc_t MATROSKA_MetaSeekID(const matroska_seekpoint *MetaSeek)
{
	ebml_element *SeekID;
332
    assert(EBML_ElementIsType((ebml_element*)MetaSeek, &MATROSKA_ContextSeek));
333
    SeekID = EBML_MasterFindChild((ebml_master*)MetaSeek, &MATROSKA_ContextSeekID);
334 335 336 337 338
	if (!SeekID)
		return 0;
	return EBML_BufferToID(EBML_BinaryGetData((ebml_binary*)SeekID));
}

339 340 341 342 343
bool_t MATROSKA_MetaSeekIsClass(const matroska_seekpoint *MetaSeek, const ebml_context *Class)
{
    return MATROSKA_MetaSeekID(MetaSeek) == Class->Id;
}

344 345
filepos_t MATROSKA_MetaSeekPosInSegment(const matroska_seekpoint *MetaSeek)
{
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 350 351 352 353 354 355 356 357 358 359 360 361
	if (!SeekPos)
		return INVALID_FILEPOS_T;
	return EBML_IntegerValue(SeekPos);
}

filepos_t MATROSKA_MetaSeekAbsolutePos(const matroska_seekpoint *MetaSeek)
{
	filepos_t RelPos = MATROSKA_MetaSeekPosInSegment(MetaSeek);
	ebml_element *RSegment;
	if (RelPos==INVALID_FILEPOS_T)
		return INVALID_FILEPOS_T;

    RSegment = EBML_ElementParent(MetaSeek);
362
    while (RSegment && !EBML_ElementIsType(RSegment, &MATROSKA_ContextSegment))
363 364 365 366 367 368 369
        RSegment = EBML_ElementParent(RSegment);
    if (!RSegment)
        return INVALID_FILEPOS_T;

	return RelPos + EBML_ElementPositionData(RSegment);
}

370 371
err_t MATROSKA_MetaSeekUpdate(matroska_seekpoint *MetaSeek)
{
372
    ebml_element *WSeekID, *WSeekPosSegmentInfo, *RSegment, *Link = NULL;
373 374 375 376
    size_t IdSize;
    err_t Err;
    uint8_t IdBuffer[4];

377 378 379
    if (Node_IsPartOf(MetaSeek,EBML_VOID_CLASS))
        return ERR_NONE;

380
    assert(EBML_ElementIsType((ebml_element*)MetaSeek, &MATROSKA_ContextSeek));
381
    RSegment = EBML_ElementParent(MetaSeek);
382
    while (RSegment && !EBML_ElementIsType(RSegment, &MATROSKA_ContextSegment))
383 384
        RSegment = EBML_ElementParent(RSegment);
    if (!RSegment)
385 386 387 388 389 390 391 392
        return ERR_INVALID_DATA;

    Err = Node_GET(MetaSeek,MATROSKA_SEEKPOINT_ELEMENT,&Link);
    if (Err != ERR_NONE)
        return Err;
    if (Link==NULL)
        return ERR_INVALID_DATA;

393
    WSeekID = EBML_MasterFindFirstElt((ebml_master*)MetaSeek,&MATROSKA_ContextSeekID,1,0);
394 395 396
    IdSize = EBML_FillBufferID(IdBuffer,sizeof(IdBuffer),Link->Context->Id);
    EBML_BinarySetData((ebml_binary*)WSeekID,IdBuffer,IdSize);

397
    WSeekPosSegmentInfo = EBML_MasterFindFirstElt((ebml_master*)MetaSeek,&MATROSKA_ContextSeekPosition,1,0);
398
    EBML_IntegerSetValue((ebml_integer*)WSeekPosSegmentInfo, Link->ElementPosition - EBML_ElementPositionData(RSegment));
399 400 401 402

    return Err;
}

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 408 409 410 411 412 413
    Node_SET(Cluster,MATROSKA_CLUSTER_READ_SEGMENTINFO,&SegmentInfo);
    if (UseForWriteToo)
        Node_SET(Cluster,MATROSKA_CLUSTER_WRITE_SEGMENTINFO,&SegmentInfo);
    return ERR_NONE;
}

#if defined(CONFIG_EBML_WRITING)
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 419 420 421 422
    Node_SET(Cluster,MATROSKA_CLUSTER_WRITE_SEGMENTINFO,&SegmentInfo);
    return ERR_NONE;
}
#endif

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 427 428 429 430 431
    assert(Node_IsPartOf(Block,MATROSKA_BLOCK_CLASS));
    Node_SET(Block,MATROSKA_BLOCK_READ_SEGMENTINFO,&SegmentInfo);
#if defined(CONFIG_EBML_WRITING)
    if (UseForWriteToo)
        Node_SET(Block,MATROSKA_BLOCK_WRITE_SEGMENTINFO,&SegmentInfo);
#endif
432 433 434
    return ERR_NONE;
}

435
#if defined(CONFIG_EBML_WRITING)
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 442
    return ERR_NONE;
}
443
#endif
444

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 450 451 452
        return NULL;
    return SegmentInfo;
}

453 454 455 456 457 458 459 460 461 462
#if defined(CONFIG_EBML_WRITING)
ebml_element *MATROSKA_BlockWriteSegmentInfo(const matroska_block *Block)
{
    ebml_element *SegmentInfo;
    if (Node_GET((node*)Block,MATROSKA_BLOCK_WRITE_SEGMENTINFO,&SegmentInfo)!=ERR_NONE)
        return NULL;
    return SegmentInfo;
}
#endif

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 468 469 470
    Node_SET(Cue,MATROSKA_CUE_SEGMENTINFO,&SegmentInfo);
    return ERR_NONE;
}

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 477 478
    return ERR_NONE;
}

479 480
static int MATROSKA_BlockCmp(const matroska_block *BlockA, const matroska_block *BlockB)
{
481 482
    timecode_t TimeA = MATROSKA_BlockTimecode((matroska_block*)BlockA);
    timecode_t TimeB = MATROSKA_BlockTimecode((matroska_block*)BlockB);
483 484 485 486 487 488 489 490
    if (TimeA != TimeB)
        return (int)((TimeA - TimeB)/100000);
    return MATROSKA_BlockTrackNum(BlockB) - MATROSKA_BlockTrackNum(BlockA); // usually the first track is video, so put audio/subs first
}

static int ClusterEltCmp(const matroska_cluster* Cluster, const ebml_element** a,const ebml_element** b)
{
    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 495
        return 1;

496
    if (EBML_ElementIsType(*a, &MATROSKA_ContextSimpleBlock))
497
        BlockA = (const matroska_block *)*a;
498 499 500
    else if (EBML_ElementIsType(*a, &MATROSKA_ContextBlockGroup))
        BlockA = (const matroska_block *)EBML_MasterFindChild((ebml_master*)*a,&MATROSKA_ContextBlock);
    if (EBML_ElementIsType(*b, &MATROSKA_ContextSimpleBlock))
501
        BlockB = (const matroska_block *)*b;
502 503
    else if (EBML_ElementIsType(*a, &MATROSKA_ContextBlockGroup))
        BlockB = (const matroska_block *)EBML_MasterFindChild((ebml_master*)*b,&MATROSKA_ContextBlock);
504 505 506 507 508 509 510 511 512
    if (BlockA != NULL && BlockB != NULL)
        return MATROSKA_BlockCmp(BlockA,BlockB);

    assert(0); // unsupported comparison
    return 0;
}

void MATROSKA_ClusterSort(matroska_cluster *Cluster)
{
513
    EBML_MasterSort((ebml_master*)Cluster,(arraycmp)ClusterEltCmp,Cluster);
514 515
}

516 517
void MATROSKA_ClusterSetTimecode(matroska_cluster *Cluster, timecode_t Timecode)
{
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 528
#if defined(CONFIG_EBML_WRITING)
	assert(Cluster->WriteSegInfo);
529
	EBML_IntegerSetValue(TimecodeElt, Scale64(Timecode,1,MATROSKA_SegmentInfoTimecodeScale(Cluster->WriteSegInfo)));
530 531 532
    // update all the blocks LocalTimecode
    for (Elt = EBML_MasterChildren(Cluster); Elt; Elt = EBML_MasterNext(Elt))
    {
533
        if (EBML_ElementIsType(Elt, &MATROSKA_ContextBlockGroup))
534 535 536
        {
            for (GBlock = EBML_MasterChildren(Elt);GBlock;GBlock=EBML_MasterNext(GBlock))
            {
537
                if (EBML_ElementIsType(GBlock, &MATROSKA_ContextBlock))
538
                {
539 540 541
                    BlockTimeCode = MATROSKA_BlockTimecode((matroska_block*)GBlock);
                    if (BlockTimeCode!=INVALID_TIMECODE_T)
                        MATROSKA_BlockSetTimecode((matroska_block*)GBlock, BlockTimeCode, Timecode);
542 543 544 545
                    break;
                }
            }
        }
546
        else if (EBML_ElementIsType(Elt, &MATROSKA_ContextSimpleBlock))
547 548 549 550 551
        {
            BlockTimeCode = MATROSKA_BlockTimecode((matroska_block*)Elt);
            if (BlockTimeCode!=INVALID_TIMECODE_T)
                MATROSKA_BlockSetTimecode((matroska_block*)Elt, BlockTimeCode, Timecode);
        }
552
    }
553 554
#else
	assert(Cluster->ReadSegInfo);
555
	EBML_IntegerSetValue(TimecodeElt, Scale64(Timecode,1,MATROSKA_SegmentInfoTimecodeScale(Cluster->ReadSegInfo)));
556
#endif
557 558
}

559
timecode_t MATROSKA_ClusterTimecode(matroska_cluster *Cluster)
560
{
561
    assert(EBML_ElementIsType((ebml_element*)Cluster, &MATROSKA_ContextCluster));
562 563
    if (Cluster->GlobalTimecode == INVALID_TIMECODE_T)
    {
564
        ebml_integer *Timecode = (ebml_integer*)EBML_MasterFindChild((ebml_master*)Cluster,&MATROSKA_ContextTimecode);
565 566 567 568
        if (Timecode)
            Cluster->GlobalTimecode = EBML_IntegerValue(Timecode) * MATROSKA_SegmentInfoTimecodeScale(Cluster->ReadSegInfo);
    }
    return Cluster->GlobalTimecode;
569 570
}

571 572 573 574 575 576 577 578 579 580
timecode_t MATROSKA_ClusterTimecodeScale(matroska_cluster *Cluster, bool_t Read)
{
#if defined(CONFIG_EBML_WRITING)
    if (!Read)
        return MATROSKA_SegmentInfoTimecodeScale(Cluster->WriteSegInfo);
#endif
    return MATROSKA_SegmentInfoTimecodeScale(Cluster->ReadSegInfo);
}

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 591 592
	if (InternalTimecode > 32767 || InternalTimecode < -32768)
		return ERR_INVALID_DATA;
	Block->LocalTimecode = (int16_t)InternalTimecode;
593
    Block->LocalTimecodeUsed = 1;
594 595 596
	return ERR_NONE;
}

597
timecode_t MATROSKA_BlockTimecode(matroska_block *Block)
598 599 600
{
    ebml_element *Cluster;
    assert(Node_IsPartOf(Block,MATROSKA_BLOCK_CLASS));
601 602
	if (Block->GlobalTimecode!=INVALID_TIMECODE_T)
		return Block->GlobalTimecode;
603 604
    if (Block->ReadTrack==NULL)
        return INVALID_TIMECODE_T;
605
    assert(Block->LocalTimecodeUsed);
606
    Cluster = EBML_ElementParent(Block);
607
    while (Cluster && !EBML_ElementIsType(Cluster, &MATROSKA_ContextCluster))
608 609 610
        Cluster = EBML_ElementParent(Cluster);
    if (!Cluster)
        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 613
    MATROSKA_BlockSetTimecode(Block, Block->GlobalTimecode, MATROSKA_ClusterTimecode((matroska_cluster*)Cluster));
    return Block->GlobalTimecode;
614 615 616 617 618
}

int16_t MATROSKA_BlockTrackNum(const matroska_block *Block)
{
    assert(Node_IsPartOf(Block,MATROSKA_BLOCK_CLASS));
619
    assert(Block->LocalTimecodeUsed);
620 621 622
    return Block->TrackNumber;
}

623 624
bool_t MATROSKA_BlockKeyframe(const matroska_block *Block)
{
625 626 627
    ebml_master *BlockGroup;
    ebml_integer *Duration;

628
    assert(Node_IsPartOf(Block,MATROSKA_BLOCK_CLASS));
629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646
    if (Block->IsKeyframe)
        return 1;

	if (!EBML_ElementIsType((const ebml_element*)Block, &MATROSKA_ContextBlock))
        return 0;
	
	BlockGroup = (ebml_master*)EBML_ElementParent(Block);
    if (!BlockGroup || !Node_IsPartOf(BlockGroup,MATROSKA_BLOCKGROUP_CLASS))
        return 0;

	if (EBML_MasterFindChild(BlockGroup,&MATROSKA_ContextReferenceBlock))
        return 0;

    Duration = (ebml_integer*)EBML_MasterFindChild(BlockGroup,&MATROSKA_ContextBlockDuration);
	if (Duration!=NULL && EBML_IntegerValue(Duration)==0)
        return 0;

    return 1;
647 648
}

649 650 651
bool_t MATROSKA_BlockDiscardable(const matroska_block *Block)
{
    assert(Node_IsPartOf(Block,MATROSKA_BLOCK_CLASS));
652
	if (EBML_ElementIsType((const ebml_element*)Block, &MATROSKA_ContextBlock))
653 654 655 656
        return 0;
	return Block->IsDiscardable;
}

657 658 659 660 661 662
void MATROSKA_BlockSetKeyframe(matroska_block *Block, bool_t Set)
{
    assert(Node_IsPartOf(Block,MATROSKA_BLOCK_CLASS));
	Block->IsKeyframe = Set;
}

663 664 665
void MATROSKA_BlockSetDiscardable(matroska_block *Block, bool_t Set)
{
    assert(Node_IsPartOf(Block,MATROSKA_BLOCK_CLASS));
666
	if (EBML_ElementIsType((const ebml_element*)Block, &MATROSKA_ContextSimpleBlock))
667 668 669
    	Block->IsDiscardable = Set;
}

670 671 672
bool_t MATROSKA_BlockLaced(const matroska_block *Block)
{
    assert(Node_IsPartOf(Block,MATROSKA_BLOCK_CLASS));
673
    assert(Block->LocalTimecodeUsed);
674 675 676
    return Block->Lacing != LACING_NONE;
}

677 678
int16_t MATROSKA_CueTrackNum(const matroska_cuepoint *Cue)
{
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 684
    if (!Position)
        return -1;
685
    CueTrack = (ebml_integer*)EBML_MasterFindChild(Position,&MATROSKA_ContextCueTrack);
686 687
    if (!CueTrack)
        return -1;
688
    return (int16_t)EBML_IntegerValue(CueTrack);
689 690
}

691
void MATROSKA_CuesSort(ebml_master *Cues)
692
{
693
    assert(EBML_ElementIsType((ebml_element*)Cues, &MATROSKA_ContextCues));
694 695 696
    EBML_MasterSort(Cues,NULL,NULL);
}

697 698
void MATROSKA_AttachmentSort(ebml_master *Attachments)
{
699
    assert(EBML_ElementIsType((ebml_element*)Attachments, &MATROSKA_ContextAttachments));
700 701 702
    EBML_MasterSort(Attachments,NULL,NULL);
}

703
timecode_t MATROSKA_SegmentInfoTimecodeScale(const ebml_master *SegmentInfo)
704
{
705
    ebml_integer *TimecodeScale = NULL;
706 707
    if (SegmentInfo)
    {
708
        assert(EBML_ElementIsType((ebml_element*)SegmentInfo, &MATROSKA_ContextInfo));
709
        TimecodeScale = (ebml_integer*)EBML_MasterFindChild((ebml_master*)SegmentInfo,&MATROSKA_ContextTimecodeScale);
710
    }
711 712
    if (!TimecodeScale)
        return MATROSKA_ContextTimecodeScale.DefaultValue;
713
    return EBML_IntegerValue(TimecodeScale);
714 715
}

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 724 725 726 727
    return ((ebml_float*)TimecodeScale)->Value;
}

timecode_t MATROSKA_CueTimecode(const matroska_cuepoint *Cue)
{
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 732
    if (!TimeCode)
        return INVALID_TIMECODE_T;
733
    return EBML_IntegerValue(TimeCode) * MATROSKA_SegmentInfoTimecodeScale(Cue->SegInfo);
734 735
}

736 737 738
filepos_t MATROSKA_CuePosInSegment(const matroska_cuepoint *Cue)
{
    ebml_element *TimeCode;
739
    assert(EBML_ElementIsType((ebml_element*)Cue, &MATROSKA_ContextCuePoint));
740
    TimeCode = EBML_MasterFindChild((ebml_master*)Cue,&MATROSKA_ContextCueTrackPositions);
741 742
    if (!TimeCode)
        return INVALID_TIMECODE_T;
743
    TimeCode = EBML_MasterFindChild((ebml_master*)TimeCode,&MATROSKA_ContextCueClusterPosition);
744 745
    if (!TimeCode)
        return INVALID_TIMECODE_T;
746
    return EBML_IntegerValue((ebml_integer*)TimeCode);
747 748
}

749 750
err_t MATROSKA_CuePointUpdate(matroska_cuepoint *Cue, ebml_element *Segment)
{
751 752
    ebml_element *TimecodeElt, *Elt, *PosInCluster;
    ebml_integer *TrackNum;
753
    assert(EBML_ElementIsType((ebml_element*)Cue, &MATROSKA_ContextCuePoint));
754 755 756
    assert(Cue->Block);
    assert(Cue->SegInfo);
    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 766
    if (!Elt)
        return ERR_OUT_OF_MEMORY;
767
	TrackNum = (ebml_integer*)EBML_MasterGetChild((ebml_master*)Elt,&MATROSKA_ContextCueTrack);
768 769
    if (!TrackNum)
        return ERR_OUT_OF_MEMORY;
770
	EBML_IntegerSetValue(TrackNum, MATROSKA_BlockTrackNum(Cue->Block));
771
	
772
    PosInCluster = EBML_MasterGetChild((ebml_master*)Elt,&MATROSKA_ContextCueClusterPosition);
773 774 775
    if (!PosInCluster)
        return ERR_OUT_OF_MEMORY;
    Elt = EBML_ElementParent(Cue->Block);
776
    while (Elt && !EBML_ElementIsType(Elt, &MATROSKA_ContextCluster))
777 778 779
        Elt = EBML_ElementParent(Elt);
    if (!Elt)
        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 786 787

    return ERR_NONE;
}

788 789 790 791 792
matroska_block *MATROSKA_GetBlockForTimecode(matroska_cluster *Cluster, timecode_t Timecode, int16_t Track)
{
    ebml_element *Block, *GBlock;
    for (Block = EBML_MasterChildren(Cluster);Block;Block=EBML_MasterNext(Block))
    {
793
        if (EBML_ElementIsType(Block, &MATROSKA_ContextBlockGroup))
794 795 796
        {
            for (GBlock = EBML_MasterChildren(Block);GBlock;GBlock=EBML_MasterNext(GBlock))
            {
797
                if (EBML_ElementIsType(GBlock, &MATROSKA_ContextBlock))
798 799 800 801 802 803 804 805 806
                {
                    if (MATROSKA_BlockTrackNum((matroska_block*)GBlock) == Track &&
                        MATROSKA_BlockTimecode((matroska_block*)GBlock) == Timecode)
                    {
                        return (matroska_block*)GBlock;
                    }
                }
            }
        }
807
        else if (EBML_ElementIsType(Block, &MATROSKA_ContextSimpleBlock))
808 809 810 811 812 813 814 815 816 817 818
        {
            if (MATROSKA_BlockTrackNum((matroska_block*)Block) == Track &&
                MATROSKA_BlockTimecode((matroska_block*)Block) == Timecode)
            {
                return (matroska_block*)Block;
            }
        }
    }
    return NULL;
}

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 835
		{
			for (GBlock = EBML_MasterChildren(Block);GBlock;GBlock=EBML_MasterNext(GBlock))
			{
836
				if (EBML_ElementIsType(GBlock, &MATROSKA_ContextBlock))
837
				{
838
					if (MATROSKA_LinkBlockWithReadTracks((matroska_block*)GBlock,Tracks,1)!=ERR_NONE && !KeepUnmatched)
839 840
                        NodeDelete((node*)Block);
                    else
841
					    MATROSKA_LinkBlockReadSegmentInfo((matroska_block*)GBlock,RSegmentInfo,1);
842 843 844 845
					break;
				}
			}
		}
846
		else if (EBML_ElementIsType(Block, &MATROSKA_ContextSimpleBlock))
847
		{
848
			if (MATROSKA_LinkBlockWithReadTracks((matroska_block*)Block,Tracks,1)!=ERR_NONE && !KeepUnmatched)
849 850
                NodeDelete((node*)Block);
            else
851
    			MATROSKA_LinkBlockReadSegmentInfo((matroska_block*)Block,RSegmentInfo,1);
852 853 854 855 856
		}
	}
}


857 858 859 860 861 862 863 864 865
static size_t GetBlockHeadSize(const matroska_block *Element)
{
    assert(Element->TrackNumber < 0x4000);
    if (Element->TrackNumber < 0x80)
        return 4;
    else
        return 5;
}

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 873 874 875 876 877 878 879 880
    if (ARRAYCOUNT(Block->SizeListIn,int32_t))
    {
        // recover the size of each lace in SizeList for later reading
        int32_t *i,*o;
        assert(ARRAYCOUNT(Block->SizeListIn,int32_t) == ARRAYCOUNT(Block->SizeList,int32_t));
        for (i=ARRAYBEGIN(Block->SizeListIn,int32_t),o=ARRAYBEGIN(Block->SizeList,int32_t);i!=ARRAYEND(Block->SizeListIn,int32_t);++i,++o)
            *o = *i;
        ArrayClear(&Block->SizeListIn);
    }
881 882 883
    return ERR_NONE;
}

884 885 886 887 888 889 890 891 892 893
err_t MATROSKA_BlockSkipToFrame(const matroska_block *Block, stream *Input, size_t FrameNum)
{
	uint32_t *i;
	filepos_t SeekPos = EBML_ElementPositionData((ebml_element*)Block);
	if (FrameNum >= ARRAYCOUNT(Block->SizeList,uint32_t))
		return ERR_INVALID_PARAM;
	if (Block->Lacing == LACING_NONE)
		SeekPos += GetBlockHeadSize(Block);
	else
	{
894
		SeekPos = Block->FirstFrameLocation;
895 896 897 898 899 900 901 902
		for (i=ARRAYBEGIN(Block->SizeList,uint32_t);FrameNum;--FrameNum,++i)
			SeekPos += *i;
	}
	if (Stream_Seek(Input,SeekPos,SEEK_SET) != SeekPos)
		return ERR_READ;
	return ERR_NONE;
}

903 904
// TODO: support zero copy reading (read the frames directly into a buffer with a callback per frame)
//       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
905 906
err_t MATROSKA_BlockReadData(matroska_block *Element, stream *Input)
{
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 917
        // find out if compressed headers are used
        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 923 924 925
            if (EBML_MasterChildren(Elt))
            {
                if (EBML_MasterNext(Elt))
                    return ERR_NOT_SUPPORTED; // TODO support cascaded compression/encryption
926

927 928
                Elt2 = EBML_MasterFindChild((ebml_master*)Elt, &MATROSKA_ContextContentEncodingScope);
                if (Elt2)
929
                    CompressionScope = (int)EBML_IntegerValue((ebml_integer*)Elt2);
930

931
                Elt = EBML_MasterFindChild((ebml_master*)Elt, &MATROSKA_ContextContentCompression);
932 933
                if (!Elt)
                    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 941
#endif
#if defined(CONFIG_LZO1X)
942
                    if (EBML_IntegerValue((ebml_integer*)Header)!=MATROSKA_BLOCK_COMPR_LZO1X)
943 944
#endif
#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 961
#endif

962 963 964
        if (Header && Header->Context==&MATROSKA_ContextContentCompAlgo && !(CompressionScope & MATROSKA_COMPR_SCOPE_BLOCK))
            Header = NULL;

965
        Stream_Seek(Input,Element->FirstFrameLocation,SEEK_SET);
966 967
        if (Header)
            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 975 976 977 978
                // zlib handling, read the buffer in temp memory
                array TmpBuf;
                ArrayInit(&TmpBuf);
                if (!ArrayResize(&TmpBuf,(size_t)ARRAYBEGIN(Element->SizeList,int32_t)[0],0))
                    Err = ERR_OUT_OF_MEMORY;
979 980
                InBuf = ARRAYBEGIN(TmpBuf,uint8_t);
                Err = Stream_Read(Input,InBuf,(size_t)ARRAYBEGIN(Element->SizeList,int32_t)[0],&Read);
981 982 983 984 985 986
                if (Err==ERR_NONE)
                {
                    if (Read!=(size_t)ARRAYBEGIN(Element->SizeList,int32_t)[0])
                        Err = ERR_READ;
                    else
                    {
987
#if defined(CONFIG_ZLIB)
988
                        if (EBML_IntegerValue((ebml_integer*)Header)==MATROSKA_BLOCK_COMPR_ZLIB)
989
                        {
990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024
                            // get the ouput size, adjust the Element->SizeList value, write in Element->Data
                            z_stream stream;
                            int Res;
                            memset(&stream,0,sizeof(stream));
                            Res = inflateInit(&stream);
                            if (Res != Z_OK)
                                Err = ERR_INVALID_DATA;
                            else
                            {
                                size_t Count = 0;
                                stream.next_in = InBuf;
                                stream.avail_in = ARRAYBEGIN(Element->SizeList,int32_t)[0];
                                stream.next_out = ARRAYBEGIN(Element->Data,uint8_t);
                                do {
                                    Count = stream.next_out - ARRAYBEGIN(Element->Data,uint8_t);
                                    stream.avail_out = 1024;
                                    if (!ArrayResize(&Element->Data, Count + stream.avail_out, 0))
                                    {
                                        Res = Z_MEM_ERROR;
                                        break;
                                    }
                                    stream.next_out = ARRAYBEGIN(Element->Data,uint8_t) + Count;
                                    Res = inflate(&stream, Z_NO_FLUSH);
                                    if (Res!=Z_STREAM_END && Res!=Z_OK)
                                        break;
                                } while (Res!=Z_STREAM_END && stream.avail_in && !stream.avail_out);
                                ArrayResize(&Element->Data, stream.total_out, 0);
                                ARRAYBEGIN(Element->SizeList,int32_t)[0] = stream.total_out;
                                inflateEnd(&stream);
                                if (Res != Z_STREAM_END)
                                    Err = ERR_INVALID_DATA;
                            }
                        }
#endif
#if defined(CONFIG_LZO1X)
1025
                        if (EBML_IntegerValue((ebml_integer*)Header)==MATROSKA_BLOCK_COMPR_LZO1X)
1026 1027 1028 1029 1030
                        {
                            if (lzo_init() != LZO_E_OK)
                                Err = ERR_INVALID_DATA;
                            else
                            {
1031
                                lzo_uint outSize = max(2048, ARRAYBEGIN(Element->SizeList,int32_t)[0] << 2);
1032 1033 1034
                                if (!ArrayResize(&Element->Data, outSize, 0))
                                    Err = ERR_OUT_OF_MEMORY;
                                else
1035
                                {
1036 1037 1038 1039 1040 1041 1042
                                    if (lzo1x_decompress_safe(InBuf, ARRAYBEGIN(Element->SizeList,int32_t)[0], ARRAYBEGIN(Element->Data,uint8_t), &outSize, NULL) != LZO_E_OK)
                                        Err = ERR_INVALID_DATA;
                                    else
                                    {
                                        ARRAYBEGIN(Element->SizeList,int32_t)[0] = outSize;
                                        ArrayResize(&Element->Data,outSize,0);
                                    }
1043
                                }
1044
                            }
1045
                        }
1046 1047
#endif
#if defined(CONFIG_BZLIB)
1048
                        if (EBML_IntegerValue((ebml_integer*)Header)==MATROSKA_BLOCK_COMPR_BZLIB)
1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065
                        {
                            unsigned int outSize = ARRAYBEGIN(Element->SizeList,int32_t)[0] << 2;
                            bz_stream strm;
                            int Res;

                            if (!ArrayResize(&Element->Data, outSize, 0))
                                Err = ERR_OUT_OF_MEMORY;
                            else
                            {
                               strm.bzalloc = NULL;
                               strm.bzfree = NULL;
                               strm.opaque = NULL;
                               if (BZ2_bzDecompressInit (&strm, 0, 1) != BZ_OK)
                                   Err = ERR_INVALID_DATA;
                               else
                               {
                                    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 1070 1071
                                    strm.avail_out = 0;

                                    do {
1072
                                        Count = strm.next_out - ARRAYBEGIN(Element->Data,char);
1073 1074 1075 1076 1077 1078
                                        strm.avail_out = 1024;
                                        if (!ArrayResize(&Element->Data, Count + strm.avail_out, 0))
                                        {
                                            Res = BZ_MEM_ERROR;
                                            break;
                                        }
1079
                                        strm.next_out = ARRAYBEGIN(Element->Data,char) + Count;
1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092
                                        Res = BZ2_bzDecompress(&strm);
                                        if (Res!=BZ_STREAM_END && Res!=BZ_OK)
                                            break;
                                    } while (Res!=BZ_STREAM_END && strm.avail_in && !strm.avail_out);
                                    ArrayResize(&Element->Data, strm.total_out_lo32, 0);
                                    ARRAYBEGIN(Element->SizeList,int32_t)[0] = strm.total_out_lo32;
                                    BZ2_bzDecompressEnd(&strm);
                                    if (Res != BZ_STREAM_END)
                                        Err = ERR_INVALID_DATA;
                                }
                            }
                        }
#endif
Steve Lhomme's avatar