diff options
author | anders <anders@b3059339-0415-0410-9bf9-f77b7e298cf2> | 2002-10-01 06:45:08 +0000 |
---|---|---|
committer | anders <anders@b3059339-0415-0410-9bf9-f77b7e298cf2> | 2002-10-01 06:45:08 +0000 |
commit | 1f6c494641c4ca99eec7a9f47818526c72789439 (patch) | |
tree | 17bf220c1c1ac1144dfa8212f09444e51c248a26 /libaf/af_format.c | |
parent | c0091278d8f15580eecebfc8c454fba250cf4b94 (diff) | |
download | mpv-1f6c494641c4ca99eec7a9f47818526c72789439.tar.bz2 mpv-1f6c494641c4ca99eec7a9f47818526c72789439.tar.xz |
Adding new audio output filter layer libaf
git-svn-id: svn://svn.mplayerhq.hu/mplayer/trunk@7569 b3059339-0415-0410-9bf9-f77b7e298cf2
Diffstat (limited to 'libaf/af_format.c')
-rw-r--r-- | libaf/af_format.c | 291 |
1 files changed, 291 insertions, 0 deletions
diff --git a/libaf/af_format.c b/libaf/af_format.c new file mode 100644 index 0000000000..d2ee6806b3 --- /dev/null +++ b/libaf/af_format.c @@ -0,0 +1,291 @@ +/* This audio output filter changes the format of a data block. Valid + formats are: AFMT_U8, AFMT_S8, AFMT_S16_LE, AFMT_S16_BE + AFMT_U16_LE, AFMT_U16_BE, AFMT_S32_LE and AFMT_S32_BE. +*/ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <inttypes.h> +#include <limits.h> + +#include "../config.h" +#include "../mp_msg.h" + +#include "../libao2/afmt.h" + +#include "af.h" + +// 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) + +// Signed +#define US (0<<3) // Un Signed +#define SI (1<<3) // SIgned +#define SIGN_MASK (1<<3) + +int decode(int format) +{ + // 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; + } + +} + +// Initialization and runtime control +static int control(struct af_instance_s* af, int cmd, void* arg) +{ + switch(cmd){ + case AF_CONTROL_REINIT: + // Make sure this filter isn't redundant + if(af->data->format == ((af_data_t*)arg)->format && af->data->bps == ((af_data_t*)arg)->bps) + return AF_DETACH; + + 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_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); + return AF_ERROR; + } + 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); + return AF_OK; + } + return AF_UNKNOWN; +} + +// Deallocate memory +static void uninit(struct af_instance_s* af) +{ + if(af->data) + free(af->data); + (int)af->setup = 0; +} + +// 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 + + if(AF_OK != RESIZE_LOCAL_BUFFER(af,data)) + return NULL; + + la = l->audio; + + // Change to little endian + if((cf&END_MASK)!=LE){ + switch(cf&NBITS_MASK){ + case(B16):{ + register uint16_t s; + for(i=1;i<len;i++){ + s=((uint16_t*)ca)[i]; + ((uint16_t*)ca)[i]=(uint16_t)(((s&0x00FF)<<8) | (s&0xFF00)>>8); + } + } + break; + case(B32):{ + register uint32_t s; + for(i=1;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)); + } + } + 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; + } + 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; + } + 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; + } + 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=1;i<len;i++) + ((uint16_t*)la)[i]=((uint16_t)((uint8_t*)ca)[i])<<8; + break; + case(B32): + for(i=1;i<len;i++) + ((uint32_t*)la)[i]=((uint32_t)((uint8_t*)ca)[i])<<24; + break; + } + 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=1;i<len;i++) + ((uint32_t*)la)[i]=((uint32_t)((uint16_t*)ca)[i])<<16; + break; + } + 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=1;i<len;i++) + ((uint16_t*)la)[i]=(uint16_t)((((uint32_t*)ca)[i])>>16); + break; + } + break; + } + } + // Switch to the correct endainess (again the problem with sun?) + if((lf&END_MASK)!=LE){ + switch(cf&NBITS_MASK){ + case(B16):{ + register uint16_t s; + for(i=1;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=1;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; + } + } + + // Set output data + + // Make sure no samples are lost + c->len = (c->len*l->bps)/c->bps; + c->audio = l->audio; + c->bps = l->bps; + c->format = l->format; + return c; +} + +// Allocate memory and set function pointers +static int open(af_instance_t* af){ + af->control=control; + af->uninit=uninit; + af->play=play; + af->mul.n=1; + af->mul.d=1; + af->data=calloc(1,sizeof(af_data_t)); + if(af->data == NULL) + return AF_ERROR; + (int)af->setup = 0; + return AF_OK; +} + +// Description of this filter +af_info_t af_info_format = { + "Sample format conversion", + "format", + "Anders", + "", + open +}; |