system.c
来自「VLC媒体播放程序」· C语言 代码 · 共 1,499 行 · 第 1/4 页
C
1,499 行
/***************************************************************************** * system.c: helper module for TS, PS and PES management ***************************************************************************** * Copyright (C) 1998-2004 VideoLAN * $Id: system.c,v 1.31 2004/02/20 17:16:50 massiot Exp $ * * Authors: Christophe Massiot <massiot@via.ecp.fr> * Michel Lespinasse <walken@via.ecp.fr> * Beno顃 Steiner <benny@via.ecp.fr> * Sam Hocevar <sam@zoy.org> * Henri Fallon <henri@via.ecp.fr> * * 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>#include <vlc/vlc.h>#include <vlc/input.h>#include "system.h"/***************************************************************************** * Local prototypes *****************************************************************************/static int Activate ( vlc_object_t * );static ssize_t ReadPS ( input_thread_t *, data_packet_t ** );static es_descriptor_t * ParsePS ( input_thread_t *, data_packet_t * );static void DemuxPS ( input_thread_t *, data_packet_t * );static ssize_t ReadTS ( input_thread_t *, data_packet_t ** );static void DemuxTS ( input_thread_t *, data_packet_t *, psi_callback_t );/***************************************************************************** * Module descriptor *****************************************************************************/vlc_module_begin(); set_description( _("Generic ISO 13818-1 MPEG demultiplexing") ); set_capability( "mpeg-system", 100 ); set_callbacks( Activate, NULL );vlc_module_end();/***************************************************************************** * Activate: initializes helper functions *****************************************************************************/static int Activate ( vlc_object_t *p_this ){ static mpeg_demux_t mpeg_demux = { NULL, ReadPS, ParsePS, DemuxPS, ReadTS, DemuxTS }; mpeg_demux.cur_scr_time = -1; memcpy( p_this->p_private, &mpeg_demux, sizeof( mpeg_demux ) ); return VLC_SUCCESS;}/* * PES Packet management *//***************************************************************************** * MoveChunk ***************************************************************************** * Small utility function used to parse discontinuous headers safely. Copies * i_buf_len bytes of data to a buffer and returns the size copied. * It also solves some alignment problems on non-IA-32, non-PPC processors. * This is a variation on the theme of input_ext-dec.h:GetChunk(). *****************************************************************************/static inline size_t MoveChunk( byte_t * p_dest, data_packet_t ** pp_data_src, byte_t ** pp_src, size_t i_buf_len ){ size_t i_available; i_available = (ptrdiff_t)((*pp_data_src)->p_payload_end - *pp_src); if( i_available >= i_buf_len ) { if( p_dest != NULL ) memcpy( p_dest, *pp_src, i_buf_len ); *pp_src += i_buf_len; return( i_buf_len ); } else { size_t i_init_len = i_buf_len; do { if( p_dest != NULL ) memcpy( p_dest, *pp_src, i_available ); *pp_data_src = (*pp_data_src)->p_next; i_buf_len -= i_available; p_dest += i_available; if( *pp_data_src == NULL ) { *pp_src = NULL; return( i_init_len - i_buf_len ); } *pp_src = (*pp_data_src)->p_payload_start; i_available = (ptrdiff_t)((*pp_data_src)->p_payload_end - *pp_src); } while( i_available <= i_buf_len ); if( i_buf_len ) { if( p_dest != NULL ) memcpy( p_dest, *pp_src, i_buf_len ); *pp_src += i_buf_len; } return( i_init_len ); }}/***************************************************************************** * ParsePES ***************************************************************************** * Parse a finished PES packet and analyze its header. *****************************************************************************/#define PES_HEADER_SIZE 7static void ParsePES( input_thread_t * p_input, es_descriptor_t * p_es ){ data_packet_t * p_data; byte_t * p_byte; byte_t p_header[PES_HEADER_SIZE]; int i_done;#define p_pes (p_es->p_pes) /* Parse the header. The header has a variable length, but in order * to improve the algorithm, we will read the 14 bytes we may be * interested in */ p_data = p_pes->p_first; p_byte = p_data->p_payload_start; i_done = 0; if( MoveChunk( p_header, &p_data, &p_byte, PES_HEADER_SIZE ) != PES_HEADER_SIZE ) { msg_Warn( p_input, "PES packet too short to have a header" ); input_DeletePES( p_input->p_method_data, p_pes ); p_pes = NULL; return; } /* Get the PES size if defined */ p_es->i_pes_real_size = U16_AT(p_header + 4); if( p_es->i_pes_real_size ) { p_es->i_pes_real_size += 6; } /* First read the 6 header bytes common to all PES packets: * use them to test the PES validity */ if( (p_header[0] || p_header[1] || (p_header[2] != 1)) ) { /* packet_start_code_prefix != 0x000001 */ msg_Warn( p_input, "data loss, PES packet does not start with 000001" ); input_DeletePES( p_input->p_method_data, p_pes ); p_pes = NULL; } else { unsigned int i_pes_header_size, i_payload_size; if ( p_es->i_pes_real_size && (p_es->i_pes_real_size != p_pes->i_pes_size) ) { /* PES_packet_length is set and != total received payload */ /* Warn the decoder that the data may be corrupt. */ msg_Warn( p_input, "packet corrupted, PES sizes do not match" ); } switch( p_header[3] ) { case 0xBC: /* Program stream map */ case 0xBE: /* Padding */ case 0xBF: /* Private stream 2 */ case 0xB0: /* ECM */ case 0xB1: /* EMM */ case 0xFF: /* Program stream directory */ case 0xF2: /* DSMCC stream */ case 0xF8: /* ITU-T H.222.1 type E stream */ /* The payload begins immediately after the 6 bytes header, so * we have finished with the parsing */ i_pes_header_size = 6; break; default: if( (p_header[6] & 0xC0) == 0x80 ) { /* MPEG-2 : the PES header contains at least 3 more bytes. */ size_t i_max_len; vlc_bool_t b_has_pts, b_has_dts; byte_t p_full_header[12]; p_pes->b_data_alignment = p_header[6] & 0x04; i_max_len = MoveChunk( p_full_header, &p_data, &p_byte, 12 ); if( i_max_len < 2 ) { msg_Warn( p_input, "PES packet too short to have a MPEG-2 header" ); input_DeletePES( p_input->p_method_data, p_pes ); p_pes = NULL; return; } b_has_pts = p_full_header[0] & 0x80; b_has_dts = p_full_header[0] & 0x40; i_pes_header_size = p_full_header[1] + 9; /* Now parse the optional header extensions */ if( b_has_pts ) { if( i_max_len < 7 ) { msg_Warn( p_input, "PES packet too short to have a MPEG-2 header" ); input_DeletePES( p_input->p_method_data, p_pes ); p_pes = NULL; return; } p_pes->i_pts = input_ClockGetTS( p_input, p_es->p_pgrm, ( ((mtime_t)(p_full_header[2] & 0x0E) << 29) | ((mtime_t)(p_full_header[3]) << 22) | ((mtime_t)(p_full_header[4] & 0xFE) << 14) | ((mtime_t)p_full_header[5] << 7) | ((mtime_t)p_full_header[6] >> 1) ) ); if( b_has_dts ) { if( i_max_len < 12 ) { msg_Warn( p_input, "PES packet too short to have a MPEG-2 header" ); input_DeletePES( p_input->p_method_data, p_pes ); p_pes = NULL; return; } p_pes->i_dts = input_ClockGetTS( p_input, p_es->p_pgrm, ( ((mtime_t)(p_full_header[7] & 0x0E) << 29) | (((mtime_t)U16_AT(p_full_header + 8) << 14) - (1 << 14)) | ((mtime_t)U16_AT(p_full_header + 10) >> 1) ) ); } } } else { /* Probably MPEG-1 */ vlc_bool_t b_has_pts, b_has_dts; i_pes_header_size = 6; p_data = p_pes->p_first; p_byte = p_data->p_payload_start; /* Cannot fail because the previous one succeeded. */ MoveChunk( NULL, &p_data, &p_byte, 6 ); while( *p_byte == 0xFF && i_pes_header_size < 23 ) { i_pes_header_size++; if( MoveChunk( NULL, &p_data, &p_byte, 1 ) != 1 ) { msg_Warn( p_input, "PES packet too short to have a MPEG-1 header" ); input_DeletePES( p_input->p_method_data, p_pes ); p_pes = NULL; return; } } if( i_pes_header_size == 23 ) { msg_Warn( p_input, "too much MPEG-1 stuffing" ); input_DeletePES( p_input->p_method_data, p_pes ); p_pes = NULL; return; } if( (*p_byte & 0xC0) == 0x40 ) { /* Don't ask why... --Meuuh */ /* Erm... why ? --Sam */ /* Well... According to the recommendation, it is for * STD_buffer_scale and STD_buffer_size. --Meuuh */ i_pes_header_size += 2; if( MoveChunk( NULL, &p_data, &p_byte, 2 ) != 2 ) { msg_Warn( p_input, "PES packet too short to have a MPEG-1 header" ); input_DeletePES( p_input->p_method_data, p_pes ); p_pes = NULL; return; } } i_pes_header_size++; b_has_pts = *p_byte & 0x20; b_has_dts = *p_byte & 0x10; if( b_has_pts ) { byte_t p_ts[5]; i_pes_header_size += 4; if( MoveChunk( p_ts, &p_data, &p_byte, 5 ) != 5 ) { msg_Warn( p_input, "PES packet too short to have a MPEG-1 header" ); input_DeletePES( p_input->p_method_data, p_pes ); p_pes = NULL; return; } p_pes->i_pts = input_ClockGetTS( p_input, p_es->p_pgrm, ( ((mtime_t)(p_ts[0] & 0x0E) << 29) | (((mtime_t)U32_AT(p_ts) & 0xFFFE00) << 6) | ((mtime_t)p_ts[3] << 7) | ((mtime_t)p_ts[4] >> 1) ) ); if( b_has_dts ) { i_pes_header_size += 5; if( MoveChunk( p_ts, &p_data, &p_byte, 5 ) != 5 ) { msg_Warn( p_input, "PES packet too short to have a MPEG-1 header" ); input_DeletePES( p_input->p_method_data, p_pes ); p_pes = NULL; return; } p_pes->i_dts = input_ClockGetTS( p_input, p_es->p_pgrm, ( ((mtime_t)(p_ts[0] & 0x0E) << 29) | (((mtime_t)U32_AT(p_ts) & 0xFFFE00) << 6) | ((mtime_t)p_ts[3] << 7) | ((mtime_t)p_ts[4] >> 1) ) ); } } } break; } /* Welcome to the kludge area ! --Meuuh */ if ( p_es->i_fourcc == VLC_FOURCC('a','5','2','b') || p_es->i_fourcc == VLC_FOURCC('d','t','s','b') ) { /* With A/52 or DTS audio, we need to skip the first 4 bytes */ i_pes_header_size += 4; } if ( p_es->i_fourcc == VLC_FOURCC('l','p','c','b') || p_es->i_fourcc == VLC_FOURCC('s','p','u','b') || p_es->i_fourcc == VLC_FOURCC('s','d','d','b') )
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?