2 * Copyright 2005 Timo Hirvonen
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License as
6 * published by the Free Software Foundation; either version 2 of the
7 * License, or (at your option) any later version.
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
25 #include <FLAC/seekable_stream_decoder.h>
26 #include <FLAC/metadata.h>
28 #include <sys/types.h>
33 #define UINT64_MAX ((uint64_t)-1)
36 /* Reduce typing. Namespaces are nice but FLAC API is fscking ridiculous. */
38 /* functions, types, enums */
39 #define F(s) FLAC__seekable_stream_decoder_ ## s
40 #define T(s) FLAC__SeekableStreamDecoder ## s
41 #define Dec FLAC__SeekableStreamDecoder
42 #define E(s) FLAC__SEEKABLE_STREAM_DECODER_ ## s
45 /* file/stream position and length */
53 unsigned int buf_size
;
54 unsigned int buf_wpos
;
55 unsigned int buf_rpos
;
57 struct keyval
*comments
;
61 unsigned int ignore_next_write
: 1;
64 static T(ReadStatus
) read_cb(const Dec
*dec
, unsigned char *buf
, unsigned *size
, void *data
)
66 struct input_plugin_data
*ip_data
= data
;
67 struct flac_private
*priv
= ip_data
->private;
72 d_print("EOF! EOF! EOF!\n");
73 return E(READ_STATUS_OK
);
76 return E(READ_STATUS_OK
);
78 rc
= read(ip_data
->fd
, buf
, *size
);
81 if (errno
== EINTR
|| errno
== EAGAIN
) {
82 /* FIXME: not sure how the flac decoder handles this */
83 d_print("interrupted\n");
84 return E(READ_STATUS_OK
);
86 return E(READ_STATUS_ERROR
);
89 d_print("%d != %d\n", rc
, *size
);
97 return E(READ_STATUS_OK
);
99 return E(READ_STATUS_OK
);
102 static T(SeekStatus
) seek_cb(const Dec
*dec
, uint64_t offset
, void *data
)
104 struct input_plugin_data
*ip_data
= data
;
105 struct flac_private
*priv
= ip_data
->private;
108 if (priv
->len
== UINT64_MAX
)
109 return E(SEEK_STATUS_ERROR
);
110 off
= lseek(ip_data
->fd
, offset
, SEEK_SET
);
112 return E(SEEK_STATUS_ERROR
);
115 return E(SEEK_STATUS_OK
);
118 static T(TellStatus
) tell_cb(const Dec
*dec
, uint64_t *offset
, void *data
)
120 struct input_plugin_data
*ip_data
= data
;
121 struct flac_private
*priv
= ip_data
->private;
125 return E(TELL_STATUS_OK
);
128 static T(LengthStatus
) length_cb(const Dec
*dec
, uint64_t *len
, void *data
)
130 struct input_plugin_data
*ip_data
= data
;
131 struct flac_private
*priv
= ip_data
->private;
134 if (ip_data
->remote
) {
135 return E(LENGTH_STATUS_ERROR
);
138 return E(LENGTH_STATUS_OK
);
141 static int eof_cb(const Dec
*dec
, void *data
)
143 struct input_plugin_data
*ip_data
= data
;
144 struct flac_private
*priv
= ip_data
->private;
146 d_print("%d\n", priv
->eof
);
150 static FLAC__StreamDecoderWriteStatus
write_cb(const Dec
*dec
, const FLAC__Frame
*frame
,
151 const int32_t * const *buf
, void *data
)
153 struct input_plugin_data
*ip_data
= data
;
154 struct flac_private
*priv
= ip_data
->private;
155 int samples
, bytes
, size
, channels
, bits
;
157 if (ip_data
->sf
== 0) {
158 return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE
;
161 if (priv
->ignore_next_write
) {
162 priv
->ignore_next_write
= 0;
163 return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE
;
166 samples
= frame
->header
.blocksize
;
167 channels
= sf_get_channels(ip_data
->sf
);
168 bits
= sf_get_bits(ip_data
->sf
);
169 bytes
= samples
* frame
->header
.bits_per_sample
/ 8 * channels
;
170 size
= priv
->buf_size
;
172 if (size
- priv
->buf_wpos
< bytes
) {
176 priv
->buf
= xrenew(char, priv
->buf
, size
);
177 priv
->buf_size
= size
;
181 char *b
= priv
->buf
+ priv
->buf_wpos
;
184 for (i
= 0; i
< samples
; i
++) {
185 for (ch
= 0; ch
< channels
; ch
++)
188 } else if (bits
== 16) {
189 int16_t *b
= (int16_t *)(priv
->buf
+ priv
->buf_wpos
);
192 for (i
= 0; i
< samples
; i
++) {
193 for (ch
= 0; ch
< channels
; ch
++)
196 } else if (bits
== 24) {
197 char *b
= (char *)(priv
->buf
+ priv
->buf_wpos
);
201 for (i
= 0; i
< samples
; i
++) {
202 for (ch
= 0; ch
< channels
; ch
++) {
203 int32_t sample
= buf
[ch
][i
];
205 /* FIXME: doesn't work with bin-endian machines? */
206 b
[j
++] = sample
& 0xff; sample
>>= 8;
207 b
[j
++] = sample
& 0xff; sample
>>= 8;
208 b
[j
++] = sample
& 0xff;
212 int32_t *b
= (int32_t *)(priv
->buf
+ priv
->buf_wpos
);
216 for (i
= 0; i
< samples
; i
++) {
217 for (ch
= 0; ch
< channels
; ch
++)
222 priv
->buf_wpos
+= bytes
;
223 return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE
;
226 /* You should make a copy of metadata with FLAC__metadata_object_clone() if you will
227 * need it elsewhere. Since metadata blocks can potentially be large, by
228 * default the decoder only calls the metadata callback for the STREAMINFO
229 * block; you can instruct the decoder to pass or filter other blocks with
230 * FLAC__stream_decoder_set_metadata_*() calls.
232 static void metadata_cb(const Dec
*dec
, const FLAC__StreamMetadata
*metadata
, void *data
)
234 struct input_plugin_data
*ip_data
= data
;
235 struct flac_private
*priv
= ip_data
->private;
237 switch (metadata
->type
) {
238 case FLAC__METADATA_TYPE_STREAMINFO
:
240 const FLAC__StreamMetadata_StreamInfo
*si
= &metadata
->data
.stream_info
;
242 d_print("STREAMINFO\n");
243 ip_data
->sf
= sf_rate(si
->sample_rate
) | sf_bits(si
->bits_per_sample
) |
244 sf_signed(1) | sf_channels(si
->channels
);
245 if (!ip_data
->remote
&& si
->total_samples
)
246 priv
->duration
= si
->total_samples
/ si
->sample_rate
;
249 case FLAC__METADATA_TYPE_VORBIS_COMMENT
:
250 d_print("VORBISCOMMENT\n");
251 if (priv
->comments
) {
252 d_print("Ignoring\n");
257 nr
= metadata
->data
.vorbis_comment
.num_comments
;
258 c
= xnew0(struct keyval
, nr
+ 1);
259 for (s
= 0, d
= 0; s
< nr
; s
++) {
262 /* until you have finished reading this function name
263 * you have already forgot WTF you're doing */
264 if (!FLAC__metadata_object_vorbiscomment_entry_to_name_value_pair(
265 metadata
->data
.vorbis_comment
.comments
[s
],
269 if (!is_interesting_key(key
)) {
274 if (!strcasecmp(key
, "tracknumber") || !strcasecmp(key
, "discnumber"))
275 fix_track_or_disc(val
);
277 d_print("comment: '%s=%s'\n", key
, val
);
286 d_print("something else\n");
291 static void error_cb(const Dec
*dec
, FLAC__StreamDecoderErrorStatus status
, void *data
)
293 /* struct input_plugin_data *ip_data = data; */
294 /* struct flac_private *priv = ip_data->private; */
299 static int flac_open(struct input_plugin_data
*ip_data
)
301 struct flac_private
*priv
;
306 return -IP_ERROR_INTERNAL
;
308 priv
= xnew(struct flac_private
, 1);
315 priv
->ignore_next_write
= 0;
317 priv
->comments
= NULL
;
319 if (ip_data
->remote
) {
320 priv
->len
= UINT64_MAX
;
322 off_t off
= lseek(ip_data
->fd
, 0, SEEK_END
);
324 if (off
== -1 || lseek(ip_data
->fd
, 0, SEEK_SET
) == -1) {
330 return -IP_ERROR_ERRNO
;
334 ip_data
->private = priv
;
336 F(set_read_callback
)(dec
, read_cb
);
337 F(set_seek_callback
)(dec
, seek_cb
);
338 F(set_tell_callback
)(dec
, tell_cb
);
339 F(set_length_callback
)(dec
, length_cb
);
340 F(set_eof_callback
)(dec
, eof_cb
);
341 F(set_write_callback
)(dec
, write_cb
);
342 F(set_metadata_callback
)(dec
, metadata_cb
);
343 F(set_error_callback
)(dec
, error_cb
);
344 F(set_client_data
)(dec
, ip_data
);
346 /* FLAC__METADATA_TYPE_STREAMINFO already accepted */
347 F(set_metadata_respond
)(dec
, FLAC__METADATA_TYPE_VORBIS_COMMENT
);
349 if (F(init
)(dec
) != E(OK
)) {
352 d_print("init failed\n");
353 F(delete)(priv
->dec
);
355 ip_data
->private = NULL
;
357 return -IP_ERROR_ERRNO
;
361 while (priv
->buf_wpos
== 0 && !priv
->eof
) {
362 if (!F(process_single
)(priv
->dec
)) {
365 d_print("process_single failed\n");
366 F(finish
)(priv
->dec
);
367 F(delete)(priv
->dec
);
369 free(priv
->comments
);
372 ip_data
->private = NULL
;
374 return -IP_ERROR_ERRNO
;
377 BUG_ON(ip_data
->sf
== 0);
378 d_print("sr: %d, ch: %d, bits: %d\n", sf_get_rate(ip_data
->sf
),
379 sf_get_channels(ip_data
->sf
), sf_get_bits(ip_data
->sf
));
383 static int flac_close(struct input_plugin_data
*ip_data
)
385 struct flac_private
*priv
= ip_data
->private;
387 F(finish
)(priv
->dec
);
388 F(delete)(priv
->dec
);
390 comments_free(priv
->comments
);
393 ip_data
->private = NULL
;
397 static int flac_read(struct input_plugin_data
*ip_data
, char *buffer
, int count
)
399 struct flac_private
*priv
= ip_data
->private;
401 int libflac_suck_count
= 0;
404 int old_pos
= priv
->buf_wpos
;
406 avail
= priv
->buf_wpos
- priv
->buf_rpos
;
412 if (!F(process_single
)(priv
->dec
)) {
413 d_print("process_single failed\n");
416 if (old_pos
== priv
->buf_wpos
) {
417 libflac_suck_count
++;
419 libflac_suck_count
= 0;
421 if (libflac_suck_count
> 5) {
422 d_print("libflac sucks\n");
429 memcpy(buffer
, priv
->buf
+ priv
->buf_rpos
, count
);
430 priv
->buf_rpos
+= count
;
431 BUG_ON(priv
->buf_rpos
> priv
->buf_wpos
);
432 if (priv
->buf_rpos
== priv
->buf_wpos
) {
439 /* Flush the input and seek to an absolute sample. Decoding will resume at the
440 * given sample. Note that because of this, the next write callback may contain
443 static int flac_seek(struct input_plugin_data
*ip_data
, double offset
)
445 struct flac_private
*priv
= ip_data
->private;
449 return -IP_ERROR_ERRNO
;
451 sample
= (uint64_t)(offset
* (double)sf_get_rate(ip_data
->sf
) + 0.5);
452 if (!F(seek_absolute
)(priv
->dec
, sample
)) {
453 return -IP_ERROR_ERRNO
;
455 priv
->ignore_next_write
= 1;
461 static int flac_read_comments(struct input_plugin_data
*ip_data
, struct keyval
**comments
)
463 struct flac_private
*priv
= ip_data
->private;
465 if (priv
->comments
) {
466 *comments
= comments_dup(priv
->comments
);
468 *comments
= xnew0(struct keyval
, 1);
473 static int flac_duration(struct input_plugin_data
*ip_data
)
475 struct flac_private
*priv
= ip_data
->private;
477 return priv
->duration
;
480 const struct input_plugin_ops ip_ops
= {
485 .read_comments
= flac_read_comments
,
486 .duration
= flac_duration
489 const char * const ip_extensions
[] = { "flac", "fla", NULL
};
490 const char * const ip_mime_types
[] = { NULL
};