Mercurial > mplayer.hg
annotate libmpcodecs/ad_flac.c @ 11599:ad9216814665
sync tag update
author | wight |
---|---|
date | Mon, 08 Dec 2003 22:28:50 +0000 |
parents | 1188bf65b776 |
children | 8ab2028e6ed9 |
rev | line source |
---|---|
11004 | 1 /* |
2 * This is FLAC decoder for MPlayer using stream_decoder from libFLAC | |
3 * (directly or from libmpflac). | |
4 * This file is part of MPlayer, see http://mplayerhq.hu/ for info. | |
5 * Copyright (C) 2003 Dmitry Baryshkov <mitya at school.ioffe.ru> | |
6 * | |
7 * This program is free software; you can redistribute it and/or modify | |
8 * it under the terms of the GNU General Public License as published by | |
9 * the Free Software Foundation; either version 2 of the License, or | |
10 * (at your option) any later version. | |
11 * | |
12 * This program is distributed in the hope that it will be useful, | |
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
15 * GNU General Public License for more details. | |
16 * | |
17 * You should have received a copy of the GNU General Public License | |
18 * along with this program; if not, write to the Free Software | |
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
20 * | |
21 * parse_double_, grabbag__replaygain_load_from_vorbiscomment, grabbag__replaygain_compute_scale_factor | |
22 * functions are imported from FLAC project (from grabbag lib sources (replaygain.c)) and are | |
23 * Copyright (C) 2002,2003 Josh Coalson under the terms of GPL. | |
24 */ | |
25 | |
26 /* | |
27 * TODO: | |
28 * in demux_audio use data from seektable block for seeking. | |
29 * support FLAC-in-Ogg. | |
30 */ | |
31 | |
32 #include <stdio.h> | |
33 #include <stdlib.h> | |
34 #include <unistd.h> | |
35 #include <math.h> | |
36 | |
37 #include "config.h" | |
38 #ifdef HAVE_FLAC | |
39 #include "ad_internal.h" | |
40 #include "mp_msg.h" | |
41 | |
42 static ad_info_t info = { | |
43 "FLAC audio decoder", // name of the driver | |
44 "flac", // driver name. should be the same as filename without ad_ | |
45 "Dmitry Baryshkov", // writer/maintainer of _this_ file | |
46 "http://flac.sf.net/", // writer/maintainer/site of the _codec_ | |
47 "" // comments | |
48 }; | |
49 | |
50 LIBAD_EXTERN(flac) | |
51 | |
52 #ifdef USE_MPFLAC_DECODER | |
53 #include "FLAC_stream_decoder.h" | |
54 #include "FLAC_assert.h" | |
55 #include "FLAC_metadata.h" | |
56 #else | |
57 #include "FLAC/stream_decoder.h" | |
58 #include "FLAC/assert.h" | |
59 #include "FLAC/metadata.h" | |
60 #endif | |
61 | |
62 /* dithering & replaygain always from libmpflac */ | |
63 #include "dither.h" | |
64 #include "replaygain_synthesis.h" | |
65 | |
66 /* Some global constants. Thay have to be configurable, so leaved them as globals. */ | |
67 static const FLAC__bool album_mode = true; | |
68 static const int preamp = 0; | |
69 static const FLAC__bool hard_limit = false; | |
70 static const int noise_shaping = 1; | |
71 static const FLAC__bool dither = true; | |
72 typedef struct flac_struct_st | |
73 { | |
74 FLAC__StreamDecoder *flac_dec; /*decoder handle*/ | |
75 sh_audio_t *sh; /* link back to corresponding sh */ | |
76 | |
77 /* set this fields before calling FLAC__stream_decoder_process_single */ | |
78 unsigned char *buf; | |
79 int minlen; | |
80 int maxlen; | |
81 /* Here goes number written at write_callback */ | |
82 int written; | |
83 | |
84 /* replaygain and dithering via plugin_common */ | |
85 FLAC__bool has_replaygain; | |
86 double replay_scale; | |
87 DitherContext dither_context; | |
88 int bits_per_sample; | |
89 } flac_struct_t; | |
90 | |
91 FLAC__StreamDecoderReadStatus flac_read_callback (const FLAC__StreamDecoder *decoder, FLAC__byte buffer[], unsigned *bytes, void *client_data) | |
92 { | |
11476
1188bf65b776
Made the FLAC decoder be less greedy resulting in much better A/V sync handling.
mosu
parents:
11004
diff
changeset
|
93 /* Don't be greedy. Try to read as few packets as possible. *bytes is often |
1188bf65b776
Made the FLAC decoder be less greedy resulting in much better A/V sync handling.
mosu
parents:
11004
diff
changeset
|
94 > 60kb big which is more than one second of data. Reading it all at |
1188bf65b776
Made the FLAC decoder be less greedy resulting in much better A/V sync handling.
mosu
parents:
11004
diff
changeset
|
95 once sucks in all packets available making d_audio->pts jump to the |
1188bf65b776
Made the FLAC decoder be less greedy resulting in much better A/V sync handling.
mosu
parents:
11004
diff
changeset
|
96 pts of the last packet read which is not what we want. We're decoging |
1188bf65b776
Made the FLAC decoder be less greedy resulting in much better A/V sync handling.
mosu
parents:
11004
diff
changeset
|
97 only one FLAC block anyway, so let's just read as few bytes as |
1188bf65b776
Made the FLAC decoder be less greedy resulting in much better A/V sync handling.
mosu
parents:
11004
diff
changeset
|
98 neccessary. */ |
1188bf65b776
Made the FLAC decoder be less greedy resulting in much better A/V sync handling.
mosu
parents:
11004
diff
changeset
|
99 int b = demux_read_data(((flac_struct_t*)client_data)->sh->ds, buffer, *bytes > 500 ? 500 : *bytes); |
1188bf65b776
Made the FLAC decoder be less greedy resulting in much better A/V sync handling.
mosu
parents:
11004
diff
changeset
|
100 mp_msg(MSGT_DECAUDIO, MSGL_DBG2, "\nFLAC READ CB read %d bytes\n", b); |
11004 | 101 *bytes = b; |
102 if (b <= 0) | |
103 return FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM; | |
104 return FLAC__STREAM_DECODER_READ_STATUS_CONTINUE; | |
105 } | |
106 | |
107 /*FIXME: we need to support format conversion:(flac specs allow bits/sample to be from 4 to 32. Not only 8 and 16 !!!)*/ | |
108 FLAC__StreamDecoderWriteStatus flac_write_callback(const FLAC__StreamDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 * const buffer[], void *client_data) | |
109 { | |
110 FLAC__byte *buf = ((flac_struct_t*)(client_data))->buf; | |
111 int channel, sample; | |
112 int bps = ((flac_struct_t*)(client_data))->sh->samplesize; | |
113 mp_msg(MSGT_DECAUDIO, MSGL_DBG2, "\nWrite callback (%d bytes)!!!!\n", bps*frame->header.blocksize*frame->header.channels); | |
114 if (buf == NULL) | |
115 { | |
116 /* This is used in control for skipping 1 audio frame */ | |
117 return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE; | |
118 } | |
119 #if 0 | |
120 for (sample = 0; sample < frame->header.blocksize; sample ++) | |
121 for (channel = 0; channel < frame->header.channels; channel ++) | |
122 switch (bps) | |
123 { | |
124 case 3: | |
125 buf[bps*(sample*frame->header.channels+channel)+2] = (FLAC__byte)(buffer[channel][sample]>>16); | |
126 case 2: | |
127 buf[bps*(sample*frame->header.channels+channel)+1] = (FLAC__byte)(buffer[channel][sample]>>8); | |
128 buf[bps*(sample*frame->header.channels+channel)+0] = (FLAC__byte)(buffer[channel][sample]); | |
129 break; | |
130 case 1: | |
131 buf[bps*(sample*frame->header.channels+channel)] = buffer[channel][sample]^0x80; | |
132 break; | |
133 } | |
134 #else | |
135 FLAC__plugin_common__apply_gain( | |
136 buf, | |
137 buffer, | |
138 frame->header.blocksize, | |
139 frame->header.channels, | |
140 ((flac_struct_t*)(client_data))->bits_per_sample, | |
141 ((flac_struct_t*)(client_data))->sh->samplesize * 8, | |
142 ((flac_struct_t*)(client_data))->replay_scale, | |
143 hard_limit, | |
144 dither, | |
145 &(((flac_struct_t*)(client_data))->dither_context) | |
146 ); | |
147 #endif | |
148 ((flac_struct_t*)(client_data))->written += bps*frame->header.blocksize*frame->header.channels; | |
149 return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE; | |
150 } | |
151 | |
152 #ifdef local_min | |
153 #undef local_min | |
154 #endif | |
155 #define local_min(a,b) ((a)<(b)?(a):(b)) | |
156 | |
157 static FLAC__bool parse_double_(const FLAC__StreamMetadata_VorbisComment_Entry *entry, double *val) | |
158 { | |
159 char s[32], *end; | |
160 const char *p, *q; | |
161 double v; | |
162 | |
163 FLAC__ASSERT(0 != entry); | |
164 FLAC__ASSERT(0 != val); | |
165 | |
166 p = (const char *)entry->entry; | |
167 q = strchr(p, '='); | |
168 if(0 == q) | |
169 return false; | |
170 q++; | |
171 memset(s, 0, sizeof(s)-1); | |
172 strncpy(s, q, local_min(sizeof(s)-1, entry->length - (q-p))); | |
173 | |
174 v = strtod(s, &end); | |
175 if(end == s) | |
176 return false; | |
177 | |
178 *val = v; | |
179 return true; | |
180 } | |
181 | |
182 FLAC__bool grabbag__replaygain_load_from_vorbiscomment(const FLAC__StreamMetadata *block, FLAC__bool album_mode, double *gain, double *peak) | |
183 { | |
184 int gain_offset, peak_offset; | |
185 static const FLAC__byte *tag_title_gain_ = "REPLAYGAIN_TRACK_GAIN"; | |
186 static const FLAC__byte *tag_title_peak_ = "REPLAYGAIN_TRACK_PEAK"; | |
187 static const FLAC__byte *tag_album_gain_ = "REPLAYGAIN_ALBUM_GAIN"; | |
188 static const FLAC__byte *tag_album_peak_ = "REPLAYGAIN_ALBUM_PEAK"; | |
189 | |
190 FLAC__ASSERT(0 != block); | |
191 FLAC__ASSERT(block->type == FLAC__METADATA_TYPE_VORBIS_COMMENT); | |
192 | |
193 if(0 > (gain_offset = FLAC__metadata_object_vorbiscomment_find_entry_from(block, /*offset=*/0, (const char *)(album_mode? tag_album_gain_ : tag_title_gain_)))) | |
194 return false; | |
195 if(0 > (peak_offset = FLAC__metadata_object_vorbiscomment_find_entry_from(block, /*offset=*/0, (const char *)(album_mode? tag_album_peak_ : tag_title_peak_)))) | |
196 return false; | |
197 | |
198 if(!parse_double_(block->data.vorbis_comment.comments + gain_offset, gain)) | |
199 return false; | |
200 if(!parse_double_(block->data.vorbis_comment.comments + peak_offset, peak)) | |
201 return false; | |
202 | |
203 return true; | |
204 } | |
205 | |
206 double grabbag__replaygain_compute_scale_factor(double peak, double gain, double preamp, FLAC__bool prevent_clipping) | |
207 { | |
208 double scale; | |
209 FLAC__ASSERT(peak >= 0.0); | |
210 gain += preamp; | |
211 scale = (float) pow(10.0, gain * 0.05); | |
212 if(prevent_clipping && peak > 0.0) { | |
213 const double max_scale = (float)(1.0 / peak); | |
214 if(scale > max_scale) | |
215 scale = max_scale; | |
216 } | |
217 return scale; | |
218 } | |
219 | |
220 void flac_metadata_callback (const FLAC__StreamDecoder *decoder, const FLAC__StreamMetadata *metadata, void *client_data) | |
221 { | |
222 int i, j; | |
223 sh_audio_t *sh = ((flac_struct_t*)client_data)->sh; | |
224 mp_msg(MSGT_DECAUDIO, MSGL_DBG2, "Metadata received\n"); | |
225 switch (metadata->type) | |
226 { | |
227 case FLAC__METADATA_TYPE_STREAMINFO: | |
228 mp_msg(MSGT_DECAUDIO, MSGL_V, "STREAMINFO block (%u bytes):\n", metadata->length); | |
229 mp_msg(MSGT_DECAUDIO, MSGL_V, "min_blocksize: %u samples\n", metadata->data.stream_info.min_blocksize); | |
230 mp_msg(MSGT_DECAUDIO, MSGL_V, "max_blocksize: %u samples\n", metadata->data.stream_info.max_blocksize); | |
231 mp_msg(MSGT_DECAUDIO, MSGL_V, "min_framesize: %u bytes\n", metadata->data.stream_info.min_framesize); | |
232 mp_msg(MSGT_DECAUDIO, MSGL_V, "max_framesize: %u bytes\n", metadata->data.stream_info.max_framesize); | |
233 mp_msg(MSGT_DECAUDIO, MSGL_V, "sample_rate: %u Hz\n", metadata->data.stream_info.sample_rate); | |
234 sh->samplerate = metadata->data.stream_info.sample_rate; | |
235 mp_msg(MSGT_DECAUDIO, MSGL_V, "channels: %u\n", metadata->data.stream_info.channels); | |
236 sh->channels = metadata->data.stream_info.channels; | |
237 mp_msg(MSGT_DECAUDIO, MSGL_V, "bits_per_sample: %u\n", metadata->data.stream_info.bits_per_sample); | |
238 ((flac_struct_t*)client_data)->bits_per_sample = metadata->data.stream_info.bits_per_sample; | |
239 sh->samplesize = (metadata->data.stream_info.bits_per_sample<=8)?1:2; | |
240 /* FIXME: need to support dithering to samplesize 4 */ | |
241 sh->sample_format=(sh->samplesize==1)?AFMT_U8:AFMT_S16_LE; // sample format, see libao2/afmt.h | |
242 sh->o_bps = sh->samplesize * metadata->data.stream_info.channels * metadata->data.stream_info.sample_rate; | |
243 sh->i_bps = metadata->data.stream_info.bits_per_sample * metadata->data.stream_info.channels * metadata->data.stream_info.sample_rate / 8 / 2; | |
244 // input data rate (compressed bytes per second) | |
245 // Compression rate is near 0.5 | |
246 mp_msg(MSGT_DECAUDIO, MSGL_V, "total_samples: %llu\n", metadata->data.stream_info.total_samples); | |
247 mp_msg(MSGT_DECAUDIO, MSGL_V, "md5sum: "); | |
248 for (i = 0; i < 16; i++) | |
249 mp_msg(MSGT_DECAUDIO, MSGL_V, "%02hhx", metadata->data.stream_info.md5sum[i]); | |
250 mp_msg(MSGT_DECAUDIO, MSGL_V, "\n"); | |
251 | |
252 break; | |
253 case FLAC__METADATA_TYPE_PADDING: | |
254 mp_msg(MSGT_DECAUDIO, MSGL_V, "PADDING block (%u bytes)\n", metadata->length); | |
255 break; | |
256 case FLAC__METADATA_TYPE_APPLICATION: | |
257 mp_msg(MSGT_DECAUDIO, MSGL_V, "APPLICATION block (%u bytes):\n", metadata->length); | |
258 mp_msg(MSGT_DECAUDIO, MSGL_V, "Application id: 0x"); | |
259 for (i = 0; i < 4; i++) | |
260 mp_msg(MSGT_DECAUDIO, MSGL_V, "%02hhx", metadata->data.application.id[i]); | |
261 mp_msg(MSGT_DECAUDIO, MSGL_V, "\nData: \n"); | |
262 for (i = 0; i < (metadata->length-4)/8; i++) | |
263 { | |
264 for(j = 0; j < 8; j++) | |
265 mp_msg(MSGT_DECAUDIO, MSGL_V, "%c", (unsigned char)metadata->data.application.data[i*8+j]<0x20?'.':metadata->data.application.data[i*8+j]); | |
266 mp_msg(MSGT_DECAUDIO, MSGL_V, " | "); | |
267 for(j = 0; j < 8; j++) | |
268 mp_msg(MSGT_DECAUDIO, MSGL_V, "%#02hhx ", metadata->data.application.data[i*8+j]); | |
269 mp_msg(MSGT_DECAUDIO, MSGL_V, "\n"); | |
270 } | |
271 if (metadata->length-4-i*8 != 0) | |
272 { | |
273 for(j = 0; j < metadata->length-4-i*8; j++) | |
274 mp_msg(MSGT_DECAUDIO, MSGL_V, "%c", (unsigned char)metadata->data.application.data[i*8+j]<0x20?'.':metadata->data.application.data[i*8+j]); | |
275 for(; j <8; j++) | |
276 mp_msg(MSGT_DECAUDIO, MSGL_V, " "); | |
277 mp_msg(MSGT_DECAUDIO, MSGL_V, " | "); | |
278 for(j = 0; j < metadata->length-4-i*8; j++) | |
279 mp_msg(MSGT_DECAUDIO, MSGL_V, "%#02hhx ", metadata->data.application.data[i*8+j]); | |
280 mp_msg(MSGT_DECAUDIO, MSGL_V, "\n"); | |
281 } | |
282 break; | |
283 case FLAC__METADATA_TYPE_SEEKTABLE: | |
284 mp_msg(MSGT_DECAUDIO, MSGL_V, "SEEKTABLE block (%u bytes):\n", metadata->length); | |
285 mp_msg(MSGT_DECAUDIO, MSGL_V, "%d seekpoints:\n", metadata->data.seek_table.num_points); | |
286 for (i = 0; i < metadata->data.seek_table.num_points; i++) | |
287 if (metadata->data.seek_table.points[i].sample_number != FLAC__STREAM_METADATA_SEEKPOINT_PLACEHOLDER) | |
288 mp_msg(MSGT_DECAUDIO, MSGL_V, " %3d) sample_number=%llu stream_offset=%llu frame_samples=%u\n", i, | |
289 metadata->data.seek_table.points[i].sample_number, | |
290 metadata->data.seek_table.points[i].stream_offset, | |
291 metadata->data.seek_table.points[i].frame_samples); | |
292 else | |
293 mp_msg(MSGT_DECAUDIO, MSGL_V, " %3d) PLACEHOLDER\n", i); | |
294 break; | |
295 case FLAC__METADATA_TYPE_VORBIS_COMMENT: | |
296 mp_msg(MSGT_DECAUDIO, MSGL_V, "VORBISCOMMENT block (%u bytes):\n", metadata->length); | |
297 { | |
298 char entry[metadata->data.vorbis_comment.vendor_string.length+1]; | |
299 memcpy(&entry, metadata->data.vorbis_comment.vendor_string.entry, metadata->data.vorbis_comment.vendor_string.length); | |
300 entry[metadata->data.vorbis_comment.vendor_string.length] = '\0'; | |
301 mp_msg(MSGT_DECAUDIO, MSGL_V, "vendor_string: %s\n", entry); | |
302 } | |
303 mp_msg(MSGT_DECAUDIO, MSGL_V, "%d comment(s):\n", metadata->data.vorbis_comment.num_comments); | |
304 for (i = 0; i < metadata->data.vorbis_comment.num_comments; i++) | |
305 { | |
306 char entry[metadata->data.vorbis_comment.comments[i].length]; | |
307 memcpy(&entry, metadata->data.vorbis_comment.comments[i].entry, metadata->data.vorbis_comment.comments[i].length); | |
308 entry[metadata->data.vorbis_comment.comments[i].length] = '\0'; | |
309 mp_msg(MSGT_DECAUDIO, MSGL_V, "%s\n", entry); | |
310 } | |
311 { | |
312 double gain, peak; | |
313 if(grabbag__replaygain_load_from_vorbiscomment(metadata, album_mode, &gain, &peak)) | |
314 { | |
315 ((flac_struct_t*)client_data)->has_replaygain = true; | |
316 ((flac_struct_t*)client_data)->replay_scale = grabbag__replaygain_compute_scale_factor(peak, gain, (double)preamp, /*prevent_clipping=*/!hard_limit); | |
317 mp_msg(MSGT_DECAUDIO, MSGL_V, "calculated replay_scale: %lf\n", ((flac_struct_t*)client_data)->replay_scale); | |
318 } | |
319 } | |
320 break; | |
321 case FLAC__METADATA_TYPE_CUESHEET: | |
322 mp_msg(MSGT_DECAUDIO, MSGL_V, "CUESHEET block (%u bytes):\n", metadata->length); | |
323 mp_msg(MSGT_DECAUDIO, MSGL_V, "mcn: '%s'\n", metadata->data.cue_sheet.media_catalog_number); | |
324 mp_msg(MSGT_DECAUDIO, MSGL_V, "lead_in: %llu\n", metadata->data.cue_sheet.lead_in); | |
325 mp_msg(MSGT_DECAUDIO, MSGL_V, "is_cd: %s\n", metadata->data.cue_sheet.is_cd?"true":"false"); | |
326 mp_msg(MSGT_DECAUDIO, MSGL_V, "num_tracks: %u\n", metadata->data.cue_sheet.num_tracks); | |
327 for (i = 0; i < metadata->data.cue_sheet.num_tracks; i++) | |
328 { | |
329 mp_msg(MSGT_DECAUDIO, MSGL_V, "track[%d]:\n", i); | |
330 mp_msg(MSGT_DECAUDIO, MSGL_V, "offset: %llu\n", metadata->data.cue_sheet.tracks[i].offset); | |
331 mp_msg(MSGT_DECAUDIO, MSGL_V, "number: %hhu%s\n", metadata->data.cue_sheet.tracks[i].number, metadata->data.cue_sheet.tracks[i].number==170?"(LEAD-OUT)":""); | |
332 mp_msg(MSGT_DECAUDIO, MSGL_V, "isrc: '%s'\n", metadata->data.cue_sheet.tracks[i].isrc); | |
333 mp_msg(MSGT_DECAUDIO, MSGL_V, "type: %s\n", metadata->data.cue_sheet.tracks[i].type?"non-audio":"audio"); | |
334 mp_msg(MSGT_DECAUDIO, MSGL_V, "pre_emphasis: %s\n", metadata->data.cue_sheet.tracks[i].pre_emphasis?"true":"false"); | |
335 mp_msg(MSGT_DECAUDIO, MSGL_V, "num_indices: %hhu\n", metadata->data.cue_sheet.tracks[i].num_indices); | |
336 for (j = 0; j < metadata->data.cue_sheet.tracks[i].num_indices; j++) | |
337 { | |
338 mp_msg(MSGT_DECAUDIO, MSGL_V, "index[%d]:\n", j); | |
339 mp_msg(MSGT_DECAUDIO, MSGL_V, "offset:%llu\n", metadata->data.cue_sheet.tracks[i].indices[j].offset); | |
340 mp_msg(MSGT_DECAUDIO, MSGL_V, "number:%hhu\n", metadata->data.cue_sheet.tracks[i].indices[j].number); | |
341 } | |
342 } | |
343 break; | |
344 default: if (metadata->type >= FLAC__METADATA_TYPE_UNDEFINED) | |
345 mp_msg(MSGT_DECAUDIO, MSGL_V, "UNKNOWN block (%u bytes):\n", metadata->length); | |
346 else | |
347 mp_msg(MSGT_DECAUDIO, MSGL_V, "Strange block: UNKNOWN #%d < FLAC__METADATA_TYPE_UNDEFINED (%u bytes):\n", metadata->type, metadata->length); | |
348 for (i = 0; i < (metadata->length)/8; i++) | |
349 { | |
350 for(j = 0; j < 8; j++) | |
351 mp_msg(MSGT_DECAUDIO, MSGL_V, "%c", (unsigned char)metadata->data.unknown.data[i*8+j]<0x20?'.':metadata->data.unknown.data[i*8+j]); | |
352 mp_msg(MSGT_DECAUDIO, MSGL_V, " | "); | |
353 for(j = 0; j < 8; j++) | |
354 mp_msg(MSGT_DECAUDIO, MSGL_V, "%#02hhx ", metadata->data.unknown.data[i*8+j]); | |
355 mp_msg(MSGT_DECAUDIO, MSGL_V, "\n"); | |
356 } | |
357 if (metadata->length-i*8 != 0) | |
358 { | |
359 for(j = 0; j < metadata->length-i*8; j++) | |
360 mp_msg(MSGT_DECAUDIO, MSGL_V, "%c", (unsigned char)metadata->data.unknown.data[i*8+j]<0x20?'.':metadata->data.unknown.data[i*8+j]); | |
361 for(; j <8; j++) | |
362 mp_msg(MSGT_DECAUDIO, MSGL_V, " "); | |
363 mp_msg(MSGT_DECAUDIO, MSGL_V, " | "); | |
364 for(j = 0; j < metadata->length-i*8; j++) | |
365 mp_msg(MSGT_DECAUDIO, MSGL_V, "%#02hhx ", metadata->data.unknown.data[i*8+j]); | |
366 mp_msg(MSGT_DECAUDIO, MSGL_V, "\n"); | |
367 } | |
368 break; | |
369 } | |
370 } | |
371 | |
372 void flac_error_callback(const FLAC__StreamDecoder *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data) | |
373 { | |
374 if (status != FLAC__STREAM_DECODER_ERROR_STATUS_LOST_SYNC) | |
375 mp_msg(MSGT_DECAUDIO, MSGL_ERR, "\nError callback called (%s)!!!\n", FLAC__StreamDecoderErrorStatusString[status]); | |
376 } | |
377 | |
378 static int preinit(sh_audio_t *sh){ | |
379 // there are default values set for buffering, but you can override them: | |
380 | |
381 sh->audio_out_minsize=8*4*65535; // due to specs: we assume max 8 channels, | |
382 // 4 bytes/sample and 65535 samples/frame | |
383 // So allocating 2Mbytes buffer :) | |
384 | |
385 // minimum input buffer size (set only if you need input buffering) | |
386 // (should be the max compressed frame size) | |
387 sh->audio_in_minsize=2048; // Default: 0 (no input buffer) | |
388 | |
389 // if you set audio_in_minsize non-zero, the buffer will be allocated | |
390 // before the init() call by the core, and you can access it via | |
391 // pointer: sh->audio_in_buffer | |
392 // it will free'd after uninit(), so you don't have to use malloc/free here! | |
393 | |
394 return 1; // return values: 1=OK 0=ERROR | |
395 } | |
396 | |
397 static int init(sh_audio_t *sh_audio){ | |
398 flac_struct_t *context = (flac_struct_t*)calloc(sizeof(flac_struct_t), 1); | |
399 | |
400 sh_audio->context = context; | |
401 context->sh = sh_audio; | |
402 if (context == NULL) | |
403 { | |
404 mp_msg(MSGT_DECAUDIO, MSGL_FATAL, "flac_init: error allocating context.\n"); | |
405 return 0; | |
406 } | |
407 | |
408 context->flac_dec = FLAC__stream_decoder_new(); | |
409 if (context->flac_dec == NULL) | |
410 { | |
411 mp_msg(MSGT_DECAUDIO, MSGL_ERR, "flac_init: error allocaing FLAC decoder.\n"); | |
412 return 0; | |
413 } | |
414 | |
415 if (!FLAC__stream_decoder_set_client_data(context->flac_dec, context)) | |
416 { | |
417 mp_msg(MSGT_DECAUDIO, MSGL_ERR, "error setting private data for callbacks.\n"); | |
418 return 0; | |
419 } | |
420 | |
421 if (!FLAC__stream_decoder_set_read_callback(context->flac_dec, &flac_read_callback)) | |
422 { | |
423 mp_msg(MSGT_DECAUDIO, MSGL_ERR, "error setting read callback.\n"); | |
424 return 0; | |
425 } | |
426 | |
427 if (!FLAC__stream_decoder_set_write_callback(context->flac_dec, &flac_write_callback)) | |
428 { | |
429 mp_msg(MSGT_DECAUDIO, MSGL_ERR, "error setting write callback.\n"); | |
430 return 0; | |
431 } | |
432 | |
433 if (!FLAC__stream_decoder_set_metadata_callback(context->flac_dec, &flac_metadata_callback)) | |
434 { | |
435 mp_msg(MSGT_DECAUDIO, MSGL_ERR, "error setting metadata callback.\n"); | |
436 return 0; | |
437 } | |
438 | |
439 if (!FLAC__stream_decoder_set_error_callback(context->flac_dec, &flac_error_callback)) | |
440 { | |
441 mp_msg(MSGT_DECAUDIO, MSGL_ERR, "error setting error callback.\n"); | |
442 return 0; | |
443 } | |
444 | |
445 if (!FLAC__stream_decoder_set_metadata_respond_all(context->flac_dec)) | |
446 { | |
447 mp_msg(MSGT_DECAUDIO, MSGL_ERR, "error during setting metadata_respond_all.\n"); | |
448 return 0; | |
449 } | |
450 | |
451 if (FLAC__stream_decoder_init(context->flac_dec) != FLAC__STREAM_DECODER_SEARCH_FOR_METADATA) | |
452 { | |
453 mp_msg(MSGT_DECAUDIO, MSGL_ERR, "Error initializing decoder!\n"); | |
454 return 0; | |
455 } | |
456 | |
457 context->buf = NULL; | |
458 context->minlen = context->maxlen = 0; | |
459 context->replay_scale = 1.0; | |
460 | |
461 FLAC__stream_decoder_process_until_end_of_metadata(context->flac_dec); | |
462 | |
463 FLAC__plugin_common__init_dither_context(&(context->dither_context), sh_audio->samplesize * 8, noise_shaping); | |
464 | |
465 return 1; // return values: 1=OK 0=ERROR | |
466 } | |
467 | |
468 static void uninit(sh_audio_t *sh){ | |
469 // uninit the decoder etc... | |
470 FLAC__stream_decoder_finish(((flac_struct_t*)(sh->context))->flac_dec); | |
471 FLAC__stream_decoder_delete(((flac_struct_t*)(sh->context))->flac_dec); | |
472 // again: you don't have to free() a_in_buffer here! it's done by the core. | |
473 } | |
474 | |
475 static int decode_audio(sh_audio_t *sh_audio,unsigned char *buf,int minlen,int maxlen){ | |
476 FLAC__StreamDecoderState decstate; | |
477 FLAC__bool status; | |
478 | |
479 // audio decoding. the most important thing :) | |
480 // parameters you get: | |
481 // buf = pointer to the output buffer, you have to store uncompressed | |
482 // samples there | |
483 // minlen = requested minimum size (in bytes!) of output. it's just a | |
484 // _recommendation_, you can decode more or less, it just tell you that | |
485 // the caller process needs 'minlen' bytes. if it gets less, it will | |
486 // call decode_audio() again. | |
487 // maxlen = maximum size (bytes) of output. you MUST NOT write more to the | |
488 // buffer, it's the upper-most limit! | |
489 // note: maxlen will be always greater or equal to sh->audio_out_minsize | |
490 | |
491 // Store params in private context for callback: | |
492 ((flac_struct_t*)(sh_audio->context))->buf = buf; | |
493 ((flac_struct_t*)(sh_audio->context))->minlen = minlen; | |
494 ((flac_struct_t*)(sh_audio->context))->maxlen = maxlen; | |
495 ((flac_struct_t*)(sh_audio->context))->written = 0; | |
496 | |
497 status = FLAC__stream_decoder_process_single(((flac_struct_t*)(sh_audio->context))->flac_dec); | |
498 decstate = FLAC__stream_decoder_get_state(((flac_struct_t*)(sh_audio->context))->flac_dec); | |
499 if (!status || ( | |
500 decstate != FLAC__STREAM_DECODER_SEARCH_FOR_METADATA && | |
501 decstate != FLAC__STREAM_DECODER_READ_METADATA && | |
502 decstate != FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC && | |
503 decstate != FLAC__STREAM_DECODER_READ_FRAME | |
504 )) | |
505 { | |
506 if (decstate == FLAC__STREAM_DECODER_END_OF_STREAM) | |
507 { | |
508 /* return what we have decoded */ | |
509 if (((flac_struct_t*)(sh_audio->context))->written != 0) | |
510 return ((flac_struct_t*)(sh_audio->context))->written; | |
511 mp_msg(MSGT_DECAUDIO, MSGL_V, "End of stream.\n"); | |
512 return -1; | |
513 } | |
514 mp_msg(MSGT_DECAUDIO, MSGL_WARN, "process_single problem: returned %s, state is %s!\n", status?"true":"false", FLAC__StreamDecoderStateString[decstate]); | |
515 FLAC__stream_decoder_flush(((flac_struct_t*)(sh_audio->context))->flac_dec); | |
516 return -1; | |
517 } | |
518 | |
519 | |
520 return ((flac_struct_t*)(sh_audio->context))->written; // return value: number of _bytes_ written to output buffer, | |
521 // or -1 for EOF (or uncorrectable error) | |
522 } | |
523 | |
524 static int control(sh_audio_t *sh,int cmd,void* arg, ...){ | |
525 switch(cmd){ | |
526 case ADCTRL_RESYNC_STREAM: | |
527 // it is called once after seeking, to resync. | |
528 // Note: sh_audio->a_in_buffer_len=0; is done _before_ this call! | |
529 FLAC__stream_decoder_flush (((flac_struct_t*)(sh->context))->flac_dec); | |
530 return CONTROL_TRUE; | |
531 case ADCTRL_SKIP_FRAME: | |
532 // it is called to skip (jump over) small amount (1/10 sec or 1 frame) | |
533 // of audio data - used to sync audio to video after seeking | |
534 // if you don't return CONTROL_TRUE, it will defaults to: | |
535 // ds_fill_buffer(sh_audio->ds); // skip 1 demux packet | |
536 ((flac_struct_t*)(sh->context))->buf = NULL; | |
537 ((flac_struct_t*)(sh->context))->minlen = | |
538 ((flac_struct_t*)(sh->context))->maxlen = 0; | |
539 FLAC__stream_decoder_process_single(((flac_struct_t*)(sh->context))->flac_dec); | |
540 return CONTROL_TRUE; | |
541 } | |
542 return CONTROL_UNKNOWN; | |
543 } | |
544 #endif |