Adding support for multiple audio streams and removing annoying message from resample and format

git-svn-id: svn://svn.mplayerhq.hu/mplayer/trunk@7572 b3059339-0415-0410-9bf9-f77b7e298cf2
This commit is contained in:
anders 2002-10-01 12:53:30 +00:00
parent 5cc92f1a4e
commit 3ef4629545
4 changed files with 122 additions and 124 deletions

View File

@ -27,28 +27,6 @@ static af_info_t* filter_list[]={ \
NULL \
};
// Command line config switches
af_cfg_t af_cfg={\
0,\
0,\
0,\
0,\
NULL,\
};
// Initialization types
#define SLOW 1
#define FAST 2
#define FORCE 3
// The first and last filter in the list
static af_instance_t* first=NULL;
static af_instance_t* last=NULL;
// Storage for input and output data formats (set by init)
static af_data_t input;
static af_data_t output;
/* Find a filter in the static list of filters using it's name. This
function is used internally */
af_info_t* af_find(char*name)
@ -89,9 +67,9 @@ af_instance_t* af_create(char* name)
/* Create and insert a new filter of type name before the filter in the
argument. This function can be called during runtime, the return
value is the new filter */
af_instance_t* af_prepend(af_instance_t* af, char* name)
af_instance_t* af_prepend(af_stream_t* s, af_instance_t* af, char* name)
{
// Create the new filter and make sure it is ok
// Create the new filter and make sure it is OK
af_instance_t* new=af_create(name);
if(!new)
return NULL;
@ -102,18 +80,18 @@ af_instance_t* af_prepend(af_instance_t* af, char* name)
af->prev=new;
}
else
last=new;
s->last=new;
if(new->prev)
new->prev->next=new;
else
first=new;
s->first=new;
return new;
}
/* Create and insert a new filter of type name after the filter in the
argument. This function can be called during runtime, the return
value is the new filter */
af_instance_t* af_append(af_instance_t* af, char* name)
af_instance_t* af_append(af_stream_t* s, af_instance_t* af, char* name)
{
// Create the new filter and make sure it is OK
af_instance_t* new=af_create(name);
@ -126,16 +104,16 @@ af_instance_t* af_append(af_instance_t* af, char* name)
af->next=new;
}
else
first=new;
s->first=new;
if(new->next)
new->next->prev=new;
else
last=new;
s->last=new;
return new;
}
// Uninit and remove the filter "af"
void af_remove(af_instance_t* af)
void af_remove(af_stream_t* s, af_instance_t* af)
{
if(!af) return;
@ -143,11 +121,11 @@ void af_remove(af_instance_t* af)
if(af->prev)
af->prev->next=af->next;
else
first=af->next;
s->first=af->next;
if(af->next)
af->next->prev=af->prev;
else
last=af->prev;
s->last=af->prev;
// Uninitialize af and free memory
af->uninit(af);
@ -155,7 +133,7 @@ void af_remove(af_instance_t* af)
}
/* Reinitializes all filters downstream from the filter given in the argument */
int af_reinit(af_instance_t* af)
int af_reinit(af_stream_t* s, af_instance_t* af)
{
if(!af)
return AF_ERROR;
@ -166,7 +144,7 @@ int af_reinit(af_instance_t* af)
// Check if this is the first filter
if(!af->prev)
memcpy(&in,&input,sizeof(af_data_t));
memcpy(&in,&(s->input),sizeof(af_data_t));
else
memcpy(&in,af->prev->data,sizeof(af_data_t));
// Reset just in case...
@ -180,33 +158,33 @@ int af_reinit(af_instance_t* af)
case AF_FALSE:{ // Configuration filter is needed
af_instance_t* new = NULL;
// Insert channels filter
if((af->prev?af->prev->data->nch:input.nch) != in.nch){
if((af->prev?af->prev->data->nch:s->input.nch) != in.nch){
// Create channels filter
if(NULL == (new = af_prepend(af,"channels")))
if(NULL == (new = af_prepend(s,af,"channels")))
return AF_ERROR;
// Set number of output channels
if(AF_OK != (rv = new->control(new,AF_CONTROL_CHANNELS,&in.nch)))
return rv;
// Initialize channels filter
if(!new->prev)
memcpy(&in,&input,sizeof(af_data_t));
memcpy(&in,&(s->input),sizeof(af_data_t));
else
memcpy(&in,new->prev->data,sizeof(af_data_t));
if(AF_OK != (rv = new->control(new,AF_CONTROL_REINIT,&in)))
return rv;
}
// Insert format filter
if(((af->prev?af->prev->data->format:input.format) != in.format) ||
((af->prev?af->prev->data->bps:input.bps) != in.bps)){
if(((af->prev?af->prev->data->format:s->input.format) != in.format) ||
((af->prev?af->prev->data->bps:s->input.bps) != in.bps)){
// Create format filter
if(NULL == (new = af_prepend(af,"format")))
if(NULL == (new = af_prepend(s,af,"format")))
return AF_ERROR;
// Set output format
if(AF_OK != (rv = new->control(new,AF_CONTROL_FORMAT,&in)))
return rv;
// Initialize format filter
if(!new->prev)
memcpy(&in,&input,sizeof(af_data_t));
memcpy(&in,&(s->input),sizeof(af_data_t));
else
memcpy(&in,new->prev->data,sizeof(af_data_t));
if(AF_OK != (rv = new->control(new,AF_CONTROL_REINIT,&in)))
@ -219,15 +197,15 @@ int af_reinit(af_instance_t* af)
}
case AF_DETACH:{ // Filter is redundant and wants to be unloaded
af_instance_t* aft=af->prev;
af_remove(af);
af_remove(s,af);
if(aft)
af=aft;
else
af=first; // Restart configuration
af=s->first; // Restart configuration
break;
}
default:
mp_msg(MSGT_AFILTER,MSGL_ERR,"Reinit did not work, audio filter '%s' returned error code %i\n",af->info->name,rv);
mp_msg(MSGT_AFILTER,MSGL_ERR,"Reinitialization did not work, audio filter '%s' returned error code %i\n",af->info->name,rv);
return AF_ERROR;
}
af=af->next;
@ -237,9 +215,9 @@ int af_reinit(af_instance_t* af)
/* Find filter in the dynamic filter list using it's name This
function is used for finding already initialized filters */
af_instance_t* af_get(char* name)
af_instance_t* af_get(af_stream_t* s, char* name)
{
af_instance_t* af=first;
af_instance_t* af=s->first;
while(af->next != NULL){
if(!strcmp(af->info->name,name))
return af;
@ -249,27 +227,34 @@ af_instance_t* af_get(char* name)
}
// Uninit and remove all filters
void af_uninit()
void af_uninit(af_stream_t* s)
{
while(first)
af_remove(first);
while(s->first)
af_remove(s,s->first);
}
/* Init read configuration and create filter list accordingly. In and
out contains the format of the current movie and the formate of the
preferred output respectively */
int af_init(af_data_t* in, af_data_t* out)
/* Initialize the stream "s". This function creates a new filter list
if necessary according to the values set in input and output. Input
and output should contain the format of the current movie and the
formate of the preferred output respectively. The function is
reentrant i.e. if called with an already initialized stream the
stream will be reinitialized. The return value is 0 if success and
-1 if failure */
int af_init(af_stream_t* s)
{
int cfg=SLOW; // configuration type
int i=0;
// Sanity check
if(!s) return -1;
// Precaution in case caller is misbehaving
in->audio = out->audio = NULL;
in->len = out->len = 0;
s->input.audio = s->output.audio = NULL;
s->input.len = s->output.len = 0;
// Figure out how fast the machine is
if(af_cfg.force)
cfg=af_cfg.force;
if(s->cfg.force)
cfg=s->cfg.force;
else{
# if defined(HAVE_SSE) || defined(HAVE_3DNOWEX)
cfg=FAST;
@ -277,92 +262,91 @@ int af_init(af_data_t* in, af_data_t* out)
cfg=SLOW;
# endif
}
// Input and output configuration
memcpy(&input,in,sizeof(af_data_t));
memcpy(&output,out,sizeof(af_data_t));
// Check if this is the first call
if(!first){
if(!s->first){
// Add all filters in the list (if there are any)
if(!af_cfg.list){
if(!af_append(first,"dummy")) // To make automatic format conversion work
if(!s->cfg.list){ // To make automatic format conversion work
if(!af_append(s,s->first,"dummy"))
return -1;
}
else{
while(af_cfg.list[i]){
if(!af_append(last,af_cfg.list[i++]))
while(s->cfg.list[i]){
if(!af_append(s,s->last,s->cfg.list[i++]))
return -1;
}
}
}
// Init filters
if(AF_OK != af_reinit(first))
if(AF_OK != af_reinit(s,s->first))
return -1;
// Check output format
if(cfg!=FORCE){
af_instance_t* af = NULL; // New filter
// Check output frequency if not OK fix with resample
if(last->data->rate!=output.rate){
if(NULL==(af=af_get("resample"))){
if(s->last->data->rate!=s->output.rate){
if(NULL==(af=af_get(s,"resample"))){
if(cfg==SLOW){
if(!strcmp(first->info->name,"format"))
af = af_append(first,"resample");
if(!strcmp(s->first->info->name,"format"))
af = af_append(s,s->first,"resample");
else
af = af_prepend(first,"resample");
af = af_prepend(s,s->first,"resample");
}
else{
if(!strcmp(last->info->name,"format"))
af = af_prepend(last,"resample");
if(!strcmp(s->last->info->name,"format"))
af = af_prepend(s,s->last,"resample");
else
af = af_append(last,"resample");
af = af_append(s,s->last,"resample");
}
}
// Init the new filter
if(!af || (AF_OK != af->control(af,AF_CONTROL_RESAMPLE,&output.rate)))
if(!af || (AF_OK != af->control(af,AF_CONTROL_RESAMPLE,&(s->output.rate))))
return -1;
if(AF_OK != af_reinit(af))
if(AF_OK != af_reinit(s,af))
return -1;
}
// Check number of output channels fix if not OK
// If needed always inserted last -> easy to screw up other filters
if(last->data->nch!=output.nch){
if(!strcmp(last->info->name,"format"))
af = af_prepend(last,"channels");
if(s->last->data->nch!=s->output.nch){
if(!strcmp(s->last->info->name,"format"))
af = af_prepend(s,s->last,"channels");
else
af = af_append(last,"channels");
af = af_append(s,s->last,"channels");
// Init the new filter
if(!af || (AF_OK != af->control(af,AF_CONTROL_CHANNELS,&output.nch)))
if(!af || (AF_OK != af->control(af,AF_CONTROL_CHANNELS,&(s->output.nch))))
return -1;
if(AF_OK != af_reinit(af))
if(AF_OK != af_reinit(s,af))
return -1;
}
// Check output format fix if not OK
if((last->data->format != output.format) || (last->data->bps != output.bps)){
if(strcmp(last->info->name,"format"))
af = af_append(last,"format");
if((s->last->data->format != s->output.format) ||
(s->last->data->bps != s->output.bps)){
if(strcmp(s->last->info->name,"format"))
af = af_append(s,s->last,"format");
else
af = last;
af = s->last;
// Init the new filter
if(!af ||(AF_OK != af->control(af,AF_CONTROL_FORMAT,&output)))
if(!af ||(AF_OK != af->control(af,AF_CONTROL_FORMAT,&(s->output))))
return -1;
if(AF_OK != af_reinit(af))
if(AF_OK != af_reinit(s,af))
return -1;
}
// Re init again just in case
if(AF_OK != af_reinit(first))
if(AF_OK != af_reinit(s,s->first))
return -1;
if((last->data->format != output.format) || (last->data->bps != output.bps) ||
(last->data->nch!=output.nch) || (last->data->rate!=output.rate)){
if((s->last->data->format != s->output.format) ||
(s->last->data->bps != s->output.bps) ||
(s->last->data->nch != s->output.nch) ||
(s->last->data->rate != s->output.rate)) {
// Something is stuffed audio out will not work
mp_msg(MSGT_AFILTER,MSGL_ERR,"Unable to setup filter system can not meet sound-card demands, please report this error on MPlayer development mailing list. \n");
af_uninit();
af_uninit(s);
return -1;
}
}
@ -370,9 +354,9 @@ int af_init(af_data_t* in, af_data_t* out)
}
// Filter data chunk through the filters in the list
af_data_t* af_play(af_data_t* data)
af_data_t* af_play(af_stream_t* s, af_data_t* data)
{
af_instance_t* af=first;
af_instance_t* af=s->first;
// Iterate through all filters
do{
data=af->play(af,data);
@ -390,9 +374,9 @@ inline int af_lencalc(frac_t mul, int len){
/* Calculate how long the output from the filters will be given the
input length "len" */
int af_outputlen(int len)
int af_outputlen(af_stream_t* s, int len)
{
af_instance_t* af=first;
af_instance_t* af=s->first;
frac_t mul = {1,1};
// Iterate through all filters
do{
@ -406,9 +390,9 @@ int af_outputlen(int len)
/* Calculate how long the input to the filters should be to produce a
certain output length, i.e. the return value of this function is
the input length required to produce the output length "len". */
int af_inputlen(int len)
int af_inputlen(af_stream_t* s, int len)
{
af_instance_t* af=first;
af_instance_t* af=s->first;
frac_t mul = {1,1};
// Iterate through all filters
do{

View File

@ -47,6 +47,31 @@ typedef struct af_instance_s
the length of the buffer. */
}af_instance_t;
// Initialization types
#define SLOW 1
#define FAST 2
#define FORCE 3
// Configuration switches
typedef struct af_cfg_s{
int force; // Initialization type
char** list; /* list of names of plugins that are added to filter
list during first initialization of stream */
}af_cfg_t;
// Current audio stream
typedef struct af_stream_s
{
// The first and last filter in the list
af_instance_t* first;
af_instance_t* last;
// Storage for input and output data formats
af_data_t input;
af_data_t output;
// Cofiguration for this stream
af_cfg_t cfg;
}af_stream_t;
/*********************************************
// Control parameters
*/
@ -97,35 +122,28 @@ typedef struct af_instance_s
#define AF_NA -3
/*********************************************
// Command line configuration switches
*/
typedef struct af_cfg_s{
int rate;
int format;
int bps;
int force;
char** list;
}af_cfg_t;
// Export functions
/* Init read configuration and create filter list accordingly. In and
out contains the format of the current movie and the formate of the
prefered output respectively */
int af_init(af_data_t* in, af_data_t* out);
/* Initialize the stream "s". This function creates a new fileterlist
if nessesary according to the values set in input and output. Input
and output should contain the format of the current movie and the
formate of the preferred output respectively. The function is
reentreant i.e. if called wit an already initialized stream the
stream will be reinitialized. The return value is 0 if sucess and
-1 if failure */
int af_init(af_stream_t* s);
// Uninit and remove all filters
void af_uninit();
void af_uninit(af_stream_t* s);
// Filter data chunk through the filters in the list
af_data_t* af_play(af_data_t* data);
af_data_t* af_play(af_stream_t* s, af_data_t* data);
/* Calculate how long the output from the filters will be given the
input length "len" */
int af_outputlen(int len);
int af_outputlen(af_stream_t* s, int len);
/* Calculate how long the input to the filters should be to produce a
certain output length, i.e. the return value of this function is
the input length required to produce the output length "len". */
int af_inputlen(int len);
int af_inputlen(af_stream_t* s, int len);
@ -153,8 +171,4 @@ int af_lencalc(frac_t mul, int len);
#define max(a,b)(((a)>(b))?(a):(b))
#endif
#ifndef AUDIO_FILTER
extern af_cfg_t af_cfg;
#endif /* AUDIO_FILTER */
#endif

View File

@ -97,7 +97,7 @@ static int control(struct af_instance_s* af, int cmd, void* arg)
}
af->data->bps=((af_data_t*)arg)->bps;
mp_msg(MSGT_AFILTER,MSGL_STATUS,"[format] Changing number sample format to 0x%08X and/or bytes per sample to %i \n",af->data->format,af->data->bps);
mp_msg(MSGT_AFILTER,MSGL_V,"[format] Changing number sample format to 0x%08X and/or bytes per sample to %i \n",af->data->format,af->data->bps);
return AF_OK;
}
return AF_UNKNOWN;

View File

@ -277,7 +277,7 @@ static int control(struct af_instance_s* af, int cmd, void* arg)
}
af->data->rate=((int*)arg)[0];
mp_msg(MSGT_AFILTER,MSGL_STATUS,"[resample] Changing sample rate to %iHz\n",af->data->rate);
mp_msg(MSGT_AFILTER,MSGL_V,"[resample] Changing sample rate to %iHz\n",af->data->rate);
return AF_OK;
}
return AF_UNKNOWN;