summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorWilliam Wilgus <me.theuser@yahoo.com>2019-01-12 12:56:26 -0600
committerWilliam Wilgus <me.theuser@yahoo.com>2019-01-23 23:37:46 +0100
commit00943537e63347f9ca338288c32dd91d45529ec8 (patch)
tree18bd2ac181423659a43ad48884c371f023db6f23
parentc70e40f05024537074fc20585482c8d1f007081f (diff)
downloadrockbox-00943537e63347f9ca338288c32dd91d45529ec8.tar.gz
rockbox-00943537e63347f9ca338288c32dd91d45529ec8.zip
opus optimize playback function
knocks off about .5 second from decode time not a big change but might help a bit on devices that barely achieve realtime Change-Id: If6e822b7273613c9449c102ce7dd3543bf975d37
-rw-r--r--lib/rbcodec/codecs/opus.c128
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 */
62static int seek_ogg_page(int64_t filepos) 62static 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
211static int speex_seek_page_granule(int64_t pos, int64_t curpos, 211static 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 */
327enum codec_status codec_main(enum codec_entry_call_reason reason) 327enum 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(&param);
386 action = ci->get_command(&param); 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