parse.c

来自「VLC媒体播放程序」· C语言 代码 · 共 673 行 · 第 1/2 页

C
673
字号
/***************************************************************************** * parse.c: SPU parser ***************************************************************************** * Copyright (C) 2000-2001 VideoLAN * $Id: parse.c,v 1.17 2004/01/27 22:51:39 hartman Exp $ * * Authors: Samuel Hocevar <sam@zoy.org> *          Laurent Aimar <fenrir@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 <vlc/vlc.h>#include <vlc/vout.h>#include <vlc/decoder.h>#include "spudec.h"/***************************************************************************** * Local prototypes. *****************************************************************************/static int  ParseControlSeq  ( decoder_t *, subpicture_t * );static int  ParseRLE         ( decoder_t *, subpicture_t * );static void DestroySPU       ( subpicture_t * );static void UpdateSPU        ( subpicture_t *, vlc_object_t * );static int  CropCallback     ( vlc_object_t *, char const *,                               vlc_value_t, vlc_value_t, void * );/***************************************************************************** * AddNibble: read a nibble from a source packet and add it to our integer. *****************************************************************************/static inline unsigned int AddNibble( unsigned int i_code,                                      uint8_t *p_src, int *pi_index ){    if( *pi_index & 0x1 )    {        return( i_code << 4 | ( p_src[(*pi_index)++ >> 1] & 0xf ) );    }    else    {        return( i_code << 4 | p_src[(*pi_index)++ >> 1] >> 4 );    }}/***************************************************************************** * ParsePacket: parse an SPU packet and send it to the video output ***************************************************************************** * This function parses the SPU packet and, if valid, sends it to the * video output. *****************************************************************************/void E_(ParsePacket)( decoder_t *p_dec){    decoder_sys_t *p_sys = p_dec->p_sys;    subpicture_t  *p_spu;    /* Allocate the subpicture internal data. */    p_spu = vout_CreateSubPicture( p_sys->p_vout, MEMORY_SUBPICTURE );    if( p_spu == NULL )    {        return;    }    /* Rationale for the "p_spudec->i_rle_size * 4": we are going to     * expand the RLE stuff so that we won't need to read nibbles later     * on. This will speed things up a lot. Plus, we'll only need to do     * this stupid interlacing stuff once. */    p_spu->p_sys = malloc( sizeof( subpicture_sys_t ) + 4*p_sys->i_rle_size );    /* Fill the p_spu structure */    vlc_mutex_init( p_dec, &p_spu->p_sys->lock );    p_spu->pf_render = E_(RenderSPU);    p_spu->pf_destroy = DestroySPU;    p_spu->p_sys->p_data = (uint8_t*)p_spu->p_sys + sizeof( subpicture_sys_t );    p_spu->p_sys->b_palette = VLC_FALSE;    p_spu->p_sys->pi_alpha[0] = 0x00;    p_spu->p_sys->pi_alpha[1] = 0x0f;    p_spu->p_sys->pi_alpha[2] = 0x0f;    p_spu->p_sys->pi_alpha[3] = 0x0f;    p_spu->p_sys->b_crop = VLC_FALSE;    /* Get display time now. If we do it later, we may miss the PTS. */    p_spu->p_sys->i_pts = p_sys->i_pts;    /* Attach to our input thread */    p_spu->p_sys->p_input = vlc_object_find( p_dec,                                             VLC_OBJECT_INPUT, FIND_PARENT );    if( p_spu->p_sys->p_input )    {        vlc_value_t val;        if( !var_Get( p_spu->p_sys->p_input, "highlight-mutex", &val ) )        {            vlc_mutex_t *p_mutex = val.p_address;            vlc_mutex_lock( p_mutex );            UpdateSPU( p_spu, VLC_OBJECT(p_spu->p_sys->p_input) );            var_AddCallback( p_spu->p_sys->p_input,                             "highlight", CropCallback, p_spu );            vlc_mutex_unlock( p_mutex );        }    }    /* Getting the control part */    if( ParseControlSeq( p_dec, p_spu ) )    {        /* There was a parse error, delete the subpicture */        vout_DestroySubPicture( p_sys->p_vout, p_spu );        return;    }     /* We try to display it */    if( ParseRLE( p_dec, p_spu ) )    {        /* There was a parse error, delete the subpicture */        vout_DestroySubPicture( p_sys->p_vout, p_spu );        return;    }    msg_Dbg( p_dec, "total size: 0x%x, RLE offsets: 0x%x 0x%x",             p_sys->i_spu_size,             p_spu->p_sys->pi_offset[0], p_spu->p_sys->pi_offset[1] );    /* SPU is finished - we can ask the video output to display it */    vout_DisplaySubPicture( p_sys->p_vout, p_spu );    /* TODO: do stuff! */}/***************************************************************************** * ParseControlSeq: parse all SPU control sequences ***************************************************************************** * This is the most important part in SPU decoding. We get dates, palette * information, coordinates, and so on. For more information on the * subtitles format, see http://sam.zoy.org/doc/dvd/subtitles/index.html *****************************************************************************/static int ParseControlSeq( decoder_t *p_dec, subpicture_t * p_spu ){    decoder_sys_t *p_sys = p_dec->p_sys;    /* Our current index in the SPU packet */    unsigned int i_index = p_sys->i_rle_size + 4;    /* The next start-of-control-sequence index and the previous one */    unsigned int i_next_seq = 0, i_cur_seq = 0;    /* Command and date */    uint8_t i_command = SPU_CMD_END;    mtime_t date = 0;    unsigned int i, pi_alpha[4];    /* Initialize the structure */    p_spu->i_start = p_spu->i_stop = 0;    p_spu->b_ephemer = VLC_FALSE;    do    {        if( (int)i_index >= p_sys->i_spu_size + 1 )        {            /* sanity             * XXX only on test by loop as p_sys->buffer is bigger than needed             * to avoid checking at each access             */            break;        }        /* If we just read a command sequence, read the next one;         * otherwise, go on with the commands of the current sequence. */        if( i_command == SPU_CMD_END )        {            /* Get the control sequence date */            date = (mtime_t)GetWBE( &p_sys->buffer[i_index] ) * 11000;            /* FIXME How to access i_rate                    * p_spudec->bit_stream.p_pes->i_rate / DEFAULT_RATE;            */            /* Next offset */            i_cur_seq = i_index;            i_next_seq = GetWBE( &p_sys->buffer[i_index+2] );            /* Skip what we just read */            i_index += 4;        }        i_command = p_sys->buffer[i_index++];        switch( i_command )        {        case SPU_CMD_FORCE_DISPLAY: /* 00 (force displaying) */            p_spu->i_start = p_spu->p_sys->i_pts + date;            p_spu->b_ephemer = VLC_TRUE;            break;        /* Convert the dates in seconds to PTS values */        case SPU_CMD_START_DISPLAY: /* 01 (start displaying) */            p_spu->i_start = p_spu->p_sys->i_pts + date;            break;        case SPU_CMD_STOP_DISPLAY: /* 02 (stop displaying) */            p_spu->i_stop = p_spu->p_sys->i_pts + date;            break;        case SPU_CMD_SET_PALETTE:            /* 03xxxx (palette) */            if( p_dec->fmt_in.subs.spu.palette[0] == 0xBeeF )            {                unsigned int idx[4];                p_spu->p_sys->b_palette = VLC_TRUE;                idx[0] = (p_sys->buffer[i_index+0]>>4)&0x0f;                idx[1] = (p_sys->buffer[i_index+0])&0x0f;                idx[2] = (p_sys->buffer[i_index+1]>>4)&0x0f;                idx[3] = (p_sys->buffer[i_index+1])&0x0f;                for( i = 0; i < 4 ; i++ )                {                    uint32_t i_color = p_dec->fmt_in.subs.spu.palette[1+idx[i]];                    /* FIXME: this job should be done sooner */                    p_spu->p_sys->pi_yuv[3-i][0] = (i_color>>16) & 0xff;                    p_spu->p_sys->pi_yuv[3-i][1] = (i_color>>0) & 0xff;                    p_spu->p_sys->pi_yuv[3-i][2] = (i_color>>8) & 0xff;                }            }            i_index += 2;            break;        case SPU_CMD_SET_ALPHACHANNEL: /* 04xxxx (alpha channel) */            pi_alpha[3] = (p_sys->buffer[i_index+0]>>4)&0x0f;            pi_alpha[2] = (p_sys->buffer[i_index+0])&0x0f;            pi_alpha[1] = (p_sys->buffer[i_index+1]>>4)&0x0f;            pi_alpha[0] = (p_sys->buffer[i_index+1])&0x0f;            /* Ignore blank alpha palette. Sometimes spurious blank             * alpha palettes are present - dunno why. */            if( pi_alpha[0] | pi_alpha[1] | pi_alpha[2] | pi_alpha[3] )            {                p_spu->p_sys->pi_alpha[0] = pi_alpha[0];                p_spu->p_sys->pi_alpha[1] = pi_alpha[1];                p_spu->p_sys->pi_alpha[2] = pi_alpha[2];                p_spu->p_sys->pi_alpha[3] = pi_alpha[3];            }            else            {                msg_Warn( p_dec, "ignoring blank alpha palette" );            }            i_index += 2;            break;        case SPU_CMD_SET_COORDINATES: /* 05xxxyyyxxxyyy (coordinates) */            p_spu->i_x = (p_sys->buffer[i_index+0]<<4)|                         ((p_sys->buffer[i_index+1]>>4)&0x0f);            p_spu->i_width = (((p_sys->buffer[i_index+1]&0x0f)<<8)|                              p_sys->buffer[i_index+2]) - p_spu->i_x + 1;            p_spu->i_y = (p_sys->buffer[i_index+3]<<4)|                         ((p_sys->buffer[i_index+4]>>4)&0x0f);            p_spu->i_height = (((p_sys->buffer[i_index+4]&0x0f)<<8)|                              p_sys->buffer[i_index+5]) - p_spu->i_y + 1;                        i_index += 6;            break;        case SPU_CMD_SET_OFFSETS: /* 06xxxxyyyy (byte offsets) */            p_spu->p_sys->pi_offset[0] = GetWBE(&p_sys->buffer[i_index+0]) - 4;            p_spu->p_sys->pi_offset[1] = GetWBE(&p_sys->buffer[i_index+2]) - 4;            i_index += 4;            break;        case SPU_CMD_END: /* ff (end) */            break;        default: /* xx (unknown command) */            msg_Warn( p_dec, "unknown command 0x%.2x", i_command );            return VLC_EGENERIC;        }        /* We need to check for quit commands here */        if( p_dec->b_die )        {            return VLC_EGENERIC;        }    } while( i_command != SPU_CMD_END || i_index == i_next_seq );    /* Check that the next sequence index matches the current one */    if( i_next_seq != i_cur_seq )    {        msg_Err( p_dec, "index mismatch (0x%.4x != 0x%.4x)",                 i_next_seq, i_cur_seq );        return VLC_EGENERIC;    }    if( (int)i_index > p_sys->i_spu_size )    {        msg_Err( p_dec, "uh-oh, we went too far (0x%.4x > 0x%.4x)",                 i_index, p_sys->i_spu_size );        return VLC_EGENERIC;    }    if( !p_spu->i_start )    {        msg_Err( p_dec, "no `start display' command" );    }    if( p_spu->i_stop <= p_spu->i_start && !p_spu->b_ephemer )    {        /* This subtitle will live for 5 seconds or until the next subtitle */        p_spu->i_stop = p_spu->i_start + (mtime_t)500 * 11000;        /* FIXME how to access i_rate ?                        * p_spudec->bit_stream.p_pes->i_rate / DEFAULT_RATE;

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?