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 + -
显示快捷键?