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 }