Coverage Report

Created: 2026-10-17 07:46

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
0
{
40
0
    int result;
41
0
    z_stream d_stream;
42
0
    size_t n = 0;
43
0
    uint8_t * p_new_extra = NULL;
44
45
0
    msg_Dbg(p_demux,"Inflating private data");
46
47
0
    d_stream.zalloc = Z_NULL;
48
0
    d_stream.zfree = Z_NULL;
49
0
    d_stream.opaque = Z_NULL;
50
0
    if( inflateInit( &d_stream ) != Z_OK )
51
0
    {
52
0
        msg_Err( p_demux, "Couldn't initiate inflation ignore track %u",
53
0
                 tk.i_number );
54
0
        return 1;
55
0
    }
56
57
0
    d_stream.next_in = tk.p_extra_data;
58
0
    d_stream.avail_in = tk.i_extra_data;
59
0
    do
60
0
    {
61
0
        n++;
62
0
        void *alloc = realloc(p_new_extra, n*1024);
63
0
        if( alloc == NULL )
64
0
        {
65
0
            msg_Err( p_demux, "Couldn't allocate buffer to inflate data, ignore track %u",
66
0
                      tk.i_number );
67
0
            free(p_new_extra);
68
0
            inflateEnd( &d_stream );
69
0
            return 1;
70
0
        }
71
72
0
        p_new_extra = static_cast<uint8_t *>( alloc );
73
0
        d_stream.next_out = &p_new_extra[(n - 1) * 1024];
74
0
        d_stream.avail_out = 1024;
75
0
        result = inflate(&d_stream, Z_NO_FLUSH);
76
0
        if( result != Z_OK && result != Z_STREAM_END )
77
0
        {
78
0
            msg_Err( p_demux, "Zlib decompression failed. Result: %d", result );
79
0
            inflateEnd( &d_stream );
80
0
            free(p_new_extra);
81
0
            return 1;
82
0
        }
83
0
    }
84
0
    while ( d_stream.avail_out == 0 && d_stream.avail_in != 0  &&
85
0
            result != Z_STREAM_END );
86
87
0
    free( tk.p_extra_data );
88
0
    tk.i_extra_data = d_stream.total_out;
89
0
    p_new_extra = static_cast<uint8_t *>( realloc(p_new_extra, tk.i_extra_data) );
90
0
    if( !p_new_extra )
91
0
    {
92
0
        msg_Err( p_demux, "Couldn't allocate buffer to inflate data, ignore track %u",
93
0
                 tk.i_number );
94
0
        inflateEnd( &d_stream );
95
0
        tk.p_extra_data = NULL;
96
0
        return 1;
97
0
    }
98
99
0
    tk.p_extra_data = p_new_extra;
100
101
0
    inflateEnd( &d_stream );
102
0
    return 0;
103
0
}
104
105
441
block_t *block_zlib_decompress( vlc_object_t *p_this, block_t *p_in_block ) {
106
441
    int result, dstsize, n;
107
441
    unsigned char *dst;
108
441
    block_t *p_block;
109
441
    z_stream d_stream;
110
111
441
    d_stream.zalloc = NULL;
112
441
    d_stream.zfree = NULL;
113
441
    d_stream.opaque = NULL;
114
441
    result = inflateInit(&d_stream);
115
441
    if( result != Z_OK )
116
0
    {
117
0
        msg_Dbg( p_this, "inflateInit() failed. Result: %d", result );
118
0
        return NULL;
119
0
    }
120
121
441
    d_stream.next_in = (Bytef *)p_in_block->p_buffer;
122
441
    d_stream.avail_in = p_in_block->i_buffer;
123
441
    n = 0;
124
441
    p_block = block_Alloc( 0 );
125
441
    dst = NULL;
126
441
    do
127
441
    {
128
441
        n++;
129
441
        p_block = block_Realloc( p_block, 0, n * 1000 );
130
441
        dst = static_cast<unsigned char *>( p_block->p_buffer );
131
441
        d_stream.next_out = (Bytef *)&dst[(n - 1) * 1000];
132
441
        d_stream.avail_out = 1000;
133
441
        result = inflate(&d_stream, Z_NO_FLUSH);
134
441
        if( ( result != Z_OK ) && ( result != Z_STREAM_END ) )
135
439
        {
136
439
            msg_Err( p_this, "Zlib decompression failed. Result: %d", result );
137
439
            inflateEnd( &d_stream );
138
439
            block_Release( p_block );
139
439
            return p_in_block;
140
439
        }
141
441
    }
142
441
    while( ( d_stream.avail_out == 0 ) && ( d_stream.avail_in != 0 ) &&
143
0
           ( result != Z_STREAM_END ) );
144
145
2
    dstsize = d_stream.total_out;
146
2
    inflateEnd( &d_stream );
147
148
2
    p_block = block_Realloc( p_block, 0, dstsize );
149
2
    p_block->i_buffer = dstsize;
150
2
    block_Release( p_in_block );
151
152
2
    return p_block;
153
441
}
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
1.71k
block_t *block_lzo1x_decompress( vlc_object_t *p_this, block_t *p_in_block ) {
197
1.71k
    lzokay::EResult result;
198
1.71k
    size_t dstsize = 0, n;
199
1.71k
    block_t *p_block;
200
201
1.71k
    n = 0;
202
1.71k
    p_block = block_Alloc( 0 );
203
1.71k
    do
204
3.87k
    {
205
3.87k
        n++;
206
3.87k
        p_block = block_Realloc( p_block, 0, n * 1000 );
207
3.87k
        result = lzokay::decompress( p_in_block->p_buffer, p_in_block->i_buffer,
208
3.87k
                                     p_block->p_buffer, p_block->i_buffer, dstsize );
209
3.87k
    }
210
3.87k
    while( result == lzokay::EResult::OutputOverrun );
211
212
1.71k
    if( result != lzokay::EResult::Success )
213
767
    {
214
767
        msg_Err( p_this, "LZO1X decompression failed. Result: %d", (int)result );
215
767
        block_Release( p_block );
216
767
        return p_in_block;
217
767
    }
218
219
949
    p_block = block_Realloc( p_block, 0, dstsize );
220
949
    p_block->i_buffer = dstsize;
221
949
    block_Release( p_in_block );
222
223
949
    return p_block;
224
1.71k
}
225
226
/* Utility function for BlockDecode */
227
block_t *MemToBlock( uint8_t *p_mem, size_t i_mem, size_t offset)
228
678k
{
229
678k
    if( unlikely( i_mem > SIZE_MAX - offset ) )
230
0
        return NULL;
231
232
678k
    block_t *p_block = block_Alloc( i_mem + offset );
233
678k
    if( likely(p_block != NULL) )
234
678k
    {
235
678k
        memcpy( p_block->p_buffer + offset, p_mem, i_mem );
236
678k
    }
237
678k
    return p_block;
238
678k
}
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
341
{
243
341
    uint8_t * p_frame = p_blk->p_buffer;
244
341
    Cook_PrivateTrackData * p_sys = static_cast<Cook_PrivateTrackData *>(p_tk->p_sys);
245
341
    size_t size = p_blk->i_buffer;
246
247
341
    if( p_tk->i_last_dts == VLC_TICK_INVALID )
248
8
    {
249
648
        for( size_t i = 0; i < p_sys->p_subpackets.size(); i++)
250
640
            if( p_sys->p_subpackets[i] )
251
0
            {
252
0
                block_Release(p_sys->p_subpackets[i]);
253
0
                p_sys->p_subpackets[i] = NULL;
254
0
            }
255
8
        p_sys->i_subpacket = 0;
256
257
8
        if ( !( p_blk->i_flags & BLOCK_FLAG_TYPE_I) )
258
0
        {
259
0
            msg_Dbg( p_demux, "discard non-key preroll block in track %u at %" PRId64,
260
0
                     p_tk->i_number, i_pts );
261
0
            return;
262
0
        }
263
8
    }
264
265
341
    if( p_tk->fmt.i_codec == VLC_CODEC_COOK ||
266
0
        p_tk->fmt.i_codec == VLC_CODEC_ATRAC3 )
267
341
    {
268
341
        const uint16_t i_num = p_sys->i_frame_size / p_sys->i_subpacket_size;
269
341
        if ( i_num == 0 )
270
0
            return;
271
341
        const size_t y = p_sys->i_subpacket / i_num;
272
273
2.01k
        for( uint16_t i = 0; i < i_num; i++ )
274
1.68k
        {
275
1.68k
            size_t i_index = (size_t) p_sys->i_sub_packet_h * i +
276
1.68k
                          ((p_sys->i_sub_packet_h + 1) / 2) * (y&1) + (y>>1);
277
1.68k
            if( unlikely(i_index >= p_sys->p_subpackets.size()) )
278
0
                return;
279
280
1.68k
            if( size < p_sys->i_subpacket_size )
281
8
                return;
282
283
1.67k
            if (likely(p_sys->p_subpackets[i_index] == nullptr))
284
1.66k
            {
285
                // the index was not used
286
1.66k
                block_t *p_block = block_Alloc( p_sys->i_subpacket_size );
287
1.66k
                if( !p_block )
288
0
                    return;
289
290
1.66k
                memcpy( p_block->p_buffer, p_frame, p_sys->i_subpacket_size );
291
1.66k
                p_block->i_dts = VLC_TICK_INVALID;
292
1.66k
                p_block->i_pts = VLC_TICK_INVALID;
293
1.66k
                if( p_sys->i_subpacket == 0 )
294
25
                {
295
25
                    p_tk->i_last_dts =
296
25
                    p_block->i_pts = i_pts;
297
25
                }
298
1.66k
                p_sys->p_subpackets[i_index] = p_block;
299
1.66k
            }
300
301
1.67k
            p_frame += p_sys->i_subpacket_size;
302
1.67k
            size -=  p_sys->i_subpacket_size;
303
304
1.67k
            p_sys->i_subpacket++;
305
1.67k
        }
306
341
    }
307
0
    else
308
0
    {
309
        /*TODO*/
310
0
    }
311
333
    if( p_sys->i_subpacket == p_sys->p_subpackets.size() )
312
17
    {
313
1.37k
        for( size_t i = 0; i < p_sys->p_subpackets.size(); i++)
314
1.36k
        {
315
1.36k
            if (likely(p_sys->p_subpackets[i]))
316
1.36k
            {
317
1.36k
                send_Block( p_demux, p_tk, p_sys->p_subpackets[i], 1, 0 );
318
1.36k
                p_sys->p_subpackets[i] = NULL;
319
1.36k
            }
320
1.36k
        }
321
17
        p_sys->i_subpacket = 0;
322
17
    }
323
333
}
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
78.4k
{
394
78.4k
    demux_sys_t *p_sys = (demux_sys_t *)p_demux->p_sys;
395
78.4k
    matroska_segment_c *p_segment = p_sys->GetCurrentVSegment()->CurrentSegment();
396
397
78.4k
    vlc_tick_t i_pcr = VLC_TICK_INVALID;
398
399
78.4k
    for( const auto & it : p_segment->tracks )
400
171k
    {
401
171k
        const auto &track = it.second;
402
403
171k
        if( track->i_last_dts == VLC_TICK_INVALID )
404
76.2k
            continue;
405
406
95.3k
        if( track->fmt.i_cat != VIDEO_ES && track->fmt.i_cat != AUDIO_ES )
407
24
            continue;
408
409
95.3k
        if( track->i_last_dts < i_pcr || i_pcr == VLC_TICK_INVALID )
410
69.5k
        {
411
69.5k
            i_pcr = track->i_last_dts;
412
69.5k
        }
413
95.3k
    }
414
415
78.4k
    if( i_pcr != VLC_TICK_INVALID && i_pcr > p_sys->i_pcr )
416
17.9k
    {
417
17.9k
        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
17.9k
        p_sys->i_pcr = i_pcr;
424
17.9k
    }
425
426
78.4k
    return VLC_SUCCESS;
427
78.4k
}
428
429
void send_Block( demux_t * p_demux, mkv_track_t * p_tk, block_t * p_block, unsigned int i_number_frames, uint64_t i_duration )
430
681k
{
431
681k
    demux_sys_t *p_sys = (demux_sys_t *)p_demux->p_sys;
432
681k
    matroska_segment_c *p_segment = p_sys->GetCurrentVSegment()->CurrentSegment();
433
434
681k
    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
681k
    if( p_block->i_dts != VLC_TICK_INVALID &&
442
547k
        ( p_tk->fmt.i_cat == VIDEO_ES || p_tk->fmt.i_cat == AUDIO_ES ) )
443
546k
    {
444
546k
        p_tk->i_last_dts = p_block->i_dts;
445
546k
    }
446
447
681k
    if( !p_tk->b_no_duration )
448
676k
    {
449
676k
        p_block->i_length = VLC_TICK_FROM_NS(i_duration * p_tk->f_timecodescale *
450
676k
                                             p_segment->i_timescale) / i_number_frames;
451
676k
    }
452
453
681k
    if( p_tk->b_discontinuity )
454
25
    {
455
25
        p_block->i_flags |= BLOCK_FLAG_DISCONTINUITY;
456
25
        p_tk->b_discontinuity = false;
457
25
    }
458
459
681k
    if ( p_sys->i_pcr == VLC_TICK_INVALID )
460
11.7k
        UpdatePCR( p_demux );
461
462
681k
    es_out_Send( p_demux->out, p_tk->p_es, p_block);
463
681k
}
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
8
{
504
    // real_audio_private
505
8
    bytes.skip(4);                      // fourcc
506
507
    /* FIXME RALF and SIPR */
508
8
    uint16_t version = bytes.GetBE16(); // version
509
8
    bytes.skip(2);                      // unknown1
510
8
    bytes.skip(12);                     // unknown2
511
8
    bytes.skip(2);                      // unknown3
512
8
    bytes.skip(2);                      // flavor
513
8
    coded_frame_size = bytes.GetBE32(); // coded_frame_size
514
8
    bytes.skip(3*4);                    // unknown4
515
8
    i_sub_packet_h   = bytes.GetBE16(); // sub_packet_h
516
8
    i_frame_size     = bytes.GetBE16(); // frame_size
517
8
    i_subpacket_size = bytes.GetBE16(); // sub_packet_size
518
8
    bytes.skip(2);                      // unknown5
519
520
8
    if ( i_subpacket_size == 0 )
521
0
        return false;
522
523
8
    if( version == 4 )
524
0
    {
525
        // real_audio_private_v4
526
0
        i_rate          = bytes.GetBE16(); // sample_rate
527
0
        bytes.skip(2);                     // unknown
528
0
        i_bitspersample = bytes.GetBE16(); // sample_size
529
0
        i_channels      = bytes.GetBE16(); // channels
530
0
    }
531
8
    else if( version == 5 )
532
8
    {
533
        // real_audio_private_v5
534
8
        bytes.skip(4);                     // unknown1
535
8
        bytes.skip(2);                     // unknown2
536
8
        i_rate          = bytes.GetBE16(); // sample_rate
537
8
        bytes.skip(2);                     // unknown2
538
8
        i_bitspersample = bytes.GetBE16(); // sample_size
539
8
        i_channels      = bytes.GetBE16(); // channels
540
8
    }
541
0
    else
542
0
        return false;
543
8
    if (bytes.hasErrors())
544
0
        return false;
545
546
8
    size_t i_subpackets = (size_t) i_sub_packet_h * (size_t) i_frame_size / (size_t) i_subpacket_size;
547
8
    p_subpackets.resize(i_subpackets);
548
549
8
    return true;
550
8
}
551
552
Cook_PrivateTrackData::~Cook_PrivateTrackData()
553
8
{
554
648
    for( size_t i = 0; i < p_subpackets.size(); i++ )
555
640
        if( p_subpackets[i] )
556
307
            block_Release( p_subpackets[i] );
557
8
}
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
1.49k
{
562
1.49k
    const uint8_t wvpk_header[] = {'w','v','p','k',         /* ckId */
563
1.49k
                                    0x0, 0x0, 0x0, 0x0,     /* ckSize */
564
1.49k
                                    0x0, 0x0,               /* version */
565
1.49k
                                    0x0,                    /* track_no */
566
1.49k
                                    0x0,                    /* index_no */
567
1.49k
                                    0xFF, 0xFF, 0xFF, 0xFF, /* total_samples */
568
1.49k
                                    0x0, 0x0, 0x0, 0x0 };   /* block_index */
569
1.49k
    memcpy( dst, wvpk_header, sizeof( wvpk_header ) );
570
1.49k
    SetDWLE( dst + 4, srclen + 24 );
571
1.49k
    SetWLE( dst + 8, version );
572
1.49k
    SetDWLE( dst + 20, block_samples );
573
1.49k
    SetDWLE( dst + 24, flags );
574
1.49k
    SetDWLE( dst + 28, crc );
575
1.49k
    memcpy( dst + 32, src, srclen );
576
1.49k
}
577
578
block_t * packetize_wavpack( const mkv_track_t & tk, uint8_t * buffer, size_t  size)
579
1.48k
{
580
1.48k
    uint16_t version = 0x403;
581
1.48k
    uint32_t block_samples;
582
1.48k
    uint32_t flags;
583
1.48k
    uint32_t crc;
584
1.48k
    block_t * p_block = NULL;
585
586
1.48k
    if( tk.i_extra_data >= 2 )
587
1.48k
        version = GetWLE( tk.p_extra_data );
588
589
1.48k
    if( size < 12 )
590
0
        return NULL;
591
592
1.48k
    block_samples = GetDWLE(buffer);
593
1.48k
    buffer += 4;
594
1.48k
    flags = GetDWLE(buffer);
595
1.48k
    size -= 4;
596
597
    /* Check if WV_INITIAL_BLOCK and WV_FINAL_BLOCK are present */
598
1.48k
    if( ( flags & 0x1800 ) == 0x1800 )
599
6
    {
600
6
        crc = GetDWLE(buffer+4);
601
6
        buffer += 8;
602
6
        size -= 8;
603
604
6
        p_block = block_Alloc( size + 32 );
605
6
        if( !p_block )
606
0
            return NULL;
607
608
6
        fill_wvpk_block(version, block_samples, flags, crc, buffer, size, p_block->p_buffer);
609
6
    }
610
1.48k
    else
611
1.48k
    {
612
        /* Multiblock */
613
1.48k
        size_t total_size = 0;
614
615
1.48k
        p_block = block_Alloc( 0 );
616
1.48k
        if( !p_block )
617
0
            return NULL;
618
619
2.97k
        while(size >= 12)
620
1.48k
        {
621
1.48k
            flags = GetDWLE(buffer);
622
1.48k
            buffer += 4;
623
1.48k
            crc = GetDWLE(buffer);
624
1.48k
            buffer += 4;
625
1.48k
            uint32_t bsz = GetDWLE(buffer);
626
1.48k
            buffer+= 4;
627
1.48k
            size -= 12;
628
629
1.48k
            bsz = (bsz < size)?bsz:size;
630
631
1.48k
            total_size += bsz + 32;
632
633
1.48k
            assert(total_size >= p_block->i_buffer);
634
635
1.48k
            p_block = block_Realloc( p_block, 0, total_size );
636
637
1.48k
            if( !p_block )
638
0
                return NULL;
639
640
1.48k
            fill_wvpk_block(version, block_samples, flags, crc, buffer, bsz,
641
1.48k
                            p_block->p_buffer + total_size - bsz - 32 );
642
1.48k
            buffer += bsz;
643
1.48k
            size -= bsz;
644
1.48k
        }
645
1.48k
    }
646
647
1.48k
    return p_block;
648
1.48k
}
649
650
void MkvTree_va( demux_t& demuxer, int i_level, const char* fmt, va_list args)
651
85.2k
{
652
85.2k
    static const char indent[] = "|   ";
653
85.2k
    static const char prefix[] = "+ ";
654
85.2k
    static int  const   indent_len = sizeof( indent ) - 1;
655
85.2k
    static int  const   prefix_len = sizeof( prefix ) - 1;
656
657
85.2k
    char   fixed_buffer[256] = {};
658
85.2k
    size_t const  static_len = sizeof( fixed_buffer );
659
85.2k
    char *            buffer = fixed_buffer;
660
85.2k
    size_t         total_len = indent_len * i_level + prefix_len + strlen( fmt ) + 1;
661
662
85.2k
    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
85.2k
    char * dst = buffer;
672
673
360k
    for (int i = 0; i < i_level; ++i, dst += indent_len)
674
274k
        memcpy( dst, indent, indent_len );
675
676
85.2k
    strcat( dst, prefix );
677
85.2k
    strcat( dst, fmt );
678
679
85.2k
    msg_GenericVa( &demuxer, VLC_MSG_DBG, buffer, args );
680
681
85.2k
    if (buffer != fixed_buffer)
682
0
        delete [] buffer;
683
85.2k
}
684
685
void MkvTree( demux_t & demuxer, int i_level, const char *psz_format, ... )
686
9.97k
{
687
9.97k
    va_list args; va_start( args, psz_format );
688
9.97k
    MkvTree_va( demuxer, i_level, psz_format, args );
689
    va_end( args );
690
9.97k
}
691
692
} // namespace