view libao2/ao_plugin.c @ 3639:64ee21b3bd09

Modified the sync code once again, commented out hardware pts sync (I'll likely burn in hell before understanding how to get this bastard to sync well) Added automagic setup of aspect ratio, will remove the "aspect-bug" (I hope). As well as please you rich 16:9 doods ;)
author mswitch
date Thu, 20 Dec 2001 20:50:35 +0000
parents 9eaee0d257e1
children 2cc5737ec923
line wrap: on
line source

#include <stdio.h>
#include <stdlib.h>

#include "../config.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
{
  ao_functions_t* driver;      // Output driver set in mplayer.c
  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,NULL,AO_PLUGINS};

// gloabal data 
volatile ao_plugin_data_t ao_plugin_data; // data used by the plugins
volatile ao_plugin_cfg_t  ao_plugin_cfg=CFG_DEFAULTS;  // cfg data 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;
  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 itteration or just another plugin
  if(cfg[cnt]=='\0'){
    ao_plugin_local_data.plugins=malloc((i+1)*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 ok=1;

  /* Create list of plugins from cfg option */
  int i=0; 
  if(ao_plugin_cfg.plugin_list){
    if(!add_plugin(i,ao_plugin_cfg.plugin_list))
      return 0;
  }

  /* Set input parameters and itterate through plugins each plugin
     changes the parameters according to its output */
  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;
  i=0;
  while(plugin(i)&&ok)
    ok=plugin(i++)->init();
  
  if(!ok) return 0;

  // 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;

  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);
}

// stop playing and empty buffers (for seeking/pause)
static void reset(){
  int i=0;
  driver()->reset();
  while(plugin(i))
    plugin(i++)->reset();
}

// 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=(double)(driver()->get_space());
  sz*=ao_plugin_data.sz_mult;
  sz+=ao_plugin_data.sz_fix;
  return (int)(sz);
}

// plays 'len' bytes of 'data'
// return: number of bytes played
static int play(void* data,int len,int flags){
  int i=0;
  /* Due to constant buffer sizes in plugins limit length */
  int tmp = get_space();
  int ret_len =(tmp<len)?tmp:len;
  /* Filter data */
  ao_plugin_data.len=ret_len;  
  ao_plugin_data.data=data;
  while(plugin(i))
    plugin(i++)->play();
  /* Send data to output */
  //fprintf(stderr, "ao_plugin: ret_len=%d, len=%d\n", ret_len, len);
  len=driver()->play(ao_plugin_data.data,ao_plugin_data.len,flags);
  //fprintf(stderr, "ao_plugin: returned len=%d\n", len);

  if(len!=ao_plugin_data.len)
    fprintf(stderr,"[ao_plugin] Warning under or over flow in sound plugin\n");
  
  return ret_len;
}

// return: delay in seconds between first and last sample in buffer
static float get_delay(){
  float delay=driver()->get_delay();
  delay*=ao_plugin_data.delay_mult;
  delay+=ao_plugin_data.delay_fix;
  return delay;
}