update copyright for 2001
[platform/upstream/flac.git] / src / flac / decode.c
1 /* flac - Command-line FLAC encoder/decoder
2  * Copyright (C) 2000,2001  Josh Coalson
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
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  02111-1307, USA.
17  */
18
19 #if defined _WIN32 && !defined __CYGWIN__
20 /* where MSVC puts unlink() */
21 # include <io.h>
22 #else
23 # include <unistd.h>
24 #endif
25 #include <stdio.h> /* for FILE */
26 #include <string.h> /* for strcmp() */
27 #include "FLAC/all.h"
28 #include "decode.h"
29
30 typedef struct {
31         FILE *fout;
32         bool abort_flag;
33         bool test_only;
34         bool is_wave_out;
35         bool is_big_endian;
36         bool is_unsigned_samples;
37         uint64 total_samples;
38         unsigned bps;
39         unsigned channels;
40         unsigned sample_rate;
41         bool verbose;
42         uint64 skip;
43         uint64 samples_processed;
44         unsigned frame_counter;
45 } stream_info_struct;
46
47 static FLAC__FileDecoder *decoder;
48 static bool is_big_endian_host;
49
50 /* local routines */
51 static bool init(const char *infile, stream_info_struct *stream_info);
52 static bool write_little_endian_uint16(FILE *f, uint16 val);
53 static bool write_little_endian_uint32(FILE *f, uint32 val);
54 static FLAC__StreamDecoderWriteStatus write_callback(const FLAC__FileDecoder *decoder, const FLAC__FrameHeader *header, const int32 *buffer[], void *client_data);
55 static void metadata_callback(const FLAC__FileDecoder *decoder, const FLAC__StreamMetaData *metadata, void *client_data);
56 static void error_callback(const FLAC__FileDecoder *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data);
57 static void print_stats(const stream_info_struct *stream_info);
58
59 int decode_wav(const char *infile, const char *outfile, bool verbose, uint64 skip)
60 {
61         bool md5_failure = false;
62         stream_info_struct stream_info;
63
64         decoder = 0;
65         stream_info.abort_flag = false;
66         stream_info.test_only = (outfile == 0);
67         stream_info.is_wave_out = true;
68         stream_info.verbose = verbose;
69         stream_info.skip = skip;
70         stream_info.samples_processed = 0;
71         stream_info.frame_counter = 0;
72
73         if(!stream_info.test_only) {
74                 if(0 == strcmp(outfile, "-")) {
75                         stream_info.fout = stdout;
76                 }
77                 else {
78                         if(0 == (stream_info.fout = fopen(outfile, "wb"))) {
79                                 fprintf(stderr, "ERROR: can't open output file %s\n", outfile);
80                                 return false;
81                         }
82                 }
83         }
84
85         if(!init(infile, &stream_info))
86                 goto wav_abort_;
87
88         if(skip > 0) {
89                 if(!FLAC__file_decoder_process_metadata(decoder)) {
90                         fprintf(stderr, "%s: ERROR during decoding\n", infile);
91                         goto wav_abort_;
92                 }
93                 if(!FLAC__file_decoder_seek_absolute(decoder, skip)) {
94                         fprintf(stderr, "%s: ERROR seeking while skipping bytes\n", infile);
95                         goto wav_abort_;
96                 }
97                 if(!FLAC__file_decoder_process_remaining_frames(decoder)) {
98                         if(verbose) { printf("\n"); fflush(stdout); }
99                         fprintf(stderr, "%s: ERROR during decoding\n", infile);
100                         goto wav_abort_;
101                 }
102                 if(decoder->state != FLAC__FILE_DECODER_OK && decoder->state != FLAC__FILE_DECODER_END_OF_FILE) {
103                         if(verbose) { printf("\n"); fflush(stdout); }
104                         fprintf(stderr, "%s: ERROR during decoding\n", infile);
105                         goto wav_abort_;
106                 }
107         }
108         else {
109                 if(!FLAC__file_decoder_process_whole_file(decoder)) {
110                         if(verbose) { printf("\n"); fflush(stdout); }
111                         fprintf(stderr, "%s: ERROR during decoding\n", infile);
112                         goto wav_abort_;
113                 }
114                 if(decoder->state != FLAC__FILE_DECODER_OK && decoder->state != FLAC__FILE_DECODER_END_OF_FILE) {
115                         if(verbose) { printf("\n"); fflush(stdout); }
116                         fprintf(stderr, "%s: ERROR during decoding, state=%d:%s\n", infile, decoder->state, FLAC__FileDecoderStateString[decoder->state]);
117                         goto wav_abort_;
118                 }
119         }
120
121         if(decoder) {
122                 if(decoder->state != FLAC__FILE_DECODER_UNINITIALIZED)
123                         md5_failure = !FLAC__file_decoder_finish(decoder);
124                 print_stats(&stream_info);
125                 FLAC__file_decoder_free_instance(decoder);
126         }
127         if(!stream_info.test_only)
128                 fclose(stream_info.fout);
129         if(verbose)
130                 printf("\n");
131         fflush(stdout);
132         if(md5_failure) {
133                 fprintf(stderr, "%s: WARNING, MD5 signature mismatch\n", infile);
134                 return 1;
135         }
136         else {
137                 if(stream_info.test_only)
138                         printf("%s: ok\n", infile);
139         }
140         return 0;
141 wav_abort_:
142         if(decoder) {
143                 if(decoder->state != FLAC__FILE_DECODER_UNINITIALIZED)
144                         FLAC__file_decoder_finish(decoder);
145                 FLAC__file_decoder_free_instance(decoder);
146         }
147         if(!stream_info.test_only) {
148                 fclose(stream_info.fout);
149                 unlink(outfile);
150         }
151         return 1;
152 }
153
154 int decode_raw(const char *infile, const char *outfile, bool verbose, uint64 skip, bool is_big_endian, bool is_unsigned_samples)
155 {
156         bool md5_failure = false;
157         stream_info_struct stream_info;
158
159         decoder = 0;
160         stream_info.abort_flag = false;
161         stream_info.test_only = (outfile == 0);
162         stream_info.is_wave_out = false;
163         stream_info.is_big_endian = is_big_endian;
164         stream_info.is_unsigned_samples = is_unsigned_samples;
165         stream_info.verbose = verbose;
166         stream_info.skip = skip;
167         stream_info.samples_processed = 0;
168         stream_info.frame_counter = 0;
169
170         if(!stream_info.test_only) {
171                 if(0 == strcmp(outfile, "-")) {
172                         stream_info.fout = stdout;
173                 }
174                 else {
175                         if(0 == (stream_info.fout = fopen(outfile, "wb"))) {
176                                 fprintf(stderr, "ERROR: can't open output file %s\n", outfile);
177                                 return false;
178                         }
179                 }
180         }
181
182         if(!init(infile, &stream_info))
183                 goto raw_abort_;
184
185         if(skip > 0) {
186                 if(!FLAC__file_decoder_process_metadata(decoder)) {
187                         fprintf(stderr, "%s: ERROR during decoding\n", infile);
188                         goto raw_abort_;
189                 }
190                 if(!FLAC__file_decoder_seek_absolute(decoder, skip)) {
191                         fprintf(stderr, "%s: ERROR seeking while skipping bytes\n", infile);
192                         goto raw_abort_;
193                 }
194                 if(!FLAC__file_decoder_process_remaining_frames(decoder)) {
195                         if(verbose) { printf("\n"); fflush(stdout); }
196                         fprintf(stderr, "%s: ERROR during decoding\n", infile);
197                         goto raw_abort_;
198                 }
199                 if(decoder->state != FLAC__FILE_DECODER_OK && decoder->state != FLAC__FILE_DECODER_END_OF_FILE) {
200                         if(verbose) { printf("\n"); fflush(stdout); }
201                         fprintf(stderr, "%s: ERROR during decoding\n", infile);
202                         goto raw_abort_;
203                 }
204         }
205         else {
206                 if(!FLAC__file_decoder_process_whole_file(decoder)) {
207                         if(verbose) { printf("\n"); fflush(stdout); }
208                         fprintf(stderr, "%s: ERROR during decoding\n", infile);
209                         goto raw_abort_;
210                 }
211                 if(decoder->state != FLAC__FILE_DECODER_OK && decoder->state != FLAC__FILE_DECODER_END_OF_FILE) {
212                         if(verbose) { printf("\n"); fflush(stdout); }
213                         fprintf(stderr, "%s: ERROR during decoding\n", infile);
214                         goto raw_abort_;
215                 }
216         }
217
218         if(decoder) {
219                 if(decoder->state != FLAC__FILE_DECODER_UNINITIALIZED)
220                         md5_failure = !FLAC__file_decoder_finish(decoder);
221                 print_stats(&stream_info);
222                 FLAC__file_decoder_free_instance(decoder);
223         }
224         if(!stream_info.test_only)
225                 fclose(stream_info.fout);
226         if(verbose)
227                 printf("\n");
228         fflush(stdout);
229         if(md5_failure) {
230                 fprintf(stderr, "%s: WARNING, MD5 signature mismatch\n", infile);
231                 return 1;
232         }
233         else {
234                 if(stream_info.test_only)
235                         printf("%s: ok\n", infile);
236         }
237         return 0;
238 raw_abort_:
239         if(decoder) {
240                 if(decoder->state != FLAC__FILE_DECODER_UNINITIALIZED)
241                         FLAC__file_decoder_finish(decoder);
242                 FLAC__file_decoder_free_instance(decoder);
243         }
244         if(!stream_info.test_only) {
245                 fclose(stream_info.fout);
246                 unlink(outfile);
247         }
248         return 1;
249 }
250
251 bool init(const char *infile, stream_info_struct *stream_info)
252 {
253         uint32 test = 1;
254
255         is_big_endian_host = (*((byte*)(&test)))? false : true;
256
257         decoder = FLAC__file_decoder_get_new_instance();
258         if(0 == decoder) {
259                 fprintf(stderr, "ERROR creating the decoder instance\n");
260                 return false;
261         }
262         decoder->check_md5 = true;
263
264         if(FLAC__file_decoder_init(decoder, infile, write_callback, metadata_callback, error_callback, stream_info) != FLAC__FILE_DECODER_OK) {
265                 fprintf(stderr, "ERROR initializing decoder, state = %d\n", decoder->state);
266                 return false;
267         }
268
269         return true;
270 }
271
272 bool write_little_endian_uint16(FILE *f, uint16 val)
273 {
274         byte *b = (byte*)(&val);
275         if(is_big_endian_host) {
276                 byte tmp;
277                 tmp = b[1]; b[1] = b[0]; b[0] = tmp;
278         }
279         return fwrite(b, 1, 2, f) == 2;
280 }
281
282 bool write_little_endian_uint32(FILE *f, uint32 val)
283 {
284         byte *b = (byte*)(&val);
285         if(is_big_endian_host) {
286                 byte tmp;
287                 tmp = b[3]; b[3] = b[0]; b[0] = tmp;
288                 tmp = b[2]; b[2] = b[1]; b[1] = tmp;
289         }
290         return fwrite(b, 1, 4, f) == 4;
291 }
292
293 FLAC__StreamDecoderWriteStatus write_callback(const FLAC__FileDecoder *decoder, const FLAC__FrameHeader *header, const int32 *buffer[], void *client_data)
294 {
295         stream_info_struct *stream_info = (stream_info_struct *)client_data;
296         FILE *fout = stream_info->fout;
297         unsigned bps = stream_info->bps, channels = stream_info->channels;
298         bool is_big_endian = (stream_info->is_wave_out? false : stream_info->is_big_endian);
299         bool is_unsigned_samples = (stream_info->is_wave_out? bps==8 : stream_info->is_unsigned_samples);
300         unsigned wide_samples = header->blocksize, wide_sample, sample, channel, byte;
301         static signed char scbuffer[FLAC__MAX_BLOCK_SIZE * FLAC__MAX_CHANNELS * ((FLAC__MAX_BITS_PER_SAMPLE+7)>>3)]; /* WATCHOUT: can be up to 2 megs */
302         unsigned char *ucbuffer = (unsigned char *)scbuffer;
303         signed short *ssbuffer = (signed short *)scbuffer;
304         unsigned short *usbuffer = (unsigned short *)scbuffer;
305
306         (void)decoder;
307
308         if(stream_info->abort_flag)
309                 return FLAC__STREAM_DECODER_WRITE_ABORT;
310
311         stream_info->samples_processed += wide_samples;
312         stream_info->frame_counter++;
313
314         if(stream_info->verbose && !(stream_info->frame_counter & 0x1f))
315                 print_stats(stream_info);
316
317         if(!stream_info->test_only) {
318                 if(bps == 8) {
319                         if(is_unsigned_samples) {
320                                 for(sample = wide_sample = 0; wide_sample < wide_samples; wide_sample++)
321                                         for(channel = 0; channel < channels; channel++, sample++)
322                                                 ucbuffer[sample] = buffer[channel][wide_sample] + 128;
323                         }
324                         else {
325                                 for(sample = wide_sample = 0; wide_sample < wide_samples; wide_sample++)
326                                         for(channel = 0; channel < channels; channel++, sample++)
327                                                 scbuffer[sample] = buffer[channel][wide_sample];
328                         }
329                         if(fwrite(ucbuffer, 1, sample, fout) != sample)
330                                 return FLAC__STREAM_DECODER_WRITE_ABORT;
331                 }
332                 else { /* bps == 16 */
333                         if(is_unsigned_samples) {
334                                 for(sample = wide_sample = 0; wide_sample < wide_samples; wide_sample++)
335                                         for(channel = 0; channel < channels; channel++, sample++)
336                                                 usbuffer[sample] = buffer[channel][wide_sample] + 32768;
337                         }
338                         else {
339                                 for(sample = wide_sample = 0; wide_sample < wide_samples; wide_sample++)
340                                         for(channel = 0; channel < channels; channel++, sample++)
341                                                 ssbuffer[sample] = buffer[channel][wide_sample];
342                         }
343                         if(is_big_endian != is_big_endian_host) {
344                                 unsigned char tmp;
345                                 for(byte = 0; byte < sample<<1; byte += 2) {
346                                         tmp = ucbuffer[byte];
347                                         ucbuffer[byte] = ucbuffer[byte+1];
348                                         ucbuffer[byte+1] = tmp;
349                                 }
350                         }
351                         if(fwrite(usbuffer, 2, sample, fout) != sample)
352                                 return FLAC__STREAM_DECODER_WRITE_ABORT;
353                 }
354         }
355         return FLAC__STREAM_DECODER_WRITE_CONTINUE;
356 }
357
358 void metadata_callback(const FLAC__FileDecoder *decoder, const FLAC__StreamMetaData *metadata, void *client_data)
359 {
360         stream_info_struct *stream_info = (stream_info_struct *)client_data;
361         (void)decoder;
362         if(metadata->type == FLAC__METADATA_TYPE_ENCODING) {
363                 stream_info->total_samples = metadata->data.encoding.total_samples - stream_info->skip;
364                 stream_info->bps = metadata->data.encoding.bits_per_sample;
365                 stream_info->channels = metadata->data.encoding.channels;
366                 stream_info->sample_rate = metadata->data.encoding.sample_rate;
367
368                 if(stream_info->bps != 8 && stream_info->bps != 16) {
369                         fprintf(stderr, "ERROR: bits per sample is not 8 or 16\n");
370                         stream_info->abort_flag = true;
371                         return;
372                 }
373
374                 /* write the WAVE headers if necessary */
375                 if(!stream_info->test_only && stream_info->is_wave_out) {
376                         uint64 data_size = stream_info->total_samples * stream_info->channels * ((stream_info->bps+7)/8);
377                         if(data_size >= 0xFFFFFFDC) {
378                                 fprintf(stderr, "ERROR: stream is too big for a wave file\n");
379                                 stream_info->abort_flag = true;
380                                 return;
381                         }
382                         if(fwrite("RIFF", 1, 4, stream_info->fout) != 4) stream_info->abort_flag = true;
383                         if(!write_little_endian_uint32(stream_info->fout, (uint32)(data_size+36))) stream_info->abort_flag = true; /* filesize-8 */
384                         if(fwrite("WAVEfmt ", 1, 8, stream_info->fout) != 8) stream_info->abort_flag = true;
385                         if(fwrite("\020\000\000\000", 1, 4, stream_info->fout) != 4) stream_info->abort_flag = true; /* chunk size = 16 */
386                         if(fwrite("\001\000", 1, 2, stream_info->fout) != 2) stream_info->abort_flag = true; /* compression code == 1 */
387                         if(!write_little_endian_uint16(stream_info->fout, (uint16)(stream_info->channels))) stream_info->abort_flag = true;
388                         if(!write_little_endian_uint32(stream_info->fout, stream_info->sample_rate)) stream_info->abort_flag = true;
389                         if(!write_little_endian_uint32(stream_info->fout, stream_info->sample_rate * stream_info->channels * ((stream_info->bps+7) / 8))) stream_info->abort_flag = true; /* @@@ or is it (sample_rate*channels*bps) / 8 ??? */
390                         if(!write_little_endian_uint16(stream_info->fout, (uint16)(stream_info->channels * ((stream_info->bps+7) / 8)))) stream_info->abort_flag = true; /* block align */
391                         if(!write_little_endian_uint16(stream_info->fout, (uint16)(stream_info->bps))) stream_info->abort_flag = true; /* bits per sample */
392                         if(fwrite("data", 1, 4, stream_info->fout) != 4) stream_info->abort_flag = true;
393                         if(!write_little_endian_uint32(stream_info->fout, (uint32)data_size)) stream_info->abort_flag = true; /* data size */
394                 }
395         }
396 }
397
398 void error_callback(const FLAC__FileDecoder *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data)
399 {
400         stream_info_struct *stream_info = (stream_info_struct *)client_data;
401         (void)decoder;
402         fprintf(stderr, "*** Got error code %d\n", status);
403         stream_info->abort_flag = true;
404 }
405
406 void print_stats(const stream_info_struct *stream_info)
407 {
408         if(stream_info->verbose) {
409                 printf("\r%s %u of %u samples, %6.2f%% complete",
410                         stream_info->test_only? "tested" : "wrote",
411                         (unsigned)stream_info->samples_processed,
412                         (unsigned)stream_info->total_samples,
413 #ifdef _MSC_VER
414                         /* with VC++ you have to spoon feed it the casting */
415                         (double)(int64)stream_info->samples_processed / (double)(int64)stream_info->total_samples * 100.0
416 #else
417                         (double)stream_info->samples_processed / (double)stream_info->total_samples * 100.0
418 #endif
419                 );
420                 fflush(stdout);
421         }
422 }