mirror of
https://github.com/mpv-player/mpv
synced 2025-02-17 13:17:13 +00:00
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:
parent
5cc92f1a4e
commit
3ef4629545
182
libaf/af.c
182
libaf/af.c
@ -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{
|
||||
|
60
libaf/af.h
60
libaf/af.h
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user