From 8d1888a19823183ee5ea798846b994c8cdd0ddab Mon Sep 17 00:00:00 2001 From: philippe44 Date: Tue, 4 Apr 2023 22:13:31 -0700 Subject: [PATCH] new opus decoder --- components/codecs/CMakeLists.txt | 4 +- components/codecs/lib/libopusfile.a | Bin 91888 -> 0 bytes components/squeezelite/opus.c | 335 ++++++++++++++++++---------- 3 files changed, 218 insertions(+), 121 deletions(-) delete mode 100644 components/codecs/lib/libopusfile.a diff --git a/components/codecs/CMakeLists.txt b/components/codecs/CMakeLists.txt index b7d0b148..f53fe272 100644 --- a/components/codecs/CMakeLists.txt +++ b/components/codecs/CMakeLists.txt @@ -1,5 +1,5 @@ idf_component_register( - INCLUDE_DIRS . ./inc inc/alac inc/helix-aac inc/mad inc/resample16 inc/soxr inc/vorbis inc/opus inc/opusfile + INCLUDE_DIRS . ./inc inc/alac inc/helix-aac inc/mad inc/resample16 inc/soxr inc/vorbis inc/opus ) if (DEFINED AAC_DISABLE_SBR) @@ -14,7 +14,6 @@ add_prebuilt_library(libvorbisidec lib/libvorbisidec.a ) add_prebuilt_library(libogg lib/libogg.a ) add_prebuilt_library(libalac lib/libalac.a ) add_prebuilt_library(libresample16 lib/libresample16.a ) -add_prebuilt_library(libopusfile lib/libopusfile.a ) add_prebuilt_library(libopus lib/libopus.a ) target_link_libraries(${COMPONENT_LIB} INTERFACE libmad) @@ -24,5 +23,4 @@ target_link_libraries(${COMPONENT_LIB} INTERFACE libvorbisidec) target_link_libraries(${COMPONENT_LIB} INTERFACE libogg) target_link_libraries(${COMPONENT_LIB} INTERFACE libalac) target_link_libraries(${COMPONENT_LIB} INTERFACE libresample16) -target_link_libraries(${COMPONENT_LIB} INTERFACE libopusfile) target_link_libraries(${COMPONENT_LIB} INTERFACE libopus) diff --git a/components/codecs/lib/libopusfile.a b/components/codecs/lib/libopusfile.a deleted file mode 100644 index e51f47ad357c2a678672abc9b2b17689a4d27940..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 91888 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 diff --git a/components/squeezelite/opus.c b/components/squeezelite/opus.c index 4bffdf55..bafdd8a5 100644 --- a/components/squeezelite/opus.c +++ b/components/squeezelite/opus.c @@ -30,9 +30,6 @@ * thread has a higher priority. Using an interim buffer where opus decoder writes the output is not great from * an efficiency (one extra memory copy) point of view, but it allows the lock to not be kept for too long */ -#if EMBEDDED -#define FRAME_BUF 2048 -#endif #if BYTES_PER_FRAME == 4 #define ALIGN(n) (n) @@ -40,23 +37,53 @@ #define ALIGN(n) (n << 16) #endif -#include +#include +#include + +// opus maximum output frames is 120ms @ 48kHz +#define MAX_OPUS_FRAMES 5760 struct opus { - struct OggOpusFile *of; - bool end; -#if FRAME_BUF - u8_t *write_buf; -#endif -#if !LINKALL - // opus symbols to be dynamically loaded - void (*op_free)(OggOpusFile *_of); - int (*op_read)(OggOpusFile *_of, opus_int16 *_pcm, int _buf_size, int *_li); - const OpusHead* (*op_head)(OggOpusFile *_of, int _li); - OggOpusFile* (*op_open_callbacks) (void *_source, OpusFileCallbacks *_cb, unsigned char *_initial_data, size_t _initial_bytes, int *_error); -#endif + enum {OGG_SYNC, OGG_HEADER, OGG_PCM, OGG_DECODE} status; + ogg_stream_state state; + ogg_packet packet; + ogg_sync_state sync; + ogg_page page; + OpusDecoder* decoder; + int rate, gain, pre_skip; + bool fetch; + size_t overframes; + u8_t *overbuf; + int channels; }; +#if !LINKALL +static struct { + void *handle; + int (*ogg_stream_init)(ogg_stream_state* os, int serialno); + int (*ogg_stream_clear)(ogg_stream_state* os); + int (*ogg_stream_reset)(ogg_stream_state* os); + int (*ogg_stream_eos)(ogg_stream_state* os); + int (*ogg_stream_reset_serialno)(ogg_stream_state* os, int serialno); + int (*ogg_sync_clear)(ogg_sync_state* oy); + void (*ogg_packet_clear)(ogg_packet* op); + char* (*ogg_sync_buffer)(ogg_sync_state* oy, long size); + int (*ogg_sync_wrote)(ogg_sync_state* oy, long bytes); + long (*ogg_sync_pageseek)(ogg_sync_state* oy, ogg_page* og); + int (*ogg_sync_pageout)(ogg_sync_state* oy, ogg_page* og); + int (*ogg_stream_pagein)(ogg_stream_state* os, ogg_page* og); + int (*ogg_stream_packetout)(ogg_stream_state* os, ogg_packet* op); + int (*ogg_page_packets)(const ogg_page* og); +} go; + +static struct { + void* handle; + OpusDecoder* (*opus_decoder_create)(opus_int32 Fs, int channels, int* error); + int (*opus_decode)(OpusDecoder* st, const unsigned char* data, opus_int32 len, opus_int16* pcm, int frame_size, int decode_fec); + void (*opus_decoder_destroy)(OpusDecoder* st); +} gu; +#endif + static struct opus *u; extern log_level loglevel; @@ -89,26 +116,112 @@ extern struct processstate process; #endif #if LINKALL -#define OP(h, fn, ...) (op_ ## fn)(__VA_ARGS__) +#define OG(h, fn, ...) (ogg_ ## fn)(__VA_ARGS__) +#define OP(h, fn, ...) (opus_ ## fn)(__VA_ARGS__) #else -#define OP(h, fn, ...) (h)->op_ ## fn(__VA_ARGS__) +#define OG(h, fn, ...) (h)->ogg_ ## fn(__VA_ARGS__) +#define OP(h, fn, ...) (h)->opus_ ## fn(__VA_ARGS__) #endif -// called with mutex locked within vorbis_decode to avoid locking O before S -static int _read_cb(void *datasource, char *ptr, int size) { - size_t bytes; +static unsigned parse_uint16(const unsigned char* _data) { + return _data[0] | _data[1] << 8; +} + +static int parse_int16(const unsigned char* _data) { + return ((_data[0] | _data[1] << 8) ^ 0x8000) - 0x8000; +} + +static opus_uint32 parse_uint32(const unsigned char* _data) { + return _data[0] | (opus_uint32)_data[1] << 8 | + (opus_uint32)_data[2] << 16 | (opus_uint32)_data[3] << 24; +} + +static int get_opus_packet(void) { + int status = 0; LOCK_S; + size_t bytes = min(_buf_used(streambuf), _buf_cont_read(streambuf)); + + while (!(status = OG(&go, stream_packetout, &u->state, &u->packet)) && bytes) { + do { + size_t consumed = min(bytes, 4096); + char* buffer = OG(&gu, sync_buffer, &u->sync, consumed); + memcpy(buffer, streambuf->readp, consumed); + OG(&gu, sync_wrote, &u->sync, consumed); - bytes = min(_buf_used(streambuf), _buf_cont_read(streambuf)); - bytes = min(bytes, size); + _buf_inc_readp(streambuf, consumed); + bytes -= consumed; + } while (!(status = OG(&gu, sync_pageseek, &u->sync, &u->page)) && bytes); - memcpy(ptr, streambuf->readp, bytes); - _buf_inc_readp(streambuf, bytes); + // if we have a new page, put it in + if (status) OG(&go, stream_pagein, &u->state, &u->page); + } UNLOCK_S; + return status; +} - return bytes; +static int read_opus_header(void) { + int status = 0; + + LOCK_S; + size_t bytes = min(_buf_used(streambuf), _buf_cont_read(streambuf)); + + while (bytes && !status) { + + // first fetch a page if we need one + if (u->fetch) { + size_t consumed = min(bytes, 4096); + char* buffer = OG(&gu, sync_buffer, &u->sync, consumed); + memcpy(buffer, streambuf->readp, consumed); + OG(&gu, sync_wrote, &u->sync, consumed); + + _buf_inc_readp(streambuf, consumed); + bytes -= consumed; + + if (!OG(&gu, sync_pageseek, &u->sync, &u->page)) continue; + u->fetch = false; + } + + //bytes = min(bytes, size); + switch (u->status) { + case OGG_SYNC: + u->status = OGG_HEADER; + //OG(&gu, sync_pageout, &u->sync, &u->page); + OG(&gu, stream_reset_serialno, &u->state, OG(&gu, page_serialno, &u->page)); + break; + case OGG_HEADER: + status = OG(&gu, stream_pagein, &u->state, &u->page); + if (OG(&gu, stream_packetout, &u->state, &u->packet)) { + u->status = OGG_PCM; + if (u->packet.bytes < 19 || memcmp(u->packet.packet, "OpusHead", 8)) { + LOG_ERROR("wrong opus header packet (size:%u)", u->packet.bytes); + status = -100; + break; + } + u->channels = u->packet.packet[9]; + u->pre_skip = parse_uint16(u->packet.packet + 10); + u->rate = parse_uint32(u->packet.packet + 12); + u->gain = parse_int16(u->packet.packet + 16); + u->decoder = OP(&gu, decoder_create, 48000, u->channels, &status); + if (!u->decoder || status != OPUS_OK) { + LOG_ERROR("can't create decoder %d (channels:%u)", status, u->channels); + } + } + u->fetch = true; + break; + case OGG_PCM: + // loop until we have consumed VorbisComment and get ready for a new packet + u->fetch = true; + status = OG(&gu, page_packets, &u->page); + break; + default: + break; + } + } + + UNLOCK_S; + return status; } static decode_state opus_decompress(void) { @@ -117,30 +230,16 @@ static decode_state opus_decompress(void) { static int channels; u8_t *write_buf; - LOCK_S; + if (decode.new_stream) { + int status = read_opus_header(); - if (stream.state <= DISCONNECT && u->end) { - UNLOCK_S; - return DECODE_COMPLETE; - } - - UNLOCK_S; - - if (decode.new_stream) { - struct OpusFileCallbacks cbs; - const struct OpusHead *info; - int err; - - cbs.read = (op_read_func) _read_cb; - cbs.seek = NULL; cbs.tell = NULL; cbs.close = NULL; - - if ((u->of = OP(u, open_callbacks, streambuf, &cbs, NULL, 0, &err)) == NULL) { - LOG_WARN("open_callbacks error: %d", err); - return DECODE_COMPLETE; + if (status == 0) { + return DECODE_RUNNING; + } else if (status < 0) { + LOG_WARN("can't create codec"); + return DECODE_ERROR; } - - info = OP(u, head, u->of, -1); - + LOCK_O; output.next_sample_rate = decode_newstream(48000, output.supported_rates); IF_DSD( output.next_fmt = PCM; ) @@ -148,39 +247,49 @@ static decode_state opus_decompress(void) { if (output.fade_mode) _checkfade(true); decode.new_stream = false; UNLOCK_O; - - channels = info->channel_count; + + channels = u->channels; LOG_INFO("setting track_start"); } -#if FRAME_BUF - IF_DIRECT( - frames = min(_buf_space(outputbuf), _buf_cont_write(outputbuf)) / BYTES_PER_FRAME; - frames = min(frames, FRAME_BUF); - write_buf = u->write_buf; - ); -#else LOCK_O_direct; IF_DIRECT( frames = min(_buf_space(outputbuf), _buf_cont_write(outputbuf)) / BYTES_PER_FRAME; write_buf = outputbuf->writep; ); -#endif IF_PROCESS( frames = process.max_in_frames; write_buf = process.inbuf; ); - u->end = frames == 0; - - // write the decoded frames into outputbuf then unpack them (they are 16 bits) - n = OP(u, read, u->of, (opus_int16*) write_buf, frames * channels, NULL); + // get some packets and decode them, or use the leftover from previous pass + if (u->overframes) { + /* use potential leftover from previous encoding. We know that it will fit this time + * as min_space is >=MAX_OPUS_FRAMES and we start from the beginning of the buffer */ + memcpy(write_buf, u->overbuf, u->overframes * BYTES_PER_FRAME); + n = u->overframes; + u->overframes = 0; + } else if (get_opus_packet() > 0) { + if (frames < MAX_OPUS_FRAMES) { + // don't have enough contiguous space, use the overflow buffer (still works if n < 0) + n = OP(&gu, decode, u->decoder, u->packet.packet, u->packet.bytes, (opus_int16*) u->overbuf, MAX_OPUS_FRAMES, 0); + if (n > 0) { + u->overframes = n - min(n, frames); + n = min(n, frames); + memcpy(write_buf, u->overbuf, n * BYTES_PER_FRAME); + memmove(u->overbuf, u->overbuf + n, u->overframes); + } + } else { + /* we just do one packet at a time, although we could loop on packets but that means locking the + * outputbuf and streambuf for maybe a long time while we process it all, so don't do that */ + n = OP(&gu, decode, u->decoder, u->packet.packet, u->packet.bytes, (opus_int16*) write_buf, frames, 0); + } + } else if (!OG(&go, page_eos, &u->page)) { + UNLOCK_O_direct; + return DECODE_RUNNING; + } -#if FRAME_BUF - LOCK_O_direct; -#endif - if (n > 0) { frames_t count; s16_t *iptr; @@ -199,14 +308,7 @@ static decode_state opus_decompress(void) { ) if (channels == 2) { -#if BYTES_PER_FRAME == 4 -#if FRAME_BUF - // copy needed only when DIRECT and FRAME_BUF - IF_DIRECT( - memcpy(outputbuf->writep, write_buf, frames * BYTES_PER_FRAME); - ) -#endif -#else +#if BYTES_PER_FRAME == 8 while (count--) { *--optr = ALIGN(*--iptr); } @@ -230,21 +332,16 @@ static decode_state opus_decompress(void) { } else if (n == 0) { if (stream.state <= DISCONNECT) { - LOG_INFO("partial decode"); + LOG_INFO("end of decode"); UNLOCK_O_direct; return DECODE_COMPLETE; } else { LOG_INFO("no frame decoded"); } - } else if (n == OP_HOLE) { - - // recoverable hole in stream, seen when skipping - LOG_DEBUG("hole in stream"); - } else { - LOG_INFO("op_read error: %d", n); + LOG_INFO("opus decode error: %d", n); UNLOCK_O_direct; return DECODE_COMPLETE; } @@ -254,44 +351,52 @@ static decode_state opus_decompress(void) { return DECODE_RUNNING; } - -static void opus_open(u8_t size, u8_t rate, u8_t chan, u8_t endianness) { - if (!u->of) { -#if FRAME_BUF - if (!u->write_buf) u->write_buf = malloc(FRAME_BUF * BYTES_PER_FRAME); -#endif - } else { - OP(u, free, u->of); - u->of = NULL; - } - u->end = false; +static void opus_open(u8_t size, u8_t rate, u8_t chan, u8_t endianness) { + if (u->decoder) OP(&gu, decoder_destroy, u->decoder); + + if (!u->overbuf) u->overbuf = malloc(MAX_OPUS_FRAMES * BYTES_PER_FRAME); + u->status = OGG_SYNC; + u->fetch = true; + u->overframes = 0; + + OG(&gu, sync_init, &u->sync); + OG(&gu, stream_init, &u->state, -1); } -static void opus_close(void) { - if (u->of) { - OP(u, free, u->of); - u->of = NULL; - } -#if FRAME_BUF - free(u->write_buf); - u->write_buf = NULL; -#endif +static void opus_close(void) { + if (u->decoder) OP(&gu, decoder_destroy, u->decoder); + free(u->overbuf); + OG(&gu, stream_clear, &u->state); + OG(&gu, sync_clear, &u->sync); } static bool load_opus(void) { #if !LINKALL - void *handle = dlopen(LIBOPUS, RTLD_NOW); char *err; - - if (!handle) { + void *g_handle = dlopen(LIBOGG, RTLD_NOW); + void *u.handle = dlopen(LIBOPUS, RTLD_NOW); + + if (!g_handle || !u_handle) { LOG_INFO("dlerror: %s", dlerror()); return false; } - - u->op_free = dlsym(handle, "op_free"); - u->op_read = dlsym(handle, "op_read"); - u->op_head = dlsym(handle, "op_head"); - u->op_open_callbacks = dlsym(handle, "op_open_callbacks"); + + g_handle->ogg_stream_clear = dlsym(g_handle->handle, "ogg_stream_clear"); + g_handle->.ogg_stream_reset = dlsym(g_handle->handle, "ogg_stream_reset"); + g_handle->ogg_stream_eos = dlsym(g_handle->handle, "ogg_stream_eos"); + g_handle->ogg_stream_reset_serialno = dlsym(g_handle->handle, "ogg_stream_reset_serialno"); + g_handle->ogg_sync_clear = dlsym(g_handle->handle, "ogg_sync_clear"); + g_handle->ogg_packet_clear = dlsym(g_handle->handle, "ogg_packet_clear"); + g_handle->ogg_sync_buffer = dlsym(g_handle->handle, "ogg_sync_buffer"); + g_handle->ogg_sync_wrote = dlsym(g_handle->handle, "ogg_sync_wrote"); + g_handle->ogg_sync_pageseek = dlsym(g_handle->handle, "ogg_sync_pageseek"); + g_handle->ogg_sync_pageout = dlsym(g_handle->handle, "ogg_sync_pageout"); + g_handle->ogg_stream_pagein = dlsym(g_handle->handle, "ogg_stream_pagein"); + g_handle->ogg_stream_packetout = dlsym(g_handle->handle, "ogg_stream_packetout"); + g_handle->ogg_page_packets = dlsym(g_handle->handle, "ogg_page_packets"); + u_handle->opus_decoder_create = dlsym(u_handle->handle, "opus_decoder_create"); + u_handle->opus_decoder_destroy = dlsym(u_handle->handle, "opus_decoder_destroy"); + u_handle->opus_decode = dlsym(u_handle->handle, "opus_decode"); if ((err = dlerror()) != NULL) { LOG_INFO("dlerror: %s", err); @@ -308,23 +413,17 @@ struct codec *register_opus(void) { static struct codec ret = { 'u', // id "ops", // types - 4*1024, // min read - 32*1024, // min space + 8*1024, // min read + MAX_OPUS_FRAMES*BYTES_PER_FRAME*2, // min space opus_open, // open opus_close, // close opus_decompress, // decode }; - u = malloc(sizeof(struct opus)); - if (!u) { + if ((u = calloc(1, sizeof(struct opus))) == NULL) { return NULL; } - u->of = NULL; -#if FRAME_BUF - u->write_buf = NULL; -#endif - if (!load_opus()) { return NULL; }