diff src/alac/plugin.c @ 56:56c88eee9802 trunk

[svn] - experimental ALAC plugin -- don't use this, it crashes
author nenolod
date Sat, 30 Sep 2006 19:26:34 -0700
parents
children 96901271d2e2
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/alac/plugin.c	Sat Sep 30 19:26:34 2006 -0700
@@ -0,0 +1,275 @@
+/*
+ * Copyright (c) 2005 David Hammerton
+ * All rights reserved.
+ *
+ * Adapted from example program by William Pitcock <nenolod@atheme.org>
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include <ctype.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <string.h>
+
+#include <audacious/plugin.h>
+#include <audacious/output.h>
+#include <audacious/vfs.h>
+
+#include "demux.h"
+#include "decomp.h"
+#include "stream.h"
+
+alac_file *alac = NULL;
+
+static VFSFile *input_file = NULL;
+static int input_opened = 0;
+static stream_t *input_stream;
+
+static int write_wav_format = 0;
+static int verbose = 0;
+
+gpointer decode_thread(void *args);
+static GThread *playback_thread;
+
+static void alac_init(void)
+{
+	/* empty */
+}
+
+gboolean is_our_file(char *filename)
+{
+    demux_res_t demux_res;
+    input_file = vfs_fopen(filename, "rb");
+#ifdef WORDS_BIGENDIAN
+    input_stream = stream_create_file(input_file, 1);
+#else
+    input_stream = stream_create_file(input_file, 0);
+#endif
+    if (!input_stream)
+    {
+        fprintf(stderr, "failed to create input stream from file\n");
+	vfs_fclose(input_file);
+        return FALSE;
+    }
+        
+    /* if qtmovie_read returns successfully, the stream is up to
+     * the movie data, which can be used directly by the decoder */
+    if (!qtmovie_read(input_stream, &demux_res))
+    {
+        fprintf(stderr, "failed to load the QuickTime movie headers\n");
+        stream_destroy(input_stream);
+	vfs_fclose(input_file);
+        return FALSE;
+    }
+
+    stream_destroy(input_stream);
+    vfs_fclose(input_file);
+
+    return TRUE;
+}
+
+static void play_file(char *filename)
+{
+    playback_thread = g_thread_create(decode_thread, filename, TRUE, NULL);
+}
+
+static void stop(void)
+{
+    g_thread_join(playback_thread);
+    output_close_audio();
+}
+
+static void seek(gint time)
+{
+	/* unimplemented */
+}
+
+InputPlugin alac_ip = {
+    NULL,
+    NULL,
+    "Apple Lossless Plugin",                       /* Description */  
+    alac_init,
+    NULL,
+    NULL,
+    is_our_file,
+    NULL,
+    play_file,
+    stop,
+    output_pause,
+    seek,
+    NULL,
+    get_output_time,
+    NULL,
+    NULL,
+    NULL,
+    NULL,
+    NULL,
+    NULL,
+    NULL,
+    NULL,
+    NULL,                       /* file_info_box */
+    NULL
+};
+
+static int get_sample_info(demux_res_t *demux_res, uint32_t samplenum,
+                           uint32_t *sample_duration,
+                           uint32_t *sample_byte_size)
+{
+    unsigned int duration_index_accum = 0;
+    unsigned int duration_cur_index = 0;
+
+    if (samplenum >= demux_res->num_sample_byte_sizes)
+    {
+        fprintf(stderr, "sample %i does not exist\n", samplenum);
+        return 0;
+    }
+
+    if (!demux_res->num_time_to_samples)
+    {
+        fprintf(stderr, "no time to samples\n");
+        return 0;
+    }
+    while ((demux_res->time_to_sample[duration_cur_index].sample_count + duration_index_accum)
+            <= samplenum)
+    {
+        duration_index_accum += demux_res->time_to_sample[duration_cur_index].sample_count;
+        duration_cur_index++;
+        if (duration_cur_index >= demux_res->num_time_to_samples)
+        {
+            fprintf(stderr, "sample %i does not have a duration\n", samplenum);
+            return 0;
+        }
+    }
+
+    *sample_duration = demux_res->time_to_sample[duration_cur_index].sample_duration;
+    *sample_byte_size = demux_res->sample_byte_size[samplenum];
+
+    return 1;
+}
+
+static void GetBuffer(demux_res_t *demux_res)
+{
+    unsigned long destBufferSize = 1024*16; /* 16kb buffer = 4096 frames = 1 alac sample */
+    void *pDestBuffer = malloc(destBufferSize);
+    int bytes_read = 0;
+
+    unsigned int buffer_size = 1024*64;
+    void *buffer;
+
+    unsigned int i;
+
+    buffer = malloc(buffer_size);
+
+    for (i = 0; i < demux_res->num_sample_byte_sizes; i++)
+    {
+        uint32_t sample_duration;
+        uint32_t sample_byte_size;
+
+        int outputBytes;
+
+        /* just get one sample for now */
+        if (!get_sample_info(demux_res, i,
+                             &sample_duration, &sample_byte_size))
+        {
+            fprintf(stderr, "sample failed\n");
+            return;
+        }
+
+        if (buffer_size < sample_byte_size)
+        {
+            fprintf(stderr, "sorry buffer too small! (is %i want %i)\n",
+                    buffer_size,
+                    sample_byte_size);
+            return;
+        }
+
+        stream_read(input_stream, sample_byte_size,
+                    buffer);
+
+        /* now fetch */
+        outputBytes = destBufferSize;
+        decode_frame(alac, buffer, pDestBuffer, &outputBytes);
+
+        /* write */
+        bytes_read += outputBytes;
+
+        if (verbose)
+            fprintf(stderr, "read %i bytes. total: %i\n", outputBytes, bytes_read);
+
+        produce_audio(get_written_time(), FMT_S16_LE, demux_res->num_channels, outputBytes, pDestBuffer, NULL);
+    }
+    if (verbose)
+        fprintf(stderr, "done reading, read %i frames\n", i);
+}
+
+static void init_sound_converter(demux_res_t *demux_res)
+{
+    alac = create_alac(demux_res->sample_size, demux_res->num_channels);
+
+    alac_set_info(alac, demux_res->codecdata);
+}
+
+gpointer decode_thread(void *args)
+{
+    demux_res_t demux_res;
+    unsigned int output_size, i;
+
+    input_file = vfs_fopen((char *) args, "rb");
+#ifdef WORDS_BIGENDIAN
+    input_stream = stream_create_file(input_file, 1);
+#else
+    input_stream = stream_create_file(input_file, 0);
+#endif
+    if (!input_stream)
+    {
+        fprintf(stderr, "failed to create input stream from file\n");
+        return 0;
+    }
+
+    /* if qtmovie_read returns successfully, the stream is up to
+     * the movie data, which can be used directly by the decoder */
+    if (!qtmovie_read(input_stream, &demux_res))
+    {
+        fprintf(stderr, "failed to load the QuickTime movie headers\n");
+        return 0;
+    }
+
+    /* initialise the sound converter */
+    init_sound_converter(&demux_res);
+
+    /* will convert the entire buffer */
+    GetBuffer(&demux_res);
+
+    stream_destroy(input_stream);
+
+    if (input_opened)
+        vfs_fclose(input_file);
+
+    return NULL;
+}
+
+InputPlugin *get_iplugin_info(void)
+{
+    return &alac_ip;
+}