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