h264.c 18.7 KB
Newer Older
1
2
3
4
/*****************************************************************************
 * h264.c: h264/avc video packetizer
 *****************************************************************************
 * Copyright (C) 2001, 2002 VideoLAN
Laurent Aimar's avatar
Laurent Aimar committed
5
 * $Id$
6
7
8
 *
 * Authors: Laurent Aimar <fenrir@via.ecp.fr>
 *          Eric Petit <titer@videolan.org>
9
 *          Gildas Bazin <gbazin@videolan.org>
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
 *****************************************************************************/

/*****************************************************************************
 * Preamble
 *****************************************************************************/
#include <stdlib.h>                                      /* malloc(), free() */

#include <vlc/vlc.h>
#include <vlc/decoder.h>
#include <vlc/sout.h>

#include "vlc_block_helper.h"
#include "vlc_bits.h"

/*****************************************************************************
 * Module descriptor
 *****************************************************************************/
static int  Open ( vlc_object_t * );
static void Close( vlc_object_t * );

vlc_module_begin();
    set_description( _("H264 video packetizer") );
    set_capability( "packetizer", 50 );
    set_callbacks( Open, Close );
vlc_module_end();


/****************************************************************************
 * Local prototypes
 ****************************************************************************/
static block_t *Packetize( decoder_t *, block_t ** );
55
static block_t *PacketizeAVC1( decoder_t *, block_t ** );
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72

struct decoder_sys_t
{
    block_bytestream_t bytestream;

    int     i_state;
    int     i_offset;
    uint8_t startcode[4];

    vlc_bool_t b_slice;
    block_t    *p_frame;

    int64_t      i_dts;
    int64_t      i_pts;
    unsigned int i_flags;

    vlc_bool_t   b_sps;
73
74
75

    /* avcC data */
    int i_avcC_length_size;
76
77
78
79
80
81
82

    /* Useful values of the Sequence Parameter Set */
    int i_log2_max_frame_num;
    int b_frame_mbs_only;

    /* Useful values of the Slice Header */
    int i_nal_type;
gbazin's avatar
gbazin committed
83
    int i_nal_ref_idc;
84
85
    int i_idr_pic_id;
    int i_frame_num;
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
};

enum
{
    STATE_NOSYNC,
    STATE_NEXT_SYNC,
};

enum nal_unit_type_e
{
    NAL_UNKNOWN = 0,
    NAL_SLICE   = 1,
    NAL_SLICE_DPA   = 2,
    NAL_SLICE_DPB   = 3,
    NAL_SLICE_DPC   = 4,
    NAL_SLICE_IDR   = 5,    /* ref_idc != 0 */
    NAL_SEI         = 6,    /* ref_idc == 0 */
    NAL_SPS         = 7,
    NAL_PPS         = 8
    /* ref_idc == 0 for 6,9,10,11,12 */
};

enum nal_priority_e
{
    NAL_PRIORITY_DISPOSABLE = 0,
    NAL_PRIORITY_LOW        = 1,
    NAL_PRIORITY_HIGH       = 2,
    NAL_PRIORITY_HIGHEST    = 3,
};

static block_t *ParseNALBlock( decoder_t *, block_t * );

118
static block_t *nal_get_annexeb( decoder_t *, uint8_t *p, int );
119

120
121
122
123
124
125
126
127
128
/*****************************************************************************
 * Open: probe the packetizer and return score
 *****************************************************************************/
static int Open( vlc_object_t *p_this )
{
    decoder_t     *p_dec = (decoder_t*)p_this;
    decoder_sys_t *p_sys;

    if( p_dec->fmt_in.i_codec != VLC_FOURCC( 'h', '2', '6', '4') &&
129
        p_dec->fmt_in.i_codec != VLC_FOURCC( 'H', '2', '6', '4') &&
Laurent Aimar's avatar
Laurent Aimar committed
130
131
        p_dec->fmt_in.i_codec != VLC_FOURCC( 'V', 'S', 'S', 'H') &&
        p_dec->fmt_in.i_codec != VLC_FOURCC( 'v', 's', 's', 'h') &&
132
133
        ( p_dec->fmt_in.i_codec != VLC_FOURCC( 'a', 'v', 'c', '1') ||
          p_dec->fmt_in.i_extra < 7 ) )
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
    {
        return VLC_EGENERIC;
    }

    /* Allocate the memory needed to store the decoder's structure */
    if( ( p_dec->p_sys = p_sys = malloc( sizeof(decoder_sys_t) ) ) == NULL )
    {
        msg_Err( p_dec, "out of memory" );
        return VLC_EGENERIC;
    }
    p_sys->i_state = STATE_NOSYNC;
    p_sys->i_offset = 0;
    p_sys->startcode[0] = 0;
    p_sys->startcode[1] = 0;
    p_sys->startcode[2] = 0;
    p_sys->startcode[3] = 1;
    p_sys->bytestream = block_BytestreamInit( p_dec );
    p_sys->b_slice = VLC_FALSE;
    p_sys->p_frame = NULL;
    p_sys->i_dts   = 0;
    p_sys->i_pts   = 0;
    p_sys->i_flags = 0;
    p_sys->b_sps   = VLC_FALSE;

158
    p_sys->i_nal_type = -1;
gbazin's avatar
gbazin committed
159
    p_sys->i_nal_ref_idc = -1;
160
161
162
    p_sys->i_idr_pic_id = -1;
    p_sys->i_frame_num = -1;

163
164
165
    /* Setup properties */
    es_format_Copy( &p_dec->fmt_out, &p_dec->fmt_in );
    p_dec->fmt_out.i_codec = VLC_FOURCC( 'h', '2', '6', '4' );
gbazin's avatar
gbazin committed
166
167
168
    /* FIXME: FFMPEG isn't happy at all if you leave this */
    if( p_dec->fmt_out.i_extra ) free( p_dec->fmt_out.p_extra );
    p_dec->fmt_out.i_extra = 0; p_dec->fmt_out.p_extra = 0;
169

170
    if( p_dec->fmt_in.i_codec == VLC_FOURCC( 'a', 'v', 'c', '1' ) )
171
    {
172
173
174
175
176
177
178
179
180
181
182
183
184
        uint8_t *p = &((uint8_t*)p_dec->fmt_in.p_extra)[4];
        int i_sps, i_pps;
        int i;

        /* Parse avcC */
        p_sys->i_avcC_length_size = 1 + ((*p++)&0x03);

        /* Read SPS */
        i_sps = (*p++)&0x1f;

        for( i = 0; i < i_sps; i++ )
        {
            int i_length = GetWBE( p );
185
            block_t *p_sps = nal_get_annexeb( p_dec, p + 2, i_length );
186
187
188
189
190
191
192
193
194

            ParseNALBlock( p_dec, p_sps );
            p += 2 + i_length;
        }
        /* Read PPS */
        i_pps = *p++;
        for( i = 0; i < i_pps; i++ )
        {
            int i_length = GetWBE( p );
195
            block_t *p_pps = nal_get_annexeb( p_dec, p + 2, i_length );
196
197
198
199
200
201
202
203
204

            ParseNALBlock( p_dec, p_pps );
            p += 2 + i_length;
        }
        msg_Dbg( p_dec, "avcC length size=%d sps=%d pps=%d",
                 p_sys->i_avcC_length_size, i_sps, i_pps );

        /* Set callback */
        p_dec->pf_packetize = PacketizeAVC1;
205
206
207
    }
    else
    {
208
209
        /* Set callback */
        p_dec->pf_packetize = Packetize;
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
    }

    return VLC_SUCCESS;
}

/*****************************************************************************
 * Close: clean up the packetizer
 *****************************************************************************/
static void Close( vlc_object_t *p_this )
{
    decoder_t *p_dec = (decoder_t*)p_this;
    decoder_sys_t *p_sys = p_dec->p_sys;

    block_BytestreamRelease( &p_sys->bytestream );
    free( p_sys );
}

/****************************************************************************
 * Packetize: the whole thing
 ****************************************************************************/
static block_t *Packetize( decoder_t *p_dec, block_t **pp_block )
{
    decoder_sys_t *p_sys = p_dec->p_sys;
    block_t       *p_pic;

    if( !pp_block || !*pp_block ) return NULL;

    block_BytestreamPush( &p_sys->bytestream, *pp_block );

    for( ;; )
    {
        switch( p_sys->i_state )
        {
            case STATE_NOSYNC:
                if( block_FindStartcodeFromOffset( &p_sys->bytestream,
gbazin's avatar
gbazin committed
245
                      &p_sys->i_offset, p_sys->startcode+1, 3 ) == VLC_SUCCESS)
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
                {
                    p_sys->i_state = STATE_NEXT_SYNC;
                }

                if( p_sys->i_offset )
                {
                    block_SkipBytes( &p_sys->bytestream, p_sys->i_offset );
                    p_sys->i_offset = 0;
                    block_BytestreamFlush( &p_sys->bytestream );
                }

                if( p_sys->i_state != STATE_NEXT_SYNC )
                {
                    /* Need more data */
                    return NULL;
                }

                p_sys->i_offset = 1; /* To find next startcode */

            case STATE_NEXT_SYNC:
                /* Find the next startcode */
                if( block_FindStartcodeFromOffset( &p_sys->bytestream,
gbazin's avatar
gbazin committed
268
                      &p_sys->i_offset, p_sys->startcode, 3 ) != VLC_SUCCESS)
269
                {
gbazin's avatar
gbazin committed
270
271
272
273
274
275
276
                    if( block_FindStartcodeFromOffset( &p_sys->bytestream,
                          &p_sys->i_offset, p_sys->startcode+1, 3 ) !=
                        VLC_SUCCESS )
                    {
                        /* Need more data */
                        return NULL;
                    }
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
                }

                /* Get the new fragment and set the pts/dts */
                p_pic = block_New( p_dec, p_sys->i_offset );
                p_pic->i_pts = p_sys->bytestream.p_block->i_pts;
                p_pic->i_dts = p_sys->bytestream.p_block->i_dts;

                block_GetBytes( &p_sys->bytestream, p_pic->p_buffer,
                                p_pic->i_buffer );

                p_sys->i_offset = 0;

                /* Parse the NAL */
                if( !( p_pic = ParseNALBlock( p_dec, p_pic ) ) )
                {
                    p_sys->i_state = STATE_NOSYNC;
                    break;
                }

                /* So p_block doesn't get re-added several times */
                *pp_block = block_BytestreamPop( &p_sys->bytestream );

                p_sys->i_state = STATE_NOSYNC;

                return p_pic;
        }
    }
}

306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
/****************************************************************************
 * PacketizeAVC1: the whole thing
 ****************************************************************************/
static block_t *PacketizeAVC1( decoder_t *p_dec, block_t **pp_block )
{
    decoder_sys_t *p_sys = p_dec->p_sys;
    block_t       *p_block;
    block_t       *p_ret = NULL;
    uint8_t       *p;

    if( !pp_block || !*pp_block ) return NULL;

    p_block = *pp_block;
    *pp_block = NULL;

    for( p = p_block->p_buffer; p < &p_block->p_buffer[p_block->i_buffer]; )
    {
        block_t *p_pic;
        int i_size = 0;
        int i;

        for( i = 0; i < p_sys->i_avcC_length_size; i++ )
        {
            i_size = (i_size << 8) | (*p++);
        }

        if( i_size > 0 )
        {
334
            block_t *p_part = nal_get_annexeb( p_dec, p, i_size );
335
336
337

            p_part->i_dts = p_block->i_dts;
            p_part->i_pts = p_block->i_pts;
338

339
340
341
342
343
344
345
346
347
348
349
350
            /* Parse the NAL */
            if( ( p_pic = ParseNALBlock( p_dec, p_part ) ) )
            {
                block_ChainAppend( &p_ret, p_pic );
            }
        }
        p += i_size;
    }

    return p_ret;
}

351
static block_t *nal_get_annexeb( decoder_t *p_dec, uint8_t *p, int i_size )
352
353
354
{
    block_t *p_nal;

gbazin's avatar
gbazin committed
355
    p_nal = block_New( p_dec, 3 + i_size );
356

357
358
359
    /* Add start code */
    p_nal->p_buffer[0] = 0x00;
    p_nal->p_buffer[1] = 0x00;
gbazin's avatar
gbazin committed
360
    p_nal->p_buffer[2] = 0x01;
361

362
    /* Copy nalu */
gbazin's avatar
gbazin committed
363
    memcpy( &p_nal->p_buffer[3], p, i_size );
364
365
366
367

    return p_nal;
}

368
369
static void nal_get_decoded( uint8_t **pp_ret, int *pi_ret,
                             uint8_t *src, int i_src )
370
371
372
373
374
375
376
377
{
    uint8_t *end = &src[i_src];
    uint8_t *dst = malloc( i_src );

    *pp_ret = dst;

    while( src < end )
    {
378
379
        if( src < end - 3 && src[0] == 0x00 && src[1] == 0x00 &&
            src[2] == 0x03 )
380
381
382
383
384
        {
            *dst++ = 0x00;
            *dst++ = 0x00;

            src += 3;
Laurent Aimar's avatar
Laurent Aimar committed
385
            continue;
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
        }
        *dst++ = *src++;
    }

    *pi_ret = dst - *pp_ret;
}

static inline int bs_read_ue( bs_t *s )
{
    int i = 0;

    while( bs_read1( s ) == 0 && s->p < s->p_end && i < 32 )
    {
        i++;
    }
    return( ( 1 << i) - 1 + bs_read( s, i ) );
}
403

404
static inline int bs_read_se( bs_t *s )
405
406
407
408
409
410
411
412
413
414
415
416
{
    int val = bs_read_ue( s );

    return val&0x01 ? (val+1)/2 : -(val/2);
}


static block_t *ParseNALBlock( decoder_t *p_dec, block_t *p_frag )
{
    decoder_sys_t *p_sys = p_dec->p_sys;
    block_t *p_pic = NULL;

gbazin's avatar
gbazin committed
417
418
    const int i_nal_ref_idc = (p_frag->p_buffer[3] >> 5)&0x03;
    const int i_nal_type = p_frag->p_buffer[3]&0x1f;
419

420
    if( p_sys->b_slice && !p_sys->b_sps )
421
    {
422
423
        block_ChainRelease( p_sys->p_frame );
        msg_Warn( p_dec, "waiting for SPS" );
424

425
        /* Reset context */
426
427
428
429
        p_sys->p_frame = NULL;
        p_sys->b_slice = VLC_FALSE;
    }

430
431
432
433
434
435
436
    if( !p_sys->b_sps &&
        i_nal_type >= NAL_SLICE && i_nal_type <= NAL_SLICE_IDR )
    {
        p_sys->b_slice = VLC_TRUE;
        /* Fragment will be discarded later on */
    }
    else if( i_nal_type >= NAL_SLICE && i_nal_type <= NAL_SLICE_IDR )
437
438
    {
        uint8_t *dec;
439
440
        int i_dec, i_first_mb, i_slice_type, i_frame_num, i_pic_flags = 0;
        vlc_bool_t b_pic = VLC_FALSE;
441
442
443
        bs_t s;

        /* do not convert the whole frame */
gbazin's avatar
gbazin committed
444
445
        nal_get_decoded( &dec, &i_dec, &p_frag->p_buffer[4],
                         __MIN( p_frag->i_buffer - 4, 60 ) );
446
447
        bs_init( &s, dec, i_dec );

448
449
450
451
452
        /* first_mb_in_slice */
        i_first_mb = bs_read_ue( &s );

        /* slice_type */
        switch( (i_slice_type = bs_read_ue( &s )) )
453
454
        {
            case 0: case 5:
455
                i_pic_flags = BLOCK_FLAG_TYPE_P;
456
457
                break;
            case 1: case 6:
458
                i_pic_flags = BLOCK_FLAG_TYPE_B;
459
460
                break;
            case 2: case 7:
461
                i_pic_flags = BLOCK_FLAG_TYPE_I;
462
463
                break;
            case 3: case 8: /* SP */
464
                i_pic_flags = BLOCK_FLAG_TYPE_P;
465
466
                break;
            case 4: case 9:
467
                i_pic_flags = BLOCK_FLAG_TYPE_I;
468
469
470
                break;
        }

471
472
473
474
475
        /* pic_parameter_set_id */
        bs_read_ue( &s );
        /* frame_num */
        i_frame_num = bs_read( &s, p_sys->i_log2_max_frame_num + 4 );

gbazin's avatar
gbazin committed
476
477
478
479
480
        /* Detection of the first VCL NAL unit of a primary coded picture
         * (cf. 7.4.1.2.4) */
        if( i_frame_num != p_sys->i_frame_num ||
            ( (i_nal_ref_idc != p_sys->i_nal_ref_idc) &&
              (!i_nal_ref_idc || !p_sys->i_nal_ref_idc) ) )
481
482
483
484
        {
            b_pic = VLC_TRUE;
        }
        p_sys->i_frame_num = i_frame_num;
gbazin's avatar
gbazin committed
485
        p_sys->i_nal_ref_idc = i_nal_ref_idc;
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524

        if( !p_sys->b_frame_mbs_only )
        {
            /* field_pic_flag */
            if( bs_read( &s, 1 ) )
            {
                /* bottom_field_flag */
                bs_read( &s, 1 );
            }
        }

        if( i_nal_type == NAL_SLICE_IDR )
        {
            /* id_pic_id */
            int i_idr_pic_id = bs_read_ue( &s );
            if( p_sys->i_nal_type != i_nal_type ) b_pic = VLC_TRUE;
            if( p_sys->i_idr_pic_id != i_idr_pic_id ) b_pic = VLC_TRUE;
            p_sys->i_idr_pic_id = i_idr_pic_id;
        }
        p_sys->i_nal_type = i_nal_type;

        if( b_pic && p_sys->b_slice )
        {
            p_pic = block_ChainGather( p_sys->p_frame );
            p_pic->i_dts = p_sys->i_dts;
            p_pic->i_pts = p_sys->i_pts;
            p_pic->i_length = 0;    /* FIXME */
            p_pic->i_flags = p_sys->i_flags;

            /* Reset context */
            p_sys->p_frame = NULL;
            p_sys->b_slice = VLC_FALSE;
        }

        p_sys->b_slice = VLC_TRUE;
        p_sys->i_flags = i_pic_flags;
        p_sys->i_dts   = p_frag->i_dts;
        p_sys->i_pts   = p_frag->i_pts;

525
526
527
528
529
530
531
532
533
        free( dec );
    }
    else if( i_nal_type == NAL_SPS )
    {
        uint8_t *dec;
        int     i_dec;
        bs_t s;
        int i_tmp;

534
535
        msg_Dbg( p_dec, "found NAL_SPS" );

536
537
        p_sys->b_sps = VLC_TRUE;

gbazin's avatar
gbazin committed
538
539
        nal_get_decoded( &dec, &i_dec, &p_frag->p_buffer[4],
                         p_frag->i_buffer - 4 );
540
541
542
543
544
545
546

        bs_init( &s, dec, i_dec );
        /* Skip profile(8), constraint_set012, reserver(5), level(8) */
        bs_skip( &s, 8 + 1+1+1 + 5 + 8 );
        /* sps id */
        bs_read_ue( &s );
        /* Skip i_log2_max_frame_num */
547
        p_sys->i_log2_max_frame_num = bs_read_ue( &s );
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
        /* Read poc_type */
        i_tmp = bs_read_ue( &s );
        if( i_tmp == 0 )
        {
            /* skip i_log2_max_poc_lsb */
            bs_read_ue( &s );
        }
        else if( i_tmp == 1 )
        {
            int i_cycle;
            /* skip b_delta_pic_order_always_zero */
            bs_skip( &s, 1 );
            /* skip i_offset_for_non_ref_pic */
            bs_read_se( &s );
            /* skip i_offset_for_top_to_bottom_field */
            bs_read_se( &s );
            /* read i_num_ref_frames_in_poc_cycle */
            i_cycle = bs_read_ue( &s );
            if( i_cycle > 256 ) i_cycle = 256;
            while( i_cycle > 0 )
            {
                /* skip i_offset_for_ref_frame */
                bs_read_se(&s );
            }
        }
        /* i_num_ref_frames */
        bs_read_ue( &s );
        /* b_gaps_in_frame_num_value_allowed */
        bs_skip( &s, 1 );

        /* Read size */
        p_dec->fmt_out.video.i_width  = 16 * ( bs_read_ue( &s ) + 1 );
        p_dec->fmt_out.video.i_height = 16 * ( bs_read_ue( &s ) + 1 );

        /* b_frame_mbs_only */
583
584
        p_sys->b_frame_mbs_only = bs_read( &s, 1 );
        if( p_sys->b_frame_mbs_only == 0 )
585
586
587
588
589
590
        {
            bs_skip( &s, 1 );
        }
        /* b_direct8x8_inference */
        bs_skip( &s, 1 );

gbazin's avatar
gbazin committed
591
        /* crop */
592
593
594
595
        i_tmp = bs_read( &s, 1 );
        if( i_tmp )
        {
            /* left */
gbazin's avatar
gbazin committed
596
            bs_read_ue( &s );
597
            /* right */
gbazin's avatar
gbazin committed
598
            bs_read_ue( &s );
599
            /* top */
gbazin's avatar
gbazin committed
600
            bs_read_ue( &s );
601
            /* bottom */
gbazin's avatar
gbazin committed
602
            bs_read_ue( &s );
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
        }

        /* vui */
        i_tmp = bs_read( &s, 1 );
        if( i_tmp )
        {
            /* read the aspect ratio part if any FIXME check it */
            i_tmp = bs_read( &s, 1 );
            if( i_tmp )
            {
                static const struct { int w, h; } sar[14] =
                {
                    { 0,   0 }, { 1,   1 }, { 12, 11 }, { 10, 11 },
                    { 16, 11 }, { 40, 33 }, { 24, 11 }, { 20, 11 },
                    { 32, 11 }, { 80, 33 }, { 18, 11 }, { 15, 11 },
                    { 64, 33 }, { 160,99 },
                };
                int i_sar = bs_read( &s, 8 );
                int w, h;

                if( i_sar < 14 )
                {
                    w = sar[i_sar].w;
                    h = sar[i_sar].h;
                }
                else
                {
                    w = bs_read( &s, 16 );
                    h = bs_read( &s, 16 );
                }
                p_dec->fmt_out.video.i_aspect =
634
635
                    VOUT_ASPECT_FACTOR * w / h * p_dec->fmt_out.video.i_width /
                    p_dec->fmt_out.video.i_height;
636
637
638
639
640
641
642
643
            }
        }

        free( dec );
    }
    else if( i_nal_type == NAL_PPS )
    {
        bs_t s;
gbazin's avatar
gbazin committed
644
        bs_init( &s, &p_frag->p_buffer[4], p_frag->i_buffer - 4 );
645
646

        /* TODO */
647
        msg_Dbg( p_dec, "found NAL_PPS" );
648
649
650
651
652
653
654
    }

    /* Append the block */
    block_ChainAppend( &p_sys->p_frame, p_frag );

    return p_pic;
}