From 3bcddd27ccd9abe41bd59719b77b4a9465e6f24b Mon Sep 17 00:00:00 2001 From: Ilari Liusvaara Date: Sun, 19 May 2013 14:49:25 +0300 Subject: [PATCH] Support runtime loading of libopus --- include/core/loadlib.hpp | 1 + include/library/opus.hpp | 9 + src/core/inthread.cpp | 33 +- src/core/loadlib.cpp | 17 +- src/emulation/sky/music.cpp | 85 ++- src/emulation/sky/music.hpp | 4 - src/library/opus.cpp | 588 ++++++++++++++++++++- src/platform/wxwidgets/editor-voicesub.cpp | 2 - src/platform/wxwidgets/mainwindow.cpp | 8 +- src/util/lsnes-dumpavi.cpp | 2 +- 10 files changed, 657 insertions(+), 92 deletions(-) diff --git a/include/core/loadlib.hpp b/include/core/loadlib.hpp index 2716f507..e8380eee 100644 --- a/include/core/loadlib.hpp +++ b/include/core/loadlib.hpp @@ -5,5 +5,6 @@ void handle_post_loadlibrary(); void autoload_libraries(); +void with_loaded_library(loaded_library* l); #endif diff --git a/include/library/opus.hpp b/include/library/opus.hpp index 762466c6..b520635c 100644 --- a/include/library/opus.hpp +++ b/include/library/opus.hpp @@ -5,15 +5,24 @@ #include #include #include +#include + +class loaded_library; namespace opus { +void load_libopus(loaded_library& lib); +bool libopus_loaded(); +size_t add_callback(std::function fun); +void cancel_callback(size_t handle); + struct bad_argument : public std::runtime_error { bad_argument(); }; struct buffer_too_small : public std::runtime_error { buffer_too_small(); }; struct internal_error : public std::runtime_error { internal_error(); }; struct invalid_packet : public std::runtime_error { invalid_packet(); }; struct unimplemented : public std::runtime_error { unimplemented(); }; struct invalid_state : public std::runtime_error { invalid_state(); }; +struct not_loaded : public std::runtime_error { not_loaded(); }; class encoder; class decoder; diff --git a/src/core/inthread.cpp b/src/core/inthread.cpp index b54da6fe..949829f0 100644 --- a/src/core/inthread.cpp +++ b/src/core/inthread.cpp @@ -1,6 +1,5 @@ #include #include -#ifdef WITH_OPUS_CODEC #include "library/filesys.hpp" #include "library/minmax.hpp" #include "library/workthread.hpp" @@ -635,7 +634,7 @@ out: header.coupled = 0; header.chanmap[0] = 0; memset(header.chanmap + 1, 255, 254); - tags.vendor = opus::version(); + tags.vendor = "unknown"; tags.comments.push_back((stringfmt() << "ENCODER=lsnes rr" + lsnes_version).str()); tags.comments.push_back((stringfmt() << "LSNES_STREAM_TS=" << s_timebase).str()); struct ogg_page hpage = serialize_oggopus_header(header); @@ -658,9 +657,7 @@ out: } if(!p.size()) (stringfmt() << "Empty Opus packet is not valid").throwex(); - uint32_t frames = opus::packet_get_nb_frames(&p[0], p.size()); - uint32_t samples_pf = opus::packet_get_samples_per_frame(&p[0], opus::samplerate::r48k); - uint32_t samples = frames * samples_pf; + uint32_t samples = static_cast(opus_packet_tick_count(&p[0], p.size())) * 120; if(i + 1 < packets.size()) true_granule += samples; else @@ -1547,6 +1544,10 @@ out: void kill() { quit = true; + { + umutex_class h(lmut); + lcond.notify_all(); + } while(!quit_ack) usleep(100000); usleep(100000); @@ -1565,6 +1566,21 @@ out: } void entry2() { + //Wait for libopus to load... + size_t cbh = opus::add_callback([this]() { + umutex_class h(this->lmut); + this->lcond.notify_all(); + }); + while(true) { + umutex_class h(lmut); + if(opus::libopus_loaded() || quit) + break; + lcond.wait(h); + } + opus::cancel_callback(cbh); + if(quit) + return; + int err; opus::encoder oenc(opus::samplerate::r48k, false, opus::application::voice); oenc.ctl(opus::bitrate(opus_bitrate.get())); @@ -1645,6 +1661,8 @@ out: double position; volatile bool quit; volatile bool quit_ack; + mutex_class lmut; + cv_class lcond; }; //The tangent function. @@ -1861,8 +1879,3 @@ double voicesub_ts_seconds(uint64_t ts) { return ts / 48000.0; } -#else -void voicethread_task() {} -void voice_frame_number(uint64_t newframe, double rate) {} -void voicethread_kill() {} -#endif diff --git a/src/core/loadlib.cpp b/src/core/loadlib.cpp index d5ff388d..9a68a844 100644 --- a/src/core/loadlib.cpp +++ b/src/core/loadlib.cpp @@ -4,6 +4,7 @@ #include "core/dispatch.hpp" #include "core/misc.hpp" #include "library/directory.hpp" +#include "library/opus.hpp" #include #include #include @@ -16,16 +17,22 @@ void handle_post_loadlibrary() } } +void with_loaded_library(loaded_library* l) +{ + try { + if(!opus::libopus_loaded()) + opus::load_libopus(*l); + } catch(...) { + //This wasn't libopus. + } +} + void autoload_libraries() { try { auto libs = enumerate_directory(get_config_path() + "/autoload", ".*"); for(auto i : libs) - try { - new loaded_library(i); - messages << "Autoloaded '" << i << "'" << std::endl; - } catch(...) { - } + with_loaded_library(new loaded_library(i)); handle_post_loadlibrary(); } catch(std::exception& e) { messages << e.what() << std::endl; diff --git a/src/emulation/sky/music.cpp b/src/emulation/sky/music.cpp index c2330afc..29d0daef 100644 --- a/src/emulation/sky/music.cpp +++ b/src/emulation/sky/music.cpp @@ -481,7 +481,6 @@ namespace sky song_buffer* bsong; -#ifdef WITH_OPUS_CODEC packet_decoder::packet_decoder() { d = NULL; @@ -490,24 +489,29 @@ namespace sky void packet_decoder::set_multistream(const struct multistream_characteristics& c) { - size_t msstate_size = opus::multistream_decoder::size(c.streams, c.coupled); - msstate_size += sizeof(opus::multistream_decoder) + alignof(opus::multistream_decoder); - size_t dmix_offset = msstate_size; - msstate_size += 5760 * c.channels * sizeof(float); - if(memory.size() < msstate_size) - memory.resize(msstate_size); - uint8_t* a = &memory[0]; - if(reinterpret_cast(a) % alignof(opus::multistream_decoder)) - a++; - uint8_t* b = a + sizeof(opus::multistream_decoder); - d = new(a) opus::multistream_decoder(opus::samplerate::r48k, c.channels, c.streams, c.coupled, - c.mapping, reinterpret_cast(b)); - dmem = reinterpret_cast(a + dmix_offset); - channels = c.channels; - float gain_factor = 2 * pow(10, c.gain / 5120.0); - for(unsigned i = 0; i < channels; i++) { - downmix_l[i] = gain_factor * c.downmix_l[i]; - downmix_r[i] = gain_factor * c.downmix_r[i]; + try { + size_t msstate_size = opus::multistream_decoder::size(c.streams, c.coupled); + msstate_size += sizeof(opus::multistream_decoder) + alignof(opus::multistream_decoder); + size_t dmix_offset = msstate_size; + msstate_size += 5760 * c.channels * sizeof(float); + if(memory.size() < msstate_size) + memory.resize(msstate_size); + uint8_t* a = &memory[0]; + if(reinterpret_cast(a) % alignof(opus::multistream_decoder)) + a++; + uint8_t* b = a + sizeof(opus::multistream_decoder); + d = new(a) opus::multistream_decoder(opus::samplerate::r48k, c.channels, c.streams, c.coupled, + c.mapping, reinterpret_cast(b)); + dmem = reinterpret_cast(a + dmix_offset); + channels = c.channels; + float gain_factor = 2 * pow(10, c.gain / 5120.0); + for(unsigned i = 0; i < channels; i++) { + downmix_l[i] = gain_factor * c.downmix_l[i]; + downmix_r[i] = gain_factor * c.downmix_r[i]; + } + } catch(opus::not_loaded l) { + d = NULL; + channels = c.channels; } } @@ -515,7 +519,18 @@ namespace sky { size_t s = 120; try { - s = d->decode(&data[0], data.size(), dmem, 5760); + if(d) + s = d->decode(&data[0], data.size(), dmem, 5760); + else { + //Insert silence. + uint8_t ticks = opus_packet_tick_count(&data[0], data.size()); + if(!ticks) + ticks = 1; //Try to recover. + memset(pcmbuf, 0, 240 * ticks * sizeof(int16_t)); + pcmpos = 0; + pcmlen = 120 * ticks; + return; + } } catch(std::exception& e) { //Try to insert silence. messages << "Failed to decode opus packet: " << e.what() << std::endl; @@ -543,32 +558,12 @@ namespace sky void packet_decoder::reset() { - d->ctl(opus::reset); + try { + if(d) + d->ctl(opus::reset); + } catch(opus::not_loaded e) { + } } -#else - packet_decoder::packet_decoder() - { - channels = 0; - } - - void packet_decoder::set_multistream(const struct multistream_characteristics& c) - { - } - - void packet_decoder::decode_packet(const std::vector& data) - { - uint32_t ticks = opus_packet_tick_count(&data[0], data.size()); - if(!ticks) - ticks = 1; //Stream damaged, try to recover. - pcmpos = 0; - pcmlen = 120 * ticks; - memset(pcmbuf, 0, 240 * ticks * sizeof(int16_t)); - } - - void packet_decoder::reset() - { - } -#endif music_player::music_player(struct music_player_memory& m, random& _rng) : mem(m), rng(_rng) diff --git a/src/emulation/sky/music.hpp b/src/emulation/sky/music.hpp index 6fe1892d..a796d5ec 100644 --- a/src/emulation/sky/music.hpp +++ b/src/emulation/sky/music.hpp @@ -8,9 +8,7 @@ #include #include "random.hpp" #include "library/ogg.hpp" -#ifdef WITH_OPUS_CODEC #include "library/opus.hpp" -#endif namespace sky { @@ -133,9 +131,7 @@ namespace sky uint16_t pcmlen; int16_t pcmbuf[11522]; private: -#ifdef WITH_OPUS_CODEC opus::multistream_decoder* d; -#endif uint8_t channels; float downmix_l[255]; float downmix_r[255]; diff --git a/src/library/opus.cpp b/src/library/opus.cpp index 2cd1938e..c54a88ff 100644 --- a/src/library/opus.cpp +++ b/src/library/opus.cpp @@ -1,11 +1,82 @@ -#ifdef WITH_OPUS_CODEC +#ifndef WITH_OPUS_CODEC +#define RUNTIME_LIBOPUS +#endif #define OPUS_BUILD #include "opus.hpp" +#ifndef RUNTIME_LIBOPUS #include #include #include +#else +#include "loadlib.hpp" +#include "threadtypes.hpp" +#endif #include #include +#include +#include + +#ifdef RUNTIME_LIBOPUS +#define OPUS_AUTO -1000 +#define OPUS_ALLOC_FAIL -7 +#define OPUS_APPLICATION_AUDIO 2049 +#define OPUS_APPLICATION_RESTRICTED_LOWDELAY 2051 +#define OPUS_APPLICATION_VOIP 2048 +#define OPUS_AUTO -1000 +#define OPUS_BAD_ARG -1 +#define OPUS_BANDWIDTH_FULLBAND 1105 +#define OPUS_BANDWIDTH_MEDIUMBAND 1102 +#define OPUS_BANDWIDTH_NARROWBAND 1101 +#define OPUS_BANDWIDTH_SUPERWIDEBAND 1104 +#define OPUS_BANDWIDTH_WIDEBAND 1103 +#define OPUS_BITRATE_MAX -1 +#define OPUS_BUFFER_TOO_SMALL -2 +#define OPUS_GET_APPLICATION_REQUEST 4001 +#define OPUS_GET_BANDWIDTH_REQUEST 4009 +#define OPUS_GET_BITRATE_REQUEST 4003 +#define OPUS_GET_COMPLEXITY_REQUEST 4011 +#define OPUS_GET_DTX_REQUEST 4017 +#define OPUS_GET_FINAL_RANGE_REQUEST 4031 +#define OPUS_GET_FORCE_CHANNELS_REQUEST 4023 +#define OPUS_GET_INBAND_FEC_REQUEST 4013 +#define OPUS_GET_LOOKAHEAD_REQUEST 4027 +#define OPUS_GET_MAX_BANDWIDTH_REQUEST 4005 +#define OPUS_GET_PACKET_LOSS_PERC_REQUEST 4015 +#define OPUS_GET_PITCH_REQUEST 4033 +#define OPUS_GET_SAMPLE_RATE_REQUEST 4029 +#define OPUS_GET_SIGNAL_REQUEST 4025 +#define OPUS_GET_VBR_CONSTRAINT_REQUEST 4021 +#define OPUS_GET_VBR_REQUEST 4007 +#define OPUS_INTERNAL_ERROR -3 +#define OPUS_INVALID_PACKET -4 +#define OPUS_INVALID_STATE -6 +#define OPUS_RESET_STATE 4028 +#define OPUS_SET_APPLICATION_REQUEST 4000 +#define OPUS_SET_BANDWIDTH_REQUEST 4008 +#define OPUS_SET_BITRATE_REQUEST 4002 +#define OPUS_SET_COMPLEXITY_REQUEST 4010 +#define OPUS_SET_DTX_REQUEST 4016 +#define OPUS_SET_FORCE_CHANNELS_REQUEST 4022 +#define OPUS_SET_INBAND_FEC_REQUEST 4012 +#define OPUS_SET_MAX_BANDWIDTH_REQUEST 4004 +#define OPUS_SET_PACKET_LOSS_PERC_REQUEST 4014 +#define OPUS_SET_SIGNAL_REQUEST 4024 +#define OPUS_SET_VBR_CONSTRAINT_REQUEST 4020 +#define OPUS_SET_VBR_REQUEST 4006 +#define OPUS_SIGNAL_MUSIC 3002 +#define OPUS_SIGNAL_VOICE 3001 +#define OPUS_UNIMPLEMENTED -5 +#define OPUS_MULTISTREAM_GET_ENCODER_STATE_REQUEST 5120 +#define OPUS_MULTISTREAM_GET_DECODER_STATE_REQUEST 5122 +#define OPUS_SUPPORTS_SURROUND +#define SURROUND_SUPPORTED opus_surround_supported() +#else +#ifdef OPUS_SUPPORTS_SURROUND +#define SURROUND_SUPPORTED 1 +#else +#define SURROUND_SUPPORTED 0 +#endif +#endif //Some of these might not be in stable. #ifndef OPUS_SET_GAIN_REQUEST @@ -26,6 +97,477 @@ namespace opus { +#ifdef RUNTIME_LIBOPUS +struct OpusEncoder { int dummy; }; +struct OpusDecoder { int dummy; }; +struct OpusMSEncoder { int dummy; }; +struct OpusMSDecoder { int dummy; }; +struct OpusRepacketizer { int dummy; }; + +int dummy_encoder_ctl(OpusEncoder* e, int request, ...) { throw not_loaded(); } +int dummy_decoder_ctl(OpusDecoder* e, int request, ...) { throw not_loaded(); } +int dummy_multistream_encoder_ctl(OpusMSEncoder* e, int request, ...) { throw not_loaded(); } +int dummy_multistream_decoder_ctl(OpusMSDecoder* e, int request, ...) { throw not_loaded(); } + +struct functions +{ + int (*encoder_ctl)(OpusEncoder* e, int request, ...); + int (*decoder_ctl)(OpusDecoder* e, int request, ...); + int (*multistream_encoder_ctl)(OpusMSEncoder* e, int request, ...); + int (*multistream_decoder_ctl)(OpusMSDecoder* e, int request, ...); + int (*encoder_init)(OpusEncoder* e, int32_t fs, int ch, int app); + int (*decoder_init)(OpusDecoder* e, int32_t fs, int ch); + int (*encoder_get_size)(int ch); + int (*decoder_get_size)(int ch); + int32_t (*encode)(OpusEncoder* e, const int16_t* pcm, int frames, unsigned char* data, int32_t maxout); + int32_t (*encode_float)(OpusEncoder* e, const float* pcm, int frames, unsigned char* data, int32_t maxout); + int32_t (*decode)(OpusDecoder* e, const unsigned char* data, int32_t datasize, int16_t* pcm, int frames, + int fec); + int32_t (*decode_float)(OpusDecoder* e, const unsigned char* data, int32_t datasize, float* pcm, int frames, + int fec); + int (*decoder_get_nb_samples)(const OpusDecoder* dec, const unsigned char packet[], int32_t len); + OpusRepacketizer *(*repacketizer_init)(OpusRepacketizer* r); + int (*repacketizer_get_size)(); + int (*repacketizer_cat)(OpusRepacketizer* r, const unsigned char* data, int32_t len); + int32_t (*repacketizer_out_range)(OpusRepacketizer* r, int begin, int end, unsigned char* data, + int32_t maxlen); + int32_t (*repacketizer_out)(OpusRepacketizer* r, unsigned char* data, int32_t maxlen); + int (*repacketizer_get_nb_frames)(OpusRepacketizer* r); + const char* (*get_version_string)(); + int (*multistream_decode)(OpusMSDecoder* d, const unsigned char* data, int32_t datasize, int16_t* pcm, + int pcmlen, int fec); + int (*multistream_decode_float)(OpusMSDecoder* d, const unsigned char* data, int32_t datasize, float* pcm, + int pcmlen, int fec); + int32_t (*multistream_decoder_get_size)(int streams, int coupled); + int (*multistream_decoder_init)(OpusMSDecoder* d, int32_t fs, int ch, int st, int co, + const unsigned char* map); + int (*multistream_encode)(OpusMSEncoder* d, const int16_t* pcm, int pcmlen, unsigned char* data, + int32_t datasize); + int (*multistream_encode_float)(OpusMSEncoder* d, const float* pcm, int pcmlen, unsigned char* data, + int32_t datasize); + int32_t (*multistream_encoder_get_size)(int streams, int coupled); + int (*multistream_encoder_init)(OpusMSEncoder* d, int32_t fs, int ch, int st, int co, + const unsigned char* map, int app); + int (*packet_get_bandwidth)(const unsigned char* p); + int (*packet_get_nb_channels)(const unsigned char* p); + int (*packet_get_nb_frames)(const unsigned char* p, int32_t psize); + int (*packet_get_samples_per_frame)(const unsigned char* p, int32_t fs); + int (*packet_parse)(const unsigned char* data, int32_t dsize, unsigned char* toc, + const unsigned char* fdata[48], short fsize[48], int* poffset); + int32_t (*multistream_surround_encoder_get_size)(int ch, int f); + int (*multistream_surround_encoder_init)(OpusMSEncoder* e, int32_t fs, int ch, int f, int* st, int* co, + unsigned char* map, int app); +}; + +struct functions dummy_functions = { + .encoder_ctl = dummy_encoder_ctl, + .decoder_ctl = dummy_decoder_ctl, + .multistream_encoder_ctl = dummy_multistream_encoder_ctl, + .multistream_decoder_ctl = dummy_multistream_decoder_ctl, + .encoder_init = [](OpusEncoder* e, int32_t fs, int ch, int app) -> int { throw not_loaded(); }, + .decoder_init = [](OpusDecoder* e, int32_t fs, int ch) -> int { throw not_loaded(); }, + .encoder_get_size = [](int ch) -> int { throw not_loaded(); }, + .decoder_get_size = [](int ch) -> int { throw not_loaded(); }, + .encode = [](OpusEncoder* e, const int16_t* pcm, int frames, unsigned char* data, int32_t maxout) + -> int32_t { throw not_loaded(); }, + .encode_float = [](OpusEncoder* e, const float* pcm, int frames, unsigned char* data, int32_t maxout) + -> int32_t { throw not_loaded(); }, + .decode = [](OpusDecoder* e, const unsigned char* data, int32_t datasize, int16_t* pcm, int frames, int fec) + -> int32_t { throw not_loaded(); }, + .decode_float = [](OpusDecoder* e, const unsigned char* data, int32_t datasize, float* pcm, int frames, + int fec) -> int32_t { throw not_loaded(); }, + .decoder_get_nb_samples = [](const OpusDecoder* dec, const unsigned char packet[], int32_t len) + -> int { throw not_loaded(); }, + .repacketizer_init = [](OpusRepacketizer* r) -> OpusRepacketizer* { throw not_loaded(); }, + .repacketizer_get_size = []() -> int { throw not_loaded(); }, + .repacketizer_cat = [](OpusRepacketizer* r, const unsigned char* data, int32_t len) + -> int { throw not_loaded(); }, + .repacketizer_out_range = [](OpusRepacketizer* r, int begin, int end, unsigned char* data, int32_t maxlen) + -> int32_t { throw not_loaded(); }, + .repacketizer_out = [](OpusRepacketizer* r, unsigned char* data, int32_t maxlen) + -> int32_t { throw not_loaded(); }, + .repacketizer_get_nb_frames = [](OpusRepacketizer* r) -> int { throw not_loaded(); }, + .get_version_string = []() -> const char* { throw not_loaded(); }, + .multistream_decode = [](OpusMSDecoder* d, const unsigned char* data, int32_t datasize, int16_t* pcm, + int pcmlen, int fec) -> int { throw not_loaded(); }, + .multistream_decode_float = [](OpusMSDecoder* d, const unsigned char* data, int32_t datasize, float* pcm, + int pcmlen, int fec) -> int { throw not_loaded(); }, + .multistream_decoder_get_size = [](int streams, int coupled) -> int32_t { throw not_loaded(); }, + .multistream_decoder_init = [](OpusMSDecoder* d, int32_t fs, int ch, int st, int co, const unsigned char* map) + -> int { throw not_loaded(); }, + .multistream_encode = [](OpusMSEncoder* d, const int16_t* pcm, int pcmlen, unsigned char* data, + int32_t datasize) -> int { throw not_loaded(); }, + .multistream_encode_float = [](OpusMSEncoder* d, const float* pcm, int pcmlen, unsigned char* data, + int32_t datasize) -> int { throw not_loaded(); }, + .multistream_encoder_get_size = [](int streams, int coupled) -> int32_t { throw not_loaded(); }, + .multistream_encoder_init = [](OpusMSEncoder* d, int32_t fs, int ch, int st, int co, const unsigned char* map, + int app) -> int { throw not_loaded(); }, + .packet_get_bandwidth = [](const unsigned char* p) -> int { throw not_loaded(); }, + .packet_get_nb_channels = [](const unsigned char* p) -> int { throw not_loaded(); }, + .packet_get_nb_frames = [](const unsigned char* p, int32_t psize) -> int { throw not_loaded(); }, + .packet_get_samples_per_frame = [](const unsigned char* p, int32_t fs) -> int { throw not_loaded(); }, + .packet_parse = [](const unsigned char* data, int32_t dsize, unsigned char* toc, + const unsigned char* fdata[48], short fsize[48], int* poffset) -> int { throw not_loaded(); }, + .multistream_surround_encoder_get_size = [](int ch, int f) -> int32_t { throw not_loaded(); }, + .multistream_surround_encoder_init = [](OpusMSEncoder* e, int32_t fs, int ch, int f, int* st, int* co, + unsigned char* map, int app) -> int { throw not_loaded(); } +}; + +struct functions* opus_functions = &dummy_functions; + +std::map> lcbs; +mutex_class mut; + +template void CA(T& d, void* s) +{ + d = reinterpret_cast(s); +} + +void load_libopus(loaded_library& lib) +{ + static functions lfun; + functions tmp; + + CA(tmp.encoder_ctl, lib["opus_encoder_ctl"]); + CA(tmp.decoder_ctl, lib["opus_decoder_ctl"]); + CA(tmp.multistream_encoder_ctl, lib["opus_multistream_encoder_ctl"]); + CA(tmp.multistream_decoder_ctl, lib["opus_multistream_decoder_ctl"]); + CA(tmp.encoder_init, lib["opus_encoder_init"]); + CA(tmp.decoder_init, lib["opus_decoder_init"]); + CA(tmp.encoder_get_size, lib["opus_encoder_get_size"]); + CA(tmp.decoder_get_size, lib["opus_decoder_get_size"]); + CA(tmp.encode, lib["opus_encode"]); + CA(tmp.encode_float, lib["opus_encode_float"]); + CA(tmp.decode, lib["opus_decode"]); + CA(tmp.decode_float, lib["opus_decode_float"]); + CA(tmp.decoder_get_nb_samples, lib["opus_decoder_get_nb_samples"]); + CA(tmp.repacketizer_init, lib["opus_repacketizer_init"]); + CA(tmp.repacketizer_get_size, lib["opus_repacketizer_get_size"]); + CA(tmp.repacketizer_cat, lib["opus_repacketizer_cat"]); + CA(tmp.repacketizer_out_range, lib["opus_repacketizer_out_range"]); + CA(tmp.repacketizer_out, lib["opus_repacketizer_out"]); + CA(tmp.repacketizer_get_nb_frames, lib["opus_repacketizer_get_nb_frames"]); + CA(tmp.get_version_string, lib["opus_get_version_string"]); + CA(tmp.multistream_decode, lib["opus_multistream_decode"]); + CA(tmp.multistream_decode_float, lib["opus_multistream_decode_float"]); + CA(tmp.multistream_decoder_get_size, lib["opus_multistream_decoder_get_size"]); + CA(tmp.multistream_decoder_init, lib["opus_multistream_decoder_init"]); + CA(tmp.multistream_encode, lib["opus_multistream_encode"]); + CA(tmp.multistream_encode_float, lib["opus_multistream_encode_float"]); + CA(tmp.multistream_encoder_get_size, lib["opus_multistream_encoder_get_size"]); + CA(tmp.multistream_encoder_init, lib["opus_multistream_encoder_init"]); + CA(tmp.packet_get_bandwidth, lib["opus_packet_get_bandwidth"]); + CA(tmp.packet_get_nb_channels, lib["opus_packet_get_nb_channels"]); + CA(tmp.packet_get_nb_frames, lib["opus_packet_get_nb_frames"]); + CA(tmp.packet_get_samples_per_frame, lib["opus_packet_get_samples_per_frame"]); + CA(tmp.packet_parse, lib["opus_packet_parse"]); + try { + CA(tmp.multistream_surround_encoder_get_size, lib["opus_multistream_surround_encoder_get_size"]); + CA(tmp.multistream_surround_encoder_init, lib["opus_multistream_surround_encoder_init"]); + } catch(...) { + tmp.multistream_surround_encoder_get_size = dummy_functions.multistream_surround_encoder_get_size; + tmp.multistream_surround_encoder_init = dummy_functions.multistream_surround_encoder_init; + } + + lfun = tmp; + umutex_class h(mut); + opus_functions = &lfun; + for(auto i : lcbs) + (i.second)(); +} + +bool libopus_loaded() +{ + umutex_class h(mut); + return (opus_functions != &dummy_functions); +} + +size_t add_callback(std::function fun) +{ + umutex_class h(mut); + static size_t var = 0; + size_t hd = 0; + if(opus_functions != &dummy_functions) + fun(); + else + lcbs[hd = var++] = fun; + return hd; +} + +void cancel_callback(size_t handle) +{ + umutex_class h(mut); + lcbs.erase(handle); +} + +int opus_encoder_ctl(OpusEncoder* e, int req) +{ + return opus_functions->encoder_ctl(e, req); +} + +int opus_decoder_ctl(OpusDecoder* e, int req) +{ + return opus_functions->decoder_ctl(e, req); +} + +int opus_encoder_ctl(OpusEncoder* e, int req, int* arg) +{ + return opus_functions->encoder_ctl(e, req, arg); +} + +int opus_decoder_ctl(OpusDecoder* e, int req, int* arg) +{ + return opus_functions->decoder_ctl(e, req, arg); +} + +int opus_encoder_ctl(OpusEncoder* e, int req, int arg) +{ + return opus_functions->encoder_ctl(e, req, arg); +} + +int opus_decoder_ctl(OpusDecoder* e, int req, int arg) +{ + return opus_functions->decoder_ctl(e, req, arg); +} + +int opus_encoder_ctl(OpusEncoder* e, int req, uint32_t* arg) +{ + return opus_functions->encoder_ctl(e, req, arg); +} + +int opus_decoder_ctl(OpusDecoder* e, int req, uint32_t* arg) +{ + return opus_functions->decoder_ctl(e, req, arg); +} + +int opus_multistream_encoder_ctl(OpusMSEncoder* e, int req) +{ + return opus_functions->multistream_encoder_ctl(e, req); +} + +int opus_multistream_decoder_ctl(OpusMSDecoder* e, int req) +{ + return opus_functions->multistream_decoder_ctl(e, req); +} + +int opus_multistream_encoder_ctl(OpusMSEncoder* e, int req, int arg) +{ + return opus_functions->multistream_encoder_ctl(e, req, arg); +} + +int opus_multistream_decoder_ctl(OpusMSDecoder* e, int req, int arg) +{ + return opus_functions->multistream_decoder_ctl(e, req, arg); +} + +int opus_multistream_encoder_ctl(OpusMSEncoder* e, int req, int* arg) +{ + return opus_functions->multistream_encoder_ctl(e, req, arg); +} + +int opus_multistream_decoder_ctl(OpusMSDecoder* e, int req, int* arg) +{ + return opus_functions->multistream_decoder_ctl(e, req, arg); +} + +int opus_multistream_encoder_ctl(OpusMSEncoder* e, int req, int arg, OpusEncoder** arg2) +{ + return opus_functions->multistream_encoder_ctl(e, req, arg, arg2); +} + +int opus_multistream_decoder_ctl(OpusMSDecoder* e, int req, int arg, OpusDecoder** arg2) +{ + return opus_functions->multistream_decoder_ctl(e, req, arg, arg2); +} + +int opus_encoder_init(OpusEncoder* e, int32_t fs, int ch, int app) +{ + return opus_functions->encoder_init(e, fs, ch, app); +} + +int opus_decoder_init(OpusDecoder* e, int32_t fs, int ch) +{ + return opus_functions->decoder_init(e, fs, ch); +} + +int opus_encoder_get_size(int ch) +{ + return opus_functions->encoder_get_size(ch); +} + +int opus_decoder_get_size(int ch) +{ + return opus_functions->decoder_get_size(ch); +} + +int32_t opus_encode(OpusEncoder* e, const int16_t* pcm, int frames, unsigned char* data, int32_t maxout) +{ + return opus_functions->encode(e, pcm, frames, data, maxout); +} + +int32_t opus_encode_float(OpusEncoder* e, const float* pcm, int frames, unsigned char* data, int32_t maxout) +{ + return opus_functions->encode_float(e, pcm, frames, data, maxout); +} + +int32_t opus_decode(OpusDecoder* e, const unsigned char* data, int32_t datasize, int16_t* pcm, int frames, int fec) +{ + return opus_functions->decode(e, data, datasize, pcm, frames, fec); +} + +int32_t opus_decode_float(OpusDecoder* e, const unsigned char* data, int32_t datasize, float* pcm, int frames, + int fec) +{ + return opus_functions->decode_float(e, data, datasize, pcm, frames, fec); +} + +int opus_decoder_get_nb_samples(const OpusDecoder* dec, const unsigned char packet[], int32_t len) +{ + return opus_functions->decoder_get_nb_samples(dec, packet, len); +} + +OpusRepacketizer *opus_repacketizer_init(OpusRepacketizer* r) +{ + return opus_functions->repacketizer_init(r); +} + +int opus_repacketizer_get_size() +{ + return opus_functions->repacketizer_get_size(); +} + +int opus_repacketizer_cat(OpusRepacketizer* r, const unsigned char* data, int32_t len) +{ + return opus_functions->repacketizer_cat(r, data, len); +} + +int32_t opus_repacketizer_out_range(OpusRepacketizer* r, int begin, int end, unsigned char* data, int32_t maxlen) +{ + return opus_functions->repacketizer_out_range(r, begin, end, data, maxlen); +} + +int32_t opus_repacketizer_out(OpusRepacketizer* r, unsigned char* data, int32_t maxlen) +{ + return opus_functions->repacketizer_out(r, data, maxlen); +} + +int opus_repacketizer_get_nb_frames(OpusRepacketizer* r) +{ + return opus_functions->repacketizer_get_nb_frames(r); +} + +const char* opus_get_version_string() +{ + return opus_functions->get_version_string(); +} + +int opus_multistream_decode(OpusMSDecoder* d, const unsigned char* data, int32_t datasize, int16_t* pcm, int pcmlen, + int fec) +{ + return opus_functions->multistream_decode(d, data, datasize, pcm, pcmlen, fec); +} + +int opus_multistream_decode_float(OpusMSDecoder* d, const unsigned char* data, int32_t datasize, float* pcm, + int pcmlen, int fec) +{ + return opus_functions->multistream_decode_float(d, data, datasize, pcm, pcmlen, fec); +} + +int32_t opus_multistream_decoder_get_size(int streams, int coupled) +{ + return opus_functions->multistream_decoder_get_size(streams, coupled); +} + +int opus_multistream_decoder_init(OpusMSDecoder* d, int32_t fs, int ch, int st, int co, const unsigned char* map) +{ + return opus_functions->multistream_decoder_init(d, fs, ch, st, co, map); +} + +int opus_multistream_encode(OpusMSEncoder* d, const int16_t* pcm, int pcmlen, unsigned char* data, int32_t datasize) +{ + return opus_functions->multistream_encode(d, pcm, pcmlen, data, datasize); +} + +int opus_multistream_encode_float(OpusMSEncoder* d, const float* pcm, int pcmlen, unsigned char* data, + int32_t datasize) +{ + return opus_functions->multistream_encode_float(d, pcm, pcmlen, data, datasize); +} + +int32_t opus_multistream_encoder_get_size(int streams, int coupled) +{ + return opus_functions->multistream_encoder_get_size(streams, coupled); +} + +int opus_multistream_encoder_init(OpusMSEncoder* d, int32_t fs, int ch, int st, int co, const unsigned char* map, + int app) +{ + return opus_functions->multistream_encoder_init(d, fs, ch, st, co, map, app); +} + +int opus_packet_get_bandwidth(const unsigned char* p) +{ + return opus_functions->packet_get_bandwidth(p); +} + +int opus_packet_get_nb_channels(const unsigned char* p) +{ + return opus_functions->packet_get_nb_channels(p); +} + +int opus_packet_get_nb_frames(const unsigned char* p, int32_t psize) +{ + return opus_functions->packet_get_nb_frames(p, psize); +} + +int opus_packet_get_samples_per_frame(const unsigned char* p, int32_t fs) +{ + return opus_functions->packet_get_samples_per_frame(p, fs); +} + +int opus_packet_parse(const unsigned char* data, int32_t dsize, unsigned char* toc, const unsigned char* fdata[48], + short fsize[48], int* poffset) +{ + return opus_functions->packet_parse(data, dsize, toc, fdata, fsize, poffset); +} + +bool opus_surround_supported() +{ + return (opus_functions->multistream_surround_encoder_get_size != + dummy_functions.multistream_surround_encoder_get_size); +} + +int32_t opus_multistream_surround_encoder_get_size(int ch, int f) +{ + return opus_functions->multistream_surround_encoder_get_size(ch, f); +} + +int opus_multistream_surround_encoder_init(OpusMSEncoder* e, int32_t fs, int ch, int f, int* st, int* co, + unsigned char* map, int app) +{ + return opus_functions->multistream_surround_encoder_init(e, fs, ch, f, st, co, map, app); +} +#else +void load_libopus(loaded_library& lib) +{ +} + +bool libopus_loaded() +{ + return true; +} + +size_t add_callback(std::function fun) +{ + fun(); + return 0; +} + +void cancel_callback(size_t handle) +{ +} + +#endif samplerate samplerate::r8k(8000); samplerate samplerate::r12k(12000); samplerate samplerate::r16k(16000); @@ -88,6 +630,9 @@ unimplemented::unimplemented() invalid_state::invalid_state() : std::runtime_error("Invalid state") {} +not_loaded::not_loaded() + : std::runtime_error("Library not loaded") {} + const unsigned f1_streams[] = {0, 1, 1, 2, 2, 3, 4, 4, 5}; const unsigned f1_coupled[] = {0, 0, 1, 1, 2, 2, 2, 3, 3}; const char* chanmap[] = {"", "A", "AB", "ACB", "ABCD", "ACDEB", "ACDEBF", "ACBFDEG", "ACDEFGBH"}; @@ -513,27 +1058,27 @@ void set_control_int::operator()(multistream_decoder& d) const int32_t get_control_int::operator()(encoder& e) const { - return generic_ctl(e, ctl); + return generic_ctl(e, ctl); } int32_t get_control_int::operator()(decoder& d) const { - return generic_ctl(d, ctl); + return generic_ctl(d, ctl); } int32_t get_control_int::operator()(multistream_encoder& e) const { - return generic_ctl(e, ctl); + return generic_ctl(e, ctl); } int32_t get_control_int::operator()(surround_encoder& e) const { - return generic_ctl(e, ctl); + return generic_ctl(e, ctl); } int32_t get_control_int::operator()(multistream_decoder& d) const { - return generic_ctl(d, ctl); + return generic_ctl(d, ctl); } void force_instantiate() @@ -842,7 +1387,7 @@ multistream_encoder::multistream_encoder(samplerate rate, unsigned _channels, un memory = _memory ? alignptr(_memory, alignof(encoder)) : new char[size(streams, coupled_streams)]; try { offset = _streams * sizeof(encoder); - throwex(opus_multistream_encoder_init(ME(*this), rate, channels, _streams, coupled_streams, mapping, + throwex(opus_multistream_encoder_init(ME(*this), rate, _channels, _streams, coupled_streams, mapping, app)); init_structures(_channels, _streams, coupled_streams); } catch(...) { @@ -883,7 +1428,7 @@ void multistream_encoder::init_structures(unsigned _channels, unsigned _streams, opussize = opus_multistream_encoder_get_size(streams, coupled); for(int32_t i = 0; i < streams; i++) { OpusEncoder* e; - opus_multistream_encoder_ctl(ME(*this), OPUS_MULTISTREAM_GET_ENCODER_STATE(i, &e)); + opus_multistream_encoder_ctl(ME(*this), OPUS_MULTISTREAM_GET_ENCODER_STATE_REQUEST, (int)i, &e); new(substream(i)) encoder(e, i < coupled); } } @@ -923,14 +1468,14 @@ size_t surround_encoder::size(unsigned channels, unsigned family) { //Be conservative with memory, as stream count is not known. #ifdef OPUS_SUPPORTS_SURROUND + if(SURROUND_SUPPORTED) return alignof(encoder) + channels * sizeof(encoder) + opus_multistream_surround_encoder_get_size(channels, family); -#else +#endif int streams, coupled; lookup_params(channels, family, streams, coupled); //We use channels and not streams here to keep compatiblity on fallback. return alignof(encoder) + channels * sizeof(encoder) + opus_multistream_encoder_get_size(streams, coupled); -#endif } surround_encoder::~surround_encoder() @@ -949,13 +1494,16 @@ surround_encoder::surround_encoder(samplerate rate, unsigned _channels, unsigned unsigned char rmapping[256]; offset = _channels * sizeof(encoder); //Conservative. #ifdef OPUS_SUPPORTS_SURROUND + if(SURROUND_SUPPORTED) throwex(opus_multistream_surround_encoder_init(ME(*this), rate, _channels, _family, &rstreams, &rcoupled, rmapping, app)); -#else + else +#endif + { lookup_params(_channels, _family, rstreams, rcoupled); generate_mapping(_channels, _family, rmapping); throwex(opus_multistream_encoder_init(ME(*this), rate, channels, rstreams, rcoupled, rmapping, app)); -#endif + } init_structures(_channels, rstreams, rcoupled, _family); format.channels = channels; format.family = family; @@ -997,14 +1545,15 @@ void surround_encoder::init_structures(unsigned _channels, unsigned _streams, un streams = _streams; coupled = _coupled; family = _family; -#if OPUS_SUPPORTS_SURROUND +#ifdef OPUS_SUPPORTS_SURROUND + if(SURROUND_SUPPORTED) opussize = opus_multistream_surround_encoder_get_size(_channels, family); -#else - opussize = opus_multistream_encoder_get_size(streams, coupled); + else #endif + opussize = opus_multistream_encoder_get_size(streams, coupled); for(int32_t i = 0; i < streams; i++) { OpusEncoder* e; - opus_multistream_encoder_ctl(ME(*this), OPUS_MULTISTREAM_GET_ENCODER_STATE(i, &e)); + opus_multistream_encoder_ctl(ME(*this), OPUS_MULTISTREAM_GET_ENCODER_STATE_REQUEST, (int)i, &e); new(substream(i)) encoder(e, i < coupled); } } @@ -1052,7 +1601,9 @@ multistream_decoder::multistream_decoder(samplerate rate, unsigned _channels, un user = (_memory != NULL); memory = _memory ? alignptr(_memory, alignof(decoder)) : new char[size(streams, coupled_streams)]; try { - throwex(opus_multistream_decoder_init(MD(*this), rate, channels, streams, coupled_streams, mapping)); + offset = _streams * sizeof(encoder); + throwex(opus_multistream_decoder_init(MD(*this), rate, _channels, _streams, coupled_streams, + mapping)); init_structures(_channels, _streams, coupled_streams); } catch(...) { if(!user) @@ -1095,7 +1646,7 @@ void multistream_decoder::init_structures(unsigned _channels, unsigned _streams, opussize = opus_multistream_decoder_get_size(streams, coupled); for(int32_t i = 0; i < (size_t)streams; i++) { OpusDecoder* d; - opus_multistream_decoder_ctl(MD(*this), OPUS_MULTISTREAM_GET_DECODER_STATE(i, &d)); + opus_multistream_decoder_ctl(MD(*this), OPUS_MULTISTREAM_GET_DECODER_STATE_REQUEST, (int)i, &d); new(substream(i)) decoder(d, i < coupled); } } @@ -1175,4 +1726,3 @@ std::string version() } } -#endif diff --git a/src/platform/wxwidgets/editor-voicesub.cpp b/src/platform/wxwidgets/editor-voicesub.cpp index c04e893e..d879a713 100644 --- a/src/platform/wxwidgets/editor-voicesub.cpp +++ b/src/platform/wxwidgets/editor-voicesub.cpp @@ -1,4 +1,3 @@ -#ifdef WITH_OPUS_CODEC #include "core/inthread.hpp" #include "core/project.hpp" #include @@ -419,4 +418,3 @@ void show_wxeditor_voicesub(wxWindow* parent) v->Show(); voicesub_open = true; } -#endif diff --git a/src/platform/wxwidgets/mainwindow.cpp b/src/platform/wxwidgets/mainwindow.cpp index 67d7ca42..0feef37a 100644 --- a/src/platform/wxwidgets/mainwindow.cpp +++ b/src/platform/wxwidgets/mainwindow.cpp @@ -780,9 +780,7 @@ wxwin_mainwindow::wxwin_mainwindow() menu_check(wxID_READONLY_MODE, is_readonly_mode()); menu_entry(wxID_EDIT_AUTHORS, wxT("Edit game name && authors...")); menu_entry(wxID_EDIT_SUBTITLES, wxT("Edit subtitles...")); -#ifdef WITH_OPUS_CODEC menu_entry(wxID_EDIT_VSUBTITLES, wxT("Edit commantary track...")); -#endif menu_separator(); menu_entry(wxID_REWIND_MOVIE, wxT("Rewind to start")); @@ -1078,11 +1076,9 @@ void wxwin_mainwindow::handle_menu_click_cancelable(wxCommandEvent& e) case wxID_EDIT_SUBTITLES: wxeditor_subtitles_display(this); return; -#ifdef WITH_OPUS_CODEC case wxID_EDIT_VSUBTITLES: show_wxeditor_voicesub(this); return; -#endif case wxID_EDIT_MEMORYWATCH: wxeditor_memorywatch_display(this); return; @@ -1236,8 +1232,8 @@ void wxwin_mainwindow::handle_menu_click_cancelable(wxCommandEvent& e) break; case wxID_LOAD_LIBRARY: { std::string name = std::string("load ") + loaded_library::call_library(); - new loaded_library(pick_file(this, name, project_otherpath(), false, - loaded_library::call_library_ext())); + with_loaded_library(new loaded_library(pick_file(this, name, project_otherpath(), false, + loaded_library::call_library_ext()))); handle_post_loadlibrary(); break; } diff --git a/src/util/lsnes-dumpavi.cpp b/src/util/lsnes-dumpavi.cpp index 8466e764..9a15d19d 100644 --- a/src/util/lsnes-dumpavi.cpp +++ b/src/util/lsnes-dumpavi.cpp @@ -165,7 +165,7 @@ namespace } } else if(a.length() >= 12 && a.substr(0, 15) == "--load-library=") try { - new loaded_library(a.substr(15)); + with_loaded_library(new loaded_library(a.substr(15))); handle_post_loadlibrary(); } catch(std::runtime_error& e) { std::cerr << "Can't load '" << a.substr(15) << "': " << e.what() << std::endl;