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 }