📄 mpegvideo.c
字号:
/***************************************************************************** * mpegvideo.c: parse and packetize an MPEG1/2 video stream ***************************************************************************** * Copyright (C) 2001-2006 the VideoLAN team * $Id$ * * Authors: Laurent Aimar <fenrir@via.ecp.fr> * Eric Petit <titer@videolan.org> * Gildas Bazin <gbazin@videolan.org> * Jean-Paul Saman <jpsaman #_at_# m2x dot nl> * * 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., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA. *****************************************************************************//***************************************************************************** * Problem with this implementation: * * Although we should time-stamp each picture with a PTS, this isn't possible * with the current implementation. * The problem comes from the fact that for non-low-delay streams we can't * calculate the PTS of pictures used as backward reference. Even the temporal * reference number doesn't help here because all the pictures don't * necessarily have the same duration (eg. 3:2 pulldown). * * However this doesn't really matter as far as the MPEG muxers are concerned * because they allow having empty PTS fields. --gibalou *****************************************************************************//***************************************************************************** * Preamble *****************************************************************************/#ifdef HAVE_CONFIG_H# include "config.h"#endif#include <vlc_common.h>#include <vlc_plugin.h>#include <vlc_block.h>#include <vlc_codec.h>#include <vlc_block_helper.h>#include "../codec/cc.h"#define SYNC_INTRAFRAME_TEXT N_("Sync on Intra Frame")#define SYNC_INTRAFRAME_LONGTEXT N_("Normally the packetizer would " \ "sync on the next full frame. This flags instructs the packetizer " \ "to sync on the first Intra Frame found.")/***************************************************************************** * Module descriptor *****************************************************************************/static int Open ( vlc_object_t * );static void Close( vlc_object_t * );vlc_module_begin(); set_category( CAT_SOUT ); set_subcategory( SUBCAT_SOUT_PACKETIZER ); set_description( N_("MPEG-I/II video packetizer") ); set_capability( "packetizer", 50 ); set_callbacks( Open, Close ); add_bool( "packetizer-mpegvideo-sync-iframe", 0, NULL, SYNC_INTRAFRAME_TEXT, SYNC_INTRAFRAME_LONGTEXT, true );vlc_module_end();/***************************************************************************** * Local prototypes *****************************************************************************/static block_t *Packetize( decoder_t *, block_t ** );static block_t *ParseMPEGBlock( decoder_t *, block_t * );static block_t *GetCc( decoder_t *p_dec, bool pb_present[4] );struct decoder_sys_t{ /* * Input properties */ block_bytestream_t bytestream; int i_state; size_t i_offset; uint8_t p_startcode[3]; /* Sequence header and extension */ block_t *p_seq; block_t *p_ext; /* Current frame being built */ block_t *p_frame; block_t **pp_last; bool b_frame_slice; mtime_t i_pts; mtime_t i_dts; /* Sequence properties */ int i_frame_rate; int i_frame_rate_base; bool b_seq_progressive; bool b_low_delay; int i_aspect_ratio_info; bool b_inited; /* Picture properties */ int i_temporal_ref; int i_picture_type; int i_picture_structure; int i_top_field_first; int i_repeat_first_field; int i_progressive_frame; mtime_t i_interpolated_dts; mtime_t i_last_ref_pts; bool b_second_field; /* Number of pictures since last sequence header */ int i_seq_old; /* Sync behaviour */ bool b_sync_on_intra_frame; bool b_discontinuity; /* */ bool b_cc_reset; uint32_t i_cc_flags; mtime_t i_cc_pts; mtime_t i_cc_dts; cc_data_t cc;};enum { STATE_NOSYNC, STATE_NEXT_SYNC};/***************************************************************************** * Open: *****************************************************************************/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( 'm', 'p', 'g', '1' ) && p_dec->fmt_in.i_codec != VLC_FOURCC( 'm', 'p', 'g', '2' ) && p_dec->fmt_in.i_codec != VLC_FOURCC( 'm', 'p', 'g', 'v' ) ) { return VLC_EGENERIC; } es_format_Init( &p_dec->fmt_out, VIDEO_ES, VLC_FOURCC('m','p','g','v') ); p_dec->pf_packetize = Packetize; p_dec->pf_get_cc = GetCc; p_dec->p_sys = p_sys = malloc( sizeof( decoder_sys_t ) ); if( !p_dec->p_sys ) return VLC_ENOMEM; memset( p_dec->p_sys, 0, sizeof( decoder_sys_t ) ); /* Misc init */ p_sys->i_state = STATE_NOSYNC; p_sys->bytestream = block_BytestreamInit(); p_sys->p_startcode[0] = 0; p_sys->p_startcode[1] = 0; p_sys->p_startcode[2] = 1; p_sys->i_offset = 0; p_sys->p_seq = NULL; p_sys->p_ext = NULL; p_sys->p_frame = NULL; p_sys->pp_last = &p_sys->p_frame; p_sys->b_frame_slice = false; p_sys->i_dts = p_sys->i_pts = 0; p_sys->i_frame_rate = 1; p_sys->i_frame_rate_base = 1; p_sys->b_seq_progressive = true; p_sys->b_low_delay = true; p_sys->i_seq_old = 0; p_sys->i_temporal_ref = 0; p_sys->i_picture_type = 0; p_sys->i_picture_structure = 0x03; /* frame */ p_sys->i_top_field_first = 0; p_sys->i_repeat_first_field = 0; p_sys->i_progressive_frame = 0; p_sys->b_inited = 0; p_sys->i_interpolated_dts = 0; p_sys->i_last_ref_pts = 0; p_sys->b_second_field = 0; p_sys->b_discontinuity = false; p_sys->b_sync_on_intra_frame = var_CreateGetBool( p_dec, "packetizer-mpegvideo-sync-iframe" ); if( p_sys->b_sync_on_intra_frame ) msg_Dbg( p_dec, "syncing on intra frame now" ); p_sys->b_cc_reset = false; p_sys->i_cc_pts = 0; p_sys->i_cc_dts = 0; p_sys->i_cc_flags = 0; cc_Init( &p_sys->cc ); return VLC_SUCCESS;}/***************************************************************************** * Close: *****************************************************************************/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 ); if( p_sys->p_seq ) { block_Release( p_sys->p_seq ); } if( p_sys->p_ext ) { block_Release( p_sys->p_ext ); } if( p_sys->p_frame ) { block_ChainRelease( p_sys->p_frame ); } var_Destroy( p_dec, "packetizer-mpegvideo-sync-iframe" ); free( p_sys );}/***************************************************************************** * Packetize: *****************************************************************************/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 == NULL || *pp_block == NULL ) { return NULL; } if( (*pp_block)->i_flags&(BLOCK_FLAG_DISCONTINUITY|BLOCK_FLAG_CORRUPTED) ) { if( (*pp_block)->i_flags&BLOCK_FLAG_CORRUPTED ) { p_sys->i_state = STATE_NOSYNC; block_BytestreamFlush( &p_sys->bytestream ); p_sys->b_discontinuity = true; if( p_sys->p_frame ) block_ChainRelease( p_sys->p_frame ); p_sys->p_frame = NULL; p_sys->pp_last = &p_sys->p_frame; p_sys->b_frame_slice = false; }// p_sys->i_interpolated_dts =// p_sys->i_last_ref_pts = 0; block_Release( *pp_block ); return NULL; } block_BytestreamPush( &p_sys->bytestream, *pp_block ); while( 1 ) { switch( p_sys->i_state ) { case STATE_NOSYNC: if( block_FindStartcodeFromOffset( &p_sys->bytestream, &p_sys->i_offset, p_sys->p_startcode, 3 ) == VLC_SUCCESS ) { 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: /* TODO: If p_block == NULL, flush the buffer without checking the * next sync word */ /* Find the next startcode */ if( block_FindStartcodeFromOffset( &p_sys->bytestream, &p_sys->i_offset, p_sys->p_startcode, 3 ) != VLC_SUCCESS ) { /* Need more data */ return NULL; } /* Get the new fragment and set the pts/dts */ p_pic = block_New( p_dec, p_sys->i_offset ); block_BytestreamFlush( &p_sys->bytestream ); 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 ); /* don't reuse the same timestamps several times */ if( p_pic->i_buffer >= 4 && p_pic->p_buffer[3] == 0x00 ) { /* We have a picture start code */ p_sys->bytestream.p_block->i_pts = 0; p_sys->bytestream.p_block->i_dts = 0; } p_sys->i_offset = 0; /* Get picture if any */ if( !( p_pic = ParseMPEGBlock( p_dec, p_pic ) ) ) { p_sys->i_state = STATE_NOSYNC; break; } /* If a discontinuity has been encountered, then wait till * the next Intra frame before continuing with packetizing */ if( p_sys->b_discontinuity && p_sys->b_sync_on_intra_frame ) { if( p_pic->i_flags & BLOCK_FLAG_TYPE_I ) { msg_Dbg( p_dec, "synced on intra frame" ); p_sys->b_discontinuity = false; p_pic->i_flags |= BLOCK_FLAG_DISCONTINUITY; } else { msg_Dbg( p_dec, "waiting on intra frame" ); p_sys->i_state = STATE_NOSYNC; block_Release( p_pic );
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -