📄 decoder.c
字号:
/***************************************************************************** * decoder.c: Functions for the management of decoders ***************************************************************************** * Copyright (C) 1999-2004 VideoLAN * $Id: decoder.c 10745 2005-04-19 15:59:57Z fenrir $ * * Authors: Christophe Massiot <massiot@via.ecp.fr> * Gildas Bazin <gbazin@videolan.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 <stdlib.h>#include <vlc/vlc.h>#include <vlc/decoder.h>#include <vlc/vout.h>#include <vlc/input.h>#include "stream_output.h"#include "input_internal.h"static decoder_t * CreateDecoder( input_thread_t *, es_format_t *, int );static void DeleteDecoder( decoder_t * );static int DecoderThread( decoder_t * );static int DecoderDecode( decoder_t * p_dec, block_t *p_block );/* Buffers allocation callbacks for the decoders */static aout_buffer_t *aout_new_buffer( decoder_t *, int );static void aout_del_buffer( decoder_t *, aout_buffer_t * );static picture_t *vout_new_buffer( decoder_t * );static void vout_del_buffer( decoder_t *, picture_t * );static void vout_link_picture( decoder_t *, picture_t * );static void vout_unlink_picture( decoder_t *, picture_t * );static subpicture_t *spu_new_buffer( decoder_t * );static void spu_del_buffer( decoder_t *, subpicture_t * );static es_format_t null_es_format = {0};struct decoder_owner_sys_t{ vlc_bool_t b_own_thread; int64_t i_preroll_end; input_thread_t *p_input; aout_instance_t *p_aout; aout_input_t *p_aout_input; vout_thread_t *p_vout; vout_thread_t *p_spu_vout; int i_spu_channel; sout_instance_t *p_sout; sout_packetizer_input_t *p_sout_input; /* Some decoders require already packetized data (ie. not truncated) */ decoder_t *p_packetizer; /* Current format in use by the output */ video_format_t video; audio_format_t audio; es_format_t sout; /* fifo */ block_fifo_t *p_fifo;};/** * Spawns a new decoder thread * * \param p_input the input thread * \param p_es the es descriptor * \return the spawned decoder object */decoder_t *input_DecoderNew( input_thread_t *p_input, es_format_t *fmt, vlc_bool_t b_force_decoder ){ decoder_t *p_dec = NULL; vlc_value_t val; /* If we are in sout mode, search for packetizer module */ if( p_input->p_sout && !b_force_decoder ) { /* Create the decoder configuration structure */ p_dec = CreateDecoder( p_input, fmt, VLC_OBJECT_PACKETIZER ); if( p_dec == NULL ) { msg_Err( p_input, "could not create packetizer" ); return NULL; } } else { /* Create the decoder configuration structure */ p_dec = CreateDecoder( p_input, fmt, VLC_OBJECT_DECODER ); if( p_dec == NULL ) { msg_Err( p_input, "could not create decoder" ); return NULL; } } if( !p_dec->p_module ) { msg_Err( p_dec, "no suitable decoder module for fourcc `%4.4s'.\n" "VLC probably does not support this sound or video format.", (char*)&p_dec->fmt_in.i_codec ); DeleteDecoder( p_dec ); vlc_object_destroy( p_dec ); return NULL; } if( p_input->p_sout && p_input->input.b_can_pace_control && !b_force_decoder ) { msg_Dbg( p_input, "stream out mode -> no decoder thread" ); p_dec->p_owner->b_own_thread = VLC_FALSE; } else { var_Get( p_input, "minimize-threads", &val ); p_dec->p_owner->b_own_thread = !val.b_bool; } if( p_dec->p_owner->b_own_thread ) { int i_priority; if( fmt->i_cat == AUDIO_ES ) i_priority = VLC_THREAD_PRIORITY_AUDIO; else i_priority = VLC_THREAD_PRIORITY_VIDEO; /* Spawn the decoder thread */ if( vlc_thread_create( p_dec, "decoder", DecoderThread, i_priority, VLC_FALSE ) ) { msg_Err( p_dec, "cannot spawn decoder thread \"%s\"", p_dec->p_module->psz_object_name ); module_Unneed( p_dec, p_dec->p_module ); DeleteDecoder( p_dec ); vlc_object_destroy( p_dec ); return NULL; } } return p_dec;}/** * Kills a decoder thread and waits until it's finished * * \param p_input the input thread * \param p_es the es descriptor * \return nothing */void input_DecoderDelete( decoder_t *p_dec ){ p_dec->b_die = VLC_TRUE; if( p_dec->p_owner->b_own_thread ) { /* Make sure the thread leaves the function by * sending it an empty block. */ block_t *p_block = block_New( p_dec, 0 ); input_DecoderDecode( p_dec, p_block ); vlc_thread_join( p_dec ); /* Don't module_Unneed() here because of the dll loader that wants * close() in the same thread than open()/decode() */ } else { /* Flush */ input_DecoderDecode( p_dec, NULL ); module_Unneed( p_dec, p_dec->p_module ); } /* Delete decoder configuration */ DeleteDecoder( p_dec ); /* Delete the decoder */ vlc_object_destroy( p_dec );}/** * Put a block_t in the decoder's fifo. * * \param p_dec the decoder object * \param p_block the data block */void input_DecoderDecode( decoder_t * p_dec, block_t *p_block ){ if( p_dec->p_owner->b_own_thread ) { if( p_dec->p_owner->p_input->b_out_pace_control ) { /* FIXME !!!!! */ while( !p_dec->b_die && !p_dec->b_error && p_dec->p_owner->p_fifo->i_depth > 10 ) { msleep( 1000 ); } } else if( p_dec->p_owner->p_fifo->i_size > 50000000 /* 50 MB */ ) { /* FIXME: ideally we would check the time amount of data * in the fifo instead of its size. */ msg_Warn( p_dec, "decoder/packetizer fifo full (data not " "consummed quickly enough), resetting fifo!" ); block_FifoEmpty( p_dec->p_owner->p_fifo ); } block_FifoPut( p_dec->p_owner->p_fifo, p_block ); } else { if( p_dec->b_error || (p_block && p_block->i_buffer <= 0) ) { if( p_block ) block_Release( p_block ); } else { DecoderDecode( p_dec, p_block ); } }}void input_DecoderDiscontinuity( decoder_t * p_dec ){ block_t *p_null; /* Empty the fifo */ if( p_dec->p_owner->b_own_thread ) { block_FifoEmpty( p_dec->p_owner->p_fifo ); } /* Send a special block */ p_null = block_New( p_dec, 128 ); p_null->i_flags |= BLOCK_FLAG_DISCONTINUITY; memset( p_null->p_buffer, 0, p_null->i_buffer ); input_DecoderDecode( p_dec, p_null );}vlc_bool_t input_DecoderEmpty( decoder_t * p_dec ){ if( p_dec->p_owner->b_own_thread && p_dec->p_owner->p_fifo->i_depth > 0 ) { return VLC_FALSE; } return VLC_TRUE;}void input_DecoderPreroll( decoder_t *p_dec, int64_t i_preroll_end ){ p_dec->p_owner->i_preroll_end = i_preroll_end;}#if 0/** * Create a NULL packet for padding in case of a data loss * * \param p_input the input thread * \param p_es es descriptor * \return nothing */static void input_NullPacket( input_thread_t * p_input, es_descriptor_t * p_es ){#if 0 block_t *p_block = block_New( p_input, PADDING_PACKET_SIZE ); if( p_block ) { memset( p_block->p_buffer, 0, PADDING_PACKET_SIZE ); p_block->i_flags |= BLOCK_FLAG_DISCONTINUITY; block_FifoPut( p_es->p_dec->p_owner->p_fifo, p_block ); }#endif}/** * Send a NULL packet to the decoders * * \param p_input the input thread * \return nothing */void input_EscapeDiscontinuity( input_thread_t * p_input ){#if 0 unsigned int i_es, i; for( i_es = 0; i_es < p_input->stream.i_selected_es_number; i_es++ ) { es_descriptor_t * p_es = p_input->stream.pp_selected_es[i_es]; if( p_es->p_dec != NULL ) { for( i = 0; i < PADDING_PACKET_NUMBER; i++ ) { input_NullPacket( p_input, p_es ); } } }#endif}/** * Send a NULL packet to the audio decoders * * \param p_input the input thread * \return nothing */void input_EscapeAudioDiscontinuity( input_thread_t * p_input ){#if 0 unsigned int i_es, i; for( i_es = 0; i_es < p_input->stream.i_selected_es_number; i_es++ ) { es_descriptor_t * p_es = p_input->stream.pp_selected_es[i_es]; if( p_es->p_dec != NULL && p_es->i_cat == AUDIO_ES ) { for( i = 0; i < PADDING_PACKET_NUMBER; i++ ) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -