diff options
author | anders <anders@b3059339-0415-0410-9bf9-f77b7e298cf2> | 2002-11-12 12:33:56 +0000 |
---|---|---|
committer | anders <anders@b3059339-0415-0410-9bf9-f77b7e298cf2> | 2002-11-12 12:33:56 +0000 |
commit | 66f4e56389d97b61a4a17325201643ef6bd87e37 (patch) | |
tree | 2f8fd12c1e876b7abaeed2d8bf2d34bd0fa37493 /libaf/af_format.c | |
parent | 54a8a603fb418b675a08c6349dfc720939f6c37a (diff) | |
download | mpv-66f4e56389d97b61a4a17325201643ef6bd87e37.tar.bz2 mpv-66f4e56389d97b61a4a17325201643ef6bd87e37.tar.xz |
New features:
-- Support for runtime cpu detection
-- Stand alone compile of libaf
-- Unlimited number of channels (compiletime switch)
-- Sample format defined by bit-fields
-- New formats: float, A-Law and mu-law
-- Format conversion set in human readable format
i.e. format=4:us_be to set 32 bit unsigned big endian output
-- Format reporting in human readable format
-- Volume control has only one parameter for setting the volume
i.e. volume=-10.0:1:0:1 to set atenuation = -10dB
git-svn-id: svn://svn.mplayerhq.hu/mplayer/trunk@8168 b3059339-0415-0410-9bf9-f77b7e298cf2
Diffstat (limited to 'libaf/af_format.c')
-rw-r--r-- | libaf/af_format.c | 557 |
1 files changed, 356 insertions, 201 deletions
diff --git a/libaf/af_format.c b/libaf/af_format.c index d9ca5fd7e7..fb6e6d79f5 100644 --- a/libaf/af_format.c +++ b/libaf/af_format.c @@ -10,105 +10,184 @@ #include <inttypes.h> #include <limits.h> -#include "../config.h" -#include "../mp_msg.h" +#include "af.h" -#include "../libao2/afmt.h" -#include "af.h" +/* Functions used by play to convert the input audio to the correct + format */ + +/* The below includes retrives functions for converting to and from + ulaw and alaw */ +#include "af_format_ulaw.c" +#include "af_format_alaw.c" + +// Switch endianess +static void endian(void* in, void* out, int len, int bps); +// From singed to unsigned +static void si2us(void* in, void* out, int len, int bps); +// From unsinged to signed +static void us2si(void* in, void* out, int len, int bps); +// Change the number of bits per sample +static void change_bps(void* in, void* out, int len, int inbps, int outbps); +// From float to int signed +static void float2int(void* in, void* out, int len, int bps); +// From signed int to float +static void int2float(void* in, void* out, int len, int bps); + +// Convert from string to format +static int str2fmt(char* str) +{ + int format=0; + // Scan for endianess + if(strstr(str,"be") || strstr(str,"BE")) + format |= AF_FORMAT_BE; + else if(strstr(str,"le") || strstr(str,"LE")) + format |= AF_FORMAT_LE; + else + format |= AF_FORMAT_NE; + + // Scan for special formats + if(strstr(str,"mulaw") || strstr(str,"MULAW")){ + format |= AF_FORMAT_MU_LAW; return format; + } + if(strstr(str,"alaw") || strstr(str,"ALAW")){ + format |= AF_FORMAT_A_LAW; return format; + } + if(strstr(str,"ac3") || strstr(str,"AC3")){ + format |= AF_FORMAT_AC3; return format; + } + if(strstr(str,"mpeg2") || strstr(str,"MPEG2")){ + format |= AF_FORMAT_MPEG2; return format; + } + if(strstr(str,"imaadpcm") || strstr(str,"IMAADPCM")){ + format |= AF_FORMAT_IMA_ADPCM; return format; + } + + // Scan for int/float + if(strstr(str,"float") || strstr(str,"FLOAT")){ + format |= AF_FORMAT_F; return format; + } + else + format |= AF_FORMAT_I; + + // Scan for signed/unsigned + if(strstr(str,"unsigned") || strstr(str,"UNSIGNED")) + format |= AF_FORMAT_US; + else + format |= AF_FORMAT_SI; + + return format; +} -// Number of bits -#define B08 (0<<0) -#define B16 (1<<0) -#define B32 (2<<0) -#define NBITS_MASK (3<<0) - -// Endianess -#define BE (0<<2) // Big Endian -#define LE (1<<2) // Little Endian -#define END_MASK (1<<2) - -#if WORDS_BIGENDIAN // native endian of cpu -#define NE BE -#else -#define NE LE -#endif - -// Signed -#define US (0<<3) // Un Signed -#define SI (1<<3) // SIgned -#define SIGN_MASK (1<<3) - -int decode(int format) +/* Convert format to str input str is a buffer for the + converted string, size is the size of the buffer */ +static char* fmt2str(int format, char* str, size_t size) { - // Check input format - switch(format){ - case(AFMT_U8): - return LE|B08|US; - case(AFMT_S8): - return LE|B08|SI; break; - case(AFMT_S16_LE): - return LE|B16|SI; break; - case(AFMT_S16_BE): - return BE|B16|SI; break; - case(AFMT_U16_LE): - return LE|B16|US; break; - case(AFMT_U16_BE): - return BE|B16|US; break; - case(AFMT_S32_LE): - return LE|B32|SI; break; - case(AFMT_S32_BE): - return BE|B32|SI; break; - case(AFMT_IMA_ADPCM): - case(AFMT_MU_LAW): - case(AFMT_A_LAW): - case(AFMT_MPEG): - case(AFMT_AC3): - mp_msg(MSGT_AFILTER,MSGL_ERR,"[af_format] Input audio format not yet supported \n"); - return 0; - default: - //This can not happen .... - mp_msg(MSGT_AFILTER,MSGL_ERR,"Unrecognized input audio format\n"); - return 0; + int i=0; + // Print endinaness + if(AF_FORMAT_LE == (format & AF_FORMAT_END_MASK)) + i+=snprintf(str,size,"little endian "); + else + i+=snprintf(str,size,"big endian "); + + if(format & AF_FORMAT_SPECIAL_MASK){ + switch(format & AF_FORMAT_SPECIAL_MASK){ + case(AF_FORMAT_MU_LAW): + i+=snprintf(&str[i],size-i,"mu law "); break; + case(AF_FORMAT_A_LAW): + i+=snprintf(&str[i],size-i,"A law "); break; + case(AF_FORMAT_MPEG2): + i+=snprintf(&str[i],size-i,"MPEG 2 "); break; + case(AF_FORMAT_AC3): + i+=snprintf(&str[i],size-i,"AC3 "); break; + } } + else{ + // Point + if(AF_FORMAT_F == (format & AF_FORMAT_POINT_MASK)) + i+=snprintf(&str[i],size,"float "); + else{ + // Sign + if(AF_FORMAT_US == (format & AF_FORMAT_SIGN_MASK)) + i+=snprintf(&str[i],size-i,"unsigned "); + else + i+=snprintf(&str[i],size-i,"signed "); + i+=snprintf(&str[i],size,"int "); + } + } + return str; } // Initialization and runtime control static int control(struct af_instance_s* af, int cmd, void* arg) { switch(cmd){ - case AF_CONTROL_REINIT: + case AF_CONTROL_REINIT:{ + char buf1[256]; + char buf2[256]; // Make sure this filter isn't redundant - if(af->data->format == ((af_data_t*)arg)->format && af->data->bps == ((af_data_t*)arg)->bps) + if(af->data->format == ((af_data_t*)arg)->format && + af->data->bps == ((af_data_t*)arg)->bps) return AF_DETACH; + + // Sanity check for bytes per sample + if(((af_data_t*)arg)->bps != 4 && ((af_data_t*)arg)->bps != 2 && + ((af_data_t*)arg)->bps != 1){ + af_msg(AF_MSG_ERROR,"[format] The number of output bytes per sample must be 1, 2 or 4. Current value is %i \n",((af_data_t*)arg)->bps); + return AF_ERROR; + } + + // Check for unsupported formats + switch(((af_data_t*)arg)->format & AF_FORMAT_SPECIAL_MASK){ + case(AF_FORMAT_MPEG2): + case(AF_FORMAT_AC3): + af_msg(AF_MSG_ERROR,"[format] Sample format not yet supported \n"); + return AF_ERROR; + } + + af_msg(AF_MSG_VERBOSE,"[format] Changing sample format from %ibit %sto %ibit %s \n", + ((af_data_t*)arg)->bps*8,fmt2str(((af_data_t*)arg)->format,buf1,256), + af->data->bps*8,fmt2str(af->data->format,buf2,256)); af->data->rate = ((af_data_t*)arg)->rate; af->data->nch = ((af_data_t*)arg)->nch; af->mul.n = af->data->bps; af->mul.d = ((af_data_t*)arg)->bps; return AF_OK; + } case AF_CONTROL_COMMAND_LINE:{ - af_data_t d; - sscanf((char*)arg,"%i:%i",&(d.format),&(d.bps)); + af_data_t d={NULL,0,0,0,0,2}; + char str[256]; + sscanf((char*)arg,"%i:%s",&(d.bps),str); + // Convert string to format + d.format = str2fmt(str); + // Automatic correction of errors + switch(d.format & AF_FORMAT_SPECIAL_MASK){ + case(AF_FORMAT_A_LAW): + case(AF_FORMAT_MU_LAW): + d.bps=1; break; + case(AF_FORMAT_AC3): + d.bps=4; break; // I think + } + if(AF_FORMAT_F == (d.format & AF_FORMAT_POINT_MASK)) + d.bps=4; + return af->control(af,AF_CONTROL_FORMAT,&d); - } + } case AF_CONTROL_FORMAT: // Reinit must be called after this function has been called - // Sanity check for sample format - if(0 == ((int)af->setup=decode(((af_data_t*)arg)->format))) - return AF_ERROR; - af->data->format = ((af_data_t*)arg)->format; - - // Sanity check for bytes per sample - if(((af_data_t*)arg)->bps != 4 && ((af_data_t*)arg)->bps != 2 && ((af_data_t*)arg)->bps != 1){ - mp_msg(MSGT_AFILTER,MSGL_ERR,"[format] The number of output bytes per sample must be 1, 2 or 4. Current value is%i \n",((af_data_t*)arg)->bps); + // Check for unsupported formats + switch(((af_data_t*)arg)->format & AF_FORMAT_SPECIAL_MASK){ + case(AF_FORMAT_MPEG2): + case(AF_FORMAT_AC3): + af_msg(AF_MSG_ERROR,"[format] Sample format not yet supported \n"); return AF_ERROR; } - af->data->bps=((af_data_t*)arg)->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); + af->data->format = ((af_data_t*)arg)->format; + af->data->bps=((af_data_t*)arg)->bps; return AF_OK; } return AF_UNKNOWN; @@ -125,156 +204,86 @@ static void uninit(struct af_instance_s* af) // Filter data through filter static af_data_t* play(struct af_instance_s* af, af_data_t* data) { - af_data_t* l = af->data; // Local data - void* la = NULL; // Local audio - int lf = (int)af->setup; // Local format - af_data_t* c = data; // Current working data - void* ca = c->audio; // Current audio - int cf = decode(c->format); // Current format - register int i = 0; // Counter - int len = c->len>>(cf&NBITS_MASK); // Loop end + af_data_t* l = af->data; // Local data + af_data_t* c = data; // Current working data + int len = c->len/c->bps; // Lenght in samples of current audio block if(AF_OK != RESIZE_LOCAL_BUFFER(af,data)) return NULL; - la = l->audio; + // Change to cpu native endian format + if((c->format&AF_FORMAT_END_MASK)!=AF_FORMAT_NE) + endian(c->audio,c->audio,len,c->bps); - // Change to cpu native endian - if((cf&END_MASK)!=NE){ - switch(cf&NBITS_MASK){ - case(B16):{ - register uint16_t s; - for(i=0;i<len;i++){ - s=((uint16_t*)ca)[i]; - ((uint16_t*)ca)[i]=(uint16_t)(((s&0x00FF)<<8) | (s&0xFF00)>>8); - } - } + // Conversion table + switch(c->format & ~AF_FORMAT_END_MASK){ + case(AF_FORMAT_MU_LAW): + from_ulaw(c->audio, l->audio, len, l->bps, l->format&AF_FORMAT_POINT_MASK); + if(AF_FORMAT_A_LAW == (l->format&AF_FORMAT_SPECIAL_MASK)) + to_ulaw(l->audio, l->audio, len, 1, AF_FORMAT_SI); + if((l->format&AF_FORMAT_SIGN_MASK) == AF_FORMAT_US) + si2us(l->audio,l->audio,len,l->bps); break; - case(B32):{ - register uint32_t s; - for(i=0;i<len;i++){ - s=((uint32_t*)ca)[i]; - ((uint32_t*)ca)[i]=(uint32_t)(((s&0x000000FF)<<24) | ((s&0x0000FF00)<<8) | - ((s&0x00FF0000)>>8) | ((s&0xFF000000)>>24)); - } - } + case(AF_FORMAT_A_LAW): + from_alaw(c->audio, l->audio, len, l->bps, l->format&AF_FORMAT_POINT_MASK); + if(AF_FORMAT_A_LAW == (l->format&AF_FORMAT_SPECIAL_MASK)) + to_alaw(l->audio, l->audio, len, 1, AF_FORMAT_SI); + if((l->format&AF_FORMAT_SIGN_MASK) == AF_FORMAT_US) + si2us(l->audio,l->audio,len,l->bps); break; - } - } - - // Change signed/unsigned - if((cf&SIGN_MASK) != (lf&SIGN_MASK)){ - switch((cf&NBITS_MASK)){ - case(B08): - switch(cf&SIGN_MASK){ - case(US): - for(i=0;i<len;i++) - ((int8_t*)ca)[i]=(int8_t)(SCHAR_MIN+((int)((uint8_t*)ca)[i])); - break; - case(SI): - for(i=0;i<len;i++) - ((uint8_t*)ca)[i]=(uint8_t)(SCHAR_MAX+((int)((int8_t*)ca)[i])); - break; - } + case(AF_FORMAT_F): + float2int(c->audio, l->audio, len, l->bps); + switch(l->format&AF_FORMAT_SPECIAL_MASK){ + case(AF_FORMAT_MU_LAW): + to_ulaw(c->audio, l->audio, len, c->bps, c->format&AF_FORMAT_POINT_MASK); break; - case(B16): - switch(cf&SIGN_MASK){ - case(US): - for(i=0;i<len;i++) - ((int16_t*)ca)[i]=(int16_t)(SHRT_MIN+((int)((uint16_t*)ca)[i])); - break; - case(SI): - for(i=0;i<len;i++) - ((uint16_t*)ca)[i]=(uint16_t)(SHRT_MAX+((int)((int16_t*)ca)[i])); - break; - } + case(AF_FORMAT_A_LAW): + to_alaw(c->audio, l->audio, len, c->bps, c->format&AF_FORMAT_POINT_MASK); break; - case(B32): - switch(cf&SIGN_MASK){ - case(US): - for(i=0;i<len;i++) - ((int32_t*)ca)[i]=(int32_t)(INT_MIN+((uint32_t*)ca)[i]); - break; - case(SI): - for(i=0;i<len;i++) - ((uint32_t*)ca)[i]=(uint32_t)(INT_MAX+((int32_t*)ca)[i]); - break; - } + } + if((l->format&AF_FORMAT_SIGN_MASK) == AF_FORMAT_US) + si2us(l->audio,l->audio,len,l->bps); + break; + default: + // Input must be int + + // Change signed/unsigned + if((c->format&AF_FORMAT_SIGN_MASK) != (l->format&AF_FORMAT_SIGN_MASK)){ + if((c->format&AF_FORMAT_SIGN_MASK) == AF_FORMAT_US) + us2si(c->audio,c->audio,len,c->bps); + else + si2us(c->audio,c->audio,len,c->bps); + } + // Convert to special formats + switch(l->format&AF_FORMAT_SPECIAL_MASK){ + case(AF_FORMAT_MU_LAW): + to_ulaw(c->audio, l->audio, len, c->bps, c->format&AF_FORMAT_POINT_MASK); break; - } - } - // Change the number of bits - if((cf&NBITS_MASK) == (lf&NBITS_MASK)){ - memcpy(la,ca,c->len); - } else { - switch(cf&NBITS_MASK){ - case(B08): - switch(lf&NBITS_MASK){ - case(B16): - for(i=0;i<len;i++) - ((uint16_t*)la)[i]=((uint16_t)((uint8_t*)ca)[i])<<8; - break; - case(B32): - for(i=0;i<len;i++) - ((uint32_t*)la)[i]=((uint32_t)((uint8_t*)ca)[i])<<24; - break; - } + case(AF_FORMAT_A_LAW): + to_alaw(c->audio, l->audio, len, c->bps, c->format&AF_FORMAT_POINT_MASK); break; - case(B16): - switch(lf&NBITS_MASK){ - case(B08): - for(i=0;i<len;i++) - ((uint8_t*)la)[i]=(uint8_t)((((uint16_t*)ca)[i])>>8); - break; - case(B32): - for(i=0;i<len;i++) - ((uint32_t*)la)[i]=((uint32_t)((uint16_t*)ca)[i])<<16; - break; + default: + // Change to float + if(AF_FORMAT_F == (l->format&AF_FORMAT_POINT_MASK)) + int2float(c->audio, l->audio, len, c->bps); + else{ + // Change the number of bits + if(c->bps != l->bps) + change_bps(c->audio,l->audio,len,c->bps,l->bps); + else + c->audio = l->audio; } break; - case(B32): - switch(lf&NBITS_MASK){ - case(B08): - for(i=0;i<len;i++) - ((uint8_t*)la)[i]=(uint8_t)((((uint32_t*)ca)[i])>>24); - break; - case(B16): - for(i=0;i<len;i++) - ((uint16_t*)la)[i]=(uint16_t)((((uint32_t*)ca)[i])>>16); - break; - } - break; } } // Switch from cpu native endian to the correct endianess - if((lf&END_MASK)!=NE){ - switch(lf&NBITS_MASK){ - case(B16):{ - register uint16_t s; - for(i=0;i<len;i++){ - s=((uint16_t*)la)[i]; - ((uint16_t*)la)[i]=(uint16_t)(((s&0x00FF)<<8) | (s&0xFF00)>>8); - } - } - break; - case(B32):{ - register uint32_t s; - for(i=0;i<len;i++){ - s=((uint32_t*)la)[i]; - ((uint32_t*)la)[i]=(uint32_t)(((s&0x000000FF)<<24) | ((s&0x0000FF00)<<8) | - ((s&0x00FF0000)>>8) | ((s&0xFF000000)>>24)); - } - } - break; - } - } + if((l->format&AF_FORMAT_END_MASK)!=AF_FORMAT_NE) + endian(l->audio,l->audio,len,l->bps); // Set output data - - // Make sure no samples are lost - c->len = (c->len*l->bps)/c->bps; c->audio = l->audio; + c->len = len*l->bps; c->bps = l->bps; c->format = l->format; return c; @@ -303,3 +312,149 @@ af_info_t af_info_format = { AF_FLAGS_REENTRANT, open }; + +// Function implementations used by play +static void endian(void* in, void* out, int len, int bps) +{ + register int i; + switch(bps){ + case(2):{ + register uint16_t s; + for(i=0;i<len;i++){ + s=((uint16_t*)in)[i]; + ((uint16_t*)out)[i]=(uint16_t)(((s&0x00FF)<<8) | (s&0xFF00)>>8); + } + break; + } + case(4):{ + register uint32_t s; + for(i=0;i<len;i++){ + s=((uint32_t*)in)[i]; + ((uint32_t*)out)[i]=(uint32_t)(((s&0x000000FF)<<24) | + ((s&0x0000FF00)<<8) | + ((s&0x00FF0000)>>8) | + ((s&0xFF000000)>>24)); + } + break; + } + } +} + +static void si2us(void* in, void* out, int len, int bps) +{ + register int i; + switch(bps){ + case(1): + for(i=0;i<len;i++) + ((uint8_t*)out)[i]=(uint8_t)(SCHAR_MAX+((int)((int8_t*)in)[i])); + break; + case(2): + for(i=0;i<len;i++) + ((uint16_t*)out)[i]=(uint16_t)(SHRT_MAX+((int)((int16_t*)in)[i])); + break; + case(4): + for(i=0;i<len;i++) + ((uint32_t*)out)[i]=(uint32_t)(INT_MAX+((int32_t*)in)[i]); + break; + } +} + +static void us2si(void* in, void* out, int len, int bps) +{ + register int i; + switch(bps){ + case(1): + for(i=0;i<len;i++) + ((int8_t*)out)[i]=(int8_t)(SCHAR_MIN+((int)((uint8_t*)in)[i])); + break; + case(2): + for(i=0;i<len;i++) + ((int16_t*)out)[i]=(int16_t)(SHRT_MIN+((int)((uint16_t*)in)[i])); + break; + case(4): + for(i=0;i<len;i++) + ((int32_t*)out)[i]=(int32_t)(INT_MIN+((uint32_t*)in)[i]); + break; + } +} + +static void change_bps(void* in, void* out, int len, int inbps, int outbps) +{ + register int i; + switch(inbps){ + case(1): + switch(outbps){ + case(2): + for(i=0;i<len;i++) + ((uint16_t*)out)[i]=((uint16_t)((uint8_t*)in)[i])<<8; + break; + case(4): + for(i=0;i<len;i++) + ((uint32_t*)out)[i]=((uint32_t)((uint8_t*)in)[i])<<24; + break; + } + break; + case(2): + switch(outbps){ + case(1): + for(i=0;i<len;i++) + ((uint8_t*)out)[i]=(uint8_t)((((uint16_t*)in)[i])>>8); + break; + case(4): + for(i=0;i<len;i++) + ((uint32_t*)out)[i]=((uint32_t)((uint16_t*)in)[i])<<16; + break; + } + break; + case(4): + switch(outbps){ + case(1): + for(i=0;i<len;i++) + ((uint8_t*)out)[i]=(uint8_t)((((uint32_t*)in)[i])>>24); + break; + case(2): + for(i=0;i<len;i++) + ((uint16_t*)out)[i]=(uint16_t)((((uint32_t*)in)[i])>>16); + break; + } + break; + } +} + +static void float2int(void* in, void* out, int len, int bps) +{ + register int i; + switch(bps){ + case(1): + for(i=0;i<len;i++) + ((int8_t*)out)[i]=(int8_t)(SCHAR_MAX*((float*)in)[i]); + break; + case(2): + for(i=0;i<len;i++) + ((int16_t*)out)[i]=(int16_t)(SHRT_MAX*((float*)in)[i]); + break; + case(4): + for(i=0;i<len;i++) + ((int32_t*)out)[i]=(int32_t)(INT_MAX*((float*)in)[i]); + break; + } +} + +static void int2float(void* in, void* out, int len, int bps) +{ + register int i; + switch(bps){ + case(1): + for(i=0;i<len;i++) + ((float*)out)[i]=(1.0/SCHAR_MAX)*((float)((int8_t*)in)[i]); + break; + case(2): + for(i=0;i<len;i++) + ((float*)out)[i]=(1.0/SHRT_MAX)*((float)((int16_t*)in)[i]); + break; + case(4): + for(i=0;i<len;i++) + ((float*)out)[i]=(1.0/INT_MAX)*((float)((int32_t*)in)[i]); + break; + } +} |