Mercurial > audlegacy-plugins
comparison src/madplug/decoder.c @ 611:3f7a52adfe0e trunk
[svn] merge recent changes from yaz's branch.
- stable shoutcast playback.
- tag handling improvement.
- view track detail on streaming won't crash. (disabled.)
- filepopup for streaming is partially supported. filepopup displays track name and stream name, but not updated automatically.
| author | yaz |
|---|---|
| date | Tue, 06 Feb 2007 12:11:42 -0800 |
| parents | 862190d39e00 |
| children | ca4cd00ca0c8 |
comparison
equal
deleted
inserted
replaced
| 610:862190d39e00 | 611:3f7a52adfe0e |
|---|---|
| 25 #include <signal.h> | 25 #include <signal.h> |
| 26 | 26 |
| 27 #include <audacious/plugin.h> | 27 #include <audacious/plugin.h> |
| 28 #include <audacious/output.h> | 28 #include <audacious/output.h> |
| 29 #include <audacious/util.h> | 29 #include <audacious/util.h> |
| 30 #include <sys/time.h> | |
| 30 #include "plugin.h" | 31 #include "plugin.h" |
| 31 #include "input.h" | 32 #include "input.h" |
| 32 | 33 |
| 33 #define BUFFER_SIZE 16*1024 | 34 #define BUFFER_SIZE 16*1024 |
| 34 #define N_AVERAGE_FRAMES 10 | 35 #define N_AVERAGE_FRAMES 10 |
| 150 output[pos++] = (sample >> 0) & 0xff; | 151 output[pos++] = (sample >> 0) & 0xff; |
| 151 output[pos++] = (sample >> 8) & 0xff; | 152 output[pos++] = (sample >> 8) & 0xff; |
| 152 } | 153 } |
| 153 } | 154 } |
| 154 assert(pos == olen); | 155 assert(pos == olen); |
| 155 if (info->playback->playing == 0) | 156 if (!info->playback->playing) |
| 156 return; | 157 return; |
| 157 produce_audio(mad_plugin->output->written_time(), | 158 produce_audio(info->playback->output->written_time(), |
| 158 FMT_S16_LE, MAD_NCHANNELS(header), olen, output, NULL); | 159 FMT_S16_LE, MAD_NCHANNELS(header), olen, output, &(info->playback->playing)); |
| 159 if (info->playback->playing == 0) | 160 if (!info->playback->playing) |
| 160 return; | 161 return; |
| 161 g_free(output); | 162 g_free(output); |
| 162 } | 163 } |
| 163 | 164 |
| 164 /** | 165 /** |
| 243 #endif /* DEBUG */ | 244 #endif /* DEBUG */ |
| 244 continue; | 245 continue; |
| 245 } | 246 } |
| 246 info->frames++; | 247 info->frames++; |
| 247 #ifdef DEBUG | 248 #ifdef DEBUG |
| 249 #ifdef DEBUG_INTENSIVELY | |
| 248 g_message("duration = %lu", | 250 g_message("duration = %lu", |
| 249 mad_timer_count(header.duration, | 251 mad_timer_count(header.duration, |
| 250 MAD_UNITS_MILLISECONDS)); | 252 MAD_UNITS_MILLISECONDS)); |
| 251 g_message("size = %d", stream.next_frame - stream.this_frame); | 253 g_message("size = %d", stream.next_frame - stream.this_frame); |
| 254 #endif | |
| 252 #endif | 255 #endif |
| 253 mad_timer_add(&info->duration, header.duration); | 256 mad_timer_add(&info->duration, header.duration); |
| 254 data_used += stream.next_frame - stream.this_frame; | 257 data_used += stream.next_frame - stream.this_frame; |
| 255 if (info->frames == 1) { | 258 if (info->frames == 1) { |
| 256 /* most of these *should* remain constant */ | 259 /* most of these *should* remain constant */ |
| 299 } | 302 } |
| 300 | 303 |
| 301 if (fast && info->frames >= N_AVERAGE_FRAMES) { | 304 if (fast && info->frames >= N_AVERAGE_FRAMES) { |
| 302 float frame_size = ((double) data_used) / N_AVERAGE_FRAMES; | 305 float frame_size = ((double) data_used) / N_AVERAGE_FRAMES; |
| 303 info->frames = (info->size - tagsize) / frame_size; | 306 info->frames = (info->size - tagsize) / frame_size; |
| 304 //int frame_frac = (info->size - tagsize) % frame_size; | |
| 305 info->duration.seconds /= N_AVERAGE_FRAMES; | 307 info->duration.seconds /= N_AVERAGE_FRAMES; |
| 306 info->duration.fraction /= N_AVERAGE_FRAMES; | 308 info->duration.fraction /= N_AVERAGE_FRAMES; |
| 307 mad_timer_multiply(&info->duration, info->frames); | 309 mad_timer_multiply(&info->duration, info->frames); |
| 308 #ifdef DEBUG | 310 #ifdef DEBUG |
| 309 g_message("using fast playtime calculation"); | 311 g_message("using fast playtime calculation"); |
| 310 g_message("data used = %d [tagsize=%d framesize=%f]", | 312 g_message("data used = %d [tagsize=%d framesize=%f]", |
| 311 data_used, tagsize, frame_size); | 313 data_used, tagsize, frame_size); |
| 312 //g_message ("frame_size = %f [frac=%d]", frame_size, frame_frac); | |
| 313 g_message("frames = %d, frequecy = %d, channels = %d", | 314 g_message("frames = %d, frequecy = %d, channels = %d", |
| 314 info->frames, info->freq, info->channels); | 315 info->frames, info->freq, info->channels); |
| 315 long millis = mad_timer_count(info->duration, | 316 long millis = mad_timer_count(info->duration, |
| 316 MAD_UNITS_MILLISECONDS); | 317 MAD_UNITS_MILLISECONDS); |
| 317 g_message("duration = %lu:%lu", millis / 1000 / 60, | 318 g_message("duration = %lu:%lu", millis / 1000 / 60, |
| 333 xing_finish(&info->xing); | 334 xing_finish(&info->xing); |
| 334 | 335 |
| 335 #ifdef DEBUG | 336 #ifdef DEBUG |
| 336 g_message("e: scan_file"); | 337 g_message("e: scan_file"); |
| 337 #endif /* DEBUG */ | 338 #endif /* DEBUG */ |
| 338 return (info->frames != 0 || info->remote == TRUE); | 339 // return info->frames != 0; |
| 340 return (info->frames != 0 || info->remote == TRUE); // suspicious | |
| 339 } | 341 } |
| 340 | 342 |
| 341 gpointer decode_loop(gpointer arg) | 343 gpointer decode_loop(gpointer arg) |
| 342 { | 344 { |
| 343 unsigned char buffer[BUFFER_SIZE]; | 345 unsigned char buffer[BUFFER_SIZE]; |
| 344 int len; | 346 int len; |
| 345 int seek_skip = 0; | 347 gboolean seek_skip = FALSE; |
| 346 int remainder = 0; | 348 int remainder = 0; |
| 347 gint tlen; | 349 gint tlen; |
| 348 | 350 |
| 349 /* mad structs */ | 351 /* mad structs */ |
| 350 struct mad_stream stream; | 352 struct mad_stream stream; |
| 361 /* init mad stuff */ | 363 /* init mad stuff */ |
| 362 mad_frame_init(&frame); | 364 mad_frame_init(&frame); |
| 363 mad_stream_init(&stream); | 365 mad_stream_init(&stream); |
| 364 mad_synth_init(&synth); | 366 mad_synth_init(&synth); |
| 365 | 367 |
| 366 if (!mad_plugin->output-> | 368 if(!info->playback){ |
| 367 open_audio(info->fmt, info->freq, info->channels)) { | 369 g_print("decode: playback == NULL\n"); |
| 370 return NULL; | |
| 371 } | |
| 372 | |
| 373 if (!info->playback->output->open_audio(info->fmt, info->freq, info->channels)) { | |
| 374 g_mutex_lock(pb_mutex); | |
| 375 info->playback->error = TRUE; | |
| 376 info->playback->eof = 1; | |
| 377 g_mutex_unlock(pb_mutex); | |
| 368 audmad_error("failed to open audio output: %s", | 378 audmad_error("failed to open audio output: %s", |
| 369 mad_plugin->output->description); | 379 info->playback->output->description); |
| 370 g_message("failed to open audio output: %s", | 380 g_message("failed to open audio output: %s", |
| 371 mad_plugin->output->description); | 381 info->playback->output->description); |
| 372 return NULL; | 382 return NULL; |
| 373 } | 383 } |
| 374 | 384 |
| 375 /* set mainwin title */ | 385 /* set mainwin title */ |
| 376 if (info->title) | 386 if (info->title) |
| 377 g_free(info->title); | 387 g_free(info->title); |
| 378 info->title = | 388 info->title = |
| 379 xmms_get_titlestring(xmms_get_gentitle_format(), info->tuple); | 389 xmms_get_titlestring(xmms_get_gentitle_format(), info->tuple); |
| 380 | 390 |
| 391 | |
| 381 tlen = (gint) mad_timer_count(info->duration, MAD_UNITS_MILLISECONDS), | 392 tlen = (gint) mad_timer_count(info->duration, MAD_UNITS_MILLISECONDS), |
| 382 | 393 |
| 383 mad_plugin->set_info(info->title, | 394 mad_plugin->set_info(info->title, |
| 384 tlen == 0 ? -1 : tlen, | 395 tlen == 0 ? -1 : tlen, |
| 385 info->bitrate, info->freq, info->channels); | 396 info->bitrate, info->freq, info->channels); |
| 386 | 397 |
| 387 /* main loop */ | 398 /* main loop */ |
| 388 do { | 399 do { |
| 389 if (info->playback->playing == 0) { | 400 if (!info->playback->playing) { |
| 390 #ifdef DEBUG | 401 #ifdef DEBUG |
| 391 g_message("decode: stop signaled"); | 402 g_message("decode: stop signaled"); |
| 392 #endif /* DEBUG */ | 403 #endif /* DEBUG */ |
| 393 break; | 404 break; |
| 394 } | 405 } |
| 425 if (mad_frame_decode(&frame, &stream) == 0) { | 436 if (mad_frame_decode(&frame, &stream) == 0) { |
| 426 mad_timer_add(&info->pos, frame.header.duration); | 437 mad_timer_add(&info->pos, frame.header.duration); |
| 427 if (--skip == 0) | 438 if (--skip == 0) |
| 428 mad_synth_frame(&synth, &frame); | 439 mad_synth_frame(&synth, &frame); |
| 429 } | 440 } |
| 430 else if (!MAD_RECOVERABLE(stream.error)) | 441 else if (!MAD_RECOVERABLE(stream.error)) { |
| 442 g_mutex_lock(pb_mutex); | |
| 443 info->playback->error = TRUE; | |
| 444 info->playback->eof = 1; | |
| 445 g_mutex_unlock(pb_mutex); | |
| 431 break; | 446 break; |
| 447 } | |
| 432 } | 448 } |
| 433 while (skip); | 449 while (skip); |
| 434 seek_skip = 0; | 450 seek_skip = FALSE; |
| 435 } | 451 } |
| 436 | 452 |
| 437 while (!info->playback->playing == 0) { | 453 while (info->playback->playing) { |
| 438 if (info->seek != -1 && !info->remote) { | 454 if (info->seek != -1 && !info->remote) { |
| 439 #ifdef DEBUG | 455 #ifdef DEBUG |
| 440 g_message("seeking: %d", info->seek); | 456 g_message("seeking: %d", info->seek); |
| 441 #endif | 457 #endif |
| 442 int new_position; | 458 int new_position; |
| 446 info->seek = seconds; | 462 info->seek = seconds; |
| 447 | 463 |
| 448 mad_timer_set(&info->pos, info->seek, 0, 0); | 464 mad_timer_set(&info->pos, info->seek, 0, 0); |
| 449 new_position = | 465 new_position = |
| 450 ((double) info->seek / (double) seconds) * info->size; | 466 ((double) info->seek / (double) seconds) * info->size; |
| 467 | |
| 468 if(new_position < 0) | |
| 469 new_position = 0; | |
| 451 #ifdef DEBUG | 470 #ifdef DEBUG |
| 452 g_message("seeking to: %d bytes", new_position); | 471 g_message("seeking to: %d bytes", new_position); |
| 453 #endif | 472 #endif |
| 454 if (vfs_fseek(info->infile, new_position, SEEK_SET) == -1) | 473 if (vfs_fseek(info->infile, new_position, SEEK_SET) == -1) |
| 455 audmad_error("failed to seek to: %d", new_position); | 474 audmad_error("failed to seek to: %d", new_position); |
| 456 mad_frame_mute(&frame); | 475 mad_frame_mute(&frame); |
| 457 mad_synth_mute(&synth); | 476 mad_synth_mute(&synth); |
| 458 stream.error = MAD_ERROR_BUFLEN; | 477 stream.error = MAD_ERROR_BUFLEN; |
| 459 mad_plugin->output->flush(mad_timer_count | 478 info->playback->output->flush(mad_timer_count(info->pos, MAD_UNITS_MILLISECONDS)); |
| 460 (info->pos, | |
| 461 MAD_UNITS_MILLISECONDS)); | |
| 462 stream.sync = 0; | 479 stream.sync = 0; |
| 463 info->seek = -1; | 480 info->seek = -1; |
| 464 seek_skip = 1; | 481 seek_skip = TRUE; |
| 465 break; | 482 break; |
| 466 } | 483 } |
| 467 | 484 |
| 468 if (mad_header_decode(&frame.header, &stream) == -1) { | 485 if (mad_header_decode(&frame.header, &stream) == -1) { |
| 469 if (!MAD_RECOVERABLE(stream.error)) | 486 if (!MAD_RECOVERABLE(stream.error)) { |
| 470 break; | 487 break; |
| 488 } | |
| 471 if (stream.error == MAD_ERROR_LOSTSYNC) { | 489 if (stream.error == MAD_ERROR_LOSTSYNC) { |
| 472 /* ignore LOSTSYNC due to ID3 tags */ | 490 /* ignore LOSTSYNC due to ID3 tags */ |
| 473 int tagsize = id3_tag_query(stream.this_frame, | 491 int tagsize = id3_tag_query(stream.this_frame, |
| 474 stream.bufend - | 492 stream.bufend - |
| 475 stream.this_frame); | 493 stream.this_frame); |
| 498 | 516 |
| 499 info->current_frame++; | 517 info->current_frame++; |
| 500 | 518 |
| 501 if (info->freq != frame.header.samplerate | 519 if (info->freq != frame.header.samplerate |
| 502 || info->channels != | 520 || info->channels != |
| 503 (guint) MAD_NCHANNELS(&frame.header)) | 521 (guint) MAD_NCHANNELS(&frame.header)) { |
| 504 { | |
| 505 tlen = mad_timer_count(info->duration, MAD_UNITS_MILLISECONDS); | |
| 506 #ifdef DEBUG | 522 #ifdef DEBUG |
| 507 g_message("re-opening audio due to change in audio type"); | 523 g_message("re-opening audio due to change in audio type"); |
| 508 g_message("old: frequency = %d, channels = %d", info->freq, | 524 g_message("old: frequency = %d, channels = %d", info->freq, |
| 509 info->channels); | 525 info->channels); |
| 510 g_message("new: frequency = %d, channels = %d", | 526 g_message("new: frequency = %d, channels = %d", |
| 511 frame.header.samplerate, | 527 frame.header.samplerate, |
| 512 (guint) MAD_NCHANNELS(&frame.header)); | 528 (guint) MAD_NCHANNELS(&frame.header)); |
| 513 #endif /* DEBUG */ | 529 #endif /* DEBUG */ |
| 514 | |
| 515 info->freq = frame.header.samplerate; | 530 info->freq = frame.header.samplerate; |
| 516 info->channels = MAD_NCHANNELS(&frame.header); | 531 info->channels = MAD_NCHANNELS(&frame.header); |
| 517 mad_plugin->output->close_audio(); | 532 info->playback->output->close_audio(); |
| 518 if (!mad_plugin->output->open_audio(info->fmt, info->freq, | 533 if (!info->playback->output->open_audio(info->fmt, info->freq, |
| 519 info->channels)) { | 534 info->channels)) { |
| 535 g_mutex_lock(pb_mutex); | |
| 536 info->playback->error = TRUE; | |
| 537 info->playback->eof = 1; | |
| 538 g_mutex_unlock(pb_mutex); | |
| 520 audmad_error("failed to re-open audio output: %s", | 539 audmad_error("failed to re-open audio output: %s", |
| 521 mad_plugin->output->description); | 540 info->playback->output->description); |
| 522 } | 541 } |
| 523 | 542 } |
| 524 mad_plugin->set_info(info->title, | 543 if (!info->playback->playing) |
| 525 tlen != 0 ? tlen : -1, | |
| 526 info->bitrate, info->freq, info->channels); | |
| 527 } | |
| 528 if (info->playback->playing == 0) | |
| 529 break; | 544 break; |
| 530 mad_synth_frame(&synth, &frame); | 545 mad_synth_frame(&synth, &frame); |
| 531 mad_stream_sync(&stream); | 546 mad_stream_sync(&stream); |
| 547 | |
| 532 write_output(info, &synth.pcm, &frame.header); | 548 write_output(info, &synth.pcm, &frame.header); |
| 533 mad_timer_add(&info->pos, frame.header.duration); | 549 mad_timer_add(&info->pos, frame.header.duration); |
| 534 } | 550 } |
| 535 } | 551 } |
| 536 while (stream.error == MAD_ERROR_BUFLEN); | 552 while (stream.error == MAD_ERROR_BUFLEN); |
| 538 /* free mad stuff */ | 554 /* free mad stuff */ |
| 539 mad_frame_finish(&frame); | 555 mad_frame_finish(&frame); |
| 540 mad_stream_finish(&stream); | 556 mad_stream_finish(&stream); |
| 541 mad_synth_finish(&synth); | 557 mad_synth_finish(&synth); |
| 542 | 558 |
| 543 if (!info->playback->playing == 0) { | 559 if (info->playback->playing) { |
| 544 mad_plugin->output->buffer_free(); | 560 GTimeVal sleeptime; |
| 545 mad_plugin->output->buffer_free(); | 561 |
| 546 while (mad_plugin->output->buffer_playing()) { | 562 info->playback->output->buffer_free(); |
| 563 info->playback->output->buffer_free(); | |
| 564 while (info->playback->output->buffer_playing()) { | |
| 547 #ifdef DEBUG | 565 #ifdef DEBUG |
| 548 g_message("f: buffer_playing=%d", | 566 g_message("f: buffer_playing=%d", |
| 549 mad_plugin->output->buffer_playing()); | 567 info->playback->output->buffer_playing()); |
| 550 #endif | 568 #endif |
| 551 xmms_usleep(10000); | 569 g_get_current_time(&sleeptime); |
| 552 if (info->playback->playing == 0) | 570 sleeptime.tv_usec += 500000; |
| 571 if(sleeptime.tv_usec >= 1000000) { | |
| 572 sleeptime.tv_sec += 1; | |
| 573 sleeptime.tv_usec -= 1000000; | |
| 574 } | |
| 575 | |
| 576 g_mutex_lock(mad_mutex); | |
| 577 g_cond_timed_wait(mad_cond, mad_mutex, &sleeptime); | |
| 578 if (!info->playback->playing) { | |
| 579 g_mutex_unlock(mad_mutex); | |
| 553 break; | 580 break; |
| 581 } | |
| 582 g_mutex_unlock(mad_mutex); | |
| 554 } | 583 } |
| 555 } | 584 } |
| 556 #ifdef DEBUG | 585 #ifdef DEBUG |
| 557 g_message("e: decode"); | 586 g_message("e: decode"); |
| 558 #endif /* DEBUG */ | 587 #endif /* DEBUG */ |
| 559 | 588 |
| 560 bmp_title_input_free(info->tuple); | 589 bmp_title_input_free(info->tuple); |
| 561 info->tuple = NULL; | 590 info->tuple = NULL; |
| 562 | 591 |
| 563 mad_plugin->output->close_audio(); | 592 info->playback->output->close_audio(); |
| 593 g_mutex_lock(mad_mutex); | |
| 564 info->playback->playing = 0; | 594 info->playback->playing = 0; |
| 595 g_mutex_unlock(mad_mutex); | |
| 565 g_thread_exit(0); | 596 g_thread_exit(0); |
| 566 return NULL; /* dummy */ | 597 return NULL; /* dummy */ |
| 567 } | 598 } |
