summaryrefslogtreecommitdiff
path: root/core/multimedia/opieplayer/libmpeg3/audio/mpeg3audio.c
authorkergoth <kergoth>2002-01-25 22:14:26 (UTC)
committer kergoth <kergoth>2002-01-25 22:14:26 (UTC)
commit15318cad33835e4e2dc620d033e43cd930676cdd (patch) (side-by-side diff)
treec2fa0399a2c47fda8e2cd0092c73a809d17f68eb /core/multimedia/opieplayer/libmpeg3/audio/mpeg3audio.c
downloadopie-15318cad33835e4e2dc620d033e43cd930676cdd.zip
opie-15318cad33835e4e2dc620d033e43cd930676cdd.tar.gz
opie-15318cad33835e4e2dc620d033e43cd930676cdd.tar.bz2
Initial revision
Diffstat (limited to 'core/multimedia/opieplayer/libmpeg3/audio/mpeg3audio.c') (more/less context) (ignore whitespace changes)
-rw-r--r--core/multimedia/opieplayer/libmpeg3/audio/mpeg3audio.c536
1 files changed, 536 insertions, 0 deletions
diff --git a/core/multimedia/opieplayer/libmpeg3/audio/mpeg3audio.c b/core/multimedia/opieplayer/libmpeg3/audio/mpeg3audio.c
new file mode 100644
index 0000000..e2d3912
--- a/dev/null
+++ b/core/multimedia/opieplayer/libmpeg3/audio/mpeg3audio.c
@@ -0,0 +1,536 @@
+#include "../libmpeg3.h"
+#include "../mpeg3protos.h"
+#include "mpeg3audio.h"
+#include "tables.h"
+
+#include <math.h>
+#include <stdlib.h>
+
+mpeg3audio_t* mpeg3audio_allocate_struct(mpeg3_t *file, mpeg3_atrack_t *track)
+{
+ mpeg3audio_t *audio = (mpeg3audio_t*)calloc(1, sizeof(mpeg3audio_t));
+ audio->file = file;
+ audio->track = track;
+ audio->astream = mpeg3bits_new_stream(file, track->demuxer);
+ audio->outscale = 1;
+ audio->bsbuf = audio->bsspace[1];
+ audio->init = 1;
+ audio->bo = 1;
+ audio->channels = 1;
+ return audio;
+}
+
+
+int mpeg3audio_delete_struct(mpeg3audio_t *audio)
+{
+ mpeg3bits_delete_stream(audio->astream);
+ if(audio->pcm_sample) free(audio->pcm_sample);
+ free(audio);
+ return 0;
+}
+
+int mpeg3audio_replace_buffer(mpeg3audio_t *audio, long new_allocation)
+{
+ long i;
+
+ audio->pcm_sample = (mpeg3_real_t*)realloc( audio->pcm_sample, sizeof(mpeg3_real_t) * new_allocation * audio->channels );
+ audio->pcm_allocated = new_allocation;
+/*
+ // Isn't this exactly the same as what the ANSI C function call realloc does,
+ // or did I miss C Programming 101 ?
+
+ if(!audio->pcm_sample)
+ {
+ audio->pcm_sample = (mpeg3_real_t*)malloc(sizeof(mpeg3_real_t) * new_allocation * audio->channels);
+ audio->pcm_allocated = new_allocation;
+ }
+ else
+ {
+ mpeg3_real_t *new_samples = (mpeg3_real_t*)malloc(sizeof(mpeg3_real_t) * new_allocation * audio->channels);
+ for(i = 0; i < audio->pcm_allocated * audio->channels; i++)
+ {
+ new_samples[i] = audio->pcm_sample[i];
+ }
+ free(audio->pcm_sample);
+ audio->pcm_sample = new_samples;
+ audio->pcm_allocated = new_allocation;
+ }
+*/
+ return 0;
+}
+
+int mpeg3audio_read_frame(mpeg3audio_t *audio)
+{
+ int result = 0;
+ result = mpeg3audio_read_header(audio);
+
+ if(!result)
+ {
+ switch(audio->format)
+ {
+ case AUDIO_AC3:
+ result = mpeg3audio_do_ac3(audio);
+ break;
+
+ case AUDIO_MPEG:
+ switch(audio->layer)
+ {
+ case 1:
+ break;
+
+ case 2:
+ result = mpeg3audio_dolayer2(audio);
+ break;
+
+ case 3:
+ result = mpeg3audio_dolayer3(audio);
+ break;
+
+ default:
+ result = 1;
+ break;
+ }
+ break;
+
+ case AUDIO_PCM:
+ result = mpeg3audio_do_pcm(audio);
+ break;
+ }
+ }
+
+ if(!result)
+ {
+/* Byte align the stream */
+ mpeg3bits_byte_align(audio->astream);
+ }
+ return result;
+}
+
+/* Get the length but also initialize the frame sizes. */
+int mpeg3audio_get_length(mpeg3audio_t *audio, mpeg3_atrack_t *track)
+{
+ long result = 0;
+ long framesize1 = 0, total1 = 0;
+ long framesize2 = 0, total2 = 0;
+ long total_framesize = 0, total_frames = 0;
+ long byte_limit = 131072; /* Total bytes to gather information from */
+ long total_bytes = 0;
+ long major_framesize; /* Bigger framesize + header */
+ long minor_framesize; /* Smaller framesize + header */
+ long major_total;
+ long minor_total;
+ mpeg3_t *file = audio->file;
+
+/* Get the frame sizes */
+ mpeg3bits_seek_start(audio->astream);
+ audio->pcm_point = 0;
+ result = mpeg3audio_read_frame(audio); /* Stores the framesize */
+ audio->samples_per_frame = audio->pcm_point / audio->channels;
+
+ switch(audio->format)
+ {
+ case AUDIO_AC3:
+ audio->avg_framesize = audio->framesize;
+ break;
+
+ case AUDIO_MPEG:
+ framesize1 = audio->framesize;
+ total_bytes += audio->framesize;
+ total1 = 1;
+
+ while(!result && total_bytes < byte_limit)
+ {
+ audio->pcm_point = 0;
+ result = mpeg3audio_read_frame(audio);
+ total_bytes += audio->framesize;
+ if(audio->framesize != framesize1)
+ {
+ framesize2 = audio->framesize;
+ total2 = 1;
+ break;
+ }
+ else
+ {
+ total1++;
+ }
+ }
+
+ while(!result && total_bytes < byte_limit)
+ {
+ audio->pcm_point = 0;
+ result = mpeg3audio_read_frame(audio);
+ total_bytes += audio->framesize;
+ if(audio->framesize != framesize2)
+ {
+ break;
+ }
+ else
+ {
+ total2++;
+ }
+ }
+
+ audio->pcm_point = 0;
+ result = mpeg3audio_read_frame(audio);
+ if(audio->framesize != framesize1 && audio->framesize != framesize2)
+ {
+/* Variable bit rate. Get the average frame size. */
+ while(!result && total_bytes < byte_limit)
+ {
+ audio->pcm_point = 0;
+ result = mpeg3audio_read_frame(audio);
+ total_bytes += audio->framesize;
+ if(!result)
+ {
+ total_framesize += audio->framesize;
+ total_frames++;
+ }
+ }
+ audio->avg_framesize = 4 + (total_framesize + framesize1 + framesize2) / (total_frames + total1 + total2);
+ }
+ else
+ {
+ major_framesize = framesize2 > framesize1 ? framesize2 : framesize1;
+ major_total = framesize2 > framesize1 ? total2 : total1;
+ minor_framesize = framesize2 > framesize1 ? framesize1 : framesize2;
+ minor_total = framesize2 > framesize1 ? total1 : total2;
+/* Add the headers to the framesizes */
+ audio->avg_framesize = 4 + (major_framesize * major_total + minor_framesize * minor_total) / (major_total + minor_total);
+ }
+ break;
+
+ case AUDIO_PCM:
+ break;
+ }
+
+/* Estimate the total samples */
+ if(file->is_audio_stream)
+ {
+/* From the raw file */
+ result = (long)((float)mpeg3demuxer_total_bytes(audio->astream->demuxer) / audio->avg_framesize * audio->samples_per_frame);
+ }
+ else
+ {
+/* Gross approximation from a multiplexed file. */
+ result = (long)(mpeg3demux_length(audio->astream->demuxer) * track->sample_rate);
+/* result = (long)((mpeg3_real_t)mpeg3_video_frames(file, 0) / mpeg3_frame_rate(file, 0) * track->sample_rate); */
+/* We would scan the multiplexed packets here for the right timecode if only */
+/* they had meaningful timecode. */
+ }
+
+ audio->pcm_point = 0;
+ mpeg3bits_seek_start(audio->astream);
+ mpeg3audio_reset_synths(audio);
+ return result;
+}
+
+int mpeg3audio_seek(mpeg3audio_t *audio, long position)
+{
+ int result = 0;
+ mpeg3_t *file = audio->file;
+ mpeg3_atrack_t *track = audio->track;
+ long frame_number;
+ long byte_position;
+ double time_position;
+
+/* Sample seek wasn't requested */
+ if(audio->sample_seek < 0)
+ {
+ audio->pcm_position = position;
+ audio->pcm_size = 0;
+ return 0;
+ }
+
+/* Can't slide buffer. Seek instead. */
+ if(!file->is_audio_stream)
+ {
+/* Seek in a multiplexed stream using the multiplexer. */
+ time_position = (double)position / track->sample_rate;
+ result |= mpeg3bits_seek_time(audio->astream, time_position);
+ audio->pcm_position = (long)mpeg3bits_packet_time(audio->astream) * track->sample_rate;
+/*printf("wanted %f got %f\n", time_position, mpeg3bits_packet_time(audio->astream)); */
+ }
+ else
+ {
+/* Seek in an elemental stream. This algorithm achieves sample accuracy on fixed bitrates. */
+/* Forget about variable bitrates or program streams. */
+ frame_number = position / audio->samples_per_frame;
+ byte_position = (long)(audio->avg_framesize * frame_number);
+ audio->pcm_position = frame_number * audio->samples_per_frame;
+
+ if(byte_position < audio->avg_framesize * 2)
+ {
+ result |= mpeg3bits_seek_start(audio->astream);
+ audio->pcm_position = 0;
+ }
+ else
+ {
+ result |= mpeg3bits_seek_byte(audio->astream, byte_position);
+ }
+ }
+
+/* Arm the backstep buffer for layer 3 if not at the beginning already. */
+ if(byte_position >= audio->avg_framesize * 2 && audio->layer == 3 && !result)
+ {
+ result |= mpeg3audio_prev_header(audio);
+ result |= mpeg3audio_read_layer3_frame(audio);
+ }
+
+/* Reset the tables. */
+ mpeg3audio_reset_synths(audio);
+ audio->pcm_size = 0;
+ audio->pcm_point = 0;
+ return result;
+}
+
+/* ================================================================ */
+/* ENTRY POINTS */
+/* ================================================================ */
+
+
+
+
+mpeg3audio_t* mpeg3audio_new(mpeg3_t *file, mpeg3_atrack_t *track, int format)
+{
+ mpeg3audio_t *audio = mpeg3audio_allocate_struct(file, track);
+ int result = 0;
+
+/* Init tables */
+ mpeg3audio_new_decode_tables(audio);
+ audio->percentage_seek = -1;
+ audio->sample_seek = -1;
+ audio->format = format;
+
+/* Determine the format of the stream */
+ if(format == AUDIO_UNKNOWN)
+ {
+ if(((mpeg3bits_showbits(audio->astream, 32) & 0xffff0000) >> 16) == MPEG3_AC3_START_CODE)
+ audio->format = AUDIO_AC3;
+ else
+ audio->format = AUDIO_MPEG;
+ }
+
+/* get channel count */
+ result = mpeg3audio_read_header(audio);
+
+/* Set up the sample buffer */
+ mpeg3audio_replace_buffer(audio, 262144);
+
+/* Copy information to the mpeg struct */
+ if(!result)
+ {
+ track->channels = audio->channels;
+
+ switch(audio->format)
+ {
+ case AUDIO_AC3:
+ track->sample_rate = mpeg3_ac3_samplerates[audio->sampling_frequency_code];
+ break;
+
+ case AUDIO_MPEG:
+ track->sample_rate = mpeg3_freqs[audio->sampling_frequency_code];
+ break;
+
+ case AUDIO_PCM:
+ track->sample_rate = 48000;
+ break;
+ }
+
+ track->total_samples = mpeg3audio_get_length(audio, track);
+ result |= mpeg3bits_seek_start(audio->astream);
+ }
+ else
+ {
+ mpeg3audio_delete_struct(audio);
+ audio = 0;
+ }
+
+ return audio;
+}
+
+int mpeg3audio_delete(mpeg3audio_t *audio)
+{
+ mpeg3audio_delete_struct(audio);
+ return 0;
+}
+
+int mpeg3audio_seek_percentage(mpeg3audio_t *audio, double percentage)
+{
+ audio->percentage_seek = percentage;
+ return 0;
+}
+
+int mpeg3audio_seek_sample(mpeg3audio_t *audio, long sample)
+{
+ audio->sample_seek = sample;
+ return 0;
+}
+
+/* Read raw frames for concatenation purposes */
+int mpeg3audio_read_raw(mpeg3audio_t *audio, unsigned char *output, long *size, long max_size)
+{
+ int result = 0;
+ int i;
+ *size = 0;
+
+ switch(audio->format)
+ {
+ case AUDIO_AC3:
+/* Just write the AC3 stream */
+ if(mpeg3bits_read_buffer(audio->astream, output, audio->framesize))
+ return 1;
+ *size = audio->framesize;
+ break;
+
+ case AUDIO_MPEG:
+/* Fix the mpeg stream */
+ result = mpeg3audio_read_header(audio);
+ if(!result)
+ {
+ if(max_size < 4) return 1;
+ *output++ = (audio->newhead & 0xff000000) >> 24;
+ *output++ = (audio->newhead & 0xff0000) >> 16;
+ *output++ = (audio->newhead & 0xff00) >> 8;
+ *output++ = (audio->newhead & 0xff);
+ *size += 4;
+
+ if(max_size < 4 + audio->framesize) return 1;
+ if(mpeg3bits_read_buffer(audio->astream, output, audio->framesize))
+ return 1;
+
+ *size += audio->framesize;
+ }
+ break;
+
+ case AUDIO_PCM:
+ if(mpeg3bits_read_buffer(audio->astream, output, audio->framesize))
+ return 1;
+ *size = audio->framesize;
+ break;
+ }
+ return result;
+}
+
+/* Channel is 0 to channels - 1 */
+int mpeg3audio_decode_audio(mpeg3audio_t *audio,
+ mpeg3_real_t *output_f,
+ short *output_i, int sampleSpacing,
+ int channel,
+ long start_position,
+ long len)
+{
+ long allocation_needed = len + MPEG3AUDIO_PADDING;
+ long i, j, result = 0;
+ mpeg3_t *file = audio->file;
+ mpeg3_atrack_t *atrack = audio->track;
+ long attempts;
+
+/* Create new buffer */
+ if(audio->pcm_allocated < allocation_needed)
+ {
+ mpeg3audio_replace_buffer(audio, allocation_needed);
+ }
+
+/* There was a percentage seek */
+ if(audio->percentage_seek >= 0)
+ {
+ mpeg3bits_seek_percentage(audio->astream, audio->percentage_seek);
+/* Force the pcm buffer to be reread. */
+ audio->pcm_position = start_position;
+ audio->pcm_size = 0;
+ audio->percentage_seek = -1;
+ }
+ else
+ {
+/* Entire output is in buffer so don't do anything. */
+ if(start_position >= audio->pcm_position && start_position < audio->pcm_position + audio->pcm_size &&
+ start_position + len <= audio->pcm_size)
+ {
+ ;
+ }
+ else
+/* Output starts in buffer but ends later so slide it back. */
+ if(start_position <= audio->pcm_position + audio->pcm_size &&
+ start_position >= audio->pcm_position)
+ {
+ for(i = 0, j = (start_position - audio->pcm_position) * audio->channels;
+ j < audio->pcm_size * audio->channels;
+ i++, j++)
+ {
+ audio->pcm_sample[i] = audio->pcm_sample[j];
+ }
+
+ audio->pcm_point = i;
+ audio->pcm_size -= start_position - audio->pcm_position;
+ audio->pcm_position = start_position;
+ }
+ else
+ {
+/* Output is outside buffer completely. */
+ result = mpeg3audio_seek(audio, start_position);
+ audio->sample_seek = -1;
+/* Check sanity */
+ if(start_position < audio->pcm_position) audio->pcm_position = start_position;
+ }
+ audio->sample_seek = -1;
+ }
+
+/* Read packets until the buffer is full. */
+ if(!result)
+ {
+ attempts = 0;
+ result = 1;
+ while(attempts < 6 &&
+ !mpeg3bits_eof(audio->astream) &&
+ audio->pcm_size + audio->pcm_position < start_position + len)
+ {
+ result = mpeg3audio_read_frame(audio);
+ if(result) attempts++;
+ audio->pcm_size = audio->pcm_point / audio->channels;
+ }
+ }
+
+
+
+/* Copy the buffer to the output */
+ if(output_f)
+ {
+ for(i = 0, j = (start_position - audio->pcm_position) * audio->channels + channel;
+ i < len && j < audio->pcm_size * audio->channels;
+ i++, j += audio->channels)
+ {
+ output_f[i] = audio->pcm_sample[j];
+ }
+ for( ; i < len; i++)
+ {
+ output_f[i] = 0;
+ }
+ }
+ else
+ if(output_i)
+ {
+ int sample;
+ for(i = 0, j = (start_position - audio->pcm_position) * audio->channels + channel;
+ i < (len*(sampleSpacing+1)) && j < audio->pcm_size * audio->channels;
+ i++, j += audio->channels)
+ {
+ sample = (int)(audio->pcm_sample[j] * 32767);
+ if(sample > 32767) sample = 32767;
+ else
+ if(sample < -32768) sample = -32768;
+
+ output_i[i] = sample;
+ i += sampleSpacing;
+ }
+ for( ; i < (len*(sampleSpacing+1)); i++)
+ {
+ output_i[i] = 0;
+ i += sampleSpacing;
+ }
+ }
+
+ if(audio->pcm_point > 0)
+ return 0;
+ else
+ return result;
+}