Coverage Report

Created: 2026-01-17 06:26

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/vlc/modules/demux/mkv/util.cpp
Line
Count
Source
1
/*****************************************************************************
2
 * util.cpp : matroska demuxer
3
 *****************************************************************************
4
 * Copyright (C) 2003-2004 VLC authors and VideoLAN
5
 *
6
 * Authors: Laurent Aimar <fenrir@via.ecp.fr>
7
 *          Steve Lhomme <steve.lhomme@free.fr>
8
 *
9
 * This program is free software; you can redistribute it and/or modify it
10
 * under the terms of the GNU Lesser General Public License as published by
11
 * the Free Software Foundation; either version 2.1 of the License, or
12
 * (at your option) any later version.
13
 *
14
 * This program is distributed in the hope that it will be useful,
15
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17
 * GNU Lesser General Public License for more details.
18
 *
19
 * You should have received a copy of the GNU Lesser General Public License
20
 * along with this program; if not, write to the Free Software Foundation,
21
 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
22
 *****************************************************************************/
23
#include "mkv.hpp"
24
#include "util.hpp"
25
#include "demux.hpp"
26
#include "virtual_segment.hpp"
27
#include "../../codec/webvtt/helpers.h"
28
29
#include "lzokay.hpp"
30
31
namespace mkv {
32
33
/*****************************************************************************
34
 * Local prototypes
35
 *****************************************************************************/
36
37
#ifdef HAVE_ZLIB
38
int32_t zlib_decompress_extra( demux_t * p_demux, mkv_track_t & tk )
39
{
40
    int result;
41
    z_stream d_stream;
42
    size_t n = 0;
43
    uint8_t * p_new_extra = NULL;
44
45
    msg_Dbg(p_demux,"Inflating private data");
46
47
    d_stream.zalloc = Z_NULL;
48
    d_stream.zfree = Z_NULL;
49
    d_stream.opaque = Z_NULL;
50
    if( inflateInit( &d_stream ) != Z_OK )
51
    {
52
        msg_Err( p_demux, "Couldn't initiate inflation ignore track %u",
53
                 tk.i_number );
54
        return 1;
55
    }
56
57
    d_stream.next_in = tk.p_extra_data;
58
    d_stream.avail_in = tk.i_extra_data;
59
    do
60
    {
61
        n++;
62
        void *alloc = realloc(p_new_extra, n*1024);
63
        if( alloc == NULL )
64
        {
65
            msg_Err( p_demux, "Couldn't allocate buffer to inflate data, ignore track %u",
66
                      tk.i_number );
67
            free(p_new_extra);
68
            inflateEnd( &d_stream );
69
            return 1;
70
        }
71
72
        p_new_extra = static_cast<uint8_t *>( alloc );
73
        d_stream.next_out = &p_new_extra[(n - 1) * 1024];
74
        d_stream.avail_out = 1024;
75
        result = inflate(&d_stream, Z_NO_FLUSH);
76
        if( result != Z_OK && result != Z_STREAM_END )
77
        {
78
            msg_Err( p_demux, "Zlib decompression failed. Result: %d", result );
79
            inflateEnd( &d_stream );
80
            free(p_new_extra);
81
            return 1;
82
        }
83
    }
84
    while ( d_stream.avail_out == 0 && d_stream.avail_in != 0  &&
85
            result != Z_STREAM_END );
86
87
    free( tk.p_extra_data );
88
    tk.i_extra_data = d_stream.total_out;
89
    p_new_extra = static_cast<uint8_t *>( realloc(p_new_extra, tk.i_extra_data) );
90
    if( !p_new_extra )
91
    {
92
        msg_Err( p_demux, "Couldn't allocate buffer to inflate data, ignore track %u",
93
                 tk.i_number );
94
        inflateEnd( &d_stream );
95
        tk.p_extra_data = NULL;
96
        return 1;
97
    }
98
99
    tk.p_extra_data = p_new_extra;
100
101
    inflateEnd( &d_stream );
102
    return 0;
103
}
104
105
block_t *block_zlib_decompress( vlc_object_t *p_this, block_t *p_in_block ) {
106
    int result, dstsize, n;
107
    unsigned char *dst;
108
    block_t *p_block;
109
    z_stream d_stream;
110
111
    d_stream.zalloc = NULL;
112
    d_stream.zfree = NULL;
113
    d_stream.opaque = NULL;
114
    result = inflateInit(&d_stream);
115
    if( result != Z_OK )
116
    {
117
        msg_Dbg( p_this, "inflateInit() failed. Result: %d", result );
118
        return NULL;
119
    }
120
121
    d_stream.next_in = (Bytef *)p_in_block->p_buffer;
122
    d_stream.avail_in = p_in_block->i_buffer;
123
    n = 0;
124
    p_block = block_Alloc( 0 );
125
    dst = NULL;
126
    do
127
    {
128
        n++;
129
        p_block = block_Realloc( p_block, 0, n * 1000 );
130
        dst = static_cast<unsigned char *>( p_block->p_buffer );
131
        d_stream.next_out = (Bytef *)&dst[(n - 1) * 1000];
132
        d_stream.avail_out = 1000;
133
        result = inflate(&d_stream, Z_NO_FLUSH);
134
        if( ( result != Z_OK ) && ( result != Z_STREAM_END ) )
135
        {
136
            msg_Err( p_this, "Zlib decompression failed. Result: %d", result );
137
            inflateEnd( &d_stream );
138
            block_Release( p_block );
139
            return p_in_block;
140
        }
141
    }
142
    while( ( d_stream.avail_out == 0 ) && ( d_stream.avail_in != 0 ) &&
143
           ( result != Z_STREAM_END ) );
144
145
    dstsize = d_stream.total_out;
146
    inflateEnd( &d_stream );
147
148
    p_block = block_Realloc( p_block, 0, dstsize );
149
    p_block->i_buffer = dstsize;
150
    block_Release( p_in_block );
151
152
    return p_block;
153
}
154
#endif
155
156
bool lzo1x_decompress_extra( demux_t * p_demux, mkv_track_t & tk )
157
0
{
158
0
    lzokay::EResult result;
159
0
    size_t n = 0, total_out = 0;
160
0
    uint8_t * p_new_extra = nullptr;
161
162
0
    msg_Dbg(p_demux,"Inflating private data");
163
164
0
    do
165
0
    {
166
0
        n++;
167
0
        void *alloc = realloc(p_new_extra, n * 1024);
168
0
        if( alloc == nullptr )
169
0
        {
170
0
            msg_Err( p_demux, "Couldn't allocate buffer to inflate data, ignore track %u",
171
0
                      tk.i_number );
172
0
            free(p_new_extra);
173
0
            return false;
174
0
        }
175
176
0
        p_new_extra = static_cast<uint8_t *>( alloc );
177
0
        result = lzokay::decompress( tk.p_extra_data, tk.i_extra_data,
178
0
                                     p_new_extra, n * 1024, total_out );
179
0
    }
180
0
    while ( result == lzokay::EResult::OutputOverrun );
181
182
0
    if( result != lzokay::EResult::Success )
183
0
    {
184
0
        msg_Err( p_demux, "LZO1X private data decompression failed. Result: %d", (int)result );
185
0
        free(p_new_extra);
186
0
        return false;
187
0
    }
188
189
0
    free( tk.p_extra_data );
190
0
    tk.i_extra_data = total_out;
191
0
    tk.p_extra_data = p_new_extra;
192
193
0
    return true;
194
0
}
195
196
28.4k
block_t *block_lzo1x_decompress( vlc_object_t *p_this, block_t *p_in_block ) {
197
28.4k
    lzokay::EResult result;
198
28.4k
    size_t dstsize = 0, n;
199
28.4k
    block_t *p_block;
200
201
28.4k
    n = 0;
202
28.4k
    p_block = block_Alloc( 0 );
203
28.4k
    do
204
32.5k
    {
205
32.5k
        n++;
206
32.5k
        p_block = block_Realloc( p_block, 0, n * 1000 );
207
32.5k
        result = lzokay::decompress( p_in_block->p_buffer, p_in_block->i_buffer,
208
32.5k
                                     p_block->p_buffer, p_block->i_buffer, dstsize );
209
32.5k
    }
210
32.5k
    while( result == lzokay::EResult::OutputOverrun );
211
212
28.4k
    if( result != lzokay::EResult::Success )
213
26.4k
    {
214
26.4k
        msg_Err( p_this, "LZO1X decompression failed. Result: %d", (int)result );
215
26.4k
        block_Release( p_block );
216
26.4k
        return p_in_block;
217
26.4k
    }
218
219
1.96k
    p_block = block_Realloc( p_block, 0, dstsize );
220
1.96k
    p_block->i_buffer = dstsize;
221
1.96k
    block_Release( p_in_block );
222
223
1.96k
    return p_block;
224
28.4k
}
225
226
/* Utility function for BlockDecode */
227
block_t *MemToBlock( uint8_t *p_mem, size_t i_mem, size_t offset)
228
74.5k
{
229
74.5k
    if( unlikely( i_mem > SIZE_MAX - offset ) )
230
0
        return NULL;
231
232
74.5k
    block_t *p_block = block_Alloc( i_mem + offset );
233
74.5k
    if( likely(p_block != NULL) )
234
74.5k
    {
235
74.5k
        memcpy( p_block->p_buffer + offset, p_mem, i_mem );
236
74.5k
    }
237
74.5k
    return p_block;
238
74.5k
}
239
240
241
void handle_real_audio(demux_t * p_demux, mkv_track_t * p_tk, block_t * p_blk, vlc_tick_t i_pts)
242
1.85k
{
243
1.85k
    uint8_t * p_frame = p_blk->p_buffer;
244
1.85k
    Cook_PrivateTrackData * p_sys = static_cast<Cook_PrivateTrackData *>(p_tk->p_sys);
245
1.85k
    size_t size = p_blk->i_buffer;
246
247
1.85k
    if( p_tk->i_last_dts == VLC_TICK_INVALID )
248
1.18k
    {
249
24.2M
        for( size_t i = 0; i < p_sys->p_subpackets.size(); i++)
250
24.2M
            if( p_sys->p_subpackets[i] )
251
95
            {
252
95
                block_Release(p_sys->p_subpackets[i]);
253
95
                p_sys->p_subpackets[i] = NULL;
254
95
            }
255
1.18k
        p_sys->i_subpacket = 0;
256
257
1.18k
        if ( !( p_blk->i_flags & BLOCK_FLAG_TYPE_I) )
258
425
        {
259
425
            msg_Dbg( p_demux, "discard non-key preroll block in track %u at %" PRId64,
260
425
                     p_tk->i_number, i_pts );
261
425
            return;
262
425
        }
263
1.18k
    }
264
265
1.43k
    if( p_tk->fmt.i_codec == VLC_CODEC_COOK ||
266
0
        p_tk->fmt.i_codec == VLC_CODEC_ATRAC3 )
267
1.43k
    {
268
1.43k
        const uint16_t i_num = p_sys->i_frame_size / p_sys->i_subpacket_size;
269
1.43k
        if ( i_num == 0 )
270
533
            return;
271
899
        const size_t y = p_sys->i_subpacket / i_num;
272
273
8.61k
        for( uint16_t i = 0; i < i_num; i++ )
274
7.95k
        {
275
7.95k
            size_t i_index = (size_t) p_sys->i_sub_packet_h * i +
276
7.95k
                          ((p_sys->i_sub_packet_h + 1) / 2) * (y&1) + (y>>1);
277
7.95k
            if( unlikely(i_index >= p_sys->p_subpackets.size()) )
278
17
                return;
279
280
7.93k
            if( size < p_sys->i_subpacket_size )
281
220
                return;
282
283
7.71k
            if (likely(p_sys->p_subpackets[i_index] == nullptr))
284
7.08k
            {
285
                // the index was not used
286
7.08k
                block_t *p_block = block_Alloc( p_sys->i_subpacket_size );
287
7.08k
                if( !p_block )
288
0
                    return;
289
290
7.08k
                memcpy( p_block->p_buffer, p_frame, p_sys->i_subpacket_size );
291
7.08k
                p_block->i_dts = VLC_TICK_INVALID;
292
7.08k
                p_block->i_pts = VLC_TICK_INVALID;
293
7.08k
                if( p_sys->i_subpacket == 0 )
294
126
                {
295
126
                    p_tk->i_last_dts =
296
126
                    p_block->i_pts = i_pts;
297
126
                }
298
7.08k
                p_sys->p_subpackets[i_index] = p_block;
299
7.08k
            }
300
301
7.71k
            p_frame += p_sys->i_subpacket_size;
302
7.71k
            size -=  p_sys->i_subpacket_size;
303
304
7.71k
            p_sys->i_subpacket++;
305
7.71k
        }
306
899
    }
307
0
    else
308
0
    {
309
        /*TODO*/
310
0
    }
311
662
    if( p_sys->i_subpacket == p_sys->p_subpackets.size() )
312
54
    {
313
2.23k
        for( size_t i = 0; i < p_sys->p_subpackets.size(); i++)
314
2.17k
        {
315
2.17k
            if (likely(p_sys->p_subpackets[i]))
316
2.16k
            {
317
2.16k
                send_Block( p_demux, p_tk, p_sys->p_subpackets[i], 1, 0 );
318
2.16k
                p_sys->p_subpackets[i] = NULL;
319
2.16k
            }
320
2.17k
        }
321
54
        p_sys->i_subpacket = 0;
322
54
    }
323
662
}
324
325
block_t *WEBVTT_Repack_Sample(block_t *p_block, bool b_webm,
326
                              const uint8_t *p_add, size_t i_add)
327
0
{
328
0
    struct webvtt_cueelements_s els;
329
0
    memset(&els, 0, sizeof(els));
330
0
    size_t newsize = 0;
331
0
    block_t *newblock = nullptr;
332
    /* Repack to ISOBMFF samples format */
333
0
    if( !b_webm ) /* S_TEXT/WEBVTT */
334
0
    {
335
        /* process addition fields */
336
0
        if( i_add )
337
0
        {
338
0
            const uint8_t *end = p_add + i_add;
339
0
            const uint8_t *iden =
340
0
                    reinterpret_cast<const uint8_t *>(std::memchr( p_add, '\n', i_add ));
341
0
            if( iden && ++iden != end )
342
0
            {
343
0
                els.sttg.p_data = p_add;
344
0
                els.sttg.i_data = &iden[-1] - p_add;
345
0
                const uint8_t *comm =
346
0
                        reinterpret_cast<const uint8_t *>(std::memchr( iden, '\n', end - iden ));
347
0
                els.iden.p_data = iden;
348
0
                if( comm )
349
0
                    els.iden.i_data = comm - iden;
350
0
                else
351
0
                    els.iden.i_data = end - iden;
352
0
            }
353
0
        }
354
        /* the payload being in the block */
355
0
        els.payl.p_data = p_block->p_buffer;
356
0
        els.payl.i_data = p_block->i_buffer;
357
0
    }
358
0
    else /* deprecated D_WEBVTT/ */
359
0
    {
360
0
        const uint8_t *start = p_block->p_buffer;
361
0
        const uint8_t *end = p_block->p_buffer + p_block->i_buffer;
362
0
        const uint8_t *sttg =
363
0
                reinterpret_cast<const uint8_t *>(std::memchr( start, '\n', p_block->i_buffer ));
364
0
        if( !sttg || ++sttg == end )
365
0
            goto error;
366
0
        const uint8_t *payl =
367
0
                reinterpret_cast<const uint8_t *>(std::memchr( sttg, '\n', end - sttg ));
368
0
        if( !payl || ++payl == end )
369
0
            goto error;
370
0
        els.iden.p_data = start;
371
0
        els.iden.i_data = &sttg[-1] - start;
372
0
        els.sttg.p_data = sttg;
373
0
        els.sttg.i_data = &payl[-1] - sttg;
374
0
        els.payl.p_data = payl;
375
0
        els.payl.i_data = end - payl;
376
0
    }
377
378
0
    newsize = WEBVTT_Pack_CueElementsGetNewSize( &els );
379
0
    newblock = block_Alloc( newsize );
380
0
    if( !newblock )
381
0
        goto error;
382
0
    WEBVTT_Pack_CueElements( &els, newblock->p_buffer );
383
0
    block_CopyProperties( newblock, p_block );
384
0
    block_Release( p_block );
385
0
    return newblock;
386
387
0
error:
388
0
    block_Release( p_block );
389
0
    return NULL;
390
0
}
391
392
int UpdatePCR( demux_t * p_demux )
393
44.2k
{
394
44.2k
    demux_sys_t *p_sys = (demux_sys_t *)p_demux->p_sys;
395
44.2k
    matroska_segment_c *p_segment = p_sys->GetCurrentVSegment()->CurrentSegment();
396
397
44.2k
    vlc_tick_t i_pcr = VLC_TICK_INVALID;
398
399
44.2k
    for( const auto & it : p_segment->tracks )
400
73.6k
    {
401
73.6k
        const auto &track = it.second;
402
403
73.6k
        if( track->i_last_dts == VLC_TICK_INVALID )
404
23.9k
            continue;
405
406
49.7k
        if( track->fmt.i_cat != VIDEO_ES && track->fmt.i_cat != AUDIO_ES )
407
489
            continue;
408
409
49.2k
        if( track->i_last_dts < i_pcr || i_pcr == VLC_TICK_INVALID )
410
44.0k
        {
411
44.0k
            i_pcr = track->i_last_dts;
412
44.0k
        }
413
49.2k
    }
414
415
44.2k
    if( i_pcr != VLC_TICK_INVALID && i_pcr > p_sys->i_pcr )
416
25.7k
    {
417
25.7k
        if( es_out_SetPCR( p_demux->out, i_pcr ) )
418
0
        {
419
0
            msg_Err( p_demux, "ES_OUT_SET_PCR failed, aborting." );
420
0
            return VLC_EGENERIC;
421
0
        }
422
423
25.7k
        p_sys->i_pcr = i_pcr;
424
25.7k
    }
425
426
44.2k
    return VLC_SUCCESS;
427
44.2k
}
428
429
void send_Block( demux_t * p_demux, mkv_track_t * p_tk, block_t * p_block, unsigned int i_number_frames, int64_t i_duration )
430
74.9k
{
431
74.9k
    demux_sys_t *p_sys = (demux_sys_t *)p_demux->p_sys;
432
74.9k
    matroska_segment_c *p_segment = p_sys->GetCurrentVSegment()->CurrentSegment();
433
434
74.9k
    if( p_tk->fmt.i_cat == AUDIO_ES && p_tk->i_chans_to_reorder )
435
0
    {
436
0
        aout_ChannelReorder( p_block->p_buffer, p_block->i_buffer,
437
0
                             p_tk->i_chans_to_reorder,
438
0
                             p_tk->pi_chan_table, p_tk->fmt.i_codec );
439
0
    }
440
441
74.9k
    if( p_block->i_dts != VLC_TICK_INVALID &&
442
44.1k
        ( p_tk->fmt.i_cat == VIDEO_ES || p_tk->fmt.i_cat == AUDIO_ES ) )
443
43.1k
    {
444
43.1k
        p_tk->i_last_dts = p_block->i_dts;
445
43.1k
    }
446
447
74.9k
    if( !p_tk->b_no_duration )
448
73.4k
    {
449
73.4k
        p_block->i_length = VLC_TICK_FROM_NS(i_duration * p_tk->f_timecodescale *
450
73.4k
                                             p_segment->i_timescale) / i_number_frames;
451
73.4k
    }
452
453
74.9k
    if( p_tk->b_discontinuity )
454
81
    {
455
81
        p_block->i_flags |= BLOCK_FLAG_DISCONTINUITY;
456
81
        p_tk->b_discontinuity = false;
457
81
    }
458
459
74.9k
    if ( p_sys->i_pcr == VLC_TICK_INVALID )
460
3.17k
        UpdatePCR( p_demux );
461
462
74.9k
    es_out_Send( p_demux->out, p_tk->p_es, p_block);
463
74.9k
}
464
465
struct real_audio_private
466
{
467
    uint32_t fourcc;
468
    uint16_t version;
469
    uint16_t unknown1;
470
    uint8_t  unknown2[12];
471
    uint16_t unknown3;
472
    uint16_t flavor;
473
    uint32_t coded_frame_size;
474
    uint32_t unknown4[3];
475
    uint16_t sub_packet_h;
476
    uint16_t frame_size;
477
    uint16_t sub_packet_size;
478
    uint16_t unknown5;
479
};
480
481
struct real_audio_private_v4
482
{
483
    real_audio_private header;
484
    uint16_t sample_rate;
485
    uint16_t unknown;
486
    uint16_t sample_size;
487
    uint16_t channels;
488
};
489
490
491
struct real_audio_private_v5
492
{
493
    real_audio_private header;
494
    uint32_t unknown1;
495
    uint16_t unknown2;
496
    uint16_t sample_rate;
497
    uint16_t unknown3;
498
    uint16_t sample_size;
499
    uint16_t channels;
500
};
501
502
bool Cook_PrivateTrackData::Init()
503
210
{
504
    // real_audio_private
505
210
    bytes.skip(4);                      // fourcc
506
507
    /* FIXME RALF and SIPR */
508
210
    uint16_t version = bytes.GetBE16(); // version
509
210
    bytes.skip(2);                      // unknown1
510
210
    bytes.skip(12);                     // unknown2
511
210
    bytes.skip(2);                      // unknown3
512
210
    bytes.skip(2);                      // flavor
513
210
    coded_frame_size = bytes.GetBE32(); // coded_frame_size
514
210
    bytes.skip(3*4);                    // unknown4
515
210
    i_sub_packet_h   = bytes.GetBE16(); // sub_packet_h
516
210
    i_frame_size     = bytes.GetBE16(); // frame_size
517
210
    i_subpacket_size = bytes.GetBE16(); // sub_packet_size
518
210
    bytes.skip(2);                      // unknown5
519
520
210
    if ( i_subpacket_size == 0 )
521
8
        return false;
522
523
202
    if( version == 4 )
524
9
    {
525
        // real_audio_private_v4
526
9
        i_rate          = bytes.GetBE16(); // sample_rate
527
9
        bytes.skip(2);                     // unknown
528
9
        i_bitspersample = bytes.GetBE16(); // sample_size
529
9
        i_channels      = bytes.GetBE16(); // channels
530
9
    }
531
193
    else if( version == 5 )
532
191
    {
533
        // real_audio_private_v5
534
191
        bytes.skip(4);                     // unknown1
535
191
        bytes.skip(2);                     // unknown2
536
191
        i_rate          = bytes.GetBE16(); // sample_rate
537
191
        bytes.skip(2);                     // unknown2
538
191
        i_bitspersample = bytes.GetBE16(); // sample_size
539
191
        i_channels      = bytes.GetBE16(); // channels
540
191
    }
541
2
    else
542
2
        return false;
543
200
    if (bytes.hasErrors())
544
28
        return false;
545
546
172
    size_t i_subpackets = (size_t) i_sub_packet_h * (size_t) i_frame_size / (size_t) i_subpacket_size;
547
172
    p_subpackets.resize(i_subpackets);
548
549
172
    return true;
550
200
}
551
552
Cook_PrivateTrackData::~Cook_PrivateTrackData()
553
210
{
554
4.30M
    for( size_t i = 0; i < p_subpackets.size(); i++ )
555
4.30M
        if( p_subpackets[i] )
556
4.82k
            block_Release( p_subpackets[i] );
557
210
}
558
559
static inline void fill_wvpk_block(uint16_t version, uint32_t block_samples, uint32_t flags,
560
                                   uint32_t crc, uint8_t * src, size_t srclen, uint8_t * dst)
561
83
{
562
83
    const uint8_t wvpk_header[] = {'w','v','p','k',         /* ckId */
563
83
                                    0x0, 0x0, 0x0, 0x0,     /* ckSize */
564
83
                                    0x0, 0x0,               /* version */
565
83
                                    0x0,                    /* track_no */
566
83
                                    0x0,                    /* index_no */
567
83
                                    0xFF, 0xFF, 0xFF, 0xFF, /* total_samples */
568
83
                                    0x0, 0x0, 0x0, 0x0 };   /* block_index */
569
83
    memcpy( dst, wvpk_header, sizeof( wvpk_header ) );
570
83
    SetDWLE( dst + 4, srclen + 24 );
571
83
    SetWLE( dst + 8, version );
572
83
    SetDWLE( dst + 20, block_samples );
573
83
    SetDWLE( dst + 24, flags );
574
83
    SetDWLE( dst + 28, crc );
575
83
    memcpy( dst + 32, src, srclen );
576
83
}
577
578
block_t * packetize_wavpack( const mkv_track_t & tk, uint8_t * buffer, size_t  size)
579
83
{
580
83
    uint16_t version = 0x403;
581
83
    uint32_t block_samples;
582
83
    uint32_t flags;
583
83
    uint32_t crc;
584
83
    block_t * p_block = NULL;
585
586
83
    if( tk.i_extra_data >= 2 )
587
83
        version = GetWLE( tk.p_extra_data );
588
589
83
    if( size < 12 )
590
1
        return NULL;
591
592
82
    block_samples = GetDWLE(buffer);
593
82
    buffer += 4;
594
82
    flags = GetDWLE(buffer);
595
82
    size -= 4;
596
597
    /* Check if WV_INITIAL_BLOCK and WV_FINAL_BLOCK are present */
598
82
    if( ( flags & 0x1800 ) == 0x1800 )
599
39
    {
600
39
        crc = GetDWLE(buffer+4);
601
39
        buffer += 8;
602
39
        size -= 8;
603
604
39
        p_block = block_Alloc( size + 32 );
605
39
        if( !p_block )
606
0
            return NULL;
607
608
39
        fill_wvpk_block(version, block_samples, flags, crc, buffer, size, p_block->p_buffer);
609
39
    }
610
43
    else
611
43
    {
612
        /* Multiblock */
613
43
        size_t total_size = 0;
614
615
43
        p_block = block_Alloc( 0 );
616
43
        if( !p_block )
617
0
            return NULL;
618
619
87
        while(size >= 12)
620
44
        {
621
44
            flags = GetDWLE(buffer);
622
44
            buffer += 4;
623
44
            crc = GetDWLE(buffer);
624
44
            buffer += 4;
625
44
            uint32_t bsz = GetDWLE(buffer);
626
44
            buffer+= 4;
627
44
            size -= 12;
628
629
44
            bsz = (bsz < size)?bsz:size;
630
631
44
            total_size += bsz + 32;
632
633
44
            assert(total_size >= p_block->i_buffer);
634
635
44
            p_block = block_Realloc( p_block, 0, total_size );
636
637
44
            if( !p_block )
638
0
                return NULL;
639
640
44
            fill_wvpk_block(version, block_samples, flags, crc, buffer, bsz,
641
44
                            p_block->p_buffer + total_size - bsz - 32 );
642
44
            buffer += bsz;
643
44
            size -= bsz;
644
44
        }
645
43
    }
646
647
82
    return p_block;
648
82
}
649
650
void MkvTree_va( demux_t& demuxer, int i_level, const char* fmt, va_list args)
651
254k
{
652
254k
    static const char indent[] = "|   ";
653
254k
    static const char prefix[] = "+ ";
654
254k
    static int  const   indent_len = sizeof( indent ) - 1;
655
254k
    static int  const   prefix_len = sizeof( prefix ) - 1;
656
657
254k
    char   fixed_buffer[256] = {};
658
254k
    size_t const  static_len = sizeof( fixed_buffer );
659
254k
    char *            buffer = fixed_buffer;
660
254k
    size_t         total_len = indent_len * i_level + prefix_len + strlen( fmt ) + 1;
661
662
254k
    if( total_len >= static_len ) {
663
0
        buffer = new (std::nothrow) char[total_len] ();
664
665
0
        if (buffer == NULL) {
666
0
            msg_Err (&demuxer, "Unable to allocate memory for format string");
667
0
            return;
668
0
        }
669
0
    }
670
671
254k
    char * dst = buffer;
672
673
1.02M
    for (int i = 0; i < i_level; ++i, dst += indent_len)
674
772k
        memcpy( dst, indent, indent_len );
675
676
254k
    strcat( dst, prefix );
677
254k
    strcat( dst, fmt );
678
679
254k
    msg_GenericVa( &demuxer, VLC_MSG_DBG, buffer, args );
680
681
254k
    if (buffer != fixed_buffer)
682
0
        delete [] buffer;
683
254k
}
684
685
void MkvTree( demux_t & demuxer, int i_level, const char *psz_format, ... )
686
63.8k
{
687
63.8k
    va_list args; va_start( args, psz_format );
688
63.8k
    MkvTree_va( demuxer, i_level, psz_format, args );
689
    va_end( args );
690
63.8k
}
691
692
} // namespace