Mercurial > mplayer.hg
view libao2/ao_plugin.c @ 8843:c70444c5b516
I have seen problems where DVD subtitles don't display
at the right time and sometimes they don't appear at
all. The problem stems from the fact that subtitle
command packets are being applied as soon as they are
read and assembled from the input stream. Sometimes,
a fully assembled subtitle packet arrives at the
spudec_assemble function before the previous subtitle
appears onscreen and thus the viewer only sees the
second subtitle. So I created a patch that queues
assembled subtitle packets and applies them at the
appropriate time within the heartbeat function. The
reset function clears the packet queue when seeking
through the video.
Tomasz Farkas <tomasz_farkas@yahoo.co.uk>
author | arpi |
---|---|
date | Wed, 08 Jan 2003 18:36:36 +0000 |
parents | c4434bdf6e51 |
children | eaee773aee9c |
line wrap: on
line source
#include "../config.h" #include <stdio.h> #include <stdlib.h> #include <string.h> #include "afmt.h" #include "audio_out.h" #include "audio_out_internal.h" #include "audio_plugin.h" static ao_info_t info = { "Plugin audio output", "plugin", "Anders", "" }; LIBAO_EXTERN(plugin) #define plugin(i) (ao_plugin_local_data.plugins[i]) #define driver() (ao_plugin_local_data.driver) // local data typedef struct ao_plugin_local_data_s { void* buf; // Output data buffer int len; // Amount of data in buffer int channels; int format; int bpm; //bit of format float bps; // Bytes per second out ao_functions_t* driver; // Output driver ao_plugin_functions_t** plugins; // List of used plugins ao_plugin_functions_t* available_plugins[NPL]; // List of available plugins } ao_plugin_local_data_t; static ao_plugin_local_data_t ao_plugin_local_data={NULL,0,0,0,0,0.0,NULL,NULL,AO_PLUGINS}; // global data volatile ao_plugin_data_t ao_plugin_data; // Data used by the plugins ao_plugin_cfg_t ao_plugin_cfg=CFG_DEFAULTS; // Set in cfg-mplayer.h // to set/get/query special features/parameters static int control(int cmd,int arg){ switch(cmd){ case AOCONTROL_SET_PLUGIN_DRIVER: ao_plugin_local_data.driver=(ao_functions_t*)arg; return CONTROL_OK; case AOCONTROL_GET_VOLUME: case AOCONTROL_SET_VOLUME: { int r=audio_plugin_volume.control(cmd,arg); if(CONTROL_OK != r) return driver()->control(cmd,arg); else return r; } default: return driver()->control(cmd,arg); } return CONTROL_UNKNOWN; } // Recursive function for adding plugins // return 1 for success and 0 for error int add_plugin(int i,char* cfg){ int cnt=0; // Find end of plugin name while((cfg[cnt]!=',')&&(cfg[cnt]!='\0')&&(cnt<100)) cnt++; if(cnt >= 100) return 0; // Is this the last iteration or just another plugin if(cfg[cnt]=='\0'){ ao_plugin_local_data.plugins=malloc((i+2)*sizeof(ao_plugin_functions_t*)); if(ao_plugin_local_data.plugins){ ao_plugin_local_data.plugins[i+1]=NULL; // Find the plugin matching the cfg string name cnt=0; while(ao_plugin_local_data.available_plugins[cnt] && cnt<20){ if(0==strcmp(ao_plugin_local_data.available_plugins[cnt]->info->short_name,cfg)){ ao_plugin_local_data.plugins[i]=ao_plugin_local_data.available_plugins[cnt]; return 1; } cnt++; } printf("[plugin]: Invalid plugin: %s \n",cfg); return 0; } else return 0; } else { cfg[cnt]='\0'; if(add_plugin(i+1,&cfg[cnt+1])){ cnt=0; // Find the plugin matching the cfg string name while(ao_plugin_local_data.available_plugins[cnt] && cnt < 20){ if(0==strcmp(ao_plugin_local_data.available_plugins[cnt]->info->short_name,cfg)){ ao_plugin_local_data.plugins[i]=ao_plugin_local_data.available_plugins[cnt]; return 1; } cnt++; } printf("[plugin]: Invalid plugin: %s \n",cfg); return 0; } else return 0; } return 0; // Will never happen... } // open & setup audio device and plugins // return: 1=success 0=fail static int init(int rate,int channels,int format,int flags){ int use_plugin[NPL]; int x,npl,unused=0; int ok=1; char *config; // Create list of plugins from cfg option int i=0; if(ao_plugin_cfg.plugin_list){ config = malloc(strlen(ao_plugin_cfg.plugin_list)); if(!config) return 0; if(!strcpy(config, ao_plugin_cfg.plugin_list) || !add_plugin(i,config)){ free(config); return 0; } free(config); } /* Set input parameters and itterate through plugins each plugin changes the parameters according to its output */ ao_plugin_local_data.format=format; ao_plugin_local_data.channels=channels; ao_plugin_local_data.bpm=audio_out_format_bits(format); ao_plugin_data.rate=rate; ao_plugin_data.channels=channels; ao_plugin_data.format=format; ao_plugin_data.sz_mult=1; ao_plugin_data.sz_fix=0; ao_plugin_data.delay_mult=1; ao_plugin_data.delay_fix=0; for(i=0;i<NPL && plugin(i);i++){ use_plugin[i]=plugin(i)->init(); if(!use_plugin[i]) plugin(i)->uninit(); } npl=i; for(i=0;i<npl && plugin(i);i++) if(!use_plugin[i+unused]){ unused++; for(x=i;x<npl && plugin(x+1);x++) plugin(x)=plugin(x+1); plugin(x)=NULL; npl--; i--; } i=npl; // Calculate bps ao_plugin_local_data.bps=(float)(ao_plugin_data.rate * ao_plugin_data.channels); ao_plugin_local_data.bps*=audio_out_format_bits(ao_plugin_data.format)/8; // This should never happen but check anyway if(NULL==ao_plugin_local_data.driver) return 0; ok = driver()->init(ao_plugin_data.rate, ao_plugin_data.channels, ao_plugin_data.format, flags); if(!ok) return 0; /* Now that the driver is initialized we can calculate and set the input and output buffers for each plugin */ ao_plugin_data.len=driver()->get_space(); while((i>0) && ok) ok=plugin(--i)->control(AOCONTROL_PLUGIN_SET_LEN,0); if(!ok) return 0; // Allocate output buffer if(ao_plugin_local_data.buf) free(ao_plugin_local_data.buf); ao_plugin_local_data.buf=malloc(MAX_OUTBURST); if(!ao_plugin_local_data.buf) return 0; return 1; } // close audio device static void uninit(){ int i=0; driver()->uninit(); while(plugin(i)) plugin(i++)->uninit(); if(ao_plugin_local_data.plugins) free(ao_plugin_local_data.plugins); ao_plugin_local_data.plugins=NULL; if(ao_plugin_local_data.buf) free(ao_plugin_local_data.buf); ao_plugin_local_data.buf=NULL; } // stop playing and empty buffers (for seeking/pause) static void reset(){ int i=0; driver()->reset(); while(plugin(i)) plugin(i++)->reset(); ao_plugin_local_data.len=0; } // stop playing, keep buffers (for pause) static void audio_pause(){ driver()->pause(); } // resume playing, after audio_pause() static void audio_resume(){ driver()->resume(); } // return: how many bytes can be played without blocking static int get_space(){ double sz; int isz; sz=(double)(driver()->get_space()); if(sz+(double)ao_plugin_local_data.len > (double)MAX_OUTBURST) sz=(double)MAX_OUTBURST-(double)ao_plugin_local_data.len; sz*=ao_plugin_data.sz_mult; sz+=ao_plugin_data.sz_fix; isz=(int)(sz); isz-=isz%(ao_plugin_local_data.channels*ao_plugin_local_data.bpm/8); return isz; } // plays 'len' bytes of 'data' // return: number of bytes played static int play(void* data,int len,int flags){ int l,i=0; // Limit length to avoid over flow in plugins int tmp = get_space(); int ret_len =(tmp<len)?tmp:len; // keep all channels of each sample together ret_len -= ret_len % (ao_plugin_local_data.channels*ao_plugin_local_data.bpm/8); if(ret_len){ // Filter data ao_plugin_data.len=ret_len; ao_plugin_data.data=data; while(plugin(i)) plugin(i++)->play(); // Copy data to output buffer memcpy(ao_plugin_local_data.buf+ao_plugin_local_data.len, ao_plugin_data.data,ao_plugin_data.len); // Send data to output l=driver()->play(ao_plugin_local_data.buf, ao_plugin_data.len+ao_plugin_local_data.len,flags); // Save away unsent data ao_plugin_local_data.len=ao_plugin_data.len+ao_plugin_local_data.len-l; memcpy(ao_plugin_local_data.buf,ao_plugin_local_data.buf+l, ao_plugin_local_data.len); } return ret_len; } // return: delay in seconds between first and last sample in buffer static float get_delay(){ float delay=driver()->get_delay(); delay+=(float)ao_plugin_local_data.len/ao_plugin_local_data.bps; delay*=ao_plugin_data.delay_mult; delay+=ao_plugin_data.delay_fix; return delay; }