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 } |