Coverage Report

Created: 2026-02-26 08:10

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
24.1k
block_t *block_lzo1x_decompress( vlc_object_t *p_this, block_t *p_in_block ) {
197
24.1k
    lzokay::EResult result;
198
24.1k
    size_t dstsize = 0, n;
199
24.1k
    block_t *p_block;
200
201
24.1k
    n = 0;
202
24.1k
    p_block = block_Alloc( 0 );
203
24.1k
    do
204
27.3k
    {
205
27.3k
        n++;
206
27.3k
        p_block = block_Realloc( p_block, 0, n * 1000 );
207
27.3k
        result = lzokay::decompress( p_in_block->p_buffer, p_in_block->i_buffer,
208
27.3k
                                     p_block->p_buffer, p_block->i_buffer, dstsize );
209
27.3k
    }
210
27.3k
    while( result == lzokay::EResult::OutputOverrun );
211
212
24.1k
    if( result != lzokay::EResult::Success )
213
22.6k
    {
214
22.6k
        msg_Err( p_this, "LZO1X decompression failed. Result: %d", (int)result );
215
22.6k
        block_Release( p_block );
216
22.6k
        return p_in_block;
217
22.6k
    }
218
219
1.41k
    p_block = block_Realloc( p_block, 0, dstsize );
220
1.41k
    p_block->i_buffer = dstsize;
221
1.41k
    block_Release( p_in_block );
222
223
1.41k
    return p_block;
224
24.1k
}
225
226
/* Utility function for BlockDecode */
227
block_t *MemToBlock( uint8_t *p_mem, size_t i_mem, size_t offset)
228
74.4k
{
229
74.4k
    if( unlikely( i_mem > SIZE_MAX - offset ) )
230
0
        return NULL;
231
232
74.4k
    block_t *p_block = block_Alloc( i_mem + offset );
233
74.4k
    if( likely(p_block != NULL) )
234
74.4k
    {
235
74.4k
        memcpy( p_block->p_buffer + offset, p_mem, i_mem );
236
74.4k
    }
237
74.4k
    return p_block;
238
74.4k
}
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
2.57k
{
243
2.57k
    uint8_t * p_frame = p_blk->p_buffer;
244
2.57k
    Cook_PrivateTrackData * p_sys = static_cast<Cook_PrivateTrackData *>(p_tk->p_sys);
245
2.57k
    size_t size = p_blk->i_buffer;
246
247
2.57k
    if( p_tk->i_last_dts == VLC_TICK_INVALID )
248
1.78k
    {
249
304M
        for( size_t i = 0; i < p_sys->p_subpackets.size(); i++)
250
304M
            if( p_sys->p_subpackets[i] )
251
49
            {
252
49
                block_Release(p_sys->p_subpackets[i]);
253
49
                p_sys->p_subpackets[i] = NULL;
254
49
            }
255
1.78k
        p_sys->i_subpacket = 0;
256
257
1.78k
        if ( !( p_blk->i_flags & BLOCK_FLAG_TYPE_I) )
258
187
        {
259
187
            msg_Dbg( p_demux, "discard non-key preroll block in track %u at %" PRId64,
260
187
                     p_tk->i_number, i_pts );
261
187
            return;
262
187
        }
263
1.78k
    }
264
265
2.38k
    if( p_tk->fmt.i_codec == VLC_CODEC_COOK ||
266
0
        p_tk->fmt.i_codec == VLC_CODEC_ATRAC3 )
267
2.38k
    {
268
2.38k
        const uint16_t i_num = p_sys->i_frame_size / p_sys->i_subpacket_size;
269
2.38k
        if ( i_num == 0 )
270
558
            return;
271
1.82k
        const size_t y = p_sys->i_subpacket / i_num;
272
273
7.70k
        for( uint16_t i = 0; i < i_num; i++ )
274
7.10k
        {
275
7.10k
            size_t i_index = (size_t) p_sys->i_sub_packet_h * i +
276
7.10k
                          ((p_sys->i_sub_packet_h + 1) / 2) * (y&1) + (y>>1);
277
7.10k
            if( unlikely(i_index >= p_sys->p_subpackets.size()) )
278
150
                return;
279
280
6.95k
            if( size < p_sys->i_subpacket_size )
281
1.07k
                return;
282
283
5.87k
            if (likely(p_sys->p_subpackets[i_index] == nullptr))
284
4.61k
            {
285
                // the index was not used
286
4.61k
                block_t *p_block = block_Alloc( p_sys->i_subpacket_size );
287
4.61k
                if( !p_block )
288
0
                    return;
289
290
4.61k
                memcpy( p_block->p_buffer, p_frame, p_sys->i_subpacket_size );
291
4.61k
                p_block->i_dts = VLC_TICK_INVALID;
292
4.61k
                p_block->i_pts = VLC_TICK_INVALID;
293
4.61k
                if( p_sys->i_subpacket == 0 )
294
118
                {
295
118
                    p_tk->i_last_dts =
296
118
                    p_block->i_pts = i_pts;
297
118
                }
298
4.61k
                p_sys->p_subpackets[i_index] = p_block;
299
4.61k
            }
300
301
5.87k
            p_frame += p_sys->i_subpacket_size;
302
5.87k
            size -=  p_sys->i_subpacket_size;
303
304
5.87k
            p_sys->i_subpacket++;
305
5.87k
        }
306
1.82k
    }
307
0
    else
308
0
    {
309
        /*TODO*/
310
0
    }
311
598
    if( p_sys->i_subpacket == p_sys->p_subpackets.size() )
312
48
    {
313
1.24k
        for( size_t i = 0; i < p_sys->p_subpackets.size(); i++)
314
1.19k
        {
315
1.19k
            if (likely(p_sys->p_subpackets[i]))
316
1.16k
            {
317
1.16k
                send_Block( p_demux, p_tk, p_sys->p_subpackets[i], 1, 0 );
318
1.16k
                p_sys->p_subpackets[i] = NULL;
319
1.16k
            }
320
1.19k
        }
321
48
        p_sys->i_subpacket = 0;
322
48
    }
323
598
}
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
34.3k
{
394
34.3k
    demux_sys_t *p_sys = (demux_sys_t *)p_demux->p_sys;
395
34.3k
    matroska_segment_c *p_segment = p_sys->GetCurrentVSegment()->CurrentSegment();
396
397
34.3k
    vlc_tick_t i_pcr = VLC_TICK_INVALID;
398
399
34.3k
    for( const auto & it : p_segment->tracks )
400
67.3k
    {
401
67.3k
        const auto &track = it.second;
402
403
67.3k
        if( track->i_last_dts == VLC_TICK_INVALID )
404
28.9k
            continue;
405
406
38.3k
        if( track->fmt.i_cat != VIDEO_ES && track->fmt.i_cat != AUDIO_ES )
407
469
            continue;
408
409
37.9k
        if( track->i_last_dts < i_pcr || i_pcr == VLC_TICK_INVALID )
410
30.4k
        {
411
30.4k
            i_pcr = track->i_last_dts;
412
30.4k
        }
413
37.9k
    }
414
415
34.3k
    if( i_pcr != VLC_TICK_INVALID && i_pcr > p_sys->i_pcr )
416
14.5k
    {
417
14.5k
        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
14.5k
        p_sys->i_pcr = i_pcr;
424
14.5k
    }
425
426
34.3k
    return VLC_SUCCESS;
427
34.3k
}
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
73.5k
{
431
73.5k
    demux_sys_t *p_sys = (demux_sys_t *)p_demux->p_sys;
432
73.5k
    matroska_segment_c *p_segment = p_sys->GetCurrentVSegment()->CurrentSegment();
433
434
73.5k
    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
73.5k
    if( p_block->i_dts != VLC_TICK_INVALID &&
442
48.6k
        ( p_tk->fmt.i_cat == VIDEO_ES || p_tk->fmt.i_cat == AUDIO_ES ) )
443
47.1k
    {
444
47.1k
        p_tk->i_last_dts = p_block->i_dts;
445
47.1k
    }
446
447
73.5k
    if( !p_tk->b_no_duration )
448
72.2k
    {
449
72.2k
        p_block->i_length = VLC_TICK_FROM_NS(i_duration * p_tk->f_timecodescale *
450
72.2k
                                             p_segment->i_timescale) / i_number_frames;
451
72.2k
    }
452
453
73.5k
    if( p_tk->b_discontinuity )
454
230
    {
455
230
        p_block->i_flags |= BLOCK_FLAG_DISCONTINUITY;
456
230
        p_tk->b_discontinuity = false;
457
230
    }
458
459
73.5k
    if ( p_sys->i_pcr == VLC_TICK_INVALID )
460
3.38k
        UpdatePCR( p_demux );
461
462
73.5k
    es_out_Send( p_demux->out, p_tk->p_es, p_block);
463
73.5k
}
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
183
{
504
    // real_audio_private
505
183
    bytes.skip(4);                      // fourcc
506
507
    /* FIXME RALF and SIPR */
508
183
    uint16_t version = bytes.GetBE16(); // version
509
183
    bytes.skip(2);                      // unknown1
510
183
    bytes.skip(12);                     // unknown2
511
183
    bytes.skip(2);                      // unknown3
512
183
    bytes.skip(2);                      // flavor
513
183
    coded_frame_size = bytes.GetBE32(); // coded_frame_size
514
183
    bytes.skip(3*4);                    // unknown4
515
183
    i_sub_packet_h   = bytes.GetBE16(); // sub_packet_h
516
183
    i_frame_size     = bytes.GetBE16(); // frame_size
517
183
    i_subpacket_size = bytes.GetBE16(); // sub_packet_size
518
183
    bytes.skip(2);                      // unknown5
519
520
183
    if ( i_subpacket_size == 0 )
521
5
        return false;
522
523
178
    if( version == 4 )
524
6
    {
525
        // real_audio_private_v4
526
6
        i_rate          = bytes.GetBE16(); // sample_rate
527
6
        bytes.skip(2);                     // unknown
528
6
        i_bitspersample = bytes.GetBE16(); // sample_size
529
6
        i_channels      = bytes.GetBE16(); // channels
530
6
    }
531
172
    else if( version == 5 )
532
167
    {
533
        // real_audio_private_v5
534
167
        bytes.skip(4);                     // unknown1
535
167
        bytes.skip(2);                     // unknown2
536
167
        i_rate          = bytes.GetBE16(); // sample_rate
537
167
        bytes.skip(2);                     // unknown2
538
167
        i_bitspersample = bytes.GetBE16(); // sample_size
539
167
        i_channels      = bytes.GetBE16(); // channels
540
167
    }
541
5
    else
542
5
        return false;
543
173
    if (bytes.hasErrors())
544
19
        return false;
545
546
154
    size_t i_subpackets = (size_t) i_sub_packet_h * (size_t) i_frame_size / (size_t) i_subpacket_size;
547
154
    p_subpackets.resize(i_subpackets);
548
549
154
    return true;
550
173
}
551
552
Cook_PrivateTrackData::~Cook_PrivateTrackData()
553
183
{
554
256M
    for( size_t i = 0; i < p_subpackets.size(); i++ )
555
256M
        if( p_subpackets[i] )
556
3.39k
            block_Release( p_subpackets[i] );
557
183
}
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
857
{
562
857
    const uint8_t wvpk_header[] = {'w','v','p','k',         /* ckId */
563
857
                                    0x0, 0x0, 0x0, 0x0,     /* ckSize */
564
857
                                    0x0, 0x0,               /* version */
565
857
                                    0x0,                    /* track_no */
566
857
                                    0x0,                    /* index_no */
567
857
                                    0xFF, 0xFF, 0xFF, 0xFF, /* total_samples */
568
857
                                    0x0, 0x0, 0x0, 0x0 };   /* block_index */
569
857
    memcpy( dst, wvpk_header, sizeof( wvpk_header ) );
570
857
    SetDWLE( dst + 4, srclen + 24 );
571
857
    SetWLE( dst + 8, version );
572
857
    SetDWLE( dst + 20, block_samples );
573
857
    SetDWLE( dst + 24, flags );
574
857
    SetDWLE( dst + 28, crc );
575
857
    memcpy( dst + 32, src, srclen );
576
857
}
577
578
block_t * packetize_wavpack( const mkv_track_t & tk, uint8_t * buffer, size_t  size)
579
522
{
580
522
    uint16_t version = 0x403;
581
522
    uint32_t block_samples;
582
522
    uint32_t flags;
583
522
    uint32_t crc;
584
522
    block_t * p_block = NULL;
585
586
522
    if( tk.i_extra_data >= 2 )
587
522
        version = GetWLE( tk.p_extra_data );
588
589
522
    if( size < 12 )
590
6
        return NULL;
591
592
516
    block_samples = GetDWLE(buffer);
593
516
    buffer += 4;
594
516
    flags = GetDWLE(buffer);
595
516
    size -= 4;
596
597
    /* Check if WV_INITIAL_BLOCK and WV_FINAL_BLOCK are present */
598
516
    if( ( flags & 0x1800 ) == 0x1800 )
599
117
    {
600
117
        crc = GetDWLE(buffer+4);
601
117
        buffer += 8;
602
117
        size -= 8;
603
604
117
        p_block = block_Alloc( size + 32 );
605
117
        if( !p_block )
606
0
            return NULL;
607
608
117
        fill_wvpk_block(version, block_samples, flags, crc, buffer, size, p_block->p_buffer);
609
117
    }
610
399
    else
611
399
    {
612
        /* Multiblock */
613
399
        size_t total_size = 0;
614
615
399
        p_block = block_Alloc( 0 );
616
399
        if( !p_block )
617
0
            return NULL;
618
619
1.13k
        while(size >= 12)
620
740
        {
621
740
            flags = GetDWLE(buffer);
622
740
            buffer += 4;
623
740
            crc = GetDWLE(buffer);
624
740
            buffer += 4;
625
740
            uint32_t bsz = GetDWLE(buffer);
626
740
            buffer+= 4;
627
740
            size -= 12;
628
629
740
            bsz = (bsz < size)?bsz:size;
630
631
740
            total_size += bsz + 32;
632
633
740
            assert(total_size >= p_block->i_buffer);
634
635
740
            p_block = block_Realloc( p_block, 0, total_size );
636
637
740
            if( !p_block )
638
0
                return NULL;
639
640
740
            fill_wvpk_block(version, block_samples, flags, crc, buffer, bsz,
641
740
                            p_block->p_buffer + total_size - bsz - 32 );
642
740
            buffer += bsz;
643
740
            size -= bsz;
644
740
        }
645
399
    }
646
647
516
    return p_block;
648
516
}
649
650
void MkvTree_va( demux_t& demuxer, int i_level, const char* fmt, va_list args)
651
419k
{
652
419k
    static const char indent[] = "|   ";
653
419k
    static const char prefix[] = "+ ";
654
419k
    static int  const   indent_len = sizeof( indent ) - 1;
655
419k
    static int  const   prefix_len = sizeof( prefix ) - 1;
656
657
419k
    char   fixed_buffer[256] = {};
658
419k
    size_t const  static_len = sizeof( fixed_buffer );
659
419k
    char *            buffer = fixed_buffer;
660
419k
    size_t         total_len = indent_len * i_level + prefix_len + strlen( fmt ) + 1;
661
662
419k
    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
419k
    char * dst = buffer;
672
673
1.79M
    for (int i = 0; i < i_level; ++i, dst += indent_len)
674
1.37M
        memcpy( dst, indent, indent_len );
675
676
419k
    strcat( dst, prefix );
677
419k
    strcat( dst, fmt );
678
679
419k
    msg_GenericVa( &demuxer, VLC_MSG_DBG, buffer, args );
680
681
419k
    if (buffer != fixed_buffer)
682
0
        delete [] buffer;
683
419k
}
684
685
void MkvTree( demux_t & demuxer, int i_level, const char *psz_format, ... )
686
69.7k
{
687
69.7k
    va_list args; va_start( args, psz_format );
688
69.7k
    MkvTree_va( demuxer, i_level, psz_format, args );
689
    va_end( args );
690
69.7k
}
691
692
} // namespace