📄 es_out.c
字号:
/***************************************************************************** * es_out.c: Es Out handler for input. ***************************************************************************** * Copyright (C) 2003-2004 VideoLAN * $Id: es_out.c 11036 2005-05-16 15:10:59Z gbazin $ * * Authors: 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 <stdlib.h>#include <vlc/vlc.h>#include <vlc/input.h>#include <vlc/decoder.h>#include "input_internal.h"#include "vlc_playlist.h"#include "iso_lang.h"/* FIXME we should find a better way than including that */#include "../misc/iso-639_def.h"/***************************************************************************** * Local prototypes *****************************************************************************/typedef struct{ /* Program ID */ int i_id; /* Number of es for this pgrm */ int i_es; vlc_bool_t b_selected; /* Clock for this program */ input_clock_t clock; char *psz_now_playing;} es_out_pgrm_t;struct es_out_id_t{ /* ES ID */ int i_id; es_out_pgrm_t *p_pgrm; /* */ int64_t i_preroll_end; /* Channel in the track type */ int i_channel; es_format_t fmt; char *psz_language; char *psz_language_code; decoder_t *p_dec;};struct es_out_sys_t{ input_thread_t *p_input; /* all programs */ int i_pgrm; es_out_pgrm_t **pgrm; es_out_pgrm_t **pp_selected_pgrm; /* --programs */ es_out_pgrm_t *p_pgrm; /* Master program */ /* all es */ int i_id; int i_es; es_out_id_t **es; /* mode gestion */ vlc_bool_t b_active; int i_mode; /* es count */ int i_audio; int i_video; int i_sub; /* es to select */ int i_audio_last; int i_sub_last; char **ppsz_audio_language; char **ppsz_sub_language; /* current main es */ es_out_id_t *p_es_audio; es_out_id_t *p_es_video; es_out_id_t *p_es_sub; /* delay */ int64_t i_audio_delay; int64_t i_spu_delay;};static es_out_id_t *EsOutAdd ( es_out_t *, es_format_t * );static int EsOutSend ( es_out_t *, es_out_id_t *, block_t * );static void EsOutDel ( es_out_t *, es_out_id_t * );static void EsOutSelect( es_out_t *out, es_out_id_t *es, vlc_bool_t b_force );static int EsOutControl( es_out_t *, int i_query, va_list );static void EsOutAddInfo( es_out_t *, es_out_id_t *es );static void EsSelect( es_out_t *out, es_out_id_t *es );static void EsUnselect( es_out_t *out, es_out_id_t *es, vlc_bool_t b_update );static char *LanguageGetName( const char *psz_code );static char *LanguageGetCode( const char *psz_lang );static char **LanguageSplit( const char *psz_langs );static int LanguageArrayIndex( char **ppsz_langs, char *psz_lang );/***************************************************************************** * input_EsOutNew: *****************************************************************************/es_out_t *input_EsOutNew( input_thread_t *p_input ){ es_out_t *out = malloc( sizeof( es_out_t ) ); es_out_sys_t *p_sys = malloc( sizeof( es_out_sys_t ) ); vlc_value_t val; int i; out->pf_add = EsOutAdd; out->pf_send = EsOutSend; out->pf_del = EsOutDel; out->pf_control = EsOutControl; out->p_sys = p_sys; p_sys->p_input = p_input; p_sys->b_active = VLC_FALSE; p_sys->i_mode = ES_OUT_MODE_AUTO; p_sys->i_pgrm = 0; p_sys->pgrm = NULL; p_sys->p_pgrm = NULL; p_sys->i_id = 0; p_sys->i_es = 0; p_sys->es = NULL; p_sys->i_audio = 0; p_sys->i_video = 0; p_sys->i_sub = 0; /* */ var_Get( p_input, "audio-track", &val ); p_sys->i_audio_last = val.i_int; var_Get( p_input, "sub-track", &val ); p_sys->i_sub_last = val.i_int; var_Get( p_input, "audio-language", &val ); p_sys->ppsz_audio_language = LanguageSplit(val.psz_string); if( p_sys->ppsz_audio_language ) { for( i = 0; p_sys->ppsz_audio_language[i]; i++ ) msg_Dbg( p_input, "select audio in language[%d] %s", i, p_sys->ppsz_audio_language[i] ); } if( val.psz_string ) free( val.psz_string ); var_Get( p_input, "sub-language", &val ); p_sys->ppsz_sub_language = LanguageSplit(val.psz_string); if( p_sys->ppsz_sub_language ) { for( i = 0; p_sys->ppsz_sub_language[i]; i++ ) msg_Dbg( p_input, "select subtitle in language[%d] %s", i, p_sys->ppsz_sub_language[i] ); } if( val.psz_string ) free( val.psz_string ); p_sys->p_es_audio = NULL; p_sys->p_es_video = NULL; p_sys->p_es_sub = NULL; p_sys->i_audio_delay= 0; p_sys->i_spu_delay = 0; return out;}/***************************************************************************** * input_EsOutDelete: *****************************************************************************/void input_EsOutDelete( es_out_t *out ){ es_out_sys_t *p_sys = out->p_sys; int i; for( i = 0; i < p_sys->i_es; i++ ) { if( p_sys->es[i]->p_dec ) { input_DecoderDelete( p_sys->es[i]->p_dec ); } if( p_sys->es[i]->psz_language ) free( p_sys->es[i]->psz_language ); if( p_sys->es[i]->psz_language_code ) free( p_sys->es[i]->psz_language_code ); es_format_Clean( &p_sys->es[i]->fmt ); free( p_sys->es[i] ); } if( p_sys->ppsz_audio_language ) { for( i = 0; p_sys->ppsz_audio_language[i]; i++ ) free( p_sys->ppsz_audio_language[i] ); free( p_sys->ppsz_audio_language ); } if( p_sys->ppsz_sub_language ) { for( i = 0; p_sys->ppsz_sub_language[i]; i++ ) free( p_sys->ppsz_sub_language[i] ); free( p_sys->ppsz_sub_language ); } if( p_sys->es ) free( p_sys->es ); for( i = 0; i < p_sys->i_pgrm; i++ ) { if( p_sys->pgrm[i]->psz_now_playing ) free( p_sys->pgrm[i]->psz_now_playing ); free( p_sys->pgrm[i] ); } if( p_sys->pgrm ) free( p_sys->pgrm ); free( p_sys ); free( out );}es_out_id_t *input_EsOutGetFromID( es_out_t *out, int i_id ){ int i; if( i_id < 0 ) { /* Special HACK, -i_id is tha cat of the stream */ return (es_out_id_t*)((uint8_t*)NULL-i_id); } for( i = 0; i < out->p_sys->i_es; i++ ) { if( out->p_sys->es[i]->i_id == i_id ) return out->p_sys->es[i]; } return NULL;}void input_EsOutDiscontinuity( es_out_t *out, vlc_bool_t b_audio ){ es_out_sys_t *p_sys = out->p_sys; int i; for( i = 0; i < p_sys->i_es; i++ ) { es_out_id_t *es = p_sys->es[i]; /* Send a dummy block to let decoder know that * there is a discontinuity */ if( es->p_dec && ( !b_audio || es->fmt.i_cat == AUDIO_ES ) ) { input_DecoderDiscontinuity( es->p_dec ); } }}void input_EsOutSetDelay( es_out_t *out, int i_cat, int64_t i_delay ){ es_out_sys_t *p_sys = out->p_sys; if( i_cat == AUDIO_ES ) p_sys->i_audio_delay = i_delay; else if( i_cat == SPU_ES ) p_sys->i_spu_delay = i_delay;}vlc_bool_t input_EsOutDecodersEmpty( es_out_t *out ){ es_out_sys_t *p_sys = out->p_sys; int i; for( i = 0; i < p_sys->i_es; i++ ) { es_out_id_t *es = p_sys->es[i]; if( es->p_dec && !input_DecoderEmpty( es->p_dec ) ) return VLC_FALSE; } return VLC_TRUE;}/***************************************************************************** * *****************************************************************************/static void EsOutESVarUpdate( es_out_t *out, es_out_id_t *es, vlc_bool_t b_delete ){ es_out_sys_t *p_sys = out->p_sys; input_thread_t *p_input = p_sys->p_input; vlc_value_t val, text; char *psz_var; if( es->fmt.i_cat == AUDIO_ES ) psz_var = "audio-es"; else if( es->fmt.i_cat == VIDEO_ES ) psz_var = "video-es"; else if( es->fmt.i_cat == SPU_ES ) psz_var = "spu-es"; else return; if( b_delete ) { val.i_int = es->i_id; var_Change( p_input, psz_var, VLC_VAR_DELCHOICE, &val, NULL ); var_SetBool( p_sys->p_input, "intf-change", VLC_TRUE ); return; } /* Get the number of ES already added */ var_Change( p_input, psz_var, VLC_VAR_CHOICESCOUNT, &val, NULL ); if( val.i_int == 0 ) { vlc_value_t val2; /* First one, we need to add the "Disable" choice */ val2.i_int = -1; text.psz_string = _("Disable"); var_Change( p_input, psz_var, VLC_VAR_ADDCHOICE, &val2, &text ); val.i_int++; } /* Take care of the ES description */ if( es->fmt.psz_description && *es->fmt.psz_description ) { if( es->psz_language && *es->psz_language ) { text.psz_string = malloc( strlen( es->fmt.psz_description) + strlen( es->psz_language ) + 10 ); sprintf( text.psz_string, "%s - [%s]", es->fmt.psz_description, es->psz_language ); } else text.psz_string = strdup( es->fmt.psz_description ); } else { if( es->psz_language && *es->psz_language ) { char *temp; text.psz_string = malloc( strlen( _("Track %i") )+ strlen( es->psz_language ) + 30 ); asprintf( &temp, _("Track %i"), val.i_int ); sprintf( text.psz_string, "%s - [%s]", temp, es->psz_language ); free( temp ); } else { text.psz_string = malloc( strlen( _("Track %i") ) + 20 ); sprintf( text.psz_string, _("Track %i"), val.i_int ); } } val.i_int = es->i_id; var_Change( p_input, psz_var, VLC_VAR_ADDCHOICE, &val, &text ); free( text.psz_string ); var_SetBool( p_sys->p_input, "intf-change", VLC_TRUE );}/* EsOutProgramSelect: * Select a program and update the object variable */static void EsOutProgramSelect( es_out_t *out, es_out_pgrm_t *p_pgrm ){ es_out_sys_t *p_sys = out->p_sys; input_thread_t *p_input = p_sys->p_input; vlc_value_t val; int i; if( p_sys->p_pgrm == p_pgrm ) return; /* Nothing to do */ if( p_sys->p_pgrm ) { es_out_pgrm_t *old = p_sys->p_pgrm; msg_Dbg( p_input, "unselecting program id=%d", old->i_id ); for( i = 0; i < p_sys->i_es; i++ ) { if( p_sys->es[i]->p_pgrm == old && p_sys->es[i]->p_dec && p_sys->i_mode != ES_OUT_MODE_ALL ) EsUnselect( out, p_sys->es[i], VLC_TRUE ); } p_sys->p_es_audio = NULL; p_sys->p_es_sub = NULL; p_sys->p_es_video = NULL; } msg_Dbg( p_input, "selecting program id=%d", p_pgrm->i_id ); /* Mark it selected */ p_pgrm->b_selected = VLC_TRUE; /* Switch master stream */ if( p_sys->p_pgrm && p_sys->p_pgrm->clock.b_master ) { p_sys->p_pgrm->clock.b_master = VLC_FALSE; } p_pgrm->clock.b_master = VLC_TRUE; p_sys->p_pgrm = p_pgrm; /* Update "program" */ val.i_int = p_pgrm->i_id; var_Change( p_input, "program", VLC_VAR_SETVALUE, &val, NULL ); /* Update "es-*" */ var_Change( p_input, "audio-es", VLC_VAR_CLEARCHOICES, NULL, NULL ); var_Change( p_input, "video-es", VLC_VAR_CLEARCHOICES, NULL, NULL ); var_Change( p_input, "spu-es", VLC_VAR_CLEARCHOICES, NULL, NULL ); for( i = 0; i < p_sys->i_es; i++ ) { if( p_sys->es[i]->p_pgrm == p_sys->p_pgrm ) EsOutESVarUpdate( out, p_sys->es[i], VLC_FALSE ); EsOutSelect( out, p_sys->es[i], VLC_FALSE ); } /* Update now playing if defined per program */ if( p_pgrm->psz_now_playing ) { char *psz_cat = malloc( strlen(_("Program")) + 10 ); sprintf( psz_cat, "%s %d", _("Program"), p_pgrm->i_id ); input_Control( p_input, INPUT_ADD_INFO, _("Meta-information"), VLC_META_NOW_PLAYING, "%s", p_pgrm->psz_now_playing ); free( psz_cat ); } var_SetBool( p_sys->p_input, "intf-change", VLC_TRUE );}/* EsOutAddProgram: * Add a program */static es_out_pgrm_t *EsOutProgramAdd( es_out_t *out, int i_group ){ es_out_sys_t *p_sys = out->p_sys; input_thread_t *p_input = p_sys->p_input; vlc_value_t val; es_out_pgrm_t *p_pgrm = malloc( sizeof( es_out_pgrm_t ) ); /* Init */ p_pgrm->i_id = i_group; p_pgrm->i_es = 0; p_pgrm->b_selected = VLC_FALSE; p_pgrm->psz_now_playing = NULL; input_ClockInit( &p_pgrm->clock, VLC_FALSE, p_input->input.i_cr_average ); /* Append it */ TAB_APPEND( p_sys->i_pgrm, p_sys->pgrm, p_pgrm ); /* Update "program" variable */ val.i_int = i_group; var_Change( p_input, "program", VLC_VAR_ADDCHOICE, &val, NULL ); if( i_group == var_GetInteger( p_input, "program" ) ) { EsOutProgramSelect( out, p_pgrm ); } else { var_SetBool( p_sys->p_input, "intf-change", VLC_TRUE ); } return p_pgrm;}/* EsOutDelProgram: * Delete a program */static int EsOutProgramDel( es_out_t *out, int i_group ){ es_out_sys_t *p_sys = out->p_sys; input_thread_t *p_input = p_sys->p_input; es_out_pgrm_t *p_pgrm = NULL; vlc_value_t val; int i; for( i = 0; i < p_sys->i_pgrm; i++ ) { if( p_sys->pgrm[i]->i_id == i_group ) { p_pgrm = p_sys->pgrm[i]; break; } } if( p_pgrm == NULL ) return VLC_EGENERIC; if( p_pgrm->i_es ) { msg_Dbg( p_input, "can't delete program %d which still has %i ES", i_group, p_pgrm->i_es ); return VLC_EGENERIC; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -