1 /*****************************************************************************
2 * mpegvideo.c: parse and packetize an MPEG1/2 video stream
3 *****************************************************************************
4 * Copyright (C) 2001-2006 the VideoLAN team
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>
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.
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.
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 *****************************************************************************/
27 /*****************************************************************************
28 * Problem with this implementation:
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).
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 *****************************************************************************/
41 /*****************************************************************************
43 *****************************************************************************/
44 #include <stdlib.h> /* malloc(), free() */
47 #include <vlc_block.h>
48 #include <vlc_codec.h>
49 #include <vlc_block_helper.h>
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.")
56 /*****************************************************************************
58 *****************************************************************************/
59 static int Open ( vlc_object_t * );
60 static void Close( vlc_object_t * );
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 );
69 add_bool( "packetizer-mpegvideo-sync-iframe", 0, NULL, SYNC_INTRAFRAME_TEXT,
70 SYNC_INTRAFRAME_LONGTEXT, VLC_TRUE );
73 /*****************************************************************************
75 *****************************************************************************/
76 static block_t *Packetize( decoder_t *, block_t ** );
77 static block_t *ParseMPEGBlock( decoder_t *, block_t * );
84 block_bytestream_t bytestream;
87 uint8_t p_startcode[3];
89 /* Sequence header and extension */
93 /* Current frame being built */
97 vlc_bool_t b_frame_slice;
101 /* Sequence properties */
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;
109 /* Picture properties */
112 int i_picture_structure;
113 int i_top_field_first;
114 int i_repeat_first_field;
115 int i_progressive_frame;
117 mtime_t i_interpolated_dts;
118 mtime_t i_last_ref_pts;
119 vlc_bool_t b_second_field;
121 /* Number of pictures since last sequence header */
125 vlc_bool_t b_sync_on_intra_frame;
126 vlc_bool_t b_discontinuity;
134 /*****************************************************************************
136 *****************************************************************************/
137 static int Open( vlc_object_t *p_this )
139 decoder_t *p_dec = (decoder_t*)p_this;
140 decoder_sys_t *p_sys;
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' ) )
149 es_format_Init( &p_dec->fmt_out, VIDEO_ES, VLC_FOURCC('m','p','g','v') );
150 p_dec->pf_packetize = Packetize;
152 p_dec->p_sys = p_sys = malloc( sizeof( decoder_sys_t ) );
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;
164 p_sys->p_frame = NULL;
165 p_sys->pp_last = &p_sys->p_frame;
166 p_sys->b_frame_slice = VLC_FALSE;
168 p_sys->i_dts = p_sys->i_pts = 0;
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;
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;
184 p_sys->i_interpolated_dts = 0;
185 p_sys->i_last_ref_pts = 0;
186 p_sys->b_second_field = 0;
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" );
196 /*****************************************************************************
198 *****************************************************************************/
199 static void Close( vlc_object_t *p_this )
201 decoder_t *p_dec = (decoder_t*)p_this;
202 decoder_sys_t *p_sys = p_dec->p_sys;
204 block_BytestreamRelease( &p_sys->bytestream );
208 block_Release( p_sys->p_seq );
212 block_Release( p_sys->p_ext );
216 block_ChainRelease( p_sys->p_frame );
219 var_Destroy( p_dec, "packetizer-mpegvideo-sync-iframe" );
224 /*****************************************************************************
226 *****************************************************************************/
227 static block_t *Packetize( decoder_t *p_dec, block_t **pp_block )
229 decoder_sys_t *p_sys = p_dec->p_sys;
232 if( pp_block == NULL || *pp_block == NULL )
237 if( (*pp_block)->i_flags&(BLOCK_FLAG_DISCONTINUITY|BLOCK_FLAG_CORRUPTED) )
239 if( (*pp_block)->i_flags&BLOCK_FLAG_CORRUPTED )
241 p_sys->i_state = STATE_NOSYNC;
242 block_BytestreamFlush( &p_sys->bytestream );
244 p_sys->b_discontinuity = VLC_TRUE;
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;
251 // p_sys->i_interpolated_dts =
252 // p_sys->i_last_ref_pts = 0;
254 block_Release( *pp_block );
259 block_BytestreamPush( &p_sys->bytestream, *pp_block );
263 switch( p_sys->i_state )
267 if( block_FindStartcodeFromOffset( &p_sys->bytestream,
268 &p_sys->i_offset, p_sys->p_startcode, 3 ) == VLC_SUCCESS )
270 p_sys->i_state = STATE_NEXT_SYNC;
273 if( p_sys->i_offset )
275 block_SkipBytes( &p_sys->bytestream, p_sys->i_offset );
277 block_BytestreamFlush( &p_sys->bytestream );
280 if( p_sys->i_state != STATE_NEXT_SYNC )
286 p_sys->i_offset = 1; /* To find next startcode */
288 case STATE_NEXT_SYNC:
289 /* TODO: If p_block == NULL, flush the buffer without checking the
292 /* Find the next startcode */
293 if( block_FindStartcodeFromOffset( &p_sys->bytestream,
294 &p_sys->i_offset, p_sys->p_startcode, 3 ) != VLC_SUCCESS )
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;
306 block_GetBytes( &p_sys->bytestream, p_pic->p_buffer,
309 /* don't reuse the same timestamps several times */
310 if( p_pic->i_buffer >= 4 && p_pic->p_buffer[3] == 0x00 )
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;
319 /* Get picture if any */
320 if( !( p_pic = ParseMPEGBlock( p_dec, p_pic ) ) )
322 p_sys->i_state = STATE_NOSYNC;
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 )
331 if( p_pic->i_flags & BLOCK_FLAG_TYPE_I )
333 msg_Dbg( p_dec, "synced on intra frame" );
334 p_sys->b_discontinuity = VLC_FALSE;
335 p_pic->i_flags |= BLOCK_FLAG_DISCONTINUITY;
339 msg_Dbg( p_dec, "waiting on intra frame" );
340 p_sys->i_state = STATE_NOSYNC;
341 block_Release( p_pic );
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 )
351 msg_Dbg( p_dec, "need a starting pts/dts" );
352 p_sys->i_state = STATE_NOSYNC;
353 block_Release( p_pic );
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;
361 /* So p_block doesn't get re-added several times */
362 *pp_block = block_BytestreamPop( &p_sys->bytestream );
364 p_sys->i_state = STATE_NOSYNC;
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 )
376 decoder_sys_t *p_sys = p_dec->p_sys;
377 block_t *p_pic = NULL;
380 * Check if previous picture is finished
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 )
386 /* We have a picture but without a sequence header we can't
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;
395 else if( p_sys->b_frame_slice &&
396 (p_frag->p_buffer[3] == 0x00 || p_frag->p_buffer[3] > 0xaf) )
400 p_pic = block_ChainGather( p_sys->p_frame );
402 i_duration = (mtime_t)( 1000000 * p_sys->i_frame_rate_base /
403 p_sys->i_frame_rate );
405 if( !p_sys->b_seq_progressive && p_sys->i_picture_structure != 0x03 )
410 if( p_sys->b_seq_progressive )
412 if( p_sys->i_top_field_first == 0 &&
413 p_sys->i_repeat_first_field == 1 )
417 else if( p_sys->i_top_field_first == 1 &&
418 p_sys->i_repeat_first_field == 1 )
425 if( p_sys->i_picture_structure == 0x03 )
427 if( p_sys->i_progressive_frame && p_sys->i_repeat_first_field )
429 i_duration += i_duration / 2;
434 if( p_sys->b_low_delay || p_sys->i_picture_type == 0x03 )
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;
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;
448 if( !p_sys->b_second_field )
449 p_sys->i_last_ref_pts = p_sys->i_pts;
452 p_pic->i_dts = p_sys->i_interpolated_dts;
453 p_sys->i_interpolated_dts += i_duration;
455 /* Set PTS only if we have a B frame or if it comes from the stream */
456 if( p_sys->i_pts > 0 )
458 p_pic->i_pts = p_sys->i_pts;
460 else if( p_sys->i_picture_type == 0x03 )
462 p_pic->i_pts = p_pic->i_dts;
469 switch ( p_sys->i_picture_type )
472 p_pic->i_flags |= BLOCK_FLAG_TYPE_I;
475 p_pic->i_flags |= BLOCK_FLAG_TYPE_P;
478 p_pic->i_flags |= BLOCK_FLAG_TYPE_B;
482 p_pic->i_length = p_sys->i_interpolated_dts - p_pic->i_dts;
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);
490 p_sys->p_frame = NULL;
491 p_sys->pp_last = &p_sys->p_frame;
492 p_sys->b_frame_slice = VLC_FALSE;
494 if( p_sys->i_picture_structure != 0x03 )
496 p_sys->b_second_field = !p_sys->b_second_field;
500 p_sys->b_second_field = 0;
505 * Check info of current fragment
507 if( p_frag->p_buffer[3] == 0xb8 )
509 /* Group start code */
511 p_sys->i_seq_old > p_sys->i_frame_rate/p_sys->i_frame_rate_base )
513 /* Usefull for mpeg1: repeat sequence header every second */
514 block_ChainLastAppend( &p_sys->pp_last, block_Duplicate( p_sys->p_seq ) );
517 block_ChainLastAppend( &p_sys->pp_last, block_Duplicate( p_sys->p_ext ) );
520 p_sys->i_seq_old = 0;
523 else if( p_frag->p_buffer[3] == 0xb3 && p_frag->i_buffer >= 8 )
525 /* Sequence header code */
526 static const int code_to_frame_rate[16][2] =
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*/
533 /* Unofficial economy rates from libmpeg3 */
534 { 5, 1001 }, { 10, 1001 }, { 12, 1001 }, { 15, 1001 },
535 { 1, 1 }, { 1, 1 } /* invalid */
538 if( p_sys->p_seq ) block_Release( p_sys->p_seq );
539 if( p_sys->p_ext ) block_Release( p_sys->p_ext );
541 p_sys->p_seq = block_Duplicate( p_frag );
542 p_sys->i_seq_old = 0;
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;
551 /* TODO: MPEG1 aspect ratio */
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];
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;
560 p_sys->b_seq_progressive = VLC_TRUE;
561 p_sys->b_low_delay = VLC_TRUE;
563 if ( !p_sys->b_inited )
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 );
571 else if( p_frag->p_buffer[3] == 0xb5 )
573 int i_type = p_frag->p_buffer[4] >> 4;
575 /* Extension start code */
579 static const int mpeg2_aspect[16][2] =
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},
587 /* sequence extension */
588 if( p_sys->p_ext) block_Release( p_sys->p_ext );
589 p_sys->p_ext = block_Duplicate( p_frag );
591 if( p_frag->i_buffer >= 10 )
593 p_sys->b_seq_progressive =
594 p_frag->p_buffer[5]&0x08 ? VLC_TRUE : VLC_FALSE;
596 p_frag->p_buffer[9]&0x80 ? VLC_TRUE : VLC_FALSE;
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
606 p_dec->fmt_out.video.i_aspect =
607 mpeg2_aspect[p_sys->i_aspect_ratio_info][0] *
609 mpeg2_aspect[p_sys->i_aspect_ratio_info][1];
613 else if( i_type == 0x08 )
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;
622 else if( p_frag->p_buffer[3] == 0x00 )
624 /* Picture start code */
627 if( p_frag->i_buffer >= 6 )
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;
634 p_sys->i_dts = p_frag->i_dts;
635 p_sys->i_pts = p_frag->i_pts;
637 else if( p_frag->p_buffer[3] >= 0x01 && p_frag->p_buffer[3] <= 0xaf )
639 /* Slice start code */
640 p_sys->b_frame_slice = VLC_TRUE;
643 /* Append the block */
644 block_ChainLastAppend( &p_sys->pp_last, p_frag );