Mercurial > audlegacy-plugins
comparison 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 |
comparison
equal
deleted
inserted
replaced
| 55:4423278dc9ae | 56:56c88eee9802 |
|---|---|
| 1 /* | |
| 2 * Copyright (c) 2005 David Hammerton | |
| 3 * All rights reserved. | |
| 4 * | |
| 5 * Adapted from example program by William Pitcock <nenolod@atheme.org> | |
| 6 * | |
| 7 * Permission is hereby granted, free of charge, to any person | |
| 8 * obtaining a copy of this software and associated documentation | |
| 9 * files (the "Software"), to deal in the Software without | |
| 10 * restriction, including without limitation the rights to use, | |
| 11 * copy, modify, merge, publish, distribute, sublicense, and/or | |
| 12 * sell copies of the Software, and to permit persons to whom the | |
| 13 * Software is furnished to do so, subject to the following conditions: | |
| 14 * | |
| 15 * The above copyright notice and this permission notice shall be | |
| 16 * included in all copies or substantial portions of the Software. | |
| 17 * | |
| 18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | |
| 19 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES | |
| 20 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND | |
| 21 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT | |
| 22 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, | |
| 23 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | |
| 24 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR | |
| 25 * OTHER DEALINGS IN THE SOFTWARE. | |
| 26 */ | |
| 27 | |
| 28 #include <ctype.h> | |
| 29 #include <stdio.h> | |
| 30 #include <stdint.h> | |
| 31 #include <stdlib.h> | |
| 32 #include <errno.h> | |
| 33 #include <string.h> | |
| 34 | |
| 35 #include <audacious/plugin.h> | |
| 36 #include <audacious/output.h> | |
| 37 #include <audacious/vfs.h> | |
| 38 | |
| 39 #include "demux.h" | |
| 40 #include "decomp.h" | |
| 41 #include "stream.h" | |
| 42 | |
| 43 alac_file *alac = NULL; | |
| 44 | |
| 45 static VFSFile *input_file = NULL; | |
| 46 static int input_opened = 0; | |
| 47 static stream_t *input_stream; | |
| 48 | |
| 49 static int write_wav_format = 0; | |
| 50 static int verbose = 0; | |
| 51 | |
| 52 gpointer decode_thread(void *args); | |
| 53 static GThread *playback_thread; | |
| 54 | |
| 55 static void alac_init(void) | |
| 56 { | |
| 57 /* empty */ | |
| 58 } | |
| 59 | |
| 60 gboolean is_our_file(char *filename) | |
| 61 { | |
| 62 demux_res_t demux_res; | |
| 63 input_file = vfs_fopen(filename, "rb"); | |
| 64 #ifdef WORDS_BIGENDIAN | |
| 65 input_stream = stream_create_file(input_file, 1); | |
| 66 #else | |
| 67 input_stream = stream_create_file(input_file, 0); | |
| 68 #endif | |
| 69 if (!input_stream) | |
| 70 { | |
| 71 fprintf(stderr, "failed to create input stream from file\n"); | |
| 72 vfs_fclose(input_file); | |
| 73 return FALSE; | |
| 74 } | |
| 75 | |
| 76 /* if qtmovie_read returns successfully, the stream is up to | |
| 77 * the movie data, which can be used directly by the decoder */ | |
| 78 if (!qtmovie_read(input_stream, &demux_res)) | |
| 79 { | |
| 80 fprintf(stderr, "failed to load the QuickTime movie headers\n"); | |
| 81 stream_destroy(input_stream); | |
| 82 vfs_fclose(input_file); | |
| 83 return FALSE; | |
| 84 } | |
| 85 | |
| 86 stream_destroy(input_stream); | |
| 87 vfs_fclose(input_file); | |
| 88 | |
| 89 return TRUE; | |
| 90 } | |
| 91 | |
| 92 static void play_file(char *filename) | |
| 93 { | |
| 94 playback_thread = g_thread_create(decode_thread, filename, TRUE, NULL); | |
| 95 } | |
| 96 | |
| 97 static void stop(void) | |
| 98 { | |
| 99 g_thread_join(playback_thread); | |
| 100 output_close_audio(); | |
| 101 } | |
| 102 | |
| 103 static void seek(gint time) | |
| 104 { | |
| 105 /* unimplemented */ | |
| 106 } | |
| 107 | |
| 108 InputPlugin alac_ip = { | |
| 109 NULL, | |
| 110 NULL, | |
| 111 "Apple Lossless Plugin", /* Description */ | |
| 112 alac_init, | |
| 113 NULL, | |
| 114 NULL, | |
| 115 is_our_file, | |
| 116 NULL, | |
| 117 play_file, | |
| 118 stop, | |
| 119 output_pause, | |
| 120 seek, | |
| 121 NULL, | |
| 122 get_output_time, | |
| 123 NULL, | |
| 124 NULL, | |
| 125 NULL, | |
| 126 NULL, | |
| 127 NULL, | |
| 128 NULL, | |
| 129 NULL, | |
| 130 NULL, | |
| 131 NULL, /* file_info_box */ | |
| 132 NULL | |
| 133 }; | |
| 134 | |
| 135 static int get_sample_info(demux_res_t *demux_res, uint32_t samplenum, | |
| 136 uint32_t *sample_duration, | |
| 137 uint32_t *sample_byte_size) | |
| 138 { | |
| 139 unsigned int duration_index_accum = 0; | |
| 140 unsigned int duration_cur_index = 0; | |
| 141 | |
| 142 if (samplenum >= demux_res->num_sample_byte_sizes) | |
| 143 { | |
| 144 fprintf(stderr, "sample %i does not exist\n", samplenum); | |
| 145 return 0; | |
| 146 } | |
| 147 | |
| 148 if (!demux_res->num_time_to_samples) | |
| 149 { | |
| 150 fprintf(stderr, "no time to samples\n"); | |
| 151 return 0; | |
| 152 } | |
| 153 while ((demux_res->time_to_sample[duration_cur_index].sample_count + duration_index_accum) | |
| 154 <= samplenum) | |
| 155 { | |
| 156 duration_index_accum += demux_res->time_to_sample[duration_cur_index].sample_count; | |
| 157 duration_cur_index++; | |
| 158 if (duration_cur_index >= demux_res->num_time_to_samples) | |
| 159 { | |
| 160 fprintf(stderr, "sample %i does not have a duration\n", samplenum); | |
| 161 return 0; | |
| 162 } | |
| 163 } | |
| 164 | |
| 165 *sample_duration = demux_res->time_to_sample[duration_cur_index].sample_duration; | |
| 166 *sample_byte_size = demux_res->sample_byte_size[samplenum]; | |
| 167 | |
| 168 return 1; | |
| 169 } | |
| 170 | |
| 171 static void GetBuffer(demux_res_t *demux_res) | |
| 172 { | |
| 173 unsigned long destBufferSize = 1024*16; /* 16kb buffer = 4096 frames = 1 alac sample */ | |
| 174 void *pDestBuffer = malloc(destBufferSize); | |
| 175 int bytes_read = 0; | |
| 176 | |
| 177 unsigned int buffer_size = 1024*64; | |
| 178 void *buffer; | |
| 179 | |
| 180 unsigned int i; | |
| 181 | |
| 182 buffer = malloc(buffer_size); | |
| 183 | |
| 184 for (i = 0; i < demux_res->num_sample_byte_sizes; i++) | |
| 185 { | |
| 186 uint32_t sample_duration; | |
| 187 uint32_t sample_byte_size; | |
| 188 | |
| 189 int outputBytes; | |
| 190 | |
| 191 /* just get one sample for now */ | |
| 192 if (!get_sample_info(demux_res, i, | |
| 193 &sample_duration, &sample_byte_size)) | |
| 194 { | |
| 195 fprintf(stderr, "sample failed\n"); | |
| 196 return; | |
| 197 } | |
| 198 | |
| 199 if (buffer_size < sample_byte_size) | |
| 200 { | |
| 201 fprintf(stderr, "sorry buffer too small! (is %i want %i)\n", | |
| 202 buffer_size, | |
| 203 sample_byte_size); | |
| 204 return; | |
| 205 } | |
| 206 | |
| 207 stream_read(input_stream, sample_byte_size, | |
| 208 buffer); | |
| 209 | |
| 210 /* now fetch */ | |
| 211 outputBytes = destBufferSize; | |
| 212 decode_frame(alac, buffer, pDestBuffer, &outputBytes); | |
| 213 | |
| 214 /* write */ | |
| 215 bytes_read += outputBytes; | |
| 216 | |
| 217 if (verbose) | |
| 218 fprintf(stderr, "read %i bytes. total: %i\n", outputBytes, bytes_read); | |
| 219 | |
| 220 produce_audio(get_written_time(), FMT_S16_LE, demux_res->num_channels, outputBytes, pDestBuffer, NULL); | |
| 221 } | |
| 222 if (verbose) | |
| 223 fprintf(stderr, "done reading, read %i frames\n", i); | |
| 224 } | |
| 225 | |
| 226 static void init_sound_converter(demux_res_t *demux_res) | |
| 227 { | |
| 228 alac = create_alac(demux_res->sample_size, demux_res->num_channels); | |
| 229 | |
| 230 alac_set_info(alac, demux_res->codecdata); | |
| 231 } | |
| 232 | |
| 233 gpointer decode_thread(void *args) | |
| 234 { | |
| 235 demux_res_t demux_res; | |
| 236 unsigned int output_size, i; | |
| 237 | |
| 238 input_file = vfs_fopen((char *) args, "rb"); | |
| 239 #ifdef WORDS_BIGENDIAN | |
| 240 input_stream = stream_create_file(input_file, 1); | |
| 241 #else | |
| 242 input_stream = stream_create_file(input_file, 0); | |
| 243 #endif | |
| 244 if (!input_stream) | |
| 245 { | |
| 246 fprintf(stderr, "failed to create input stream from file\n"); | |
| 247 return 0; | |
| 248 } | |
| 249 | |
| 250 /* if qtmovie_read returns successfully, the stream is up to | |
| 251 * the movie data, which can be used directly by the decoder */ | |
| 252 if (!qtmovie_read(input_stream, &demux_res)) | |
| 253 { | |
| 254 fprintf(stderr, "failed to load the QuickTime movie headers\n"); | |
| 255 return 0; | |
| 256 } | |
| 257 | |
| 258 /* initialise the sound converter */ | |
| 259 init_sound_converter(&demux_res); | |
| 260 | |
| 261 /* will convert the entire buffer */ | |
| 262 GetBuffer(&demux_res); | |
| 263 | |
| 264 stream_destroy(input_stream); | |
| 265 | |
| 266 if (input_opened) | |
| 267 vfs_fclose(input_file); | |
| 268 | |
| 269 return NULL; | |
| 270 } | |
| 271 | |
| 272 InputPlugin *get_iplugin_info(void) | |
| 273 { | |
| 274 return &alac_ip; | |
| 275 } |
