diff options
Diffstat (limited to 'lib/rbcodec/codecs')
-rw-r--r-- | lib/rbcodec/codecs/opus.c | 128 |
1 files changed, 54 insertions, 74 deletions
diff --git a/lib/rbcodec/codecs/opus.c b/lib/rbcodec/codecs/opus.c index 6574d6c052..89eb4fe3ad 100644 --- a/lib/rbcodec/codecs/opus.c +++ b/lib/rbcodec/codecs/opus.c | |||
@@ -59,7 +59,7 @@ static int get_more_data(ogg_sync_state *oy) | |||
59 | } | 59 | } |
60 | 60 | ||
61 | /* seek to ogg page after given file position */ | 61 | /* seek to ogg page after given file position */ |
62 | static int seek_ogg_page(int64_t filepos) | 62 | static int seek_ogg_page(uint64_t filepos) |
63 | { | 63 | { |
64 | const char synccode[] = "OggS\0"; /* Note: there are two nulls here */ | 64 | const char synccode[] = "OggS\0"; /* Note: there are two nulls here */ |
65 | char buf[sizeof(synccode)]; | 65 | char buf[sizeof(synccode)]; |
@@ -208,7 +208,7 @@ static int64_t seek_backwards(ogg_sync_state *oy, ogg_page *og, | |||
208 | return -1; | 208 | return -1; |
209 | } | 209 | } |
210 | 210 | ||
211 | static int speex_seek_page_granule(int64_t pos, int64_t curpos, | 211 | static int opus_seek_page_granule(int64_t pos, int64_t curpos, |
212 | ogg_sync_state *oy, ogg_stream_state *os) | 212 | ogg_sync_state *oy, ogg_stream_state *os) |
213 | { | 213 | { |
214 | /* TODO: Someone may want to try to implement seek to packet, | 214 | /* TODO: Someone may want to try to implement seek to packet, |
@@ -326,8 +326,7 @@ static int speex_seek_page_granule(int64_t pos, int64_t curpos, | |||
326 | /* this is the codec entry point */ | 326 | /* this is the codec entry point */ |
327 | enum codec_status codec_main(enum codec_entry_call_reason reason) | 327 | enum codec_status codec_main(enum codec_entry_call_reason reason) |
328 | { | 328 | { |
329 | (void)reason; | 329 | (void)reason; /* CODEC_LOAD, CODEC_UNLOAD */ |
330 | |||
331 | return CODEC_OK; | 330 | return CODEC_OK; |
332 | } | 331 | } |
333 | 332 | ||
@@ -342,7 +341,7 @@ enum codec_status codec_run(void) | |||
342 | ogg_packet op; | 341 | ogg_packet op; |
343 | ogg_stream_state os; | 342 | ogg_stream_state os; |
344 | int64_t page_granule = 0; | 343 | int64_t page_granule = 0; |
345 | int stream_init = 0; | 344 | int stream_init = -1; |
346 | int sample_rate = 48000; | 345 | int sample_rate = 48000; |
347 | OpusDecoder *st = NULL; | 346 | OpusDecoder *st = NULL; |
348 | OpusHeader header; | 347 | OpusHeader header; |
@@ -375,38 +374,29 @@ enum codec_status codec_run(void) | |||
375 | ci->seek_buffer(0); | 374 | ci->seek_buffer(0); |
376 | ci->set_elapsed(0); | 375 | ci->set_elapsed(0); |
377 | 376 | ||
378 | if (!strtoffset && param) { | 377 | goto next_page; /* need to decode header before we do anything else */ |
379 | action = CODEC_ACTION_SEEK_TIME; | ||
380 | } | ||
381 | |||
382 | goto next_page; | ||
383 | 378 | ||
384 | while (1) { | 379 | while (1) { |
385 | if (action == CODEC_ACTION_NULL) | 380 | action = ci->get_command(¶m); |
386 | action = ci->get_command(¶m); | 381 | |
387 | 382 | process_action: | |
388 | if (action != CODEC_ACTION_NULL) { | 383 | if (action == CODEC_ACTION_SEEK_TIME) { |
389 | if (action == CODEC_ACTION_HALT) | 384 | if (st != NULL) { |
390 | break; | 385 | /* calculate granule to seek to (including seek rewind) */ |
391 | 386 | seek_target = (48LL * param) + header.preskip; | |
392 | if (action == CODEC_ACTION_SEEK_TIME) { | 387 | skip = MIN(seek_target, SEEK_REWIND); |
393 | if (st != NULL) { | 388 | seek_target -= skip; |
394 | /* calculate granule to seek to (including seek rewind) */ | 389 | |
395 | seek_target = (48LL * param) + header.preskip; | 390 | LOGF("Opus seek page:%lld,%lld,%ld\n", |
396 | skip = MIN(seek_target, SEEK_REWIND); | 391 | seek_target, page_granule, (long)param); |
397 | seek_target -= skip; | 392 | opus_seek_page_granule(seek_target, page_granule, &oy, &os); |
398 | |||
399 | LOGF("Opus seek page:%lld,%lld,%ld\n", | ||
400 | seek_target, page_granule, (long)param); | ||
401 | speex_seek_page_granule(seek_target, page_granule, &oy, &os); | ||
402 | } | ||
403 | |||
404 | ci->set_elapsed(param); | ||
405 | ci->seek_complete(); | ||
406 | } | 393 | } |
407 | 394 | ||
408 | action = CODEC_ACTION_NULL; | 395 | ci->set_elapsed(param); |
409 | } | 396 | ci->seek_complete(); |
397 | param = 0; | ||
398 | } else if (action == CODEC_ACTION_HALT) | ||
399 | break; | ||
410 | 400 | ||
411 | next_page: | 401 | next_page: |
412 | /*Get the ogg buffer for writing*/ | 402 | /*Get the ogg buffer for writing*/ |
@@ -416,9 +406,12 @@ enum codec_status codec_run(void) | |||
416 | 406 | ||
417 | /* Loop for all complete pages we got (most likely only one) */ | 407 | /* Loop for all complete pages we got (most likely only one) */ |
418 | while (ogg_sync_pageout(&oy, &og) == 1) { | 408 | while (ogg_sync_pageout(&oy, &og) == 1) { |
419 | if (stream_init == 0) { | 409 | if (stream_init != 0) { |
420 | ogg_stream_init(&os, ogg_page_serialno(&og)); | 410 | stream_init = ogg_stream_init(&os, ogg_page_serialno(&og)); |
421 | stream_init = 1; | 411 | if (stream_init != 0) { |
412 | LOGF("Stream init failed"); | ||
413 | goto done; | ||
414 | } | ||
422 | } | 415 | } |
423 | 416 | ||
424 | /* Add page to the bitstream */ | 417 | /* Add page to the bitstream */ |
@@ -427,16 +420,6 @@ enum codec_status codec_run(void) | |||
427 | page_granule = ogg_page_granulepos(&og); | 420 | page_granule = ogg_page_granulepos(&og); |
428 | granule_pos = page_granule; | 421 | granule_pos = page_granule; |
429 | 422 | ||
430 | /* Do this to avoid allocating space for huge comment packets | ||
431 | (embedded Album Art) */ | ||
432 | if (os.packetno == 1 && ogg_stream_packetpeek(&os, NULL) == 0){ | ||
433 | LOGF("sync reset"); | ||
434 | /* seek buffer directly to the first audio packet */ | ||
435 | seek_ogg_page(ci->curpos - oy.returned); | ||
436 | ogg_sync_reset(&oy); | ||
437 | break; | ||
438 | } | ||
439 | |||
440 | while ((ogg_stream_packetout(&os, &op) == 1) && !op.e_o_s) { | 423 | while ((ogg_stream_packetout(&os, &op) == 1) && !op.e_o_s) { |
441 | if (op.packetno == 0){ | 424 | if (op.packetno == 0){ |
442 | /* identification header */ | 425 | /* identification header */ |
@@ -463,16 +446,21 @@ enum codec_status codec_run(void) | |||
463 | ci->configure(DSP_SET_STEREO_MODE, (header.channels == 2) ? | 446 | ci->configure(DSP_SET_STEREO_MODE, (header.channels == 2) ? |
464 | STEREO_INTERLEAVED : STEREO_MONO); | 447 | STEREO_INTERLEAVED : STEREO_MONO); |
465 | 448 | ||
466 | } else if (op.packetno == 1) { | 449 | if (strtoffset) |
467 | /* Comment header */ | 450 | seek_ogg_page(strtoffset); |
468 | } else { | 451 | else if (param) { |
469 | if (strtoffset) { | 452 | action = CODEC_ACTION_SEEK_TIME; |
470 | ci->seek_buffer(strtoffset); | 453 | goto process_action; |
471 | ogg_sync_reset(&oy); | 454 | } else { |
472 | strtoffset = 0; | 455 | /* seek buffer directly to the first audio packet to avoid |
473 | break;//next page | 456 | allocating space for huge comment packets |
457 | (embedded Album Art) */ | ||
458 | seek_ogg_page(ci->curpos - oy.returned); | ||
474 | } | 459 | } |
475 | 460 | LOGF("sync reset"); | |
461 | ogg_sync_reset(&oy); /* next page */ | ||
462 | break; | ||
463 | } else { | ||
476 | /* report progress */ | 464 | /* report progress */ |
477 | ci->set_offset((size_t) ci->curpos); | 465 | ci->set_offset((size_t) ci->curpos); |
478 | ci->set_elapsed((granule_pos - header.preskip) / 48); | 466 | ci->set_elapsed((granule_pos - header.preskip) / 48); |
@@ -480,29 +468,22 @@ enum codec_status codec_run(void) | |||
480 | /* Decode audio packets */ | 468 | /* Decode audio packets */ |
481 | ret = opus_decode(st, op.packet, op.bytes, output, MAX_FRAME_SIZE, 0); | 469 | ret = opus_decode(st, op.packet, op.bytes, output, MAX_FRAME_SIZE, 0); |
482 | 470 | ||
483 | if (ret > 0) { | 471 | if (ret > skip) { |
484 | if (skip > 0) { | 472 | /* part of or entire output buffer is played */ |
485 | if (ret <= skip) { | 473 | ret -= skip; |
486 | /* entire output buffer is skipped */ | 474 | ci->pcmbuf_insert(&output[skip * header.channels], NULL, ret); |
487 | skip -= ret; | 475 | skip = 0; |
488 | ret = 0; | ||
489 | } else { | ||
490 | /* part of output buffer is played */ | ||
491 | ret -= skip; | ||
492 | ci->pcmbuf_insert(&output[skip * header.channels], NULL, ret); | ||
493 | skip = 0; | ||
494 | } | ||
495 | } else { | ||
496 | /* entire buffer is played */ | ||
497 | ci->pcmbuf_insert(output, NULL, ret); | ||
498 | } | ||
499 | granule_pos += ret; | ||
500 | } else { | 476 | } else { |
501 | if (ret < 0) { | 477 | if (ret < 0) { |
502 | LOGF("opus_decode failed %d", ret); | 478 | LOGF("opus_decode failed %d", ret); |
503 | goto done; | 479 | goto done; |
480 | } else if (ret == 0) | ||
481 | break; | ||
482 | else { | ||
483 | /* entire output buffer is skipped */ | ||
484 | skip -= ret; | ||
485 | ret = 0; | ||
504 | } | 486 | } |
505 | break; | ||
506 | } | 487 | } |
507 | } | 488 | } |
508 | } | 489 | } |
@@ -514,4 +495,3 @@ done: | |||
514 | ogg_malloc_destroy(); | 495 | ogg_malloc_destroy(); |
515 | return error; | 496 | return error; |
516 | } | 497 | } |
517 | |||