]> git.sesse.net Git - vlc/blob - modules/packetizer/mpegvideo.c
Improved BLOCK_FLAG_DISCONTINUITY|BLOCK_FLAG_CORRUPTED handling in packetizers.
[vlc] / modules / packetizer / mpegvideo.c
1 /*****************************************************************************
2  * mpegvideo.c: parse and packetize an MPEG1/2 video stream
3  *****************************************************************************
4  * Copyright (C) 2001-2006 the VideoLAN team
5  * $Id$
6  *
7  * Authors: Laurent Aimar <fenrir@via.ecp.fr>
8  *          Eric Petit <titer@videolan.org>
9  *          Gildas Bazin <gbazin@videolan.org>
10  *          Jean-Paul Saman <jpsaman #_at_# m2x dot nl>
11  *
12  * This program is free software; you can redistribute it and/or modify
13  * it under the terms of the GNU General Public License as published by
14  * the Free Software Foundation; either version 2 of the License, or
15  * (at your option) any later version.
16  *
17  * This program is distributed in the hope that it will be useful,
18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20  * GNU General Public License for more details.
21  *
22  * You should have received a copy of the GNU General Public License
23  * along with this program; if not, write to the Free Software
24  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
25  *****************************************************************************/
26
27 /*****************************************************************************
28  * Problem with this implementation:
29  *
30  * Although we should time-stamp each picture with a PTS, this isn't possible
31  * with the current implementation.
32  * The problem comes from the fact that for non-low-delay streams we can't
33  * calculate the PTS of pictures used as backward reference. Even the temporal
34  * reference number doesn't help here because all the pictures don't
35  * necessarily have the same duration (eg. 3:2 pulldown).
36  *
37  * However this doesn't really matter as far as the MPEG muxers are concerned
38  * because they allow having empty PTS fields. --gibalou
39  *****************************************************************************/
40
41 /*****************************************************************************
42  * Preamble
43  *****************************************************************************/
44 #include <stdlib.h>                                      /* malloc(), free() */
45
46 #include <vlc/vlc.h>
47 #include <vlc_block.h>
48 #include <vlc_codec.h>
49 #include <vlc_block_helper.h>
50
51 #define SYNC_INTRAFRAME_TEXT N_("Sync on Intra Frame")
52 #define SYNC_INTRAFRAME_LONGTEXT N_("Normally the packetizer would " \
53     "sync on the next full frame. This flags instructs the packetizer " \
54     "to sync on the first Intra Frame found.")
55
56 /*****************************************************************************
57  * Module descriptor
58  *****************************************************************************/
59 static int  Open ( vlc_object_t * );
60 static void Close( vlc_object_t * );
61
62 vlc_module_begin();
63     set_category( CAT_SOUT );
64     set_subcategory( SUBCAT_SOUT_PACKETIZER );
65     set_description( _("MPEG-I/II video packetizer") );
66     set_capability( "packetizer", 50 );
67     set_callbacks( Open, Close );
68
69     add_bool( "packetizer-mpegvideo-sync-iframe", 0, NULL, SYNC_INTRAFRAME_TEXT,
70               SYNC_INTRAFRAME_LONGTEXT, VLC_TRUE );
71 vlc_module_end();
72
73 /*****************************************************************************
74  * Local prototypes
75  *****************************************************************************/
76 static block_t *Packetize( decoder_t *, block_t ** );
77 static block_t *ParseMPEGBlock( decoder_t *, block_t * );
78
79 struct decoder_sys_t
80 {
81     /*
82      * Input properties
83      */
84     block_bytestream_t bytestream;
85     int i_state;
86     int i_offset;
87     uint8_t p_startcode[3];
88
89     /* Sequence header and extension */
90     block_t *p_seq;
91     block_t *p_ext;
92
93     /* Current frame being built */
94     block_t    *p_frame;
95     block_t    **pp_last;
96
97     vlc_bool_t b_frame_slice;
98     mtime_t i_pts;
99     mtime_t i_dts;
100
101     /* Sequence properties */
102     int         i_frame_rate;
103     int         i_frame_rate_base;
104     vlc_bool_t  b_seq_progressive;
105     vlc_bool_t  b_low_delay;
106     int         i_aspect_ratio_info;
107     vlc_bool_t  b_inited;
108
109     /* Picture properties */
110     int i_temporal_ref;
111     int i_picture_type;
112     int i_picture_structure;
113     int i_top_field_first;
114     int i_repeat_first_field;
115     int i_progressive_frame;
116
117     mtime_t i_interpolated_dts;
118     mtime_t i_last_ref_pts;
119     vlc_bool_t b_second_field;
120
121     /* Number of pictures since last sequence header */
122     int i_seq_old;
123
124     /* Sync behaviour */
125     vlc_bool_t  b_sync_on_intra_frame;
126     vlc_bool_t  b_discontinuity;
127 };
128
129 enum {
130     STATE_NOSYNC,
131     STATE_NEXT_SYNC
132 };
133
134 /*****************************************************************************
135  * Open:
136  *****************************************************************************/
137 static int Open( vlc_object_t *p_this )
138 {
139     decoder_t *p_dec = (decoder_t*)p_this;
140     decoder_sys_t *p_sys;
141
142     if( p_dec->fmt_in.i_codec != VLC_FOURCC( 'm', 'p', 'g', '1' ) &&
143         p_dec->fmt_in.i_codec != VLC_FOURCC( 'm', 'p', 'g', '2' ) &&
144         p_dec->fmt_in.i_codec != VLC_FOURCC( 'm', 'p', 'g', 'v' ) )
145     {
146         return VLC_EGENERIC;
147     }
148
149     es_format_Init( &p_dec->fmt_out, VIDEO_ES, VLC_FOURCC('m','p','g','v') );
150     p_dec->pf_packetize = Packetize;
151
152     p_dec->p_sys = p_sys = malloc( sizeof( decoder_sys_t ) );
153
154     /* Misc init */
155     p_sys->i_state = STATE_NOSYNC;
156     p_sys->bytestream = block_BytestreamInit( p_dec );
157     p_sys->p_startcode[0] = 0;
158     p_sys->p_startcode[1] = 0;
159     p_sys->p_startcode[2] = 1;
160     p_sys->i_offset = 0;
161
162     p_sys->p_seq = NULL;
163     p_sys->p_ext = NULL;
164     p_sys->p_frame = NULL;
165     p_sys->pp_last = &p_sys->p_frame;
166     p_sys->b_frame_slice = VLC_FALSE;
167
168     p_sys->i_dts = p_sys->i_pts = 0;
169
170     p_sys->i_frame_rate = 1;
171     p_sys->i_frame_rate_base = 1;
172     p_sys->b_seq_progressive = VLC_TRUE;
173     p_sys->b_low_delay = VLC_TRUE;
174     p_sys->i_seq_old = 0;
175
176     p_sys->i_temporal_ref = 0;
177     p_sys->i_picture_type = 0;
178     p_sys->i_picture_structure = 0x03; /* frame */
179     p_sys->i_top_field_first = 0;
180     p_sys->i_repeat_first_field = 0;
181     p_sys->i_progressive_frame = 0;
182     p_sys->b_inited = 0;
183
184     p_sys->i_interpolated_dts = 0;
185     p_sys->i_last_ref_pts = 0;
186     p_sys->b_second_field = 0;
187
188     p_sys->b_discontinuity = VLC_FALSE;
189     p_sys->b_sync_on_intra_frame = var_CreateGetBool( p_dec, "packetizer-mpegvideo-sync-iframe" );
190     if( p_sys->b_sync_on_intra_frame )
191         msg_Dbg( p_dec, "syncing on intra frame now" );
192
193     return VLC_SUCCESS;
194 }
195
196 /*****************************************************************************
197  * Close:
198  *****************************************************************************/
199 static void Close( vlc_object_t *p_this )
200 {
201     decoder_t     *p_dec = (decoder_t*)p_this;
202     decoder_sys_t *p_sys = p_dec->p_sys;
203
204     block_BytestreamRelease( &p_sys->bytestream );
205
206     if( p_sys->p_seq )
207     {
208         block_Release( p_sys->p_seq );
209     }
210     if( p_sys->p_ext )
211     {
212         block_Release( p_sys->p_ext );
213     }
214     if( p_sys->p_frame )
215     {
216         block_ChainRelease( p_sys->p_frame );
217     }
218
219     var_Destroy( p_dec, "packetizer-mpegvideo-sync-iframe" );
220
221     free( p_sys );
222 }
223
224 /*****************************************************************************
225  * Packetize:
226  *****************************************************************************/
227 static block_t *Packetize( decoder_t *p_dec, block_t **pp_block )
228 {
229     decoder_sys_t *p_sys = p_dec->p_sys;
230     block_t       *p_pic;
231
232     if( pp_block == NULL || *pp_block == NULL )
233     {
234         return NULL;
235     }
236
237     if( (*pp_block)->i_flags&(BLOCK_FLAG_DISCONTINUITY|BLOCK_FLAG_CORRUPTED) )
238     {
239         if( (*pp_block)->i_flags&BLOCK_FLAG_CORRUPTED )
240         {
241             p_sys->i_state = STATE_NOSYNC;
242             block_BytestreamFlush( &p_sys->bytestream );
243
244             p_sys->b_discontinuity = VLC_TRUE;
245             if( p_sys->p_frame )
246                 block_ChainRelease( p_sys->p_frame );
247             p_sys->p_frame = NULL;
248             p_sys->pp_last = &p_sys->p_frame;
249             p_sys->b_frame_slice = VLC_FALSE;
250         }
251 //        p_sys->i_interpolated_dts = 
252 //        p_sys->i_last_ref_pts = 0;
253
254         block_Release( *pp_block );
255         return NULL;
256     }
257
258
259     block_BytestreamPush( &p_sys->bytestream, *pp_block );
260
261     while( 1 )
262     {
263         switch( p_sys->i_state )
264         {
265
266         case STATE_NOSYNC:
267             if( block_FindStartcodeFromOffset( &p_sys->bytestream,
268                     &p_sys->i_offset, p_sys->p_startcode, 3 ) == VLC_SUCCESS )
269             {
270                 p_sys->i_state = STATE_NEXT_SYNC;
271             }
272
273             if( p_sys->i_offset )
274             {
275                 block_SkipBytes( &p_sys->bytestream, p_sys->i_offset );
276                 p_sys->i_offset = 0;
277                 block_BytestreamFlush( &p_sys->bytestream );
278             }
279
280             if( p_sys->i_state != STATE_NEXT_SYNC )
281             {
282                 /* Need more data */
283                 return NULL;
284             }
285
286             p_sys->i_offset = 1; /* To find next startcode */
287
288         case STATE_NEXT_SYNC:
289             /* TODO: If p_block == NULL, flush the buffer without checking the
290              * next sync word */
291
292             /* Find the next startcode */
293             if( block_FindStartcodeFromOffset( &p_sys->bytestream,
294                     &p_sys->i_offset, p_sys->p_startcode, 3 ) != VLC_SUCCESS )
295             {
296                 /* Need more data */
297                 return NULL;
298             }
299
300             /* Get the new fragment and set the pts/dts */
301             p_pic = block_New( p_dec, p_sys->i_offset );
302             block_BytestreamFlush( &p_sys->bytestream );
303             p_pic->i_pts = p_sys->bytestream.p_block->i_pts;
304             p_pic->i_dts = p_sys->bytestream.p_block->i_dts;
305
306             block_GetBytes( &p_sys->bytestream, p_pic->p_buffer,
307                             p_pic->i_buffer );
308
309             /* don't reuse the same timestamps several times */
310             if( p_pic->i_buffer >= 4 && p_pic->p_buffer[3] == 0x00 )
311             {
312                 /* We have a picture start code */
313                 p_sys->bytestream.p_block->i_pts = 0;
314                 p_sys->bytestream.p_block->i_dts = 0;
315             }
316
317             p_sys->i_offset = 0;
318
319             /* Get picture if any */
320             if( !( p_pic = ParseMPEGBlock( p_dec, p_pic ) ) )
321             {
322                 p_sys->i_state = STATE_NOSYNC;
323                 break;
324             }
325
326             /* If a discontinuity has been encountered, then wait till
327              * the next Intra frame before continuing with packetizing */
328             if( p_sys->b_discontinuity &&
329                 p_sys->b_sync_on_intra_frame )
330             {
331                 if( p_pic->i_flags & BLOCK_FLAG_TYPE_I )
332                 {
333                     msg_Dbg( p_dec, "synced on intra frame" );
334                     p_sys->b_discontinuity = VLC_FALSE;
335                     p_pic->i_flags |= BLOCK_FLAG_DISCONTINUITY;
336                 }
337                 else
338                 {
339                     msg_Dbg( p_dec, "waiting on intra frame" );
340                     p_sys->i_state = STATE_NOSYNC;
341                     block_Release( p_pic );
342                     break;
343                 }
344             }
345
346             /* We've just started the stream, wait for the first PTS.
347              * We discard here so we can still get the sequence header. */
348             if( p_sys->i_dts <= 0 && p_sys->i_pts <= 0 &&
349                 p_sys->i_interpolated_dts <= 0 )
350             {
351                 msg_Dbg( p_dec, "need a starting pts/dts" );
352                 p_sys->i_state = STATE_NOSYNC;
353                 block_Release( p_pic );
354                 break;
355             }
356
357             /* When starting the stream we can have the first frame with
358              * a null DTS (i_interpolated_pts is initialized to 0) */
359             if( !p_pic->i_dts ) p_pic->i_dts = p_pic->i_pts;
360
361             /* So p_block doesn't get re-added several times */
362             *pp_block = block_BytestreamPop( &p_sys->bytestream );
363
364             p_sys->i_state = STATE_NOSYNC;
365
366             return p_pic;
367         }
368     }
369 }
370
371 /*****************************************************************************
372  * ParseMPEGBlock: Re-assemble fragments into a block containing a picture
373  *****************************************************************************/
374 static block_t *ParseMPEGBlock( decoder_t *p_dec, block_t *p_frag )
375 {
376     decoder_sys_t *p_sys = p_dec->p_sys;
377     block_t *p_pic = NULL;
378
379     /*
380      * Check if previous picture is finished
381      */
382     if( ( p_sys->b_frame_slice &&
383           (p_frag->p_buffer[3] == 0x00 || p_frag->p_buffer[3] > 0xaf) ) &&
384           p_sys->p_seq == NULL )
385     {
386         /* We have a picture but without a sequence header we can't
387          * do anything */
388         msg_Dbg( p_dec, "waiting for sequence start" );
389         if( p_sys->p_frame ) block_ChainRelease( p_sys->p_frame );
390         p_sys->p_frame = NULL;
391         p_sys->pp_last = &p_sys->p_frame;
392         p_sys->b_frame_slice = VLC_FALSE;
393
394     }
395     else if( p_sys->b_frame_slice &&
396              (p_frag->p_buffer[3] == 0x00 || p_frag->p_buffer[3] > 0xaf) )
397     {
398         mtime_t i_duration;
399
400         p_pic = block_ChainGather( p_sys->p_frame );
401
402         i_duration = (mtime_t)( 1000000 * p_sys->i_frame_rate_base /
403                                 p_sys->i_frame_rate );
404
405         if( !p_sys->b_seq_progressive && p_sys->i_picture_structure != 0x03 )
406         {
407             i_duration /= 2;
408         }
409
410         if( p_sys->b_seq_progressive )
411         {
412             if( p_sys->i_top_field_first == 0 &&
413                 p_sys->i_repeat_first_field == 1 )
414             {
415                 i_duration *= 2;
416             }
417             else if( p_sys->i_top_field_first == 1 &&
418                      p_sys->i_repeat_first_field == 1 )
419             {
420                 i_duration *= 3;
421             }
422         }
423         else
424         {
425             if( p_sys->i_picture_structure == 0x03 )
426             {
427                 if( p_sys->i_progressive_frame && p_sys->i_repeat_first_field )
428                 {
429                     i_duration += i_duration / 2;
430                 }
431             }
432         }
433
434         if( p_sys->b_low_delay || p_sys->i_picture_type == 0x03 )
435         {
436             /* Trivial case (DTS == PTS) */
437             /* Correct interpolated dts when we receive a new pts/dts */
438             if( p_sys->i_pts > 0 ) p_sys->i_interpolated_dts = p_sys->i_pts;
439             if( p_sys->i_dts > 0 ) p_sys->i_interpolated_dts = p_sys->i_dts;
440         }
441         else
442         {
443             /* Correct interpolated dts when we receive a new pts/dts */
444             if( p_sys->i_last_ref_pts > 0 && !p_sys->b_second_field )
445                 p_sys->i_interpolated_dts = p_sys->i_last_ref_pts;
446             if( p_sys->i_dts > 0 ) p_sys->i_interpolated_dts = p_sys->i_dts;
447
448             if( !p_sys->b_second_field )
449                 p_sys->i_last_ref_pts = p_sys->i_pts;
450         }
451
452         p_pic->i_dts = p_sys->i_interpolated_dts;
453         p_sys->i_interpolated_dts += i_duration;
454
455         /* Set PTS only if we have a B frame or if it comes from the stream */
456         if( p_sys->i_pts > 0 )
457         {
458             p_pic->i_pts = p_sys->i_pts;
459         }
460         else if( p_sys->i_picture_type == 0x03 )
461         {
462             p_pic->i_pts = p_pic->i_dts;
463         }
464         else
465         {
466             p_pic->i_pts = 0;
467         }
468
469         switch ( p_sys->i_picture_type )
470         {
471         case 0x01:
472             p_pic->i_flags |= BLOCK_FLAG_TYPE_I;
473             break;
474         case 0x02:
475             p_pic->i_flags |= BLOCK_FLAG_TYPE_P;
476             break;
477         case 0x03:
478             p_pic->i_flags |= BLOCK_FLAG_TYPE_B;
479             break;
480         }
481
482         p_pic->i_length = p_sys->i_interpolated_dts - p_pic->i_dts;
483
484 #if 0
485         msg_Dbg( p_dec, "pic: type=%d dts="I64Fd" pts-dts="I64Fd,
486         p_sys->i_picture_type, p_pic->i_dts, p_pic->i_pts - p_pic->i_dts);
487 #endif
488
489         /* Reset context */
490         p_sys->p_frame = NULL;
491         p_sys->pp_last = &p_sys->p_frame;
492         p_sys->b_frame_slice = VLC_FALSE;
493
494         if( p_sys->i_picture_structure != 0x03 )
495         {
496             p_sys->b_second_field = !p_sys->b_second_field;
497         }
498         else
499         {
500             p_sys->b_second_field = 0;
501         }
502     }
503
504     /*
505      * Check info of current fragment
506      */
507     if( p_frag->p_buffer[3] == 0xb8 )
508     {
509         /* Group start code */
510         if( p_sys->p_seq &&
511             p_sys->i_seq_old > p_sys->i_frame_rate/p_sys->i_frame_rate_base )
512         {
513             /* Usefull for mpeg1: repeat sequence header every second */
514             block_ChainLastAppend( &p_sys->pp_last, block_Duplicate( p_sys->p_seq ) );
515             if( p_sys->p_ext )
516             {
517                 block_ChainLastAppend( &p_sys->pp_last, block_Duplicate( p_sys->p_ext ) );
518             }
519
520             p_sys->i_seq_old = 0;
521         }
522     }
523     else if( p_frag->p_buffer[3] == 0xb3 && p_frag->i_buffer >= 8 )
524     {
525         /* Sequence header code */
526         static const int code_to_frame_rate[16][2] =
527         {
528             { 1, 1 },  /* invalid */
529             { 24000, 1001 }, { 24, 1 }, { 25, 1 },       { 30000, 1001 },
530             { 30, 1 },       { 50, 1 }, { 60000, 1001 }, { 60, 1 },
531             /* Unofficial 15fps from Xing*/
532             { 15, 1001 },
533             /* Unofficial economy rates from libmpeg3 */
534             { 5, 1001 }, { 10, 1001 }, { 12, 1001 }, { 15, 1001 },
535             { 1, 1 },  { 1, 1 }  /* invalid */
536         };
537
538         if( p_sys->p_seq ) block_Release( p_sys->p_seq );
539         if( p_sys->p_ext ) block_Release( p_sys->p_ext );
540
541         p_sys->p_seq = block_Duplicate( p_frag );
542         p_sys->i_seq_old = 0;
543         p_sys->p_ext = NULL;
544
545         p_dec->fmt_out.video.i_width =
546             ( p_frag->p_buffer[4] << 4)|(p_frag->p_buffer[5] >> 4 );
547         p_dec->fmt_out.video.i_height =
548             ( (p_frag->p_buffer[5]&0x0f) << 8 )|p_frag->p_buffer[6];
549         p_sys->i_aspect_ratio_info = p_frag->p_buffer[7] >> 4;
550
551         /* TODO: MPEG1 aspect ratio */
552
553         p_sys->i_frame_rate = code_to_frame_rate[p_frag->p_buffer[7]&0x0f][0];
554         p_sys->i_frame_rate_base =
555             code_to_frame_rate[p_frag->p_buffer[7]&0x0f][1];
556
557         p_dec->fmt_out.video.i_frame_rate = p_sys->i_frame_rate;
558         p_dec->fmt_out.video.i_frame_rate_base = p_sys->i_frame_rate_base;
559
560         p_sys->b_seq_progressive = VLC_TRUE;
561         p_sys->b_low_delay = VLC_TRUE;
562
563         if ( !p_sys->b_inited )
564         {
565             msg_Dbg( p_dec, "size %dx%d fps=%.3f",
566                  p_dec->fmt_out.video.i_width, p_dec->fmt_out.video.i_height,
567                  p_sys->i_frame_rate / (float)p_sys->i_frame_rate_base );
568             p_sys->b_inited = 1;
569         }
570     }
571     else if( p_frag->p_buffer[3] == 0xb5 )
572     {
573         int i_type = p_frag->p_buffer[4] >> 4;
574
575         /* Extension start code */
576         if( i_type == 0x01 )
577         {
578 #if 0
579             static const int mpeg2_aspect[16][2] =
580             {
581                 {0,1}, {1,1}, {4,3}, {16,9}, {221,100},
582                 {0,1}, {0,1}, {0,1}, {0,1}, {0,1}, {0,1}, {0,1}, {0,1}, {0,1},
583                 {0,1}, {0,1}
584             };
585 #endif
586
587             /* sequence extension */
588             if( p_sys->p_ext) block_Release( p_sys->p_ext );
589             p_sys->p_ext = block_Duplicate( p_frag );
590
591             if( p_frag->i_buffer >= 10 )
592             {
593                 p_sys->b_seq_progressive =
594                     p_frag->p_buffer[5]&0x08 ? VLC_TRUE : VLC_FALSE;
595                 p_sys->b_low_delay =
596                     p_frag->p_buffer[9]&0x80 ? VLC_TRUE : VLC_FALSE;
597             }
598
599             /* Do not set aspect ratio : in case we're transcoding,
600              * transcode will take our fmt_out as a fmt_in to libmpeg2.
601              * libmpeg2.c will then believe that the user has requested
602              * a specific aspect ratio, which she hasn't. Thus in case
603              * of aspect ratio change, we're screwed. --Meuuh
604              */
605 #if 0
606             p_dec->fmt_out.video.i_aspect =
607                 mpeg2_aspect[p_sys->i_aspect_ratio_info][0] *
608                 VOUT_ASPECT_FACTOR /
609                 mpeg2_aspect[p_sys->i_aspect_ratio_info][1];
610 #endif
611
612         }
613         else if( i_type == 0x08 )
614         {
615             /* picture extension */
616             p_sys->i_picture_structure = p_frag->p_buffer[6]&0x03;
617             p_sys->i_top_field_first   = p_frag->p_buffer[7] >> 7;
618             p_sys->i_repeat_first_field= (p_frag->p_buffer[7]>>1)&0x01;
619             p_sys->i_progressive_frame = p_frag->p_buffer[8] >> 7;
620         }
621     }
622     else if( p_frag->p_buffer[3] == 0x00 )
623     {
624         /* Picture start code */
625         p_sys->i_seq_old++;
626
627         if( p_frag->i_buffer >= 6 )
628         {
629             p_sys->i_temporal_ref =
630                 ( p_frag->p_buffer[4] << 2 )|(p_frag->p_buffer[5] >> 6);
631             p_sys->i_picture_type = ( p_frag->p_buffer[5] >> 3 ) & 0x03;
632         }
633
634         p_sys->i_dts = p_frag->i_dts;
635         p_sys->i_pts = p_frag->i_pts;
636     }
637     else if( p_frag->p_buffer[3] >= 0x01 && p_frag->p_buffer[3] <= 0xaf )
638     {
639         /* Slice start code */
640         p_sys->b_frame_slice = VLC_TRUE;
641     }
642
643     /* Append the block */
644     block_ChainLastAppend( &p_sys->pp_last, p_frag );
645
646     return p_pic;
647 }