Rename _flac_stat to flac_stat_s.
[platform/upstream/flac.git] / src / test_seeking / main.c
index f31c4b3..3dd707e 100644 (file)
@@ -1,5 +1,5 @@
 /* test_seeking - Seeking tester for libFLAC
- * Copyright (C) 2004,2005,2006  Josh Coalson
+ * Copyright (C) 2004,2005,2006,2007,2008,2009  Josh Coalson
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
@@ -11,9 +11,9 @@
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  * GNU General Public License for more details.
  *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  */
 
 #if HAVE_CONFIG_H
 #endif
 #include <sys/stat.h> /* for stat() */
 #include "FLAC/assert.h"
+#include "FLAC/metadata.h"
 #include "FLAC/stream_decoder.h"
+#include "share/compat.h"
 
 typedef struct {
+       FLAC__int32 **pcm;
        FLAC__bool got_data;
        FLAC__uint64 total_samples;
        unsigned channels;
@@ -73,16 +76,115 @@ static FLAC__bool die_s_(const char *msg, const FLAC__StreamDecoder *decoder)
        return false;
 }
 
-static off_t get_filesize_(const char *srcpath)
+static unsigned local_rand_(void)
 {
-       struct stat srcstat;
+#if !defined _MSC_VER && !defined __MINGW32__
+#define RNDFUNC random
+#else
+#define RNDFUNC rand
+#endif
+       /* every RAND_MAX I've ever seen is 2^15-1 or 2^31-1, so a little hackery here: */
+       if (RAND_MAX > 32767)
+               return RNDFUNC();
+       else /* usually MSVC, some solaris */
+               return (RNDFUNC()<<15) | RNDFUNC();
+#undef RNDFUNC
+}
 
-       if(0 == stat(srcpath, &srcstat))
+static FLAC__off_t get_filesize_(const char *srcpath)
+{
+       struct flac_stat_s srcstat;
+
+       if(0 == flac_stat(srcpath, &srcstat))
                return srcstat.st_size;
        else
                return -1;
 }
 
+static FLAC__bool read_pcm_(FLAC__int32 *pcm[], const char *rawfilename, const char *flacfilename)
+{
+       FILE *f;
+       unsigned channels = 0, bps = 0, samples, i, j;
+
+       FLAC__off_t rawfilesize = get_filesize_(rawfilename);
+       if (rawfilesize < 0) {
+               fprintf(stderr, "ERROR: can't determine filesize for %s\n", rawfilename);
+               return false;
+       }
+       /* get sample format from flac file; would just use FLAC__metadata_get_streaminfo() except it doesn't work for Ogg FLAC yet */
+       {
+#if 0
+               FLAC__StreamMetadata streaminfo;
+               if(!FLAC__metadata_get_streaminfo(flacfilename, &streaminfo)) {
+                       printf("ERROR: getting STREAMINFO from %s\n", flacfilename);
+                       return false;
+               }
+               channels = streaminfo.data.stream_info.channels;
+               bps = streaminfo.data.stream_info.bits_per_sample;
+#else
+               FLAC__bool ok = true;
+               FLAC__Metadata_Chain *chain = FLAC__metadata_chain_new();
+               FLAC__Metadata_Iterator *it = 0;
+               ok = ok && chain && (FLAC__metadata_chain_read(chain, flacfilename) || FLAC__metadata_chain_read_ogg(chain, flacfilename));
+               ok = ok && (it = FLAC__metadata_iterator_new());
+               if(ok) FLAC__metadata_iterator_init(it, chain);
+               ok = ok && (FLAC__metadata_iterator_get_block(it)->type == FLAC__METADATA_TYPE_STREAMINFO);
+               ok = ok && (channels = FLAC__metadata_iterator_get_block(it)->data.stream_info.channels);
+               ok = ok && (bps = FLAC__metadata_iterator_get_block(it)->data.stream_info.bits_per_sample);
+               if(it) FLAC__metadata_iterator_delete(it);
+               if(chain) FLAC__metadata_chain_delete(chain);
+               if(!ok) {
+                       printf("ERROR: getting STREAMINFO from %s\n", flacfilename);
+                       return false;
+               }
+#endif
+       }
+       if(channels > 2) {
+               printf("ERROR: PCM verification requires 1 or 2 channels, got %u\n", channels);
+               return false;
+       }
+       if(bps != 8 && bps != 16) {
+               printf("ERROR: PCM verification requires 8 or 16 bps, got %u\n", bps);
+               return false;
+       }
+       samples = rawfilesize / channels / (bps>>3);
+       if (samples > 10000000) {
+               fprintf(stderr, "ERROR: %s is too big\n", rawfilename);
+               return false;
+       }
+       for(i = 0; i < channels; i++) {
+               if(0 == (pcm[i] = malloc(sizeof(FLAC__int32)*samples))) {
+                       printf("ERROR: allocating space for PCM samples\n");
+                       return false;
+               }
+       }
+       if(0 == (f = flac_fopen(rawfilename, "rb"))) {
+               printf("ERROR: opening %s for reading\n", rawfilename);
+               return false;
+       }
+       /* assumes signed big-endian data */
+       if(bps == 8) {
+               signed char c;
+               for(i = 0; i < samples; i++) {
+                       for(j = 0; j < channels; j++) {
+                               if (fread(&c, 1, 1, f) == 1)
+                                       pcm[j][i] = c;
+                       }
+               }
+       }
+       else { /* bps == 16 */
+               unsigned char c[2];
+               for(i = 0; i < samples; i++) {
+                       for(j = 0; j < channels; j++) {
+                               if (fread(&c, 1, 2, f) == 2)
+                                       pcm[j][i] = ((int)((signed char)c[0])) << 8 | (int)c[1];
+                       }
+               }
+       }
+       fclose(f);
+       return true;
+}
+
 static FLAC__StreamDecoderWriteStatus write_callback_(const FLAC__StreamDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 * const buffer[], void *client_data)
 {
        DecoderClientData *dcd = (DecoderClientData*)client_data;
@@ -97,25 +199,22 @@ static FLAC__StreamDecoderWriteStatus write_callback_(const FLAC__StreamDecoder
        if(dcd->error_occurred)
                return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT;
 
-       if (frame->header.number_type == FLAC__FRAME_NUMBER_TYPE_FRAME_NUMBER) {
-               if (!dcd->quiet)
-                       printf("frame@%uf(%u)... ", frame->header.number.frame_number, frame->header.blocksize);
-       }
-       else if (frame->header.number_type == FLAC__FRAME_NUMBER_TYPE_SAMPLE_NUMBER) {
-               if (!dcd->quiet)
-#ifdef _MSC_VER
-                       printf("frame@%I64u(%u)... ", frame->header.number.sample_number, frame->header.blocksize);
-#else
-                       printf("frame@%llu(%u)... ", (unsigned long long)frame->header.number.sample_number, frame->header.blocksize);
-#endif
-       }
-       else {
-               FLAC__ASSERT(0);
-               dcd->error_occurred = true;
-               return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT;
-       }
+       FLAC__ASSERT(frame->header.number_type == FLAC__FRAME_NUMBER_TYPE_SAMPLE_NUMBER); /* decoder guarantees this */
+       if (!dcd->quiet)
+               printf("frame@%" PRIu64 "(%u)... ", frame->header.number.sample_number, frame->header.blocksize);
        fflush(stdout);
 
+       /* check against PCM data if we have it */
+       if (dcd->pcm) {
+               unsigned c, i, j;
+               for (c = 0; c < frame->header.channels; c++)
+                       for (i = (unsigned)frame->header.number.sample_number, j = 0; j < frame->header.blocksize; i++, j++)
+                               if (buffer[c][j] != dcd->pcm[c][i]) {
+                                       printf("ERROR: sample mismatch at sample#%u(%u), channel=%u, expected %d, got %d\n", i, j, c, buffer[c][j], dcd->pcm[c][i]);
+                                       return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT;
+                               }
+       }
+
        return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE;
 }
 
@@ -163,13 +262,14 @@ static void error_callback_(const FLAC__StreamDecoder *decoder, FLAC__StreamDeco
  * 1 - read 2 frames
  * 2 - read until end
  */
-static FLAC__bool seek_barrage(FLAC__bool is_ogg, const char *filename, off_t filesize, unsigned count, FLAC__int64 total_samples, unsigned read_mode)
+static FLAC__bool seek_barrage(FLAC__bool is_ogg, const char *filename, FLAC__off_t filesize, unsigned count, FLAC__int64 total_samples, unsigned read_mode, FLAC__int32 **pcm)
 {
        FLAC__StreamDecoder *decoder;
        DecoderClientData decoder_client_data;
        unsigned i;
        long int n;
 
+       decoder_client_data.pcm = pcm;
        decoder_client_data.got_data = false;
        decoder_client_data.total_samples = 0;
        decoder_client_data.quiet = false;
@@ -206,17 +306,7 @@ static FLAC__bool seek_barrage(FLAC__bool is_ogg, const char *filename, off_t fi
                        return die_s_("expected FLAC__STREAM_DECODER_END_OF_STREAM", decoder);
        }
 
-#ifdef _MSC_VER
-       printf("file's total_samples is %I64u\n", decoder_client_data.total_samples);
-#else
-       printf("file's total_samples is %llu\n", (unsigned long long)decoder_client_data.total_samples);
-#endif
-#if !defined _MSC_VER && !defined __MINGW32__ && !defined __EMX__
-       if (decoder_client_data.total_samples > (FLAC__uint64)RAND_MAX) {
-               printf("ERROR: must be total_samples < %u\n", (unsigned)RAND_MAX);
-               return false;
-       }
-#endif
+       printf("file's total_samples is %" PRIu64 "\n", decoder_client_data.total_samples);
        n = (long int)decoder_client_data.total_samples;
 
        if(n == 0 && total_samples >= 0)
@@ -227,10 +317,6 @@ static FLAC__bool seek_barrage(FLAC__bool is_ogg, const char *filename, off_t fi
        if(n == 0) {
                /* 8 would imply no compression, 9 guarantees that we will get some samples off the end of the stream to test that case */
                n = 9 * filesize / (decoder_client_data.channels * decoder_client_data.bits_per_sample);
-#if !defined _MSC_VER && !defined __MINGW32__
-               if(n > RAND_MAX)
-                       n = RAND_MAX;
-#endif
        }
 
        printf("Begin seek barrage, count=%u\n", count);
@@ -251,19 +337,10 @@ static FLAC__bool seek_barrage(FLAC__bool is_ogg, const char *filename, off_t fi
                        pos = n + (i-20);
                }
                else {
-#if !defined _MSC_VER && !defined __MINGW32__
-                       pos = (FLAC__uint64)(random() % n);
-#else
-                       /* RAND_MAX is only 32767 in my MSVC */
-                       pos = (FLAC__uint64)((rand()<<15|rand()) % n);
-#endif
+                       pos = (FLAC__uint64)(local_rand_() % n);
                }
 
-#ifdef _MSC_VER
-               printf("seek(%I64u)... ", pos);
-#else
-               printf("seek(%llu)... ", (unsigned long long)pos);
-#endif
+               printf("#%u:seek(%" PRIu64 ")... ", i, pos);
                fflush(stdout);
                if(!FLAC__stream_decoder_seek_absolute(decoder, pos)) {
                        if(pos >= (FLAC__uint64)n)
@@ -298,12 +375,14 @@ static FLAC__bool seek_barrage(FLAC__bool is_ogg, const char *filename, off_t fi
                printf("OK\n");
                fflush(stdout);
        }
+       stop_signal_ = false;
 
        if(FLAC__stream_decoder_get_state(decoder) != FLAC__STREAM_DECODER_UNINITIALIZED) {
                if(!FLAC__stream_decoder_finish(decoder))
                        return die_s_("FLAC__stream_decoder_finish() FAILED", decoder);
        }
 
+       FLAC__stream_decoder_delete(decoder);
        printf("\nPASSED!\n");
 
        return true;
@@ -329,19 +408,21 @@ static FLAC__uint64 local__strtoull(const char *src)
 
 int main(int argc, char *argv[])
 {
-       const char *filename;
+       const char *flacfilename, *rawfilename = 0;
        unsigned count = 0, read_mode;
        FLAC__int64 samples = -1;
-       off_t filesize;
+       FLAC__off_t flacfilesize;
+       FLAC__int32 *pcm[2] = { 0, 0 };
+       FLAC__bool ok = true;
 
-       static const char * const usage = "usage: test_seeking file.flac [#seeks] [#samples-in-file.flac]\n";
+       static const char * const usage = "usage: test_seeking file.flac [#seeks] [#samples-in-file.flac] [file.raw]\n";
 
-       if (argc < 2 || argc > 4) {
-               fprintf(stderr, usage);
+       if (argc < 2 || argc > 5) {
+               fputs(usage, stderr);
                return 1;
        }
 
-       filename = argv[1];
+       flacfilename = argv[1];
 
        if (argc > 2)
                count = strtoul(argv[2], 0, 10);
@@ -351,6 +432,8 @@ int main(int argc, char *argv[])
 #else
                samples = strtoull(argv[3], 0, 10);
 #endif
+       if (argc > 4)
+               rawfilename = argv[4];
 
        if (count < 30)
                fprintf(stderr, "WARNING: random seeks don't kick in until after 30 preprogrammed ones\n");
@@ -366,33 +449,42 @@ int main(int argc, char *argv[])
                srandom(tv.tv_usec);
        }
 #else
-       srand(time(0));
+       srand((unsigned)time(0));
 #endif
 
-       filesize = get_filesize_(filename);
-       if (filesize < 0) {
-               fprintf(stderr, "ERROR: can't determine filesize for %s\n", filename);
+       flacfilesize = get_filesize_(flacfilename);
+       if (flacfilesize < 0) {
+               fprintf(stderr, "ERROR: can't determine filesize for %s\n", flacfilename);
+               return 1;
+       }
+
+       if (rawfilename && !read_pcm_(pcm, rawfilename, flacfilename)) {
+               free(pcm[0]);
+               free(pcm[1]);
                return 1;
        }
 
        (void) signal(SIGINT, our_sigint_handler_);
 
-       for (read_mode = 0; read_mode <= 2; read_mode++) {
-               FLAC__bool ok;
-               if (strlen(filename) > 4 && 0 == strcmp(filename+strlen(filename)-4, ".ogg")) {
+       for (read_mode = 0; ok && read_mode <= 2; read_mode++) {
+               /* no need to do "decode all" read_mode if PCM checking is available */
+               if (rawfilename && read_mode > 1)
+                       continue;
+               if (strlen(flacfilename) > 4 && (0 == strcmp(flacfilename+strlen(flacfilename)-4, ".oga") || 0 == strcmp(flacfilename+strlen(flacfilename)-4, ".ogg"))) {
 #if FLAC__HAS_OGG
-                       ok = seek_barrage(/*is_ogg=*/true, filename, filesize, count, samples, read_mode);
+                       ok = seek_barrage(/*is_ogg=*/true, flacfilename, flacfilesize, count, samples, read_mode, rawfilename? pcm : 0);
 #else
                        fprintf(stderr, "ERROR: Ogg FLAC not supported\n");
                        ok = false;
 #endif
                }
                else {
-                       ok = seek_barrage(/*is_ogg=*/false, filename, filesize, count, samples, read_mode);
+                       ok = seek_barrage(/*is_ogg=*/false, flacfilename, flacfilesize, count, samples, read_mode, rawfilename? pcm : 0);
                }
-               if (!ok)
-                       return 2;
        }
 
-       return 0;
+       free(pcm[0]);
+       free(pcm[1]);
+
+       return ok? 0 : 2;
 }