summaryrefslogtreecommitdiffstats
path: root/libaf/af_format.c
diff options
context:
space:
mode:
Diffstat (limited to 'libaf/af_format.c')
-rw-r--r--libaf/af_format.c557
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;
+ }
+}