/* 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 #include #include #include #include #include #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) #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) { // 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_COMMAND_LINE:{ af_data_t d; sscanf((char*)arg,"%i:%i",&(d.format),&(d.bps)); 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); 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); 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 cpu native endian if((cf&END_MASK)!=NE){ switch(cf&NBITS_MASK){ case(B16):{ register uint16_t s; for(i=0;i>8); } } break; case(B32):{ register uint32_t s; for(i=0;i>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;ilen); } else { switch(cf&NBITS_MASK){ case(B08): switch(lf&NBITS_MASK){ case(B16): for(i=0;i>8); break; case(B32): for(i=0;i>24); break; case(B16): for(i=0;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>8); } } break; case(B32):{ register uint32_t s; for(i=0;i>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", "", AF_FLAGS_REENTRANT, open };