test.c 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322
  1. #include <stdio.h>
  2. #include <memory.h>
  3. #include <malloc.h>
  4. #include <time.h>
  5. #include "mp3.h"
  6. #include "mad_config.h"
  7. #include "mad_decoder.h"
  8. /*
  9. * This small program tests that my offset addition to libMAD actually works.
  10. * Erez Volk 2007-05-30
  11. */
  12. static void dump_file( const char *filename );
  13. static void test_file( const char *filename );
  14. static void test_mad( FILE *f );
  15. static void test_mp3f( FILE *f );
  16. static void get_offsets( FILE *f );
  17. static enum mad_flow cb_input( void *context, struct mad_stream *stream );
  18. static enum mad_flow cb_header( void *context, struct mad_header const *header );
  19. static enum mad_flow cb_accept_header( void *context, struct mad_header const *header );
  20. static enum mad_flow cb_dump( void *context, struct mad_header const *header, struct mad_pcm *pcm );
  21. static void cb_samples( const int *channels[MP3F_MAX_CHANNELS],
  22. unsigned num_samples,
  23. void *context );
  24. #define BUFFER_SIZE 2048
  25. static unsigned char the_buffer[BUFFER_SIZE];
  26. #define MAX_OFFSETS 4096
  27. static unsigned long offsets[MAX_OFFSETS];
  28. static unsigned num_offsets;
  29. int main( int argc, char *argv[] )
  30. {
  31. int i;
  32. if ( argc <= 1 )
  33. {
  34. printf( "Usage: %s MP3_FILE [MP3_FILE...]\n", argv[0] );
  35. return -1;
  36. }
  37. if ( argc > 2 && !strcmp( argv[1], "-dump" ) )
  38. dump_file( argv[2] );
  39. else for ( i = 1; i < argc; ++ i )
  40. test_file( argv[i] );
  41. return 0;
  42. }
  43. typedef struct {
  44. FILE *f;
  45. unsigned done;
  46. unsigned left;
  47. FILE *f2;
  48. } DUMP_CONTEXT;
  49. static void dump_file( const char *filename )
  50. {
  51. enum { MAX_FRAMES = 16 };
  52. FILE *f;
  53. unsigned i;
  54. printf( "Dumping file: \"%s\"...\n", filename );
  55. if ( (f = fopen( filename, "rb" )) == NULL ) {
  56. printf( " Cannot open file.\n" );
  57. return;
  58. }
  59. get_offsets( f );
  60. printf( " Header offsets: %lu, %lu, %lu, %lu, ... %lu\n",
  61. offsets[0], offsets[1], offsets[2], offsets[3],
  62. offsets[num_offsets - 1] );
  63. for ( i = 0; i < MAX_FRAMES; ++ i )
  64. {
  65. char dumpname[128];
  66. struct mad_decoder d;
  67. DUMP_CONTEXT c = { f, i, MAX_FRAMES - i };
  68. sprintf( dumpname, "%02u.dump", i );
  69. printf( " Creating %s...\n", dumpname );
  70. c.f2 = fopen( dumpname, "w" );
  71. fseek( f, offsets[i], SEEK_SET );
  72. mad_decoder_init( &d, &c, cb_input, cb_accept_header, NULL, cb_dump, NULL, NULL );
  73. mad_decoder_run( &d, MAD_DECODER_MODE_SYNC );
  74. mad_decoder_finish( &d );
  75. fclose( c.f2 );
  76. }
  77. fclose( f );
  78. }
  79. static void test_file( const char *filename )
  80. {
  81. FILE *f;
  82. printf( "Testing file: \"%s\"...\n", filename );
  83. if ( (f = fopen( filename, "rb" )) == NULL ) {
  84. printf( " Cannot open file.\n" );
  85. return;
  86. }
  87. test_mad( f );
  88. test_mp3f( f );
  89. fclose( f );
  90. }
  91. static void test_mad( FILE *f )
  92. {
  93. enum { MAX_BAD = 16 };
  94. unsigned i, bad;
  95. get_offsets( f );
  96. if ( num_offsets >= MAX_OFFSETS )
  97. printf( " Reached maximum number of headers (%u)\n", MAX_OFFSETS );
  98. else
  99. printf( " Number of headers found: %u\n", num_offsets );
  100. printf( " Header offsets: %lu, %lu, %lu, %lu, ... %lu\n",
  101. offsets[0], offsets[1], offsets[2], offsets[3],
  102. offsets[num_offsets - 1] );
  103. printf( " Checking header validity...\n" );
  104. for ( i = bad = 0; i < num_offsets && bad < MAX_BAD; ++ i )
  105. {
  106. unsigned char header[2] = { 0, 0 };
  107. if ( i > 0 && offsets[i] <= offsets[i - 1] )
  108. {
  109. printf( " Invalid offset table.\n" );
  110. return;
  111. }
  112. fseek( f, offsets[i], SEEK_SET );
  113. fread( header, 1, sizeof(header), f );
  114. if ( (header[0] != 0xFF) || ((header[1] & 0xE0) != 0xE0) )
  115. {
  116. ++ bad;
  117. printf( " ERROR: No header at file offset %lu\n", offsets[i] );
  118. }
  119. else if ( bad > 0 )
  120. printf( " Good header at file offset %lu\n", offsets[i] );
  121. }
  122. if ( bad == 0 )
  123. printf( " All offsets have valid MP3 headers\n" );
  124. }
  125. static void get_offsets( FILE *f )
  126. {
  127. struct mad_decoder d;
  128. /* Make sure there are no leftovers */
  129. memset( &d, time(NULL), sizeof(d) );
  130. num_offsets = 0;
  131. mad_decoder_init( &d, &f, cb_input, cb_header, NULL, NULL, NULL, NULL );
  132. if ( mad_decoder_run( &d, MAD_DECODER_MODE_SYNC ) != 0 )
  133. {
  134. printf( " Error scanning file.\n" );
  135. return;
  136. }
  137. mad_decoder_finish( &d );
  138. }
  139. static enum mad_flow cb_input( void *context, struct mad_stream *stream )
  140. {
  141. FILE *f = *(FILE **)context;
  142. unsigned char *data = NULL;
  143. unsigned nthrown = 0, ncopied = 0, size = 0;
  144. unsigned offset;
  145. size_t nread = 0;
  146. if (feof (f))
  147. return MAD_FLOW_STOP;
  148. if (stream -> next_frame) {
  149. nthrown = stream -> next_frame - the_buffer;
  150. ncopied = BUFFER_SIZE - nthrown;
  151. memmove (the_buffer, stream -> next_frame, ncopied);
  152. }
  153. data = the_buffer + ncopied;
  154. size = BUFFER_SIZE - ncopied;
  155. offset = ftell (f) - ncopied;
  156. if (size > 0)
  157. nread = fread (data, 1, size, f);
  158. mad_stream_buffer_offset (stream, the_buffer, nread + ncopied, offset);
  159. stream -> this_offset = offset;
  160. return MAD_FLOW_CONTINUE;
  161. }
  162. static enum mad_flow cb_header( void *context, struct mad_header const *header )
  163. {
  164. FILE *f = *(FILE **)context;
  165. unsigned long foff = ftell( f );
  166. if ( foff > header->offset + BUFFER_SIZE )
  167. printf( " ??? %lu <-> %lu\n", foff, header->offset );
  168. offsets[num_offsets] = header->offset;
  169. if ( ++ num_offsets >= MAX_OFFSETS )
  170. return MAD_FLOW_STOP;
  171. return MAD_FLOW_CONTINUE;
  172. }
  173. static enum mad_flow cb_accept_header( void *context, struct mad_header const *header )
  174. {
  175. (void)context;
  176. (void)header;
  177. return MAD_FLOW_CONTINUE;
  178. }
  179. static enum mad_flow cb_dump( void *context, struct mad_header const *header, struct mad_pcm *pcm )
  180. {
  181. DUMP_CONTEXT *c = (DUMP_CONTEXT *)context;
  182. FILE *f = c->f2;
  183. unsigned i, j, length = pcm->length;
  184. const mad_fixed_t *samples = pcm->samples[0];
  185. (void)header;
  186. fprintf( f, "FRAME %u, OFFSET %lu (expected %lu)\n",
  187. c->done, header->offset, offsets[c->done] );
  188. for ( i = 0; i < length; i += 8 ) {
  189. for ( j = i; i < length && j < i + 8; ++ j )
  190. fprintf( f, "%9i ", samples[j] );
  191. fprintf( f, "\n" );
  192. }
  193. fprintf( f, "\n" );
  194. ++ c->done;
  195. -- c->left;
  196. return c->left == 0 ? MAD_FLOW_STOP : MAD_FLOW_CONTINUE;
  197. }
  198. static void test_mp3f( FILE *f )
  199. {
  200. enum { FIRST = 15000, SECOND = 2000, TOTAL = FIRST + SECOND };
  201. enum { MID_OFFSET = 16000, MID_SIZE = 800 };
  202. static int x[TOTAL], y[TOTAL], z[MID_SIZE];
  203. int *p;
  204. MP3_FILE mp3f = mp3f_new();
  205. mp3f_set_file( mp3f, f );
  206. if ( mp3f_analyze( mp3f ) )
  207. {
  208. printf( " MP3F: Channels = %u\n", mp3f_channels( mp3f ) );
  209. printf( " MP3F: Frequency = %u\n", mp3f_frequency( mp3f ) );
  210. printf( " MP3F: Samples = %lu\n", (unsigned long)mp3f_samples( mp3f ) );
  211. printf( " MP3F: Time => %.2lfs\n",
  212. (double)mp3f_samples(mp3f) / (double)mp3f_frequency(mp3f) );
  213. }
  214. else
  215. printf( " MP3F: Cannot analyze\n" );
  216. memset( x, 0x22, sizeof(x) );
  217. memset( y, 0x22, sizeof(y) );
  218. memset( z, 0x22, sizeof(z) );
  219. mp3f_set_file( mp3f, f );
  220. p = x;
  221. mp3f_set_callback( mp3f, cb_samples, &p );
  222. mp3f_read( mp3f, TOTAL );
  223. mp3f_set_file( mp3f, f );
  224. p = y;
  225. mp3f_set_callback( mp3f, cb_samples, &p );
  226. mp3f_read( mp3f, FIRST );
  227. mp3f_read( mp3f, SECOND );
  228. mp3f_set_file( mp3f, f );
  229. p = z;
  230. mp3f_set_callback( mp3f, cb_samples, &p );
  231. if ( mp3f_seek( mp3f, MID_OFFSET ) )
  232. mp3f_read( mp3f, MID_SIZE );
  233. else
  234. printf( " MP3F: Seek failed\n" );
  235. if ( memcmp( x, y, FIRST * sizeof(int) ) != 0 )
  236. printf( " MP3F: Difference in first samples!\n" );
  237. else
  238. printf( " MP3F: First samples OK\n" );
  239. if ( memcmp( x + FIRST, y + FIRST, SECOND * sizeof(int) ) != 0 )
  240. printf( " MP3F: Difference in later samples!\n" );
  241. else
  242. printf( " MP3F: Later samples OK\n" );
  243. if ( memcmp( x + MID_OFFSET, z, MID_SIZE * sizeof(int) ) != 0 )
  244. printf( " MP3F: Seek doesn't work\n" );
  245. else
  246. printf( " MP3F: Seek works\n" );
  247. mp3f_delete( mp3f );
  248. }
  249. static void cb_samples( const int *channels[MP3F_MAX_CHANNELS],
  250. unsigned num_samples,
  251. void *context )
  252. {
  253. int **pp = (int **)context;
  254. int *p = *pp;
  255. unsigned i;
  256. for ( i = 0; i < num_samples; ++ i )
  257. p[i] = channels[0][i];
  258. *pp += num_samples;
  259. }
  260. /* Needed for libMP3 */
  261. void *Melder_malloc( unsigned size ) { return malloc( size ); }
  262. void _Melder_free( void **p ) { free( *p ); }