Mercurial > audlegacy-plugins
comparison src/flacng/seekable_stream_callbacks.c @ 930:2f742d127b3e trunk
[svn] - initial import of flacng from audacious-flacng-0.012
author | nenolod |
---|---|
date | Mon, 09 Apr 2007 10:55:23 -0700 |
parents | |
children | b6c95e2a14f4 |
comparison
equal
deleted
inserted
replaced
929:9631824411bf | 930:2f742d127b3e |
---|---|
1 /* | |
2 * A FLAC decoder plugin for the Audacious Media Player | |
3 * Copyright (C) 2005 Ralf Ertzinger | |
4 * | |
5 * This program is free software; you can redistribute it and/or modify | |
6 * it under the terms of the GNU General Public License as published by | |
7 * the Free Software Foundation; either version 2 of the License, or | |
8 * (at your option) any later version. | |
9 * | |
10 * This program is distributed in the hope that it will be useful, | |
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
13 * GNU General Public License for more details. | |
14 * | |
15 * You should have received a copy of the GNU General Public License | |
16 * along with this program; if not, write to the Free Software | |
17 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | |
18 */ | |
19 | |
20 #include <string.h> | |
21 #include <FLAC/all.h> | |
22 #include <glib.h> | |
23 #include <glib/gi18n.h> | |
24 #include <audacious/vfs.h> | |
25 #include "flacng.h" | |
26 #include "tools.h" | |
27 #include "seekable_stream_callbacks.h" | |
28 #include "debug.h" | |
29 | |
30 /* === */ | |
31 | |
32 FLAC__StreamDecoderReadStatus read_callback(const FLAC__StreamDecoder *decoder, FLAC__byte buffer[], unsigned *bytes, void *client_data) { | |
33 | |
34 callback_info* info; | |
35 gint to_read; | |
36 size_t read; | |
37 | |
38 _ENTER; | |
39 | |
40 info = (callback_info*) client_data; | |
41 _DEBUG("Using callback_info %s", info->name); | |
42 | |
43 if (NULL == info->input_stream) { | |
44 _ERROR("Trying to read data from an uninitialized file!"); | |
45 _LEAVE FLAC__STREAM_DECODER_READ_STATUS_ABORT; | |
46 } | |
47 | |
48 if (0 <= info->read_max) { | |
49 to_read = MIN(*bytes, info->read_max); | |
50 _DEBUG("Reading restricted to %d bytes", info->read_max); | |
51 } else { | |
52 to_read = *bytes; | |
53 } | |
54 | |
55 if (0 == to_read) { | |
56 _LEAVE FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM; | |
57 } | |
58 | |
59 read = vfs_fread(buffer, 1, to_read, info->input_stream); | |
60 | |
61 if ((0 < read) && (0 < info->read_max)) { | |
62 info->read_max -= read; | |
63 } | |
64 | |
65 _DEBUG("Wanted %d bytes, got %d bytes", *bytes, read); | |
66 *bytes = read; | |
67 | |
68 switch(read) { | |
69 case -1: | |
70 _ERROR("Error while reading from stream!"); | |
71 _LEAVE FLAC__STREAM_DECODER_READ_STATUS_ABORT; | |
72 break; | |
73 | |
74 case 0: | |
75 _DEBUG("Stream reached EOF"); | |
76 _LEAVE FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM; | |
77 break; | |
78 | |
79 default: | |
80 _LEAVE FLAC__STREAM_DECODER_READ_STATUS_CONTINUE; | |
81 } | |
82 } | |
83 | |
84 /* --- */ | |
85 | |
86 FLAC__StreamDecoderSeekStatus seek_callback(const FLAC__StreamDecoder *decoder, FLAC__uint64 absolute_byte_offset, void *client_data) { | |
87 | |
88 callback_info* info; | |
89 | |
90 _ENTER; | |
91 | |
92 info = (callback_info*) client_data; | |
93 _DEBUG("Using callback_info %s", info->name); | |
94 | |
95 _DEBUG("Seeking to %lld", absolute_byte_offset); | |
96 | |
97 if (0 != vfs_fseek(info->input_stream, absolute_byte_offset, SEEK_SET)) { | |
98 _ERROR("Could not seek to %lld!", absolute_byte_offset); | |
99 _LEAVE FLAC__STREAM_DECODER_SEEK_STATUS_ERROR; | |
100 } | |
101 | |
102 _LEAVE FLAC__STREAM_DECODER_SEEK_STATUS_OK; | |
103 } | |
104 | |
105 /* --- */ | |
106 | |
107 FLAC__StreamDecoderTellStatus tell_callback(const FLAC__StreamDecoder *decoder, FLAC__uint64 *absolute_byte_offset, void *client_data) { | |
108 | |
109 callback_info* info; | |
110 glong position; | |
111 | |
112 _ENTER; | |
113 | |
114 info = (callback_info*) client_data; | |
115 _DEBUG("Using callback_info %s", info->name); | |
116 | |
117 if (-1 == (position = vfs_ftell(info->input_stream))) { | |
118 fprintf(stderr, "Could not tell current position!"); | |
119 return FLAC__STREAM_DECODER_TELL_STATUS_ERROR; | |
120 } | |
121 | |
122 _DEBUG("Current position: %d", position); | |
123 | |
124 *absolute_byte_offset = position; | |
125 | |
126 _LEAVE FLAC__STREAM_DECODER_TELL_STATUS_OK; | |
127 } | |
128 | |
129 /* --- */ | |
130 | |
131 FLAC__bool eof_callback(const FLAC__StreamDecoder *decoder, void *client_data) { | |
132 | |
133 callback_info* info; | |
134 gboolean eof; | |
135 | |
136 _ENTER; | |
137 | |
138 info = (callback_info*) client_data; | |
139 _DEBUG("Using callback_info %s", info->name); | |
140 | |
141 eof = vfs_feof(info->input_stream); | |
142 | |
143 _LEAVE eof; | |
144 } | |
145 | |
146 /* --- */ | |
147 | |
148 FLAC__StreamDecoderLengthStatus length_callback(const FLAC__StreamDecoder *decoder, FLAC__uint64 *stream_length, void *client_data) { | |
149 | |
150 callback_info* info; | |
151 size_t size; | |
152 | |
153 _ENTER; | |
154 | |
155 info = (callback_info*) client_data; | |
156 _DEBUG("Using callback_info %s", info->name); | |
157 | |
158 *stream_length = 0; | |
159 | |
160 _LEAVE FLAC__STREAM_DECODER_LENGTH_STATUS_OK; | |
161 } | |
162 | |
163 /* --- */ | |
164 | |
165 FLAC__StreamDecoderWriteStatus write_callback(const FLAC__StreamDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 * const buffer[], void *client_data) { | |
166 | |
167 glong i; | |
168 gshort j; | |
169 gint32 sample; | |
170 callback_info* info; | |
171 | |
172 _ENTER; | |
173 | |
174 info = (callback_info*) client_data; | |
175 _DEBUG("Using callback_info %s", info->name); | |
176 | |
177 _DEBUG("Frame decoded: %d samples per channel, %d channels, %d bps", | |
178 frame->header.blocksize, frame->header.channels, frame->header.bits_per_sample); | |
179 | |
180 /* | |
181 * Check if there is more data decoded than we have space | |
182 * for. This _should_ not happen given how our buffer is sized, | |
183 * but you never know. | |
184 */ | |
185 if (info->buffer_free < (frame->header.blocksize * frame->header.channels)) { | |
186 _ERROR("BUG! Too much data decoded from stream!"); | |
187 _LEAVE FLAC__STREAM_DECODER_WRITE_STATUS_ABORT; | |
188 } | |
189 | |
190 if ((frame->header.bits_per_sample != 8) && | |
191 (frame->header.bits_per_sample != 16) && | |
192 (frame->header.bits_per_sample != 24)) { | |
193 _ERROR("Unsupported bitrate found in stream: %d!", frame->header.bits_per_sample); | |
194 _LEAVE FLAC__STREAM_DECODER_WRITE_STATUS_ABORT; | |
195 } | |
196 | |
197 /* | |
198 * Copy the frame metadata, will be compared to stream | |
199 * metadata later | |
200 * This also describes the format of the current buffer content. | |
201 */ | |
202 info->frame.channels = frame->header.channels; | |
203 info->frame.samplerate = frame->header.sample_rate; | |
204 info->frame.bits_per_sample = frame->header.bits_per_sample; | |
205 | |
206 for (i=0; i < frame->header.blocksize; i++) { | |
207 for (j=0; j < frame->header.channels; j++) { | |
208 *(info->write_pointer++) = buffer[j][i]; | |
209 info->buffer_free -= 1; | |
210 info->buffer_used += 1; | |
211 } | |
212 } | |
213 | |
214 _DEBUG("free space in buffer after copying: %d samples", info->buffer_free); | |
215 | |
216 _LEAVE FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE; | |
217 } | |
218 | |
219 /* --- */ | |
220 | |
221 void error_callback(const FLAC__StreamDecoder *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data) { | |
222 | |
223 _ENTER; | |
224 | |
225 _ERROR("FLAC decoder error callback was called: %d", status); | |
226 | |
227 _LEAVE; | |
228 | |
229 } | |
230 | |
231 /* --- */ | |
232 | |
233 void metadata_callback(const FLAC__StreamDecoder *decoder, const FLAC__StreamMetadata *metadata, void *client_data) { | |
234 | |
235 callback_info* info; | |
236 gint i; | |
237 FLAC__StreamMetadata_VorbisComment_Entry* entry; | |
238 FLAC__StreamMetadata* metadata_copy; | |
239 gchar* key; | |
240 gchar* value; | |
241 int artist_offset; | |
242 | |
243 _ENTER; | |
244 | |
245 info = (callback_info*) client_data; | |
246 _DEBUG("Using callback_info %s", info->name); | |
247 | |
248 /* | |
249 * We have found a metadata block. Enable unrestricted reading | |
250 */ | |
251 info->read_max = -1; | |
252 | |
253 if (FLAC__METADATA_TYPE_STREAMINFO == metadata->type) { | |
254 /* | |
255 * Basic stream information. Sample rate, channels and stuff | |
256 */ | |
257 _DEBUG("FLAC__METADATA_TYPE_STREAMINFO found"); | |
258 | |
259 info->stream.samples = metadata->data.stream_info.total_samples; | |
260 _DEBUG("total_samples=%lld", metadata->data.stream_info.total_samples); | |
261 info->stream.bits_per_sample = metadata->data.stream_info.bits_per_sample; | |
262 _DEBUG("bits_per_sample=%d", metadata->data.stream_info.bits_per_sample); | |
263 info->stream.channels = metadata->data.stream_info.channels; | |
264 _DEBUG("channels=%d", metadata->data.stream_info.channels); | |
265 info->stream.samplerate = metadata->data.stream_info.sample_rate; | |
266 _DEBUG("sample_rate=%d", metadata->data.stream_info.sample_rate); | |
267 | |
268 info->metadata_changed = TRUE; | |
269 } | |
270 | |
271 if (FLAC__METADATA_TYPE_VORBIS_COMMENT == metadata->type) { | |
272 /* | |
273 * We will possibly need to modify some of the entries | |
274 * in the metadata field, so we make a copy of it | |
275 * first. | |
276 * The original structure must not be modified. | |
277 */ | |
278 metadata_copy = FLAC__metadata_object_clone(metadata); | |
279 | |
280 /* | |
281 * A vorbis type comment field. | |
282 */ | |
283 _DEBUG("FLAC__METADATA_TYPE_VORBIS_COMMENT found"); | |
284 _DEBUG("Vorbis comment contains %d fields", metadata_copy->data.vorbis_comment.num_comments); | |
285 _DEBUG("Vendor string: %s", metadata_copy->data.vorbis_comment.vendor_string.entry); | |
286 | |
287 /* | |
288 * Find an ARTIST field | |
289 */ | |
290 if (0 <= (artist_offset = FLAC__metadata_object_vorbiscomment_find_entry_from(metadata_copy, 0, "ARTIST"))) { | |
291 _DEBUG("ARTIST field found @ %d: %s", artist_offset, | |
292 metadata_copy->data.vorbis_comment.comments[artist_offset].entry); | |
293 } | |
294 | |
295 | |
296 /* | |
297 * Enumerate the comment entries | |
298 */ | |
299 entry = metadata_copy->data.vorbis_comment.comments; | |
300 for (i=0; i < metadata_copy->data.vorbis_comment.num_comments; i++,entry++) { | |
301 _DEBUG("Comment[%d]: %s", i, entry->entry); | |
302 | |
303 /* | |
304 * Try and parse the comment. | |
305 * If FLAC__metadata_object_vorbiscomment_entry_to_name_value_pair() succeeds, | |
306 * it allocates memory for the key and value which we have to take | |
307 * care of. | |
308 */ | |
309 if (false == FLAC__metadata_object_vorbiscomment_entry_to_name_value_pair(*entry, &key, &value)) { | |
310 _DEBUG("Could not parse comment"); | |
311 } else { | |
312 _DEBUG("Key: <%s>, Value <%s>", key, value); | |
313 add_comment(info, key, value); | |
314 free(key); | |
315 free(value); | |
316 } | |
317 } | |
318 | |
319 /* | |
320 * Free our metadata copy | |
321 */ | |
322 FLAC__metadata_object_delete(metadata_copy); | |
323 | |
324 info->metadata_changed = TRUE; | |
325 } | |
326 | |
327 if (FLAC__METADATA_TYPE_SEEKTABLE == metadata->type) { | |
328 /* | |
329 * We have found a seektable, which means that we can seek | |
330 * without telling FLAC the length of the file (which we can not | |
331 * do, since Audacious lacks the functions for that) | |
332 */ | |
333 _DEBUG("FLAC__METADATA_TYPE_SEEKTABLE found"); | |
334 info->stream.has_seektable = TRUE; | |
335 } | |
336 | |
337 _LEAVE; | |
338 } |