add verbose option to analysis mode to dump residuals
[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 <assert.h> /* for FILE */
26 #include <stdio.h> /* for FILE */
27 #include <string.h> /* for strcmp() */
28 #include "FLAC/all.h"
29 #include "decode.h"
30
31 typedef struct {
32         FILE *fout;
33         bool abort_flag;
34         bool analysis_mode;
35         bool analyze_residual;
36         bool test_only;
37         bool is_wave_out;
38         bool is_big_endian;
39         bool is_unsigned_samples;
40         uint64 total_samples;
41         unsigned bps;
42         unsigned channels;
43         unsigned sample_rate;
44         bool verbose;
45         uint64 skip;
46         uint64 samples_processed;
47         unsigned frame_counter;
48 } stream_info_struct;
49
50 static FLAC__FileDecoder *decoder;
51 static bool is_big_endian_host;
52
53 /* local routines */
54 static bool init(const char *infile, stream_info_struct *stream_info);
55 static bool write_little_endian_uint16(FILE *f, uint16 val);
56 static bool write_little_endian_uint32(FILE *f, uint32 val);
57 static FLAC__StreamDecoderWriteStatus write_callback(const FLAC__FileDecoder *decoder, const FLAC__Frame *frame, const int32 *buffer[], void *client_data);
58 static void metadata_callback(const FLAC__FileDecoder *decoder, const FLAC__StreamMetaData *metadata, void *client_data);
59 static void error_callback(const FLAC__FileDecoder *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data);
60 static void print_stats(const stream_info_struct *stream_info);
61
62 int decode_wav(const char *infile, const char *outfile, bool analysis_mode, bool analyze_residual, bool verbose, uint64 skip)
63 {
64         bool md5_failure = false;
65         stream_info_struct stream_info;
66
67         decoder = 0;
68         stream_info.abort_flag = false;
69         stream_info.analysis_mode = analysis_mode;
70         stream_info.analyze_residual = analyze_residual;
71         stream_info.test_only = (outfile == 0);
72         stream_info.is_wave_out = true;
73         stream_info.verbose = verbose;
74         stream_info.skip = skip;
75         stream_info.samples_processed = 0;
76         stream_info.frame_counter = 0;
77
78         assert(!(stream_info.test_only && stream_info.analysis_mode));
79
80         if(!stream_info.test_only) {
81                 if(0 == strcmp(outfile, "-")) {
82                         stream_info.fout = stdout;
83                 }
84                 else {
85                         if(0 == (stream_info.fout = fopen(outfile, "wb"))) {
86                                 fprintf(stderr, "ERROR: can't open output file %s\n", outfile);
87                                 return false;
88                         }
89                 }
90         }
91
92         if(!init(infile, &stream_info))
93                 goto wav_abort_;
94
95         if(skip > 0) {
96                 if(!FLAC__file_decoder_process_metadata(decoder)) {
97                         fprintf(stderr, "%s: ERROR during decoding\n", infile);
98                         goto wav_abort_;
99                 }
100                 if(!FLAC__file_decoder_seek_absolute(decoder, skip)) {
101                         fprintf(stderr, "%s: ERROR seeking while skipping bytes\n", infile);
102                         goto wav_abort_;
103                 }
104                 if(!FLAC__file_decoder_process_remaining_frames(decoder)) {
105                         if(verbose) { printf("\n"); fflush(stdout); }
106                         fprintf(stderr, "%s: ERROR during decoding\n", infile);
107                         goto wav_abort_;
108                 }
109                 if(decoder->state != FLAC__FILE_DECODER_OK && decoder->state != FLAC__FILE_DECODER_END_OF_FILE) {
110                         if(verbose) { printf("\n"); fflush(stdout); }
111                         fprintf(stderr, "%s: ERROR during decoding\n", infile);
112                         goto wav_abort_;
113                 }
114         }
115         else {
116                 if(!FLAC__file_decoder_process_whole_file(decoder)) {
117                         if(verbose) { printf("\n"); fflush(stdout); }
118                         fprintf(stderr, "%s: ERROR during decoding\n", infile);
119                         goto wav_abort_;
120                 }
121                 if(decoder->state != FLAC__FILE_DECODER_OK && decoder->state != FLAC__FILE_DECODER_END_OF_FILE) {
122                         if(verbose) { printf("\n"); fflush(stdout); }
123                         fprintf(stderr, "%s: ERROR during decoding, state=%d:%s\n", infile, decoder->state, FLAC__FileDecoderStateString[decoder->state]);
124                         goto wav_abort_;
125                 }
126         }
127
128         if(decoder) {
129                 if(decoder->state != FLAC__FILE_DECODER_UNINITIALIZED)
130                         md5_failure = !FLAC__file_decoder_finish(decoder);
131                 print_stats(&stream_info);
132                 FLAC__file_decoder_free_instance(decoder);
133         }
134         if(!stream_info.test_only)
135                 fclose(stream_info.fout);
136         if(verbose)
137                 printf("\n");
138         fflush(stdout);
139         if(md5_failure) {
140                 fprintf(stderr, "%s: WARNING, MD5 signature mismatch\n", infile);
141                 return 1;
142         }
143         else {
144                 if(stream_info.test_only)
145                         printf("%s: ok\n", infile);
146         }
147         return 0;
148 wav_abort_:
149         if(decoder) {
150                 if(decoder->state != FLAC__FILE_DECODER_UNINITIALIZED)
151                         FLAC__file_decoder_finish(decoder);
152                 FLAC__file_decoder_free_instance(decoder);
153         }
154         if(!stream_info.test_only) {
155                 fclose(stream_info.fout);
156                 unlink(outfile);
157         }
158         return 1;
159 }
160
161 int decode_raw(const char *infile, const char *outfile, bool analysis_mode, bool analyze_residual, bool verbose, uint64 skip, bool is_big_endian, bool is_unsigned_samples)
162 {
163         bool md5_failure = false;
164         stream_info_struct stream_info;
165
166         decoder = 0;
167         stream_info.abort_flag = false;
168         stream_info.analysis_mode = analysis_mode;
169         stream_info.analyze_residual = analyze_residual;
170         stream_info.test_only = (outfile == 0);
171         stream_info.is_wave_out = false;
172         stream_info.is_big_endian = is_big_endian;
173         stream_info.is_unsigned_samples = is_unsigned_samples;
174         stream_info.verbose = verbose;
175         stream_info.skip = skip;
176         stream_info.samples_processed = 0;
177         stream_info.frame_counter = 0;
178
179         assert(!(stream_info.test_only && stream_info.analysis_mode));
180
181         if(!stream_info.test_only) {
182                 if(0 == strcmp(outfile, "-")) {
183                         stream_info.fout = stdout;
184                 }
185                 else {
186                         if(0 == (stream_info.fout = fopen(outfile, "wb"))) {
187                                 fprintf(stderr, "ERROR: can't open output file %s\n", outfile);
188                                 return false;
189                         }
190                 }
191         }
192
193         if(!init(infile, &stream_info))
194                 goto raw_abort_;
195
196         if(skip > 0) {
197                 if(!FLAC__file_decoder_process_metadata(decoder)) {
198                         fprintf(stderr, "%s: ERROR during decoding\n", infile);
199                         goto raw_abort_;
200                 }
201                 if(!FLAC__file_decoder_seek_absolute(decoder, skip)) {
202                         fprintf(stderr, "%s: ERROR seeking while skipping bytes\n", infile);
203                         goto raw_abort_;
204                 }
205                 if(!FLAC__file_decoder_process_remaining_frames(decoder)) {
206                         if(verbose) { printf("\n"); fflush(stdout); }
207                         fprintf(stderr, "%s: ERROR during decoding\n", infile);
208                         goto raw_abort_;
209                 }
210                 if(decoder->state != FLAC__FILE_DECODER_OK && decoder->state != FLAC__FILE_DECODER_END_OF_FILE) {
211                         if(verbose) { printf("\n"); fflush(stdout); }
212                         fprintf(stderr, "%s: ERROR during decoding\n", infile);
213                         goto raw_abort_;
214                 }
215         }
216         else {
217                 if(!FLAC__file_decoder_process_whole_file(decoder)) {
218                         if(verbose) { printf("\n"); fflush(stdout); }
219                         fprintf(stderr, "%s: ERROR during decoding\n", infile);
220                         goto raw_abort_;
221                 }
222                 if(decoder->state != FLAC__FILE_DECODER_OK && decoder->state != FLAC__FILE_DECODER_END_OF_FILE) {
223                         if(verbose) { printf("\n"); fflush(stdout); }
224                         fprintf(stderr, "%s: ERROR during decoding\n", infile);
225                         goto raw_abort_;
226                 }
227         }
228
229         if(decoder) {
230                 if(decoder->state != FLAC__FILE_DECODER_UNINITIALIZED)
231                         md5_failure = !FLAC__file_decoder_finish(decoder);
232                 print_stats(&stream_info);
233                 FLAC__file_decoder_free_instance(decoder);
234         }
235         if(!stream_info.test_only)
236                 fclose(stream_info.fout);
237         if(verbose)
238                 printf("\n");
239         fflush(stdout);
240         if(md5_failure) {
241                 fprintf(stderr, "%s: WARNING, MD5 signature mismatch\n", infile);
242                 return 1;
243         }
244         else {
245                 if(stream_info.test_only)
246                         printf("%s: ok\n", infile);
247         }
248         return 0;
249 raw_abort_:
250         if(decoder) {
251                 if(decoder->state != FLAC__FILE_DECODER_UNINITIALIZED)
252                         FLAC__file_decoder_finish(decoder);
253                 FLAC__file_decoder_free_instance(decoder);
254         }
255         if(!stream_info.test_only) {
256                 fclose(stream_info.fout);
257                 unlink(outfile);
258         }
259         return 1;
260 }
261
262 bool init(const char *infile, stream_info_struct *stream_info)
263 {
264         uint32 test = 1;
265
266         is_big_endian_host = (*((byte*)(&test)))? false : true;
267
268         decoder = FLAC__file_decoder_get_new_instance();
269         if(0 == decoder) {
270                 fprintf(stderr, "ERROR creating the decoder instance\n");
271                 return false;
272         }
273         decoder->check_md5 = true;
274
275         if(FLAC__file_decoder_init(decoder, infile, write_callback, metadata_callback, error_callback, stream_info) != FLAC__FILE_DECODER_OK) {
276                 fprintf(stderr, "ERROR initializing decoder, state = %d\n", decoder->state);
277                 return false;
278         }
279
280         return true;
281 }
282
283 bool write_little_endian_uint16(FILE *f, uint16 val)
284 {
285         byte *b = (byte*)(&val);
286         if(is_big_endian_host) {
287                 byte tmp;
288                 tmp = b[1]; b[1] = b[0]; b[0] = tmp;
289         }
290         return fwrite(b, 1, 2, f) == 2;
291 }
292
293 bool write_little_endian_uint32(FILE *f, uint32 val)
294 {
295         byte *b = (byte*)(&val);
296         if(is_big_endian_host) {
297                 byte tmp;
298                 tmp = b[3]; b[3] = b[0]; b[0] = tmp;
299                 tmp = b[2]; b[2] = b[1]; b[1] = tmp;
300         }
301         return fwrite(b, 1, 4, f) == 4;
302 }
303
304 FLAC__StreamDecoderWriteStatus write_callback(const FLAC__FileDecoder *decoder, const FLAC__Frame *frame, const int32 *buffer[], void *client_data)
305 {
306         stream_info_struct *stream_info = (stream_info_struct *)client_data;
307         FILE *fout = stream_info->fout;
308         unsigned bps = stream_info->bps, channels = stream_info->channels;
309         bool is_big_endian = (stream_info->is_wave_out? false : stream_info->is_big_endian);
310         bool is_unsigned_samples = (stream_info->is_wave_out? bps<=8 : stream_info->is_unsigned_samples);
311         unsigned wide_samples = frame->header.blocksize, wide_sample, sample, channel, byte;
312         static int8 s8buffer[FLAC__MAX_BLOCK_SIZE * FLAC__MAX_CHANNELS * sizeof(int32)]; /* WATCHOUT: can be up to 2 megs */
313         /* WATCHOUT: we say 'sizeof(int32)' above instead of '(FLAC__MAX_BITS_PER_SAMPLE+7)/8' because we have to use an array int32 even for 24 bps */
314         uint8  *u8buffer  = (uint8  *)s8buffer;
315         int16  *s16buffer = (int16  *)s8buffer;
316         uint16 *u16buffer = (uint16 *)s8buffer;
317         int32  *s32buffer = (int32  *)s8buffer;
318         uint32 *u32buffer = (uint32 *)s8buffer;
319
320         (void)decoder;
321
322         if(stream_info->abort_flag)
323                 return FLAC__STREAM_DECODER_WRITE_ABORT;
324
325         stream_info->samples_processed += wide_samples;
326         stream_info->frame_counter++;
327
328         if(stream_info->verbose && !(stream_info->frame_counter & 0x1f))
329                 print_stats(stream_info);
330
331         if(stream_info->analysis_mode) {
332                 unsigned i;
333                 fprintf(fout, "frame=%u\tblocksize=%u\tsample_rate=%u\tchannels=%u\tchannel_assignment=%s\n", stream_info->frame_counter-1, frame->header.blocksize, frame->header.sample_rate, frame->header.channels, FLAC__ChannelAssignmentString[frame->header.channel_assignment]);
334                 for(channel = 0; channel < channels; channel++) {
335                         const FLAC__Subframe *subframe = frame->subframes+channel;
336                         fprintf(fout, "\tsubframe=%u\ttype=%s", channel, FLAC__SubframeTypeString[subframe->type]);
337                         switch(subframe->type) {
338                                 case FLAC__SUBFRAME_TYPE_CONSTANT:
339                                         fprintf(fout, "\tvalue=%d\n", subframe->data.constant.value);
340                                         break;
341                                 case FLAC__SUBFRAME_TYPE_FIXED:
342                                         fprintf(fout, "\torder=%u\tpartition_order=%u\n", subframe->data.fixed.order, subframe->data.fixed.entropy_coding_method.data.partitioned_rice.order); /*@@@ assumes method is partitioned-rice */
343                                         for(i = 0; i < subframe->data.fixed.order; i++)
344                                                 fprintf(fout, "\t\twarmup[%u]=%d\n", i, subframe->data.fixed.warmup[i]);
345                                         if(stream_info->analyze_residual) {
346                                                 for(i = 0; i < frame->header.blocksize-subframe->data.fixed.order; i++)
347                                                         fprintf(fout, "\t\tresidual[%u]=%d\n", i, subframe->data.fixed.residual[i]);
348                                         }
349                                         break;
350                                 case FLAC__SUBFRAME_TYPE_LPC:
351                                         fprintf(fout, "\torder=%u\tpartition_order=%u\tqlp_coeff_precision=%u\tquantization_level=%d\n", subframe->data.lpc.order, subframe->data.lpc.entropy_coding_method.data.partitioned_rice.order, subframe->data.lpc.qlp_coeff_precision, subframe->data.lpc.quantization_level); /*@@@ assumes method is partitioned-rice */
352                                         for(i = 0; i < subframe->data.lpc.order; i++)
353                                                 fprintf(fout, "\t\twarmup[%u]=%d\n", i, subframe->data.lpc.warmup[i]);
354                                         if(stream_info->analyze_residual) {
355                                                 for(i = 0; i < frame->header.blocksize-subframe->data.lpc.order; i++)
356                                                         fprintf(fout, "\t\tresidual[%u]=%d\n", i, subframe->data.lpc.residual[i]);
357                                         }
358                                         break;
359                                 case FLAC__SUBFRAME_TYPE_VERBATIM:
360                                         fprintf(fout, "\n");
361                                         break;
362                         }
363                 }
364         }
365         else if(!stream_info->test_only) {
366                 if(bps == 8) {
367                         if(is_unsigned_samples) {
368                                 for(sample = wide_sample = 0; wide_sample < wide_samples; wide_sample++)
369                                         for(channel = 0; channel < channels; channel++, sample++)
370                                                 u8buffer[sample] = buffer[channel][wide_sample] + 0x80;
371                         }
372                         else {
373                                 for(sample = wide_sample = 0; wide_sample < wide_samples; wide_sample++)
374                                         for(channel = 0; channel < channels; channel++, sample++)
375                                                 s8buffer[sample] = buffer[channel][wide_sample];
376                         }
377                         if(fwrite(u8buffer, 1, sample, fout) != sample)
378                                 return FLAC__STREAM_DECODER_WRITE_ABORT;
379                 }
380                 else if(bps == 16) {
381                         if(is_unsigned_samples) {
382                                 for(sample = wide_sample = 0; wide_sample < wide_samples; wide_sample++)
383                                         for(channel = 0; channel < channels; channel++, sample++)
384                                                 u16buffer[sample] = buffer[channel][wide_sample] + 0x8000;
385                         }
386                         else {
387                                 for(sample = wide_sample = 0; wide_sample < wide_samples; wide_sample++)
388                                         for(channel = 0; channel < channels; channel++, sample++)
389                                                 s16buffer[sample] = buffer[channel][wide_sample];
390                         }
391                         if(is_big_endian != is_big_endian_host) {
392                                 unsigned char tmp;
393                                 const unsigned bytes = sample * 2;
394                                 for(byte = 0; byte < bytes; byte += 2) {
395                                         tmp = u8buffer[byte];
396                                         u8buffer[byte] = u8buffer[byte+1];
397                                         u8buffer[byte+1] = tmp;
398                                 }
399                         }
400                         if(fwrite(u16buffer, 2, sample, fout) != sample)
401                                 return FLAC__STREAM_DECODER_WRITE_ABORT;
402                 }
403                 else if(bps == 24) {
404                         if(is_unsigned_samples) {
405                                 for(sample = wide_sample = 0; wide_sample < wide_samples; wide_sample++)
406                                         for(channel = 0; channel < channels; channel++, sample++)
407                                                 u32buffer[sample] = buffer[channel][wide_sample] + 0x800000;
408                         }
409                         else {
410                                 for(sample = wide_sample = 0; wide_sample < wide_samples; wide_sample++)
411                                         for(channel = 0; channel < channels; channel++, sample++)
412                                                 s32buffer[sample] = buffer[channel][wide_sample];
413                         }
414                         if(is_big_endian != is_big_endian_host) {
415                                 unsigned char tmp;
416                                 const unsigned bytes = sample * 4;
417                                 for(byte = 0; byte < bytes; byte += 4) {
418                                         tmp = u8buffer[byte];
419                                         u8buffer[byte] = u8buffer[byte+3];
420                                         u8buffer[byte+3] = tmp;
421                                         tmp = u8buffer[byte+1];
422                                         u8buffer[byte+1] = u8buffer[byte+2];
423                                         u8buffer[byte+2] = tmp;
424                                 }
425                         }
426                         if(is_big_endian) {
427                                 unsigned lbyte;
428                                 const unsigned bytes = sample * 4;
429                                 for(lbyte = byte = 0; byte < bytes; ) {
430                                         byte++;
431                                         u8buffer[lbyte++] = u8buffer[byte++];
432                                         u8buffer[lbyte++] = u8buffer[byte++];
433                                         u8buffer[lbyte++] = u8buffer[byte++];
434                                 }
435                         }
436                         else {
437                                 unsigned lbyte;
438                                 const unsigned bytes = sample * 4;
439                                 for(lbyte = byte = 0; byte < bytes; ) {
440                                         u8buffer[lbyte++] = u8buffer[byte++];
441                                         u8buffer[lbyte++] = u8buffer[byte++];
442                                         u8buffer[lbyte++] = u8buffer[byte++];
443                                         byte++;
444                                 }
445                         }
446                         if(fwrite(u8buffer, 3, sample, fout) != sample)
447                                 return FLAC__STREAM_DECODER_WRITE_ABORT;
448                 }
449                 else {
450                         assert(0);
451                 }
452         }
453         return FLAC__STREAM_DECODER_WRITE_CONTINUE;
454 }
455
456 void metadata_callback(const FLAC__FileDecoder *decoder, const FLAC__StreamMetaData *metadata, void *client_data)
457 {
458         stream_info_struct *stream_info = (stream_info_struct *)client_data;
459         (void)decoder;
460         if(metadata->type == FLAC__METADATA_TYPE_STREAMINFO) {
461                 stream_info->total_samples = metadata->data.stream_info.total_samples - stream_info->skip;
462                 stream_info->bps = metadata->data.stream_info.bits_per_sample;
463                 stream_info->channels = metadata->data.stream_info.channels;
464                 stream_info->sample_rate = metadata->data.stream_info.sample_rate;
465
466                 if(stream_info->bps != 8 && stream_info->bps != 16 && stream_info->bps != 24) {
467                         fprintf(stderr, "ERROR: bits per sample is not 8/16/24\n");
468                         stream_info->abort_flag = true;
469                         return;
470                 }
471
472                 /* write the WAVE headers if necessary */
473                 if(!stream_info->analysis_mode && !stream_info->test_only && stream_info->is_wave_out) {
474                         uint64 data_size = stream_info->total_samples * stream_info->channels * ((stream_info->bps+7)/8);
475                         if(data_size >= 0xFFFFFFDC) {
476                                 fprintf(stderr, "ERROR: stream is too big for a wave file\n");
477                                 stream_info->abort_flag = true;
478                                 return;
479                         }
480                         if(fwrite("RIFF", 1, 4, stream_info->fout) != 4) stream_info->abort_flag = true;
481                         if(!write_little_endian_uint32(stream_info->fout, (uint32)(data_size+36))) stream_info->abort_flag = true; /* filesize-8 */
482                         if(fwrite("WAVEfmt ", 1, 8, stream_info->fout) != 8) stream_info->abort_flag = true;
483                         if(fwrite("\020\000\000\000", 1, 4, stream_info->fout) != 4) stream_info->abort_flag = true; /* chunk size = 16 */
484                         if(fwrite("\001\000", 1, 2, stream_info->fout) != 2) stream_info->abort_flag = true; /* compression code == 1 */
485                         if(!write_little_endian_uint16(stream_info->fout, (uint16)(stream_info->channels))) stream_info->abort_flag = true;
486                         if(!write_little_endian_uint32(stream_info->fout, stream_info->sample_rate)) stream_info->abort_flag = true;
487                         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 ??? */
488                         if(!write_little_endian_uint16(stream_info->fout, (uint16)(stream_info->channels * ((stream_info->bps+7) / 8)))) stream_info->abort_flag = true; /* block align */
489                         if(!write_little_endian_uint16(stream_info->fout, (uint16)(stream_info->bps))) stream_info->abort_flag = true; /* bits per sample */
490                         if(fwrite("data", 1, 4, stream_info->fout) != 4) stream_info->abort_flag = true;
491                         if(!write_little_endian_uint32(stream_info->fout, (uint32)data_size)) stream_info->abort_flag = true; /* data size */
492                 }
493         }
494 }
495
496 void error_callback(const FLAC__FileDecoder *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data)
497 {
498         stream_info_struct *stream_info = (stream_info_struct *)client_data;
499         (void)decoder;
500         fprintf(stderr, "*** Got error code %d\n", status);
501         stream_info->abort_flag = true;
502 }
503
504 void print_stats(const stream_info_struct *stream_info)
505 {
506         if(stream_info->verbose) {
507                 printf("\r%s %u of %u samples, %6.2f%% complete",
508                         stream_info->test_only? "tested" : stream_info->analysis_mode? "analyzed" : "wrote",
509                         (unsigned)stream_info->samples_processed,
510                         (unsigned)stream_info->total_samples,
511 #ifdef _MSC_VER
512                         /* with VC++ you have to spoon feed it the casting */
513                         (double)(int64)stream_info->samples_processed / (double)(int64)stream_info->total_samples * 100.0
514 #else
515                         (double)stream_info->samples_processed / (double)stream_info->total_samples * 100.0
516 #endif
517                 );
518                 fflush(stdout);
519         }
520 }