--- ./libao/audio_out.c.org 2002-05-22 14:35:22.000000000 +0900 +++ ./libao/audio_out.c 2005-08-22 20:48:09.000000000 +0900 @@ -45,8 +45,10 @@ extern ao_open_t ao_wavdolby_open; extern ao_open_t ao_aif_open; extern ao_open_t ao_aifdolby_open; +extern ao_open_t ao_aifindiv_open; extern ao_open_t ao_peak_open; extern ao_open_t ao_peakdolby_open; +extern ao_open_t ao_peakindiv_open; extern ao_open_t ao_null_open; extern ao_open_t ao_null4_open; extern ao_open_t ao_null6_open; @@ -77,8 +79,10 @@ {"wavdolby", ao_wavdolby_open}, {"aif", ao_aif_open}, {"aifdolby", ao_aifdolby_open}, + {"aifindiv", ao_aifindiv_open}, {"peak", ao_peak_open}, {"peakdolby", ao_peakdolby_open}, + {"peakindiv", ao_peakindiv_open}, {"null", ao_null_open}, {"null4", ao_null4_open}, {"null6", ao_null6_open}, --- ./libao/audio_out_aif.c.org 2002-04-28 19:23:02.000000000 +0900 +++ ./libao/audio_out_aif.c 2005-08-22 22:03:38.000000000 +0900 @@ -40,6 +40,16 @@ int size; } aif_instance_t; +typedef struct indiv_instance_s { + ao_instance_t ao; + int sample_rate; + int set_params; + int flags; + int size; + int exist; + FILE * fp[6]; +} indiv_instance_t; + static uint8_t aif_header[] = { 'F', 'O', 'R', 'M', 0xff, 0xff, 0xff, 0xfe, 'A', 'I', 'F', 'F', 'C', 'O', 'M', 'M', 0, 0, 0, 18, @@ -47,6 +57,13 @@ 'S', 'S', 'N', 'D', 0xff, 0xff, 0xff, 0xd8, 0, 0, 0, 0, 0, 0, 0, 0 }; +static uint8_t indiv_header[] = { + 'F', 'O', 'R', 'M', 0xff, 0xff, 0xff, 0xfe, 'A', 'I', 'F', 'F', + 'C', 'O', 'M', 'M', 0, 0, 0, 18, + 0, 1, 0x7f, 0xff, 0xff, 0xe8, 0, 16, 0x40, 0x0e, -1, -1, 0, 0, 0, 0, 0, 0, + 'S', 'S', 'N', 'D', 0xff, 0xff, 0xff, 0xd8, 0, 0, 0, 0, 0, 0, 0, 0 +}; + static int aif_setup (ao_instance_t * _instance, int sample_rate, int * flags, sample_t * level, sample_t * bias) { @@ -77,7 +94,7 @@ buf[1] = value; } -static int aif_play (ao_instance_t * _instance, int flags, sample_t * _samples) +/*static */int aif_play (ao_instance_t * _instance, int flags, sample_t * _samples) { aif_instance_t * instance = (aif_instance_t *) _instance; int16_t int16_samples[256*2]; @@ -107,6 +124,233 @@ return 0; } +int aif_lpcm (ao_instance_t * _instance, sample_t gain, uint8_t * samples, size_t size) +{ + aif_instance_t * instance = (aif_instance_t *) _instance; + + if (instance->set_params) { + instance->set_params = 0; + store2 (aif_header + 30, instance->sample_rate); + fwrite (aif_header, sizeof (aif_header), 1, stdout); + } + + if (gain) { + int16_t * p; + int16_t sample; + size_t i; + sample_t f; + + p = (int16_t *) samples; + for (i = 0; i < size; i += 2) { + f = (sample_t) *p * gain; + if (f < 0) { + f -= 0.5; + if (f < -32768.) f = -32768.; + } else { + f += 0.5; + if (f > 32767.) f = 32767.; + } + sample = f; + fwrite (&sample, 2, 1, stdout); + p++; + } + } else { + fwrite (samples, size, 1, stdout); + } + + instance->size += size; + return 0; +} + + +static inline int16_t convert (int32_t i) +{ + if (i > 0x43c07fff) + return 32767; + else if (i < 0x43bf8000) + return -32768; + else + return i - 0x43c00000; +} + +enum { + chLFE = 0x01, + chLf = 0x02, + chC = 0x04, + chRf = 0x08, + chLs = 0x10, + chRs = 0x20 +}; + +static void float_to_int (float * _f, int16_t * s16, int flags, int * exist) +{ + int i; + int32_t * f = (int32_t *) _f; + + switch (flags) { + case A52_MONO: + *exist |= chC; + for (i = 0; i < 256; i++) { + s16[i] = s16[i+256] = 0; + s16[i+512] = convert (f[i]); + s16[i+768] = s16[i+1024] = s16[i+1280] = 0; + } + s16_BE (&s16[i+512], 1); + break; + case A52_CHANNEL: + case A52_STEREO: + case A52_DOLBY: + *exist |= chLf | chRf; + for (i = 0; i < 256; i++) { + s16[i] = 0; + s16[i+256] = convert (f[i]); + s16[i+512] = 0; + s16[i+768] = convert (f[i+256]); + s16[i+1024] = s16[i+1280] = 0; + } + s16_BE (&s16[i+256], 1); + s16_BE (&s16[i+768], 1); + break; + case A52_3F: + *exist |= chLf | chC | chRf; + for (i = 0; i < 256; i++) { + s16[i] = 0; + s16[i+256] = convert (f[i]); + s16[i+512] = convert (f[i+256]); + s16[i+768] = convert (f[i+512]); + s16[i+1024] = s16[i+1280] = 0; + } + s16_BE (&s16[i+256], 3); + break; + case A52_2F2R: + *exist |= chLf | chRf | chLs | chRs; + for (i = 0; i < 256; i++) { + s16[i] = 0; + s16[i+256] = convert (f[i]); + s16[i+512] = 0; + s16[i+768] = convert (f[i+256]); + s16[i+1024] = convert (f[i+512]); + s16[i+1280] = convert (f[i+768]); + } + s16_BE (&s16[i+256], 1); + s16_BE (&s16[i+768], 3); + break; + case A52_3F2R: + *exist |= chLf | chC | chRf | chLs | chRs; + for (i = 0; i < 256; i++) { + s16[i] = 0; + s16[i+256] = convert (f[i]); + s16[i+512] = convert (f[i+256]); + s16[i+768] = convert (f[i+512]); + s16[i+1024] = convert (f[i+768]); + s16[i+1280] = convert (f[i+1024]); + } + s16_BE (&s16[i+256], 5); + break; + case A52_MONO | A52_LFE: + *exist |= chLFE | chC; + for (i = 0; i < 256; i++) { + s16[i] = convert (f[i]); + s16[i+256] = 0; + s16[i+512] = convert (f[i+256]); + s16[i+768] = s16[i+1024] = s16[i+1280] = 0; + } + s16_BE (s16, 1); + s16_BE (&s16[i+512], 1); + break; + case A52_CHANNEL | A52_LFE: + case A52_STEREO | A52_LFE: + case A52_DOLBY | A52_LFE: + *exist |= chLFE | chLf | chRf; + for (i = 0; i < 256; i++) { + s16[i] = convert (f[i]); + s16[i+256] = convert (f[i+256]); + s16[i+512] = 0; + s16[i+768] = convert (f[i+512]); + s16[i+1024] = s16[i+1280] = 0; + } + s16_BE (s16, 2); + s16_BE (&s16[i+768], 1); + break; + case A52_3F | A52_LFE: + *exist |= chLFE | chLf | chC | chRf; + for (i = 0; i < 256; i++) { + s16[i] = convert (f[i]); + s16[i+256] = convert (f[i+256]); + s16[i+512] = convert (f[i+512]); + s16[i+768] = convert (f[i+768]); + s16[i+1024] = s16[i+1280] = 0; + } + s16_BE (s16, 4); + break; + case A52_2F2R | A52_LFE: + *exist |= chLFE | chLf | chRf | chLs | chRs; + for (i = 0; i < 256; i++) { + s16[i] = convert (f[i]); + s16[i+256] = convert (f[i+256]); + s16[i+512] = 0; + s16[i+768] = convert (f[i+512]); + s16[i+1024] = convert (f[i+768]); + s16[i+1280] = convert (f[i+1024]); + } + s16_BE (s16, 2); + s16_BE (&s16[i+768], 3); + break; + case A52_3F2R | A52_LFE: + *exist |= chLFE | chLf | chC | chRf | chLs | chRs; + for (i = 0; i < 256; i++) { + s16[i] = convert (f[i]); + s16[i+256] = convert (f[i+256]); + s16[i+512] = convert (f[i+512]); + s16[i+768] = convert (f[i+768]); + s16[i+1024] = convert (f[i+1024]); + s16[i+1280] = convert (f[i+1280]); + } + s16_BE (s16, 6); + break; + } +} + +int indiv_play (ao_instance_t * _instance, int flags, sample_t * _samples) +{ + indiv_instance_t * instance = (indiv_instance_t *) _instance; + int16_t int16_samples[256*6]; + int i; + FILE *fp; + +#ifdef LIBA52_DOUBLE + float samples[256 * 6]; + + for (i = 0; i < 256 * 6; i++) + samples[i] = _samples[i]; +#else + float * samples = _samples; +#endif + + flags &= A52_CHANNEL_MASK | A52_LFE; + + if (instance->set_params) { + instance->set_params = 0; + store2 (indiv_header + 30, instance->sample_rate); + fp = instance->fp[0]; + for (i = 0; i < 6; i++) { + fwrite (indiv_header, sizeof (indiv_header), 1, fp); + fp++; + } + } + + float_to_int (samples, int16_samples, flags, &instance->exist); + fp = instance->fp[0]; + for (i = 0; i < 6; i++) { + fwrite (&int16_samples[i*256], sizeof (int16_t) * 256, 1, fp); + fp++; + } + + instance->size += 256 * sizeof (int16_t); + + return 0; +} + static void aif_close (ao_instance_t * _instance) { aif_instance_t * instance = (aif_instance_t *) _instance; @@ -149,3 +393,70 @@ { return aif_open (A52_DOLBY); } + +void indiv_close (ao_instance_t * _instance) +{ + indiv_instance_t * instance = (indiv_instance_t *) _instance; + FILE *fp; + int i, j; + char str[15]; + + for (i = 0; i < 6; i++) { + fp = instance->fp[i]; + if (fseek (fp, 0, SEEK_SET) < 0) { + fclose (fp); + continue; + } + + store4 (indiv_header + 4, instance->size + 46); + store4 (indiv_header + 22, instance->size / 2); + store4 (indiv_header + 42, instance->size + 8); + fwrite (indiv_header, sizeof (indiv_header), 1, fp); + fclose (fp); + } + + j = 1; + for (i = 0; i < 6; i++) { + if (!(instance->exist & j)) { + sprintf(str, "a52_out_%d.aiff", i); + remove(str); + } + j <<= 1; + } +} + +ao_instance_t * ao_aifindiv_open (void) +{ + indiv_instance_t * instance; + int i, j; + char str[15]; + + instance = malloc (sizeof (indiv_instance_t)); + if (instance == NULL) + return NULL; + + instance->ao.setup = aif_setup; + instance->ao.play = indiv_play; + instance->ao.close = indiv_close; + + instance->sample_rate = 0; + instance->set_params = 1; + instance->flags = A52_3F2R | A52_LFE; + instance->size = 0; + instance->exist = 0; + + for (i = 0; i < 6; i++) { + sprintf(str, "a52_out_%d.aiff", i); + instance->fp[i] = fopen(str, "w+b"); + if (!instance->fp[i]) { + for (j = 0; j < i; j++) { + fclose(instance->fp[j]); + } + fprintf (stderr, "Can not open work file: %s\n", str); + free (instance); + return NULL; + } + } + + return (ao_instance_t *) instance; +} --- ./libao/audio_out_peak.c.org 2002-05-22 14:35:22.000000000 +0900 +++ ./libao/audio_out_peak.c 2005-08-23 14:32:55.000000000 +0900 @@ -27,7 +27,7 @@ return 0; } -static int peak_play (ao_instance_t * _instance, int flags, sample_t * samples) +/*static */int peak_play (ao_instance_t * _instance, int flags, sample_t * samples) { peak_instance_t * instance = (peak_instance_t *) _instance; int i; @@ -40,6 +40,64 @@ return 0; } +/*static */int peak_lpcm (ao_instance_t * _instance, sample_t * samples, int size) +{ + peak_instance_t * instance = (peak_instance_t *) _instance; + sample_t * p; + sample_t sample; + int i; + + p = samples; + for (i = 0; i < size; i += 2) { + sample = *p; + if (instance->peak < fabs(sample)) + instance->peak = fabs(sample); + p++; + } + + return 0; +} + +#define compare256(p) do {\ + int i;\ + sample_t * samples = p;\ + for (i = 0; i < 256; i++)\ + if (instance->peak < fabs(samples[i]))\ + instance->peak = fabs(samples[i]);\ +} while (0) + +/*static */int peakindiv_play (ao_instance_t * _instance, int flags, sample_t * samples) +{ + peak_instance_t * instance = (peak_instance_t *) _instance; + + flags &= A52_CHANNEL_MASK | A52_LFE; + + switch (flags) { /* don't break */ + case A52_3F2R | A52_LFE: + compare256 (&samples[1280]); + case A52_3F2R: + case A52_2F2R | A52_LFE: + compare256 (&samples[1024]); + case A52_2F2R: + case A52_3F | A52_LFE: + compare256 (&samples[768]); + case A52_3F: + case A52_CHANNEL | A52_LFE: + case A52_STEREO | A52_LFE: + case A52_DOLBY | A52_LFE: + compare256 (&samples[512]); + case A52_CHANNEL: + case A52_STEREO: + case A52_DOLBY: + case A52_MONO | A52_LFE: + compare256 (&samples[256]); + case A52_MONO: + compare256 (samples); + } + + return 0; +} + static void peak_close (ao_instance_t * _instance) { peak_instance_t * instance = (peak_instance_t *) _instance; @@ -74,3 +132,16 @@ { return peak_open (A52_DOLBY); } + +ao_instance_t * ao_peakindiv_open (void) +{ + peak_instance_t * instance; + + instance = (peak_instance_t *) peak_open(A52_3F2R | A52_LFE); + if (instance == NULL) + return NULL; + + instance->ao.play = peakindiv_play; + + return (ao_instance_t *) instance; +} --- ./src/a52dec.c.org 2002-06-28 12:11:49.000000000 +0900 +++ ./src/a52dec.c 2005-08-22 22:11:02.000000000 +0900 @@ -261,7 +261,7 @@ length = a52_syncinfo (buf, &flags, &sample_rate, &bit_rate); if (!length) { - fprintf (stderr, "skip\n"); + fprintf (stderr, "skip\r"); for (bufptr = buf; bufptr < buf + 6; bufptr++) bufptr[0] = bufptr[1]; continue; @@ -299,6 +299,19 @@ } } +int aif_play (ao_instance_t * _instance, int flags, sample_t * _samples); +int aif_lpcm (ao_instance_t * _instance, sample_t gain, uint8_t * samples, size_t size); +int peak_play (ao_instance_t * _instance, int flags, sample_t * _samples); +int peak_lpcm (ao_instance_t * _instance, uint8_t * samples, size_t size); + +void decode_lpcm (uint8_t * samples, size_t size) +{ + if (output->play == aif_play) + aif_lpcm (output, gain, samples, size); + else if (output->play == peak_play) + peak_lpcm (output, samples, size); +} + #define DEMUX_PAYLOAD_START 1 static int demux (uint8_t * buf, uint8_t * end, int flags) { @@ -325,6 +338,7 @@ #define DEMUX_HEADER 0 #define DEMUX_DATA 1 #define DEMUX_SKIP 2 +#define DEMUX_LPCM 3 static int state = DEMUX_SKIP; static int state_bytes = 0; static uint8_t head_buf[268]; @@ -390,6 +404,16 @@ } buf += state_bytes; break; + case DEMUX_LPCM: + if (demux_pid || (state_bytes > end - buf)) { + decode_lpcm (buf, end - buf); + state_bytes -= end - buf; + return 0; + } + decode_lpcm (buf, state_bytes); + buf += state_bytes; + print_fps (0); + break; } while (1) { @@ -468,11 +492,44 @@ /* header points to the mpeg1 pes header */ } if ((!demux_pid) && ((header-1)[len] != demux_track)) { - DONEBYTES (len); - bytes = 6 + (header[4] << 8) + header[5] - len; - if (bytes <= 0) - continue; - goto skip; + if ((header-1)[len] == (demux_track | 0x20)) { + len += 6; + NEEDBYTES (len); + + if ((output->play == aif_play || output->play == peak_play) + && (header[len - 2] & 0xf0) <= 0x10 + && (header[len - 2] & 0x07) == 0x01 + && header[len - 1] == 0x80) { + int sample_rate; + sample_t level, bias; + + if (header[len - 2] & 0x10) sample_rate = 96000; + else sample_rate = 48000; + if (!ao_setup (output, sample_rate, &flags, &level, &bias)) { + DONEBYTES (len); + bytes = 6 + (header[4] << 8) + header[5] - len; + if (bytes > end - buf) { + decode_lpcm (buf, end - buf); + state = DEMUX_LPCM; + state_bytes = bytes - (end - buf); + return 0; + } else if (bytes <= 0) + continue; + decode_lpcm (buf, bytes); + buf += bytes; + print_fps (0); + break; + } + } + goto next; + } else { + next: + DONEBYTES (len); + bytes = 6 + (header[4] << 8) + header[5] - len; + if (bytes <= 0) + continue; + goto skip; + } } len += 3; NEEDBYTES (len);