From 786546653a062c8270e608524de1c0a7e1fc1e6e Mon Sep 17 00:00:00 2001 From: jacqueline Date: Tue, 13 Feb 2024 12:05:12 +1100 Subject: [PATCH 1/9] include repeat, replay, and shuffle in persisted queue info --- src/audio/include/track_queue.hpp | 41 +++++++- src/audio/track_queue.cpp | 150 +++++++++++++++++++++--------- 2 files changed, 146 insertions(+), 45 deletions(-) diff --git a/src/audio/include/track_queue.hpp b/src/audio/include/track_queue.hpp index fd6061a7..e4fd7881 100644 --- a/src/audio/include/track_queue.hpp +++ b/src/audio/include/track_queue.hpp @@ -12,6 +12,7 @@ #include #include +#include "cppbor_parse.h" #include "database.hpp" #include "tasks.hpp" #include "track.hpp" @@ -24,6 +25,7 @@ namespace audio { */ class RandomIterator { public: + RandomIterator(); RandomIterator(size_t size); auto current() const -> size_t; @@ -35,6 +37,10 @@ class RandomIterator { auto resize(size_t) -> void; auto replay(bool) -> void; + auto seed() -> size_t& { return seed_; } + auto pos() -> size_t& { return pos_; } + auto size() -> size_t& { return size_; } + private: size_t seed_; size_t pos_; @@ -85,12 +91,11 @@ class TrackQueue { auto next() -> void; auto previous() -> void; - /* + /* * Called when the current track finishes */ auto finish() -> void; - auto skipTo(database::TrackId) -> void; /* @@ -125,6 +130,38 @@ class TrackQueue { std::optional shuffle_; bool repeat_; bool replay_; + + class QueueParseClient : public cppbor::ParseClient { + public: + QueueParseClient(TrackQueue& queue); + + ParseClient* item(std::unique_ptr& item, + const uint8_t* hdrBegin, + const uint8_t* valueBegin, + const uint8_t* end) override; + + ParseClient* itemEnd(std::unique_ptr& item, + const uint8_t* hdrBegin, + const uint8_t* valueBegin, + const uint8_t* end) override; + + void error(const uint8_t* position, + const std::string& errorMessage) override {} + + private: + TrackQueue& queue_; + + enum class State { + kInit, + kRoot, + kMetadata, + kShuffle, + kTracks, + kFinished, + }; + State state_; + size_t i_; + }; }; } // namespace audio diff --git a/src/audio/track_queue.cpp b/src/audio/track_queue.cpp index c4c101f6..534da10c 100644 --- a/src/audio/track_queue.cpp +++ b/src/audio/track_queue.cpp @@ -33,6 +33,9 @@ namespace audio { [[maybe_unused]] static constexpr char kTag[] = "tracks"; +RandomIterator::RandomIterator() + : seed_(0), pos_(0), size_(0), replay_(false) {} + RandomIterator::RandomIterator(size_t size) : seed_(), pos_(0), size_(size), replay_(false) { esp_fill_random(&seed_, sizeof(seed_)); @@ -338,66 +341,127 @@ auto TrackQueue::serialise() -> std::string { for (database::TrackId track : tracks_) { tracks.add(cppbor::Uint(track)); } - // FIXME: this should include the RandomIterator's seed as well. - cppbor::Array encoded{ - cppbor::Uint{pos_}, - std::move(tracks), - }; + cppbor::Map encoded; + encoded.add(cppbor::Uint{0}, cppbor::Array{ + cppbor::Uint{pos_}, + cppbor::Bool{repeat_}, + cppbor::Bool{replay_}, + }); + if (shuffle_) { + encoded.add(cppbor::Uint{1}, cppbor::Array{ + cppbor::Uint{shuffle_->size()}, + cppbor::Uint{shuffle_->seed()}, + cppbor::Uint{shuffle_->pos()}, + }); + } + encoded.add(cppbor::Uint{2}, std::move(tracks)); return encoded.toString(); } -class QueueParseClient : public cppbor::ParseClient { - public: - QueueParseClient(size_t& pos, std::pmr::vector& tracks) - : pos_(pos), - tracks_(tracks), - in_root_array_(false), - in_track_list_(false) {} - - ParseClient* item(std::unique_ptr& item, - const uint8_t* hdrBegin, - const uint8_t* valueBegin, - const uint8_t* end) override { +TrackQueue::QueueParseClient::QueueParseClient(TrackQueue& queue) + : queue_(queue), state_(State::kInit), i_(0) {} + +cppbor::ParseClient* TrackQueue::QueueParseClient::item( + std::unique_ptr& item, + const uint8_t* hdrBegin, + const uint8_t* valueBegin, + const uint8_t* end) { + if (state_ == State::kInit) { + if (item->type() == cppbor::MAP) { + state_ = State::kRoot; + } + } else if (state_ == State::kRoot) { + if (item->type() == cppbor::UINT) { + switch (item->asUint()->unsignedValue()) { + case 0: + state_ = State::kMetadata; + break; + case 1: + state_ = State::kShuffle; + break; + case 2: + state_ = State::kTracks; + break; + default: + state_ = State::kFinished; + } + } + } else if (state_ == State::kMetadata) { if (item->type() == cppbor::ARRAY) { - if (!in_root_array_) { - in_root_array_ = true; - } else { - in_track_list_ = true; + i_ = 0; + } else if (item->type() == cppbor::UINT) { + queue_.pos_ = item->asUint()->unsignedValue(); + } else if (item->type() == cppbor::SIMPLE) { + bool val = item->asBool()->value(); + if (i_ == 0) { + queue_.repeat_ = val; + } else if (i_ == 1) { + queue_.replay_ = val; } + i_++; + } + } else if (state_ == State::kShuffle) { + if (item->type() == cppbor::ARRAY) { + i_ = 0; + queue_.shuffle_.emplace(); + queue_.shuffle_->replay(queue_.replay_); } else if (item->type() == cppbor::UINT) { auto val = item->asUint()->unsignedValue(); - if (in_track_list_) { - tracks_.push_back(val); - } else { - pos_ = static_cast(val); + switch (i_) { + case 0: + queue_.shuffle_->size() = val; + break; + case 1: + queue_.shuffle_->seed() = val; + break; + case 2: + queue_.shuffle_->pos() = val; + break; + default: + break; } + i_++; } - return this; + } else if (state_ == State::kTracks) { + if (item->type() == cppbor::UINT) { + queue_.tracks_.push_back(item->asUint()->unsignedValue()); + } + } else if (state_ == State::kFinished) { } + return this; +} - ParseClient* itemEnd(std::unique_ptr& item, - const uint8_t* hdrBegin, - const uint8_t* valueBegin, - const uint8_t* end) override { - return this; +cppbor::ParseClient* TrackQueue::QueueParseClient::itemEnd( + std::unique_ptr& item, + const uint8_t* hdrBegin, + const uint8_t* valueBegin, + const uint8_t* end) { + if (state_ == State::kInit) { + state_ = State::kFinished; + } else if (state_ == State::kRoot) { + state_ = State::kFinished; + } else if (state_ == State::kMetadata) { + if (item->type() == cppbor::ARRAY) { + state_ = State::kRoot; + } + } else if (state_ == State::kShuffle) { + if (item->type() == cppbor::ARRAY) { + state_ = State::kRoot; + } + } else if (state_ == State::kTracks) { + if (item->type() == cppbor::ARRAY) { + state_ = State::kRoot; + } + } else if (state_ == State::kFinished) { } - - void error(const uint8_t* position, - const std::string& errorMessage) override {} - - private: - size_t& pos_; - std::pmr::vector& tracks_; - - bool in_root_array_; - bool in_track_list_; -}; + return this; +} auto TrackQueue::deserialise(const std::string& s) -> void { if (s.empty()) { return; } - QueueParseClient client{pos_, tracks_}; + QueueParseClient client{*this}; const uint8_t* data = reinterpret_cast(s.data()); cppbor::parse(data, data + s.size(), &client); notifyChanged(true); From b31bc07555fdd862181d8d6ed551163cea89bc62 Mon Sep 17 00:00:00 2001 From: jacqueline Date: Tue, 13 Feb 2024 16:39:56 +1100 Subject: [PATCH 2/9] fix (improve?) libtremor strangeness something fucky --- lib/tremor/CMakeLists.txt | 2 ++ src/codecs/include/vorbis.hpp | 2 +- src/codecs/vorbis.cpp | 25 +++++++++++++++---------- 3 files changed, 18 insertions(+), 11 deletions(-) diff --git a/lib/tremor/CMakeLists.txt b/lib/tremor/CMakeLists.txt index 296dd4cc..1000fe5f 100644 --- a/lib/tremor/CMakeLists.txt +++ b/lib/tremor/CMakeLists.txt @@ -6,3 +6,5 @@ idf_component_register( res012.c sharedbook.c synthesis.c vorbisfile.c window.c INCLUDE_DIRS "." REQUIRES "ogg") + +target_compile_options("${COMPONENT_LIB}" PRIVATE -Og) diff --git a/src/codecs/include/vorbis.hpp b/src/codecs/include/vorbis.hpp index 2f93c37e..673b67a0 100644 --- a/src/codecs/include/vorbis.hpp +++ b/src/codecs/include/vorbis.hpp @@ -41,7 +41,7 @@ class TremorVorbisDecoder : public ICodec { private: std::shared_ptr input_; - OggVorbis_File vorbis_; + std::unique_ptr vorbis_; }; } // namespace codecs diff --git a/src/codecs/vorbis.cpp b/src/codecs/vorbis.cpp index 3b3798cb..c373ebf5 100644 --- a/src/codecs/vorbis.cpp +++ b/src/codecs/vorbis.cpp @@ -78,17 +78,21 @@ static const ov_callbacks kCallbacks{ .tell_func = tell_cb, // Not seekable }; -TremorVorbisDecoder::TremorVorbisDecoder() : input_(), vorbis_() {} +TremorVorbisDecoder::TremorVorbisDecoder() + : input_(), + vorbis_(reinterpret_cast( + heap_caps_malloc(sizeof(OggVorbis_File), + MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT))) {} TremorVorbisDecoder::~TremorVorbisDecoder() { - ov_clear(&vorbis_); + ov_clear(vorbis_.get()); } auto TremorVorbisDecoder::OpenStream(std::shared_ptr input) -> cpp::result { - int res = ov_open_callbacks(input.get(), &vorbis_, NULL, 0, kCallbacks); + int res = ov_open_callbacks(input.get(), vorbis_.get(), NULL, 0, kCallbacks); if (res < 0) { - std::pmr::string err; + std::string err; switch (res) { case OV_EREAD: err = "OV_EREAD"; @@ -112,13 +116,13 @@ auto TremorVorbisDecoder::OpenStream(std::shared_ptr input) return cpp::fail(Error::kMalformedData); } - vorbis_info* info = ov_info(&vorbis_, -1); + vorbis_info* info = ov_info(vorbis_.get(), -1); if (info == NULL) { ESP_LOGE(kTag, "failed to get stream info"); return cpp::fail(Error::kMalformedData); } - auto l = ov_pcm_total(&vorbis_, -1); + auto l = ov_pcm_total(vorbis_.get(), -1); std::optional length; if (l > 0) { length = l * info->channels; @@ -133,9 +137,10 @@ auto TremorVorbisDecoder::OpenStream(std::shared_ptr input) auto TremorVorbisDecoder::DecodeTo(cpp::span output) -> cpp::result { - int bitstream = 0; - long bytes_written = ov_read(&vorbis_, reinterpret_cast(output.data()), - output.size_bytes(), &bitstream); + int unused = 0; + long bytes_written = + ov_read(vorbis_.get(), reinterpret_cast(output.data()), + ((output.size() - 1) * sizeof(sample::Sample)), &unused); if (bytes_written == OV_HOLE) { ESP_LOGE(kTag, "got OV_HOLE"); return cpp::fail(Error::kMalformedData); @@ -152,7 +157,7 @@ auto TremorVorbisDecoder::DecodeTo(cpp::span output) } auto TremorVorbisDecoder::SeekTo(size_t target) -> cpp::result { - if (ov_pcm_seek(&vorbis_, target) != 0) { + if (ov_pcm_seek(vorbis_.get(), target) != 0) { return cpp::fail(Error::kInternalError); } return {}; From 7ec0ff2589ffd5774e78f9e6b436ea55be45deb1 Mon Sep 17 00:00:00 2001 From: jacqueline Date: Wed, 14 Feb 2024 12:21:33 +1100 Subject: [PATCH 3/9] Switch to the lowmem tremor branch in addition to using slightly less memory, this branch also doesn't seem to have the same issues with `-O2` builds that the main branch has. --- lib/tremor/CMakeLists.txt | 10 +- lib/tremor/Makefile.am | 31 +- lib/tremor/TODO | 2 + lib/tremor/Version_script.in | 1 - lib/tremor/asm_arm.h | 58 +- lib/tremor/autogen.sh | 89 +- lib/tremor/backends.h | 131 - lib/tremor/bitwise.c | 675 +++++ lib/tremor/block.c | 497 ---- lib/tremor/block.h | 24 - lib/tremor/codebook.c | 922 +++++-- lib/tremor/codebook.h | 106 +- lib/tremor/codec_internal.h | 191 +- lib/tremor/config_types.h | 13 +- lib/tremor/configure.in | 37 +- lib/tremor/dsp.c | 298 +++ lib/tremor/floor0.c | 346 ++- lib/tremor/floor1.c | 392 +-- lib/tremor/floor_lookup.c | 92 + lib/tremor/framing.c | 1117 ++++++++ lib/tremor/info.c | 271 +- lib/tremor/iseeking_example.c | 265 -- lib/tremor/ivorbiscodec.h | 112 +- lib/tremor/ivorbisfile.h | 103 +- lib/tremor/ivorbisfile_example.c | 13 +- lib/tremor/lsp_lookup.h | 36 +- lib/tremor/mapping0.c | 277 +- lib/tremor/mdct.c | 704 +++-- lib/tremor/mdct.h | 19 +- lib/tremor/mdct_lookup.h | 10 +- lib/tremor/misc.c | 208 ++ lib/tremor/misc.h | 148 +- lib/tremor/os.h | 8 +- lib/tremor/os_types.h | 42 + lib/tremor/registry.c | 50 - lib/tremor/registry.h | 40 - lib/tremor/res012.c | 467 ++-- lib/tremor/sharedbook.c | 447 ---- lib/tremor/synthesis.c | 131 - lib/tremor/tremor_ogg.h | 206 ++ lib/tremor/vorbisfile.c | 2279 +++++++---------- lib/tremor/vorbisidec.pc.in | 4 +- lib/tremor/win32/VS2005/libogg.vsprops | 19 - .../win32/VS2005/libtremor/libtremor.vcproj | 865 ------- lib/tremor/win32/VS2008/libogg.vsprops | 19 - .../win32/VS2008/libtremor/libtremor.vcproj | 865 ------- lib/tremor/window.c | 83 - lib/tremor/window.h | 27 - lib/tremor/window_lookup.h | 25 +- src/codecs/include/vorbis.hpp | 4 +- src/codecs/vorbis.cpp | 25 +- 51 files changed, 5684 insertions(+), 7120 deletions(-) create mode 100644 lib/tremor/TODO delete mode 100644 lib/tremor/backends.h create mode 100644 lib/tremor/bitwise.c delete mode 100644 lib/tremor/block.c delete mode 100644 lib/tremor/block.h create mode 100644 lib/tremor/dsp.c create mode 100644 lib/tremor/floor_lookup.c create mode 100644 lib/tremor/framing.c delete mode 100644 lib/tremor/iseeking_example.c create mode 100644 lib/tremor/misc.c create mode 100644 lib/tremor/os_types.h delete mode 100644 lib/tremor/registry.c delete mode 100644 lib/tremor/registry.h delete mode 100644 lib/tremor/sharedbook.c delete mode 100644 lib/tremor/synthesis.c create mode 100644 lib/tremor/tremor_ogg.h delete mode 100644 lib/tremor/win32/VS2005/libogg.vsprops delete mode 100644 lib/tremor/win32/VS2005/libtremor/libtremor.vcproj delete mode 100644 lib/tremor/win32/VS2008/libogg.vsprops delete mode 100644 lib/tremor/win32/VS2008/libtremor/libtremor.vcproj delete mode 100644 lib/tremor/window.c delete mode 100644 lib/tremor/window.h diff --git a/lib/tremor/CMakeLists.txt b/lib/tremor/CMakeLists.txt index 1000fe5f..e44f9084 100644 --- a/lib/tremor/CMakeLists.txt +++ b/lib/tremor/CMakeLists.txt @@ -2,9 +2,7 @@ # # SPDX-License-Identifier: GPL-3.0-only idf_component_register( - SRCS block.c codebook.c floor0.c floor1.c info.c mapping0.c mdct.c registry.c - res012.c sharedbook.c synthesis.c vorbisfile.c window.c - INCLUDE_DIRS "." - REQUIRES "ogg") - -target_compile_options("${COMPONENT_LIB}" PRIVATE -Og) + SRCS bitwise.c codebook.c dsp.c floor0.c floor1.c floor_lookup.c framing.c + info.c mapping0.c mdct.c misc.c res012.c vorbisfile.c + INCLUDE_DIRS ".") +target_compile_options("${COMPONENT_LIB}" PRIVATE -Wno-error=misleading-indentation -Wno-error=maybe-uninitialized -Wno-error=char-subscripts -Wno-error=unused-label) diff --git a/lib/tremor/Makefile.am b/lib/tremor/Makefile.am index 0a4bb2c3..1d18b1a7 100644 --- a/lib/tremor/Makefile.am +++ b/lib/tremor/Makefile.am @@ -1,50 +1,43 @@ AUTOMAKE_OPTIONS = foreign -INCLUDES = -I./ @OGG_CFLAGS@ +INCLUDES = -I./ pkgconfigdir = $(libdir)/pkgconfig pkgconfig_DATA = vorbisidec.pc lib_LTLIBRARIES = libvorbisidec.la -libvorbisidec_la_SOURCES = mdct.c block.c window.c \ - synthesis.c info.c \ +libvorbisidec_la_SOURCES = mdct.c dsp.c info.c misc.c \ floor1.c floor0.c vorbisfile.c \ - res012.c mapping0.c registry.c codebook.c \ - sharedbook.c \ + res012.c mapping0.c codebook.c \ + framing.c bitwise.c \ codebook.h misc.h mdct_lookup.h\ - os.h mdct.h block.h ivorbisfile.h lsp_lookup.h\ - registry.h window.h window_lookup.h\ - codec_internal.h backends.h \ + os.h mdct.h ivorbisfile.h lsp_lookup.h\ + window_lookup.h floor_lookup.c \ + codec_internal.h ogg.h \ asm_arm.h ivorbiscodec.h libvorbisidec_la_LDFLAGS = -version-info @V_LIB_CURRENT@:@V_LIB_REVISION@:@V_LIB_AGE@ -libvorbisidec_la_LIBADD = @OGG_LIBS@ -EXTRA_PROGRAMS = ivorbisfile_example iseeking_example +EXTRA_PROGRAMS = ivorbisfile_example CLEANFILES = $(EXTRA_PROGRAMS) $(lib_LTLIBRARIES) ivorbisfile_example_SOURCES = ivorbisfile_example.c ivorbisfile_example_LDFLAGS = -static -ivorbisfile_example_LDADD = libvorbisidec.la @OGG_LIBS@ - -iseeking_example_SOURCES = iseeking_example.c -iseeking_example_LDFLAGS = -static -iseeking_example_LDADD = libvorbisidec.la @OGG_LIBS@ +ivorbisfile_example_LDADD = libvorbisidec.la includedir = $(prefix)/include/tremor -include_HEADERS = ivorbiscodec.h ivorbisfile.h config_types.h +include_HEADERS = ivorbiscodec.h ivorbisfile.h ogg.h os_types.h config_types.h EXTRA_DIST = vorbisidec.pc.in \ - $(srcdir)/doc/*.html $(srcdir)/win32/VS*/libtremor/*.vcproj + $(srcdir)/doc/*.html example: -ln -fs . vorbis $(MAKE) ivorbisfile_example - $(MAKE) iseeking_example debug: - $(MAKE) all CFLAGS="@DEBUG@" + $(MAKE) all CFLAGS="@DEBUG@" profile: $(MAKE) all CFLAGS="@PROFILE@" diff --git a/lib/tremor/TODO b/lib/tremor/TODO new file mode 100644 index 00000000..0e542a37 --- /dev/null +++ b/lib/tremor/TODO @@ -0,0 +1,2 @@ +Add explicit 64 bit integer support rather than relying on compiler +Roll in optional use of bounded heap memory manager diff --git a/lib/tremor/Version_script.in b/lib/tremor/Version_script.in index cf05203c..85d76539 100644 --- a/lib/tremor/Version_script.in +++ b/lib/tremor/Version_script.in @@ -51,7 +51,6 @@ vorbis_synthesis_init; vorbis_synthesis_restart; vorbis_synthesis; - vorbis_synthesis_trackonly; vorbis_synthesis_blockin; vorbis_synthesis_pcmout; vorbis_synthesis_read; diff --git a/lib/tremor/asm_arm.h b/lib/tremor/asm_arm.h index c3bda005..ac2b6899 100644 --- a/lib/tremor/asm_arm.h +++ b/lib/tremor/asm_arm.h @@ -1,12 +1,12 @@ /******************************************************************** * * - * THIS FILE IS PART OF THE OggVorbis 'TREMOR' CODEC SOURCE CODE. * + * THIS FILE IS PART OF THE TremorOggVorbis 'TREMOR' CODEC SOURCE CODE. * * * * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS * * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE * * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. * * * - * THE OggVorbis 'TREMOR' SOURCE CODE IS (C) COPYRIGHT 1994-2002 * + * THE TremorOggVorbis 'TREMOR' SOURCE CODE IS (C) COPYRIGHT 1994-2002 * * BY THE Xiph.Org FOUNDATION http://www.xiph.org/ * * * ******************************************************************** @@ -20,7 +20,7 @@ #if !defined(_V_WIDE_MATH) && !defined(_LOW_ACCURACY_) #define _V_WIDE_MATH -static inline ogg_int32_t MULT32(ogg_int32_t x, ogg_int32_t y) { +static inline tremor_ogg_int32_t MULT32(tremor_ogg_int32_t x, tremor_ogg_int32_t y) { int lo,hi; asm volatile("smull\t%0, %1, %2, %3" : "=&r"(lo),"=&r"(hi) @@ -29,11 +29,11 @@ static inline ogg_int32_t MULT32(ogg_int32_t x, ogg_int32_t y) { return(hi); } -static inline ogg_int32_t MULT31(ogg_int32_t x, ogg_int32_t y) { +static inline tremor_ogg_int32_t MULT31(tremor_ogg_int32_t x, tremor_ogg_int32_t y) { return MULT32(x,y)<<1; } -static inline ogg_int32_t MULT31_SHIFT15(ogg_int32_t x, ogg_int32_t y) { +static inline tremor_ogg_int32_t MULT31_SHIFT15(tremor_ogg_int32_t x, tremor_ogg_int32_t y) { int lo,hi; asm volatile("smull %0, %1, %2, %3\n\t" "movs %0, %0, lsr #15\n\t" @@ -46,9 +46,9 @@ static inline ogg_int32_t MULT31_SHIFT15(ogg_int32_t x, ogg_int32_t y) { #define MB() asm volatile ("" : : : "memory") -static inline void XPROD32(ogg_int32_t a, ogg_int32_t b, - ogg_int32_t t, ogg_int32_t v, - ogg_int32_t *x, ogg_int32_t *y) +static inline void XPROD32(tremor_ogg_int32_t a, tremor_ogg_int32_t b, + tremor_ogg_int32_t t, tremor_ogg_int32_t v, + tremor_ogg_int32_t *x, tremor_ogg_int32_t *y) { int x1, y1, l; asm( "smull %0, %1, %4, %6\n\t" @@ -64,9 +64,9 @@ static inline void XPROD32(ogg_int32_t a, ogg_int32_t b, *y = y1; } -static inline void XPROD31(ogg_int32_t a, ogg_int32_t b, - ogg_int32_t t, ogg_int32_t v, - ogg_int32_t *x, ogg_int32_t *y) +static inline void XPROD31(tremor_ogg_int32_t a, tremor_ogg_int32_t b, + tremor_ogg_int32_t t, tremor_ogg_int32_t v, + tremor_ogg_int32_t *x, tremor_ogg_int32_t *y) { int x1, y1, l; asm( "smull %0, %1, %4, %6\n\t" @@ -82,9 +82,9 @@ static inline void XPROD31(ogg_int32_t a, ogg_int32_t b, *y = y1 << 1; } -static inline void XNPROD31(ogg_int32_t a, ogg_int32_t b, - ogg_int32_t t, ogg_int32_t v, - ogg_int32_t *x, ogg_int32_t *y) +static inline void XNPROD31(tremor_ogg_int32_t a, tremor_ogg_int32_t b, + tremor_ogg_int32_t t, tremor_ogg_int32_t v, + tremor_ogg_int32_t *x, tremor_ogg_int32_t *y) { int x1, y1, l; asm( "rsb %2, %4, #0\n\t" @@ -105,7 +105,7 @@ static inline void XNPROD31(ogg_int32_t a, ogg_int32_t b, #ifndef _V_CLIP_MATH #define _V_CLIP_MATH -static inline ogg_int32_t CLIP_TO_15(ogg_int32_t x) { +static inline tremor_ogg_int32_t CLIP_TO_15(tremor_ogg_int32_t x) { int tmp; asm volatile("subs %1, %0, #32768\n\t" "movpl %0, #0x7f00\n\t" @@ -123,18 +123,17 @@ static inline ogg_int32_t CLIP_TO_15(ogg_int32_t x) { #ifndef _V_LSP_MATH_ASM #define _V_LSP_MATH_ASM -static inline void lsp_loop_asm(ogg_uint32_t *qip,ogg_uint32_t *pip, - ogg_int32_t *qexpp, - ogg_int32_t *ilsp,ogg_int32_t wi, - ogg_int32_t m){ +static inline void lsp_loop_asm(tremor_ogg_uint32_t *qip,tremor_ogg_uint32_t *pip, + tremor_ogg_int32_t *qexpp, + tremor_ogg_int32_t *ilsp,tremor_ogg_int32_t wi, + tremor_ogg_int32_t m){ - ogg_uint32_t qi=*qip,pi=*pip; - ogg_int32_t qexp=*qexpp; + tremor_ogg_uint32_t qi=*qip,pi=*pip; + tremor_ogg_int32_t qexp=*qexpp; asm("mov r0,%3;" - "movs r1,%5,asr#1;" + "mov r1,%5,asr#1;" "add r0,r0,r1,lsl#3;" - "beq 2f;\n" "1:" "ldmdb r0!,{r1,r3};" @@ -157,10 +156,9 @@ static inline void lsp_loop_asm(ogg_uint32_t *qip,ogg_uint32_t *pip, "cmp r0,%3;\n" "bhi 1b;\n" - "2:" // odd filter assymetry "ands r0,%5,#1;\n" - "beq 3f;\n" + "beq 2f;\n" "add r0,%3,%5,lsl#2;\n" "ldr r1,[r0,#-4];\n" @@ -172,7 +170,7 @@ static inline void lsp_loop_asm(ogg_uint32_t *qip,ogg_uint32_t *pip, "umull %1,r3,r0,%1;\n" //pi*=labs(ilsp[j+1]-wi) "cmn r2,r3;\n" // shift down 16? - "beq 3f;\n" + "beq 2f;\n" "add %2,%2,#16;\n" "mov %0,%0,lsr #16;\n" "orr %0,%0,r2,lsl #16;\n" @@ -186,7 +184,7 @@ static inline void lsp_loop_asm(ogg_uint32_t *qip,ogg_uint32_t *pip, //} /* normalize to max 16 sig figs */ - "3:" + "2:" "mov r2,#0;" "orr r1,%0,%1;" "tst r1,#0xff000000;" @@ -216,10 +214,10 @@ static inline void lsp_loop_asm(ogg_uint32_t *qip,ogg_uint32_t *pip, *qexpp=qexp; } -static inline void lsp_norm_asm(ogg_uint32_t *qip,ogg_int32_t *qexpp){ +static inline void lsp_norm_asm(tremor_ogg_uint32_t *qip,tremor_ogg_int32_t *qexpp){ - ogg_uint32_t qi=*qip; - ogg_int32_t qexp=*qexpp; + tremor_ogg_uint32_t qi=*qip; + tremor_ogg_int32_t qexp=*qexpp; asm("tst %0,#0x0000ff00;" "moveq %0,%0,lsl #8;" diff --git a/lib/tremor/autogen.sh b/lib/tremor/autogen.sh index 73c8fca8..e2e6f6b9 100755 --- a/lib/tremor/autogen.sh +++ b/lib/tremor/autogen.sh @@ -2,16 +2,14 @@ # Run this to set up the build system: configure, makefiles, etc. # (based on the version in enlightenment's cvs) -package="vorbisdec" +package="vorbisidec" -olddir=`pwd` srcdir=`dirname $0` test -z "$srcdir" && srcdir=. cd "$srcdir" DIE=0 -echo "checking for autoconf... " (autoconf --version) < /dev/null > /dev/null 2>&1 || { echo echo "You must have autoconf installed to compile $package." @@ -20,72 +18,16 @@ echo "checking for autoconf... " DIE=1 } -VERSIONGREP="sed -e s/.*[^0-9\.]\([0-9]\.[0-9]\).*/\1/" -VERSIONMKINT="sed -e s/[^0-9]//" - -# do we need automake? -if test -r Makefile.am; then - AM_OPTIONS=`fgrep AUTOMAKE_OPTIONS Makefile.am` - AM_NEEDED=`echo $AM_OPTIONS | $VERSIONGREP` - if test x"$AM_NEEDED" = "x$AM_OPTIONS"; then - AM_NEEDED="" - fi - if test -z $AM_NEEDED; then - echo -n "checking for automake... " - AUTOMAKE=automake - ACLOCAL=aclocal - if ($AUTOMAKE --version < /dev/null > /dev/null 2>&1); then - echo "yes" - else - echo "no" - AUTOMAKE= - fi - else - echo -n "checking for automake $AM_NEEDED or later... " - for am in automake-$AM_NEEDED automake$AM_NEEDED automake; do - ($am --version < /dev/null > /dev/null 2>&1) || continue - ver=`$am --version < /dev/null | head -n 1 | $VERSIONGREP | $VERSIONMKINT` - verneeded=`echo $AM_NEEDED | $VERSIONMKINT` - if test $ver -ge $verneeded; then - AUTOMAKE=$am - echo $AUTOMAKE - break - fi - done - test -z $AUTOMAKE && echo "no" - echo -n "checking for aclocal $AM_NEEDED or later... " - for ac in aclocal-$AM_NEEDED aclocal$AM_NEEDED aclocal; do - ($ac --version < /dev/null > /dev/null 2>&1) || continue - ver=`$ac --version < /dev/null | head -n 1 | $VERSIONGREP | $VERSIONMKINT` - verneeded=`echo $AM_NEEDED | $VERSIONMKINT` - if test $ver -ge $verneeded; then - ACLOCAL=$ac - echo $ACLOCAL - break - fi - done - test -z $ACLOCAL && echo "no" - fi - test -z $AUTOMAKE || test -z $ACLOCAL && { +(automake --version) < /dev/null > /dev/null 2>&1 || { echo echo "You must have automake installed to compile $package." - echo "Download the appropriate package for your distribution," - echo "or get the source tarball at ftp://ftp.gnu.org/pub/gnu/" - exit 1 - } -fi + echo "Download the appropriate package for your system," + echo "or get the source from one of the GNU ftp sites" + echo "listed in http://www.gnu.org/order/ftp.html" + DIE=1 +} -echo -n "checking for libtool... " -for LIBTOOLIZE in libtoolize glibtoolize nope; do - ($LIBTOOLIZE --version) < /dev/null > /dev/null 2>&1 && break -done -if test x$LIBTOOLIZE = xnope; then - echo "nope." - LIBTOOLIZE=libtoolize -else - echo $LIBTOOLIZE -fi -($LIBTOOLIZE --version) < /dev/null > /dev/null 2>&1 || { +(libtool --version) < /dev/null > /dev/null 2>&1 || { echo echo "You must have libtool installed to compile $package." echo "Download the appropriate package for your system," @@ -105,16 +47,15 @@ fi echo "Generating configuration files for $package, please wait...." -echo " $ACLOCAL $ACLOCAL_FLAGS" -$ACLOCAL $ACLOCAL_FLAGS || exit 1 -echo " $LIBTOOLIZE --automake" -$LIBTOOLIZE --automake || exit 1 +echo " aclocal $ACLOCAL_FLAGS" +aclocal $ACLOCAL_FLAGS || exit 1 echo " autoheader" autoheader || exit 1 -echo " $AUTOMAKE --add-missing $AUTOMAKE_FLAGS" -$AUTOMAKE --add-missing $AUTOMAKE_FLAGS || exit 1 +echo " libtoolize --automake" +libtoolize --automake || exit 1 +echo " automake --add-missing $AUTOMAKE_FLAGS" +automake --add-missing $AUTOMAKE_FLAGS || exit 1 echo " autoconf" autoconf || exit 1 -cd $olddir -$srcdir/configure --enable-maintainer-mode "$@" && echo +$srcdir/configure "$@" && echo diff --git a/lib/tremor/backends.h b/lib/tremor/backends.h deleted file mode 100644 index 52024219..00000000 --- a/lib/tremor/backends.h +++ /dev/null @@ -1,131 +0,0 @@ -/******************************************************************** - * * - * THIS FILE IS PART OF THE OggVorbis 'TREMOR' CODEC SOURCE CODE. * - * * - * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS * - * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE * - * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. * - * * - * THE OggVorbis 'TREMOR' SOURCE CODE IS (C) COPYRIGHT 1994-2002 * - * BY THE Xiph.Org FOUNDATION http://www.xiph.org/ * - * * - ******************************************************************** - - function: backend and mapping structures - - ********************************************************************/ - -/* this is exposed up here because we need it for static modes. - Lookups for each backend aren't exposed because there's no reason - to do so */ - -#ifndef _vorbis_backend_h_ -#define _vorbis_backend_h_ - -#include "codec_internal.h" - -/* this would all be simpler/shorter with templates, but.... */ -/* Transform backend generic *************************************/ - -/* only mdct right now. Flesh it out more if we ever transcend mdct - in the transform domain */ - -/* Floor backend generic *****************************************/ -typedef struct{ - vorbis_info_floor *(*unpack)(vorbis_info *,oggpack_buffer *); - vorbis_look_floor *(*look) (vorbis_dsp_state *,vorbis_info_mode *, - vorbis_info_floor *); - void (*free_info) (vorbis_info_floor *); - void (*free_look) (vorbis_look_floor *); - void *(*inverse1) (struct vorbis_block *,vorbis_look_floor *); - int (*inverse2) (struct vorbis_block *,vorbis_look_floor *, - void *buffer,ogg_int32_t *); -} vorbis_func_floor; - -typedef struct{ - int order; - long rate; - long barkmap; - - int ampbits; - int ampdB; - - int numbooks; /* <= 16 */ - int books[16]; - -} vorbis_info_floor0; - -#define VIF_POSIT 63 -#define VIF_CLASS 16 -#define VIF_PARTS 31 -typedef struct{ - int partitions; /* 0 to 31 */ - int partitionclass[VIF_PARTS]; /* 0 to 15 */ - - int class_dim[VIF_CLASS]; /* 1 to 8 */ - int class_subs[VIF_CLASS]; /* 0,1,2,3 (bits: 1< +#include +#include "misc.h" +#include "tremor_ogg.h" + +static unsigned long mask[]= +{0x00000000,0x00000001,0x00000003,0x00000007,0x0000000f, + 0x0000001f,0x0000003f,0x0000007f,0x000000ff,0x000001ff, + 0x000003ff,0x000007ff,0x00000fff,0x00001fff,0x00003fff, + 0x00007fff,0x0000ffff,0x0001ffff,0x0003ffff,0x0007ffff, + 0x000fffff,0x001fffff,0x003fffff,0x007fffff,0x00ffffff, + 0x01ffffff,0x03ffffff,0x07ffffff,0x0fffffff,0x1fffffff, + 0x3fffffff,0x7fffffff,0xffffffff }; + +/* spans forward, skipping as many bytes as headend is negative; if + headend is zero, simply finds next byte. If we're up to the end + of the buffer, leaves headend at zero. If we've read past the end, + halt the decode process. */ + +static void _span(tremor_oggpack_buffer *b){ + while(b->headend-(b->headbit>>3)<1){ + b->headend-=b->headbit>>3; + b->headbit&=0x7; + + if(b->head->next){ + b->count+=b->head->length; + b->head=b->head->next; + + if(b->headend+b->head->length>0) + b->headptr=b->head->buffer->data+b->head->begin-b->headend; + + b->headend+=b->head->length; + }else{ + /* we've either met the end of decode, or gone past it. halt + only if we're past */ + if(b->headend*8headbit) + /* read has fallen off the end */ + b->headend=-1; + break; + } + } +} + +void tremor_oggpack_readinit(tremor_oggpack_buffer *b,tremor_ogg_reference *r){ + memset(b,0,sizeof(*b)); + + b->tail=b->head=r; + b->count=0; + b->headptr=b->head->buffer->data+b->head->begin; + b->headend=b->head->length; + _span(b); +} + +#define _lookspan() while(!end){\ + head=head->next;\ + if(!head) return -1;\ + ptr=head->buffer->data + head->begin;\ + end=head->length;\ + } + +/* Read in bits without advancing the bitptr; bits <= 32 */ +long tremor_oggpack_look(tremor_oggpack_buffer *b,int bits){ + unsigned long m=mask[bits]; + unsigned long ret; + + bits+=b->headbit; + + if(bits >= b->headend<<3){ + int end=b->headend; + unsigned char *ptr=b->headptr; + tremor_ogg_reference *head=b->head; + + if(end<0)return -1; + + if(bits){ + _lookspan(); + ret=*ptr++>>b->headbit; + if(bits>8){ + --end; + _lookspan(); + ret|=*ptr++<<(8-b->headbit); + if(bits>16){ + --end; + _lookspan(); + ret|=*ptr++<<(16-b->headbit); + if(bits>24){ + --end; + _lookspan(); + ret|=*ptr++<<(24-b->headbit); + if(bits>32 && b->headbit){ + --end; + _lookspan(); + ret|=*ptr<<(32-b->headbit); + } + } + } + } + } + + }else{ + + /* make this a switch jump-table */ + ret=b->headptr[0]>>b->headbit; + if(bits>8){ + ret|=b->headptr[1]<<(8-b->headbit); + if(bits>16){ + ret|=b->headptr[2]<<(16-b->headbit); + if(bits>24){ + ret|=b->headptr[3]<<(24-b->headbit); + if(bits>32 && b->headbit) + ret|=b->headptr[4]<<(32-b->headbit); + } + } + } + } + + ret&=m; + return ret; +} + +/* limited to 32 at a time */ +void tremor_oggpack_adv(tremor_oggpack_buffer *b,int bits){ + bits+=b->headbit; + b->headbit=bits&7; + b->headend-=(bits>>3); + b->headptr+=(bits>>3); + if(b->headend<1)_span(b); +} + +int tremor_oggpack_eop(tremor_oggpack_buffer *b){ + if(b->headend<0)return -1; + return 0; +} + +/* bits <= 32 */ +long tremor_oggpack_read(tremor_oggpack_buffer *b,int bits){ + long ret=tremor_oggpack_look(b,bits); + tremor_oggpack_adv(b,bits); + return(ret); +} + +long tremor_oggpack_bytes(tremor_oggpack_buffer *b){ + if(b->headend<0)return b->count+b->head->length; + return b->count + b->head->length-b->headend + + (b->headbit+7)/8; +} + +long tremor_oggpack_bits(tremor_oggpack_buffer *b){ + if(b->headend<0)return (b->count+b->head->length)*8; + return (b->count + b->head->length-b->headend)*8 + + b->headbit; +} + +/* Self test of the bitwise routines; everything else is based on + them, so they damned well better be solid. */ + +#ifdef _V_BIT_TEST +#include +#include +#include +#include "framing.c" + +static int ilog(unsigned long v){ + int ret=0; + while(v){ + ret++; + v>>=1; + } + return(ret); +} + +tremor_oggpack_buffer r; +tremor_oggpack_buffer o; +tremor_ogg_buffer_state *bs; +tremor_ogg_reference *or; +#define TESTWORDS 256 + +void report(char *in){ + fprintf(stderr,"%s",in); + exit(1); +} + +int getbyte(tremor_ogg_reference *or,int position){ + while(or && position>=or->length){ + position-=or->length; + or=or->next; + if(or==NULL){ + fprintf(stderr,"\n\tERROR: getbyte ran off end of buffer.\n"); + exit(1); + } + } + + if((position+or->begin)&1) + return (or->buffer->data[(position+or->begin)>>1])&0xff; + else + return (or->buffer->data[(position+or->begin)>>1]>>8)&0xff; +} + +void cliptest(unsigned long *b,int vals,int bits,int *comp,int compsize){ + long i,bitcount=0; + tremor_ogg_reference *or=tremor_ogg_buffer_alloc(bs,64); + for(i=0;ibuffer->data[i]= comp[i]; + or->length=i; + + tremor_oggpack_readinit(&r,or); + for(i=0;i7) + report("\nERROR: too many bits reported left over.\n"); + + /* does reading to exactly byte alignment *not* trip EOF? */ + if(tremor_oggpack_read(&o,leftover)==-1) + report("\nERROR: read to but not past exact end tripped EOF.\n"); + if(tremor_oggpack_bits(&o)!=count*8) + report("\nERROR: read to but not past exact end reported bad bitcount.\n"); + + /* does EOF trip properly after a single additional bit? */ + if(tremor_oggpack_read(&o,1)!=-1) + report("\nERROR: read past exact end did not trip EOF.\n"); + if(tremor_oggpack_bits(&o)!=count*8) + report("\nERROR: read past exact end reported bad bitcount.\n"); + + /* does EOF stay set over additional bit reads? */ + for(i=0;i<=32;i++){ + if(tremor_oggpack_read(&o,i)!=-1) + report("\nERROR: EOF did not stay set on stream.\n"); + if(tremor_oggpack_bits(&o)!=count*8) + report("\nERROR: read past exact end reported bad bitcount.\n"); + } +} + +void _end_verify2(int count){ + int i; + + /* are the proper number of bits left over? */ + int leftover=count*8-tremor_oggpack_bits(&o); + if(leftover>7) + report("\nERROR: too many bits reported left over.\n"); + + /* does reading to exactly byte alignment *not* trip EOF? */ + tremor_oggpack_adv(&o,leftover); + if(o.headend!=0) + report("\nERROR: read to but not past exact end tripped EOF.\n"); + if(tremor_oggpack_bits(&o)!=count*8) + report("\nERROR: read to but not past exact end reported bad bitcount.\n"); + + /* does EOF trip properly after a single additional bit? */ + tremor_oggpack_adv(&o,1); + if(o.headend>=0) + report("\nERROR: read past exact end did not trip EOF.\n"); + if(tremor_oggpack_bits(&o)!=count*8) + report("\nERROR: read past exact end reported bad bitcount.\n"); + + /* does EOF stay set over additional bit reads? */ + for(i=0;i<=32;i++){ + tremor_oggpack_adv(&o,i); + if(o.headend>=0) + report("\nERROR: EOF did not stay set on stream.\n"); + if(tremor_oggpack_bits(&o)!=count*8) + report("\nERROR: read past exact end reported bad bitcount.\n"); + } +} + +long tremor_ogg_buffer_length(tremor_ogg_reference *or){ + int count=0; + while(or){ + count+=or->length; + or=or->next; + } + return count; +} + +tremor_ogg_reference *tremor_ogg_buffer_extend(tremor_ogg_reference *or,long bytes){ + if(or){ + while(or->next){ + or=or->next; + } + or->next=tremor_ogg_buffer_alloc(or->buffer->ptr.owner,bytes); + return(or->next); + } + return 0; +} + +void tremor_ogg_buffer_posttruncate(tremor_ogg_reference *or,long pos){ + /* walk to the point where we want to begin truncate */ + while(or && pos>or->length){ + pos-=or->length; + or=or->next; + } + if(or){ + tremor_ogg_buffer_release(or->next); + or->next=0; + or->length=pos; + } +} + +int main(void){ + long i; + static unsigned long testbuffer1[]= + {18,12,103948,4325,543,76,432,52,3,65,4,56,32,42,34,21,1,23,32,546,456,7, + 567,56,8,8,55,3,52,342,341,4,265,7,67,86,2199,21,7,1,5,1,4}; + int test1size=43; + + static unsigned long testbuffer2[]= + {216531625L,1237861823,56732452,131,3212421,12325343,34547562,12313212, + 1233432,534,5,346435231,14436467,7869299,76326614,167548585, + 85525151,0,12321,1,349528352}; + int test2size=21; + + static unsigned long testbuffer3[]= + {1,0,14,0,1,0,12,0,1,0,0,0,1,1,0,1,0,1,0,1,0,1,0,1,0,1,0,0,1,1,1,1,1,0,0,1, + 0,1,30,1,1,1,0,0,1,0,0,0,12,0,11,0,1,0,0,1}; + int test3size=56; + + static unsigned long large[]= + {2136531625L,2137861823,56732452,131,3212421,12325343,34547562,12313212, + 1233432,534,5,2146435231,14436467,7869299,76326614,167548585, + 85525151,0,12321,1,2146528352}; + + int onesize=33; + static int one[33]={146,25,44,151,195,15,153,176,233,131,196,65,85,172,47,40, + 34,242,223,136,35,222,211,86,171,50,225,135,214,75,172, + 223,4}; + + int twosize=6; + static int two[6]={61,255,255,251,231,29}; + + int threesize=54; + static int three[54]={169,2,232,252,91,132,156,36,89,13,123,176,144,32,254, + 142,224,85,59,121,144,79,124,23,67,90,90,216,79,23,83, + 58,135,196,61,55,129,183,54,101,100,170,37,127,126,10, + 100,52,4,14,18,86,77,1}; + + int foursize=38; + static int four[38]={18,6,163,252,97,194,104,131,32,1,7,82,137,42,129,11,72, + 132,60,220,112,8,196,109,64,179,86,9,137,195,208,122,169, + 28,2,133,0,1}; + + int fivesize=45; + static int five[45]={169,2,126,139,144,172,30,4,80,72,240,59,130,218,73,62, + 241,24,210,44,4,20,0,248,116,49,135,100,110,130,181,169, + 84,75,159,2,1,0,132,192,8,0,0,18,22}; + + int sixsize=7; + static int six[7]={17,177,170,242,169,19,148}; + + /* Test read/write together */ + /* Later we test against pregenerated bitstreams */ + bs=tremor_ogg_buffer_create(); + + fprintf(stderr,"\nSmall preclipped packing (LSb): "); + cliptest(testbuffer1,test1size,0,one,onesize); + fprintf(stderr,"ok."); + + fprintf(stderr,"\nNull bit call (LSb): "); + cliptest(testbuffer3,test3size,0,two,twosize); + fprintf(stderr,"ok."); + + fprintf(stderr,"\nLarge preclipped packing (LSb): "); + cliptest(testbuffer2,test2size,0,three,threesize); + fprintf(stderr,"ok."); + + fprintf(stderr,"\n32 bit preclipped packing (LSb): "); + + or=tremor_ogg_buffer_alloc(bs,128); + for(i=0;ibuffer->data[i*4] = large[i]&0xff; + or->buffer->data[i*4+1] = (large[i]>>8)&0xff; + or->buffer->data[i*4+2] = (large[i]>>16)&0xff; + or->buffer->data[i*4+3] = (large[i]>>24)&0xff; + } + or->length=test2size*4; + tremor_oggpack_readinit(&r,or); + for(i=0;i>k)&0x1)<7){ + bit=0; + word++; + } + } + } + } + count2=(bitcount+7)>>3; + + /* construct random-length buffer chain from flat vector; random + byte starting offset within the length of the vector */ + { + tremor_ogg_reference *or=NULL,*orl=NULL; + long pos=0; + + /* build buffer chain */ + while(count2){ + int ilen=(rand()%32),k; + int ibegin=(rand()%32); + + + if(ilen>count2)ilen=count2; + + if(or) + orl=tremor_ogg_buffer_extend(orl,64); + else + or=orl=tremor_ogg_buffer_alloc(bs,64); + + orl->length=ilen; + orl->begin=ibegin; + + for(k=0;kbuffer->data[ibegin++]= flat[pos++]; + + count2-=ilen; + } + + if(tremor_ogg_buffer_length(or)!=(bitcount+7)/8){ + fprintf(stderr,"\nERROR: buffer length incorrect after build.\n"); + exit(1); + } + + + { + int begin=0; //=(rand()%TESTWORDS); + int ilen=(rand()%(TESTWORDS-begin)); + int bitoffset,bitcount=0; + unsigned long temp; + + for(j=0;j -#include -#include -#include -#include "ivorbiscodec.h" -#include "codec_internal.h" - -#include "window.h" -#include "registry.h" -#include "misc.h" - -static int ilog(unsigned int v){ - int ret=0; - if(v)--v; - while(v){ - ret++; - v>>=1; - } - return(ret); -} - -/* pcm accumulator examples (not exhaustive): - - <-------------- lW ----------------> - <--------------- W ----------------> -: .....|..... _______________ | -: .''' | '''_--- | |\ | -:.....''' |_____--- '''......| | \_______| -:.................|__________________|_______|__|______| - |<------ Sl ------>| > Sr < |endW - |beginSl |endSl | |endSr - |beginW |endlW |beginSr - - - |< lW >| - <--------------- W ----------------> - | | .. ______________ | - | | ' `/ | ---_ | - |___.'___/`. | ---_____| - |_______|__|_______|_________________| - | >|Sl|< |<------ Sr ----->|endW - | | |endSl |beginSr |endSr - |beginW | |endlW - mult[0] |beginSl mult[n] - - <-------------- lW -----------------> - |<--W-->| -: .............. ___ | | -: .''' |`/ \ | | -:.....''' |/`....\|...| -:.........................|___|___|___| - |Sl |Sr |endW - | | |endSr - | |beginSr - | |endSl - |beginSl - |beginW -*/ - -/* block abstraction setup *********************************************/ - -#ifndef WORD_ALIGN -#define WORD_ALIGN 8 -#endif - -int vorbis_block_init(vorbis_dsp_state *v, vorbis_block *vb){ - memset(vb,0,sizeof(*vb)); - vb->vd=v; - vb->localalloc=0; - vb->localstore=NULL; - - return(0); -} - -void *_vorbis_block_alloc(vorbis_block *vb,long bytes){ - bytes=(bytes+(WORD_ALIGN-1)) & ~(WORD_ALIGN-1); - if(bytes+vb->localtop>vb->localalloc){ - /* can't just _ogg_realloc... there are outstanding pointers */ - if(vb->localstore){ - struct alloc_chain *link=(struct alloc_chain *)_ogg_malloc(sizeof(*link)); - vb->totaluse+=vb->localtop; - link->next=vb->reap; - link->ptr=vb->localstore; - vb->reap=link; - } - /* highly conservative */ - vb->localalloc=bytes; - vb->localstore=_ogg_malloc(vb->localalloc); - vb->localtop=0; - } - { - void *ret=(void *)(((char *)vb->localstore)+vb->localtop); - vb->localtop+=bytes; - return ret; - } -} - -/* reap the chain, pull the ripcord */ -void _vorbis_block_ripcord(vorbis_block *vb){ - /* reap the chain */ - struct alloc_chain *reap=vb->reap; - while(reap){ - struct alloc_chain *next=reap->next; - _ogg_free(reap->ptr); - memset(reap,0,sizeof(*reap)); - _ogg_free(reap); - reap=next; - } - /* consolidate storage */ - if(vb->totaluse){ - vb->localstore=_ogg_realloc(vb->localstore,vb->totaluse+vb->localalloc); - vb->localalloc+=vb->totaluse; - vb->totaluse=0; - } - - /* pull the ripcord */ - vb->localtop=0; - vb->reap=NULL; -} - -int vorbis_block_clear(vorbis_block *vb){ - _vorbis_block_ripcord(vb); - if(vb->localstore)_ogg_free(vb->localstore); - - memset(vb,0,sizeof(*vb)); - return(0); -} - -static int _vds_init(vorbis_dsp_state *v,vorbis_info *vi){ - int i; - codec_setup_info *ci=(codec_setup_info *)vi->codec_setup; - private_state *b=NULL; - - if(ci==NULL) return 1; - - memset(v,0,sizeof(*v)); - b=(private_state *)(v->backend_state=_ogg_calloc(1,sizeof(*b))); - - v->vi=vi; - b->modebits=ilog(ci->modes); - - /* Vorbis I uses only window type 0 */ - b->window[0]=_vorbis_window(0,ci->blocksizes[0]/2); - b->window[1]=_vorbis_window(0,ci->blocksizes[1]/2); - - /* finish the codebooks */ - if(!ci->fullbooks){ - ci->fullbooks=(codebook *)_ogg_calloc(ci->books,sizeof(*ci->fullbooks)); - for(i=0;ibooks;i++){ - if(ci->book_param[i]==NULL) - goto abort_books; - if(vorbis_book_init_decode(ci->fullbooks+i,ci->book_param[i])) - goto abort_books; - /* decode codebooks are now standalone after init */ - vorbis_staticbook_destroy(ci->book_param[i]); - ci->book_param[i]=NULL; - } - } - - v->pcm_storage=ci->blocksizes[1]; - v->pcm=(ogg_int32_t **)_ogg_malloc(vi->channels*sizeof(*v->pcm)); - v->pcmret=(ogg_int32_t **)_ogg_malloc(vi->channels*sizeof(*v->pcmret)); - for(i=0;ichannels;i++) - v->pcm[i]=(ogg_int32_t *)_ogg_calloc(v->pcm_storage,sizeof(*v->pcm[i])); - - /* all 1 (large block) or 0 (small block) */ - /* explicitly set for the sake of clarity */ - v->lW=0; /* previous window size */ - v->W=0; /* current window size */ - - /* initialize all the mapping/backend lookups */ - b->mode=(vorbis_look_mapping **)_ogg_calloc(ci->modes,sizeof(*b->mode)); - for(i=0;imodes;i++){ - int mapnum=ci->mode_param[i]->mapping; - int maptype=ci->map_type[mapnum]; - b->mode[i]=_mapping_P[maptype]->look(v,ci->mode_param[i], - ci->map_param[mapnum]); - } - return 0; -abort_books: - for(i=0;ibooks;i++){ - if(ci->book_param[i]!=NULL){ - vorbis_staticbook_destroy(ci->book_param[i]); - ci->book_param[i]=NULL; - } - } - vorbis_dsp_clear(v); - return -1; -} - -int vorbis_synthesis_restart(vorbis_dsp_state *v){ - vorbis_info *vi=v->vi; - codec_setup_info *ci; - - if(!v->backend_state)return -1; - if(!vi)return -1; - ci=vi->codec_setup; - if(!ci)return -1; - - v->centerW=ci->blocksizes[1]/2; - v->pcm_current=v->centerW; - - v->pcm_returned=-1; - v->granulepos=-1; - v->sequence=-1; - ((private_state *)(v->backend_state))->sample_count=-1; - - return(0); -} - -int vorbis_synthesis_init(vorbis_dsp_state *v,vorbis_info *vi){ - if(_vds_init(v,vi))return 1; - vorbis_synthesis_restart(v); - - return 0; -} - -void vorbis_dsp_clear(vorbis_dsp_state *v){ - int i; - if(v){ - vorbis_info *vi=v->vi; - codec_setup_info *ci=(codec_setup_info *)(vi?vi->codec_setup:NULL); - private_state *b=(private_state *)v->backend_state; - - if(v->pcm){ - for(i=0;ichannels;i++) - if(v->pcm[i])_ogg_free(v->pcm[i]); - _ogg_free(v->pcm); - if(v->pcmret)_ogg_free(v->pcmret); - } - - /* free mode lookups; these are actually vorbis_look_mapping structs */ - if(ci){ - for(i=0;imodes;i++){ - int mapnum=ci->mode_param[i]->mapping; - int maptype=ci->map_type[mapnum]; - if(b && b->mode)_mapping_P[maptype]->free_look(b->mode[i]); - } - } - - if(b){ - if(b->mode)_ogg_free(b->mode); - _ogg_free(b); - } - - memset(v,0,sizeof(*v)); - } -} - -/* Unlike in analysis, the window is only partially applied for each - block. The time domain envelope is not yet handled at the point of - calling (as it relies on the previous block). */ - -int vorbis_synthesis_blockin(vorbis_dsp_state *v,vorbis_block *vb){ - vorbis_info *vi=v->vi; - codec_setup_info *ci=(codec_setup_info *)vi->codec_setup; - private_state *b=v->backend_state; - int i,j; - - if(v->pcm_current>v->pcm_returned && v->pcm_returned!=-1)return(OV_EINVAL); - - v->lW=v->W; - v->W=vb->W; - v->nW=-1; - - if((v->sequence==-1)|| - (v->sequence+1 != vb->sequence)){ - v->granulepos=-1; /* out of sequence; lose count */ - b->sample_count=-1; - } - - v->sequence=vb->sequence; - - if(vb->pcm){ /* no pcm to process if vorbis_synthesis_trackonly - was called on block */ - int n=ci->blocksizes[v->W]/2; - int n0=ci->blocksizes[0]/2; - int n1=ci->blocksizes[1]/2; - - int thisCenter; - int prevCenter; - - if(v->centerW){ - thisCenter=n1; - prevCenter=0; - }else{ - thisCenter=0; - prevCenter=n1; - } - - /* v->pcm is now used like a two-stage double buffer. We don't want - to have to constantly shift *or* adjust memory usage. Don't - accept a new block until the old is shifted out */ - - /* overlap/add PCM */ - - for(j=0;jchannels;j++){ - /* the overlap/add section */ - if(v->lW){ - if(v->W){ - /* large/large */ - ogg_int32_t *pcm=v->pcm[j]+prevCenter; - ogg_int32_t *p=vb->pcm[j]; - for(i=0;ipcm[j]+prevCenter+n1/2-n0/2; - ogg_int32_t *p=vb->pcm[j]; - for(i=0;iW){ - /* small/large */ - ogg_int32_t *pcm=v->pcm[j]+prevCenter; - ogg_int32_t *p=vb->pcm[j]+n1/2-n0/2; - for(i=0;ipcm[j]+prevCenter; - ogg_int32_t *p=vb->pcm[j]; - for(i=0;ipcm[j]+thisCenter; - ogg_int32_t *p=vb->pcm[j]+n; - for(i=0;icenterW) - v->centerW=0; - else - v->centerW=n1; - - /* deal with initial packet state; we do this using the explicit - pcm_returned==-1 flag otherwise we're sensitive to first block - being short or long */ - - if(v->pcm_returned==-1){ - v->pcm_returned=thisCenter; - v->pcm_current=thisCenter; - }else{ - v->pcm_returned=prevCenter; - v->pcm_current=prevCenter+ - ci->blocksizes[v->lW]/4+ - ci->blocksizes[v->W]/4; - } - - } - - /* track the frame number... This is for convenience, but also - making sure our last packet doesn't end with added padding. If - the last packet is partial, the number of samples we'll have to - return will be past the vb->granulepos. - - This is not foolproof! It will be confused if we begin - decoding at the last page after a seek or hole. In that case, - we don't have a starting point to judge where the last frame - is. For this reason, vorbisfile will always try to make sure - it reads the last two marked pages in proper sequence */ - - if(b->sample_count==-1){ - b->sample_count=0; - }else{ - b->sample_count+=ci->blocksizes[v->lW]/4+ci->blocksizes[v->W]/4; - } - - if(v->granulepos==-1){ - if(vb->granulepos!=-1){ /* only set if we have a position to set to */ - - v->granulepos=vb->granulepos; - - /* is this a short page? */ - if(b->sample_count>v->granulepos){ - /* corner case; if this is both the first and last audio page, - then spec says the end is cut, not beginning */ - long extra=b->sample_count-vb->granulepos; - - /* we use ogg_int64_t for granule positions because a - uint64 isn't universally available. Unfortunately, - that means granposes can be 'negative' and result in - extra being negative */ - if(extra<0) - extra=0; - - if(vb->eofflag){ - /* trim the end */ - /* no preceeding granulepos; assume we started at zero (we'd - have to in a short single-page stream) */ - /* granulepos could be -1 due to a seek, but that would result - in a long coun`t, not short count */ - - /* Guard against corrupt/malicious frames that set EOP and - a backdated granpos; don't rewind more samples than we - actually have */ - if(extra > v->pcm_current - v->pcm_returned) - extra = v->pcm_current - v->pcm_returned; - - v->pcm_current-=extra; - }else{ - /* trim the beginning */ - v->pcm_returned+=extra; - if(v->pcm_returned>v->pcm_current) - v->pcm_returned=v->pcm_current; - } - - } - - } - }else{ - v->granulepos+=ci->blocksizes[v->lW]/4+ci->blocksizes[v->W]/4; - if(vb->granulepos!=-1 && v->granulepos!=vb->granulepos){ - - if(v->granulepos>vb->granulepos){ - long extra=v->granulepos-vb->granulepos; - - if(extra) - if(vb->eofflag){ - /* partial last frame. Strip the extra samples off */ - - /* Guard against corrupt/malicious frames that set EOP and - a backdated granpos; don't rewind more samples than we - actually have */ - if(extra > v->pcm_current - v->pcm_returned) - extra = v->pcm_current - v->pcm_returned; - - /* we use ogg_int64_t for granule positions because a - uint64 isn't universally available. Unfortunately, - that means granposes can be 'negative' and result in - extra being negative */ - if(extra<0) - extra=0; - - v->pcm_current-=extra; - - } /* else {Shouldn't happen *unless* the bitstream is out of - spec. Either way, believe the bitstream } */ - } /* else {Shouldn't happen *unless* the bitstream is out of - spec. Either way, believe the bitstream } */ - v->granulepos=vb->granulepos; - } - } - - /* Update, cleanup */ - - if(vb->eofflag)v->eofflag=1; - return(0); -} - -/* pcm==NULL indicates we just want the pending samples, no more */ -int vorbis_synthesis_pcmout(vorbis_dsp_state *v,ogg_int32_t ***pcm){ - vorbis_info *vi=v->vi; - if(v->pcm_returned>-1 && v->pcm_returnedpcm_current){ - if(pcm){ - int i; - for(i=0;ichannels;i++) - v->pcmret[i]=v->pcm[i]+v->pcm_returned; - *pcm=v->pcmret; - } - return(v->pcm_current-v->pcm_returned); - } - return(0); -} - -int vorbis_synthesis_read(vorbis_dsp_state *v,int bytes){ - if(bytes && v->pcm_returned+bytes>v->pcm_current)return(OV_EINVAL); - v->pcm_returned+=bytes; - return(0); -} - diff --git a/lib/tremor/block.h b/lib/tremor/block.h deleted file mode 100644 index 5e193543..00000000 --- a/lib/tremor/block.h +++ /dev/null @@ -1,24 +0,0 @@ -/******************************************************************** - * * - * THIS FILE IS PART OF THE OggVorbis 'TREMOR' CODEC SOURCE CODE. * - * * - * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS * - * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE * - * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. * - * * - * THE OggVorbis 'TREMOR' SOURCE CODE IS (C) COPYRIGHT 1994-2008 * - * BY THE Xiph.Org FOUNDATION http://www.xiph.org/ * - * * - ******************************************************************** - - function: shared block functions - - ********************************************************************/ - -#ifndef _V_BLOCK_ -#define _V_BLOCK_ - -extern void _vorbis_block_ripcord(vorbis_block *vb); -extern void *_vorbis_block_alloc(vorbis_block *vb,long bytes); - -#endif diff --git a/lib/tremor/codebook.c b/lib/tremor/codebook.c index 1e1ae8a9..85a46eb2 100644 --- a/lib/tremor/codebook.c +++ b/lib/tremor/codebook.c @@ -1,12 +1,12 @@ /******************************************************************** * * - * THIS FILE IS PART OF THE OggVorbis 'TREMOR' CODEC SOURCE CODE. * + * THIS FILE IS PART OF THE TremorOggVorbis 'TREMOR' CODEC SOURCE CODE. * * * * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS * * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE * * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. * * * - * THE OggVorbis 'TREMOR' SOURCE CODE IS (C) COPYRIGHT 1994-2002 * + * THE TremorOggVorbis 'TREMOR' SOURCE CODE IS (C) COPYRIGHT 1994-2002 * * BY THE Xiph.Org FOUNDATION http://www.xiph.org/ * * * ******************************************************************** @@ -18,77 +18,385 @@ #include #include #include -#include +#include "tremor_ogg.h" #include "ivorbiscodec.h" #include "codebook.h" #include "misc.h" +#include "os.h" -/* unpacks a codebook from the packet buffer into the codebook struct, - readies the codebook auxiliary structures for decode *************/ -static_codebook *vorbis_staticbook_unpack(oggpack_buffer *opb){ - long i,j; - static_codebook *s=_ogg_calloc(1,sizeof(*s)); + +/**** pack/unpack helpers ******************************************/ +int _ilog(unsigned int v){ + int ret=0; + while(v){ + ret++; + v>>=1; + } + return(ret); +} + +static tremor_ogg_uint32_t decpack(long entry,long used_entry,long quantvals, + codebook *b,tremor_oggpack_buffer *opb,int maptype){ + tremor_ogg_uint32_t ret=0; + int j; + + switch(b->dec_type){ + + case 0: + return (tremor_ogg_uint32_t)entry; + + case 1: + if(maptype==1){ + /* vals are already read into temporary column vector here */ + for(j=0;jdim;j++){ + tremor_ogg_uint32_t off=entry%quantvals; + entry/=quantvals; + ret|=((tremor_ogg_uint16_t *)(b->q_val))[off]<<(b->q_bits*j); + } + }else{ + for(j=0;jdim;j++) + ret|=tremor_oggpack_read(opb,b->q_bits)<<(b->q_bits*j); + } + return ret; + + case 2: + for(j=0;jdim;j++){ + tremor_ogg_uint32_t off=entry%quantvals; + entry/=quantvals; + ret|=off<<(b->q_pack*j); + } + return ret; + + case 3: + return (tremor_ogg_uint32_t)used_entry; + + } + return 0; /* silence compiler */ +} + +/* 32 bit float (not IEEE; nonnormalized mantissa + + biased exponent) : neeeeeee eeemmmmm mmmmmmmm mmmmmmmm + Why not IEEE? It's just not that important here. */ + +static tremor_ogg_int32_t _float32_unpack(long val,int *point){ + long mant=val&0x1fffff; + int sign=val&0x80000000; + + *point=((val&0x7fe00000L)>>21)-788; + + if(mant){ + while(!(mant&0x40000000)){ + mant<<=1; + *point-=1; + } + if(sign)mant= -mant; + }else{ + *point=-9999; + } + return mant; +} + +/* choose the smallest supported node size that fits our decode table. + Legal bytewidths are 1/1 1/2 2/2 2/4 4/4 */ +static int _determine_node_bytes(long used, int leafwidth){ + + /* special case small books to size 4 to avoid multiple special + cases in repack */ + if(used<2) + return 4; + + if(leafwidth==3)leafwidth=4; + if(_ilog(3*used-6)+1 <= leafwidth*4) + return leafwidth/2?leafwidth/2:1; + return leafwidth; +} + +/* convenience/clarity; leaves are specified as multiple of node word + size (1 or 2) */ +static int _determine_leaf_words(int nodeb, int leafwidth){ + if(leafwidth>nodeb)return 2; + return 1; +} + +/* given a list of word lengths, number of used entries, and byte + width of a leaf, generate the decode table */ +static int _make_words(char *l,long n,tremor_ogg_uint32_t *r,long quantvals, + codebook *b, tremor_oggpack_buffer *opb,int maptype){ + long i,j,count=0; + long top=0; + tremor_ogg_uint32_t marker[33]; + + if(n<2){ + r[0]=0x80000000; + }else{ + memset(marker,0,sizeof(marker)); + + for(i=0;i>(length-j-1))&1; + if(chase>=top){ + top++; + r[chase*2]=top; + r[chase*2+1]=0; + }else + if(!r[chase*2+bit]) + r[chase*2+bit]=top; + chase=r[chase*2+bit]; + } + { + int bit=(entry>>(length-j-1))&1; + if(chase>=top){ + top++; + r[chase*2+1]=0; + } + r[chase*2+bit]= decpack(i,count++,quantvals,b,opb,maptype) | + 0x80000000; + } + + /* Look to see if the next shorter marker points to the node + above. if so, update it and repeat. */ + for(j=length;j>0;j--){ + if(marker[j]&1){ + marker[j]=marker[j-1]<<1; + break; + } + marker[j]++; + } + + /* prune the tree; the implicit invariant says all the longer + markers were dangling from our just-taken node. Dangle them + from our *new* node. */ + for(j=length+1;j<33;j++) + if((marker[j]>>1) == entry){ + entry=marker[j]; + marker[j]=marker[j-1]<<1; + }else + break; + } + } + } + + return 0; +} + +static int _make_decode_table(codebook *s,char *lengthlist,long quantvals, + tremor_oggpack_buffer *opb,int maptype){ + int i; + tremor_ogg_uint32_t *work; + + if(s->dec_nodeb==4){ + s->dec_table=_tremor_ogg_malloc((s->used_entries*2+1)*sizeof(*work)); + /* +1 (rather than -2) is to accommodate 0 and 1 sized books, + which are specialcased to nodeb==4 */ + if(_make_words(lengthlist,s->entries, + s->dec_table,quantvals,s,opb,maptype))return 1; + + return 0; + } + + work=alloca((s->used_entries*2-2)*sizeof(*work)); + if(_make_words(lengthlist,s->entries,work,quantvals,s,opb,maptype))return 1; + s->dec_table=_tremor_ogg_malloc((s->used_entries*(s->dec_leafw+1)-2)* + s->dec_nodeb); + + if(s->dec_leafw==1){ + switch(s->dec_nodeb){ + case 1: + for(i=0;iused_entries*2-2;i++) + ((unsigned char *)s->dec_table)[i]= + ((work[i] & 0x80000000UL) >> 24) | work[i]; + break; + case 2: + for(i=0;iused_entries*2-2;i++) + ((tremor_ogg_uint16_t *)s->dec_table)[i]= + ((work[i] & 0x80000000UL) >> 16) | work[i]; + break; + } + + }else{ + /* more complex; we have to do a two-pass repack that updates the + node indexing. */ + long top=s->used_entries*3-2; + if(s->dec_nodeb==1){ + unsigned char *out=(unsigned char *)s->dec_table; + + for(i=s->used_entries*2-4;i>=0;i-=2){ + if(work[i]&0x80000000UL){ + if(work[i+1]&0x80000000UL){ + top-=4; + out[top]=(work[i]>>8 & 0x7f)|0x80; + out[top+1]=(work[i+1]>>8 & 0x7f)|0x80; + out[top+2]=work[i] & 0xff; + out[top+3]=work[i+1] & 0xff; + }else{ + top-=3; + out[top]=(work[i]>>8 & 0x7f)|0x80; + out[top+1]=work[work[i+1]*2]; + out[top+2]=work[i] & 0xff; + } + }else{ + if(work[i+1]&0x80000000UL){ + top-=3; + out[top]=work[work[i]*2]; + out[top+1]=(work[i+1]>>8 & 0x7f)|0x80; + out[top+2]=work[i+1] & 0xff; + }else{ + top-=2; + out[top]=work[work[i]*2]; + out[top+1]=work[work[i+1]*2]; + } + } + work[i]=top; + } + }else{ + tremor_ogg_uint16_t *out=(tremor_ogg_uint16_t *)s->dec_table; + for(i=s->used_entries*2-4;i>=0;i-=2){ + if(work[i]&0x80000000UL){ + if(work[i+1]&0x80000000UL){ + top-=4; + out[top]=(work[i]>>16 & 0x7fff)|0x8000; + out[top+1]=(work[i+1]>>16 & 0x7fff)|0x8000; + out[top+2]=work[i] & 0xffff; + out[top+3]=work[i+1] & 0xffff; + }else{ + top-=3; + out[top]=(work[i]>>16 & 0x7fff)|0x8000; + out[top+1]=work[work[i+1]*2]; + out[top+2]=work[i] & 0xffff; + } + }else{ + if(work[i+1]&0x80000000UL){ + top-=3; + out[top]=work[work[i]*2]; + out[top+1]=(work[i+1]>>16 & 0x7fff)|0x8000; + out[top+2]=work[i+1] & 0xffff; + }else{ + top-=2; + out[top]=work[work[i]*2]; + out[top+1]=work[work[i+1]*2]; + } + } + work[i]=top; + } + } + } + + return 0; +} + +/* most of the time, entries%dimensions == 0, but we need to be + well defined. We define that the possible vales at each + scalar is values == entries/dim. If entries%dim != 0, we'll + have 'too few' values (values*dimentries); + int vals=b->entries>>((bits-1)*(b->dim-1)/b->dim); + + while(1){ + long acc=1; + long acc1=1; + int i; + for(i=0;idim;i++){ + acc*=vals; + acc1*=vals+1; + } + if(acc<=b->entries && acc1>b->entries){ + return(vals); + }else{ + if(acc>b->entries){ + vals--; + }else{ + vals++; + } + } + } +} + +void vorbis_book_clear(codebook *b){ + /* static book is not cleared; we're likely called on the lookup and + the static codebook belongs to the info struct */ + if(b->q_val)_tremor_ogg_free(b->q_val); + if(b->dec_table)_tremor_ogg_free(b->dec_table); + + memset(b,0,sizeof(*b)); +} + +int vorbis_book_unpack(tremor_oggpack_buffer *opb,codebook *s){ + char *lengthlist=NULL; + int quantvals=0; + long i,j; + int maptype; + + memset(s,0,sizeof(*s)); /* make sure alignment is correct */ - if(oggpack_read(opb,24)!=0x564342)goto _eofout; + if(tremor_oggpack_read(opb,24)!=0x564342)goto _eofout; /* first the basic parameters */ - s->dim=oggpack_read(opb,16); - s->entries=oggpack_read(opb,24); + s->dim=tremor_oggpack_read(opb,16); + s->entries=tremor_oggpack_read(opb,24); if(s->entries==-1)goto _eofout; - if(_ilog(s->dim)+_ilog(s->entries)>24)goto _eofout; - /* codeword ordering.... length ordered or unordered? */ - switch((int)oggpack_read(opb,1)){ - case 0:{ - long unused; - /* allocated but unused entries? */ - unused=oggpack_read(opb,1); - if((s->entries*(unused?1:5)+7)>>3>opb->storage-oggpack_bytes(opb)) - goto _eofout; + switch((int)tremor_oggpack_read(opb,1)){ + case 0: /* unordered */ - s->lengthlist=(long *)_ogg_malloc(sizeof(*s->lengthlist)*s->entries); + lengthlist=(char *)alloca(sizeof(*lengthlist)*s->entries); /* allocated but unused entries? */ - if(unused){ + if(tremor_oggpack_read(opb,1)){ /* yes, unused entries */ for(i=0;ientries;i++){ - if(oggpack_read(opb,1)){ - long num=oggpack_read(opb,5); + if(tremor_oggpack_read(opb,1)){ + long num=tremor_oggpack_read(opb,5); if(num==-1)goto _eofout; - s->lengthlist[i]=num+1; + lengthlist[i]=num+1; + s->used_entries++; + if(num+1>s->dec_maxlength)s->dec_maxlength=num+1; }else - s->lengthlist[i]=0; + lengthlist[i]=0; } }else{ /* all entries used; no tagging */ + s->used_entries=s->entries; for(i=0;ientries;i++){ - long num=oggpack_read(opb,5); + long num=tremor_oggpack_read(opb,5); if(num==-1)goto _eofout; - s->lengthlist[i]=num+1; + lengthlist[i]=num+1; + if(num+1>s->dec_maxlength)s->dec_maxlength=num+1; } } break; - } case 1: /* ordered */ { - long length=oggpack_read(opb,5)+1; - if(length==0)goto _eofout; - s->lengthlist=(long *)_ogg_malloc(sizeof(*s->lengthlist)*s->entries); + long length=tremor_oggpack_read(opb,5)+1; + s->used_entries=s->entries; + lengthlist=(char *)alloca(sizeof(*lengthlist)*s->entries); + for(i=0;ientries;){ - long num=oggpack_read(opb,_ilog(s->entries-i)); + long num=tremor_oggpack_read(opb,_ilog(s->entries-i)); if(num==-1)goto _eofout; - if(length>32 || num>s->entries-i || - (num>0 && (num-1)>>(length>>1)>>((length+1)>>1))>0){ - goto _errout; - } - for(j=0;jlengthlist[i]=length; + for(j=0;jentries;j++,i++) + lengthlist[i]=length; + s->dec_maxlength=length; length++; } } @@ -97,295 +405,393 @@ static_codebook *vorbis_staticbook_unpack(oggpack_buffer *opb){ /* EOF */ goto _eofout; } - + + /* Do we have a mapping to unpack? */ - switch((s->maptype=oggpack_read(opb,4))){ + + if((maptype=tremor_oggpack_read(opb,4))>0){ + s->q_min=_float32_unpack(tremor_oggpack_read(opb,32),&s->q_minp); + s->q_del=_float32_unpack(tremor_oggpack_read(opb,32),&s->q_delp); + s->q_bits=tremor_oggpack_read(opb,4)+1; + s->q_seq=tremor_oggpack_read(opb,1); + + s->q_del>>=s->q_bits; + s->q_delp+=s->q_bits; + } + + switch(maptype){ case 0: - /* no mapping */ + + /* no mapping; decode type 0 */ + + /* how many bytes for the indexing? */ + /* this is the correct boundary here; we lose one bit to + node/leaf mark */ + s->dec_nodeb=_determine_node_bytes(s->used_entries,_ilog(s->entries)/8+1); + s->dec_leafw=_determine_leaf_words(s->dec_nodeb,_ilog(s->entries)/8+1); + s->dec_type=0; + + if(_make_decode_table(s,lengthlist,quantvals,opb,maptype)) goto _errout; break; - case 1: case 2: - /* implicitly populated value mapping */ - /* explicitly populated value mapping */ - s->q_min=oggpack_read(opb,32); - s->q_delta=oggpack_read(opb,32); - s->q_quant=oggpack_read(opb,4)+1; - s->q_sequencep=oggpack_read(opb,1); - if(s->q_sequencep==-1)goto _eofout; + case 1: + /* mapping type 1; implicit values by lattice position */ + quantvals=_book_maptype1_quantvals(s); + + /* dec_type choices here are 1,2; 3 doesn't make sense */ { - int quantvals=0; - switch(s->maptype){ - case 1: - quantvals=(s->dim==0?0:_book_maptype1_quantvals(s)); - break; - case 2: - quantvals=s->entries*s->dim; - break; - } + /* packed values */ + long total1=(s->q_bits*s->dim+8)/8; /* remember flag bit */ + /* vector of column offsets; remember flag bit */ + long total2=(_ilog(quantvals-1)*s->dim+8)/8+(s->q_bits+7)/8; + - /* quantized values */ - if((quantvals*s->q_quant+7)>>3>opb->storage-oggpack_bytes(opb)) - goto _eofout; - s->quantlist=(long *)_ogg_malloc(sizeof(*s->quantlist)*quantvals); - for(i=0;iquantlist[i]=oggpack_read(opb,s->q_quant); + if(total1<=4 && total1<=total2){ + /* use dec_type 1: vector of packed values */ + + /* need quantized values before */ + s->q_val=alloca(sizeof(tremor_ogg_uint16_t)*quantvals); + for(i=0;iq_val)[i]=tremor_oggpack_read(opb,s->q_bits); + + if(tremor_oggpack_eop(opb)){ + s->q_val=0; /* cleanup must not free alloca memory */ + goto _eofout; + } + + s->dec_type=1; + s->dec_nodeb=_determine_node_bytes(s->used_entries, + (s->q_bits*s->dim+8)/8); + s->dec_leafw=_determine_leaf_words(s->dec_nodeb, + (s->q_bits*s->dim+8)/8); + if(_make_decode_table(s,lengthlist,quantvals,opb,maptype)){ + s->q_val=0; /* cleanup must not free alloca memory */ + goto _errout; + } + + s->q_val=0; /* about to go out of scope; _make_decode_table + was using it */ + + }else{ + /* use dec_type 2: packed vector of column offsets */ + + /* need quantized values before */ + if(s->q_bits<=8){ + s->q_val=_tremor_ogg_malloc(quantvals); + for(i=0;iq_val)[i]=tremor_oggpack_read(opb,s->q_bits); + }else{ + s->q_val=_tremor_ogg_malloc(quantvals*2); + for(i=0;iq_val)[i]=tremor_oggpack_read(opb,s->q_bits); + } + + if(tremor_oggpack_eop(opb))goto _eofout; + + s->q_pack=_ilog(quantvals-1); + s->dec_type=2; + s->dec_nodeb=_determine_node_bytes(s->used_entries, + (_ilog(quantvals-1)*s->dim+8)/8); + s->dec_leafw=_determine_leaf_words(s->dec_nodeb, + (_ilog(quantvals-1)*s->dim+8)/8); + if(_make_decode_table(s,lengthlist,quantvals,opb,maptype))goto _errout; + + } + } + break; + case 2: + + /* mapping type 2; explicit array of values */ + quantvals=s->entries*s->dim; + /* dec_type choices here are 1,3; 2 is not possible */ + + if( (s->q_bits*s->dim+8)/8 <=4){ /* remember flag bit */ + /* use dec_type 1: vector of packed values */ + + s->dec_type=1; + s->dec_nodeb=_determine_node_bytes(s->used_entries,(s->q_bits*s->dim+8)/8); + s->dec_leafw=_determine_leaf_words(s->dec_nodeb,(s->q_bits*s->dim+8)/8); + if(_make_decode_table(s,lengthlist,quantvals,opb,maptype))goto _errout; - if(quantvals&&s->quantlist[quantvals-1]==-1)goto _eofout; + }else{ + /* use dec_type 3: scalar offset into packed value array */ + + s->dec_type=3; + s->dec_nodeb=_determine_node_bytes(s->used_entries,_ilog(s->used_entries-1)/8+1); + s->dec_leafw=_determine_leaf_words(s->dec_nodeb,_ilog(s->used_entries-1)/8+1); + if(_make_decode_table(s,lengthlist,quantvals,opb,maptype))goto _errout; + + /* get the vals & pack them */ + s->q_pack=(s->q_bits+7)/8*s->dim; + s->q_val=_tremor_ogg_malloc(s->q_pack*s->used_entries); + + if(s->q_bits<=8){ + for(i=0;iused_entries*s->dim;i++) + ((unsigned char *)(s->q_val))[i]=tremor_oggpack_read(opb,s->q_bits); + }else{ + for(i=0;iused_entries*s->dim;i++) + ((tremor_ogg_uint16_t *)(s->q_val))[i]=tremor_oggpack_read(opb,s->q_bits); + } } break; default: goto _errout; } - /* all set */ - return(s); - + if(tremor_oggpack_eop(opb))goto _eofout; + + return 0; _errout: _eofout: - vorbis_staticbook_destroy(s); - return(NULL); + vorbis_book_clear(s); + return -1; } -/* the 'eliminate the decode tree' optimization actually requires the - codewords to be MSb first, not LSb. This is an annoying inelegancy - (and one of the first places where carefully thought out design - turned out to be wrong; Vorbis II and future Ogg codecs should go - to an MSb bitpacker), but not actually the huge hit it appears to - be. The first-stage decode table catches most words so that - bitreverse is not in the main execution path. */ - -static ogg_uint32_t bitreverse(ogg_uint32_t x){ - x= ((x>>16)&0x0000ffff) | ((x<<16)&0xffff0000); - x= ((x>> 8)&0x00ff00ff) | ((x<< 8)&0xff00ff00); - x= ((x>> 4)&0x0f0f0f0f) | ((x<< 4)&0xf0f0f0f0); - x= ((x>> 2)&0x33333333) | ((x<< 2)&0xcccccccc); - return((x>> 1)&0x55555555) | ((x<< 1)&0xaaaaaaaa); -} - -STIN long decode_packed_entry_number(codebook *book, - oggpack_buffer *b){ +static inline tremor_ogg_uint32_t decode_packed_entry_number(codebook *book, + tremor_oggpack_buffer *b){ + tremor_ogg_uint32_t chase=0; int read=book->dec_maxlength; - long lo,hi; - long lok = oggpack_look(b,book->dec_firsttablen); - - if (lok >= 0) { - long entry = book->dec_firsttable[lok]; - if(entry&0x80000000UL){ - lo=(entry>>15)&0x7fff; - hi=book->used_entries-(entry&0x7fff); - }else{ - oggpack_adv(b, book->dec_codelengths[entry-1]); - return(entry-1); - } - }else{ - lo=0; - hi=book->used_entries; - } - - lok = oggpack_look(b, read); - + long lok = tremor_oggpack_look(b,read),i; + while(lok<0 && read>1) - lok = oggpack_look(b, --read); + lok = tremor_oggpack_look(b, --read); if(lok<0){ - oggpack_adv(b,1); /* force eop */ + tremor_oggpack_adv(b,1); /* force eop */ return -1; } - /* bisect search for the codeword in the ordered list */ - { - ogg_uint32_t testword=bitreverse((ogg_uint32_t)lok); + /* chase the tree with the bits we got */ + if(book->dec_nodeb==1){ + if(book->dec_leafw==1){ + + /* 8/8 */ + unsigned char *t=(unsigned char *)book->dec_table; + for(i=0;i>i)&1)]; + if(chase&0x80UL)break; + } + chase&=0x7fUL; - while(hi-lo>1){ - long p=(hi-lo)>>1; - long test=book->codelist[lo+p]>testword; - lo+=p&(test-1); - hi-=p&(-test); + }else{ + + /* 8/16 */ + unsigned char *t=(unsigned char *)book->dec_table; + for(i=0;i>i)&1; + int next=t[chase+bit]; + if(next&0x80){ + chase= (next<<8) | t[chase+bit+1+(!bit || t[chase]&0x80)]; + break; + } + chase=next; + } + chase&=0x7fffUL; } - if(book->dec_codelengths[lo]<=read){ - oggpack_adv(b, book->dec_codelengths[lo]); - return(lo); + }else{ + if(book->dec_nodeb==2){ + if(book->dec_leafw==1){ + + /* 16/16 */ + for(i=0;idec_table))[chase*2+((lok>>i)&1)]; + if(chase&0x8000UL)break; + } + chase&=0x7fffUL; + + }else{ + + /* 16/32 */ + tremor_ogg_uint16_t *t=(tremor_ogg_uint16_t *)book->dec_table; + for(i=0;i>i)&1; + int next=t[chase+bit]; + if(next&0x8000){ + chase= (next<<16) | t[chase+bit+1+(!bit || t[chase]&0x8000)]; + break; + } + chase=next; + } + chase&=0x7fffffffUL; + } + + }else{ + + for(i=0;idec_table))[chase*2+((lok>>i)&1)]; + if(chase&0x80000000UL)break; + } + chase&=0x7fffffffUL; + } } - oggpack_adv(b, read+1); + if(idec_type)return -1; + return decode_packed_entry_number(book,b); +} + +int decode_map(codebook *s, tremor_oggpack_buffer *b, tremor_ogg_int32_t *v, int point){ + tremor_ogg_uint32_t entry = decode_packed_entry_number(s,b); + int i; + if(tremor_oggpack_eop(b))return(-1); + + /* according to decode type */ + switch(s->dec_type){ + case 1:{ + /* packed vector of values */ + int mask=(1<q_bits)-1; + for(i=0;idim;i++){ + v[i]=entry&mask; + entry>>=s->q_bits; + } + break; + } + case 2:{ + /* packed vector of column offsets */ + int mask=(1<q_pack)-1; + for(i=0;idim;i++){ + if(s->q_bits<=8) + v[i]=((unsigned char *)(s->q_val))[entry&mask]; + else + v[i]=((tremor_ogg_uint16_t *)(s->q_val))[entry&mask]; + entry>>=s->q_pack; + } + break; + } + case 3:{ + /* offset into array */ + void *ptr=s->q_val+entry*s->q_pack; - Cascades may be additive or multiplicitive; this is not inherent in - the codebook, but set in the code using the codebook. Like - interleaving, it's easiest to do it here. - addmul==0 -> declarative (set the value) - addmul==1 -> additive - addmul==2 -> multiplicitive */ + if(s->q_bits<=8){ + for(i=0;idim;i++) + v[i]=((unsigned char *)ptr)[i]; + }else{ + for(i=0;idim;i++) + v[i]=((tremor_ogg_uint16_t *)ptr)[i]; + } + break; + } + default: + return -1; + } -/* returns the [original, not compacted] entry number or -1 on eof *********/ -long vorbis_book_decode(codebook *book, oggpack_buffer *b){ - if(book->used_entries>0){ - long packed_entry=decode_packed_entry_number(book,b); - if(packed_entry>=0) - return(book->dec_index[packed_entry]); + /* we have the unpacked multiplicands; compute final vals */ + { + int shiftM=point-s->q_delp; + tremor_ogg_int32_t add=point-s->q_minp; + if(add>0) + add= s->q_min >> add; + else + add= s->q_min << -add; + + if(shiftM>0) + for(i=0;idim;i++) + v[i]= add + ((v[i] * s->q_del) >> shiftM); + else + for(i=0;idim;i++) + v[i]= add + ((v[i] * s->q_del) << -shiftM); + + if(s->q_seq) + for(i=1;idim;i++) + v[i]+=v[i-1]; } - /* if there's no dec_index, the codebook unpacking isn't collapsed */ - return(-1); + return 0; } /* returns 0 on OK or -1 on eof *************************************/ -/* decode vector / dim granularity gaurding is done in the upper layer */ -long vorbis_book_decodevs_add(codebook *book,ogg_int32_t *a, - oggpack_buffer *b,int n,int point){ - if(book->used_entries>0){ +/* decode vector / dim granularity guarding is done in the upper layer */ +long vorbis_book_decodevs_add(codebook *book,tremor_ogg_int32_t *a, + tremor_oggpack_buffer *b,int n,int point){ + if(book->used_entries>0){ int step=n/book->dim; - long *entry = (long *)alloca(sizeof(*entry)*step); - ogg_int32_t **t = (ogg_int32_t **)alloca(sizeof(*t)*step); + tremor_ogg_int32_t *v = (tremor_ogg_int32_t *)alloca(sizeof(*v)*book->dim); int i,j,o; - int shift=point-book->binarypoint; - if(shift>=0){ - for (i = 0; i < step; i++) { - entry[i]=decode_packed_entry_number(book,b); - if(entry[i]==-1)return(-1); - t[i] = book->valuelist+entry[i]*book->dim; - } - for(i=0,o=0;idim;i++,o+=step) - for (j=0;o+j>shift; - }else{ - for (i = 0; i < step; i++) { - entry[i]=decode_packed_entry_number(book,b); - if(entry[i]==-1)return(-1); - t[i] = book->valuelist+entry[i]*book->dim; - } - for(i=0,o=0;idim;i++,o+=step) - for (j=0;o+jdim;i++,o+=step) + a[o]+=v[i]; } } - return(0); + return 0; } -/* decode vector / dim granularity gaurding is done in the upper layer */ -long vorbis_book_decodev_add(codebook *book,ogg_int32_t *a, - oggpack_buffer *b,int n,int point){ +/* decode vector / dim granularity guarding is done in the upper layer */ +long vorbis_book_decodev_add(codebook *book,tremor_ogg_int32_t *a, + tremor_oggpack_buffer *b,int n,int point){ if(book->used_entries>0){ - int i,j,entry; - ogg_int32_t *t; - int shift=point-book->binarypoint; + tremor_ogg_int32_t *v = (tremor_ogg_int32_t *)alloca(sizeof(*v)*book->dim); + int i,j; - if(shift>=0){ - for(i=0;ivaluelist+entry*book->dim; - for (j=0;idim;) - a[i++]+=t[j++]>>shift; - } - }else{ - for(i=0;ivaluelist+entry*book->dim; - for (j=0;idim;) - a[i++]+=t[j++]<<-shift; - } + for(i=0;idim;j++) + a[i++]+=v[j]; } } - return(0); + return 0; } /* unlike the others, we guard against n not being an integer number - of internally rather than in the upper layer (called only by - floor0) */ -long vorbis_book_decodev_set(codebook *book,ogg_int32_t *a, - oggpack_buffer *b,int n,int point){ + * of internally rather than in the upper layer (called only by + * floor0) */ +long vorbis_book_decodev_set(codebook *book,tremor_ogg_int32_t *a, + tremor_oggpack_buffer *b,int n,int point){ if(book->used_entries>0){ - int i,j,entry; - ogg_int32_t *t; - int shift=point-book->binarypoint; + tremor_ogg_int32_t *v = (tremor_ogg_int32_t *)alloca(sizeof(*v)*book->dim); + int i,j; - if(shift>=0){ - - for(i=0;ivaluelist+entry*book->dim; - for (j=0;idim;){ - a[i++]=t[j++]>>shift; - } - } - }else{ - - for(i=0;ivaluelist+entry*book->dim; - for (j=0;idim;){ - a[i++]=t[j++]<<-shift; - } - } + for(i=0;idim;j++) + a[i++]=v[j]; } }else{ - - int i,j; + int i; + for(i=0;iused_entries>0){ - long i,j,entry; + + tremor_ogg_int32_t *v = (tremor_ogg_int32_t *)alloca(sizeof(*v)*book->dim); + long i,j; int chptr=0; - int shift=point-book->binarypoint; - int m=offset+n; - if(shift>=0){ - - for(i=offset;ivaluelist+entry*book->dim; - for (j=0;idim;j++){ - a[chptr++][i]+=t[j]>>shift; - if(chptr==ch){ - chptr=0; - i++; - } - } - } - } - }else{ - - for(i=offset;ivaluelist+entry*book->dim; - for (j=0;idim;j++){ - a[chptr++][i]+=t[j]<<-shift; - if(chptr==ch){ - chptr=0; - i++; - } - } + long m=offset+n; + + for(i=offset;idim;j++){ + a[chptr++][i]+=v[j]; + if(chptr==ch){ + chptr=0; + i++; } } } } - return(0); + + return 0; } diff --git a/lib/tremor/codebook.h b/lib/tremor/codebook.h index bb139426..a32f0f7a 100644 --- a/lib/tremor/codebook.h +++ b/lib/tremor/codebook.h @@ -1,12 +1,12 @@ /******************************************************************** * * - * THIS FILE IS PART OF THE OggVorbis 'TREMOR' CODEC SOURCE CODE. * + * THIS FILE IS PART OF THE TremorOggVorbis 'TREMOR' CODEC SOURCE CODE. * * * * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS * * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE * * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. * * * - * THE OggVorbis 'TREMOR' SOURCE CODE IS (C) COPYRIGHT 1994-2002 * + * THE TremorOggVorbis 'TREMOR' SOURCE CODE IS (C) COPYRIGHT 1994-2002 * * BY THE Xiph.Org FOUNDATION http://www.xiph.org/ * * * ******************************************************************** @@ -18,82 +18,46 @@ #ifndef _V_CODEBOOK_H_ #define _V_CODEBOOK_H_ -#include - -/* This structure encapsulates huffman and VQ style encoding books; it - doesn't do anything specific to either. - - valuelist/quantlist are nonNULL (and q_* significant) only if - there's entry->value mapping to be done. - - If encode-side mapping must be done (and thus the entry needs to be - hunted), the auxiliary encode pointer will point to a decision - tree. This is true of both VQ and huffman, but is mostly useful - with VQ. - -*/ - -typedef struct static_codebook{ - long dim; /* codebook dimensions (elements per vector) */ - long entries; /* codebook entries */ - long *lengthlist; /* codeword lengths in bits */ - - /* mapping ***************************************************************/ - int maptype; /* 0=none - 1=implicitly populated values from map column - 2=listed arbitrary values */ - - /* The below does a linear, single monotonic sequence mapping. */ - long q_min; /* packed 32 bit float; quant value 0 maps to minval */ - long q_delta; /* packed 32 bit float; val 1 - val 0 == delta */ - int q_quant; /* bits: 0 < quant <= 16 */ - int q_sequencep; /* bitflag */ - - long *quantlist; /* map == 1: (int)(entries^(1/dim)) element column map - map == 2: list of dim*entries quantized entry vals - */ -} static_codebook; +#include "tremor_ogg.h" typedef struct codebook{ - long dim; /* codebook dimensions (elements per vector) */ - long entries; /* codebook entries */ - long used_entries; /* populated codebook entries */ - - /* the below are ordered by bitreversed codeword and only used - entries are populated */ - int binarypoint; - ogg_int32_t *valuelist; /* list of dim*entries actual entry values */ - ogg_uint32_t *codelist; /* list of bitstream codewords for each entry */ - - int *dec_index; - char *dec_codelengths; - ogg_uint32_t *dec_firsttable; - int dec_firsttablen; - int dec_maxlength; - - long q_min; /* packed 32 bit float; quant value 0 maps to minval */ - long q_delta; /* packed 32 bit float; val 1 - val 0 == delta */ + long dim; /* codebook dimensions (elements per vector) */ + long entries; /* codebook entries */ + long used_entries; /* populated codebook entries */ + + int dec_maxlength; + void *dec_table; + int dec_nodeb; + int dec_leafw; + int dec_type; /* 0 = entry number + 1 = packed vector of values + 2 = packed vector of column offsets, maptype 1 + 3 = scalar offset into value array, maptype 2 */ + + tremor_ogg_int32_t q_min; + int q_minp; + tremor_ogg_int32_t q_del; + int q_delp; + int q_seq; + int q_bits; + int q_pack; + void *q_val; } codebook; -extern void vorbis_staticbook_destroy(static_codebook *b); -extern int vorbis_book_init_decode(codebook *dest,const static_codebook *source); - extern void vorbis_book_clear(codebook *b); -extern long _book_maptype1_quantvals(const static_codebook *b); - -extern static_codebook *vorbis_staticbook_unpack(oggpack_buffer *b); - -extern long vorbis_book_decode(codebook *book, oggpack_buffer *b); -extern long vorbis_book_decodevs_add(codebook *book, ogg_int32_t *a, - oggpack_buffer *b,int n,int point); -extern long vorbis_book_decodev_set(codebook *book, ogg_int32_t *a, - oggpack_buffer *b,int n,int point); -extern long vorbis_book_decodev_add(codebook *book, ogg_int32_t *a, - oggpack_buffer *b,int n,int point); -extern long vorbis_book_decodevv_add(codebook *book, ogg_int32_t **a, +extern int vorbis_book_unpack(tremor_oggpack_buffer *b,codebook *c); + +extern long vorbis_book_decode(codebook *book, tremor_oggpack_buffer *b); +extern long vorbis_book_decodevs_add(codebook *book, tremor_ogg_int32_t *a, + tremor_oggpack_buffer *b,int n,int point); +extern long vorbis_book_decodev_set(codebook *book, tremor_ogg_int32_t *a, + tremor_oggpack_buffer *b,int n,int point); +extern long vorbis_book_decodev_add(codebook *book, tremor_ogg_int32_t *a, + tremor_oggpack_buffer *b,int n,int point); +extern long vorbis_book_decodevv_add(codebook *book, tremor_ogg_int32_t **a, long off,int ch, - oggpack_buffer *b,int n,int point); + tremor_oggpack_buffer *b,int n,int point); extern int _ilog(unsigned int v); diff --git a/lib/tremor/codec_internal.h b/lib/tremor/codec_internal.h index 3ca7f547..f9a768bb 100644 --- a/lib/tremor/codec_internal.h +++ b/lib/tremor/codec_internal.h @@ -1,12 +1,12 @@ /******************************************************************** * * - * THIS FILE IS PART OF THE OggVorbis 'TREMOR' CODEC SOURCE CODE. * + * THIS FILE IS PART OF THE TremorOggVorbis 'TREMOR' CODEC SOURCE CODE. * * * * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS * * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE * * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. * * * - * THE OggVorbis 'TREMOR' SOURCE CODE IS (C) COPYRIGHT 1994-2002 * + * THE TremorOggVorbis 'TREMOR' SOURCE CODE IS (C) COPYRIGHT 1994-2003 * * BY THE Xiph.Org FOUNDATION http://www.xiph.org/ * * * ******************************************************************** @@ -18,36 +18,149 @@ #ifndef _V_CODECI_H_ #define _V_CODECI_H_ +#define CHUNKSIZE 1024 + #include "codebook.h" +#include "ivorbiscodec.h" + +#define VI_TRANSFORMB 1 +#define VI_WINDOWB 1 +#define VI_TIMEB 1 +#define VI_FLOORB 2 +#define VI_RESB 3 +#define VI_MAPB 1 -typedef void vorbis_look_mapping; -typedef void vorbis_look_floor; -typedef void vorbis_look_residue; -typedef void vorbis_look_transform; +typedef void vorbis_info_floor; + +/* vorbis_dsp_state buffers the current vorbis audio + analysis/synthesis state. The DSP state belongs to a specific + logical bitstream ****************************************************/ +struct vorbis_dsp_state{ + vorbis_info *vi; + tremor_oggpack_buffer opb; + + tremor_ogg_int32_t **work; + tremor_ogg_int32_t **mdctright; + int out_begin; + int out_end; + + long lW; + long W; + + tremor_ogg_int64_t granulepos; + tremor_ogg_int64_t sequence; + tremor_ogg_int64_t sample_count; + +}; + + +/* Floor backend generic *****************************************/ + +extern vorbis_info_floor *floor0_info_unpack(vorbis_info *,tremor_oggpack_buffer *); +extern void floor0_free_info(vorbis_info_floor *); +extern int floor0_memosize(vorbis_info_floor *); +extern tremor_ogg_int32_t *floor0_inverse1(struct vorbis_dsp_state *, + vorbis_info_floor *,tremor_ogg_int32_t *); +extern int floor0_inverse2 (struct vorbis_dsp_state *,vorbis_info_floor *, + tremor_ogg_int32_t *buffer,tremor_ogg_int32_t *); + +extern vorbis_info_floor *floor1_info_unpack(vorbis_info *,tremor_oggpack_buffer *); +extern void floor1_free_info(vorbis_info_floor *); +extern int floor1_memosize(vorbis_info_floor *); +extern tremor_ogg_int32_t *floor1_inverse1(struct vorbis_dsp_state *, + vorbis_info_floor *,tremor_ogg_int32_t *); +extern int floor1_inverse2 (struct vorbis_dsp_state *,vorbis_info_floor *, + tremor_ogg_int32_t *buffer,tremor_ogg_int32_t *); + +typedef struct{ + int order; + long rate; + long barkmap; + + int ampbits; + int ampdB; + + int numbooks; /* <= 16 */ + char books[16]; + +} vorbis_info_floor0; + +typedef struct{ + char class_dim; /* 1 to 8 */ + char class_subs; /* 0,1,2,3 (bits: 1<= 1.0, HAVE_OGG=yes, HAVE_OGG=no) -fi -if test "x$HAVE_OGG" = "xno" -then - dnl fall back to the old school test - XIPH_PATH_OGG(, AC_MSG_ERROR(must have Ogg installed!)) - libs_save=$LIBS - LIBS="$OGG_LIBS" - AC_CHECK_FUNC(oggpack_writealign, , AC_MSG_ERROR(Ogg >= 1.0 required !)) - LIBS=$libs_save -fi - dnl -------------------------------------------------- dnl Check for library functions dnl -------------------------------------------------- diff --git a/lib/tremor/dsp.c b/lib/tremor/dsp.c new file mode 100644 index 00000000..35a82d66 --- /dev/null +++ b/lib/tremor/dsp.c @@ -0,0 +1,298 @@ +/******************************************************************** + * * + * THIS FILE IS PART OF THE TremorOggVorbis 'TREMOR' CODEC SOURCE CODE. * + * * + * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS * + * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE * + * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. * + * * + * THE TremorOggVorbis 'TREMOR' SOURCE CODE IS (C) COPYRIGHT 1994-2003 * + * BY THE Xiph.Org FOUNDATION http://www.xiph.org/ * + * * + ******************************************************************** + + function: PCM data vector blocking, windowing and dis/reassembly + + ********************************************************************/ + +#include +#include "tremor_ogg.h" +#include "mdct.h" +#include "ivorbiscodec.h" +#include "codec_internal.h" +#include "misc.h" +#include "window_lookup.h" + +int vorbis_dsp_restart(vorbis_dsp_state *v){ + if(!v)return -1; + { + vorbis_info *vi=v->vi; + codec_setup_info *ci; + + if(!vi)return -1; + ci=vi->codec_setup; + if(!ci)return -1; + + v->out_end=-1; + v->out_begin=-1; + + v->granulepos=-1; + v->sequence=-1; + v->sample_count=-1; + } + return 0; +} + +vorbis_dsp_state *vorbis_dsp_create(vorbis_info *vi){ + int i; + + vorbis_dsp_state *v=_tremor_ogg_calloc(1,sizeof(*v)); + codec_setup_info *ci=(codec_setup_info *)vi->codec_setup; + + v->vi=vi; + + v->work=(tremor_ogg_int32_t **)_tremor_ogg_malloc(vi->channels*sizeof(*v->work)); + v->mdctright=(tremor_ogg_int32_t **)_tremor_ogg_malloc(vi->channels*sizeof(*v->mdctright)); + for(i=0;ichannels;i++){ + v->work[i]=(tremor_ogg_int32_t *)_tremor_ogg_calloc(1,(ci->blocksizes[1]>>1)* + sizeof(*v->work[i])); + v->mdctright[i]=(tremor_ogg_int32_t *)_tremor_ogg_calloc(1,(ci->blocksizes[1]>>2)* + sizeof(*v->mdctright[i])); + } + + v->lW=0; /* previous window size */ + v->W=0; /* current window size */ + + vorbis_dsp_restart(v); + return v; +} + +void vorbis_dsp_destroy(vorbis_dsp_state *v){ + int i; + if(v){ + vorbis_info *vi=v->vi; + + if(v->work){ + for(i=0;ichannels;i++) + if(v->work[i])_tremor_ogg_free(v->work[i]); + _tremor_ogg_free(v->work); + } + if(v->mdctright){ + for(i=0;ichannels;i++) + if(v->mdctright[i])_tremor_ogg_free(v->mdctright[i]); + _tremor_ogg_free(v->mdctright); + } + + _tremor_ogg_free(v); + } +} + +static LOOKUP_T *_vorbis_window(int left){ + switch(left){ + case 32: + return vwin64; + case 64: + return vwin128; + case 128: + return vwin256; + case 256: + return vwin512; + case 512: + return vwin1024; + case 1024: + return vwin2048; + case 2048: + return vwin4096; +#ifndef LIMIT_TO_64kHz + case 4096: + return vwin8192; +#endif + default: + return(0); + } +} + +/* pcm==0 indicates we just want the pending samples, no more */ +int vorbis_dsp_pcmout(vorbis_dsp_state *v,tremor_ogg_int16_t *pcm,int samples){ + vorbis_info *vi=v->vi; + codec_setup_info *ci=(codec_setup_info *)vi->codec_setup; + if(v->out_begin>-1 && v->out_beginout_end){ + int n=v->out_end-v->out_begin; + if(pcm){ + int i; + if(n>samples)n=samples; + for(i=0;ichannels;i++) + mdct_unroll_lap(ci->blocksizes[0],ci->blocksizes[1], + v->lW,v->W,v->work[i],v->mdctright[i], + _vorbis_window(ci->blocksizes[0]>>1), + _vorbis_window(ci->blocksizes[1]>>1), + pcm+i,vi->channels, + v->out_begin,v->out_begin+n); + } + return(n); + } + return(0); +} + +int vorbis_dsp_read(vorbis_dsp_state *v,int s){ + if(s && v->out_begin+s>v->out_end)return(OV_EINVAL); + v->out_begin+=s; + return(0); +} + +long vorbis_packet_blocksize(vorbis_info *vi,tremor_ogg_packet *op){ + codec_setup_info *ci=(codec_setup_info *)vi->codec_setup; + tremor_oggpack_buffer opb; + int mode; + int modebits=0; + int v=ci->modes; + + tremor_oggpack_readinit(&opb,op->packet); + + /* Check the packet type */ + if(tremor_oggpack_read(&opb,1)!=0){ + /* Oops. This is not an audio data packet */ + return(OV_ENOTAUDIO); + } + + while(v>1){ + modebits++; + v>>=1; + } + + /* read our mode and pre/post windowsize */ + mode=tremor_oggpack_read(&opb,modebits); + if(mode==-1)return(OV_EBADPACKET); + return(ci->blocksizes[ci->mode_param[mode].blockflag]); +} + + +static int ilog(tremor_ogg_uint32_t v){ + int ret=0; + if(v)--v; + while(v){ + ret++; + v>>=1; + } + return(ret); +} + +int vorbis_dsp_synthesis(vorbis_dsp_state *vd,tremor_ogg_packet *op,int decodep){ + vorbis_info *vi=vd->vi; + codec_setup_info *ci=(codec_setup_info *)vi->codec_setup; + int mode,i; + + tremor_oggpack_readinit(&vd->opb,op->packet); + + /* Check the packet type */ + if(tremor_oggpack_read(&vd->opb,1)!=0){ + /* Oops. This is not an audio data packet */ + return OV_ENOTAUDIO ; + } + + /* read our mode and pre/post windowsize */ + mode=tremor_oggpack_read(&vd->opb,ilog(ci->modes)); + if(mode==-1 || mode>=ci->modes) return OV_EBADPACKET; + + /* shift information we still need from last window */ + vd->lW=vd->W; + vd->W=ci->mode_param[mode].blockflag; + for(i=0;ichannels;i++) + mdct_shift_right(ci->blocksizes[vd->lW],vd->work[i],vd->mdctright[i]); + + if(vd->W){ + int temp; + tremor_oggpack_read(&vd->opb,1); + temp=tremor_oggpack_read(&vd->opb,1); + if(temp==-1) return OV_EBADPACKET; + } + + /* packet decode and portions of synthesis that rely on only this block */ + if(decodep){ + mapping_inverse(vd,ci->map_param+ci->mode_param[mode].mapping); + + if(vd->out_begin==-1){ + vd->out_begin=0; + vd->out_end=0; + }else{ + vd->out_begin=0; + vd->out_end=ci->blocksizes[vd->lW]/4+ci->blocksizes[vd->W]/4; + } + } + + /* track the frame number... This is for convenience, but also + making sure our last packet doesn't end with added padding. + + This is not foolproof! It will be confused if we begin + decoding at the last page after a seek or hole. In that case, + we don't have a starting point to judge where the last frame + is. For this reason, vorbisfile will always try to make sure + it reads the last two marked pages in proper sequence */ + + /* if we're out of sequence, dump granpos tracking until we sync back up */ + if(vd->sequence==-1 || vd->sequence+1 != op->packetno-3){ + /* out of sequence; lose count */ + vd->granulepos=-1; + vd->sample_count=-1; + } + + vd->sequence=op->packetno; + vd->sequence=vd->sequence-3; + + if(vd->sample_count==-1){ + vd->sample_count=0; + }else{ + vd->sample_count+= + ci->blocksizes[vd->lW]/4+ci->blocksizes[vd->W]/4; + } + + if(vd->granulepos==-1){ + if(op->granulepos!=-1){ /* only set if we have a + position to set to */ + + vd->granulepos=op->granulepos; + + /* is this a short page? */ + if(vd->sample_count>vd->granulepos){ + /* corner case; if this is both the first and last audio page, + then spec says the end is cut, not beginning */ + if(op->e_o_s){ + /* trim the end */ + /* no preceeding granulepos; assume we started at zero (we'd + have to in a short single-page stream) */ + /* granulepos could be -1 due to a seek, but that would result + in a long coun t, not short count */ + + vd->out_end-=vd->sample_count-vd->granulepos; + }else{ + /* trim the beginning */ + vd->out_begin+=vd->sample_count-vd->granulepos; + if(vd->out_begin>vd->out_end) + vd->out_begin=vd->out_end; + } + + } + + } + }else{ + vd->granulepos+= + ci->blocksizes[vd->lW]/4+ci->blocksizes[vd->W]/4; + if(op->granulepos!=-1 && vd->granulepos!=op->granulepos){ + + if(vd->granulepos>op->granulepos){ + long extra=vd->granulepos-op->granulepos; + + if(extra) + if(op->e_o_s){ + /* partial last frame. Strip the extra samples off */ + vd->out_end-=extra; + } /* else {Shouldn't happen *unless* the bitstream is out of + spec. Either way, believe the bitstream } */ + } /* else {Shouldn't happen *unless* the bitstream is out of + spec. Either way, believe the bitstream } */ + vd->granulepos=op->granulepos; + } + } + + return(0); +} diff --git a/lib/tremor/floor0.c b/lib/tremor/floor0.c index 964383ef..9e4a1a30 100644 --- a/lib/tremor/floor0.c +++ b/lib/tremor/floor0.c @@ -1,12 +1,12 @@ /******************************************************************** * * - * THIS FILE IS PART OF THE OggVorbis 'TREMOR' CODEC SOURCE CODE. * + * THIS FILE IS PART OF THE TremorOggVorbis 'TREMOR' CODEC SOURCE CODE. * * * * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS * * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE * * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. * * * - * THE OggVorbis 'TREMOR' SOURCE CODE IS (C) COPYRIGHT 1994-2002 * + * THE TremorOggVorbis 'TREMOR' SOURCE CODE IS (C) COPYRIGHT 1994-2003 * * BY THE Xiph.Org FOUNDATION http://www.xiph.org/ * * * ******************************************************************** @@ -18,26 +18,15 @@ #include #include #include -#include +#include "tremor_ogg.h" #include "ivorbiscodec.h" #include "codec_internal.h" -#include "registry.h" #include "codebook.h" #include "misc.h" -#include "block.h" +#include "os.h" #define LSP_FRACBITS 14 - -typedef struct { - long n; - int ln; - int m; - int *linearmap; - - vorbis_info_floor0 *vi; - ogg_int32_t *lsp_look; - -} vorbis_look_floor0; +extern const tremor_ogg_int32_t FLOOR_fromdB_LOOKUP[]; /*************** LSP decode ********************/ @@ -48,7 +37,7 @@ typedef struct { returns in m.8 format */ static long ADJUST_SQRT2[2]={8192,5792}; -STIN ogg_int32_t vorbis_invsqlook_i(long a,long e){ +static inline tremor_ogg_int32_t vorbis_invsqlook_i(long a,long e){ long i=(a&0x7fff)>>(INVSQ_LOOKUP_I_SHIFT-1); long d=a&INVSQ_LOOKUP_I_MASK; /* 0.10 */ long val=INVSQ_LOOKUP_I[i]- /* 1.16 */ @@ -60,60 +49,60 @@ STIN ogg_int32_t vorbis_invsqlook_i(long a,long e){ /* interpolated lookup based fromdB function, domain -140dB to 0dB only */ /* a is in n.12 format */ -STIN ogg_int32_t vorbis_fromdBlook_i(long a){ - int i=(-a)>>(12-FROMdB2_SHIFT); - if(i<0) return 0x7fffffff; - if(i>=(FROMdB_LOOKUP_SZ<>FROMdB_SHIFT] * FROMdB2_LOOKUP[i&FROMdB2_MASK]; +#ifdef _LOW_ACCURACY_ +static inline tremor_ogg_int32_t vorbis_fromdBlook_i(long a){ + if(a>0) return 0x7fffffff; + if(a<(-140<<12)) return 0; + return FLOOR_fromdB_LOOKUP[((a+140)*467)>>20]<<9; +} +#else +static inline tremor_ogg_int32_t vorbis_fromdBlook_i(long a){ + if(a>0) return 0x7fffffff; + if(a<(-140<<12)) return 0; + return FLOOR_fromdB_LOOKUP[((a+(140<<12))*467)>>20]; } +#endif /* interpolated lookup based cos function, domain 0 to PI only */ /* a is in 0.16 format, where 0==0, 2^^16-1==PI, return 0.14 */ -STIN ogg_int32_t vorbis_coslook_i(long a){ +static inline tremor_ogg_int32_t vorbis_coslook_i(long a){ int i=a>>COS_LOOKUP_I_SHIFT; int d=a&COS_LOOKUP_I_MASK; return COS_LOOKUP_I[i]- ((d*(COS_LOOKUP_I[i]-COS_LOOKUP_I[i+1]))>> COS_LOOKUP_I_SHIFT); } -/* interpolated lookup based cos function */ +/* interpolated half-wave lookup based cos function */ /* a is in 0.16 format, where 0==0, 2^^16==PI, return .LSP_FRACBITS */ -STIN ogg_int32_t vorbis_coslook2_i(long a){ - a=a&0x1ffff; - - if(a>0x10000)a=0x20000-a; - { - int i=a>>COS_LOOKUP_I_SHIFT; - int d=a&COS_LOOKUP_I_MASK; - a=((COS_LOOKUP_I[i]<> - (COS_LOOKUP_I_SHIFT-LSP_FRACBITS+14); - } - - return(a); +static inline tremor_ogg_int32_t vorbis_coslook2_i(long a){ + int i=a>>COS_LOOKUP_I_SHIFT; + int d=a&COS_LOOKUP_I_MASK; + return ((COS_LOOKUP_I[i]<> + (COS_LOOKUP_I_SHIFT-LSP_FRACBITS+14); } -static const int barklook[28]={ - 0,100,200,301, 405,516,635,766, - 912,1077,1263,1476, 1720,2003,2333,2721, - 3184,3742,4428,5285, 6376,7791,9662,12181, - 15624,20397,27087,36554 +static const tremor_ogg_uint16_t barklook[54]={ + 0,51,102,154, 206,258,311,365, + 420,477,535,594, 656,719,785,854, + 926,1002,1082,1166, 1256,1352,1454,1564, + 1683,1812,1953,2107, 2276,2463,2670,2900, + 3155,3440,3756,4106, 4493,4919,5387,5901, + 6466,7094,7798,8599, 9528,10623,11935,13524, + 15453,17775,20517,23667, 27183,31004 }; /* used in init only; interpolate the long way */ -STIN ogg_int32_t toBARK(int n){ +static inline tremor_ogg_int32_t toBARK(int n){ int i; - for(i=0;i<27;i++) + for(i=0;i<54;i++) if(n>=barklook[i] && n>17); } } @@ -133,11 +122,11 @@ static const unsigned char MLOOP_2[64]={ static const unsigned char MLOOP_3[8]={0,1,2,2,3,3,3,3}; -void vorbis_lsp_to_curve(ogg_int32_t *curve,int *map,int n,int ln, - ogg_int32_t *lsp,int m, - ogg_int32_t amp, - ogg_int32_t ampoffset, - ogg_int32_t *icos){ +void vorbis_lsp_to_curve(tremor_ogg_int32_t *curve,int n,int ln, + tremor_ogg_int32_t *lsp,int m, + tremor_ogg_int32_t amp, + tremor_ogg_int32_t ampoffset, + tremor_ogg_int32_t nyq){ /* 0 <= m < 256 */ @@ -145,13 +134,34 @@ void vorbis_lsp_to_curve(ogg_int32_t *curve,int *map,int n,int ln, int i; int ampoffseti=ampoffset*4096; int ampi=amp; - ogg_int32_t *ilsp=(ogg_int32_t *)alloca(m*sizeof(*ilsp)); + tremor_ogg_int32_t *ilsp=(tremor_ogg_int32_t *)alloca(m*sizeof(*ilsp)); + + tremor_ogg_uint32_t inyq= (1UL<<31) / toBARK(nyq); + tremor_ogg_uint32_t imap= (1UL<<31) / ln; + tremor_ogg_uint32_t tBnyq1 = toBARK(nyq)<<1; + + /* Besenham for frequency scale to avoid a division */ + int f=0; + int fdx=n; + int fbase=nyq/fdx; + int ferr=0; + int fdy=nyq-fbase*fdx; + int map=0; + +#ifdef _LOW_ACCURACY_ + tremor_ogg_uint32_t nextbark=((tBnyq1<<11)/ln)>>12; +#else + tremor_ogg_uint32_t nextbark=MULT31(imap>>1,tBnyq1); +#endif + int nextf=barklook[nextbark>>14]+(((nextbark&0x3fff)* + (barklook[(nextbark>>14)+1]-barklook[nextbark>>14]))>>14); + /* lsp is in 8.24, range 0 to PI; coslook wants it in .16 0 to 1*/ for(i=0;i>10)*0x517d)>>14; + tremor_ogg_int32_t val=((lsp[i]>>10)*0x517d)>>14; #endif /* safeguard against a malicious stream */ @@ -165,11 +175,14 @@ void vorbis_lsp_to_curve(ogg_int32_t *curve,int *map,int n,int ln, i=0; while(i>15); + #ifdef _V_LSP_MATH_ASM lsp_loop_asm(&qi,&pi,&qexp,ilsp,wi,m); @@ -197,24 +210,22 @@ void vorbis_lsp_to_curve(ogg_int32_t *curve,int *map,int n,int ln, #else - j=1; - if(m>1){ - qi*=labs(ilsp[0]-wi); - pi*=labs(ilsp[1]-wi); - - for(j+=2;j>25])) - if(!(shift=MLOOP_2[(pi|qi)>>19])) - shift=MLOOP_3[(pi|qi)>>16]; - qi=(qi>>shift)*labs(ilsp[j-1]-wi); - pi=(pi>>shift)*labs(ilsp[j]-wi); - qexp+=shift; - } + qi*=labs(ilsp[0]-wi); + pi*=labs(ilsp[1]-wi); + + for(j=3;j>25])) + if(!(shift=MLOOP_2[(pi|qi)>>19])) + shift=MLOOP_3[(pi|qi)>>16]; + + qi=(qi>>shift)*labs(ilsp[j-1]-wi); + pi=(pi>>shift)*labs(ilsp[j]-wi); + qexp+=shift; } if(!(shift=MLOOP_1[(pi|qi)>>25])) if(!(shift=MLOOP_2[(pi|qi)>>19])) shift=MLOOP_3[(pi|qi)>>16]; - + /* pi,qi normalized collectively, both tracked using qexp */ if(m&1){ @@ -282,54 +293,78 @@ void vorbis_lsp_to_curve(ogg_int32_t *curve,int *map,int n,int ln, amp>>=9; #endif curve[i]= MULT31_SHIFT15(curve[i],amp); - while(map[++i]==k) curve[i]= MULT31_SHIFT15(curve[i],amp); - } -} -/*************** vorbis decode glue ************/ + while(++i=fdx){ + ferr-=fdx; + f++; + } + f+=fbase; + + if(f>=nextf)break; -static void floor0_free_info(vorbis_info_floor *i){ - vorbis_info_floor0 *info=(vorbis_info_floor0 *)i; - if(info){ - memset(info,0,sizeof(*info)); - _ogg_free(info); + curve[i]= MULT31_SHIFT15(curve[i],amp); + } + + while(1){ + map++; + + if(map+1>12; +#else + nextbark=MULT31((map+1)*(imap>>1),tBnyq1); +#endif + nextf=barklook[nextbark>>14]+ + (((nextbark&0x3fff)* + (barklook[(nextbark>>14)+1]-barklook[nextbark>>14]))>>14); + if(f<=nextf)break; + + }else{ + nextf=9999999; + break; + } + } + if(map>=ln){ + map=ln-1; /* guard against the approximation */ + nextf=9999999; + } } } -static void floor0_free_look(vorbis_look_floor *i){ - vorbis_look_floor0 *look=(vorbis_look_floor0 *)i; - if(look){ +/*************** vorbis decode glue ************/ - if(look->linearmap)_ogg_free(look->linearmap); - if(look->lsp_look)_ogg_free(look->lsp_look); - memset(look,0,sizeof(*look)); - _ogg_free(look); - } +void floor0_free_info(vorbis_info_floor *i){ + vorbis_info_floor0 *info=(vorbis_info_floor0 *)i; + if(info)_tremor_ogg_free(info); } -static vorbis_info_floor *floor0_unpack (vorbis_info *vi,oggpack_buffer *opb){ +vorbis_info_floor *floor0_info_unpack (vorbis_info *vi,tremor_oggpack_buffer *opb){ codec_setup_info *ci=(codec_setup_info *)vi->codec_setup; int j; - vorbis_info_floor0 *info=(vorbis_info_floor0 *)_ogg_malloc(sizeof(*info)); - info->order=oggpack_read(opb,8); - info->rate=oggpack_read(opb,16); - info->barkmap=oggpack_read(opb,16); - info->ampbits=oggpack_read(opb,6); - info->ampdB=oggpack_read(opb,8); - info->numbooks=oggpack_read(opb,4)+1; + vorbis_info_floor0 *info=(vorbis_info_floor0 *)_tremor_ogg_malloc(sizeof(*info)); + info->order=tremor_oggpack_read(opb,8); + info->rate=tremor_oggpack_read(opb,16); + info->barkmap=tremor_oggpack_read(opb,16); + info->ampbits=tremor_oggpack_read(opb,6); + info->ampdB=tremor_oggpack_read(opb,8); + info->numbooks=tremor_oggpack_read(opb,4)+1; if(info->order<1)goto err_out; if(info->rate<1)goto err_out; if(info->barkmap<1)goto err_out; - if(info->numbooks<1)goto err_out; for(j=0;jnumbooks;j++){ - info->books[j]=oggpack_read(opb,8); - if(info->books[j]<0 || info->books[j]>=ci->books)goto err_out; - if(ci->book_param[info->books[j]]->maptype==0)goto err_out; - if(ci->book_param[info->books[j]]->dim<1)goto err_out; + info->books[j]=tremor_oggpack_read(opb,8); + if(info->books[j]>=ci->books)goto err_out; } + + if(tremor_oggpack_eop(opb))goto err_out; return(info); err_out: @@ -337,74 +372,34 @@ static vorbis_info_floor *floor0_unpack (vorbis_info *vi,oggpack_buffer *opb){ return(NULL); } -/* initialize Bark scale and normalization lookups. We could do this - with static tables, but Vorbis allows a number of possible - combinations, so it's best to do it computationally. - - The below is authoritative in terms of defining scale mapping. - Note that the scale depends on the sampling rate as well as the - linear block and mapping sizes */ - -static vorbis_look_floor *floor0_look (vorbis_dsp_state *vd,vorbis_info_mode *mi, - vorbis_info_floor *i){ - int j; - vorbis_info *vi=vd->vi; - codec_setup_info *ci=(codec_setup_info *)vi->codec_setup; +int floor0_memosize(vorbis_info_floor *i){ vorbis_info_floor0 *info=(vorbis_info_floor0 *)i; - vorbis_look_floor0 *look=(vorbis_look_floor0 *)_ogg_calloc(1,sizeof(*look)); - look->m=info->order; - look->n=ci->blocksizes[mi->blockflag]/2; - look->ln=info->barkmap; - look->vi=info; - - /* the mapping from a linear scale to a smaller bark scale is - straightforward. We do *not* make sure that the linear mapping - does not skip bark-scale bins; the decoder simply skips them and - the encoder may do what it wishes in filling them. They're - necessary in some mapping combinations to keep the scale spacing - accurate */ - look->linearmap=(int *)_ogg_malloc((look->n+1)*sizeof(*look->linearmap)); - for(j=0;jn;j++){ - - int val=(look->ln* - ((toBARK(info->rate/2*j/look->n)<<11)/toBARK(info->rate/2)))>>11; - - if(val>=look->ln)val=look->ln-1; /* guard against the approximation */ - look->linearmap[j]=val; - } - look->linearmap[j]=-1; - - look->lsp_look=(ogg_int32_t *)_ogg_malloc(look->ln*sizeof(*look->lsp_look)); - for(j=0;jln;j++) - look->lsp_look[j]=vorbis_coslook2_i(0x10000*j/look->ln); - - return look; + return info->order+1; } -static void *floor0_inverse1(vorbis_block *vb,vorbis_look_floor *i){ - vorbis_look_floor0 *look=(vorbis_look_floor0 *)i; - vorbis_info_floor0 *info=look->vi; +tremor_ogg_int32_t *floor0_inverse1(vorbis_dsp_state *vd,vorbis_info_floor *i, + tremor_ogg_int32_t *lsp){ + vorbis_info_floor0 *info=(vorbis_info_floor0 *)i; int j,k; - int ampraw=oggpack_read(&vb->opb,info->ampbits); + int ampraw=tremor_oggpack_read(&vd->opb,info->ampbits); if(ampraw>0){ /* also handles the -1 out of data case */ long maxval=(1<ampbits)-1; int amp=((ampraw*info->ampdB)<<4)/maxval; - int booknum=oggpack_read(&vb->opb,_ilog(info->numbooks)); + int booknum=tremor_oggpack_read(&vd->opb,_ilog(info->numbooks)); if(booknum!=-1 && booknumnumbooks){ /* be paranoid */ - codec_setup_info *ci=(codec_setup_info *)vb->vd->vi->codec_setup; - codebook *b=ci->fullbooks+info->books[booknum]; - ogg_int32_t last=0; - ogg_int32_t *lsp=(ogg_int32_t *)_vorbis_block_alloc(vb,sizeof(*lsp)*(look->m+1)); + codec_setup_info *ci=(codec_setup_info *)vd->vi->codec_setup; + codebook *b=ci->book_param+info->books[booknum]; + tremor_ogg_int32_t last=0; - if(vorbis_book_decodev_set(b,lsp,&vb->opb,look->m,-24)==-1)goto eop; - for(j=0;jm;){ - for(k=0;jm && kdim;k++,j++)lsp[j]+=last; + if(vorbis_book_decodev_set(b,lsp,&vd->opb,info->order,-24)==-1)goto eop; + for(j=0;jorder;){ + for(k=0;jorder && kdim;k++,j++)lsp[j]+=last; last=lsp[j-1]; } - lsp[look->m]=amp; + lsp[info->order]=amp; return(lsp); } } @@ -412,28 +407,21 @@ static void *floor0_inverse1(vorbis_block *vb,vorbis_look_floor *i){ return(NULL); } -static int floor0_inverse2(vorbis_block *vb,vorbis_look_floor *i, - void *memo,ogg_int32_t *out){ - vorbis_look_floor0 *look=(vorbis_look_floor0 *)i; - vorbis_info_floor0 *info=look->vi; +int floor0_inverse2(vorbis_dsp_state *vd,vorbis_info_floor *i, + tremor_ogg_int32_t *lsp,tremor_ogg_int32_t *out){ + vorbis_info_floor0 *info=(vorbis_info_floor0 *)i; + codec_setup_info *ci=(codec_setup_info *)vd->vi->codec_setup; - if(memo){ - ogg_int32_t *lsp=(ogg_int32_t *)memo; - ogg_int32_t amp=lsp[look->m]; + if(lsp){ + tremor_ogg_int32_t amp=lsp[info->order]; /* take the coefficients back to a spectral envelope curve */ - vorbis_lsp_to_curve(out,look->linearmap,look->n,look->ln, - lsp,look->m,amp,info->ampdB,look->lsp_look); + vorbis_lsp_to_curve(out,ci->blocksizes[vd->W]/2,info->barkmap, + lsp,info->order,amp,info->ampdB, + info->rate>>1); return(1); } - memset(out,0,sizeof(*out)*look->n); + memset(out,0,sizeof(*out)*ci->blocksizes[vd->W]/2); return(0); } -/* export hooks */ -vorbis_func_floor floor0_exportbundle={ - &floor0_unpack,&floor0_look,&floor0_free_info, - &floor0_free_look,&floor0_inverse1,&floor0_inverse2 -}; - - diff --git a/lib/tremor/floor1.c b/lib/tremor/floor1.c index e63ae9fb..1dc5f357 100644 --- a/lib/tremor/floor1.c +++ b/lib/tremor/floor1.c @@ -1,12 +1,12 @@ /******************************************************************** * * - * THIS FILE IS PART OF THE OggVorbis 'TREMOR' CODEC SOURCE CODE. * + * THIS FILE IS PART OF THE TremorOggVorbis 'TREMOR' CODEC SOURCE CODE. * * * * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS * * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE * * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. * * * - * THE OggVorbis 'TREMOR' SOURCE CODE IS (C) COPYRIGHT 1994-2002 * + * THE TremorOggVorbis 'TREMOR' SOURCE CODE IS (C) COPYRIGHT 1994-2003 * * BY THE Xiph.Org FOUNDATION http://www.xiph.org/ * * * ******************************************************************** @@ -18,44 +18,29 @@ #include #include #include -#include +#include "tremor_ogg.h" #include "ivorbiscodec.h" #include "codec_internal.h" -#include "registry.h" #include "codebook.h" #include "misc.h" -#include "block.h" +extern const tremor_ogg_int32_t FLOOR_fromdB_LOOKUP[]; #define floor1_rangedB 140 /* floor 1 fixed at -140dB to 0dB range */ - -typedef struct { - int forward_index[VIF_POSIT+2]; - - int hineighbor[VIF_POSIT]; - int loneighbor[VIF_POSIT]; - int posts; - - int n; - int quant_q; - vorbis_info_floor1 *vi; - -} vorbis_look_floor1; +#define VIF_POSIT 63 /***********************************************/ -static void floor1_free_info(vorbis_info_floor *i){ +void floor1_free_info(vorbis_info_floor *i){ vorbis_info_floor1 *info=(vorbis_info_floor1 *)i; if(info){ + if(info->class)_tremor_ogg_free(info->class); + if(info->partitionclass)_tremor_ogg_free(info->partitionclass); + if(info->postlist)_tremor_ogg_free(info->postlist); + if(info->forward_index)_tremor_ogg_free(info->forward_index); + if(info->hineighbor)_tremor_ogg_free(info->hineighbor); + if(info->loneighbor)_tremor_ogg_free(info->loneighbor); memset(info,0,sizeof(*info)); - _ogg_free(info); - } -} - -static void floor1_free_look(vorbis_look_floor *i){ - vorbis_look_floor1 *look=(vorbis_look_floor1 *)i; - if(look){ - memset(look,0,sizeof(*look)); - _ogg_free(look); + _tremor_ogg_free(info); } } @@ -68,143 +53,131 @@ static int ilog(unsigned int v){ return(ret); } -static int icomp(const void *a,const void *b){ - return(**(int **)a-**(int **)b); +static void vorbis_mergesort(char *index,tremor_ogg_uint16_t *vals,tremor_ogg_uint16_t n){ + tremor_ogg_uint16_t i,j; + char *temp,*A=index,*B=_tremor_ogg_malloc(n*sizeof(*B)); + + for(i=1;icodec_setup; int j,k,count=0,maxclass=-1,rangebits; - - vorbis_info_floor1 *info=(vorbis_info_floor1 *)_ogg_calloc(1,sizeof(*info)); + + vorbis_info_floor1 *info=(vorbis_info_floor1 *)_tremor_ogg_calloc(1,sizeof(*info)); /* read partitions */ - info->partitions=oggpack_read(opb,5); /* only 0 to 31 legal */ + info->partitions=tremor_oggpack_read(opb,5); /* only 0 to 31 legal */ + info->partitionclass= + (char *)_tremor_ogg_malloc(info->partitions*sizeof(*info->partitionclass)); for(j=0;jpartitions;j++){ - info->partitionclass[j]=oggpack_read(opb,4); /* only 0 to 15 legal */ - if(info->partitionclass[j]<0)goto err_out; + info->partitionclass[j]=tremor_oggpack_read(opb,4); /* only 0 to 15 legal */ if(maxclasspartitionclass[j])maxclass=info->partitionclass[j]; } /* read partition classes */ + info->class= + (floor1class *)_tremor_ogg_malloc((maxclass+1)*sizeof(*info->class)); for(j=0;jclass_dim[j]=oggpack_read(opb,3)+1; /* 1 to 8 */ - info->class_subs[j]=oggpack_read(opb,2); /* 0,1,2,3 bits */ - if(info->class_subs[j]<0) - goto err_out; - if(info->class_subs[j])info->class_book[j]=oggpack_read(opb,8); - if(info->class_book[j]<0 || info->class_book[j]>=ci->books) - goto err_out; - for(k=0;k<(1<class_subs[j]);k++){ - info->class_subbook[j][k]=oggpack_read(opb,8)-1; - if(info->class_subbook[j][k]<-1 || info->class_subbook[j][k]>=ci->books) - goto err_out; + info->class[j].class_dim=tremor_oggpack_read(opb,3)+1; /* 1 to 8 */ + info->class[j].class_subs=tremor_oggpack_read(opb,2); /* 0,1,2,3 bits */ + if(tremor_oggpack_eop(opb)<0) goto err_out; + if(info->class[j].class_subs) + info->class[j].class_book=tremor_oggpack_read(opb,8); + else + info->class[j].class_book=0; + if(info->class[j].class_book>=ci->books)goto err_out; + for(k=0;k<(1<class[j].class_subs);k++){ + info->class[j].class_subbook[k]=tremor_oggpack_read(opb,8)-1; + if(info->class[j].class_subbook[k]>=ci->books && + info->class[j].class_subbook[k]!=0xff)goto err_out; } } /* read the post list */ - info->mult=oggpack_read(opb,2)+1; /* only 1,2,3,4 legal now */ - rangebits=oggpack_read(opb,4); - if(rangebits<0)goto err_out; - + info->mult=tremor_oggpack_read(opb,2)+1; /* only 1,2,3,4 legal now */ + rangebits=tremor_oggpack_read(opb,4); + + for(j=0,k=0;jpartitions;j++) + count+=info->class[info->partitionclass[j]].class_dim; + info->postlist= + (tremor_ogg_uint16_t *)_tremor_ogg_malloc((count+2)*sizeof(*info->postlist)); + info->forward_index= + (char *)_tremor_ogg_malloc((count+2)*sizeof(*info->forward_index)); + info->loneighbor= + (char *)_tremor_ogg_malloc(count*sizeof(*info->loneighbor)); + info->hineighbor= + (char *)_tremor_ogg_malloc(count*sizeof(*info->hineighbor)); + + count=0; for(j=0,k=0;jpartitions;j++){ - count+=info->class_dim[info->partitionclass[j]]; + count+=info->class[info->partitionclass[j]].class_dim; if(count>VIF_POSIT)goto err_out; for(;kpostlist[k+2]=oggpack_read(opb,rangebits); - if(t<0 || t>=(1<postlist[k+2]=tremor_oggpack_read(opb,rangebits); + if(t>=(1<postlist[0]=0; info->postlist[1]=1<postlist+j; - qsort(sortpointer,count+2,sizeof(*sortpointer),icomp); - - for(j=1;jvi=info; - look->n=info->postlist[1]; - - /* we drop each position value in-between already decoded values, - and use linear interpolation to predict each new value past the - edges. The positions are read in the order of the position - list... we precompute the bounding positions in the lookup. Of - course, the neighbors can change (if a position is declined), but - this is an initial mapping */ - - for(i=0;ipartitions;i++)n+=info->class_dim[info->partitionclass[i]]; - n+=2; - look->posts=n; + info->posts=count+2; /* also store a sorted position index */ - for(i=0;ipostlist+i; - qsort(sortpointer,n,sizeof(*sortpointer),icomp); - - /* points from sort order back to range number */ - for(i=0;iforward_index[i]=sortpointer[i]-info->postlist; + for(j=0;jposts;j++)info->forward_index[j]=j; + vorbis_mergesort(info->forward_index,info->postlist,info->posts); - /* quantize values to multiplier spec */ - switch(info->mult){ - case 1: /* 1024 -> 256 */ - look->quant_q=256; - break; - case 2: /* 1024 -> 128 */ - look->quant_q=128; - break; - case 3: /* 1024 -> 86 */ - look->quant_q=86; - break; - case 4: /* 1024 -> 64 */ - look->quant_q=64; - break; - } - /* discover our neighbors for decode where we don't use fit flags (that would push the neighbors outward) */ - for(i=0;iposts-2;j++){ int lo=0; int hi=1; int lx=0; - int hx=look->n; - int currentx=info->postlist[i+2]; - for(j=0;jpostlist[j]; + int hx=info->postlist[1]; + int currentx=info->postlist[j+2]; + for(k=0;kpostlist[k]; if(x>lx && xcurrentx){ - hi=j; + hi=k; hx=x; } } - look->loneighbor[i]=lo; - look->hineighbor[i]=hi; + info->loneighbor[j]=lo; + info->hineighbor[j]=hi; } - return(look); + return(info); + + err_out: + floor1_free_info(info); + return(NULL); } static int render_point(int x0,int x1,int y0,int y1,int x){ @@ -223,80 +196,7 @@ static int render_point(int x0,int x1,int y0,int y1,int x){ } } -#ifdef _LOW_ACCURACY_ -# define XdB(n) ((((n)>>8)+1)>>1) -#else -# define XdB(n) (n) -#endif - -static const ogg_int32_t FLOOR_fromdB_LOOKUP[256]={ - XdB(0x000000e5), XdB(0x000000f4), XdB(0x00000103), XdB(0x00000114), - XdB(0x00000126), XdB(0x00000139), XdB(0x0000014e), XdB(0x00000163), - XdB(0x0000017a), XdB(0x00000193), XdB(0x000001ad), XdB(0x000001c9), - XdB(0x000001e7), XdB(0x00000206), XdB(0x00000228), XdB(0x0000024c), - XdB(0x00000272), XdB(0x0000029b), XdB(0x000002c6), XdB(0x000002f4), - XdB(0x00000326), XdB(0x0000035a), XdB(0x00000392), XdB(0x000003cd), - XdB(0x0000040c), XdB(0x00000450), XdB(0x00000497), XdB(0x000004e4), - XdB(0x00000535), XdB(0x0000058c), XdB(0x000005e8), XdB(0x0000064a), - XdB(0x000006b3), XdB(0x00000722), XdB(0x00000799), XdB(0x00000818), - XdB(0x0000089e), XdB(0x0000092e), XdB(0x000009c6), XdB(0x00000a69), - XdB(0x00000b16), XdB(0x00000bcf), XdB(0x00000c93), XdB(0x00000d64), - XdB(0x00000e43), XdB(0x00000f30), XdB(0x0000102d), XdB(0x0000113a), - XdB(0x00001258), XdB(0x0000138a), XdB(0x000014cf), XdB(0x00001629), - XdB(0x0000179a), XdB(0x00001922), XdB(0x00001ac4), XdB(0x00001c82), - XdB(0x00001e5c), XdB(0x00002055), XdB(0x0000226f), XdB(0x000024ac), - XdB(0x0000270e), XdB(0x00002997), XdB(0x00002c4b), XdB(0x00002f2c), - XdB(0x0000323d), XdB(0x00003581), XdB(0x000038fb), XdB(0x00003caf), - XdB(0x000040a0), XdB(0x000044d3), XdB(0x0000494c), XdB(0x00004e10), - XdB(0x00005323), XdB(0x0000588a), XdB(0x00005e4b), XdB(0x0000646b), - XdB(0x00006af2), XdB(0x000071e5), XdB(0x0000794c), XdB(0x0000812e), - XdB(0x00008993), XdB(0x00009283), XdB(0x00009c09), XdB(0x0000a62d), - XdB(0x0000b0f9), XdB(0x0000bc79), XdB(0x0000c8b9), XdB(0x0000d5c4), - XdB(0x0000e3a9), XdB(0x0000f274), XdB(0x00010235), XdB(0x000112fd), - XdB(0x000124dc), XdB(0x000137e4), XdB(0x00014c29), XdB(0x000161bf), - XdB(0x000178bc), XdB(0x00019137), XdB(0x0001ab4a), XdB(0x0001c70e), - XdB(0x0001e4a1), XdB(0x0002041f), XdB(0x000225aa), XdB(0x00024962), - XdB(0x00026f6d), XdB(0x000297f0), XdB(0x0002c316), XdB(0x0002f109), - XdB(0x000321f9), XdB(0x00035616), XdB(0x00038d97), XdB(0x0003c8b4), - XdB(0x000407a7), XdB(0x00044ab2), XdB(0x00049218), XdB(0x0004de23), - XdB(0x00052f1e), XdB(0x0005855c), XdB(0x0005e135), XdB(0x00064306), - XdB(0x0006ab33), XdB(0x00071a24), XdB(0x0007904b), XdB(0x00080e20), - XdB(0x00089422), XdB(0x000922da), XdB(0x0009bad8), XdB(0x000a5cb6), - XdB(0x000b091a), XdB(0x000bc0b1), XdB(0x000c8436), XdB(0x000d5471), - XdB(0x000e3233), XdB(0x000f1e5f), XdB(0x001019e4), XdB(0x001125c1), - XdB(0x00124306), XdB(0x001372d5), XdB(0x0014b663), XdB(0x00160ef7), - XdB(0x00177df0), XdB(0x001904c1), XdB(0x001aa4f9), XdB(0x001c603d), - XdB(0x001e384f), XdB(0x00202f0f), XdB(0x0022467a), XdB(0x002480b1), - XdB(0x0026dff7), XdB(0x002966b3), XdB(0x002c1776), XdB(0x002ef4fc), - XdB(0x0032022d), XdB(0x00354222), XdB(0x0038b828), XdB(0x003c67c2), - XdB(0x004054ae), XdB(0x004482e8), XdB(0x0048f6af), XdB(0x004db488), - XdB(0x0052c142), XdB(0x005821ff), XdB(0x005ddc33), XdB(0x0063f5b0), - XdB(0x006a74a7), XdB(0x00715faf), XdB(0x0078bdce), XdB(0x0080967f), - XdB(0x0088f1ba), XdB(0x0091d7f9), XdB(0x009b5247), XdB(0x00a56a41), - XdB(0x00b02a27), XdB(0x00bb9ce2), XdB(0x00c7ce12), XdB(0x00d4ca17), - XdB(0x00e29e20), XdB(0x00f15835), XdB(0x0101074b), XdB(0x0111bb4e), - XdB(0x01238531), XdB(0x01367704), XdB(0x014aa402), XdB(0x016020a7), - XdB(0x017702c3), XdB(0x018f6190), XdB(0x01a955cb), XdB(0x01c4f9cf), - XdB(0x01e269a8), XdB(0x0201c33b), XdB(0x0223265a), XdB(0x0246b4ea), - XdB(0x026c9302), XdB(0x0294e716), XdB(0x02bfda13), XdB(0x02ed9793), - XdB(0x031e4e09), XdB(0x03522ee4), XdB(0x03896ed0), XdB(0x03c445e2), - XdB(0x0402efd6), XdB(0x0445ac4b), XdB(0x048cbefc), XdB(0x04d87013), - XdB(0x05290c67), XdB(0x057ee5ca), XdB(0x05da5364), XdB(0x063bb204), - XdB(0x06a36485), XdB(0x0711d42b), XdB(0x0787710e), XdB(0x0804b299), - XdB(0x088a17ef), XdB(0x0918287e), XdB(0x09af747c), XdB(0x0a50957e), - XdB(0x0afc2f19), XdB(0x0bb2ef7f), XdB(0x0c759034), XdB(0x0d44d6ca), - XdB(0x0e2195bc), XdB(0x0f0cad0d), XdB(0x10070b62), XdB(0x1111aeea), - XdB(0x122da66c), XdB(0x135c120f), XdB(0x149e24d9), XdB(0x15f525b1), - XdB(0x176270e3), XdB(0x18e7794b), XdB(0x1a85c9ae), XdB(0x1c3f06d1), - XdB(0x1e14f07d), XdB(0x200963d7), XdB(0x221e5ccd), XdB(0x2455f870), - XdB(0x26b2770b), XdB(0x29363e2b), XdB(0x2be3db5c), XdB(0x2ebe06b6), - XdB(0x31c7a55b), XdB(0x3503ccd4), XdB(0x3875c5aa), XdB(0x3c210f44), - XdB(0x4009632b), XdB(0x4432b8cf), XdB(0x48a149bc), XdB(0x4d59959e), - XdB(0x52606733), XdB(0x57bad899), XdB(0x5d6e593a), XdB(0x6380b298), - XdB(0x69f80e9a), XdB(0x70dafda8), XdB(0x78307d76), XdB(0x7fffffff), -}; - -static void render_line(int n, int x0,int x1,int y0,int y1,ogg_int32_t *d){ +static void render_line(int n,int x0,int x1,int y0,int y1,tremor_ogg_int32_t *d){ int dy=y1-y0; int adx=x1-x0; int ady=abs(dy); @@ -324,42 +224,48 @@ static void render_line(int n, int x0,int x1,int y0,int y1,ogg_int32_t *d){ } } -static void *floor1_inverse1(vorbis_block *vb,vorbis_look_floor *in){ - vorbis_look_floor1 *look=(vorbis_look_floor1 *)in; - vorbis_info_floor1 *info=look->vi; - codec_setup_info *ci=(codec_setup_info *)vb->vd->vi->codec_setup; +int floor1_memosize(vorbis_info_floor *i){ + vorbis_info_floor1 *info=(vorbis_info_floor1 *)i; + return info->posts; +} + +static int quant_look[4]={256,128,86,64}; + +tremor_ogg_int32_t *floor1_inverse1(vorbis_dsp_state *vd,vorbis_info_floor *in, + tremor_ogg_int32_t *fit_value){ + vorbis_info_floor1 *info=(vorbis_info_floor1 *)in; + codec_setup_info *ci=(codec_setup_info *)vd->vi->codec_setup; int i,j,k; - codebook *books=ci->fullbooks; - + codebook *books=ci->book_param; + int quant_q=quant_look[info->mult-1]; + /* unpack wrapped/predicted values from stream */ - if(oggpack_read(&vb->opb,1)==1){ - int *fit_value=(int *)_vorbis_block_alloc(vb,(look->posts)*sizeof(*fit_value)); - - fit_value[0]=oggpack_read(&vb->opb,ilog(look->quant_q-1)); - fit_value[1]=oggpack_read(&vb->opb,ilog(look->quant_q-1)); + if(tremor_oggpack_read(&vd->opb,1)==1){ + fit_value[0]=tremor_oggpack_read(&vd->opb,ilog(quant_q-1)); + fit_value[1]=tremor_oggpack_read(&vd->opb,ilog(quant_q-1)); /* partition by partition */ /* partition by partition */ for(i=0,j=2;ipartitions;i++){ int classv=info->partitionclass[i]; - int cdim=info->class_dim[classv]; - int csubbits=info->class_subs[classv]; + int cdim=info->class[classv].class_dim; + int csubbits=info->class[classv].class_subs; int csub=1<class_book[classv],&vb->opb); + cval=vorbis_book_decode(books+info->class[classv].class_book,&vd->opb); if(cval==-1)goto eop; } for(k=0;kclass_subbook[classv][cval&(csub-1)]; + int book=info->class[classv].class_subbook[cval&(csub-1)]; cval>>=csubbits; - if(book>=0){ - if((fit_value[j+k]=vorbis_book_decode(books+book,&vb->opb))==-1) + if(book!=0xff){ + if((fit_value[j+k]=vorbis_book_decode(books+book,&vd->opb))==-1) goto eop; }else{ fit_value[j+k]=0; @@ -369,13 +275,13 @@ static void *floor1_inverse1(vorbis_block *vb,vorbis_look_floor *in){ } /* unwrap positive values and reconsitute via linear interpolation */ - for(i=2;iposts;i++){ - int predicted=render_point(info->postlist[look->loneighbor[i-2]], - info->postlist[look->hineighbor[i-2]], - fit_value[look->loneighbor[i-2]], - fit_value[look->hineighbor[i-2]], + for(i=2;iposts;i++){ + int predicted=render_point(info->postlist[info->loneighbor[i-2]], + info->postlist[info->hineighbor[i-2]], + fit_value[info->loneighbor[i-2]], + fit_value[info->hineighbor[i-2]], info->postlist[i]); - int hiroom=look->quant_q-predicted; + int hiroom=quant_q-predicted; int loroom=predicted; int room=(hiroomloneighbor[i-2]]&=0x7fff; - fit_value[look->hineighbor[i-2]]&=0x7fff; + fit_value[i]=val+predicted; + fit_value[info->loneighbor[i-2]]&=0x7fff; + fit_value[info->hineighbor[i-2]]&=0x7fff; }else{ fit_value[i]=predicted|0x8000; @@ -411,34 +317,27 @@ static void *floor1_inverse1(vorbis_block *vb,vorbis_look_floor *in){ return(NULL); } -static int floor1_inverse2(vorbis_block *vb,vorbis_look_floor *in,void *memo, - ogg_int32_t *out){ - vorbis_look_floor1 *look=(vorbis_look_floor1 *)in; - vorbis_info_floor1 *info=look->vi; +int floor1_inverse2(vorbis_dsp_state *vd,vorbis_info_floor *in, + tremor_ogg_int32_t *fit_value,tremor_ogg_int32_t *out){ + vorbis_info_floor1 *info=(vorbis_info_floor1 *)in; - codec_setup_info *ci=(codec_setup_info *)vb->vd->vi->codec_setup; - int n=ci->blocksizes[vb->W]/2; + codec_setup_info *ci=(codec_setup_info *)vd->vi->codec_setup; + int n=ci->blocksizes[vd->W]/2; int j; - if(memo){ + if(fit_value){ /* render the lines */ - int *fit_value=(int *)memo; int hx=0; int lx=0; int ly=fit_value[0]*info->mult; - /* guard lookup against out-of-range values */ - ly=(ly<0?0:ly>255?255:ly); - - for(j=1;jposts;j++){ - int current=look->forward_index[j]; + for(j=1;jposts;j++){ + int current=info->forward_index[j]; int hy=fit_value[current]&0x7fff; if(hy==fit_value[current]){ - hx=info->postlist[current]; hy*=info->mult; - /* guard lookup against out-of-range values */ - hy=(hy<0?0:hy>255?255:hy); - + hx=info->postlist[current]; + render_line(n,lx,hx,ly,hy,out); lx=hx; @@ -451,10 +350,3 @@ static int floor1_inverse2(vorbis_block *vb,vorbis_look_floor *in,void *memo, memset(out,0,sizeof(*out)*n); return(0); } - -/* export hooks */ -vorbis_func_floor floor1_exportbundle={ - &floor1_unpack,&floor1_look,&floor1_free_info, - &floor1_free_look,&floor1_inverse1,&floor1_inverse2 -}; - diff --git a/lib/tremor/floor_lookup.c b/lib/tremor/floor_lookup.c new file mode 100644 index 00000000..a7140a14 --- /dev/null +++ b/lib/tremor/floor_lookup.c @@ -0,0 +1,92 @@ +/******************************************************************** + * * + * THIS FILE IS PART OF THE TremorOggVorbis 'TREMOR' CODEC SOURCE CODE. * + * * + * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS * + * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE * + * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. * + * * + * THE TremorOggVorbis 'TREMOR' SOURCE CODE IS (C) COPYRIGHT 1994-2003 * + * BY THE Xiph.Org FOUNDATION http://www.xiph.org/ * + * * + ******************************************************************** + + function: floor dB lookup + + ********************************************************************/ + +#include "os.h" + +#ifdef _LOW_ACCURACY_ +# define XdB(n) ((((n)>>8)+1)>>1) +#else +# define XdB(n) (n) +#endif + +const tremor_ogg_int32_t FLOOR_fromdB_LOOKUP[256]={ + XdB(0x000000e5), XdB(0x000000f4), XdB(0x00000103), XdB(0x00000114), + XdB(0x00000126), XdB(0x00000139), XdB(0x0000014e), XdB(0x00000163), + XdB(0x0000017a), XdB(0x00000193), XdB(0x000001ad), XdB(0x000001c9), + XdB(0x000001e7), XdB(0x00000206), XdB(0x00000228), XdB(0x0000024c), + XdB(0x00000272), XdB(0x0000029b), XdB(0x000002c6), XdB(0x000002f4), + XdB(0x00000326), XdB(0x0000035a), XdB(0x00000392), XdB(0x000003cd), + XdB(0x0000040c), XdB(0x00000450), XdB(0x00000497), XdB(0x000004e4), + XdB(0x00000535), XdB(0x0000058c), XdB(0x000005e8), XdB(0x0000064a), + XdB(0x000006b3), XdB(0x00000722), XdB(0x00000799), XdB(0x00000818), + XdB(0x0000089e), XdB(0x0000092e), XdB(0x000009c6), XdB(0x00000a69), + XdB(0x00000b16), XdB(0x00000bcf), XdB(0x00000c93), XdB(0x00000d64), + XdB(0x00000e43), XdB(0x00000f30), XdB(0x0000102d), XdB(0x0000113a), + XdB(0x00001258), XdB(0x0000138a), XdB(0x000014cf), XdB(0x00001629), + XdB(0x0000179a), XdB(0x00001922), XdB(0x00001ac4), XdB(0x00001c82), + XdB(0x00001e5c), XdB(0x00002055), XdB(0x0000226f), XdB(0x000024ac), + XdB(0x0000270e), XdB(0x00002997), XdB(0x00002c4b), XdB(0x00002f2c), + XdB(0x0000323d), XdB(0x00003581), XdB(0x000038fb), XdB(0x00003caf), + XdB(0x000040a0), XdB(0x000044d3), XdB(0x0000494c), XdB(0x00004e10), + XdB(0x00005323), XdB(0x0000588a), XdB(0x00005e4b), XdB(0x0000646b), + XdB(0x00006af2), XdB(0x000071e5), XdB(0x0000794c), XdB(0x0000812e), + XdB(0x00008993), XdB(0x00009283), XdB(0x00009c09), XdB(0x0000a62d), + XdB(0x0000b0f9), XdB(0x0000bc79), XdB(0x0000c8b9), XdB(0x0000d5c4), + XdB(0x0000e3a9), XdB(0x0000f274), XdB(0x00010235), XdB(0x000112fd), + XdB(0x000124dc), XdB(0x000137e4), XdB(0x00014c29), XdB(0x000161bf), + XdB(0x000178bc), XdB(0x00019137), XdB(0x0001ab4a), XdB(0x0001c70e), + XdB(0x0001e4a1), XdB(0x0002041f), XdB(0x000225aa), XdB(0x00024962), + XdB(0x00026f6d), XdB(0x000297f0), XdB(0x0002c316), XdB(0x0002f109), + XdB(0x000321f9), XdB(0x00035616), XdB(0x00038d97), XdB(0x0003c8b4), + XdB(0x000407a7), XdB(0x00044ab2), XdB(0x00049218), XdB(0x0004de23), + XdB(0x00052f1e), XdB(0x0005855c), XdB(0x0005e135), XdB(0x00064306), + XdB(0x0006ab33), XdB(0x00071a24), XdB(0x0007904b), XdB(0x00080e20), + XdB(0x00089422), XdB(0x000922da), XdB(0x0009bad8), XdB(0x000a5cb6), + XdB(0x000b091a), XdB(0x000bc0b1), XdB(0x000c8436), XdB(0x000d5471), + XdB(0x000e3233), XdB(0x000f1e5f), XdB(0x001019e4), XdB(0x001125c1), + XdB(0x00124306), XdB(0x001372d5), XdB(0x0014b663), XdB(0x00160ef7), + XdB(0x00177df0), XdB(0x001904c1), XdB(0x001aa4f9), XdB(0x001c603d), + XdB(0x001e384f), XdB(0x00202f0f), XdB(0x0022467a), XdB(0x002480b1), + XdB(0x0026dff7), XdB(0x002966b3), XdB(0x002c1776), XdB(0x002ef4fc), + XdB(0x0032022d), XdB(0x00354222), XdB(0x0038b828), XdB(0x003c67c2), + XdB(0x004054ae), XdB(0x004482e8), XdB(0x0048f6af), XdB(0x004db488), + XdB(0x0052c142), XdB(0x005821ff), XdB(0x005ddc33), XdB(0x0063f5b0), + XdB(0x006a74a7), XdB(0x00715faf), XdB(0x0078bdce), XdB(0x0080967f), + XdB(0x0088f1ba), XdB(0x0091d7f9), XdB(0x009b5247), XdB(0x00a56a41), + XdB(0x00b02a27), XdB(0x00bb9ce2), XdB(0x00c7ce12), XdB(0x00d4ca17), + XdB(0x00e29e20), XdB(0x00f15835), XdB(0x0101074b), XdB(0x0111bb4e), + XdB(0x01238531), XdB(0x01367704), XdB(0x014aa402), XdB(0x016020a7), + XdB(0x017702c3), XdB(0x018f6190), XdB(0x01a955cb), XdB(0x01c4f9cf), + XdB(0x01e269a8), XdB(0x0201c33b), XdB(0x0223265a), XdB(0x0246b4ea), + XdB(0x026c9302), XdB(0x0294e716), XdB(0x02bfda13), XdB(0x02ed9793), + XdB(0x031e4e09), XdB(0x03522ee4), XdB(0x03896ed0), XdB(0x03c445e2), + XdB(0x0402efd6), XdB(0x0445ac4b), XdB(0x048cbefc), XdB(0x04d87013), + XdB(0x05290c67), XdB(0x057ee5ca), XdB(0x05da5364), XdB(0x063bb204), + XdB(0x06a36485), XdB(0x0711d42b), XdB(0x0787710e), XdB(0x0804b299), + XdB(0x088a17ef), XdB(0x0918287e), XdB(0x09af747c), XdB(0x0a50957e), + XdB(0x0afc2f19), XdB(0x0bb2ef7f), XdB(0x0c759034), XdB(0x0d44d6ca), + XdB(0x0e2195bc), XdB(0x0f0cad0d), XdB(0x10070b62), XdB(0x1111aeea), + XdB(0x122da66c), XdB(0x135c120f), XdB(0x149e24d9), XdB(0x15f525b1), + XdB(0x176270e3), XdB(0x18e7794b), XdB(0x1a85c9ae), XdB(0x1c3f06d1), + XdB(0x1e14f07d), XdB(0x200963d7), XdB(0x221e5ccd), XdB(0x2455f870), + XdB(0x26b2770b), XdB(0x29363e2b), XdB(0x2be3db5c), XdB(0x2ebe06b6), + XdB(0x31c7a55b), XdB(0x3503ccd4), XdB(0x3875c5aa), XdB(0x3c210f44), + XdB(0x4009632b), XdB(0x4432b8cf), XdB(0x48a149bc), XdB(0x4d59959e), + XdB(0x52606733), XdB(0x57bad899), XdB(0x5d6e593a), XdB(0x6380b298), + XdB(0x69f80e9a), XdB(0x70dafda8), XdB(0x78307d76), XdB(0x7fffffff), +}; + diff --git a/lib/tremor/framing.c b/lib/tremor/framing.c new file mode 100644 index 00000000..e2321ae4 --- /dev/null +++ b/lib/tremor/framing.c @@ -0,0 +1,1117 @@ +/******************************************************************** + * * + * THIS FILE IS PART OF THE TremorOggVorbis 'TREMOR' CODEC SOURCE CODE. * + * * + * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS * + * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE * + * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. * + * * + * THE TremorOggVorbis 'TREMOR' SOURCE CODE IS (C) COPYRIGHT 1994-2003 * + * BY THE Xiph.Org FOUNDATION http://www.xiph.org/ * + * * + ******************************************************************** + + function: decode Ogg streams back into raw packets + + note: The CRC code is directly derived from public domain code by + Ross Williams (ross@guest.adelaide.edu.au). See docs/framing.html + for details. + + ********************************************************************/ + +#include +#include +#include "tremor_ogg.h" +#include "misc.h" + + +/* A complete description of Ogg framing exists in docs/framing.html */ + +/* basic, centralized Ogg memory management based on linked lists of + references to refcounted memory buffers. References and buffers + are both recycled. Buffers are passed around and consumed in + reference form. */ + +static tremor_ogg_buffer_state *tremor_ogg_buffer_create(void){ + tremor_ogg_buffer_state *bs=_tremor_ogg_calloc(1,sizeof(*bs)); + return bs; +} + +/* destruction is 'lazy'; there may be memory references outstanding, + and yanking the buffer state out from underneath would be + antisocial. Dealloc what is currently unused and have + _release_one watch for the stragglers to come in. When they do, + finish destruction. */ + +/* call the helper while holding lock */ +static void _tremor_ogg_buffer_destroy(tremor_ogg_buffer_state *bs){ + tremor_ogg_buffer *bt; + tremor_ogg_reference *rt; + + if(bs->shutdown){ + + bt=bs->unused_buffers; + rt=bs->unused_references; + + while(bt){ + tremor_ogg_buffer *b=bt; + bt=b->ptr.next; + if(b->data)_tremor_ogg_free(b->data); + _tremor_ogg_free(b); + } + bs->unused_buffers=0; + while(rt){ + tremor_ogg_reference *r=rt; + rt=r->next; + _tremor_ogg_free(r); + } + bs->unused_references=0; + + if(!bs->outstanding) + _tremor_ogg_free(bs); + + } +} + +static void tremor_ogg_buffer_destroy(tremor_ogg_buffer_state *bs){ + bs->shutdown=1; + _tremor_ogg_buffer_destroy(bs); +} + +static tremor_ogg_buffer *_fetch_buffer(tremor_ogg_buffer_state *bs,long bytes){ + tremor_ogg_buffer *ob; + bs->outstanding++; + + /* do we have an unused buffer sitting in the pool? */ + if(bs->unused_buffers){ + ob=bs->unused_buffers; + bs->unused_buffers=ob->ptr.next; + + /* if the unused buffer is too small, grow it */ + if(ob->sizedata=_tremor_ogg_realloc(ob->data,bytes); + ob->size=bytes; + } + }else{ + /* allocate a new buffer */ + ob=_tremor_ogg_malloc(sizeof(*ob)); + ob->data=_tremor_ogg_malloc(bytes<16?16:bytes); + ob->size=bytes; + } + + ob->refcount=1; + ob->ptr.owner=bs; + return ob; +} + +static tremor_ogg_reference *_fetch_ref(tremor_ogg_buffer_state *bs){ + tremor_ogg_reference *or; + bs->outstanding++; + + /* do we have an unused reference sitting in the pool? */ + if(bs->unused_references){ + or=bs->unused_references; + bs->unused_references=or->next; + }else{ + /* allocate a new reference */ + or=_tremor_ogg_malloc(sizeof(*or)); + } + + or->begin=0; + or->length=0; + or->next=0; + return or; +} + +/* fetch a reference pointing to a fresh, initially continguous buffer + of at least [bytes] length */ +static tremor_ogg_reference *tremor_ogg_buffer_alloc(tremor_ogg_buffer_state *bs,long bytes){ + tremor_ogg_buffer *ob=_fetch_buffer(bs,bytes); + tremor_ogg_reference *or=_fetch_ref(bs); + or->buffer=ob; + return or; +} + +/* enlarge the data buffer in the current link */ +static void tremor_ogg_buffer_realloc(tremor_ogg_reference *or,long bytes){ + tremor_ogg_buffer *ob=or->buffer; + + /* if the unused buffer is too small, grow it */ + if(ob->sizedata=_tremor_ogg_realloc(ob->data,bytes); + ob->size=bytes; + } +} + +static void _tremor_ogg_buffer_mark_one(tremor_ogg_reference *or){ + or->buffer->refcount++; +} + +/* increase the refcount of the buffers to which the reference points */ +static void tremor_ogg_buffer_mark(tremor_ogg_reference *or){ + while(or){ + _tremor_ogg_buffer_mark_one(or); + or=or->next; + } +} + +/* duplicate a reference (pointing to the same actual buffer memory) + and increment buffer refcount. If the desired segment is zero + length, a zero length ref is returned. */ +static tremor_ogg_reference *tremor_ogg_buffer_sub(tremor_ogg_reference *or,long length){ + tremor_ogg_reference *ret=0,*head=0; + + /* duplicate the reference chain; increment refcounts */ + while(or && length){ + tremor_ogg_reference *temp=_fetch_ref(or->buffer->ptr.owner); + if(head) + head->next=temp; + else + ret=temp; + head=temp; + head->buffer=or->buffer; + head->begin=or->begin; + head->length=length; + if(head->length>or->length) + head->length=or->length; + + length-=head->length; + or=or->next; + } + + tremor_ogg_buffer_mark(ret); + return ret; +} + +tremor_ogg_reference *tremor_ogg_buffer_dup(tremor_ogg_reference *or){ + tremor_ogg_reference *ret=0,*head=0; + /* duplicate the reference chain; increment refcounts */ + while(or){ + tremor_ogg_reference *temp=_fetch_ref(or->buffer->ptr.owner); + if(head) + head->next=temp; + else + ret=temp; + head=temp; + head->buffer=or->buffer; + head->begin=or->begin; + head->length=or->length; + or=or->next; + } + + tremor_ogg_buffer_mark(ret); + return ret; +} + +/* split a reference into two references; 'return' is a reference to + the buffer preceeding pos and 'head'/'tail' are the buffer past the + split. If pos is at or past the end of the passed in segment, + 'head/tail' are NULL */ +static tremor_ogg_reference *tremor_ogg_buffer_split(tremor_ogg_reference **tail, + tremor_ogg_reference **head,long pos){ + + /* walk past any preceeding fragments to one of: + a) the exact boundary that seps two fragments + b) the fragment that needs split somewhere in the middle */ + tremor_ogg_reference *ret=*tail; + tremor_ogg_reference *or=*tail; + + while(or && pos>or->length){ + pos-=or->length; + or=or->next; + } + + if(!or || pos==0){ + + return 0; + + }else{ + + if(pos>=or->length){ + /* exact split, or off the end? */ + if(or->next){ + + /* a split */ + *tail=or->next; + or->next=0; + + }else{ + + /* off or at the end */ + *tail=*head=0; + + } + }else{ + + /* split within a fragment */ + long lengthA=pos; + long beginB=or->begin+pos; + long lengthB=or->length-pos; + + /* make a new reference to tail the second piece */ + *tail=_fetch_ref(or->buffer->ptr.owner); + + (*tail)->buffer=or->buffer; + (*tail)->begin=beginB; + (*tail)->length=lengthB; + (*tail)->next=or->next; + _tremor_ogg_buffer_mark_one(*tail); + if(head && or==*head)*head=*tail; + + /* update the first piece */ + or->next=0; + or->length=lengthA; + + } + } + return ret; +} + +static void tremor_ogg_buffer_release_one(tremor_ogg_reference *or){ + tremor_ogg_buffer *ob=or->buffer; + tremor_ogg_buffer_state *bs=ob->ptr.owner; + + ob->refcount--; + if(ob->refcount==0){ + bs->outstanding--; /* for the returned buffer */ + ob->ptr.next=bs->unused_buffers; + bs->unused_buffers=ob; + } + + bs->outstanding--; /* for the returned reference */ + or->next=bs->unused_references; + bs->unused_references=or; + + _tremor_ogg_buffer_destroy(bs); /* lazy cleanup (if needed) */ + +} + +/* release the references, decrease the refcounts of buffers to which + they point, release any buffers with a refcount that drops to zero */ +static void tremor_ogg_buffer_release(tremor_ogg_reference *or){ + while(or){ + tremor_ogg_reference *next=or->next; + tremor_ogg_buffer_release_one(or); + or=next; + } +} + +static tremor_ogg_reference *tremor_ogg_buffer_pretruncate(tremor_ogg_reference *or,long pos){ + /* release preceeding fragments we don't want */ + while(or && pos>=or->length){ + tremor_ogg_reference *next=or->next; + pos-=or->length; + tremor_ogg_buffer_release_one(or); + or=next; + } + if (or) { + or->begin+=pos; + or->length-=pos; + } + return or; +} + +static tremor_ogg_reference *tremor_ogg_buffer_walk(tremor_ogg_reference *or){ + if(!or)return NULL; + while(or->next){ + or=or->next; + } + return(or); +} + +/* *head is appended to the front end (head) of *tail; both continue to + be valid pointers, with *tail at the tail and *head at the head */ +static tremor_ogg_reference *tremor_ogg_buffer_cat(tremor_ogg_reference *tail, tremor_ogg_reference *head){ + if(!tail)return head; + + while(tail->next){ + tail=tail->next; + } + tail->next=head; + return tremor_ogg_buffer_walk(head); +} + +static void _positionB(oggbyte_buffer *b,int pos){ + if(pospos){ + /* start at beginning, scan forward */ + b->ref=b->baseref; + b->pos=0; + b->end=b->pos+b->ref->length; + b->ptr=b->ref->buffer->data+b->ref->begin; + } +} + +static void _positionF(oggbyte_buffer *b,int pos){ + /* scan forward for position */ + while(pos>=b->end){ + /* just seek forward */ + b->pos+=b->ref->length; + b->ref=b->ref->next; + b->end=b->ref->length+b->pos; + b->ptr=b->ref->buffer->data+b->ref->begin; + } +} + +static int oggbyte_init(oggbyte_buffer *b,tremor_ogg_reference *or){ + memset(b,0,sizeof(*b)); + if(or){ + b->ref=b->baseref=or; + b->pos=0; + b->end=b->ref->length; + b->ptr=b->ref->buffer->data+b->ref->begin; + return 0; + }else + return -1; +} + +static void oggbyte_set4(oggbyte_buffer *b,tremor_ogg_uint32_t val,int pos){ + int i; + _positionB(b,pos); + for(i=0;i<4;i++){ + _positionF(b,pos); + b->ptr[pos-b->pos]=val; + val>>=8; + ++pos; + } +} + +static unsigned char oggbyte_read1(oggbyte_buffer *b,int pos){ + _positionB(b,pos); + _positionF(b,pos); + return b->ptr[pos-b->pos]; +} + +static tremor_ogg_uint32_t oggbyte_read4(oggbyte_buffer *b,int pos){ + tremor_ogg_uint32_t ret; + _positionB(b,pos); + _positionF(b,pos); + ret=b->ptr[pos-b->pos]; + _positionF(b,++pos); + ret|=b->ptr[pos-b->pos]<<8; + _positionF(b,++pos); + ret|=b->ptr[pos-b->pos]<<16; + _positionF(b,++pos); + ret|=b->ptr[pos-b->pos]<<24; + return ret; +} + +static tremor_ogg_int64_t oggbyte_read8(oggbyte_buffer *b,int pos){ + tremor_ogg_int64_t ret; + unsigned char t[7]; + int i; + _positionB(b,pos); + for(i=0;i<7;i++){ + _positionF(b,pos); + t[i]=b->ptr[pos++ -b->pos]; + } + + _positionF(b,pos); + ret=b->ptr[pos-b->pos]; + + for(i=6;i>=0;--i) + ret= ret<<8 | t[i]; + + return ret; +} + +/* Now we get to the actual framing code */ + +int tremor_ogg_page_version(tremor_ogg_page *og){ + oggbyte_buffer ob; + if(oggbyte_init(&ob,og->header))return -1; + return oggbyte_read1(&ob,4); +} + +int tremor_ogg_page_continued(tremor_ogg_page *og){ + oggbyte_buffer ob; + if(oggbyte_init(&ob,og->header))return -1; + return oggbyte_read1(&ob,5)&0x01; +} + +int tremor_ogg_page_bos(tremor_ogg_page *og){ + oggbyte_buffer ob; + if(oggbyte_init(&ob,og->header))return -1; + return oggbyte_read1(&ob,5)&0x02; +} + +int tremor_ogg_page_eos(tremor_ogg_page *og){ + oggbyte_buffer ob; + if(oggbyte_init(&ob,og->header))return -1; + return oggbyte_read1(&ob,5)&0x04; +} + +tremor_ogg_int64_t tremor_ogg_page_granulepos(tremor_ogg_page *og){ + oggbyte_buffer ob; + if(oggbyte_init(&ob,og->header))return -1; + return oggbyte_read8(&ob,6); +} + +tremor_ogg_uint32_t tremor_ogg_page_serialno(tremor_ogg_page *og){ + oggbyte_buffer ob; + if(oggbyte_init(&ob,og->header)) return 0xffffffffUL; + return oggbyte_read4(&ob,14); +} + +tremor_ogg_uint32_t tremor_ogg_page_pageno(tremor_ogg_page *og){ + oggbyte_buffer ob; + if(oggbyte_init(&ob,og->header))return 0xffffffffUL; + return oggbyte_read4(&ob,18); +} + +/* returns the number of packets that are completed on this page (if + the leading packet is begun on a previous page, but ends on this + page, it's counted */ + +/* NOTE: +If a page consists of a packet begun on a previous page, and a new +packet begun (but not completed) on this page, the return will be: + tremor_ogg_page_packets(page) ==1, + tremor_ogg_page_continued(page) !=0 + +If a page happens to be a single packet that was begun on a +previous page, and spans to the next page (in the case of a three or +more page packet), the return will be: + tremor_ogg_page_packets(page) ==0, + tremor_ogg_page_continued(page) !=0 +*/ + +int tremor_ogg_page_packets(tremor_ogg_page *og){ + int i; + int n; + int count=0; + oggbyte_buffer ob; + oggbyte_init(&ob,og->header); + + n=oggbyte_read1(&ob,26); + for(i=0;ibufferpool=tremor_ogg_buffer_create(); + return oy; +} + +int tremor_ogg_sync_destroy(tremor_ogg_sync_state *oy){ + if(oy){ + tremor_ogg_sync_reset(oy); + tremor_ogg_buffer_destroy(oy->bufferpool); + memset(oy,0,sizeof(*oy)); + _tremor_ogg_free(oy); + } + return OGG_SUCCESS; +} + +unsigned char *tremor_ogg_sync_bufferin(tremor_ogg_sync_state *oy, long bytes){ + + /* [allocate and] expose a buffer for data submission. + + If there is no head fragment + allocate one and expose it + else + if the current head fragment has sufficient unused space + expose it + else + if the current head fragment is unused + resize and expose it + else + allocate new fragment and expose it + */ + + /* base case; fifo uninitialized */ + if(!oy->fifo_head){ + oy->fifo_head=oy->fifo_tail=tremor_ogg_buffer_alloc(oy->bufferpool,bytes); + return oy->fifo_head->buffer->data; + } + + /* space left in current fragment case */ + if(oy->fifo_head->buffer->size- + oy->fifo_head->length- + oy->fifo_head->begin >= bytes) + return oy->fifo_head->buffer->data+ + oy->fifo_head->length+oy->fifo_head->begin; + + /* current fragment is unused, but too small */ + if(!oy->fifo_head->length){ + tremor_ogg_buffer_realloc(oy->fifo_head,bytes); + return oy->fifo_head->buffer->data+oy->fifo_head->begin; + } + + /* current fragment used/full; get new fragment */ + { + tremor_ogg_reference *new=tremor_ogg_buffer_alloc(oy->bufferpool,bytes); + oy->fifo_head->next=new; + oy->fifo_head=new; + } + return oy->fifo_head->buffer->data; +} + +int tremor_ogg_sync_wrote(tremor_ogg_sync_state *oy, long bytes){ + if(!oy->fifo_head)return OGG_EINVAL; + if(oy->fifo_head->buffer->size-oy->fifo_head->length-oy->fifo_head->begin < + bytes)return OGG_EINVAL; + oy->fifo_head->length+=bytes; + oy->fifo_fill+=bytes; + return OGG_SUCCESS; +} + +static tremor_ogg_uint32_t _checksum(tremor_ogg_reference *or, int bytes){ + tremor_ogg_uint32_t crc_reg=0; + int j,post; + + while(or){ + unsigned char *data=or->buffer->data+or->begin; + post=(byteslength?bytes:or->length); + for(j=0;j> 24)&0xff)^data[j]]; + bytes-=j; + or=or->next; + } + + return crc_reg; +} + + +/* sync the stream. This is meant to be useful for finding page + boundaries. + + return values for this: + -n) skipped n bytes + 0) page not ready; more data (no bytes skipped) + n) page synced at current location; page length n bytes + +*/ + +long tremor_ogg_sync_pageseek(tremor_ogg_sync_state *oy,tremor_ogg_page *og){ + oggbyte_buffer page; + long bytes,ret=0; + + tremor_ogg_page_release(og); + + bytes=oy->fifo_fill; + oggbyte_init(&page,oy->fifo_tail); + + if(oy->headerbytes==0){ + if(bytes<27)goto sync_out; /* not enough for even a minimal header */ + + /* verify capture pattern */ + if(oggbyte_read1(&page,0)!=(int)'O' || + oggbyte_read1(&page,1)!=(int)'g' || + oggbyte_read1(&page,2)!=(int)'g' || + oggbyte_read1(&page,3)!=(int)'S' ) goto sync_fail; + + oy->headerbytes=oggbyte_read1(&page,26)+27; + } + if(bytesheaderbytes)goto sync_out; /* not enough for header + + seg table */ + if(oy->bodybytes==0){ + int i; + /* count up body length in the segment table */ + for(i=0;iheaderbytes-27;i++) + oy->bodybytes+=oggbyte_read1(&page,27+i); + } + + if(oy->bodybytes+oy->headerbytes>bytes)goto sync_out; + + /* we have what appears to be a complete page; last test: verify + checksum */ + { + tremor_ogg_uint32_t chksum=oggbyte_read4(&page,22); + oggbyte_set4(&page,0,22); + + /* Compare checksums; memory continues to be common access */ + if(chksum!=_checksum(oy->fifo_tail,oy->bodybytes+oy->headerbytes)){ + + /* D'oh. Mismatch! Corrupt page (or miscapture and not a page + at all). replace the computed checksum with the one actually + read in; remember all the memory is common access */ + + oggbyte_set4(&page,chksum,22); + goto sync_fail; + } + oggbyte_set4(&page,chksum,22); + } + + /* We have a page. Set up page return. */ + if(og){ + /* set up page output */ + og->header=tremor_ogg_buffer_split(&oy->fifo_tail,&oy->fifo_head,oy->headerbytes); + og->header_len=oy->headerbytes; + og->body=tremor_ogg_buffer_split(&oy->fifo_tail,&oy->fifo_head,oy->bodybytes); + og->body_len=oy->bodybytes; + }else{ + /* simply advance */ + oy->fifo_tail= + tremor_ogg_buffer_pretruncate(oy->fifo_tail,oy->headerbytes+oy->bodybytes); + if(!oy->fifo_tail)oy->fifo_head=0; + } + + ret=oy->headerbytes+oy->bodybytes; + oy->unsynced=0; + oy->headerbytes=0; + oy->bodybytes=0; + oy->fifo_fill-=ret; + + return ret; + + sync_fail: + + oy->headerbytes=0; + oy->bodybytes=0; + oy->fifo_tail=tremor_ogg_buffer_pretruncate(oy->fifo_tail,1); + ret--; + + /* search forward through fragments for possible capture */ + while(oy->fifo_tail){ + /* invariant: fifo_cursor points to a position in fifo_tail */ + unsigned char *now=oy->fifo_tail->buffer->data+oy->fifo_tail->begin; + unsigned char *next=memchr(now, 'O', oy->fifo_tail->length); + + if(next){ + /* possible capture in this segment */ + long bytes=next-now; + oy->fifo_tail=tremor_ogg_buffer_pretruncate(oy->fifo_tail,bytes); + ret-=bytes; + break; + }else{ + /* no capture. advance to next segment */ + long bytes=oy->fifo_tail->length; + ret-=bytes; + oy->fifo_tail=tremor_ogg_buffer_pretruncate(oy->fifo_tail,bytes); + } + } + if(!oy->fifo_tail)oy->fifo_head=0; + oy->fifo_fill+=ret; + + sync_out: + return ret; +} + +/* sync the stream and get a page. Keep trying until we find a page. + Supress 'sync errors' after reporting the first. + + return values: + OGG_HOLE) recapture (hole in data) + 0) need more data + 1) page returned + + Returns pointers into buffered data; invalidated by next call to + _stream, _clear, _init, or _buffer */ + +int tremor_ogg_sync_pageout(tremor_ogg_sync_state *oy, tremor_ogg_page *og){ + + /* all we need to do is verify a page at the head of the stream + buffer. If it doesn't verify, we look for the next potential + frame */ + + while(1){ + long ret=tremor_ogg_sync_pageseek(oy,og); + if(ret>0){ + /* have a page */ + return 1; + } + if(ret==0){ + /* need more data */ + return 0; + } + + /* head did not start a synced page... skipped some bytes */ + if(!oy->unsynced){ + oy->unsynced=1; + return OGG_HOLE; + } + + /* loop. keep looking */ + + } +} + +/* clear things to an initial state. Good to call, eg, before seeking */ +int tremor_ogg_sync_reset(tremor_ogg_sync_state *oy){ + + tremor_ogg_buffer_release(oy->fifo_tail); + oy->fifo_tail=0; + oy->fifo_head=0; + oy->fifo_fill=0; + + oy->unsynced=0; + oy->headerbytes=0; + oy->bodybytes=0; + return OGG_SUCCESS; +} + +tremor_ogg_stream_state *tremor_ogg_stream_create(int serialno){ + tremor_ogg_stream_state *os=_tremor_ogg_calloc(1,sizeof(*os)); + os->serialno=serialno; + os->pageno=-1; + return os; +} + +int tremor_ogg_stream_destroy(tremor_ogg_stream_state *os){ + if(os){ + tremor_ogg_buffer_release(os->header_tail); + tremor_ogg_buffer_release(os->body_tail); + memset(os,0,sizeof(*os)); + _tremor_ogg_free(os); + } + return OGG_SUCCESS; +} + + +#define FINFLAG 0x80000000UL +#define FINMASK 0x7fffffffUL + +static void _next_lace(oggbyte_buffer *ob,tremor_ogg_stream_state *os){ + /* search ahead one lace */ + os->body_fill_next=0; + while(os->laceptrlacing_fill){ + int val=oggbyte_read1(ob,27+os->laceptr++); + os->body_fill_next+=val; + if(val<255){ + os->body_fill_next|=FINFLAG; + os->clearflag=1; + break; + } + } +} + +static void _span_queued_page(tremor_ogg_stream_state *os){ + while( !(os->body_fill&FINFLAG) ){ + + if(!os->header_tail)break; + + /* first flush out preceeding page header (if any). Body is + flushed as it's consumed, so that's not done here. */ + + if(os->lacing_fill>=0) + os->header_tail=tremor_ogg_buffer_pretruncate(os->header_tail, + os->lacing_fill+27); + os->lacing_fill=0; + os->laceptr=0; + os->clearflag=0; + + if(!os->header_tail){ + os->header_head=0; + break; + }else{ + + /* process/prepare next page, if any */ + + long pageno; + oggbyte_buffer ob; + tremor_ogg_page og; /* only for parsing header values */ + og.header=os->header_tail; /* only for parsing header values */ + pageno=tremor_ogg_page_pageno(&og); + + oggbyte_init(&ob,os->header_tail); + os->lacing_fill=oggbyte_read1(&ob,26); + + /* are we in sequence? */ + if(pageno!=os->pageno){ + if(os->pageno==-1) /* indicates seek or reset */ + os->holeflag=1; /* set for internal use */ + else + os->holeflag=2; /* set for external reporting */ + + os->body_tail=tremor_ogg_buffer_pretruncate(os->body_tail, + os->body_fill); + if(os->body_tail==0)os->body_head=0; + os->body_fill=0; + + } + + if(tremor_ogg_page_continued(&og)){ + if(os->body_fill==0){ + /* continued packet, but no preceeding data to continue */ + /* dump the first partial packet on the page */ + _next_lace(&ob,os); + os->body_tail= + tremor_ogg_buffer_pretruncate(os->body_tail,os->body_fill_next&FINMASK); + if(os->body_tail==0)os->body_head=0; + /* set span flag */ + if(!os->spanflag && !os->holeflag)os->spanflag=2; + } + }else{ + if(os->body_fill>0){ + /* preceeding data to continue, but not a continued page */ + /* dump body_fill */ + os->body_tail=tremor_ogg_buffer_pretruncate(os->body_tail, + os->body_fill); + if(os->body_tail==0)os->body_head=0; + os->body_fill=0; + + /* set espan flag */ + if(!os->spanflag && !os->holeflag)os->spanflag=2; + } + } + + if(os->laceptrlacing_fill){ + os->granulepos=tremor_ogg_page_granulepos(&og); + + /* get current packet size & flag */ + _next_lace(&ob,os); + os->body_fill+=os->body_fill_next; /* addition handles the flag fine; + unsigned on purpose */ + /* ...and next packet size & flag */ + _next_lace(&ob,os); + + } + + os->pageno=pageno+1; + os->e_o_s=tremor_ogg_page_eos(&og); + os->b_o_s=tremor_ogg_page_bos(&og); + + } + } +} + +/* add the incoming page to the stream state; we decompose the page + into packet segments here as well. */ + +int tremor_ogg_stream_pagein(tremor_ogg_stream_state *os, tremor_ogg_page *og){ + + int serialno=tremor_ogg_page_serialno(og); + int version=tremor_ogg_page_version(og); + + /* check the serial number */ + if(serialno!=os->serialno){ + tremor_ogg_page_release(og); + return OGG_ESERIAL; + } + if(version>0){ + tremor_ogg_page_release(og); + return OGG_EVERSION; + } + + /* add to fifos */ + if(!os->body_tail){ + os->body_tail=og->body; + os->body_head=tremor_ogg_buffer_walk(og->body); + }else{ + os->body_head=tremor_ogg_buffer_cat(os->body_head,og->body); + } + if(!os->header_tail){ + os->header_tail=og->header; + os->header_head=tremor_ogg_buffer_walk(og->header); + os->lacing_fill=-27; + }else{ + os->header_head=tremor_ogg_buffer_cat(os->header_head,og->header); + } + + memset(og,0,sizeof(*og)); + return OGG_SUCCESS; +} + +int tremor_ogg_stream_reset(tremor_ogg_stream_state *os){ + + tremor_ogg_buffer_release(os->header_tail); + tremor_ogg_buffer_release(os->body_tail); + os->header_tail=os->header_head=0; + os->body_tail=os->body_head=0; + + os->e_o_s=0; + os->b_o_s=0; + os->pageno=-1; + os->packetno=0; + os->granulepos=0; + + os->body_fill=0; + os->lacing_fill=0; + + os->holeflag=0; + os->spanflag=0; + os->clearflag=0; + os->laceptr=0; + os->body_fill_next=0; + + return OGG_SUCCESS; +} + +int tremor_ogg_stream_reset_serialno(tremor_ogg_stream_state *os,int serialno){ + tremor_ogg_stream_reset(os); + os->serialno=serialno; + return OGG_SUCCESS; +} + +static int _packetout(tremor_ogg_stream_state *os,tremor_ogg_packet *op,int adv){ + + tremor_ogg_packet_release(op); + _span_queued_page(os); + + if(os->holeflag){ + int temp=os->holeflag; + if(os->clearflag) + os->holeflag=0; + else + os->holeflag=1; + if(temp==2){ + os->packetno++; + return OGG_HOLE; + } + } + if(os->spanflag){ + int temp=os->spanflag; + if(os->clearflag) + os->spanflag=0; + else + os->spanflag=1; + if(temp==2){ + os->packetno++; + return OGG_SPAN; + } + } + + if(!(os->body_fill&FINFLAG)) return 0; + if(!op && !adv)return 1; /* just using peek as an inexpensive way + to ask if there's a whole packet + waiting */ + if(op){ + op->b_o_s=os->b_o_s; + if(os->e_o_s && os->body_fill_next==0) + op->e_o_s=os->e_o_s; + else + op->e_o_s=0; + if( (os->body_fill&FINFLAG) && !(os->body_fill_next&FINFLAG) ) + op->granulepos=os->granulepos; + else + op->granulepos=-1; + op->packetno=os->packetno; + } + + if(adv){ + oggbyte_buffer ob; + oggbyte_init(&ob,os->header_tail); + + /* split the body contents off */ + if(op){ + op->packet=tremor_ogg_buffer_split(&os->body_tail,&os->body_head, + os->body_fill&FINMASK); + op->bytes=os->body_fill&FINMASK; + }else{ + os->body_tail=tremor_ogg_buffer_pretruncate(os->body_tail, + os->body_fill&FINMASK); + if(os->body_tail==0)os->body_head=0; + } + + /* update lacing pointers */ + os->body_fill=os->body_fill_next; + _next_lace(&ob,os); + }else{ + if(op){ + op->packet=tremor_ogg_buffer_sub(os->body_tail,os->body_fill&FINMASK); + op->bytes=os->body_fill&FINMASK; + } + } + + if(adv){ + os->packetno++; + os->b_o_s=0; + } + + return 1; +} + +int tremor_ogg_stream_packetout(tremor_ogg_stream_state *os,tremor_ogg_packet *op){ + return _packetout(os,op,1); +} + +int tremor_ogg_stream_packetpeek(tremor_ogg_stream_state *os,tremor_ogg_packet *op){ + return _packetout(os,op,0); +} + +int tremor_ogg_packet_release(tremor_ogg_packet *op) { + if(op){ + tremor_ogg_buffer_release(op->packet); + memset(op, 0, sizeof(*op)); + } + return OGG_SUCCESS; +} + +int tremor_ogg_page_release(tremor_ogg_page *og) { + if(og){ + tremor_ogg_buffer_release(og->header); + tremor_ogg_buffer_release(og->body); + memset(og, 0, sizeof(*og)); + } + return OGG_SUCCESS; +} + +void tremor_ogg_page_dup(tremor_ogg_page *dup,tremor_ogg_page *orig){ + dup->header_len=orig->header_len; + dup->body_len=orig->body_len; + dup->header=tremor_ogg_buffer_dup(orig->header); + dup->body=tremor_ogg_buffer_dup(orig->body); +} + diff --git a/lib/tremor/info.c b/lib/tremor/info.c index 24e24ac7..da393f9f 100644 --- a/lib/tremor/info.c +++ b/lib/tremor/info.c @@ -1,12 +1,12 @@ /******************************************************************** * * - * THIS FILE IS PART OF THE OggVorbis 'TREMOR' CODEC SOURCE CODE. * + * THIS FILE IS PART OF THE TremorOggVorbis 'TREMOR' CODEC SOURCE CODE. * * * * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS * * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE * * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. * * * - * THE OggVorbis 'TREMOR' SOURCE CODE IS (C) COPYRIGHT 1994-2003 * + * THE TremorOggVorbis 'TREMOR' SOURCE CODE IS (C) COPYRIGHT 1994-2003 * * BY THE Xiph.Org FOUNDATION http://www.xiph.org/ * * * ******************************************************************** @@ -21,19 +21,17 @@ #include #include #include -#include -#include +#include "tremor_ogg.h" #include "ivorbiscodec.h" #include "codec_internal.h" #include "codebook.h" -#include "registry.h" -#include "window.h" #include "misc.h" +#include "os.h" /* helpers */ -static void _v_readstring(oggpack_buffer *o,char *buf,int bytes){ +static void _v_readstring(tremor_oggpack_buffer *o,char *buf,int bytes){ while(bytes--){ - *buf++=oggpack_read(o,8); + *buf++=tremor_oggpack_read(o,8); } } @@ -92,15 +90,13 @@ int vorbis_comment_query_count(vorbis_comment *vc, char *tag){ void vorbis_comment_clear(vorbis_comment *vc){ if(vc){ long i; - if(vc->user_comments){ - for(i=0;icomments;i++) - if(vc->user_comments[i])_ogg_free(vc->user_comments[i]); - _ogg_free(vc->user_comments); - } - if(vc->comment_lengths)_ogg_free(vc->comment_lengths); - if(vc->vendor)_ogg_free(vc->vendor); - memset(vc,0,sizeof(*vc)); + for(i=0;icomments;i++) + if(vc->user_comments[i])_tremor_ogg_free(vc->user_comments[i]); + if(vc->user_comments)_tremor_ogg_free(vc->user_comments); + if(vc->comment_lengths)_tremor_ogg_free(vc->comment_lengths); + if(vc->vendor)_tremor_ogg_free(vc->vendor); } + memset(vc,0,sizeof(*vc)); } /* blocksize 0 is guaranteed to be short, 1 is guarantted to be long. @@ -113,7 +109,7 @@ int vorbis_info_blocksize(vorbis_info *vi,int zo){ /* used by synthesis, which has a full, alloced vi */ void vorbis_info_init(vorbis_info *vi){ memset(vi,0,sizeof(*vi)); - vi->codec_setup=(codec_setup_info *)_ogg_calloc(1,sizeof(codec_setup_info)); + vi->codec_setup=(codec_setup_info *)_tremor_ogg_calloc(1,sizeof(codec_setup_info)); } void vorbis_info_clear(vorbis_info *vi){ @@ -122,33 +118,37 @@ void vorbis_info_clear(vorbis_info *vi){ if(ci){ - for(i=0;imodes;i++) - if(ci->mode_param[i])_ogg_free(ci->mode_param[i]); + if(ci->mode_param)_tremor_ogg_free(ci->mode_param); - for(i=0;imaps;i++) /* unpack does the range checking */ - if(ci->map_param[i]) - _mapping_P[ci->map_type[i]]->free_info(ci->map_param[i]); + if(ci->map_param){ + for(i=0;imaps;i++) /* unpack does the range checking */ + mapping_clear_info(ci->map_param+i); + _tremor_ogg_free(ci->map_param); + } - for(i=0;ifloors;i++) /* unpack does the range checking */ - if(ci->floor_param[i]) - _floor_P[ci->floor_type[i]]->free_info(ci->floor_param[i]); - - for(i=0;iresidues;i++) /* unpack does the range checking */ - if(ci->residue_param[i]) - _residue_P[ci->residue_type[i]]->free_info(ci->residue_param[i]); - - for(i=0;ibooks;i++){ - if(ci->book_param[i]){ - /* knows if the book was not alloced */ - vorbis_staticbook_destroy(ci->book_param[i]); - } - if(ci->fullbooks) - vorbis_book_clear(ci->fullbooks+i); + if(ci->floor_param){ + for(i=0;ifloors;i++) /* unpack does the range checking */ + if(ci->floor_type[i]) + floor1_free_info(ci->floor_param[i]); + else + floor0_free_info(ci->floor_param[i]); + _tremor_ogg_free(ci->floor_param); + _tremor_ogg_free(ci->floor_type); + } + + if(ci->residue_param){ + for(i=0;iresidues;i++) /* unpack does the range checking */ + res_clear_info(ci->residue_param+i); + _tremor_ogg_free(ci->residue_param); + } + + if(ci->book_param){ + for(i=0;ibooks;i++) + vorbis_book_clear(ci->book_param+i); + _tremor_ogg_free(ci->book_param); } - if(ci->fullbooks) - _ogg_free(ci->fullbooks); - _ogg_free(ci); + _tremor_ogg_free(ci); } memset(vi,0,sizeof(*vi)); @@ -156,30 +156,36 @@ void vorbis_info_clear(vorbis_info *vi){ /* Header packing/unpacking ********************************************/ -static int _vorbis_unpack_info(vorbis_info *vi,oggpack_buffer *opb){ +static int _vorbis_unpack_info(vorbis_info *vi,tremor_oggpack_buffer *opb){ codec_setup_info *ci=(codec_setup_info *)vi->codec_setup; if(!ci)return(OV_EFAULT); - vi->version=oggpack_read(opb,32); + vi->version=tremor_oggpack_read(opb,32); if(vi->version!=0)return(OV_EVERSION); - vi->channels=oggpack_read(opb,8); - vi->rate=oggpack_read(opb,32); + vi->channels=tremor_oggpack_read(opb,8); + vi->rate=tremor_oggpack_read(opb,32); - vi->bitrate_upper=oggpack_read(opb,32); - vi->bitrate_nominal=oggpack_read(opb,32); - vi->bitrate_lower=oggpack_read(opb,32); + vi->bitrate_upper=tremor_oggpack_read(opb,32); + vi->bitrate_nominal=tremor_oggpack_read(opb,32); + vi->bitrate_lower=tremor_oggpack_read(opb,32); - ci->blocksizes[0]=1<blocksizes[1]=1<blocksizes[0]=1<blocksizes[1]=1<rate>=64000 || ci->blocksizes[1]>4096)goto err_out; +#else + if(vi->rate<64000 && ci->blocksizes[1]>4096)goto err_out; +#endif + if(vi->rate<1)goto err_out; if(vi->channels<1)goto err_out; if(ci->blocksizes[0]<64)goto err_out; if(ci->blocksizes[1]blocksizes[0])goto err_out; if(ci->blocksizes[1]>8192)goto err_out; - if(oggpack_read(opb,1)!=1)goto err_out; /* EOP check */ + if(tremor_oggpack_read(opb,1)!=1)goto err_out; /* EOP check */ return(0); err_out: @@ -187,34 +193,25 @@ static int _vorbis_unpack_info(vorbis_info *vi,oggpack_buffer *opb){ return(OV_EBADHEADER); } -static int _vorbis_unpack_comment(vorbis_comment *vc,oggpack_buffer *opb){ +static int _vorbis_unpack_comment(vorbis_comment *vc,tremor_oggpack_buffer *opb){ int i; - int vendorlen; - vendorlen=oggpack_read(opb,32); + int vendorlen=tremor_oggpack_read(opb,32); if(vendorlen<0)goto err_out; - if(vendorlen>opb->storage-oggpack_bytes(opb))goto err_out; - vc->vendor=(char *)_ogg_calloc(vendorlen+1,1); - if(vc->vendor==NULL)goto err_out; + vc->vendor=(char *)_tremor_ogg_calloc(vendorlen+1,1); _v_readstring(opb,vc->vendor,vendorlen); - i=oggpack_read(opb,32); - if(i<0||i>=INT_MAX||i>(opb->storage-oggpack_bytes(opb))>>2)goto err_out; - vc->user_comments=(char **)_ogg_calloc(i+1,sizeof(*vc->user_comments)); - vc->comment_lengths=(int *)_ogg_calloc(i+1, sizeof(*vc->comment_lengths)); - if(vc->user_comments==NULL||vc->comment_lengths==NULL)goto err_out; - vc->comments=i; - + vc->comments=tremor_oggpack_read(opb,32); + if(vc->comments<0)goto err_out; + vc->user_comments=(char **)_tremor_ogg_calloc(vc->comments+1,sizeof(*vc->user_comments)); + vc->comment_lengths=(int *)_tremor_ogg_calloc(vc->comments+1, sizeof(*vc->comment_lengths)); + for(i=0;icomments;i++){ - int len=oggpack_read(opb,32); - if(len<0||len>opb->storage-oggpack_bytes(opb))goto err_out; - vc->comment_lengths[i]=len; - vc->user_comments[i]=(char *)_ogg_calloc(len+1,1); - if(vc->user_comments[i]==NULL){ - vc->comments=i; - goto err_out; - } + int len=tremor_oggpack_read(opb,32); + if(len<0)goto err_out; + vc->comment_lengths[i]=len; + vc->user_comments[i]=(char *)_tremor_ogg_calloc(len+1,1); _v_readstring(opb,vc->user_comments[i],len); - } - if(oggpack_read(opb,1)!=1)goto err_out; /* EOP check */ + } + if(tremor_oggpack_read(opb,1)!=1)goto err_out; /* EOP check */ return(0); err_out: @@ -224,76 +221,63 @@ static int _vorbis_unpack_comment(vorbis_comment *vc,oggpack_buffer *opb){ /* all of the real encoding details are here. The modes, books, everything */ -static int _vorbis_unpack_books(vorbis_info *vi,oggpack_buffer *opb){ +static int _vorbis_unpack_books(vorbis_info *vi,tremor_oggpack_buffer *opb){ codec_setup_info *ci=(codec_setup_info *)vi->codec_setup; int i; + if(!ci)return(OV_EFAULT); /* codebooks */ - ci->books=oggpack_read(opb,8)+1; - if(ci->books<=0)goto err_out; - for(i=0;ibooks;i++){ - ci->book_param[i]=vorbis_staticbook_unpack(opb); - if(!ci->book_param[i])goto err_out; - } + ci->books=tremor_oggpack_read(opb,8)+1; + ci->book_param=(codebook *)_tremor_ogg_calloc(ci->books,sizeof(*ci->book_param)); + for(i=0;ibooks;i++) + if(vorbis_book_unpack(opb,ci->book_param+i))goto err_out; - /* time backend settings */ - ci->times=oggpack_read(opb,6)+1; - if(ci->times<=0)goto err_out; - for(i=0;itimes;i++){ - ci->time_type[i]=oggpack_read(opb,16); - if(ci->time_type[i]<0 || ci->time_type[i]>=VI_TIMEB)goto err_out; - /* ci->time_param[i]=_time_P[ci->time_type[i]]->unpack(vi,opb); - Vorbis I has no time backend */ - /*if(!ci->time_param[i])goto err_out;*/ - } + /* time backend settings, not actually used */ + i=tremor_oggpack_read(opb,6); + for(;i>=0;i--) + if(tremor_oggpack_read(opb,16)!=0)goto err_out; /* floor backend settings */ - ci->floors=oggpack_read(opb,6)+1; - if(ci->floors<=0)goto err_out; + ci->floors=tremor_oggpack_read(opb,6)+1; + ci->floor_param=_tremor_ogg_malloc(sizeof(*ci->floor_param)*ci->floors); + ci->floor_type=_tremor_ogg_malloc(sizeof(*ci->floor_type)*ci->floors); for(i=0;ifloors;i++){ - ci->floor_type[i]=oggpack_read(opb,16); + ci->floor_type[i]=tremor_oggpack_read(opb,16); if(ci->floor_type[i]<0 || ci->floor_type[i]>=VI_FLOORB)goto err_out; - ci->floor_param[i]=_floor_P[ci->floor_type[i]]->unpack(vi,opb); + if(ci->floor_type[i]) + ci->floor_param[i]=floor1_info_unpack(vi,opb); + else + ci->floor_param[i]=floor0_info_unpack(vi,opb); if(!ci->floor_param[i])goto err_out; } /* residue backend settings */ - ci->residues=oggpack_read(opb,6)+1; - if(ci->residues<=0)goto err_out; - for(i=0;iresidues;i++){ - ci->residue_type[i]=oggpack_read(opb,16); - if(ci->residue_type[i]<0 || ci->residue_type[i]>=VI_RESB)goto err_out; - ci->residue_param[i]=_residue_P[ci->residue_type[i]]->unpack(vi,opb); - if(!ci->residue_param[i])goto err_out; - } + ci->residues=tremor_oggpack_read(opb,6)+1; + ci->residue_param=_tremor_ogg_malloc(sizeof(*ci->residue_param)*ci->residues); + for(i=0;iresidues;i++) + if(res_unpack(ci->residue_param+i,vi,opb))goto err_out; /* map backend settings */ - ci->maps=oggpack_read(opb,6)+1; - if(ci->maps<=0)goto err_out; + ci->maps=tremor_oggpack_read(opb,6)+1; + ci->map_param=_tremor_ogg_malloc(sizeof(*ci->map_param)*ci->maps); for(i=0;imaps;i++){ - ci->map_type[i]=oggpack_read(opb,16); - if(ci->map_type[i]<0 || ci->map_type[i]>=VI_MAPB)goto err_out; - ci->map_param[i]=_mapping_P[ci->map_type[i]]->unpack(vi,opb); - if(!ci->map_param[i])goto err_out; + if(tremor_oggpack_read(opb,16)!=0)goto err_out; + if(mapping_info_unpack(ci->map_param+i,vi,opb))goto err_out; } /* mode settings */ - ci->modes=oggpack_read(opb,6)+1; - if(ci->modes<=0)goto err_out; + ci->modes=tremor_oggpack_read(opb,6)+1; + ci->mode_param= + (vorbis_info_mode *)_tremor_ogg_malloc(ci->modes*sizeof(*ci->mode_param)); for(i=0;imodes;i++){ - ci->mode_param[i]=(vorbis_info_mode *)_ogg_calloc(1,sizeof(*ci->mode_param[i])); - ci->mode_param[i]->blockflag=oggpack_read(opb,1); - ci->mode_param[i]->windowtype=oggpack_read(opb,16); - ci->mode_param[i]->transformtype=oggpack_read(opb,16); - ci->mode_param[i]->mapping=oggpack_read(opb,8); - - if(ci->mode_param[i]->windowtype>=VI_WINDOWB)goto err_out; - if(ci->mode_param[i]->transformtype>=VI_WINDOWB)goto err_out; - if(ci->mode_param[i]->mapping>=ci->maps)goto err_out; - if(ci->mode_param[i]->mapping<0)goto err_out; + ci->mode_param[i].blockflag=tremor_oggpack_read(opb,1); + if(tremor_oggpack_read(opb,16))goto err_out; + if(tremor_oggpack_read(opb,16))goto err_out; + ci->mode_param[i].mapping=tremor_oggpack_read(opb,8); + if(ci->mode_param[i].mapping>=ci->maps)goto err_out; } - if(oggpack_read(opb,1)!=1)goto err_out; /* top level EOP check */ + if(tremor_oggpack_read(opb,1)!=1)goto err_out; /* top level EOP check */ return(0); err_out: @@ -301,47 +285,22 @@ static int _vorbis_unpack_books(vorbis_info *vi,oggpack_buffer *opb){ return(OV_EBADHEADER); } -/* Is this packet a vorbis ID header? */ -int vorbis_synthesis_idheader(ogg_packet *op){ - oggpack_buffer opb; - char buffer[6]; - - if(op){ - oggpack_readinit(&opb,op->packet,op->bytes); - - if(!op->b_o_s) - return(0); /* Not the initial packet */ - - if(oggpack_read(&opb,8) != 1) - return 0; /* not an ID header */ - - memset(buffer,0,6); - _v_readstring(&opb,buffer,6); - if(memcmp(buffer,"vorbis",6)) - return 0; /* not vorbis */ - - return 1; - } - - return 0; -} - /* The Vorbis header is in three packets; the initial small packet in the first page that identifies basic parameters, a second packet with bitstream comments and a third packet that holds the codebook. */ -int vorbis_synthesis_headerin(vorbis_info *vi,vorbis_comment *vc,ogg_packet *op){ - oggpack_buffer opb; +int vorbis_dsp_headerin(vorbis_info *vi,vorbis_comment *vc,tremor_ogg_packet *op){ + tremor_oggpack_buffer opb; if(op){ - oggpack_readinit(&opb,op->packet,op->bytes); + tremor_oggpack_readinit(&opb,op->packet); /* Which of the three types of header is this? */ /* Also verify header-ness, vorbis */ { char buffer[6]; - int packtype=oggpack_read(&opb,8); + int packtype=tremor_oggpack_read(&opb,8); memset(buffer,0,6); _v_readstring(&opb,buffer,6); if(memcmp(buffer,"vorbis",6)){ @@ -366,10 +325,6 @@ int vorbis_synthesis_headerin(vorbis_info *vi,vorbis_comment *vc,ogg_packet *op) /* um... we didn't get the initial header */ return(OV_EBADHEADER); } - if(vc->vendor!=NULL){ - /* previously initialized comment header */ - return(OV_EBADHEADER); - } return(_vorbis_unpack_comment(vc,&opb)); @@ -378,14 +333,6 @@ int vorbis_synthesis_headerin(vorbis_info *vi,vorbis_comment *vc,ogg_packet *op) /* um... we didn;t get the initial header or comments yet */ return(OV_EBADHEADER); } - if(vi->codec_setup==NULL){ - /* improperly initialized vorbis_info */ - return(OV_EFAULT); - } - if(((codec_setup_info *)vi->codec_setup)->books>0){ - /* previously initialized setup header */ - return(OV_EBADHEADER); - } return(_vorbis_unpack_books(vi,&opb)); diff --git a/lib/tremor/iseeking_example.c b/lib/tremor/iseeking_example.c deleted file mode 100644 index dc971ba4..00000000 --- a/lib/tremor/iseeking_example.c +++ /dev/null @@ -1,265 +0,0 @@ -/******************************************************************** - * * - * THIS FILE IS PART OF THE OggVorbis 'TREMOR' CODEC SOURCE CODE. * - * * - * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS * - * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE * - * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. * - * * - * THE OggVorbis 'TREMOR' SOURCE CODE IS (C) COPYRIGHT 1994-2009 * - * BY THE Xiph.Org FOUNDATION http://www.xiph.org/ * - * * - ******************************************************************** - - function: illustrate seeking, and test it too - last mod: $Id$ - - ********************************************************************/ - -#include -#include -#include "ivorbiscodec.h" -#include "ivorbisfile.h" - -#ifdef _WIN32 /* We need the following two to set stdin/stdout to binary */ -# include -# include -#endif - -void _verify(OggVorbis_File *ov, - ogg_int64_t val, - ogg_int64_t pcmval, - ogg_int64_t timeval, - ogg_int64_t pcmlength, - char *bigassbuffer){ - int j; - long bread; - char buffer[4096]; - int dummy; - ogg_int64_t pos; - - /* verify the raw position, the pcm position and position decode */ - if(val!=-1 && ov_raw_tell(ov)pcmval){ - fprintf(stderr,"pcm position out of tolerance: requested %ld, got %ld\n", - (long)pcmval,(long)ov_pcm_tell(ov)); - exit(1); - } - if(timeval!=-1 && ov_time_tell(ov)>timeval){ - fprintf(stderr,"time position out of tolerance: requested %ld, got %ld\n", - (long)timeval,(long)ov_time_tell(ov)); - exit(1); - } - pos=ov_pcm_tell(ov); - if(pos<0 || pos>pcmlength){ - fprintf(stderr,"pcm position out of bounds: got %ld\n",(long)pos); - exit(1); - } - bread=ov_read(ov,buffer,4096,&dummy); - if(bigassbuffer){ - for(j=0;jchannels!=2){ - fprintf(stderr,"Sorry; right now seeking_test can only use Vorbis files\n" - "that are entirely stereo.\n\n"); - exit(1); - } - } - - /* because we want to do sample-level verification that the seek - does what it claimed, decode the entire file into memory */ - pcmlength=ov_pcm_total(&ov,-1); - timelength=ov_time_total(&ov,-1); - bigassbuffer=malloc(pcmlength*4); /* w00t */ - if(bigassbuffer){ - i=0; - while(ival+1){ - fprintf(stderr,"Declared position didn't perfectly match request: %ld != %ld\n", - (long)val,(long)ov_time_tell(&ov)); - exit(1); - } - - _verify(&ov,-1,-1,val,pcmlength,bigassbuffer); - - } - } - - fprintf(stderr,"\r \nOK.\n\n"); - - - }else{ - fprintf(stderr,"Standard input was not seekable.\n"); - } - - ov_clear(&ov); - return 0; -} - - - - - - - - - - - - - diff --git a/lib/tremor/ivorbiscodec.h b/lib/tremor/ivorbiscodec.h index 17eab58d..41d4d5da 100644 --- a/lib/tremor/ivorbiscodec.h +++ b/lib/tremor/ivorbiscodec.h @@ -1,12 +1,12 @@ /******************************************************************** * * - * THIS FILE IS PART OF THE OggVorbis 'TREMOR' CODEC SOURCE CODE. * + * THIS FILE IS PART OF THE TremorOggVorbis 'TREMOR' CODEC SOURCE CODE. * * * * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS * * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE * * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. * * * - * THE OggVorbis 'TREMOR' SOURCE CODE IS (C) COPYRIGHT 1994-2002 * + * THE TremorOggVorbis 'TREMOR' SOURCE CODE IS (C) COPYRIGHT 1994-2002 * * BY THE Xiph.Org FOUNDATION http://www.xiph.org/ * * * ******************************************************************** @@ -23,7 +23,10 @@ extern "C" { #endif /* __cplusplus */ -#include +#include "tremor_ogg.h" + +struct vorbis_dsp_state; +typedef struct vorbis_dsp_state vorbis_dsp_state; typedef struct vorbis_info{ int version; @@ -53,80 +56,7 @@ typedef struct vorbis_info{ void *codec_setup; } vorbis_info; -/* vorbis_dsp_state buffers the current vorbis audio - analysis/synthesis state. The DSP state belongs to a specific - logical bitstream ****************************************************/ -typedef struct vorbis_dsp_state{ - int analysisp; - vorbis_info *vi; - - ogg_int32_t **pcm; - ogg_int32_t **pcmret; - int pcm_storage; - int pcm_current; - int pcm_returned; - - int preextrapolate; - int eofflag; - - long lW; - long W; - long nW; - long centerW; - - ogg_int64_t granulepos; - ogg_int64_t sequence; - - void *backend_state; -} vorbis_dsp_state; - -typedef struct vorbis_block{ - /* necessary stream state for linking to the framing abstraction */ - ogg_int32_t **pcm; /* this is a pointer into local storage */ - oggpack_buffer opb; - - long lW; - long W; - long nW; - int pcmend; - int mode; - - int eofflag; - ogg_int64_t granulepos; - ogg_int64_t sequence; - vorbis_dsp_state *vd; /* For read-only access of configuration */ - - /* local storage to avoid remallocing; it's up to the mapping to - structure it */ - void *localstore; - long localtop; - long localalloc; - long totaluse; - struct alloc_chain *reap; - -} vorbis_block; - -/* vorbis_block is a single block of data to be processed as part of -the analysis/synthesis stream; it belongs to a specific logical -bitstream, but is independant from other vorbis_blocks belonging to -that logical bitstream. *************************************************/ - -struct alloc_chain{ - void *ptr; - struct alloc_chain *next; -}; - -/* vorbis_info contains all the setup information specific to the - specific compression/decompression mode in progress (eg, - psychoacoustic settings, channel setup, options, codebook - etc). vorbis_info and substructures are in backends.h. -*********************************************************************/ - -/* the comments are not part of vorbis_info so that vorbis_info can be - static storage */ typedef struct vorbis_comment{ - /* unlimited user comment fields. libvorbis writes 'libvorbis' - whatever vendor is set to in encode */ char **user_comments; int *comment_lengths; int comments; @@ -135,18 +65,6 @@ typedef struct vorbis_comment{ } vorbis_comment; -/* libvorbis encodes in two abstraction layers; first we perform DSP - and produce a packet (see docs/analysis.txt). The packet is then - coded into a framed OggSquish bitstream by the second layer (see - docs/framing.txt). Decode is the reverse process; we sync/frame - the bitstream and extract individual packets, then decode the - packet back into PCM audio. - - The extra framing/packetizing is used in streaming formats, such as - files. Over the net (such as with UDP), the framing and - packetization aren't necessary as they're provided by the transport - and the streaming layer is not used */ - /* Vorbis PRIMITIVES: general ***************************************/ extern void vorbis_info_init(vorbis_info *vi); @@ -160,24 +78,6 @@ extern char *vorbis_comment_query(vorbis_comment *vc, char *tag, int count); extern int vorbis_comment_query_count(vorbis_comment *vc, char *tag); extern void vorbis_comment_clear(vorbis_comment *vc); -extern int vorbis_block_init(vorbis_dsp_state *v, vorbis_block *vb); -extern int vorbis_block_clear(vorbis_block *vb); -extern void vorbis_dsp_clear(vorbis_dsp_state *v); - -/* Vorbis PRIMITIVES: synthesis layer *******************************/ -extern int vorbis_synthesis_idheader(ogg_packet *op); -extern int vorbis_synthesis_headerin(vorbis_info *vi,vorbis_comment *vc, - ogg_packet *op); - -extern int vorbis_synthesis_init(vorbis_dsp_state *v,vorbis_info *vi); -extern int vorbis_synthesis_restart(vorbis_dsp_state *v); -extern int vorbis_synthesis(vorbis_block *vb,ogg_packet *op); -extern int vorbis_synthesis_trackonly(vorbis_block *vb,ogg_packet *op); -extern int vorbis_synthesis_blockin(vorbis_dsp_state *v,vorbis_block *vb); -extern int vorbis_synthesis_pcmout(vorbis_dsp_state *v,ogg_int32_t ***pcm); -extern int vorbis_synthesis_read(vorbis_dsp_state *v,int samples); -extern long vorbis_packet_blocksize(vorbis_info *vi,ogg_packet *op); - /* Vorbis ERRORS and return codes ***********************************/ #define OV_FALSE -1 diff --git a/lib/tremor/ivorbisfile.h b/lib/tremor/ivorbisfile.h index f6ecb0e4..c8734031 100644 --- a/lib/tremor/ivorbisfile.h +++ b/lib/tremor/ivorbisfile.h @@ -1,12 +1,12 @@ /******************************************************************** * * - * THIS FILE IS PART OF THE OggVorbis 'TREMOR' CODEC SOURCE CODE. * + * THIS FILE IS PART OF THE TremorOggVorbis 'TREMOR' CODEC SOURCE CODE. * * * * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS * * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE * * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. * * * - * THE OggVorbis 'TREMOR' SOURCE CODE IS (C) COPYRIGHT 1994-2002 * + * THE TremorOggVorbis 'TREMOR' SOURCE CODE IS (C) COPYRIGHT 1994-2003 * * BY THE Xiph.Org FOUNDATION http://www.xiph.org/ * * * ******************************************************************** @@ -26,8 +26,6 @@ extern "C" #include #include "ivorbiscodec.h" -#define CHUNKSIZE 65535 -#define READSIZE 1024 /* The function prototypes for the callbacks are basically the same as for * the stdio functions fread, fseek, fclose, ftell. * The one difference is that the FILE * arguments have been replaced with @@ -40,86 +38,79 @@ extern "C" */ typedef struct { size_t (*read_func) (void *ptr, size_t size, size_t nmemb, void *datasource); - int (*seek_func) (void *datasource, ogg_int64_t offset, int whence); + int (*seek_func) (void *datasource, tremor_ogg_int64_t offset, int whence); int (*close_func) (void *datasource); long (*tell_func) (void *datasource); } ov_callbacks; -#define NOTOPEN 0 -#define PARTOPEN 1 -#define OPENED 2 -#define STREAMSET 3 -#define INITSET 4 - -typedef struct OggVorbis_File { +typedef struct TremorOggVorbis_File { void *datasource; /* Pointer to a FILE *, etc. */ int seekable; - ogg_int64_t offset; - ogg_int64_t end; - ogg_sync_state oy; + tremor_ogg_int64_t offset; + tremor_ogg_int64_t end; + tremor_ogg_sync_state *oy; /* If the FILE handle isn't seekable (eg, a pipe), only the current stream appears */ int links; - ogg_int64_t *offsets; - ogg_int64_t *dataoffsets; - ogg_uint32_t *serialnos; - ogg_int64_t *pcmlengths; - vorbis_info *vi; - vorbis_comment *vc; + tremor_ogg_int64_t *offsets; + tremor_ogg_int64_t *dataoffsets; + tremor_ogg_uint32_t *serialnos; + tremor_ogg_int64_t *pcmlengths; + vorbis_info vi; + vorbis_comment vc; /* Decoding working state local storage */ - ogg_int64_t pcm_offset; + tremor_ogg_int64_t pcm_offset; int ready_state; - ogg_uint32_t current_serialno; + tremor_ogg_uint32_t current_serialno; int current_link; - ogg_int64_t bittrack; - ogg_int64_t samptrack; + tremor_ogg_int64_t bittrack; + tremor_ogg_int64_t samptrack; - ogg_stream_state os; /* take physical pages, weld into a logical + tremor_ogg_stream_state *os; /* take physical pages, weld into a logical stream of packets */ - vorbis_dsp_state vd; /* central working state for the packet->PCM decoder */ - vorbis_block vb; /* local working space for packet->PCM decode */ + vorbis_dsp_state *vd; /* central working state for the packet->PCM decoder */ ov_callbacks callbacks; -} OggVorbis_File; +} TremorOggVorbis_File; -extern int ov_clear(OggVorbis_File *vf); -extern int ov_open(FILE *f,OggVorbis_File *vf,const char *initial,long ibytes); -extern int ov_open_callbacks(void *datasource, OggVorbis_File *vf, - const char *initial, long ibytes, ov_callbacks callbacks); +extern int ov_clear(TremorOggVorbis_File *vf); +extern int ov_open(FILE *f,TremorOggVorbis_File *vf,char *initial,long ibytes); +extern int ov_open_callbacks(void *datasource, TremorOggVorbis_File *vf, + char *initial, long ibytes, ov_callbacks callbacks); -extern int ov_test(FILE *f,OggVorbis_File *vf,const char *initial,long ibytes); -extern int ov_test_callbacks(void *datasource, OggVorbis_File *vf, - const char *initial, long ibytes, ov_callbacks callbacks); -extern int ov_test_open(OggVorbis_File *vf); +extern int ov_test(FILE *f,TremorOggVorbis_File *vf,char *initial,long ibytes); +extern int ov_test_callbacks(void *datasource, TremorOggVorbis_File *vf, + char *initial, long ibytes, ov_callbacks callbacks); +extern int ov_test_open(TremorOggVorbis_File *vf); -extern long ov_bitrate(OggVorbis_File *vf,int i); -extern long ov_bitrate_instant(OggVorbis_File *vf); -extern long ov_streams(OggVorbis_File *vf); -extern long ov_seekable(OggVorbis_File *vf); -extern long ov_serialnumber(OggVorbis_File *vf,int i); +extern long ov_bitrate(TremorOggVorbis_File *vf,int i); +extern long ov_bitrate_instant(TremorOggVorbis_File *vf); +extern long ov_streams(TremorOggVorbis_File *vf); +extern long ov_seekable(TremorOggVorbis_File *vf); +extern long ov_serialnumber(TremorOggVorbis_File *vf,int i); -extern ogg_int64_t ov_raw_total(OggVorbis_File *vf,int i); -extern ogg_int64_t ov_pcm_total(OggVorbis_File *vf,int i); -extern ogg_int64_t ov_time_total(OggVorbis_File *vf,int i); +extern tremor_ogg_int64_t ov_raw_total(TremorOggVorbis_File *vf,int i); +extern tremor_ogg_int64_t ov_pcm_total(TremorOggVorbis_File *vf,int i); +extern tremor_ogg_int64_t ov_time_total(TremorOggVorbis_File *vf,int i); -extern int ov_raw_seek(OggVorbis_File *vf,ogg_int64_t pos); -extern int ov_pcm_seek(OggVorbis_File *vf,ogg_int64_t pos); -extern int ov_pcm_seek_page(OggVorbis_File *vf,ogg_int64_t pos); -extern int ov_time_seek(OggVorbis_File *vf,ogg_int64_t pos); -extern int ov_time_seek_page(OggVorbis_File *vf,ogg_int64_t pos); +extern int ov_raw_seek(TremorOggVorbis_File *vf,tremor_ogg_int64_t pos); +extern int ov_pcm_seek(TremorOggVorbis_File *vf,tremor_ogg_int64_t pos); +extern int ov_pcm_seek_page(TremorOggVorbis_File *vf,tremor_ogg_int64_t pos); +extern int ov_time_seek(TremorOggVorbis_File *vf,tremor_ogg_int64_t pos); +extern int ov_time_seek_page(TremorOggVorbis_File *vf,tremor_ogg_int64_t pos); -extern ogg_int64_t ov_raw_tell(OggVorbis_File *vf); -extern ogg_int64_t ov_pcm_tell(OggVorbis_File *vf); -extern ogg_int64_t ov_time_tell(OggVorbis_File *vf); +extern tremor_ogg_int64_t ov_raw_tell(TremorOggVorbis_File *vf); +extern tremor_ogg_int64_t ov_pcm_tell(TremorOggVorbis_File *vf); +extern tremor_ogg_int64_t ov_time_tell(TremorOggVorbis_File *vf); -extern vorbis_info *ov_info(OggVorbis_File *vf,int link); -extern vorbis_comment *ov_comment(OggVorbis_File *vf,int link); +extern vorbis_info *ov_info(TremorOggVorbis_File *vf,int link); +extern vorbis_comment *ov_comment(TremorOggVorbis_File *vf,int link); -extern long ov_read(OggVorbis_File *vf,char *buffer,int length, +extern long ov_read(TremorOggVorbis_File *vf,void *buffer,int length, int *bitstream); #ifdef __cplusplus diff --git a/lib/tremor/ivorbisfile_example.c b/lib/tremor/ivorbisfile_example.c index 7b0cf109..5c0e6bcc 100644 --- a/lib/tremor/ivorbisfile_example.c +++ b/lib/tremor/ivorbisfile_example.c @@ -1,12 +1,12 @@ /******************************************************************** * * - * THIS FILE IS PART OF THE OggVorbis 'TREMOR' CODEC SOURCE CODE. * + * THIS FILE IS PART OF THE TremorOggVorbis 'TREMOR' CODEC SOURCE CODE. * * * * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS * * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE * * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. * * * - * THE OggVorbis 'TREMOR' SOURCE CODE IS (C) COPYRIGHT 1994-2002 * + * THE TremorOggVorbis 'TREMOR' SOURCE CODE IS (C) COPYRIGHT 1994-2002 * * BY THE Xiph.Org FOUNDATION http://www.xiph.org/ * * * ******************************************************************** @@ -32,7 +32,7 @@ char pcmout[4096]; /* take 4k out of the data segment, not the stack */ int main(){ - OggVorbis_File vf; + TremorOggVorbis_File vf; int eof=0; int current_section; @@ -69,12 +69,7 @@ int main(){ /* EOF */ eof=1; } else if (ret < 0) { - if(ret==OV_EBADLINK){ - fprintf(stderr,"Corrupt bitstream section! Exiting.\n"); - exit(1); - } - - /* some other error in the stream. Not a problem, just reporting it in + /* error in the stream. Not a problem, just reporting it in case we (the app) cares. In this case, we don't. */ } else { /* we don't bother dealing with sample rate changes, etc, but diff --git a/lib/tremor/lsp_lookup.h b/lib/tremor/lsp_lookup.h index 7162392b..3edcab3a 100644 --- a/lib/tremor/lsp_lookup.h +++ b/lib/tremor/lsp_lookup.h @@ -1,12 +1,12 @@ /******************************************************************** * * - * THIS FILE IS PART OF THE OggVorbis 'TREMOR' CODEC SOURCE CODE. * + * THIS FILE IS PART OF THE TremorOggVorbis 'TREMOR' CODEC SOURCE CODE. * * * * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS * * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE * * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. * * * - * THE OggVorbis 'TREMOR' SOURCE CODE IS (C) COPYRIGHT 1994-2002 * + * THE TremorOggVorbis 'TREMOR' SOURCE CODE IS (C) COPYRIGHT 1994-2002 * * BY THE Xiph.Org FOUNDATION http://www.xiph.org/ * * * ******************************************************************** @@ -18,35 +18,7 @@ #ifndef _V_LOOKUP_DATA_H_ #define _V_LOOKUP_DATA_H_ -#include - -#define FROMdB_LOOKUP_SZ 35 -#define FROMdB2_LOOKUP_SZ 32 -#define FROMdB_SHIFT 5 -#define FROMdB2_SHIFT 3 -#define FROMdB2_MASK 31 - -static const ogg_int32_t FROMdB_LOOKUP[FROMdB_LOOKUP_SZ]={ - 0x003fffff, 0x0028619b, 0x00197a96, 0x0010137a, - 0x000a24b0, 0x00066666, 0x000409c3, 0x00028c42, - 0x00019b8c, 0x000103ab, 0x0000a3d7, 0x00006760, - 0x0000413a, 0x00002928, 0x000019f8, 0x00001062, - 0x00000a56, 0x00000686, 0x0000041e, 0x00000299, - 0x000001a3, 0x00000109, 0x000000a7, 0x00000069, - 0x00000042, 0x0000002a, 0x0000001a, 0x00000011, - 0x0000000b, 0x00000007, 0x00000004, 0x00000003, - 0x00000002, 0x00000001, 0x00000001}; - -static const ogg_int32_t FROMdB2_LOOKUP[FROMdB2_LOOKUP_SZ]={ - 0x000001fc, 0x000001f5, 0x000001ee, 0x000001e7, - 0x000001e0, 0x000001d9, 0x000001d2, 0x000001cc, - 0x000001c5, 0x000001bf, 0x000001b8, 0x000001b2, - 0x000001ac, 0x000001a6, 0x000001a0, 0x0000019a, - 0x00000194, 0x0000018e, 0x00000188, 0x00000183, - 0x0000017d, 0x00000178, 0x00000172, 0x0000016d, - 0x00000168, 0x00000163, 0x0000015e, 0x00000159, - 0x00000154, 0x0000014f, 0x0000014a, 0x00000145, -}; +#include "os_types.h" #define INVSQ_LOOKUP_I_SHIFT 10 #define INVSQ_LOOKUP_I_MASK 1023 @@ -92,7 +64,7 @@ static const long INVSQ_LOOKUP_IDel[64]={ #define COS_LOOKUP_I_SHIFT 9 #define COS_LOOKUP_I_MASK 511 #define COS_LOOKUP_I_SZ 128 -static const ogg_int32_t COS_LOOKUP_I[COS_LOOKUP_I_SZ+1]={ +static const tremor_ogg_int32_t COS_LOOKUP_I[COS_LOOKUP_I_SZ+1]={ 16384, 16379, 16364, 16340, 16305, 16261, 16207, 16143, 16069, 15986, 15893, 15791, diff --git a/lib/tremor/mapping0.c b/lib/tremor/mapping0.c index aa03e854..3da185c5 100644 --- a/lib/tremor/mapping0.c +++ b/lib/tremor/mapping0.c @@ -1,12 +1,12 @@ /******************************************************************** * * - * THIS FILE IS PART OF THE OggVorbis 'TREMOR' CODEC SOURCE CODE. * + * THIS FILE IS PART OF THE TremorOggVorbis 'TREMOR' CODEC SOURCE CODE. * * * * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS * * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE * * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. * * * - * THE OggVorbis 'TREMOR' SOURCE CODE IS (C) COPYRIGHT 1994-2002 * + * THE TremorOggVorbis 'TREMOR' SOURCE CODE IS (C) COPYRIGHT 1994-2003 * * BY THE Xiph.Org FOUNDATION http://www.xiph.org/ * * * ******************************************************************** @@ -19,101 +19,23 @@ #include #include #include -#include +#include "tremor_ogg.h" +#include "os.h" #include "ivorbiscodec.h" #include "mdct.h" #include "codec_internal.h" #include "codebook.h" -#include "window.h" -#include "registry.h" #include "misc.h" -/* simplistic, wasteful way of doing this (unique lookup for each - mode/submapping); there should be a central repository for - identical lookups. That will require minor work, so I'm putting it - off as low priority. - - Why a lookup for each backend in a given mode? Because the - blocksize is set by the mode, and low backend lookups may require - parameters from other areas of the mode/mapping */ - -typedef struct { - vorbis_info_mode *mode; - vorbis_info_mapping0 *map; - - vorbis_look_floor **floor_look; - - vorbis_look_residue **residue_look; - - vorbis_func_floor **floor_func; - vorbis_func_residue **residue_func; - - int ch; - long lastframe; /* if a different mode is called, we need to - invalidate decay */ -} vorbis_look_mapping0; - -static void mapping0_free_info(vorbis_info_mapping *i){ - vorbis_info_mapping0 *info=(vorbis_info_mapping0 *)i; +void mapping_clear_info(vorbis_info_mapping *info){ if(info){ + if(info->chmuxlist)_tremor_ogg_free(info->chmuxlist); + if(info->submaplist)_tremor_ogg_free(info->submaplist); + if(info->coupling)_tremor_ogg_free(info->coupling); memset(info,0,sizeof(*info)); - _ogg_free(info); - } -} - -static void mapping0_free_look(vorbis_look_mapping *look){ - int i; - vorbis_look_mapping0 *l=(vorbis_look_mapping0 *)look; - if(l){ - - for(i=0;imap->submaps;i++){ - l->floor_func[i]->free_look(l->floor_look[i]); - l->residue_func[i]->free_look(l->residue_look[i]); - } - - _ogg_free(l->floor_func); - _ogg_free(l->residue_func); - _ogg_free(l->floor_look); - _ogg_free(l->residue_look); - memset(l,0,sizeof(*l)); - _ogg_free(l); } } -static vorbis_look_mapping *mapping0_look(vorbis_dsp_state *vd,vorbis_info_mode *vm, - vorbis_info_mapping *m){ - int i; - vorbis_info *vi=vd->vi; - codec_setup_info *ci=(codec_setup_info *)vi->codec_setup; - vorbis_look_mapping0 *look=(vorbis_look_mapping0 *)_ogg_calloc(1,sizeof(*look)); - vorbis_info_mapping0 *info=look->map=(vorbis_info_mapping0 *)m; - look->mode=vm; - - look->floor_look=(vorbis_look_floor **)_ogg_calloc(info->submaps,sizeof(*look->floor_look)); - - look->residue_look=(vorbis_look_residue **)_ogg_calloc(info->submaps,sizeof(*look->residue_look)); - - look->floor_func=(vorbis_func_floor **)_ogg_calloc(info->submaps,sizeof(*look->floor_func)); - look->residue_func=(vorbis_func_residue **)_ogg_calloc(info->submaps,sizeof(*look->residue_func)); - - for(i=0;isubmaps;i++){ - int floornum=info->floorsubmap[i]; - int resnum=info->residuesubmap[i]; - - look->floor_func[i]=_floor_P[ci->floor_type[floornum]]; - look->floor_look[i]=look->floor_func[i]-> - look(vd,vm,ci->floor_param[floornum]); - look->residue_func[i]=_residue_P[ci->residue_type[resnum]]; - look->residue_look[i]=look->residue_func[i]-> - look(vd,vm,ci->residue_param[resnum]); - - } - - look->ch=vi->channels; - - return(look); -} - static int ilog(unsigned int v){ int ret=0; if(v)--v; @@ -125,28 +47,25 @@ static int ilog(unsigned int v){ } /* also responsible for range checking */ -static vorbis_info_mapping *mapping0_unpack(vorbis_info *vi,oggpack_buffer *opb){ - int i,b; - vorbis_info_mapping0 *info=(vorbis_info_mapping0 *)_ogg_calloc(1,sizeof(*info)); +int mapping_info_unpack(vorbis_info_mapping *info,vorbis_info *vi, + tremor_oggpack_buffer *opb){ + int i; codec_setup_info *ci=(codec_setup_info *)vi->codec_setup; memset(info,0,sizeof(*info)); - b=oggpack_read(opb,1); - if(b<0)goto err_out; - if(b){ - info->submaps=oggpack_read(opb,4)+1; - if(info->submaps<=0)goto err_out; - }else + if(tremor_oggpack_read(opb,1)) + info->submaps=tremor_oggpack_read(opb,4)+1; + else info->submaps=1; - b=oggpack_read(opb,1); - if(b<0)goto err_out; - if(b){ - info->coupling_steps=oggpack_read(opb,8)+1; - if(info->coupling_steps<=0)goto err_out; + if(tremor_oggpack_read(opb,1)){ + info->coupling_steps=tremor_oggpack_read(opb,8)+1; + info->coupling= + _tremor_ogg_malloc(info->coupling_steps*sizeof(*info->coupling)); + for(i=0;icoupling_steps;i++){ - int testM=info->coupling_mag[i]=oggpack_read(opb,ilog(vi->channels)); - int testA=info->coupling_ang[i]=oggpack_read(opb,ilog(vi->channels)); + int testM=info->coupling[i].mag=tremor_oggpack_read(opb,ilog(vi->channels)); + int testA=info->coupling[i].ang=tremor_oggpack_read(opb,ilog(vi->channels)); if(testM<0 || testA<0 || @@ -157,72 +76,82 @@ static vorbis_info_mapping *mapping0_unpack(vorbis_info *vi,oggpack_buffer *opb) } - if(oggpack_read(opb,2)!=0)goto err_out; /* 2,3:reserved */ + if(tremor_oggpack_read(opb,2)>0)goto err_out; /* 2,3:reserved */ if(info->submaps>1){ + info->chmuxlist=_tremor_ogg_malloc(sizeof(*info->chmuxlist)*vi->channels); for(i=0;ichannels;i++){ - info->chmuxlist[i]=oggpack_read(opb,4); - if(info->chmuxlist[i]>=info->submaps || info->chmuxlist[i]<0)goto err_out; + info->chmuxlist[i]=tremor_oggpack_read(opb,4); + if(info->chmuxlist[i]>=info->submaps)goto err_out; } } + + info->submaplist=_tremor_ogg_malloc(sizeof(*info->submaplist)*info->submaps); for(i=0;isubmaps;i++){ - int temp=oggpack_read(opb,8); - if(temp>=ci->times)goto err_out; - info->floorsubmap[i]=oggpack_read(opb,8); - if(info->floorsubmap[i]>=ci->floors || info->floorsubmap[i]<0)goto err_out; - info->residuesubmap[i]=oggpack_read(opb,8); - if(info->residuesubmap[i]>=ci->residues || info->residuesubmap[i]<0) - goto err_out; + int temp=tremor_oggpack_read(opb,8); + info->submaplist[i].floor=tremor_oggpack_read(opb,8); + if(info->submaplist[i].floor>=ci->floors)goto err_out; + info->submaplist[i].residue=tremor_oggpack_read(opb,8); + if(info->submaplist[i].residue>=ci->residues)goto err_out; } - return info; + return 0; err_out: - mapping0_free_info(info); - return(NULL); + mapping_clear_info(info); + return -1; } -static int seq=0; -static int mapping0_inverse(vorbis_block *vb,vorbis_look_mapping *l){ - vorbis_dsp_state *vd=vb->vd; +int mapping_inverse(vorbis_dsp_state *vd,vorbis_info_mapping *info){ vorbis_info *vi=vd->vi; codec_setup_info *ci=(codec_setup_info *)vi->codec_setup; - private_state *b=(private_state *)vd->backend_state; - vorbis_look_mapping0 *look=(vorbis_look_mapping0 *)l; - vorbis_info_mapping0 *info=look->map; int i,j; - long n=vb->pcmend=ci->blocksizes[vb->W]; - - ogg_int32_t **pcmbundle=(ogg_int32_t **)alloca(sizeof(*pcmbundle)*vi->channels); - int *zerobundle=(int *)alloca(sizeof(*zerobundle)*vi->channels); + long n=ci->blocksizes[vd->W]; + + tremor_ogg_int32_t **pcmbundle= + alloca(sizeof(*pcmbundle)*vi->channels); + int *zerobundle= + alloca(sizeof(*zerobundle)*vi->channels); + int *nonzero= + alloca(sizeof(*nonzero)*vi->channels); + tremor_ogg_int32_t **floormemo= + alloca(sizeof(*floormemo)*vi->channels); - int *nonzero =(int *)alloca(sizeof(*nonzero)*vi->channels); - void **floormemo=(void **)alloca(sizeof(*floormemo)*vi->channels); - - /* time domain information decode (note that applying the - information would have to happen later; we'll probably add a - function entry to the harness for that later */ - /* NOT IMPLEMENTED */ - /* recover the spectral envelope; store it in the PCM vector for now */ for(i=0;ichannels;i++){ - int submap=info->chmuxlist[i]; - floormemo[i]=look->floor_func[submap]-> - inverse1(vb,look->floor_look[submap]); + int submap=0; + int floorno; + + if(info->submaps>1) + submap=info->chmuxlist[i]; + floorno=info->submaplist[submap].floor; + + if(ci->floor_type[floorno]){ + /* floor 1 */ + floormemo[i]=alloca(sizeof(*floormemo[i])* + floor1_memosize(ci->floor_param[floorno])); + floormemo[i]=floor1_inverse1(vd,ci->floor_param[floorno],floormemo[i]); + }else{ + /* floor 0 */ + floormemo[i]=alloca(sizeof(*floormemo[i])* + floor0_memosize(ci->floor_param[floorno])); + floormemo[i]=floor0_inverse1(vd,ci->floor_param[floorno],floormemo[i]); + } + if(floormemo[i]) nonzero[i]=1; else nonzero[i]=0; - memset(vb->pcm[i],0,sizeof(*vb->pcm[i])*n/2); + memset(vd->work[i],0,sizeof(*vd->work[i])*n/2); } /* channel coupling can 'dirty' the nonzero listing */ for(i=0;icoupling_steps;i++){ - if(nonzero[info->coupling_mag[i]] || - nonzero[info->coupling_ang[i]]){ - nonzero[info->coupling_mag[i]]=1; - nonzero[info->coupling_ang[i]]=1; + if(nonzero[info->coupling[i].mag] || + nonzero[info->coupling[i].ang]){ + nonzero[info->coupling[i].mag]=1; + nonzero[info->coupling[i].ang]=1; } } @@ -230,31 +159,30 @@ static int mapping0_inverse(vorbis_block *vb,vorbis_look_mapping *l){ for(i=0;isubmaps;i++){ int ch_in_bundle=0; for(j=0;jchannels;j++){ - if(info->chmuxlist[j]==i){ + if(!info->chmuxlist || info->chmuxlist[j]==i){ if(nonzero[j]) zerobundle[ch_in_bundle]=1; else zerobundle[ch_in_bundle]=0; - pcmbundle[ch_in_bundle++]=vb->pcm[j]; + pcmbundle[ch_in_bundle++]=vd->work[j]; } } - look->residue_func[i]->inverse(vb,look->residue_look[i], - pcmbundle,zerobundle,ch_in_bundle); + res_inverse(vd,ci->residue_param+info->submaplist[i].residue, + pcmbundle,zerobundle,ch_in_bundle); } //for(j=0;jchannels;j++) //_analysis_output("coupled",seq+j,vb->pcm[j],-8,n/2,0,0); - /* channel coupling */ for(i=info->coupling_steps-1;i>=0;i--){ - ogg_int32_t *pcmM=vb->pcm[info->coupling_mag[i]]; - ogg_int32_t *pcmA=vb->pcm[info->coupling_ang[i]]; + tremor_ogg_int32_t *pcmM=vd->work[info->coupling[i].mag]; + tremor_ogg_int32_t *pcmA=vd->work[info->coupling[i].ang]; for(j=0;j0) if(ang>0){ @@ -280,10 +208,21 @@ static int mapping0_inverse(vorbis_block *vb,vorbis_look_mapping *l){ /* compute and apply spectral envelope */ for(i=0;ichannels;i++){ - ogg_int32_t *pcm=vb->pcm[i]; - int submap=info->chmuxlist[i]; - look->floor_func[submap]-> - inverse2(vb,look->floor_look[submap],floormemo[i],pcm); + tremor_ogg_int32_t *pcm=vd->work[i]; + int submap=0; + int floorno; + + if(info->submaps>1) + submap=info->chmuxlist[i]; + floorno=info->submaplist[submap].floor; + + if(ci->floor_type[floorno]){ + /* floor 1 */ + floor1_inverse2(vd,ci->floor_param[floorno],floormemo[i],pcm); + }else{ + /* floor 0 */ + floor0_inverse2(vd,ci->floor_param[floorno],floormemo[i],pcm); + } } //for(j=0;jchannels;j++) @@ -291,38 +230,12 @@ static int mapping0_inverse(vorbis_block *vb,vorbis_look_mapping *l){ /* transform the PCM data; takes PCM vector, vb; modifies PCM vector */ /* only MDCT right now.... */ - for(i=0;ichannels;i++){ - ogg_int32_t *pcm=vb->pcm[i]; - mdct_backward(n,pcm,pcm); - } + for(i=0;ichannels;i++) + mdct_backward(n,vd->work[i]); //for(j=0;jchannels;j++) //_analysis_output("imdct",seq+j,vb->pcm[j],-24,n,0,0); - /* window the data */ - for(i=0;ichannels;i++){ - ogg_int32_t *pcm=vb->pcm[i]; - if(nonzero[i]) - _vorbis_apply_window(pcm,b->window,ci->blocksizes,vb->lW,vb->W,vb->nW); - else - for(j=0;jchannels;j++) - //_analysis_output("window",seq+j,vb->pcm[j],-24,n,0,0); - - seq+=vi->channels; /* all done! */ return(0); } - -/* export hooks */ -vorbis_func_mapping mapping0_exportbundle={ - &mapping0_unpack, - &mapping0_look, - &mapping0_free_info, - &mapping0_free_look, - &mapping0_inverse -}; diff --git a/lib/tremor/mdct.c b/lib/tremor/mdct.c index 2aed62c5..40f53877 100644 --- a/lib/tremor/mdct.c +++ b/lib/tremor/mdct.c @@ -1,19 +1,19 @@ /******************************************************************** * * - * THIS FILE IS PART OF THE OggVorbis 'TREMOR' CODEC SOURCE CODE. * + * THIS FILE IS PART OF THE TremorOggVorbis 'TREMOR' CODEC SOURCE CODE. * * * * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS * * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE * * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. * * * - * THE OggVorbis 'TREMOR' SOURCE CODE IS (C) COPYRIGHT 1994-2002 * + * THE TremorOggVorbis 'TREMOR' SOURCE CODE IS (C) COPYRIGHT 1994-2003 * * BY THE Xiph.Org FOUNDATION http://www.xiph.org/ * * * ******************************************************************** function: normalized modified discrete cosine transform power of two length transform only [64 <= n ] - last mod: $Id$ + last mod: $Id: mdct.c,v 1.9.6.5 2003/04/29 04:03:27 xiphmont Exp $ Original algorithm adapted long ago from _The use of multirate filter banks for coding of high quality digital audio_, by T. Sporer, @@ -33,23 +33,62 @@ ********************************************************************/ #include "ivorbiscodec.h" -#include "codebook.h" +#include "os.h" #include "misc.h" #include "mdct.h" #include "mdct_lookup.h" +STIN void presymmetry(DATA_TYPE *in,int n2,int step){ + DATA_TYPE *aX; + DATA_TYPE *bX; + LOOKUP_T *T; + int n4=n2>>1; + + aX = in+n2-3; + T = sincos_lookup0; + + do{ + REG_TYPE r0= aX[0]; + REG_TYPE r2= aX[2]; + XPROD31( r0, r2, T[0], T[1], &aX[0], &aX[2] ); T+=step; + aX-=4; + }while(aX>=in+n4); + do{ + REG_TYPE r0= aX[0]; + REG_TYPE r2= aX[2]; + XPROD31( r0, r2, T[1], T[0], &aX[0], &aX[2] ); T-=step; + aX-=4; + }while(aX>=in); + + aX = in+n2-4; + bX = in; + T = sincos_lookup0; + do{ + REG_TYPE ri0= aX[0]; + REG_TYPE ri2= aX[2]; + REG_TYPE ro0= bX[0]; + REG_TYPE ro2= bX[2]; + + XNPROD31( ro2, ro0, T[1], T[0], &aX[0], &aX[2] ); T+=step; + XNPROD31( ri2, ri0, T[0], T[1], &bX[0], &bX[2] ); + + aX-=4; + bX+=4; + }while(aX>=in+n4); + +} /* 8 point butterfly (in place) */ STIN void mdct_butterfly_8(DATA_TYPE *x){ - REG_TYPE r0 = x[4] + x[0]; - REG_TYPE r1 = x[4] - x[0]; - REG_TYPE r2 = x[5] + x[1]; - REG_TYPE r3 = x[5] - x[1]; - REG_TYPE r4 = x[6] + x[2]; - REG_TYPE r5 = x[6] - x[2]; - REG_TYPE r6 = x[7] + x[3]; - REG_TYPE r7 = x[7] - x[3]; + REG_TYPE r0 = x[0] + x[1]; + REG_TYPE r1 = x[0] - x[1]; + REG_TYPE r2 = x[2] + x[3]; + REG_TYPE r3 = x[2] - x[3]; + REG_TYPE r4 = x[4] + x[5]; + REG_TYPE r5 = x[4] - x[5]; + REG_TYPE r6 = x[6] + x[7]; + REG_TYPE r7 = x[6] - x[7]; x[0] = r5 + r3; x[1] = r7 - r1; @@ -64,29 +103,25 @@ STIN void mdct_butterfly_8(DATA_TYPE *x){ /* 16 point butterfly (in place, 4 register) */ STIN void mdct_butterfly_16(DATA_TYPE *x){ - - REG_TYPE r0, r1; - - r0 = x[ 0] - x[ 8]; x[ 8] += x[ 0]; - r1 = x[ 1] - x[ 9]; x[ 9] += x[ 1]; - x[ 0] = MULT31((r0 + r1) , cPI2_8); - x[ 1] = MULT31((r1 - r0) , cPI2_8); - MB(); - - r0 = x[10] - x[ 2]; x[10] += x[ 2]; - r1 = x[ 3] - x[11]; x[11] += x[ 3]; - x[ 2] = r1; x[ 3] = r0; - MB(); - - r0 = x[12] - x[ 4]; x[12] += x[ 4]; - r1 = x[13] - x[ 5]; x[13] += x[ 5]; - x[ 4] = MULT31((r0 - r1) , cPI2_8); - x[ 5] = MULT31((r0 + r1) , cPI2_8); + + REG_TYPE r0, r1, r2, r3; + + r0 = x[ 8] - x[ 9]; x[ 8] += x[ 9]; + r1 = x[10] - x[11]; x[10] += x[11]; + r2 = x[ 1] - x[ 0]; x[ 9] = x[ 1] + x[0]; + r3 = x[ 3] - x[ 2]; x[11] = x[ 3] + x[2]; + x[ 0] = MULT31((r0 - r1) , cPI2_8); + x[ 1] = MULT31((r2 + r3) , cPI2_8); + x[ 2] = MULT31((r0 + r1) , cPI2_8); + x[ 3] = MULT31((r3 - r2) , cPI2_8); MB(); - r0 = x[14] - x[ 6]; x[14] += x[ 6]; - r1 = x[15] - x[ 7]; x[15] += x[ 7]; - x[ 6] = r0; x[ 7] = r1; + r2 = x[12] - x[13]; x[12] += x[13]; + r3 = x[14] - x[15]; x[14] += x[15]; + r0 = x[ 4] - x[ 5]; x[13] = x[ 5] + x[ 4]; + r1 = x[ 7] - x[ 6]; x[15] = x[ 7] + x[ 6]; + x[ 4] = r2; x[ 5] = r1; + x[ 6] = r3; x[ 7] = r0; MB(); mdct_butterfly_8(x); @@ -96,48 +131,40 @@ STIN void mdct_butterfly_16(DATA_TYPE *x){ /* 32 point butterfly (in place, 4 register) */ STIN void mdct_butterfly_32(DATA_TYPE *x){ - REG_TYPE r0, r1; - - r0 = x[30] - x[14]; x[30] += x[14]; - r1 = x[31] - x[15]; x[31] += x[15]; - x[14] = r0; x[15] = r1; - MB(); - - r0 = x[28] - x[12]; x[28] += x[12]; - r1 = x[29] - x[13]; x[29] += x[13]; - XNPROD31( r0, r1, cPI1_8, cPI3_8, &x[12], &x[13] ); - MB(); - - r0 = x[26] - x[10]; x[26] += x[10]; - r1 = x[27] - x[11]; x[27] += x[11]; - x[10] = MULT31((r0 - r1) , cPI2_8); - x[11] = MULT31((r0 + r1) , cPI2_8); - MB(); - - r0 = x[24] - x[ 8]; x[24] += x[ 8]; - r1 = x[25] - x[ 9]; x[25] += x[ 9]; - XNPROD31( r0, r1, cPI3_8, cPI1_8, &x[ 8], &x[ 9] ); - MB(); + REG_TYPE r0, r1, r2, r3; - r0 = x[22] - x[ 6]; x[22] += x[ 6]; - r1 = x[ 7] - x[23]; x[23] += x[ 7]; - x[ 6] = r1; x[ 7] = r0; + r0 = x[16] - x[17]; x[16] += x[17]; + r1 = x[18] - x[19]; x[18] += x[19]; + r2 = x[ 1] - x[ 0]; x[17] = x[ 1] + x[ 0]; + r3 = x[ 3] - x[ 2]; x[19] = x[ 3] + x[ 2]; + XNPROD31( r0, r1, cPI3_8, cPI1_8, &x[ 0], &x[ 2] ); + XPROD31 ( r2, r3, cPI1_8, cPI3_8, &x[ 1], &x[ 3] ); MB(); - r0 = x[ 4] - x[20]; x[20] += x[ 4]; - r1 = x[ 5] - x[21]; x[21] += x[ 5]; - XPROD31 ( r0, r1, cPI3_8, cPI1_8, &x[ 4], &x[ 5] ); + r0 = x[20] - x[21]; x[20] += x[21]; + r1 = x[22] - x[23]; x[22] += x[23]; + r2 = x[ 5] - x[ 4]; x[21] = x[ 5] + x[ 4]; + r3 = x[ 7] - x[ 6]; x[23] = x[ 7] + x[ 6]; + x[ 4] = MULT31((r0 - r1) , cPI2_8); + x[ 5] = MULT31((r3 + r2) , cPI2_8); + x[ 6] = MULT31((r0 + r1) , cPI2_8); + x[ 7] = MULT31((r3 - r2) , cPI2_8); MB(); - r0 = x[ 2] - x[18]; x[18] += x[ 2]; - r1 = x[ 3] - x[19]; x[19] += x[ 3]; - x[ 2] = MULT31((r1 + r0) , cPI2_8); - x[ 3] = MULT31((r1 - r0) , cPI2_8); + r0 = x[24] - x[25]; x[24] += x[25]; + r1 = x[26] - x[27]; x[26] += x[27]; + r2 = x[ 9] - x[ 8]; x[25] = x[ 9] + x[ 8]; + r3 = x[11] - x[10]; x[27] = x[11] + x[10]; + XNPROD31( r0, r1, cPI1_8, cPI3_8, &x[ 8], &x[10] ); + XPROD31 ( r2, r3, cPI3_8, cPI1_8, &x[ 9], &x[11] ); MB(); - r0 = x[ 0] - x[16]; x[16] += x[ 0]; - r1 = x[ 1] - x[17]; x[17] += x[ 1]; - XPROD31 ( r0, r1, cPI1_8, cPI3_8, &x[ 0], &x[ 1] ); + r0 = x[28] - x[29]; x[28] += x[29]; + r1 = x[30] - x[31]; x[30] += x[31]; + r2 = x[12] - x[13]; x[29] = x[13] + x[12]; + r3 = x[15] - x[14]; x[31] = x[15] + x[14]; + x[12] = r0; x[13] = r3; + x[14] = r1; x[15] = r2; MB(); mdct_butterfly_16(x); @@ -147,87 +174,30 @@ STIN void mdct_butterfly_32(DATA_TYPE *x){ /* N/stage point generic N stage butterfly (in place, 2 register) */ STIN void mdct_butterfly_generic(DATA_TYPE *x,int points,int step){ - LOOKUP_T *T = sincos_lookup0; - DATA_TYPE *x1 = x + points - 8; - DATA_TYPE *x2 = x + (points>>1) - 8; - REG_TYPE r0; - REG_TYPE r1; - - do{ - r0 = x1[6] - x2[6]; x1[6] += x2[6]; - r1 = x2[7] - x1[7]; x1[7] += x2[7]; - XPROD31( r1, r0, T[0], T[1], &x2[6], &x2[7] ); T+=step; - - r0 = x1[4] - x2[4]; x1[4] += x2[4]; - r1 = x2[5] - x1[5]; x1[5] += x2[5]; - XPROD31( r1, r0, T[0], T[1], &x2[4], &x2[5] ); T+=step; + LOOKUP_T *T = sincos_lookup0; + DATA_TYPE *x1 = x + points - 4; + DATA_TYPE *x2 = x + (points>>1) - 4; + REG_TYPE r0, r1, r2, r3; - r0 = x1[2] - x2[2]; x1[2] += x2[2]; - r1 = x2[3] - x1[3]; x1[3] += x2[3]; - XPROD31( r1, r0, T[0], T[1], &x2[2], &x2[3] ); T+=step; - - r0 = x1[0] - x2[0]; x1[0] += x2[0]; - r1 = x2[1] - x1[1]; x1[1] += x2[1]; - XPROD31( r1, r0, T[0], T[1], &x2[0], &x2[1] ); T+=step; - - x1-=8; x2-=8; - }while(Tsincos_lookup0); do{ - r0 = x2[6] - x1[6]; x1[6] += x2[6]; - r1 = x2[7] - x1[7]; x1[7] += x2[7]; - XPROD31( r0, r1, T[0], T[1], &x2[6], &x2[7] ); T+=step; - - r0 = x2[4] - x1[4]; x1[4] += x2[4]; - r1 = x2[5] - x1[5]; x1[5] += x2[5]; - XPROD31( r0, r1, T[0], T[1], &x2[4], &x2[5] ); T+=step; - - r0 = x2[2] - x1[2]; x1[2] += x2[2]; - r1 = x2[3] - x1[3]; x1[3] += x2[3]; - XPROD31( r0, r1, T[0], T[1], &x2[2], &x2[3] ); T+=step; - - r0 = x2[0] - x1[0]; x1[0] += x2[0]; - r1 = x2[1] - x1[1]; x1[1] += x2[1]; - XPROD31( r0, r1, T[0], T[1], &x2[0], &x2[1] ); T+=step; - - x1-=8; x2-=8; + r0 = x1[0] - x1[1]; x1[0] += x1[1]; + r1 = x1[3] - x1[2]; x1[2] += x1[3]; + r2 = x2[1] - x2[0]; x1[1] = x2[1] + x2[0]; + r3 = x2[3] - x2[2]; x1[3] = x2[3] + x2[2]; + XPROD31( r1, r0, T[0], T[1], &x2[0], &x2[2] ); + XPROD31( r2, r3, T[0], T[1], &x2[1], &x2[3] ); T+=step; + x1-=4; + x2-=4; }while(Tsincos_lookup0); } @@ -235,15 +205,14 @@ STIN void mdct_butterflies(DATA_TYPE *x,int points,int shift){ int stages=8-shift; int i,j; - + for(i=0;--stages>0;i++){ for(j=0;j<(1<>i)*j,points>>i,4<<(i+shift)); } - + for(j=0;j>8]|(bitrev[(x&0x0f0)>>4]<<4)|(((int)bitrev[x&0x00f])<<8); } -STIN void mdct_bitreverse(DATA_TYPE *x,int n,int step,int shift){ - +STIN void mdct_bitreverse(DATA_TYPE *x,int n,int shift){ int bit = 0; + DATA_TYPE *w = x+(n>>1); + + do{ + DATA_TYPE b = bitrev12(bit++); + DATA_TYPE *xx = x + (b>>shift); + REG_TYPE r; + + w -= 2; + + if(w>xx){ + + r = xx[0]; + xx[0] = w[0]; + w[0] = r; + + r = xx[1]; + xx[1] = w[1]; + w[1] = r; + } + }while(w>x); +} + +STIN void mdct_step7(DATA_TYPE *x,int n,int step){ DATA_TYPE *w0 = x; - DATA_TYPE *w1 = x = w0+(n>>1); + DATA_TYPE *w1 = x+(n>>1); LOOKUP_T *T = (step>=4)?(sincos_lookup0+(step>>1)):sincos_lookup1; LOOKUP_T *Ttop = T+1024; - DATA_TYPE r2; - + REG_TYPE r0, r1, r2, r3; + do{ - DATA_TYPE r3 = bitrev12(bit++); - DATA_TYPE *x0 = x + ((r3 ^ 0xfff)>>shift) -1; - DATA_TYPE *x1 = x + (r3>>shift); + w1 -= 2; - REG_TYPE r0 = x0[0] + x1[0]; - REG_TYPE r1 = x1[1] - x0[1]; + r0 = w0[0] + w1[0]; + r1 = w1[1] - w0[1]; + r2 = MULT32(r0, T[1]) + MULT32(r1, T[0]); + r3 = MULT32(r1, T[1]) - MULT32(r0, T[0]); + T+=step; - XPROD32( r0, r1, T[1], T[0], &r2, &r3 ); T+=step; - - w1 -= 4; - - r0 = (x0[1] + x1[1])>>1; - r1 = (x0[0] - x1[0])>>1; + r0 = (w0[1] + w1[1])>>1; + r1 = (w0[0] - w1[0])>>1; w0[0] = r0 + r2; w0[1] = r1 + r3; - w1[2] = r0 - r2; - w1[3] = r3 - r1; - - r3 = bitrev12(bit++); - x0 = x + ((r3 ^ 0xfff)>>shift) -1; - x1 = x + (r3>>shift); - - r0 = x0[0] + x1[0]; - r1 = x1[1] - x0[1]; - - XPROD32( r0, r1, T[1], T[0], &r2, &r3 ); T+=step; - - r0 = (x0[1] + x1[1])>>1; - r1 = (x0[0] - x1[0])>>1; - w0[2] = r0 + r2; - w0[3] = r1 + r3; w1[0] = r0 - r2; w1[1] = r3 - r1; - w0 += 4; + w0 += 2; }while(T>shift) -1; - DATA_TYPE *x1 = x + (r3>>shift); - - REG_TYPE r0 = x0[0] + x1[0]; - REG_TYPE r1 = x1[1] - x0[1]; + w1 -= 2; - T-=step; XPROD32( r0, r1, T[0], T[1], &r2, &r3 ); + r0 = w0[0] + w1[0]; + r1 = w1[1] - w0[1]; + T-=step; + r2 = MULT32(r0, T[0]) + MULT32(r1, T[1]); + r3 = MULT32(r1, T[0]) - MULT32(r0, T[1]); - w1 -= 4; - - r0 = (x0[1] + x1[1])>>1; - r1 = (x0[0] - x1[0])>>1; + r0 = (w0[1] + w1[1])>>1; + r1 = (w0[0] - w1[0])>>1; w0[0] = r0 + r2; w0[1] = r1 + r3; - w1[2] = r0 - r2; - w1[3] = r3 - r1; - - r3 = bitrev12(bit++); - x0 = x + ((r3 ^ 0xfff)>>shift) -1; - x1 = x + (r3>>shift); - - r0 = x0[0] + x1[0]; - r1 = x1[1] - x0[1]; - - T-=step; XPROD32( r0, r1, T[0], T[1], &r2, &r3 ); - - r0 = (x0[1] + x1[1])>>1; - r1 = (x0[0] - x1[0])>>1; - w0[2] = r0 + r2; - w0[3] = r1 + r3; w1[0] = r0 - r2; w1[1] = r3 - r1; - w0 += 4; + w0 += 2; }while(w0>1; - int n4=n>>2; - DATA_TYPE *iX; - DATA_TYPE *oX; +STIN void mdct_step8(DATA_TYPE *x, int n, int step){ LOOKUP_T *T; LOOKUP_T *V; + DATA_TYPE *iX =x+(n>>1); + step>>=2; + + switch(step) { + default: + T=(step>=4)?(sincos_lookup0+(step>>1)):sincos_lookup1; + do{ + REG_TYPE r0 = x[0]; + REG_TYPE r1 = -x[1]; + XPROD31( r0, r1, T[0], T[1], x, x+1); T+=step; + x +=2; + }while(x>1; + t1 = (*T++)>>1; + do{ + r0 = x[0]; + r1 = -x[1]; + t0 += (v0 = (*V++)>>1); + t1 += (v1 = (*V++)>>1); + XPROD31( r0, r1, t0, t1, x, x+1 ); + + r0 = x[2]; + r1 = -x[3]; + v0 += (t0 = (*T++)>>1); + v1 += (t1 = (*T++)>>1); + XPROD31( r0, r1, v0, v1, x+2, x+3 ); + + x += 4; + }while(x>2); + t1 += (q1 = (v1-t1)>>2); + r0 = x[0]; + r1 = -x[1]; + XPROD31( r0, r1, t0, t1, x, x+1 ); + t0 = v0-q0; + t1 = v1-q1; + r0 = x[2]; + r1 = -x[3]; + XPROD31( r0, r1, t0, t1, x+2, x+3 ); + + t0 = *T++; + t1 = *T++; + v0 += (q0 = (t0-v0)>>2); + v1 += (q1 = (t1-v1)>>2); + r0 = x[4]; + r1 = -x[5]; + XPROD31( r0, r1, v0, v1, x+4, x+5 ); + v0 = t0-q0; + v1 = t1-q1; + r0 = x[6]; + r1 = -x[7]; + XPROD31( r0, r1, v0, v1, x+5, x+6 ); + + x+=8; + }while(x=in+n4); - do{ - oX-=4; - XPROD31( iX[4], iX[6], T[1], T[0], &oX[2], &oX[3] ); T-=step; - XPROD31( iX[0], iX[2], T[1], T[0], &oX[0], &oX[1] ); T-=step; - iX-=8; - }while(iX>=in); - - iX = in+n2-8; - oX = out+n2+n4; - T = sincos_lookup0; - - do{ - T+=step; XNPROD31( iX[6], iX[4], T[0], T[1], &oX[0], &oX[1] ); - T+=step; XNPROD31( iX[2], iX[0], T[0], T[1], &oX[2], &oX[3] ); - iX-=8; - oX+=4; - }while(iX>=in+n4); - do{ - T-=step; XNPROD31( iX[6], iX[4], T[1], T[0], &oX[0], &oX[1] ); - T-=step; XNPROD31( iX[2], iX[0], T[1], T[0], &oX[2], &oX[3] ); - iX-=8; - oX+=4; - }while(iX>=in); + presymmetry(in,n>>1,step); + mdct_butterflies(in,n>>1,shift); + mdct_bitreverse(in,n,shift); + mdct_step7(in,n,step); + mdct_step8(in,n,step); +} - mdct_butterflies(out+n2,n2,shift); - mdct_bitreverse(out,n,step,shift); +void mdct_shift_right(int n, DATA_TYPE *in, DATA_TYPE *right){ + int i; + n>>=2; + in+=1; - /* rotate + window */ + for(i=0;i>=2; - { - DATA_TYPE *oX1=out+n2+n4; - DATA_TYPE *oX2=out+n2+n4; - DATA_TYPE *iX =out; - - switch(step) { - default: { - T=(step>=4)?(sincos_lookup0+(step>>1)):sincos_lookup1; - do{ - oX1-=4; - XPROD31( iX[0], -iX[1], T[0], T[1], &oX1[3], &oX2[0] ); T+=step; - XPROD31( iX[2], -iX[3], T[0], T[1], &oX1[2], &oX2[1] ); T+=step; - XPROD31( iX[4], -iX[5], T[0], T[1], &oX1[1], &oX2[2] ); T+=step; - XPROD31( iX[6], -iX[7], T[0], T[1], &oX1[0], &oX2[3] ); T+=step; - oX2+=4; - iX+=8; - }while(iX>1; - t1 = (*T++)>>1; - do{ - oX1-=4; - - t0 += (v0 = (*V++)>>1); - t1 += (v1 = (*V++)>>1); - XPROD31( iX[0], -iX[1], t0, t1, &oX1[3], &oX2[0] ); - v0 += (t0 = (*T++)>>1); - v1 += (t1 = (*T++)>>1); - XPROD31( iX[2], -iX[3], v0, v1, &oX1[2], &oX2[1] ); - t0 += (v0 = (*V++)>>1); - t1 += (v1 = (*V++)>>1); - XPROD31( iX[4], -iX[5], t0, t1, &oX1[1], &oX2[2] ); - v0 += (t0 = (*T++)>>1); - v1 += (t1 = (*T++)>>1); - XPROD31( iX[6], -iX[7], v0, v1, &oX1[0], &oX2[3] ); - - oX2+=4; - iX+=8; - }while(iX>2); - t1 += (q1 = (v1-t1)>>2); - XPROD31( iX[0], -iX[1], t0, t1, &oX1[3], &oX2[0] ); - t0 = v0-q0; - t1 = v1-q1; - XPROD31( iX[2], -iX[3], t0, t1, &oX1[2], &oX2[1] ); - - t0 = *T++; - t1 = *T++; - v0 += (q0 = (t0-v0)>>2); - v1 += (q1 = (t1-v1)>>2); - XPROD31( iX[4], -iX[5], v0, v1, &oX1[1], &oX2[2] ); - v0 = t0-q0; - v1 = t1-q1; - XPROD31( iX[6], -iX[7], v0, v1, &oX1[0], &oX2[3] ); - - oX2+=4; - iX+=8; - }while(iX>1 : n0>>1); + DATA_TYPE *r=right+(lW ? n1>>2 : n0>>2); + DATA_TYPE *post; + LOOKUP_T *wR=(W && lW ? w1+(n1>>1) : w0+(n0>>1)); + LOOKUP_T *wL=(W && lW ? w1 : w0 ); + + int preLap=(lW && !W ? (n1>>2)-(n0>>2) : 0 ); + int halfLap=(lW && W ? (n1>>2) : (n0>>2) ); + int postLap=(!lW && W ? (n1>>2)-(n0>>2) : 0 ); + int n,off; + + /* preceeding direct-copy lapping from previous frame, if any */ + if(preLap){ + n = (endpost){ + *out = CLIP_TO_15((*--r)>>9); + out+=step; } + } + + /* cross-lap; two halves due to wrap-around */ + n = (endpost){ + l-=2; + *out = CLIP_TO_15((MULT31(*--r,*--wR) + MULT31(*l,*wL++))>>9); + out+=step; + } - iX=out+n2+n4; - oX1=out+n4; - oX2=oX1; - - do{ - oX1-=4; - iX-=4; - - oX2[0] = -(oX1[3] = iX[3]); - oX2[1] = -(oX1[2] = iX[2]); - oX2[2] = -(oX1[1] = iX[1]); - oX2[3] = -(oX1[0] = iX[0]); - - oX2+=4; - }while(oX2>9); + out+=step; + l+=2; + } - do{ - oX1-=4; - oX1[0]= iX[3]; - oX1[1]= iX[2]; - oX1[2]= iX[1]; - oX1[3]= iX[0]; - iX+=4; - }while(oX1>oX2); + /* preceeding direct-copy lapping from previous frame, if any */ + if(postLap){ + n = (end>9); + out+=step; + l+=2; + } } } diff --git a/lib/tremor/mdct.h b/lib/tremor/mdct.h index 6d889072..3ddb8495 100644 --- a/lib/tremor/mdct.h +++ b/lib/tremor/mdct.h @@ -1,12 +1,12 @@ /******************************************************************** * * - * THIS FILE IS PART OF THE OggVorbis 'TREMOR' CODEC SOURCE CODE. * + * THIS FILE IS PART OF THE TremorOggVorbis 'TREMOR' CODEC SOURCE CODE. * * * * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS * * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE * * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. * * * - * THE OggVorbis 'TREMOR' SOURCE CODE IS (C) COPYRIGHT 1994-2002 * + * THE TremorOggVorbis 'TREMOR' SOURCE CODE IS (C) COPYRIGHT 1994-2003 * * BY THE Xiph.Org FOUNDATION http://www.xiph.org/ * * * ******************************************************************** @@ -21,8 +21,8 @@ #include "ivorbiscodec.h" #include "misc.h" -#define DATA_TYPE ogg_int32_t -#define REG_TYPE register ogg_int32_t +#define DATA_TYPE tremor_ogg_int32_t +#define REG_TYPE register tremor_ogg_int32_t #ifdef _LOW_ACCURACY_ #define cPI3_8 (0x0062) @@ -34,8 +34,15 @@ #define cPI1_8 (0x7641af3d) #endif -extern void mdct_forward(int n, DATA_TYPE *in, DATA_TYPE *out); -extern void mdct_backward(int n, DATA_TYPE *in, DATA_TYPE *out); +extern void mdct_backward(int n, DATA_TYPE *in); +extern void mdct_shift_right(int n, DATA_TYPE *in, DATA_TYPE *right); +extern void mdct_unroll_lap(int n0,int n1, + int lW,int W, + DATA_TYPE *in,DATA_TYPE *right, + LOOKUP_T *w0,LOOKUP_T *w1, + tremor_ogg_int16_t *out, + int step, + int start,int end /* samples, this frame */); #endif diff --git a/lib/tremor/mdct_lookup.h b/lib/tremor/mdct_lookup.h index ee4f101c..16a988e4 100644 --- a/lib/tremor/mdct_lookup.h +++ b/lib/tremor/mdct_lookup.h @@ -1,12 +1,12 @@ /******************************************************************** * * - * THIS FILE IS PART OF THE OggVorbis 'TREMOR' CODEC SOURCE CODE. * + * THIS FILE IS PART OF THE TremorOggVorbis 'TREMOR' CODEC SOURCE CODE. * * * * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS * * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE * * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. * * * - * THE OggVorbis 'TREMOR' SOURCE CODE IS (C) COPYRIGHT 1994-2002 * + * THE TremorOggVorbis 'TREMOR' SOURCE CODE IS (C) COPYRIGHT 1994-2002 * * BY THE Xiph.Org FOUNDATION http://www.xiph.org/ * * * ******************************************************************** @@ -15,10 +15,10 @@ ********************************************************************/ -#include "misc.h" +#include "os_types.h" /* {sin(2*i*PI/4096), cos(2*i*PI/4096)}, with i = 0 to 512 */ -static const LOOKUP_T sincos_lookup0[1026] = { +static LOOKUP_T sincos_lookup0[1026] = { X(0x00000000), X(0x7fffffff), X(0x003243f5), X(0x7ffff621), X(0x006487e3), X(0x7fffd886), X(0x0096cbc1), X(0x7fffa72c), X(0x00c90f88), X(0x7fff6216), X(0x00fb5330), X(0x7fff0943), @@ -279,7 +279,7 @@ static const LOOKUP_T sincos_lookup0[1026] = { }; /* {sin((2*i+1)*PI/4096), cos((2*i+1)*PI/4096)}, with i = 0 to 511 */ -static const LOOKUP_T sincos_lookup1[1024] = { +static LOOKUP_T sincos_lookup1[1024] = { X(0x001921fb), X(0x7ffffd88), X(0x004b65ee), X(0x7fffe9cb), X(0x007da9d4), X(0x7fffc251), X(0x00afeda8), X(0x7fff8719), X(0x00e23160), X(0x7fff3824), X(0x011474f6), X(0x7ffed572), diff --git a/lib/tremor/misc.c b/lib/tremor/misc.c new file mode 100644 index 00000000..8833e13c --- /dev/null +++ b/lib/tremor/misc.c @@ -0,0 +1,208 @@ +/******************************************************************** + * * + * THIS FILE IS PART OF THE TremorOggVorbis SOFTWARE CODEC SOURCE CODE. * + * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS * + * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE * + * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. * + * * + * THE TremorOggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2002 * + * by the XIPHOPHORUS Company http://www.xiph.org/ * + * * + ********************************************************************/ + +#define HEAD_ALIGN 64 +#include +#include +#include +#define MISC_C +#include "misc.h" +#include + +static void **pointers=NULL; +static long *insertlist=NULL; /* We can't embed this in the pointer list; + a pointer can have any value... */ + +static char **files=NULL; +static long *file_bytes=NULL; +static int filecount=0; + +static int ptop=0; +static int palloced=0; +static int pinsert=0; + +typedef struct { + char *file; + long line; + long ptr; + long bytes; +} head; + +long global_bytes=0; +long start_time=-1; + +static void *_insert(void *ptr,long bytes,char *file,long line){ + ((head *)ptr)->file=file; + ((head *)ptr)->line=line; + ((head *)ptr)->ptr=pinsert; + ((head *)ptr)->bytes=bytes-HEAD_ALIGN; + + if(pinsert>=palloced){ + palloced+=64; + if(pointers){ + pointers=(void **)realloc(pointers,sizeof(void **)*palloced); + insertlist=(long *)realloc(insertlist,sizeof(long *)*palloced); + }else{ + pointers=(void **)malloc(sizeof(void **)*palloced); + insertlist=(long *)malloc(sizeof(long *)*palloced); + } + } + + pointers[pinsert]=ptr; + + if(pinsert==ptop) + pinsert=++ptop; + else + pinsert=insertlist[pinsert]; + +#ifdef _VDBG_GRAPHFILE + { + FILE *out; + struct timeval tv; + static struct timezone tz; + int i; + char buffer[80]; + gettimeofday(&tv,&tz); + + for(i=0;ifile; + long bytes =((head *)ptr)->bytes; + int i; + + gettimeofday(&tv,&tz); + fprintf(out,"%ld, %ld\n",-start_time+(tv.tv_sec*1000)+(tv.tv_usec/1000), + global_bytes); + fprintf(out,"%ld, %ld\n",-start_time+(tv.tv_sec*1000)+(tv.tv_usec/1000), + global_bytes-((head *)ptr)->bytes); + fclose(out); + + for(i=0;ibytes; + + insert=((head *)ptr)->ptr; + insertlist[insert]=pinsert; + pinsert=insert; + + if(pointers[insert]==NULL){ + fprintf(stderr,"DEBUGGING MALLOC ERROR: freeing previously freed memory\n"); + fprintf(stderr,"\t%s %ld\n",((head *)ptr)->file,((head *)ptr)->line); + } + + if(global_bytes<0){ + fprintf(stderr,"DEBUGGING MALLOC ERROR: freeing unmalloced memory\n"); + } + + pointers[insert]=NULL; +} + +void _VDBG_dump(void){ + int i; + for(i=0;ifile,ptr->line); + } + +} + +extern void *_VDBG_malloc(void *ptr,long bytes,char *file,long line){ + bytes+=HEAD_ALIGN; + if(ptr){ + ptr-=HEAD_ALIGN; + _ripremove(ptr); + ptr=realloc(ptr,bytes); + }else{ + ptr=malloc(bytes); + memset(ptr,0,bytes); + } + return _insert(ptr,bytes,file,line); +} + +extern void _VDBG_free(void *ptr,char *file,long line){ + if(ptr){ + ptr-=HEAD_ALIGN; + _ripremove(ptr); + free(ptr); + } +} + diff --git a/lib/tremor/misc.h b/lib/tremor/misc.h index 1ae4d2e8..d818e183 100644 --- a/lib/tremor/misc.h +++ b/lib/tremor/misc.h @@ -1,12 +1,12 @@ /******************************************************************** * * - * THIS FILE IS PART OF THE OggVorbis 'TREMOR' CODEC SOURCE CODE. * + * THIS FILE IS PART OF THE TremorOggVorbis 'TREMOR' CODEC SOURCE CODE. * * * * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS * * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE * * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. * * * - * THE OggVorbis 'TREMOR' SOURCE CODE IS (C) COPYRIGHT 1994-2002 * + * THE TremorOggVorbis 'TREMOR' SOURCE CODE IS (C) COPYRIGHT 1994-2003 * * BY THE Xiph.Org FOUNDATION http://www.xiph.org/ * * * ******************************************************************** @@ -18,18 +18,27 @@ #ifndef _V_RANDOM_H_ #define _V_RANDOM_H_ #include "ivorbiscodec.h" -#include "os.h" +#include "os_types.h" -#ifdef _LOW_ACCURACY_ -# define X(n) (((((n)>>22)+1)>>1) - ((((n)>>22)+1)>>9)) -# define LOOKUP_T const unsigned char -#else -# define X(n) (n) -# define LOOKUP_T const ogg_int32_t +/*#define _VDBG_GRAPHFILE "_0.m"*/ + + +#ifdef _VDBG_GRAPHFILE +extern void *_VDBG_malloc(void *ptr,long bytes,char *file,long line); +extern void _VDBG_free(void *ptr,char *file,long line); + +#undef _tremor_ogg_malloc +#undef _tremor_ogg_calloc +#undef _tremor_ogg_realloc +#undef _tremor_ogg_free + +#define _tremor_ogg_malloc(x) _VDBG_malloc(NULL,(x),__FILE__,__LINE__) +#define _tremor_ogg_calloc(x,y) _VDBG_malloc(NULL,(x)*(y),__FILE__,__LINE__) +#define _tremor_ogg_realloc(x,y) _VDBG_malloc((x),(y),__FILE__,__LINE__) +#define _tremor_ogg_free(x) _VDBG_free((x),__FILE__,__LINE__) #endif #include "asm_arm.h" -#include /* for abs() */ #ifndef _V_WIDE_MATH #define _V_WIDE_MATH @@ -37,44 +46,42 @@ #ifndef _LOW_ACCURACY_ /* 64 bit multiply */ -#if !(defined WIN32 && defined WINCE) #include -#endif #if BYTE_ORDER==LITTLE_ENDIAN union magic { struct { - ogg_int32_t lo; - ogg_int32_t hi; + tremor_ogg_int32_t lo; + tremor_ogg_int32_t hi; } halves; - ogg_int64_t whole; + tremor_ogg_int64_t whole; }; #endif #if BYTE_ORDER==BIG_ENDIAN union magic { struct { - ogg_int32_t hi; - ogg_int32_t lo; + tremor_ogg_int32_t hi; + tremor_ogg_int32_t lo; } halves; - ogg_int64_t whole; + tremor_ogg_int64_t whole; }; #endif -STIN ogg_int32_t MULT32(ogg_int32_t x, ogg_int32_t y) { +static inline tremor_ogg_int32_t MULT32(tremor_ogg_int32_t x, tremor_ogg_int32_t y) { union magic magic; - magic.whole = (ogg_int64_t)x * y; + magic.whole = (tremor_ogg_int64_t)x * y; return magic.halves.hi; } -STIN ogg_int32_t MULT31(ogg_int32_t x, ogg_int32_t y) { +static inline tremor_ogg_int32_t MULT31(tremor_ogg_int32_t x, tremor_ogg_int32_t y) { return MULT32(x,y)<<1; } -STIN ogg_int32_t MULT31_SHIFT15(ogg_int32_t x, ogg_int32_t y) { +static inline tremor_ogg_int32_t MULT31_SHIFT15(tremor_ogg_int32_t x, tremor_ogg_int32_t y) { union magic magic; - magic.whole = (ogg_int64_t)x * y; - return ((ogg_uint32_t)(magic.halves.lo)>>15) | ((magic.halves.hi)<<17); + magic.whole = (tremor_ogg_int64_t)x * y; + return ((tremor_ogg_uint32_t)(magic.halves.lo)>>15) | ((magic.halves.hi)<<17); } #else @@ -93,15 +100,15 @@ STIN ogg_int32_t MULT31_SHIFT15(ogg_int32_t x, ogg_int32_t y) { * tables in this case. */ -STIN ogg_int32_t MULT32(ogg_int32_t x, ogg_int32_t y) { +static inline tremor_ogg_int32_t MULT32(tremor_ogg_int32_t x, tremor_ogg_int32_t y) { return (x >> 9) * y; /* y preshifted >>23 */ } -STIN ogg_int32_t MULT31(ogg_int32_t x, ogg_int32_t y) { +static inline tremor_ogg_int32_t MULT31(tremor_ogg_int32_t x, tremor_ogg_int32_t y) { return (x >> 8) * y; /* y preshifted >>23 */ } -STIN ogg_int32_t MULT31_SHIFT15(ogg_int32_t x, ogg_int32_t y) { +static inline tremor_ogg_int32_t MULT31_SHIFT15(tremor_ogg_int32_t x, tremor_ogg_int32_t y) { return (x >> 6) * y; /* y preshifted >>9 */ } @@ -138,25 +145,25 @@ STIN ogg_int32_t MULT31_SHIFT15(ogg_int32_t x, ogg_int32_t y) { #else -STIN void XPROD32(ogg_int32_t a, ogg_int32_t b, - ogg_int32_t t, ogg_int32_t v, - ogg_int32_t *x, ogg_int32_t *y) +static inline void XPROD32(tremor_ogg_int32_t a, tremor_ogg_int32_t b, + tremor_ogg_int32_t t, tremor_ogg_int32_t v, + tremor_ogg_int32_t *x, tremor_ogg_int32_t *y) { *x = MULT32(a, t) + MULT32(b, v); *y = MULT32(b, t) - MULT32(a, v); } -STIN void XPROD31(ogg_int32_t a, ogg_int32_t b, - ogg_int32_t t, ogg_int32_t v, - ogg_int32_t *x, ogg_int32_t *y) +static inline void XPROD31(tremor_ogg_int32_t a, tremor_ogg_int32_t b, + tremor_ogg_int32_t t, tremor_ogg_int32_t v, + tremor_ogg_int32_t *x, tremor_ogg_int32_t *y) { *x = MULT31(a, t) + MULT31(b, v); *y = MULT31(b, t) - MULT31(a, v); } -STIN void XNPROD31(ogg_int32_t a, ogg_int32_t b, - ogg_int32_t t, ogg_int32_t v, - ogg_int32_t *x, ogg_int32_t *y) +static inline void XNPROD31(tremor_ogg_int32_t a, tremor_ogg_int32_t b, + tremor_ogg_int32_t t, tremor_ogg_int32_t v, + tremor_ogg_int32_t *x, tremor_ogg_int32_t *y) { *x = MULT31(a, t) - MULT31(b, v); *y = MULT31(b, t) + MULT31(a, v); @@ -169,7 +176,7 @@ STIN void XNPROD31(ogg_int32_t a, ogg_int32_t b, #ifndef _V_CLIP_MATH #define _V_CLIP_MATH -STIN ogg_int32_t CLIP_TO_15(ogg_int32_t x) { +static inline tremor_ogg_int32_t CLIP_TO_15(tremor_ogg_int32_t x) { int ret=x; ret-= ((x<=32767)-1)&(x-32767); ret-= ((x>=-32768)-1)&(x+32768); @@ -178,73 +185,6 @@ STIN ogg_int32_t CLIP_TO_15(ogg_int32_t x) { #endif -STIN ogg_int32_t VFLOAT_MULT(ogg_int32_t a,ogg_int32_t ap, - ogg_int32_t b,ogg_int32_t bp, - ogg_int32_t *p){ - if(a && b){ -#ifndef _LOW_ACCURACY_ - *p=ap+bp+32; - return MULT32(a,b); -#else - *p=ap+bp+31; - return (a>>15)*(b>>16); -#endif - }else - return 0; -} - -int _ilog(unsigned int); - -STIN ogg_int32_t VFLOAT_MULTI(ogg_int32_t a,ogg_int32_t ap, - ogg_int32_t i, - ogg_int32_t *p){ - - int ip=_ilog(abs(i))-31; - return VFLOAT_MULT(a,ap,i<<-ip,ip,p); -} - -STIN ogg_int32_t VFLOAT_ADD(ogg_int32_t a,ogg_int32_t ap, - ogg_int32_t b,ogg_int32_t bp, - ogg_int32_t *p){ - - if(!a){ - *p=bp; - return b; - }else if(!b){ - *p=ap; - return a; - } - - /* yes, this can leak a bit. */ - if(ap>bp){ - int shift=ap-bp+1; - *p=ap+1; - a>>=1; - if(shift<32){ - b=(b+(1<<(shift-1)))>>shift; - }else{ - b=0; - } - }else{ - int shift=bp-ap+1; - *p=bp+1; - b>>=1; - if(shift<32){ - a=(a+(1<<(shift-1)))>>shift; - }else{ - a=0; - } - } - - a+=b; - if((a&0xc0000000)==0xc0000000 || - (a&0xc0000000)==0){ - a<<=1; - (*p)--; - } - return(a); -} - #endif diff --git a/lib/tremor/os.h b/lib/tremor/os.h index 130d27de..5a556fd9 100644 --- a/lib/tremor/os.h +++ b/lib/tremor/os.h @@ -2,13 +2,13 @@ #define _OS_H /******************************************************************** * * - * THIS FILE IS PART OF THE OggVorbis 'TREMOR' CODEC SOURCE CODE. * + * THIS FILE IS PART OF THE TremorOggVorbis 'TREMOR' CODEC SOURCE CODE. * * * * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS * * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE * * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. * * * - * THE OggVorbis 'TREMOR' SOURCE CODE IS (C) COPYRIGHT 1994-2002 * + * THE TremorOggVorbis 'TREMOR' SOURCE CODE IS (C) COPYRIGHT 1994-2002 * * BY THE Xiph.Org FOUNDATION http://www.xiph.org/ * * * ******************************************************************** @@ -18,7 +18,7 @@ ********************************************************************/ #include -#include +#include "os_types.h" #ifndef _V_IFDEFJAIL_H_ # define _V_IFDEFJAIL_H_ @@ -41,8 +41,6 @@ # define rint(x) (floor((x)+0.5f)) # define NO_FLOAT_MATH_LIB # define FAST_HYPOT(a, b) sqrt((a)*(a) + (b)*(b)) -# define LITTLE_ENDIAN 1 -# define BYTE_ORDER LITTLE_ENDIAN #endif #ifdef HAVE_ALLOCA_H diff --git a/lib/tremor/os_types.h b/lib/tremor/os_types.h new file mode 100644 index 00000000..c09c993d --- /dev/null +++ b/lib/tremor/os_types.h @@ -0,0 +1,42 @@ +/******************************************************************** + * * + * THIS FILE IS PART OF THE TremorOggVorbis 'TREMOR' CODEC SOURCE CODE. * + * * + * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS * + * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE * + * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. * + * * + * THE TremorOggVorbis 'TREMOR' SOURCE CODE IS (C) COPYRIGHT 1994-2002 * + * BY THE Xiph.Org FOUNDATION http://www.xiph.org/ * + * * + ******************************************************************** + + function: #ifdef jail to whip a few platforms into the UNIX ideal. + + ********************************************************************/ +#ifndef _TREMOR_OS_TYPES_H +#define _TREMOR_OS_TYPES_H + +#include +#ifdef _LOW_ACCURACY_ +# define X(n) (((((n)>>22)+1)>>1) - ((((n)>>22)+1)>>9)) +# define LOOKUP_T const unsigned char +#else +# define X(n) (n) +# define LOOKUP_T const tremor_ogg_int32_t +#endif + +/* make it easy on the folks that want to compile the libs with a + different malloc than stdlib */ +#define _tremor_ogg_malloc malloc +#define _tremor_ogg_calloc calloc +#define _tremor_ogg_realloc realloc +#define _tremor_ogg_free free + +typedef int64_t tremor_ogg_int64_t; +typedef int32_t tremor_ogg_int32_t; +typedef uint32_t tremor_ogg_uint32_t; +typedef int16_t tremor_ogg_int16_t; +typedef uint16_t tremor_ogg_uint16_t; + +#endif /* _TREMOR_OS_TYPES_H */ diff --git a/lib/tremor/registry.c b/lib/tremor/registry.c deleted file mode 100644 index c0b5fec0..00000000 --- a/lib/tremor/registry.c +++ /dev/null @@ -1,50 +0,0 @@ -/******************************************************************** - * * - * THIS FILE IS PART OF THE OggVorbis 'TREMOR' CODEC SOURCE CODE. * - * * - * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS * - * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE * - * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. * - * * - * THE OggVorbis 'TREMOR' SOURCE CODE IS (C) COPYRIGHT 1994-2002 * - * BY THE Xiph.Org FOUNDATION http://www.xiph.org/ * - * * - ******************************************************************** - - function: registry for floor, res backends and channel mappings - - ********************************************************************/ - -#include "ivorbiscodec.h" -#include "codec_internal.h" -#include "registry.h" -#include "misc.h" - - -/* seems like major overkill now; the backend numbers will grow into - the infrastructure soon enough */ - -extern vorbis_func_floor floor0_exportbundle; -extern vorbis_func_floor floor1_exportbundle; -extern vorbis_func_residue residue0_exportbundle; -extern vorbis_func_residue residue1_exportbundle; -extern vorbis_func_residue residue2_exportbundle; -extern vorbis_func_mapping mapping0_exportbundle; - -vorbis_func_floor *_floor_P[]={ - &floor0_exportbundle, - &floor1_exportbundle, -}; - -vorbis_func_residue *_residue_P[]={ - &residue0_exportbundle, - &residue1_exportbundle, - &residue2_exportbundle, -}; - -vorbis_func_mapping *_mapping_P[]={ - &mapping0_exportbundle, -}; - - - diff --git a/lib/tremor/registry.h b/lib/tremor/registry.h deleted file mode 100644 index 2bc8068f..00000000 --- a/lib/tremor/registry.h +++ /dev/null @@ -1,40 +0,0 @@ -/******************************************************************** - * * - * THIS FILE IS PART OF THE OggVorbis 'TREMOR' CODEC SOURCE CODE. * - * * - * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS * - * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE * - * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. * - * * - * THE OggVorbis 'TREMOR' SOURCE CODE IS (C) COPYRIGHT 1994-2002 * - * BY THE Xiph.Org FOUNDATION http://www.xiph.org/ * - * * - ******************************************************************** - - function: registry for time, floor, res backends and channel mappings - - ********************************************************************/ - -#ifndef _V_REG_H_ -#define _V_REG_H_ - -#define VI_TRANSFORMB 1 -#define VI_WINDOWB 1 -#define VI_TIMEB 1 -#define VI_FLOORB 2 -#define VI_RESB 3 -#define VI_MAPB 1 - -#include "backends.h" - -#if defined(_WIN32) && defined(VORBISDLL_IMPORT) -# define EXTERN __declspec(dllimport) extern -#else -# define EXTERN extern -#endif - -EXTERN vorbis_func_floor *_floor_P[]; -EXTERN vorbis_func_residue *_residue_P[]; -EXTERN vorbis_func_mapping *_mapping_P[]; - -#endif diff --git a/lib/tremor/res012.c b/lib/tremor/res012.c index f036caaa..e568dc10 100644 --- a/lib/tremor/res012.c +++ b/lib/tremor/res012.c @@ -1,12 +1,12 @@ /******************************************************************** * * - * THIS FILE IS PART OF THE OggVorbis 'TREMOR' CODEC SOURCE CODE. * + * THIS FILE IS PART OF THE TremorOggVorbis 'TREMOR' CODEC SOURCE CODE. * * * * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS * * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE * * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. * * * - * THE OggVorbis 'TREMOR' SOURCE CODE IS (C) COPYRIGHT 1994-2002 * + * THE TremorOggVorbis 'TREMOR' SOURCE CODE IS (C) COPYRIGHT 1994-2003 * * BY THE Xiph.Org FOUNDATION http://www.xiph.org/ * * * ******************************************************************** @@ -18,357 +18,208 @@ #include #include #include -#include +#include "tremor_ogg.h" #include "ivorbiscodec.h" #include "codec_internal.h" -#include "registry.h" #include "codebook.h" #include "misc.h" #include "os.h" -#include "block.h" -typedef struct { - vorbis_info_residue0 *info; - int map; - - int parts; - int stages; - codebook *fullbooks; - codebook *phrasebook; - codebook ***partbooks; - - int partvals; - int **decodemap; - -} vorbis_look_residue0; - -void res0_free_info(vorbis_info_residue *i){ - vorbis_info_residue0 *info=(vorbis_info_residue0 *)i; +void res_clear_info(vorbis_info_residue *info){ if(info){ + if(info->stagemasks)_tremor_ogg_free(info->stagemasks); + if(info->stagebooks)_tremor_ogg_free(info->stagebooks); memset(info,0,sizeof(*info)); - _ogg_free(info); } } -void res0_free_look(vorbis_look_residue *i){ - int j; - if(i){ - - vorbis_look_residue0 *look=(vorbis_look_residue0 *)i; - - for(j=0;jparts;j++) - if(look->partbooks[j])_ogg_free(look->partbooks[j]); - _ogg_free(look->partbooks); - for(j=0;jpartvals;j++) - _ogg_free(look->decodemap[j]); - _ogg_free(look->decodemap); - - memset(look,0,sizeof(*look)); - _ogg_free(look); - } -} - -static int ilog(unsigned int v){ - int ret=0; - while(v){ - ret++; - v>>=1; - } - return(ret); -} - -static int icount(unsigned int v){ - int ret=0; - while(v){ - ret+=v&1; - v>>=1; - } - return(ret); -} /* vorbis_info is for range checking */ -vorbis_info_residue *res0_unpack(vorbis_info *vi,oggpack_buffer *opb){ - int j,acc=0; - vorbis_info_residue0 *info=(vorbis_info_residue0 *)_ogg_calloc(1,sizeof(*info)); +int res_unpack(vorbis_info_residue *info, + vorbis_info *vi,tremor_oggpack_buffer *opb){ + int j,k; codec_setup_info *ci=(codec_setup_info *)vi->codec_setup; + memset(info,0,sizeof(*info)); + + info->type=tremor_oggpack_read(opb,16); + if(info->type>2 || info->type<0)goto errout; + info->begin=tremor_oggpack_read(opb,24); + info->end=tremor_oggpack_read(opb,24); + info->grouping=tremor_oggpack_read(opb,24)+1; + info->partitions=tremor_oggpack_read(opb,6)+1; + info->groupbook=tremor_oggpack_read(opb,8); + if(info->groupbook>=ci->books)goto errout; - info->begin=oggpack_read(opb,24); - info->end=oggpack_read(opb,24); - info->grouping=oggpack_read(opb,24)+1; - info->partitions=oggpack_read(opb,6)+1; - info->groupbook=oggpack_read(opb,8); - - /* check for premature EOP */ - if(info->groupbook<0)goto errout; + info->stagemasks=_tremor_ogg_malloc(info->partitions*sizeof(*info->stagemasks)); + info->stagebooks=_tremor_ogg_malloc(info->partitions*8*sizeof(*info->stagebooks)); for(j=0;jpartitions;j++){ - int cascade=oggpack_read(opb,3); - int cflag=oggpack_read(opb,1); - if(cflag<0) goto errout; - if(cflag){ - int c=oggpack_read(opb,5); - if(c<0) goto errout; - cascade|=(c<<3); - } - info->secondstages[j]=cascade; - - acc+=icount(cascade); - } - for(j=0;jbooklist[j]=book; + int cascade=tremor_oggpack_read(opb,3); + if(tremor_oggpack_read(opb,1)) + cascade|=(tremor_oggpack_read(opb,5)<<3); + info->stagemasks[j]=cascade; } - if(info->groupbook>=ci->books)goto errout; - for(j=0;jbooklist[j]>=ci->books)goto errout; - if(ci->book_param[info->booklist[j]]->maptype==0)goto errout; - } - - /* verify the phrasebook is not specifying an impossible or - inconsistent partitioning scheme. */ - /* modify the phrasebook ranging check from r16327; an early beta - encoder had a bug where it used an oversized phrasebook by - accident. These files should continue to be playable, but don't - allow an exploit */ - { - int entries = ci->book_param[info->groupbook]->entries; - int dim = ci->book_param[info->groupbook]->dim; - int partvals = 1; - if (dim<1) goto errout; - while(dim>0){ - partvals *= info->partitions; - if(partvals > entries) goto errout; - dim--; + for(j=0;jpartitions;j++){ + for(k=0;k<8;k++){ + if((info->stagemasks[j]>>k)&1){ + unsigned char book=tremor_oggpack_read(opb,8); + if(book>=ci->books)goto errout; + info->stagebooks[j*8+k]=book; + if(k+1>info->stages)info->stages=k+1; + }else + info->stagebooks[j*8+k]=0xff; } - info->partvals = partvals; } - return(info); + if(tremor_oggpack_eop(opb))goto errout; + + return 0; errout: - res0_free_info(info); - return(NULL); + res_clear_info(info); + return 1; } -vorbis_look_residue *res0_look(vorbis_dsp_state *vd,vorbis_info_mode *vm, - vorbis_info_residue *vr){ - vorbis_info_residue0 *info=(vorbis_info_residue0 *)vr; - vorbis_look_residue0 *look=(vorbis_look_residue0 *)_ogg_calloc(1,sizeof(*look)); +int res_inverse(vorbis_dsp_state *vd,vorbis_info_residue *info, + tremor_ogg_int32_t **in,int *nonzero,int ch){ + + int i,j,k,s,used=0; codec_setup_info *ci=(codec_setup_info *)vd->vi->codec_setup; - - int j,k,acc=0; - int dim; - int maxstage=0; - look->info=info; - look->map=vm->mapping; - - look->parts=info->partitions; - look->fullbooks=ci->fullbooks; - look->phrasebook=ci->fullbooks+info->groupbook; - dim=look->phrasebook->dim; - - look->partbooks=(codebook ***)_ogg_calloc(look->parts,sizeof(*look->partbooks)); - - for(j=0;jparts;j++){ - int stages=ilog(info->secondstages[j]); - if(stages){ - if(stages>maxstage)maxstage=stages; - look->partbooks[j]=(codebook **)_ogg_calloc(stages,sizeof(*look->partbooks[j])); - for(k=0;ksecondstages[j]&(1<partbooks[j][k]=ci->fullbooks+info->booklist[acc++]; -#ifdef TRAIN_RES - look->training_data[k][j]=calloc(look->partbooks[j][k]->entries, - sizeof(***look->training_data)); -#endif - } - } - } - - look->partvals=look->parts; - for(j=1;jpartvals*=look->parts; - look->stages=maxstage; - look->decodemap=(int **)_ogg_malloc(look->partvals*sizeof(*look->decodemap)); - for(j=0;jpartvals;j++){ - long val=j; - long mult=look->partvals/look->parts; - look->decodemap[j]=(int *)_ogg_malloc(dim*sizeof(*look->decodemap[j])); - for(k=0;kparts; - look->decodemap[j][k]=deco; - } - } - - return(look); -} - - -/* a truncated packet here just means 'stop working'; it's not an error */ -static int _01inverse(vorbis_block *vb,vorbis_look_residue *vl, - ogg_int32_t **in,int ch, - long (*decodepart)(codebook *, ogg_int32_t *, - oggpack_buffer *,int,int)){ - - long i,j,k,l,s; - vorbis_look_residue0 *look=(vorbis_look_residue0 *)vl; - vorbis_info_residue0 *info=look->info; - - /* move all this setup out later */ + codebook *phrasebook=ci->book_param+info->groupbook; int samples_per_partition=info->grouping; - int partitions_per_word=look->phrasebook->dim; - int max=vb->pcmend>>1; - int end=(info->endend:max); - int n=end-info->begin; + int partitions_per_word=phrasebook->dim; + int pcmend=ci->blocksizes[vd->W]; - if(n>0){ - int partvals=n/samples_per_partition; - int partwords=(partvals+partitions_per_word-1)/partitions_per_word; - int ***partword=(int ***)alloca(ch*sizeof(*partword)); - - for(j=0;jtype<2){ + int max=pcmend>>1; + int end=(info->endend:max); + int n=end-info->begin; - for(s=0;sstages;s++){ + if(n>0){ + int partvals=n/samples_per_partition; + int partwords=(partvals+partitions_per_word-1)/partitions_per_word; - /* each loop decodes on partition codeword containing - partitions_pre_word partitions */ - for(i=0,l=0;iphrasebook,&vb->opb); - if(temp==-1 || temp>=info->partvals)goto eopbreak; - partword[j][l]=look->decodemap[temp]; - if(partword[j][l]==NULL)goto errout; - } - } + for(i=0;ibegin+i*samples_per_partition; - if(info->secondstages[partword[j][l][k]]&(1<partbooks[partword[j][l][k]][s]; - if(stagebook){ - if(decodepart(stagebook,in[j]+offset,&vb->opb, - samples_per_partition,-8)==-1)goto eopbreak; + for(s=0;sstages;s++){ + + for(i=0;i=0;k--) + partword[0][i+k]=partword[0][i+k+1]*info->partitions; + + for(j=1;j=0;k--) + partword[j][i+k]=partword[j-1][i+k]; + + for(j=0;jopb); + if(temp==-1)goto eopbreak; + + /* this can be done quickly in assembly due to the quotient + always being at most six bits */ + for(k=0;kbegin+i*samples_per_partition; + if(info->stagemasks[(int)partword[j][i]]&(1<book_param+ + info->stagebooks[(partword[j][i]<<3)+s]; + if(info->type){ + if(vorbis_book_decodev_add(stagebook,in[j]+offset,&vd->opb, + samples_per_partition,-8)==-1) + goto eopbreak; + }else{ + if(vorbis_book_decodevs_add(stagebook,in[j]+offset,&vd->opb, + samples_per_partition,-8)==-1) + goto eopbreak; + } + } + } } - } + } + } } - } - errout: - eopbreak: - return(0); -} - -int res0_inverse(vorbis_block *vb,vorbis_look_residue *vl, - ogg_int32_t **in,int *nonzero,int ch){ - int i,used=0; - for(i=0;iinfo; - - /* move all this setup out later */ - int samples_per_partition=info->grouping; - int partitions_per_word=look->phrasebook->dim; - int max=(vb->pcmend*ch)>>1; - int end=(info->endend:max); - int n=end-info->begin; - - if(n>0){ + }else{ + int max=(pcmend*ch)>>1; + int end=(info->endend:max); + int n=end-info->begin; - int partvals=n/samples_per_partition; - int partwords=(partvals+partitions_per_word-1)/partitions_per_word; - int **partword=(int **)_vorbis_block_alloc(vb,partwords*sizeof(*partword)); - int beginoff=info->begin/ch; - - for(i=0;istages;s++){ - for(i=0,l=0;iphrasebook,&vb->opb); - if(temp==-1 || temp>=info->partvals)goto eopbreak; - partword[l]=look->decodemap[temp]; - if(partword[l]==NULL)goto errout; - } - - /* now we decode residual values for the partitions */ - for(k=0;ksecondstages[partword[l][k]]&(1<partbooks[partword[l][k]][s]; + if(n>0){ + int partvals=n/samples_per_partition; + int partwords=(partvals+partitions_per_word-1)/partitions_per_word; + + char *partword= + (char *)alloca(partwords*partitions_per_word*sizeof(*partword)); + int beginoff=info->begin/ch; + + for(i=0;istages;s++){ + for(i=0;i=0;k--) + partword[i+k]=partword[i+k+1]*info->partitions; - if(stagebook){ + /* fetch the partition word */ + temp=vorbis_book_decode(phrasebook,&vd->opb); + if(temp==-1)goto eopbreak; + + /* this can be done quickly in assembly due to the quotient + always being at most six bits */ + for(k=0;kstagemasks[(int)partword[i]]&(1<book_param+ + info->stagebooks[(partword[i]<<3)+s]; if(vorbis_book_decodevv_add(stagebook,in, i*samples_per_partition+beginoff,ch, - &vb->opb, + &vd->opb, samples_per_partition,-8)==-1) goto eopbreak; } - } + } } } } errout: eopbreak: - return(0); -} - - -vorbis_func_residue residue0_exportbundle={ - &res0_unpack, - &res0_look, - &res0_free_info, - &res0_free_look, - &res0_inverse -}; - -vorbis_func_residue residue1_exportbundle={ - &res0_unpack, - &res0_look, - &res0_free_info, - &res0_free_look, - &res1_inverse -}; + + return 0; +} -vorbis_func_residue residue2_exportbundle={ - &res0_unpack, - &res0_look, - &res0_free_info, - &res0_free_look, - &res2_inverse -}; diff --git a/lib/tremor/sharedbook.c b/lib/tremor/sharedbook.c deleted file mode 100644 index 188485e3..00000000 --- a/lib/tremor/sharedbook.c +++ /dev/null @@ -1,447 +0,0 @@ -/******************************************************************** - * * - * THIS FILE IS PART OF THE OggVorbis 'TREMOR' CODEC SOURCE CODE. * - * * - * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS * - * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE * - * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. * - * * - * THE OggVorbis 'TREMOR' SOURCE CODE IS (C) COPYRIGHT 1994-2002 * - * BY THE Xiph.Org FOUNDATION http://www.xiph.org/ * - * * - ******************************************************************** - - function: basic shared codebook operations - - ********************************************************************/ - -#include -#include -#include -#include -#include "misc.h" -#include "ivorbiscodec.h" -#include "codebook.h" - -/**** pack/unpack helpers ******************************************/ -int _ilog(unsigned int v){ - int ret=0; - while(v){ - ret++; - v>>=1; - } - return(ret); -} - -/* 32 bit float (not IEEE; nonnormalized mantissa + - biased exponent) : neeeeeee eeemmmmm mmmmmmmm mmmmmmmm - Why not IEEE? It's just not that important here. */ - -#define VQ_FEXP 10 -#define VQ_FMAN 21 -#define VQ_FEXP_BIAS 768 /* bias toward values smaller than 1. */ - -static ogg_int32_t _float32_unpack(long val,int *point){ - long mant=val&0x1fffff; - int sign=val&0x80000000; - long exp =(val&0x7fe00000L)>>VQ_FMAN; - - exp-=(VQ_FMAN-1)+VQ_FEXP_BIAS; - - if(mant){ - while(!(mant&0x40000000)){ - mant<<=1; - exp-=1; - } - - if(sign)mant= -mant; - }else{ - sign=0; - exp=-9999; - } - - *point=exp; - return mant; -} - -/* given a list of word lengths, generate a list of codewords. Works - for length ordered or unordered, always assigns the lowest valued - codewords first. Extended to handle unused entries (length 0) */ -ogg_uint32_t *_make_words(long *l,long n,long sparsecount){ - long i,j,count=0; - ogg_uint32_t marker[33]; - ogg_uint32_t *r=(ogg_uint32_t *)_ogg_malloc((sparsecount?sparsecount:n)*sizeof(*r)); - memset(marker,0,sizeof(marker)); - - for(i=0;i0){ - ogg_uint32_t entry=marker[length]; - - /* when we claim a node for an entry, we also claim the nodes - below it (pruning off the imagined tree that may have dangled - from it) as well as blocking the use of any nodes directly - above for leaves */ - - /* update ourself */ - if(length<32 && (entry>>length)){ - /* error condition; the lengths must specify an overpopulated tree */ - _ogg_free(r); - return(NULL); - } - r[count++]=entry; - - /* Look to see if the next shorter marker points to the node - above. if so, update it and repeat. */ - { - for(j=length;j>0;j--){ - - if(marker[j]&1){ - /* have to jump branches */ - if(j==1) - marker[1]++; - else - marker[j]=marker[j-1]<<1; - break; /* invariant says next upper marker would already - have been moved if it was on the same path */ - } - marker[j]++; - } - } - - /* prune the tree; the implicit invariant says all the longer - markers were dangling from our just-taken node. Dangle them - from our *new* node. */ - for(j=length+1;j<33;j++) - if((marker[j]>>1) == entry){ - entry=marker[j]; - marker[j]=marker[j-1]<<1; - }else - break; - }else - if(sparsecount==0)count++; - } - - /* sanity check the huffman tree; an underpopulated tree must be - rejected. The only exception is the one-node pseudo-nil tree, - which appears to be underpopulated because the tree doesn't - really exist; there's only one possible 'codeword' or zero bits, - but the above tree-gen code doesn't mark that. */ - if(sparsecount != 1){ - for(i=1;i<33;i++) - if(marker[i] & (0xffffffffUL>>(32-i))){ - _ogg_free(r); - return(NULL); - } - } - - /* bitreverse the words because our bitwise packer/unpacker is LSb - endian */ - for(i=0,count=0;i>j)&1; - } - - if(sparsecount){ - if(l[i]) - r[count++]=temp; - }else - r[count++]=temp; - } - - return(r); -} - -/* there might be a straightforward one-line way to do the below - that's portable and totally safe against roundoff, but I haven't - thought of it. Therefore, we opt on the side of caution */ -long _book_maptype1_quantvals(const static_codebook *b){ - /* get us a starting hint, we'll polish it below */ - int bits=_ilog(b->entries); - int vals=b->entries>>((bits-1)*(b->dim-1)/b->dim); - - while(1){ - long acc=1; - long acc1=1; - int i; - for(i=0;idim;i++){ - acc*=vals; - acc1*=vals+1; - } - if(acc<=b->entries && acc1>b->entries){ - return(vals); - }else{ - if(acc>b->entries){ - vals--; - }else{ - vals++; - } - } - } -} - -/* different than what _book_unquantize does for mainline: - we repack the book in a fixed point format that shares the same - binary point. Upon first use, we can shift point if needed */ - -/* we need to deal with two map types: in map type 1, the values are - generated algorithmically (each column of the vector counts through - the values in the quant vector). in map type 2, all the values came - in in an explicit list. Both value lists must be unpacked */ - -ogg_int32_t *_book_unquantize(const static_codebook *b,int n,int *sparsemap, - int *maxpoint){ - long j,k,count=0; - if(b->maptype==1 || b->maptype==2){ - int quantvals; - int minpoint,delpoint; - ogg_int32_t mindel=_float32_unpack(b->q_min,&minpoint); - ogg_int32_t delta=_float32_unpack(b->q_delta,&delpoint); - ogg_int32_t *r=(ogg_int32_t *)_ogg_calloc(n*b->dim,sizeof(*r)); - int *rp=(int *)_ogg_calloc(n*b->dim,sizeof(*rp)); - - *maxpoint=minpoint; - - /* maptype 1 and 2 both use a quantized value vector, but - different sizes */ - switch(b->maptype){ - case 1: - /* most of the time, entries%dimensions == 0, but we need to be - well defined. We define that the possible vales at each - scalar is values == entries/dim. If entries%dim != 0, we'll - have 'too few' values (values*dimentries;j++){ - if((sparsemap && b->lengthlist[j]) || !sparsemap){ - ogg_int32_t last=0; - int lastpoint=0; - int indexdiv=1; - for(k=0;kdim;k++){ - int index= (j/indexdiv)%quantvals; - int point=0; - int val=VFLOAT_MULTI(delta,delpoint, - abs(b->quantlist[index]),&point); - - val=VFLOAT_ADD(mindel,minpoint,val,point,&point); - val=VFLOAT_ADD(last,lastpoint,val,point,&point); - - if(b->q_sequencep){ - last=val; - lastpoint=point; - } - - if(sparsemap){ - r[sparsemap[count]*b->dim+k]=val; - rp[sparsemap[count]*b->dim+k]=point; - }else{ - r[count*b->dim+k]=val; - rp[count*b->dim+k]=point; - } - if(*maxpointentries;j++){ - if((sparsemap && b->lengthlist[j]) || !sparsemap){ - ogg_int32_t last=0; - int lastpoint=0; - - for(k=0;kdim;k++){ - int point=0; - int val=VFLOAT_MULTI(delta,delpoint, - abs(b->quantlist[j*b->dim+k]),&point); - - val=VFLOAT_ADD(mindel,minpoint,val,point,&point); - val=VFLOAT_ADD(last,lastpoint,val,point,&point); - - if(b->q_sequencep){ - last=val; - lastpoint=point; - } - - if(sparsemap){ - r[sparsemap[count]*b->dim+k]=val; - rp[sparsemap[count]*b->dim+k]=point; - }else{ - r[count*b->dim+k]=val; - rp[count*b->dim+k]=point; - } - if(*maxpointdim;j++) - if(rp[j]<*maxpoint) - r[j]>>=*maxpoint-rp[j]; - - _ogg_free(rp); - return(r); - } - return(NULL); -} - -void vorbis_staticbook_destroy(static_codebook *b){ - if(b->quantlist)_ogg_free(b->quantlist); - if(b->lengthlist)_ogg_free(b->lengthlist); - memset(b,0,sizeof(*b)); - _ogg_free(b); -} - -void vorbis_book_clear(codebook *b){ - /* static book is not cleared; we're likely called on the lookup and - the static codebook belongs to the info struct */ - if(b->valuelist)_ogg_free(b->valuelist); - if(b->codelist)_ogg_free(b->codelist); - - if(b->dec_index)_ogg_free(b->dec_index); - if(b->dec_codelengths)_ogg_free(b->dec_codelengths); - if(b->dec_firsttable)_ogg_free(b->dec_firsttable); - - memset(b,0,sizeof(*b)); -} - -static ogg_uint32_t bitreverse(ogg_uint32_t x){ - x= ((x>>16)&0x0000ffffUL) | ((x<<16)&0xffff0000UL); - x= ((x>> 8)&0x00ff00ffUL) | ((x<< 8)&0xff00ff00UL); - x= ((x>> 4)&0x0f0f0f0fUL) | ((x<< 4)&0xf0f0f0f0UL); - x= ((x>> 2)&0x33333333UL) | ((x<< 2)&0xccccccccUL); - return((x>> 1)&0x55555555UL) | ((x<< 1)&0xaaaaaaaaUL); -} - -static int sort32a(const void *a,const void *b){ - return (**(ogg_uint32_t **)a>**(ogg_uint32_t **)b)- - (**(ogg_uint32_t **)a<**(ogg_uint32_t **)b); -} - -/* decode codebook arrangement is more heavily optimized than encode */ -int vorbis_book_init_decode(codebook *c,const static_codebook *s){ - int i,j,n=0,tabn; - int *sortindex; - memset(c,0,sizeof(*c)); - - /* count actually used entries */ - for(i=0;ientries;i++) - if(s->lengthlist[i]>0) - n++; - - c->entries=s->entries; - c->used_entries=n; - c->dim=s->dim; - - if(n>0){ - /* two different remappings go on here. - - First, we collapse the likely sparse codebook down only to - actually represented values/words. This collapsing needs to be - indexed as map-valueless books are used to encode original entry - positions as integers. - - Second, we reorder all vectors, including the entry index above, - by sorted bitreversed codeword to allow treeless decode. */ - - /* perform sort */ - ogg_uint32_t *codes=_make_words(s->lengthlist,s->entries,c->used_entries); - ogg_uint32_t **codep=(ogg_uint32_t **)alloca(sizeof(*codep)*n); - - if(codes==NULL)goto err_out; - - for(i=0;icodelist=(ogg_uint32_t *)_ogg_malloc(n*sizeof(*c->codelist)); - /* the index is a reverse index */ - for(i=0;icodelist[sortindex[i]]=codes[i]; - _ogg_free(codes); - - - - c->valuelist=_book_unquantize(s,n,sortindex,&c->binarypoint); - c->dec_index=(int *)_ogg_malloc(n*sizeof(*c->dec_index)); - - for(n=0,i=0;ientries;i++) - if(s->lengthlist[i]>0) - c->dec_index[sortindex[n++]]=i; - - c->dec_codelengths=(char *)_ogg_malloc(n*sizeof(*c->dec_codelengths)); - for(n=0,i=0;ientries;i++) - if(s->lengthlist[i]>0) - c->dec_codelengths[sortindex[n++]]=s->lengthlist[i]; - - c->dec_firsttablen=_ilog(c->used_entries)-4; /* this is magic */ - if(c->dec_firsttablen<5)c->dec_firsttablen=5; - if(c->dec_firsttablen>8)c->dec_firsttablen=8; - - tabn=1<dec_firsttablen; - c->dec_firsttable=(ogg_uint32_t *)_ogg_calloc(tabn,sizeof(*c->dec_firsttable)); - c->dec_maxlength=0; - - for(i=0;idec_maxlengthdec_codelengths[i]) - c->dec_maxlength=c->dec_codelengths[i]; - if(c->dec_codelengths[i]<=c->dec_firsttablen){ - ogg_uint32_t orig=bitreverse(c->codelist[i]); - for(j=0;j<(1<<(c->dec_firsttablen-c->dec_codelengths[i]));j++) - c->dec_firsttable[orig|(j<dec_codelengths[i])]=i+1; - } - } - - /* now fill in 'unused' entries in the firsttable with hi/lo search - hints for the non-direct-hits */ - { - ogg_uint32_t mask=0xfffffffeUL<<(31-c->dec_firsttablen); - long lo=0,hi=0; - - for(i=0;idec_firsttablen); - if(c->dec_firsttable[bitreverse(word)]==0){ - while((lo+1)codelist[lo+1]<=word)lo++; - while( hi=(c->codelist[hi]&mask))hi++; - - /* we only actually have 15 bits per hint to play with here. - In order to overflow gracefully (nothing breaks, efficiency - just drops), encode as the difference from the extremes. */ - { - unsigned long loval=lo; - unsigned long hival=n-hi; - - if(loval>0x7fff)loval=0x7fff; - if(hival>0x7fff)hival=0x7fff; - c->dec_firsttable[bitreverse(word)]= - 0x80000000UL | (loval<<15) | hival; - } - } - } - } - } - - return(0); - err_out: - vorbis_book_clear(c); - return(-1); -} - diff --git a/lib/tremor/synthesis.c b/lib/tremor/synthesis.c deleted file mode 100644 index d22cb823..00000000 --- a/lib/tremor/synthesis.c +++ /dev/null @@ -1,131 +0,0 @@ -/******************************************************************** - * * - * THIS FILE IS PART OF THE OggVorbis 'TREMOR' CODEC SOURCE CODE. * - * * - * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS * - * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE * - * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. * - * * - * THE OggVorbis 'TREMOR' SOURCE CODE IS (C) COPYRIGHT 1994-2003 * - * BY THE Xiph.Org FOUNDATION http://www.xiph.org/ * - * * - ******************************************************************** - - function: single-block PCM synthesis - last mod: $Id: synthesis.c,v 1.4 2003/03/29 03:07:21 xiphmont Exp $ - - ********************************************************************/ - -#include -#include -#include "ivorbiscodec.h" -#include "codec_internal.h" -#include "registry.h" -#include "misc.h" -#include "block.h" - -static int _vorbis_synthesis1(vorbis_block *vb,ogg_packet *op,int decodep){ - vorbis_dsp_state *vd= vb ? vb->vd : 0; - private_state *b= vd ? (private_state *)vd->backend_state: 0; - vorbis_info *vi= vd ? vd->vi : 0; - codec_setup_info *ci= vi ? (codec_setup_info *)vi->codec_setup : 0; - oggpack_buffer *opb=vb ? &vb->opb : 0; - int type,mode,i; - - if (!vd || !b || !vi || !ci || !opb) { - return OV_EBADPACKET; - } - - /* first things first. Make sure decode is ready */ - _vorbis_block_ripcord(vb); - oggpack_readinit(opb,op->packet,op->bytes); - - /* Check the packet type */ - if(oggpack_read(opb,1)!=0){ - /* Oops. This is not an audio data packet */ - return(OV_ENOTAUDIO); - } - - /* read our mode and pre/post windowsize */ - mode=oggpack_read(opb,b->modebits); - if(mode==-1)return(OV_EBADPACKET); - - vb->mode=mode; - if(!ci->mode_param[mode]){ - return(OV_EBADPACKET); - } - - vb->W=ci->mode_param[mode]->blockflag; - if(vb->W){ - vb->lW=oggpack_read(opb,1); - vb->nW=oggpack_read(opb,1); - if(vb->nW==-1) return(OV_EBADPACKET); - }else{ - vb->lW=0; - vb->nW=0; - } - - /* more setup */ - vb->granulepos=op->granulepos; - vb->sequence=op->packetno; /* first block is third packet */ - vb->eofflag=op->e_o_s; - - if(decodep){ - /* alloc pcm passback storage */ - vb->pcmend=ci->blocksizes[vb->W]; - vb->pcm=(ogg_int32_t **)_vorbis_block_alloc(vb,sizeof(*vb->pcm)*vi->channels); - for(i=0;ichannels;i++) - vb->pcm[i]=(ogg_int32_t *)_vorbis_block_alloc(vb,vb->pcmend*sizeof(*vb->pcm[i])); - - /* unpack_header enforces range checking */ - type=ci->map_type[ci->mode_param[mode]->mapping]; - - return(_mapping_P[type]->inverse(vb,b->mode[mode])); - }else{ - /* no pcm */ - vb->pcmend=0; - vb->pcm=NULL; - - return(0); - } -} - -int vorbis_synthesis(vorbis_block *vb,ogg_packet *op){ - return _vorbis_synthesis1(vb,op,1); -} - -/* used to track pcm position without actually performing decode. - Useful for sequential 'fast forward' */ -int vorbis_synthesis_trackonly(vorbis_block *vb,ogg_packet *op){ - return _vorbis_synthesis1(vb,op,0); -} - -long vorbis_packet_blocksize(vorbis_info *vi,ogg_packet *op){ - codec_setup_info *ci=(codec_setup_info *)vi->codec_setup; - oggpack_buffer opb; - int mode; - - oggpack_readinit(&opb,op->packet,op->bytes); - - /* Check the packet type */ - if(oggpack_read(&opb,1)!=0){ - /* Oops. This is not an audio data packet */ - return(OV_ENOTAUDIO); - } - - { - int modebits=0; - int v=ci->modes; - while(v>1){ - modebits++; - v>>=1; - } - - /* read our mode and pre/post windowsize */ - mode=oggpack_read(&opb,modebits); - } - if(mode==-1 || !ci->mode_param[mode])return(OV_EBADPACKET); - return(ci->blocksizes[ci->mode_param[mode]->blockflag]); -} - - diff --git a/lib/tremor/tremor_ogg.h b/lib/tremor/tremor_ogg.h new file mode 100644 index 00000000..758573c7 --- /dev/null +++ b/lib/tremor/tremor_ogg.h @@ -0,0 +1,206 @@ +/******************************************************************** + * * + * THIS FILE IS PART OF THE TremorOggVorbis 'TREMOR' CODEC SOURCE CODE. * + * * + * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS * + * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE * + * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. * + * * + * THE TremorOggVorbis 'TREMOR' SOURCE CODE IS (C) COPYRIGHT 1994-2003 * + * BY THE Xiph.Org FOUNDATION http://www.xiph.org/ * + * * + ******************************************************************** + + function: subsumed libogg includes + + ********************************************************************/ +#ifndef _TREMOR_OGG_H +#define _TREMOR_OGG_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include "os_types.h" + +typedef struct tremor_ogg_buffer_state{ + struct tremor_ogg_buffer *unused_buffers; + struct tremor_ogg_reference *unused_references; + int outstanding; + int shutdown; +} tremor_ogg_buffer_state; + +typedef struct tremor_ogg_buffer { + unsigned char *data; + long size; + int refcount; + + union { + tremor_ogg_buffer_state *owner; + struct tremor_ogg_buffer *next; + } ptr; +} tremor_ogg_buffer; + +typedef struct tremor_ogg_reference { + tremor_ogg_buffer *buffer; + long begin; + long length; + + struct tremor_ogg_reference *next; +} tremor_ogg_reference; + +typedef struct tremor_oggpack_buffer { + int headbit; + unsigned char *headptr; + long headend; + + /* memory management */ + tremor_ogg_reference *head; + tremor_ogg_reference *tail; + + /* render the byte/bit counter API constant time */ + long count; /* doesn't count the tail */ +} tremor_oggpack_buffer; + +typedef struct oggbyte_buffer { + tremor_ogg_reference *baseref; + + tremor_ogg_reference *ref; + unsigned char *ptr; + long pos; + long end; +} oggbyte_buffer; + +typedef struct tremor_ogg_sync_state { + /* decode memory management pool */ + tremor_ogg_buffer_state *bufferpool; + + /* stream buffers */ + tremor_ogg_reference *fifo_head; + tremor_ogg_reference *fifo_tail; + long fifo_fill; + + /* stream sync management */ + int unsynced; + int headerbytes; + int bodybytes; + +} tremor_ogg_sync_state; + +typedef struct tremor_ogg_stream_state { + tremor_ogg_reference *header_head; + tremor_ogg_reference *header_tail; + tremor_ogg_reference *body_head; + tremor_ogg_reference *body_tail; + + int e_o_s; /* set when we have buffered the last + packet in the logical bitstream */ + int b_o_s; /* set after we've written the initial page + of a logical bitstream */ + long serialno; + long pageno; + tremor_ogg_int64_t packetno; /* sequence number for decode; the framing + knows where there's a hole in the data, + but we need coupling so that the codec + (which is in a seperate abstraction + layer) also knows about the gap */ + tremor_ogg_int64_t granulepos; + + int lacing_fill; + tremor_ogg_uint32_t body_fill; + + /* decode-side state data */ + int holeflag; + int spanflag; + int clearflag; + int laceptr; + tremor_ogg_uint32_t body_fill_next; + +} tremor_ogg_stream_state; + +typedef struct { + tremor_ogg_reference *packet; + long bytes; + long b_o_s; + long e_o_s; + tremor_ogg_int64_t granulepos; + tremor_ogg_int64_t packetno; /* sequence number for decode; the framing + knows where there's a hole in the data, + but we need coupling so that the codec + (which is in a seperate abstraction + layer) also knows about the gap */ +} tremor_ogg_packet; + +typedef struct { + tremor_ogg_reference *header; + int header_len; + tremor_ogg_reference *body; + long body_len; +} tremor_ogg_page; + +/* Ogg BITSTREAM PRIMITIVES: bitstream ************************/ + +extern void tremor_oggpack_readinit(tremor_oggpack_buffer *b,tremor_ogg_reference *r); +extern long tremor_oggpack_look(tremor_oggpack_buffer *b,int bits); +extern void tremor_oggpack_adv(tremor_oggpack_buffer *b,int bits); +extern long tremor_oggpack_read(tremor_oggpack_buffer *b,int bits); +extern long tremor_oggpack_bytes(tremor_oggpack_buffer *b); +extern long tremor_oggpack_bits(tremor_oggpack_buffer *b); +extern int tremor_oggpack_eop(tremor_oggpack_buffer *b); + +/* Ogg BITSTREAM PRIMITIVES: decoding **************************/ + +extern tremor_ogg_sync_state *tremor_ogg_sync_create(void); +extern int tremor_ogg_sync_destroy(tremor_ogg_sync_state *oy); +extern int tremor_ogg_sync_reset(tremor_ogg_sync_state *oy); + +extern unsigned char *tremor_ogg_sync_bufferin(tremor_ogg_sync_state *oy, long size); +extern int tremor_ogg_sync_wrote(tremor_ogg_sync_state *oy, long bytes); +extern long tremor_ogg_sync_pageseek(tremor_ogg_sync_state *oy,tremor_ogg_page *og); +extern int tremor_ogg_sync_pageout(tremor_ogg_sync_state *oy, tremor_ogg_page *og); +extern int tremor_ogg_stream_pagein(tremor_ogg_stream_state *os, tremor_ogg_page *og); +extern int tremor_ogg_stream_packetout(tremor_ogg_stream_state *os,tremor_ogg_packet *op); +extern int tremor_ogg_stream_packetpeek(tremor_ogg_stream_state *os,tremor_ogg_packet *op); + +/* Ogg BITSTREAM PRIMITIVES: general ***************************/ + +extern tremor_ogg_stream_state *tremor_ogg_stream_create(int serialno); +extern int tremor_ogg_stream_destroy(tremor_ogg_stream_state *os); +extern int tremor_ogg_stream_reset(tremor_ogg_stream_state *os); +extern int tremor_ogg_stream_reset_serialno(tremor_ogg_stream_state *os,int serialno); +extern int tremor_ogg_stream_eos(tremor_ogg_stream_state *os); + +extern int tremor_ogg_page_checksum_set(tremor_ogg_page *og); + +extern int tremor_ogg_page_version(tremor_ogg_page *og); +extern int tremor_ogg_page_continued(tremor_ogg_page *og); +extern int tremor_ogg_page_bos(tremor_ogg_page *og); +extern int tremor_ogg_page_eos(tremor_ogg_page *og); +extern tremor_ogg_int64_t tremor_ogg_page_granulepos(tremor_ogg_page *og); +extern tremor_ogg_uint32_t tremor_ogg_page_serialno(tremor_ogg_page *og); +extern tremor_ogg_uint32_t tremor_ogg_page_pageno(tremor_ogg_page *og); +extern int tremor_ogg_page_packets(tremor_ogg_page *og); +extern int tremor_ogg_page_getbuffer(tremor_ogg_page *og, unsigned char **buffer); + +extern int tremor_ogg_packet_release(tremor_ogg_packet *op); +extern int tremor_ogg_page_release(tremor_ogg_page *og); + +extern void tremor_ogg_page_dup(tremor_ogg_page *d, tremor_ogg_page *s); + +/* Ogg BITSTREAM PRIMITIVES: return codes ***************************/ + +#define OGG_SUCCESS 0 + +#define OGG_HOLE -10 +#define OGG_SPAN -11 +#define OGG_EVERSION -12 +#define OGG_ESERIAL -13 +#define OGG_EINVAL -14 +#define OGG_EEOS -15 + + +#ifdef __cplusplus +} +#endif + +#endif /* _TREMOR_OGG_H */ diff --git a/lib/tremor/vorbisfile.c b/lib/tremor/vorbisfile.c index cd4814df..79cdefcd 100644 --- a/lib/tremor/vorbisfile.c +++ b/lib/tremor/vorbisfile.c @@ -1,18 +1,18 @@ /******************************************************************** * * - * THIS FILE IS PART OF THE OggVorbis 'TREMOR' CODEC SOURCE CODE. * + * THIS FILE IS PART OF THE TremorOggVorbis 'TREMOR' CODEC SOURCE CODE. * * * * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS * * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE * * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. * * * - * THE OggVorbis 'TREMOR' SOURCE CODE IS (C) COPYRIGHT 1994-2014 * + * THE TremorOggVorbis 'TREMOR' SOURCE CODE IS (C) COPYRIGHT 1994-2003 * * BY THE Xiph.Org FOUNDATION http://www.xiph.org/ * * * ******************************************************************** function: stdio-based convenience library for opening/seeking/decoding - last mod: $Id$ + last mod: $Id: vorbisfile.c,v 1.6.2.5 2003/11/20 06:16:17 xiphmont Exp $ ********************************************************************/ @@ -22,12 +22,19 @@ #include #include -#include "ivorbiscodec.h" +#include "codec_internal.h" #include "ivorbisfile.h" #include "os.h" #include "misc.h" +#define NOTOPEN 0 +#define PARTOPEN 1 +#define OPENED 2 +#define STREAMSET 3 /* serialno and link set, but not to current link */ +#define LINKSET 4 /* serialno and link set to current link */ +#define INITSET 5 + /* A 'chained bitstream' is a Vorbis bitstream that contains more than one logical bitstream arranged end to end (the only form of Ogg multiplexing allowed in a Vorbis bitstream; grouping [parallel @@ -52,42 +59,35 @@ we only want coarse navigation through the stream. */ /************************************************************************* - * Many, many internal helpers. The intention is not to be confusing; - * rampant duplication and monolithic function implementation would be + * Many, many internal helpers. The intention is not to be confusing; + * rampant duplication and monolithic function implementation would be * harder to understand anyway. The high level functions are last. Begin * grokking near the end of the file */ -/* read a little more data from the file/pipe into the ogg_sync framer */ -static long _get_data(OggVorbis_File *vf){ +/* read a little more data from the file/pipe into the tremor_ogg_sync framer */ +static long _get_data(TremorOggVorbis_File *vf){ errno=0; - if(!(vf->callbacks.read_func))return(-1); if(vf->datasource){ - char *buffer=ogg_sync_buffer(&vf->oy,READSIZE); - long bytes=(vf->callbacks.read_func)(buffer,1,READSIZE,vf->datasource); - if(bytes>0)ogg_sync_wrote(&vf->oy,bytes); - if(bytes==0 && errno)return(-1); - return(bytes); + unsigned char *buffer=tremor_ogg_sync_bufferin(vf->oy,CHUNKSIZE); + long bytes=(vf->callbacks.read_func)(buffer,1,CHUNKSIZE,vf->datasource); + if(bytes>0)tremor_ogg_sync_wrote(vf->oy,bytes); + if(bytes==0 && errno)return -1; + return bytes; }else - return(0); + return 0; } /* save a tiny smidge of verbosity to make the code more readable */ -static int _seek_helper(OggVorbis_File *vf,ogg_int64_t offset){ - if(vf->datasource){ - /* only seek if the file position isn't already there */ - if(vf->offset != offset){ - if(!(vf->callbacks.seek_func)|| - (vf->callbacks.seek_func)(vf->datasource, offset, SEEK_SET) == -1) - return OV_EREAD; - vf->offset=offset; - ogg_sync_reset(&vf->oy); - } +static void _seek_helper(TremorOggVorbis_File *vf,tremor_ogg_int64_t offset){ + if(vf->datasource){ + (vf->callbacks.seek_func)(vf->datasource, offset, SEEK_SET); + vf->offset=offset; + tremor_ogg_sync_reset(vf->oy); }else{ /* shouldn't happen unless someone writes a broken callback */ - return OV_EFAULT; + return; } - return 0; } /* The read/seek functions track absolute position within the stream */ @@ -98,310 +98,221 @@ static int _seek_helper(OggVorbis_File *vf,ogg_int64_t offset){ boundary: -1) unbounded search 0) read no additional data; use cached only - n) search for a new page beginning for n bytes + n) search for a new page beginning for n bytes return: <0) did not find a page (OV_FALSE, OV_EOF, OV_EREAD) - n) found a page at absolute offset n */ + n) found a page at absolute offset n + + produces a refcounted page */ -static ogg_int64_t _get_next_page(OggVorbis_File *vf,ogg_page *og, - ogg_int64_t boundary){ +static tremor_ogg_int64_t _get_next_page(TremorOggVorbis_File *vf,tremor_ogg_page *og, + tremor_ogg_int64_t boundary){ if(boundary>0)boundary+=vf->offset; while(1){ long more; - if(boundary>0 && vf->offset>=boundary)return(OV_FALSE); - more=ogg_sync_pageseek(&vf->oy,og); - + if(boundary>0 && vf->offset>=boundary)return OV_FALSE; + more=tremor_ogg_sync_pageseek(vf->oy,og); + if(more<0){ /* skipped n bytes */ vf->offset-=more; }else{ if(more==0){ - /* send more paramedics */ - if(!boundary)return(OV_FALSE); - { - long ret=_get_data(vf); - if(ret==0)return(OV_EOF); - if(ret<0)return(OV_EREAD); - } + /* send more paramedics */ + if(!boundary)return OV_FALSE; + { + long ret=_get_data(vf); + if(ret==0)return OV_EOF; + if(ret<0)return OV_EREAD; + } }else{ - /* got a page. Return the offset at the page beginning, + /* got a page. Return the offset at the page beginning, advance the internal offset past the page end */ - ogg_int64_t ret=vf->offset; - vf->offset+=more; - return(ret); - + tremor_ogg_int64_t ret=vf->offset; + vf->offset+=more; + return ret; + } } } } -/* find the latest page beginning before the passed in position. Much - dirtier than the above as Ogg doesn't have any backward search - linkage. no 'readp' as it will certainly have to read. */ -/* returns offset or OV_EREAD, OV_FAULT */ -static ogg_int64_t _get_prev_page(OggVorbis_File *vf,ogg_int64_t begin,ogg_page *og){ - ogg_int64_t end = begin; - ogg_int64_t ret; - ogg_int64_t offset=-1; +/* find the latest page beginning before the current stream cursor + position. Much dirtier than the above as Ogg doesn't have any + backward search linkage. no 'readp' as it will certainly have to + read. */ +/* returns offset or OV_EREAD, OV_FAULT and produces a refcounted page */ + +static tremor_ogg_int64_t _get_prev_page(TremorOggVorbis_File *vf,tremor_ogg_page *og){ + tremor_ogg_int64_t begin=vf->offset; + tremor_ogg_int64_t end=begin; + tremor_ogg_int64_t ret; + tremor_ogg_int64_t offset=-1; while(offset==-1){ begin-=CHUNKSIZE; if(begin<0) begin=0; - - ret=_seek_helper(vf,begin); - if(ret)return(ret); - + _seek_helper(vf,begin); while(vf->offsetoffset); - if(ret==OV_EREAD)return(OV_EREAD); + if(ret==OV_EREAD)return OV_EREAD; if(ret<0){ - break; + break; }else{ - offset=ret; + offset=ret; } } } - /* In a fully compliant, non-multiplexed stream, we'll still be - holding the last page. In multiplexed (or noncompliant streams), - we will probably have to re-read the last page we saw */ - if(og->header_len==0){ - ret=_seek_helper(vf,offset); - if(ret)return(ret); - - ret=_get_next_page(vf,og,CHUNKSIZE); - if(ret<0) - /* this shouldn't be possible */ - return(OV_EFAULT); - } + /* we have the offset. Actually snork and hold the page now */ + _seek_helper(vf,offset); + ret=_get_next_page(vf,og,CHUNKSIZE); + if(ret<0) + /* this shouldn't be possible */ + return OV_EFAULT; - return(offset); + return offset; } -static void _add_serialno(ogg_page *og,ogg_uint32_t **serialno_list, int *n){ - ogg_uint32_t s = ogg_page_serialno(og); - (*n)++; - - if(*serialno_list){ - *serialno_list = _ogg_realloc(*serialno_list, sizeof(**serialno_list)*(*n)); - }else{ - *serialno_list = _ogg_malloc(sizeof(**serialno_list)); +/* finds each bitstream link one at a time using a bisection search + (has to begin by knowing the offset of the lb's initial page). + Recurses for each link so it can alloc the link storage after + finding them all, then unroll and fill the cache at the same time */ +static int _bisect_forward_serialno(TremorOggVorbis_File *vf, + tremor_ogg_int64_t begin, + tremor_ogg_int64_t searched, + tremor_ogg_int64_t end, + tremor_ogg_uint32_t currentno, + long m){ + tremor_ogg_int64_t endsearched=end; + tremor_ogg_int64_t next=end; + tremor_ogg_page og={0,0,0,0}; + tremor_ogg_int64_t ret; + + /* the below guards against garbage seperating the last and + first pages of two links. */ + while(searched=0)next=ret; + }else{ + searched=ret+og.header_len+og.body_len; + } + tremor_ogg_page_release(&og); } - (*serialno_list)[(*n)-1] = s; -} - -/* returns nonzero if found */ -static int _lookup_serialno(ogg_uint32_t s, ogg_uint32_t *serialno_list, int n){ - if(serialno_list){ - while(n--){ - if(*serialno_list == s) return 1; - serialno_list++; - } + _seek_helper(vf,next); + ret=_get_next_page(vf,&og,-1); + if(ret==OV_EREAD)return OV_EREAD; + + if(searched>=end || ret<0){ + tremor_ogg_page_release(&og); + vf->links=m+1; + vf->offsets=_tremor_ogg_malloc((vf->links+1)*sizeof(*vf->offsets)); + vf->serialnos=_tremor_ogg_malloc(vf->links*sizeof(*vf->serialnos)); + vf->offsets[m+1]=searched; + }else{ + ret=_bisect_forward_serialno(vf,next,vf->offset, + end,tremor_ogg_page_serialno(&og),m+1); + tremor_ogg_page_release(&og); + if(ret==OV_EREAD)return OV_EREAD; } + + vf->offsets[m]=begin; + vf->serialnos[m]=currentno; return 0; } -static int _lookup_page_serialno(ogg_page *og, ogg_uint32_t *serialno_list, int n){ - ogg_uint32_t s = ogg_page_serialno(og); - return _lookup_serialno(s,serialno_list,n); -} - -/* performs the same search as _get_prev_page, but prefers pages of - the specified serial number. If a page of the specified serialno is - spotted during the seek-back-and-read-forward, it will return the - info of last page of the matching serial number instead of the very - last page. If no page of the specified serialno is seen, it will - return the info of last page and alter *serialno. */ -static ogg_int64_t _get_prev_page_serial(OggVorbis_File *vf, ogg_int64_t begin, - ogg_uint32_t *serial_list, int serial_n, - int *serialno, ogg_int64_t *granpos){ - ogg_page og; - ogg_int64_t end=begin; - ogg_int64_t ret; - - ogg_int64_t prefoffset=-1; - ogg_int64_t offset=-1; - ogg_int64_t ret_serialno=-1; - ogg_int64_t ret_gran=-1; - - while(offset==-1){ - begin-=CHUNKSIZE; - if(begin<0) - begin=0; - - ret=_seek_helper(vf,begin); - if(ret)return(ret); - - while(vf->offsetoffset); - if(ret==OV_EREAD)return(OV_EREAD); - if(ret<0){ - break; - }else{ - ret_serialno=ogg_page_serialno(&og); - ret_gran=ogg_page_granulepos(&og); - offset=ret; - - if((ogg_uint32_t)ret_serialno == *serialno){ - prefoffset=ret; - *granpos=ret_gran; - } - - if(!_lookup_serialno((ogg_uint32_t)ret_serialno,serial_list,serial_n)){ - /* we fell off the end of the link, which means we seeked - back too far and shouldn't have been looking in that link - to begin with. If we found the preferred serial number, - forget that we saw it. */ - prefoffset=-1; - } - } - } +static int _decode_clear(TremorOggVorbis_File *vf){ + if(vf->ready_state==INITSET){ + vorbis_dsp_destroy(vf->vd); + vf->vd=0; + vf->ready_state=STREAMSET; } - - /* we're not interested in the page... just the serialno and granpos. */ - if(prefoffset>=0)return(prefoffset); - - *serialno = ret_serialno; - *granpos = ret_gran; - return(offset); - + + if(vf->ready_state>=STREAMSET){ + vorbis_info_clear(&vf->vi); + vorbis_comment_clear(&vf->vc); + vf->ready_state=OPENED; + } + return 0; } -/* uses the local ogg_stream storage in vf; this is important for +/* uses the local tremor_ogg_stream storage in vf; this is important for non-streaming input sources */ -static int _fetch_headers(OggVorbis_File *vf,vorbis_info *vi,vorbis_comment *vc, - ogg_uint32_t **serialno_list, int *serialno_n, - ogg_page *og_ptr){ - ogg_page og; - ogg_packet op; +/* consumes the page that's passed in (if any) */ +/* state is LINKSET upon successful return */ + +static int _fetch_headers(TremorOggVorbis_File *vf, + vorbis_info *vi, + vorbis_comment *vc, + tremor_ogg_uint32_t *serialno, + tremor_ogg_page *og_ptr){ + tremor_ogg_page og={0,0,0,0}; + tremor_ogg_packet op={0,0,0,0,0,0}; int i,ret; - int allbos=0; + + if(vf->ready_state>OPENED)_decode_clear(vf); if(!og_ptr){ - ogg_int64_t llret=_get_next_page(vf,&og,CHUNKSIZE); - if(llret==OV_EREAD)return(OV_EREAD); - if(llret<0)return(OV_ENOTVORBIS); + tremor_ogg_int64_t llret=_get_next_page(vf,&og,CHUNKSIZE); + if(llret==OV_EREAD)return OV_EREAD; + if(llret<0)return OV_ENOTVORBIS; og_ptr=&og; } + tremor_ogg_stream_reset_serialno(vf->os,tremor_ogg_page_serialno(og_ptr)); + if(serialno)*serialno=vf->os->serialno; + + /* extract the initial header from the first page and verify that the + Ogg bitstream is in fact Vorbis data */ + vorbis_info_init(vi); vorbis_comment_init(vc); - vf->ready_state=OPENED; - - /* extract the serialnos of all BOS pages + the first set of vorbis - headers we see in the link */ - - while(ogg_page_bos(og_ptr)){ - if(serialno_list){ - if(_lookup_page_serialno(og_ptr,*serialno_list,*serialno_n)){ - /* a dupe serialnumber in an initial header packet set == invalid stream */ - if(*serialno_list)_ogg_free(*serialno_list); - *serialno_list=0; - *serialno_n=0; - ret=OV_EBADHEADER; - goto bail_header; + + i=0; + while(i<3){ + tremor_ogg_stream_pagein(vf->os,og_ptr); + while(i<3){ + int result=tremor_ogg_stream_packetout(vf->os,&op); + if(result==0)break; + if(result==-1){ + ret=OV_EBADHEADER; + goto bail_header; } - - _add_serialno(og_ptr,serialno_list,serialno_n); - } - - if(vf->ready_stateos,ogg_page_serialno(og_ptr)); - ogg_stream_pagein(&vf->os,og_ptr); - - if(ogg_stream_packetout(&vf->os,&op) > 0 && - vorbis_synthesis_idheader(&op)){ - /* vorbis header; continue setup */ - vf->ready_state=STREAMSET; - if((ret=vorbis_synthesis_headerin(vi,vc,&op))){ - ret=OV_EBADHEADER; - goto bail_header; - } + if((ret=vorbis_dsp_headerin(vi,vc,&op))){ + goto bail_header; } + i++; } - - /* get next page */ - { - ogg_int64_t llret=_get_next_page(vf,og_ptr,CHUNKSIZE); - if(llret==OV_EREAD){ - ret=OV_EREAD; - goto bail_header; - } - if(llret<0){ - ret=OV_ENOTVORBIS; - goto bail_header; + if(i<3) + if(_get_next_page(vf,og_ptr,CHUNKSIZE)<0){ + ret=OV_EBADHEADER; + goto bail_header; } - - /* if this page also belongs to our vorbis stream, submit it and break */ - if(vf->ready_state==STREAMSET && - vf->os.serialno == ogg_page_serialno(og_ptr)){ - ogg_stream_pagein(&vf->os,og_ptr); - break; - } - } } - if(vf->ready_state!=STREAMSET){ - ret = OV_ENOTVORBIS; - goto bail_header; - } - - while(1){ - - i=0; - while(i<2){ /* get a page loop */ - - while(i<2){ /* get a packet loop */ - - int result=ogg_stream_packetout(&vf->os,&op); - if(result==0)break; - if(result==-1){ - ret=OV_EBADHEADER; - goto bail_header; - } - - if((ret=vorbis_synthesis_headerin(vi,vc,&op))) - goto bail_header; - - i++; - } - - while(i<2){ - if(_get_next_page(vf,og_ptr,CHUNKSIZE)<0){ - ret=OV_EBADHEADER; - goto bail_header; - } - - /* if this page belongs to the correct stream, go parse it */ - if(vf->os.serialno == ogg_page_serialno(og_ptr)){ - ogg_stream_pagein(&vf->os,og_ptr); - break; - } - - /* if we never see the final vorbis headers before the link - ends, abort */ - if(ogg_page_bos(og_ptr)){ - if(allbos){ - ret = OV_EBADHEADER; - goto bail_header; - }else - allbos=1; - } - - /* otherwise, keep looking */ - } - } - - return 0; - } + tremor_ogg_packet_release(&op); + tremor_ogg_page_release(&og); + vf->ready_state=LINKSET; + return 0; bail_header: + tremor_ogg_packet_release(&op); + tremor_ogg_page_release(&og); vorbis_info_clear(vi); vorbis_comment_clear(vc); vf->ready_state=OPENED; @@ -409,401 +320,321 @@ static int _fetch_headers(OggVorbis_File *vf,vorbis_info *vi,vorbis_comment *vc, return ret; } -/* Starting from current cursor position, get initial PCM offset of - next page. Consumes the page in the process without decoding - audio, however this is only called during stream parsing upon - seekable open. */ -static ogg_int64_t _initial_pcmoffset(OggVorbis_File *vf, vorbis_info *vi){ - ogg_page og; - ogg_int64_t accumulated=0; - long lastblock=-1; - int result; - int serialno = vf->os.serialno; - - while(1){ - ogg_packet op; - if(_get_next_page(vf,&og,-1)<0) - break; /* should not be possible unless the file is truncated/mangled */ - - if(ogg_page_bos(&og)) break; - if(ogg_page_serialno(&og)!=serialno) continue; - - /* count blocksizes of all frames in the page */ - ogg_stream_pagein(&vf->os,&og); - while((result=ogg_stream_packetout(&vf->os,&op))){ - if(result>0){ /* ignore holes */ - long thisblock=vorbis_packet_blocksize(vi,&op); - if(lastblock!=-1) - accumulated+=(lastblock+thisblock)>>2; - lastblock=thisblock; - } - } - - if(ogg_page_granulepos(&og)!=-1){ - /* pcm offset of last packet on the first audio page */ - accumulated= ogg_page_granulepos(&og)-accumulated; - break; - } +/* we no longer preload all vorbis_info (and the associated + codec_setup) structs. Call this to seek and fetch the info from + the bitstream, if needed */ +static int _set_link_number(TremorOggVorbis_File *vf,int link){ + if(link != vf->current_link) _decode_clear(vf); + if(vf->ready_stateoffsets[link]); + tremor_ogg_stream_reset_serialno(vf->os,vf->serialnos[link]); + vf->current_serialno=vf->serialnos[link]; + vf->current_link=link; + return _fetch_headers(vf,&vf->vi,&vf->vc,&vf->current_serialno,NULL); } - - /* less than zero? This is a stream with samples trimmed off - the beginning, a normal occurrence; set the offset to zero */ - if(accumulated<0)accumulated=0; - - return accumulated; + return 0; } -/* finds each bitstream link one at a time using a bisection search - (has to begin by knowing the offset of the lb's initial page). - Recurses for each link so it can alloc the link storage after - finding them all, then unroll and fill the cache at the same time */ -static int _bisect_forward_serialno(OggVorbis_File *vf, - ogg_int64_t begin, - ogg_int64_t searched, - ogg_int64_t end, - ogg_int64_t endgran, - int endserial, - ogg_uint32_t *currentno_list, - int currentnos, - long m){ - ogg_int64_t pcmoffset; - ogg_int64_t dataoffset=searched; - ogg_int64_t endsearched=end; - ogg_int64_t next=end; - ogg_int64_t searchgran=-1; - ogg_page og; - ogg_int64_t ret,last; - int serialno = vf->os.serialno; - - /* invariants: - we have the headers and serialnos for the link beginning at 'begin' - we have the offset and granpos of the last page in the file (potentially - not a page we care about) - */ - - /* Is the last page in our list of current serialnumbers? */ - if(_lookup_serialno(endserial,currentno_list,currentnos)){ - - /* last page is in the starting serialno list, so we've bisected - down to (or just started with) a single link. Now we need to - find the last vorbis page belonging to the first vorbis stream - for this link. */ - searched = end; - while(endserial != serialno){ - endserial = serialno; - searched=_get_prev_page_serial(vf,searched,currentno_list,currentnos,&endserial,&endgran); - } - - vf->links=m+1; - if(vf->offsets)_ogg_free(vf->offsets); - if(vf->serialnos)_ogg_free(vf->serialnos); - if(vf->dataoffsets)_ogg_free(vf->dataoffsets); - - vf->offsets=_ogg_malloc((vf->links+1)*sizeof(*vf->offsets)); - vf->vi=_ogg_realloc(vf->vi,vf->links*sizeof(*vf->vi)); - vf->vc=_ogg_realloc(vf->vc,vf->links*sizeof(*vf->vc)); - vf->serialnos=_ogg_malloc(vf->links*sizeof(*vf->serialnos)); - vf->dataoffsets=_ogg_malloc(vf->links*sizeof(*vf->dataoffsets)); - vf->pcmlengths=_ogg_malloc(vf->links*2*sizeof(*vf->pcmlengths)); - - vf->offsets[m+1]=end; - vf->offsets[m]=begin; - vf->pcmlengths[m*2+1]=(endgran<0?0:endgran); - - }else{ - - /* last page is not in the starting stream's serial number list, - so we have multiple links. Find where the stream that begins - our bisection ends. */ - - ogg_uint32_t *next_serialno_list=NULL; - int next_serialnos=0; - vorbis_info vi; - vorbis_comment vc; - int testserial = serialno+1; +static int _set_link_number_preserve_pos(TremorOggVorbis_File *vf,int link){ + tremor_ogg_int64_t pos=vf->offset; + int ret=_set_link_number(vf,link); + if(ret)return ret; + _seek_helper(vf,pos); + if(posoffsets[link] || pos>=vf->offsets[link+1]) + vf->ready_state=STREAMSET; + return 0; +} - /* the below guards against garbage seperating the last and - first pages of two links. */ - while(searcheddataoffsets=_tremor_ogg_malloc(vf->links*sizeof(*vf->dataoffsets)); + vf->pcmlengths=_tremor_ogg_malloc(vf->links*2*sizeof(*vf->pcmlengths)); + + for(i=0;ilinks;i++){ + if(i==0){ + /* we already grabbed the initial header earlier. Just set the offset */ + vf->dataoffsets[i]=dataoffset; + _seek_helper(vf,dataoffset); - if(endsearched-searched=0)next=last; + _seek_helper(vf,vf->offsets[i]); + if(_fetch_headers(vf,&vf->vi,&vf->vc,NULL,NULL)<0){ + vf->dataoffsets[i]=-1; }else{ - searched=vf->offset; + vf->dataoffsets[i]=vf->offset; } } - /* Bisection point found */ - /* for the time being, fetch end PCM offset the simple way */ - searched = next; - while(testserial != serialno){ - testserial = serialno; - searched = _get_prev_page_serial(vf,searched,currentno_list,currentnos,&testserial,&searchgran); - } - - ret=_seek_helper(vf,next); - if(ret)return(ret); + /* fetch beginning PCM offset */ - ret=_fetch_headers(vf,&vi,&vc,&next_serialno_list,&next_serialnos,NULL); - if(ret)return(ret); - serialno = vf->os.serialno; - dataoffset = vf->offset; + if(vf->dataoffsets[i]!=-1){ + tremor_ogg_int64_t accumulated=0,pos; + long lastblock=-1; + int result; - /* this will consume a page, however the next bisection always - starts with a raw seek */ - pcmoffset = _initial_pcmoffset(vf,&vi); + tremor_ogg_stream_reset_serialno(vf->os,vf->serialnos[i]); - ret=_bisect_forward_serialno(vf,next,vf->offset,end,endgran,endserial, - next_serialno_list,next_serialnos,m+1); - if(ret)return(ret); - - if(next_serialno_list)_ogg_free(next_serialno_list); + while(1){ + tremor_ogg_packet op={0,0,0,0,0,0}; + + ret=_get_next_page(vf,&og,-1); + if(ret<0) + /* this should not be possible unless the file is + truncated/mangled */ + break; + + if(tremor_ogg_page_serialno(&og)!=vf->serialnos[i]) + break; + + pos=tremor_ogg_page_granulepos(&og); + + /* count blocksizes of all frames in the page */ + tremor_ogg_stream_pagein(vf->os,&og); + while((result=tremor_ogg_stream_packetout(vf->os,&op))){ + if(result>0){ /* ignore holes */ + long thisblock=vorbis_packet_blocksize(&vf->vi,&op); + if(lastblock!=-1) + accumulated+=(lastblock+thisblock)>>2; + lastblock=thisblock; + } + } + tremor_ogg_packet_release(&op); + + if(pos!=-1){ + /* pcm offset of last packet on the first audio page */ + accumulated= pos-accumulated; + break; + } + } - vf->offsets[m+1]=next; - vf->serialnos[m+1]=serialno; - vf->dataoffsets[m+1]=dataoffset; + /* less than zero? This is a stream with samples trimmed off + the beginning, a normal occurrence; set the offset to zero */ + if(accumulated<0)accumulated=0; - vf->vi[m+1]=vi; - vf->vc[m+1]=vc; + vf->pcmlengths[i*2]=accumulated; + } - vf->pcmlengths[m*2+1]=searchgran; - vf->pcmlengths[m*2+2]=pcmoffset; - vf->pcmlengths[m*2+3]-=pcmoffset; - if(vf->pcmlengths[m*2+3]<0)vf->pcmlengths[m*2+3]=0; + /* get the PCM length of this link. To do this, + get the last page of the stream */ + { + tremor_ogg_int64_t end=vf->offsets[i+1]; + _seek_helper(vf,end); + while(1){ + ret=_get_prev_page(vf,&og); + if(ret<0){ + /* this should not be possible */ + vorbis_info_clear(&vf->vi); + vorbis_comment_clear(&vf->vc); + break; + } + if(tremor_ogg_page_granulepos(&og)!=-1){ + vf->pcmlengths[i*2+1]=tremor_ogg_page_granulepos(&og)-vf->pcmlengths[i*2]; + break; + } + vf->offset=ret; + } + } } - return(0); + tremor_ogg_page_release(&og); } -static int _make_decode_ready(OggVorbis_File *vf){ - if(vf->ready_state>STREAMSET)return 0; - if(vf->ready_stateseekable){ - if(vorbis_synthesis_init(&vf->vd,vf->vi+vf->current_link)) - return OV_EBADLINK; - }else{ - if(vorbis_synthesis_init(&vf->vd,vf->vi)) - return OV_EBADLINK; +static int _make_decode_ready(TremorOggVorbis_File *vf){ + int i; + switch(vf->ready_state){ + case OPENED: + case STREAMSET: + for(i=0;ilinks;i++) + if(vf->offsets[i+1]>=vf->offset)break; + if(i==vf->links)return -1; + i=_set_link_number_preserve_pos(vf,i); + if(i)return i; + /* fall through */ + case LINKSET: + vf->vd=vorbis_dsp_create(&vf->vi); + vf->ready_state=INITSET; + vf->bittrack=0; + vf->samptrack=0; + case INITSET: + return 0; + default: + return -1; } - vorbis_block_init(&vf->vd,&vf->vb); - vf->ready_state=INITSET; - vf->bittrack=0; - vf->samptrack=0; - return 0; + } -static int _open_seekable2(OggVorbis_File *vf){ - ogg_int64_t dataoffset=vf->dataoffsets[0],end,endgran=-1; - int endserial=vf->os.serialno; - int serialno=vf->os.serialno; +static int _open_seekable2(TremorOggVorbis_File *vf){ + tremor_ogg_uint32_t serialno=vf->current_serialno; + tremor_ogg_uint32_t tempserialno; + tremor_ogg_int64_t dataoffset=vf->offset, end; + tremor_ogg_page og={0,0,0,0}; /* we're partially open and have a first link header state in storage in vf */ - - /* fetch initial PCM offset */ - ogg_int64_t pcmoffset = _initial_pcmoffset(vf,vf->vi); - /* we can seek, so set out learning all about this file */ - if(vf->callbacks.seek_func && vf->callbacks.tell_func){ - (vf->callbacks.seek_func)(vf->datasource,0,SEEK_END); - vf->offset=vf->end=(vf->callbacks.tell_func)(vf->datasource); - }else{ - vf->offset=vf->end=-1; - } + (vf->callbacks.seek_func)(vf->datasource,0,SEEK_END); + vf->offset=vf->end=(vf->callbacks.tell_func)(vf->datasource); + + /* We get the offset for the last page of the physical bitstream. + Most TremorOggVorbis files will contain a single logical bitstream */ + end=_get_prev_page(vf,&og); + if(end<0)return end; - /* If seek_func is implemented, tell_func must also be implemented */ - if(vf->end==-1) return(OV_EINVAL); + /* more than one logical bitstream? */ + tempserialno=tremor_ogg_page_serialno(&og); + tremor_ogg_page_release(&og); - /* Get the offset of the last page of the physical bitstream, or, if - we're lucky the last vorbis page of this link as most OggVorbis - files will contain a single logical bitstream */ - end=_get_prev_page_serial(vf,vf->end,vf->serialnos+2,vf->serialnos[1],&endserial,&endgran); - if(end<0)return(end); + if(tempserialno!=serialno){ - /* now determine bitstream structure recursively */ - if(_bisect_forward_serialno(vf,0,dataoffset,end,endgran,endserial, - vf->serialnos+2,vf->serialnos[1],0)<0)return(OV_EREAD); + /* Chained bitstream. Bisect-search each logical bitstream + section. Do so based on serial number only */ + if(_bisect_forward_serialno(vf,0,0,end+1,serialno,0)<0)return OV_EREAD; - vf->offsets[0]=0; - vf->serialnos[0]=serialno; - vf->dataoffsets[0]=dataoffset; - vf->pcmlengths[0]=pcmoffset; - vf->pcmlengths[1]-=pcmoffset; - if(vf->pcmlengths[1]<0)vf->pcmlengths[1]=0; + }else{ - return(ov_raw_seek(vf,dataoffset)); -} + /* Only one logical bitstream */ + if(_bisect_forward_serialno(vf,0,end,end+1,serialno,0))return OV_EREAD; -/* clear out the current logical bitstream decoder */ -static void _decode_clear(OggVorbis_File *vf){ - vorbis_dsp_clear(&vf->vd); - vorbis_block_clear(&vf->vb); - vf->ready_state=OPENED; + } + + /* the initial header memory is referenced by vf after; don't free it */ + _prefetch_all_offsets(vf,dataoffset); + return ov_raw_seek(vf,0); } /* fetch and process a packet. Handles the case where we're at a bitstream boundary and dumps the decoding machine. If the decoding machine is unloaded, it loads it. It also keeps pcm_offset up to date (seek and read both use this. seek uses a special hack with - readp). + readp). return: <0) error, OV_HOLE (lost packet) or OV_EOF 0) need more data (only if readp==0) - 1) got a packet + 1) got a packet */ -static int _fetch_and_process_packet(OggVorbis_File *vf, - ogg_packet *op_in, - int readp, - int spanp){ - ogg_page og; +static int _fetch_and_process_packet(TremorOggVorbis_File *vf, + int readp, + int spanp){ + tremor_ogg_page og={0,0,0,0}; + tremor_ogg_packet op={0,0,0,0,0,0}; + int ret=0; /* handle one packet. Try to fetch it from current stream state */ /* extract packets from page */ while(1){ - - if(vf->ready_state==STREAMSET){ - int ret=_make_decode_ready(vf); - if(ret<0)return ret; - } - + /* process a packet if we can. If the machine isn't loaded, neither is a page */ if(vf->ready_state==INITSET){ while(1) { - ogg_packet op; - ogg_packet *op_ptr=(op_in?op_in:&op); - int result=ogg_stream_packetout(&vf->os,op_ptr); - ogg_int64_t granulepos; - - op_in=NULL; - if(result==-1)return(OV_HOLE); /* hole in the data. */ - if(result>0){ - /* got a packet. process it */ - granulepos=op_ptr->granulepos; - if(!vorbis_synthesis(&vf->vb,op_ptr)){ /* lazy check for lazy - header handling. The - header packets aren't - audio, so if/when we - submit them, - vorbis_synthesis will - reject them */ - - /* suck in the synthesis data and track bitrate */ - { - int oldsamples=vorbis_synthesis_pcmout(&vf->vd,NULL); - /* for proper use of libvorbis within libvorbisfile, - oldsamples will always be zero. */ - if(oldsamples)return(OV_EFAULT); - - vorbis_synthesis_blockin(&vf->vd,&vf->vb); - vf->samptrack+=vorbis_synthesis_pcmout(&vf->vd,NULL); - vf->bittrack+=op_ptr->bytes*8; - } - - /* update the pcm offset. */ - if(granulepos!=-1 && !op_ptr->e_o_s){ - int link=(vf->seekable?vf->current_link:0); - int i,samples; - - /* this packet has a pcm_offset on it (the last packet - completed on a page carries the offset) After processing - (above), we know the pcm position of the *last* sample - ready to be returned. Find the offset of the *first* - - As an aside, this trick is inaccurate if we begin - reading anew right at the last page; the end-of-stream - granulepos declares the last frame in the stream, and the - last packet of the last page may be a partial frame. - So, we need a previous granulepos from an in-sequence page - to have a reference point. Thus the !op_ptr->e_o_s clause - above */ - - if(vf->seekable && link>0) - granulepos-=vf->pcmlengths[link*2]; - if(granulepos<0)granulepos=0; /* actually, this - shouldn't be possible - here unless the stream - is very broken */ - - samples=vorbis_synthesis_pcmout(&vf->vd,NULL); - - granulepos-=samples; - for(i=0;ipcmlengths[i*2+1]; - vf->pcm_offset=granulepos; - } - return(1); - } - } - else - break; + int result=tremor_ogg_stream_packetout(vf->os,&op); + tremor_ogg_int64_t granulepos; + + if(result<0){ + ret=OV_HOLE; /* hole in the data. */ + goto cleanup; + } + if(result>0){ + /* got a packet. process it */ + granulepos=op.granulepos; + if(!vorbis_dsp_synthesis(vf->vd,&op,1)){ /* lazy check for lazy + header handling. The + header packets aren't + audio, so if/when we + submit them, + vorbis_synthesis will + reject them */ + + vf->samptrack+=vorbis_dsp_pcmout(vf->vd,NULL,0); + vf->bittrack+=op.bytes*8; + + /* update the pcm offset. */ + if(granulepos!=-1 && !op.e_o_s){ + int link=(vf->seekable?vf->current_link:0); + int i,samples; + + /* this packet has a pcm_offset on it (the last packet + completed on a page carries the offset) After processing + (above), we know the pcm position of the *last* sample + ready to be returned. Find the offset of the *first* + + As an aside, this trick is inaccurate if we begin + reading anew right at the last page; the end-of-stream + granulepos declares the last frame in the stream, and the + last packet of the last page may be a partial frame. + So, we need a previous granulepos from an in-sequence page + to have a reference point. Thus the !op.e_o_s clause + above */ + + if(vf->seekable && link>0) + granulepos-=vf->pcmlengths[link*2]; + if(granulepos<0)granulepos=0; /* actually, this + shouldn't be possible + here unless the stream + is very broken */ + + samples=vorbis_dsp_pcmout(vf->vd,NULL,0); + + granulepos-=samples; + for(i=0;ipcmlengths[i*2+1]; + vf->pcm_offset=granulepos; + } + ret=1; + goto cleanup; + } + } + else + break; } } if(vf->ready_state>=OPENED){ - ogg_int64_t ret; + int ret; + if(!readp){ + ret=0; + goto cleanup; + } + if((ret=_get_next_page(vf,&og,-1))<0){ + ret=OV_EOF; /* eof. leave unitialized */ + goto cleanup; + } - while(1){ - /* the loop is not strictly necessary, but there's no sense in - doing the extra checks of the larger loop for the common - case in a multiplexed bistream where the page is simply - part of a different logical bitstream; keep reading until - we get one with the correct serialno */ - - if(!readp)return(0); - if((ret=_get_next_page(vf,&og,-1))<0){ - return(OV_EOF); /* eof. leave unitialized */ - } - - /* bitrate tracking; add the header's bytes here, the body bytes - are done by packet above */ - vf->bittrack+=og.header_len*8; - - if(vf->ready_state==INITSET){ - if(vf->current_serialno!=ogg_page_serialno(&og)){ - - /* two possibilities: - 1) our decoding just traversed a bitstream boundary - 2) another stream is multiplexed into this logical section */ - - if(ogg_page_bos(&og)){ - /* boundary case */ - if(!spanp) - return(OV_EOF); - - _decode_clear(vf); - - if(!vf->seekable){ - vorbis_info_clear(vf->vi); - vorbis_comment_clear(vf->vc); - } - break; - - }else - continue; /* possibility #2 */ - } - } - - break; + /* bitrate tracking; add the header's bytes here, the body bytes + are done by packet above */ + vf->bittrack+=og.header_len*8; + + /* has our decoding just traversed a bitstream boundary? */ + if(vf->ready_state==INITSET){ + if(vf->current_serialno!=tremor_ogg_page_serialno(&og)){ + if(!spanp){ + ret=OV_EOF; + goto cleanup; + } + + _decode_clear(vf); + } } } /* Do we need to load a new machine before submitting the page? */ - /* This is different in the seekable and non-seekable cases. + /* This is different in the seekable and non-seekable cases. In the seekable case, we already have all the header information loaded and cached; we just initialize the machine @@ -814,79 +645,80 @@ static int _fetch_and_process_packet(OggVorbis_File *vf, we're now nominally at the header of the next bitstream */ - if(vf->ready_state!=INITSET){ - int link; + if(vf->ready_state!=INITSET){ + int link,ret; if(vf->ready_stateseekable){ - ogg_uint32_t serialno = ogg_page_serialno(&og); - - /* match the serialno to bitstream section. We use this rather than - offset positions to avoid problems near logical bitstream - boundaries */ - - for(link=0;linklinks;link++) - if(vf->serialnos[link]==serialno)break; - - if(link==vf->links) continue; /* not the desired Vorbis - bitstream section; keep - trying */ - - vf->current_serialno=serialno; - vf->current_link=link; - - ogg_stream_reset_serialno(&vf->os,vf->current_serialno); - vf->ready_state=STREAMSET; - - }else{ - /* we're streaming */ - /* fetch the three header packets, build the info struct */ - - int ret=_fetch_headers(vf,vf->vi,vf->vc,NULL,NULL,&og); - if(ret)return(ret); - vf->current_serialno=vf->os.serialno; - vf->current_link++; - link=0; - } + if(vf->seekable){ + vf->current_serialno=tremor_ogg_page_serialno(&og); + + /* match the serialno to bitstream section. We use this rather than + offset positions to avoid problems near logical bitstream + boundaries */ + for(link=0;linklinks;link++) + if(vf->serialnos[link]==vf->current_serialno)break; + if(link==vf->links){ + ret=OV_EBADLINK; /* sign of a bogus stream. error out, + leave machine uninitialized */ + goto cleanup; + } + + vf->current_link=link; + ret=_fetch_headers(vf,&vf->vi,&vf->vc,&vf->current_serialno,&og); + if(ret) goto cleanup; + + }else{ + /* we're streaming */ + /* fetch the three header packets, build the info struct */ + + int ret=_fetch_headers(vf,&vf->vi,&vf->vc,&vf->current_serialno,&og); + if(ret) goto cleanup; + vf->current_link++; + } } + + if(_make_decode_ready(vf)) return OV_EBADLINK; } - - /* the buffered page is the data we want, and we're ready for it; - add it to the stream state */ - ogg_stream_pagein(&vf->os,&og); - + tremor_ogg_stream_pagein(vf->os,&og); } + cleanup: + tremor_ogg_packet_release(&op); + tremor_ogg_page_release(&og); + return ret; } /* if, eg, 64 bit stdio is configured by default, this will build with fseek64 */ -static int _fseek64_wrap(FILE *f,ogg_int64_t off,int whence){ - if(f==NULL)return(-1); +static int _fseek64_wrap(FILE *f,tremor_ogg_int64_t off,int whence){ + if(f==NULL)return -1; return fseek(f,off,whence); } -static int _ov_open1(void *f,OggVorbis_File *vf,const char *initial, - long ibytes, ov_callbacks callbacks){ - int offsettest=((f && callbacks.seek_func)?callbacks.seek_func(f,0,SEEK_CUR):-1); - ogg_uint32_t *serialno_list=NULL; - int serialno_list_size=0; +static int _ov_open1(void *f,TremorOggVorbis_File *vf,char *initial, + long ibytes, ov_callbacks callbacks){ + int offsettest=(f?callbacks.seek_func(f,0,SEEK_CUR):-1); int ret; memset(vf,0,sizeof(*vf)); + + /* Tremor assumes in multiple places that right shift of a signed + integer is an arithmetic shift */ + if( (-1>>1) != -1) return OV_EIMPL; + vf->datasource=f; vf->callbacks = callbacks; /* init the framing state */ - ogg_sync_init(&vf->oy); + vf->oy=tremor_ogg_sync_create(); /* perhaps some data was previously read into a buffer for testing against other stream types. Allow initialization from this - previously read data (especially as we may be reading from a - non-seekable stream) */ + previously read data (as we may be reading from a non-seekable + stream) */ if(initial){ - char *buffer=ogg_sync_buffer(&vf->oy,ibytes); + unsigned char *buffer=tremor_ogg_sync_bufferin(vf->oy,ibytes); memcpy(buffer,initial,ibytes); - ogg_sync_wrote(&vf->oy,ibytes); + tremor_ogg_sync_wrote(vf->oy,ibytes); } /* can we seek? Stevens suggests the seek test was portable */ @@ -895,154 +727,115 @@ static int _ov_open1(void *f,OggVorbis_File *vf,const char *initial, /* No seeking yet; Set up a 'single' (current) logical bitstream entry for partial open */ vf->links=1; - vf->vi=_ogg_calloc(vf->links,sizeof(*vf->vi)); - vf->vc=_ogg_calloc(vf->links,sizeof(*vf->vc)); - ogg_stream_init(&vf->os,-1); /* fill in the serialno later */ + vf->os=tremor_ogg_stream_create(-1); /* fill in the serialno later */ - /* Fetch all BOS pages, store the vorbis header and all seen serial - numbers, load subsequent vorbis setup headers */ - if((ret=_fetch_headers(vf,vf->vi,vf->vc,&serialno_list,&serialno_list_size,NULL))<0){ + /* Try to fetch the headers, maintaining all the storage */ + if((ret=_fetch_headers(vf,&vf->vi,&vf->vc,&vf->current_serialno,NULL))<0){ vf->datasource=NULL; ov_clear(vf); - }else{ - /* serial number list for first link needs to be held somewhere - for second stage of seekable stream open; this saves having to - seek/reread first link's serialnumber data then. */ - vf->serialnos=_ogg_calloc(serialno_list_size+2,sizeof(*vf->serialnos)); - vf->serialnos[0]=vf->current_serialno=vf->os.serialno; - vf->serialnos[1]=serialno_list_size; - memcpy(vf->serialnos+2,serialno_list,serialno_list_size*sizeof(*vf->serialnos)); - - vf->offsets=_ogg_calloc(1,sizeof(*vf->offsets)); - vf->dataoffsets=_ogg_calloc(1,sizeof(*vf->dataoffsets)); - vf->offsets[0]=0; - vf->dataoffsets[0]=vf->offset; - + }else if(vf->ready_state < PARTOPEN) vf->ready_state=PARTOPEN; - } - if(serialno_list)_ogg_free(serialno_list); - return(ret); + return ret; } -static int _ov_open2(OggVorbis_File *vf){ - if(vf->ready_state != PARTOPEN) return OV_EINVAL; - vf->ready_state=OPENED; +static int _ov_open2(TremorOggVorbis_File *vf){ + if(vf->ready_state < OPENED) + vf->ready_state=OPENED; if(vf->seekable){ int ret=_open_seekable2(vf); if(ret){ vf->datasource=NULL; ov_clear(vf); } - return(ret); - }else - vf->ready_state=STREAMSET; - + return ret; + } return 0; } -/* clear out the OggVorbis_File struct */ -int ov_clear(OggVorbis_File *vf){ +/* clear out the TremorOggVorbis_File struct */ +int ov_clear(TremorOggVorbis_File *vf){ if(vf){ - vorbis_block_clear(&vf->vb); - vorbis_dsp_clear(&vf->vd); - ogg_stream_clear(&vf->os); - - if(vf->vi && vf->links){ - int i; - for(i=0;ilinks;i++){ - vorbis_info_clear(vf->vi+i); - vorbis_comment_clear(vf->vc+i); - } - _ogg_free(vf->vi); - _ogg_free(vf->vc); - } - if(vf->dataoffsets)_ogg_free(vf->dataoffsets); - if(vf->pcmlengths)_ogg_free(vf->pcmlengths); - if(vf->serialnos)_ogg_free(vf->serialnos); - if(vf->offsets)_ogg_free(vf->offsets); - ogg_sync_clear(&vf->oy); - if(vf->datasource && vf->callbacks.close_func) - (vf->callbacks.close_func)(vf->datasource); + vorbis_dsp_destroy(vf->vd); + vf->vd=0; + tremor_ogg_stream_destroy(vf->os); + vorbis_info_clear(&vf->vi); + vorbis_comment_clear(&vf->vc); + if(vf->dataoffsets)_tremor_ogg_free(vf->dataoffsets); + if(vf->pcmlengths)_tremor_ogg_free(vf->pcmlengths); + if(vf->serialnos)_tremor_ogg_free(vf->serialnos); + if(vf->offsets)_tremor_ogg_free(vf->offsets); + tremor_ogg_sync_destroy(vf->oy); + + if(vf->datasource)(vf->callbacks.close_func)(vf->datasource); memset(vf,0,sizeof(*vf)); } #ifdef DEBUG_LEAKS _VDBG_dump(); #endif - return(0); + return 0; } -/* inspects the OggVorbis file and finds/documents all the logical +/* inspects the TremorOggVorbis file and finds/documents all the logical bitstreams contained in it. Tries to be tolerant of logical - bitstream sections that are truncated/woogie. + bitstream sections that are truncated/woogie. return: -1) error 0) OK */ -int ov_open_callbacks(void *f,OggVorbis_File *vf, - const char *initial,long ibytes,ov_callbacks callbacks){ +int ov_open_callbacks(void *f,TremorOggVorbis_File *vf,char *initial,long ibytes, + ov_callbacks callbacks){ int ret=_ov_open1(f,vf,initial,ibytes,callbacks); if(ret)return ret; return _ov_open2(vf); } -int ov_open(FILE *f,OggVorbis_File *vf,const char *initial,long ibytes){ +int ov_open(FILE *f,TremorOggVorbis_File *vf,char *initial,long ibytes){ ov_callbacks callbacks = { (size_t (*)(void *, size_t, size_t, void *)) fread, - (int (*)(void *, ogg_int64_t, int)) _fseek64_wrap, + (int (*)(void *, tremor_ogg_int64_t, int)) _fseek64_wrap, (int (*)(void *)) fclose, (long (*)(void *)) ftell }; return ov_open_callbacks((void *)f, vf, initial, ibytes, callbacks); } - -int ov_fopen(const char *path,OggVorbis_File *vf){ - int ret; - FILE *f = fopen(path,"rb"); - if(!f) return -1; - - ret = ov_open(f,vf,NULL,0); - if(ret) fclose(f); - return ret; -} - - + /* Only partially open the vorbis file; test for Vorbisness, and load the headers for the first chain. Do not seek (although test for seekability). Use ov_test_open to finish opening the file, else ov_clear to close/free it. Same return codes as open. */ -int ov_test_callbacks(void *f,OggVorbis_File *vf, - const char *initial,long ibytes,ov_callbacks callbacks) +int ov_test_callbacks(void *f,TremorOggVorbis_File *vf,char *initial,long ibytes, + ov_callbacks callbacks) { return _ov_open1(f,vf,initial,ibytes,callbacks); } -int ov_test(FILE *f,OggVorbis_File *vf,const char *initial,long ibytes){ +int ov_test(FILE *f,TremorOggVorbis_File *vf,char *initial,long ibytes){ ov_callbacks callbacks = { (size_t (*)(void *, size_t, size_t, void *)) fread, - (int (*)(void *, ogg_int64_t, int)) _fseek64_wrap, + (int (*)(void *, tremor_ogg_int64_t, int)) _fseek64_wrap, (int (*)(void *)) fclose, (long (*)(void *)) ftell }; return ov_test_callbacks((void *)f, vf, initial, ibytes, callbacks); } - -int ov_test_open(OggVorbis_File *vf){ - if(vf->ready_state!=PARTOPEN)return(OV_EINVAL); + +int ov_test_open(TremorOggVorbis_File *vf){ + if(vf->ready_state!=PARTOPEN)return OV_EINVAL; return _ov_open2(vf); } /* How many logical bitstreams in this physical bitstream? */ -long ov_streams(OggVorbis_File *vf){ +long ov_streams(TremorOggVorbis_File *vf){ return vf->links; } /* Is the FILE * associated with vf seekable? */ -long ov_seekable(OggVorbis_File *vf){ +long ov_seekable(TremorOggVorbis_File *vf){ return vf->seekable; } @@ -1055,12 +848,12 @@ long ov_seekable(OggVorbis_File *vf){ If you want the actual bitrate field settings, get them from the vorbis_info structs */ -long ov_bitrate(OggVorbis_File *vf,int i){ - if(vf->ready_state=vf->links)return(OV_EINVAL); - if(!vf->seekable && i!=0)return(ov_bitrate(vf,0)); +long ov_bitrate(TremorOggVorbis_File *vf,int i){ + if(vf->ready_state=vf->links)return OV_EINVAL; + if(!vf->seekable && i!=0)return ov_bitrate(vf,0); if(i<0){ - ogg_int64_t bits=0; + tremor_ogg_int64_t bits=0; int i; for(i=0;ilinks;i++) bits+=(vf->offsets[i+1]-vf->dataoffsets[i])*8; @@ -1068,24 +861,24 @@ long ov_bitrate(OggVorbis_File *vf,int i){ * gcc 3.x on x86 miscompiled this at optimisation level 2 and above, * so this is slightly transformed to make it work. */ - return(bits*1000/ov_time_total(vf,-1)); + return bits*1000/ov_time_total(vf,-1); }else{ if(vf->seekable){ /* return the actual bitrate */ - return((vf->offsets[i+1]-vf->dataoffsets[i])*8000/ov_time_total(vf,i)); + return (vf->offsets[i+1]-vf->dataoffsets[i])*8000/ov_time_total(vf,i); }else{ /* return nominal if set */ - if(vf->vi[i].bitrate_nominal>0){ - return vf->vi[i].bitrate_nominal; + if(vf->vi.bitrate_nominal>0){ + return vf->vi.bitrate_nominal; }else{ - if(vf->vi[i].bitrate_upper>0){ - if(vf->vi[i].bitrate_lower>0){ - return (vf->vi[i].bitrate_upper+vf->vi[i].bitrate_lower)/2; - }else{ - return vf->vi[i].bitrate_upper; - } - } - return(OV_FALSE); + if(vf->vi.bitrate_upper>0){ + if(vf->vi.bitrate_lower>0){ + return (vf->vi.bitrate_upper+vf->vi.bitrate_lower)/2; + }else{ + return vf->vi.bitrate_upper; + } + } + return OV_FALSE; } } } @@ -1093,84 +886,83 @@ long ov_bitrate(OggVorbis_File *vf,int i){ /* returns the actual bitrate since last call. returns -1 if no additional data to offer since last call (or at beginning of stream), - EINVAL if stream is only partially open + EINVAL if stream is only partially open */ -long ov_bitrate_instant(OggVorbis_File *vf){ - int link=(vf->seekable?vf->current_link:0); +long ov_bitrate_instant(TremorOggVorbis_File *vf){ long ret; - if(vf->ready_statesamptrack==0)return(OV_FALSE); - ret=vf->bittrack/vf->samptrack*vf->vi[link].rate; + if(vf->ready_statesamptrack==0)return OV_FALSE; + ret=vf->bittrack/vf->samptrack*vf->vi.rate; vf->bittrack=0; vf->samptrack=0; - return(ret); + return ret; } /* Guess */ -long ov_serialnumber(OggVorbis_File *vf,int i){ - if(i>=vf->links)return(ov_serialnumber(vf,vf->links-1)); - if(!vf->seekable && i>=0)return(ov_serialnumber(vf,-1)); +long ov_serialnumber(TremorOggVorbis_File *vf,int i){ + if(i>=vf->links)return ov_serialnumber(vf,vf->links-1); + if(!vf->seekable && i>=0)return ov_serialnumber(vf,-1); if(i<0){ - return(vf->current_serialno); + return vf->current_serialno; }else{ - return(vf->serialnos[i]); + return vf->serialnos[i]; } } /* returns: total raw (compressed) length of content if i==-1 raw (compressed) length of that logical bitstream for i==0 to n - OV_EINVAL if the stream is not seekable (we can't know the length) - or if stream is only partially open + OV_EINVAL if the stream is not seekable (we can't know the length) + or if stream is only partially open */ -ogg_int64_t ov_raw_total(OggVorbis_File *vf,int i){ - if(vf->ready_stateseekable || i>=vf->links)return(OV_EINVAL); +tremor_ogg_int64_t ov_raw_total(TremorOggVorbis_File *vf,int i){ + if(vf->ready_stateseekable || i>=vf->links)return OV_EINVAL; if(i<0){ - ogg_int64_t acc=0; + tremor_ogg_int64_t acc=0; int i; for(i=0;ilinks;i++) acc+=ov_raw_total(vf,i); - return(acc); + return acc; }else{ - return(vf->offsets[i+1]-vf->offsets[i]); + return vf->offsets[i+1]-vf->offsets[i]; } } /* returns: total PCM length (samples) of content if i==-1 PCM length - (samples) of that logical bitstream for i==0 to n - OV_EINVAL if the stream is not seekable (we can't know the - length) or only partially open + (samples) of that logical bitstream for i==0 to n + OV_EINVAL if the stream is not seekable (we can't know the + length) or only partially open */ -ogg_int64_t ov_pcm_total(OggVorbis_File *vf,int i){ - if(vf->ready_stateseekable || i>=vf->links)return(OV_EINVAL); +tremor_ogg_int64_t ov_pcm_total(TremorOggVorbis_File *vf,int i){ + if(vf->ready_stateseekable || i>=vf->links)return OV_EINVAL; if(i<0){ - ogg_int64_t acc=0; + tremor_ogg_int64_t acc=0; int i; for(i=0;ilinks;i++) acc+=ov_pcm_total(vf,i); - return(acc); + return acc; }else{ - return(vf->pcmlengths[i*2+1]); + return vf->pcmlengths[i*2+1]; } } /* returns: total milliseconds of content if i==-1 milliseconds in that logical bitstream for i==0 to n - OV_EINVAL if the stream is not seekable (we can't know the - length) or only partially open + OV_EINVAL if the stream is not seekable (we can't know the + length) or only partially open */ -ogg_int64_t ov_time_total(OggVorbis_File *vf,int i){ - if(vf->ready_stateseekable || i>=vf->links)return(OV_EINVAL); +tremor_ogg_int64_t ov_time_total(TremorOggVorbis_File *vf,int i){ + if(vf->ready_stateseekable || i>=vf->links)return OV_EINVAL; if(i<0){ - ogg_int64_t acc=0; + tremor_ogg_int64_t acc=0; int i; for(i=0;ilinks;i++) acc+=ov_time_total(vf,i); - return(acc); + return acc; }else{ - return(((ogg_int64_t)vf->pcmlengths[i*2+1])*1000/vf->vi[i].rate); + return ((tremor_ogg_int64_t)vf->pcmlengths[i*2+1])*1000/vf->vi.rate; } } @@ -1181,33 +973,27 @@ ogg_int64_t ov_time_total(OggVorbis_File *vf,int i){ returns zero on success, nonzero on failure */ -int ov_raw_seek(OggVorbis_File *vf,ogg_int64_t pos){ - ogg_stream_state work_os; - int ret; - - if(vf->ready_stateready_stateseekable) - return(OV_ENOSEEK); /* don't dump machine if we can't seek */ - - if(pos<0 || pos>vf->end)return(OV_EINVAL); + return OV_ENOSEEK; /* don't dump machine if we can't seek */ - /* is the seek position outside our current link [if any]? */ - if(vf->ready_state>=STREAMSET){ - if(posoffsets[vf->current_link] || pos>=vf->offsets[vf->current_link+1]) - _decode_clear(vf); /* clear out stream state */ - } + if(pos<0 || pos>vf->end)return OV_EINVAL; /* don't yet clear out decoding machine (if it's initialized), in the case we're in the same link. Restart the decode lapping, and let _fetch_and_process_packet deal with a potential bitstream boundary */ vf->pcm_offset=-1; - ogg_stream_reset_serialno(&vf->os, - vf->current_serialno); /* must set serialno */ - vorbis_synthesis_restart(&vf->vd); - - ret=_seek_helper(vf,pos); - if(ret)goto seek_error; + tremor_ogg_stream_reset_serialno(vf->os, + vf->current_serialno); /* must set serialno */ + vorbis_dsp_restart(vf->vd); + + _seek_helper(vf,pos); /* we need to make sure the pcm_offset is set, but we don't want to advance the raw cursor past good packets just to get to the first @@ -1216,428 +1002,281 @@ int ov_raw_seek(OggVorbis_File *vf,ogg_int64_t pos){ So, a hack. We use two stream states; a local scratch state and the shared vf->os stream state. We use the local state to - scan, and the shared state as a buffer for later decode. + scan, and the shared state as a buffer for later decode. Unfortuantely, on the last page we still advance to last packet because the granulepos on the last page is not necessarily on a packet boundary, and we need to make sure the granpos is - correct. + correct. */ { - ogg_page og; - ogg_packet op; int lastblock=0; int accblock=0; - int thisblock=0; - int lastflag=0; - int firstflag=0; - ogg_int64_t pagepos=-1; - - ogg_stream_init(&work_os,vf->current_serialno); /* get the memory ready */ - ogg_stream_reset(&work_os); /* eliminate the spurious OV_HOLE - return from not necessarily - starting from the beginning */ + int thisblock; + int eosflag; + work_os=tremor_ogg_stream_create(vf->current_serialno); /* get the memory ready */ while(1){ if(vf->ready_state>=STREAMSET){ - /* snarf/scan a packet if we can */ - int result=ogg_stream_packetout(&work_os,&op); - - if(result>0){ - - if(vf->vi[vf->current_link].codec_setup){ - thisblock=vorbis_packet_blocksize(vf->vi+vf->current_link,&op); - if(thisblock<0){ - ogg_stream_packetout(&vf->os,NULL); - thisblock=0; - }else{ - - /* We can't get a guaranteed correct pcm position out of the - last page in a stream because it might have a 'short' - granpos, which can only be detected in the presence of a - preceding page. However, if the last page is also the first - page, the granpos rules of a first page take precedence. Not - only that, but for first==last, the EOS page must be treated - as if its a normal first page for the stream to open/play. */ - if(lastflag && !firstflag) - ogg_stream_packetout(&vf->os,NULL); - else - if(lastblock)accblock+=(lastblock+thisblock)>>2; - } - - if(op.granulepos!=-1){ - int i,link=vf->current_link; - ogg_int64_t granulepos=op.granulepos-vf->pcmlengths[link*2]; - if(granulepos<0)granulepos=0; - - for(i=0;ipcmlengths[i*2+1]; - vf->pcm_offset=granulepos-accblock; - if(vf->pcm_offset<0)vf->pcm_offset=0; - break; - } - lastblock=thisblock; - continue; - }else - ogg_stream_packetout(&vf->os,NULL); - } + /* snarf/scan a packet if we can */ + int result=tremor_ogg_stream_packetout(work_os,&op); + + if(result>0){ + + if(vf->vi.codec_setup){ + thisblock=vorbis_packet_blocksize(&vf->vi,&op); + if(thisblock<0){ + tremor_ogg_stream_packetout(vf->os,NULL); + thisblock=0; + }else{ + + if(eosflag) + tremor_ogg_stream_packetout(vf->os,NULL); + else + if(lastblock)accblock+=(lastblock+thisblock)>>2; + } + + if(op.granulepos!=-1){ + int i,link=vf->current_link; + tremor_ogg_int64_t granulepos=op.granulepos-vf->pcmlengths[link*2]; + if(granulepos<0)granulepos=0; + + for(i=0;ipcmlengths[i*2+1]; + vf->pcm_offset=granulepos-accblock; + break; + } + lastblock=thisblock; + continue; + }else + tremor_ogg_stream_packetout(vf->os,NULL); + } } - + if(!lastblock){ - pagepos=_get_next_page(vf,&og,-1); - if(pagepos<0){ - vf->pcm_offset=ov_pcm_total(vf,-1); - break; - } + if(_get_next_page(vf,&og,-1)<0){ + vf->pcm_offset=ov_pcm_total(vf,-1); + break; + } }else{ - /* huh? Bogus stream with packets but no granulepos */ - vf->pcm_offset=-1; - break; - } - - /* has our decoding just traversed a bitstream boundary? */ - if(vf->ready_state>=STREAMSET){ - if(vf->current_serialno!=ogg_page_serialno(&og)){ - - /* two possibilities: - 1) our decoding just traversed a bitstream boundary - 2) another stream is multiplexed into this logical section? */ - - if(ogg_page_bos(&og)){ - /* we traversed */ - _decode_clear(vf); /* clear out stream state */ - ogg_stream_clear(&work_os); - } /* else, do nothing; next loop will scoop another page */ - } + /* huh? Bogus stream with packets but no granulepos */ + vf->pcm_offset=-1; + break; } + + /* did we just grab a page from other than current link? */ + if(vf->ready_state>=STREAMSET) + if(vf->current_serialno!=tremor_ogg_page_serialno(&og)){ + _decode_clear(vf); /* clear out stream state */ + tremor_ogg_stream_destroy(work_os); + } if(vf->ready_statelinks;link++) - if(vf->serialnos[link]==serialno)break; - - if(link==vf->links) continue; /* not the desired Vorbis - bitstream section; keep - trying */ - vf->current_link=link; - vf->current_serialno=serialno; - ogg_stream_reset_serialno(&vf->os,serialno); - ogg_stream_reset_serialno(&work_os,serialno); - vf->ready_state=STREAMSET; - firstflag=(pagepos<=vf->dataoffsets[link]); + int link; + + vf->current_serialno=tremor_ogg_page_serialno(&og); + for(link=0;linklinks;link++) + if(vf->serialnos[link]==vf->current_serialno)break; + if(link==vf->links) + goto seek_error; /* sign of a bogus stream. error out, + leave machine uninitialized */ + + /* need to initialize machine to this link */ + { + int ret=_set_link_number_preserve_pos(vf,link); + if(ret) goto seek_error; + } + tremor_ogg_stream_reset_serialno(vf->os,vf->current_serialno); + tremor_ogg_stream_reset_serialno(work_os,vf->current_serialno); + + + } + + { + tremor_ogg_page dup; + tremor_ogg_page_dup(&dup,&og); + eosflag=tremor_ogg_page_eos(&og); + tremor_ogg_stream_pagein(vf->os,&og); + tremor_ogg_stream_pagein(work_os,&dup); } - - ogg_stream_pagein(&vf->os,&og); - ogg_stream_pagein(&work_os,&og); - lastflag=ogg_page_eos(&og); - } } - ogg_stream_clear(&work_os); + tremor_ogg_packet_release(&op); + tremor_ogg_page_release(&og); + tremor_ogg_stream_destroy(work_os); vf->bittrack=0; vf->samptrack=0; - return(0); + return 0; seek_error: + tremor_ogg_packet_release(&op); + tremor_ogg_page_release(&og); + /* dump the machine so we're in a known state */ vf->pcm_offset=-1; - ogg_stream_clear(&work_os); + tremor_ogg_stream_destroy(work_os); _decode_clear(vf); return OV_EBADLINK; } -/* rescales the number x from the range of [0,from] to [0,to] - x is in the range [0,from] - from, to are in the range [1, 1<<62-1] */ -ogg_int64_t rescale64(ogg_int64_t x, ogg_int64_t from, ogg_int64_t to){ - ogg_int64_t frac=0; - ogg_int64_t ret=0; - int i; - if(x >= from) return to; - if(x <= 0) return 0; - - for(i=0;i<64;i++){ - if(x>=from){ - frac|=1; - x-=from; - } - x<<=1; - frac<<=1; - } - - for(i=0;i<64;i++){ - if(frac & 1){ - ret+=to; - } - frac>>=1; - ret>>=1; - } - - return ret; -} - /* Page granularity seek (faster than sample granularity because we don't do the last bit of decode to find a specific sample). - Seek to the last [granule marked] page preceding the specified pos + Seek to the last [granule marked] page preceeding the specified pos location, such that decoding past the returned point will quickly arrive at the requested position. */ -int ov_pcm_seek_page(OggVorbis_File *vf,ogg_int64_t pos){ +int ov_pcm_seek_page(TremorOggVorbis_File *vf,tremor_ogg_int64_t pos){ int link=-1; - ogg_int64_t result=0; - ogg_int64_t total=ov_pcm_total(vf,-1); - - if(vf->ready_stateseekable)return(OV_ENOSEEK); - - if(pos<0 || pos>total)return(OV_EINVAL); - + tremor_ogg_int64_t result=0; + tremor_ogg_int64_t total=ov_pcm_total(vf,-1); + tremor_ogg_page og={0,0,0,0}; + tremor_ogg_packet op={0,0,0,0,0,0}; + + if(vf->ready_stateseekable)return OV_ENOSEEK; + if(pos<0 || pos>total)return OV_EINVAL; + /* which bitstream section does this pcm offset occur in? */ for(link=vf->links-1;link>=0;link--){ total-=vf->pcmlengths[link*2+1]; if(pos>=total)break; } - /* Search within the logical bitstream for the page with the highest - pcm_pos preceding pos. If we're looking for a position on the - first page, bisection will halt without finding our position as - it's before the first explicit granulepos fencepost. That case is - handled separately below. - - There is a danger here; missing pages or incorrect frame number - information in the bitstream could make our task impossible. - Account for that (it would be an error condition) */ - /* new search algorithm originally by HB (Nicholas Vinen) */ - - { - ogg_int64_t end=vf->offsets[link+1]; - ogg_int64_t begin=vf->dataoffsets[link]; - ogg_int64_t begintime = vf->pcmlengths[link*2]; - ogg_int64_t endtime = vf->pcmlengths[link*2+1]+begintime; - ogg_int64_t target=pos-total+begintime; - ogg_int64_t best=-1; - int got_page=0; - - ogg_page og; - - /* if we have only one page, there will be no bisection. Grab the page here */ - if(begin==end){ - result=_seek_helper(vf,begin); - if(result) goto seek_error; + if(link!=vf->current_link){ + int ret=_set_link_number(vf,link); + if(ret) goto seek_error; + }else{ + vorbis_dsp_restart(vf->vd); + } - result=_get_next_page(vf,&og,1); - if(result<0) goto seek_error; + tremor_ogg_stream_reset_serialno(vf->os,vf->serialnos[link]); - got_page=1; - } + /* search within the logical bitstream for the page with the highest + pcm_pos preceeding (or equal to) pos. There is a danger here; + missing pages or incorrect frame number information in the + bitstream could make our task impossible. Account for that (it + would be an error condition) */ - /* bisection loop */ + /* new search algorithm by HB (Nicholas Vinen) */ + { + tremor_ogg_int64_t end=vf->offsets[link+1]; + tremor_ogg_int64_t begin=vf->offsets[link]; + tremor_ogg_int64_t begintime = vf->pcmlengths[link*2]; + tremor_ogg_int64_t endtime = vf->pcmlengths[link*2+1]+begintime; + tremor_ogg_int64_t target=pos-total+begintime; + tremor_ogg_int64_t best=begin; + while(beginoffset); - if(result==OV_EREAD) goto seek_error; - if(result<0){ - /* there is no next page! */ - if(bisect<=begin+1) - /* No bisection left to perform. We've either found the - best candidate already or failed. Exit loop. */ - end=begin; - else{ - /* We tried to load a fraction of the last page; back up a - bit and try to get the whole last page */ - if(bisect==0) goto seek_error; - bisect-=CHUNKSIZE; - - /* don't repeat/loop on a read we've already performed */ - if(bisect<=begin)bisect=begin+1; - - /* seek and continue bisection */ - result=_seek_helper(vf,bisect); - if(result) goto seek_error; - } - }else{ - ogg_int64_t granulepos; - got_page=1; - - /* got a page. analyze it */ - /* only consider pages from primary vorbis stream */ - if(ogg_page_serialno(&og)!=vf->serialnos[link]) - continue; - - /* only consider pages with the granulepos set */ - granulepos=ogg_page_granulepos(&og); - if(granulepos==-1)continue; - - if(granuleposoffset; /* raw offset of next page */ - begintime=granulepos; - - /* if we're before our target but within a short distance, - don't bisect; read forward */ - if(target-begintime>44100)break; - - bisect=begin; /* *not* begin + 1 as above */ - }else{ - - /* This is one of our pages, but the granpos is - post-target; it is not a bisection return - candidate. (The only way we'd use it is if it's the - first page in the stream; we handle that case later - outside the bisection) */ - if(bisect<=begin+1){ - /* No bisection left to perform. We've either found the - best candidate already or failed. Exit loop. */ - end=begin; - }else{ - if(end==vf->offset){ - /* bisection read to the end; use the known page - boundary (result) to update bisection, back up a - little bit, and try again */ - end=result; - bisect-=CHUNKSIZE; - if(bisect<=begin)bisect=begin+1; - result=_seek_helper(vf,bisect); - if(result) goto seek_error; - }else{ - /* Normal bisection */ - end=bisect; - endtime=granulepos; - break; - } - } - } - } + result=_get_next_page(vf,&og,end-vf->offset); + if(result==OV_EREAD) goto seek_error; + if(result<0){ + if(bisect<=begin+1) + end=begin; /* found it */ + else{ + if(bisect==0) goto seek_error; + bisect-=CHUNKSIZE; + if(bisect<=begin)bisect=begin+1; + _seek_helper(vf,bisect); + } + }else{ + tremor_ogg_int64_t granulepos=tremor_ogg_page_granulepos(&og); + if(granulepos==-1)continue; + if(granuleposoffset; /* raw offset of next page */ + begintime=granulepos; + + if(target-begintime>44100)break; + bisect=begin; /* *not* begin + 1 */ + }else{ + if(bisect<=begin+1) + end=begin; /* found it */ + else{ + if(end==vf->offset){ /* we're pretty close - we'd be stuck in */ + end=result; + bisect-=CHUNKSIZE; /* an endless loop otherwise. */ + if(bisect<=begin)bisect=begin+1; + _seek_helper(vf,bisect); + }else{ + end=result; + endtime=granulepos; + break; + } + } + } + } } } - /* Out of bisection: did it 'fail?' */ - if(best == -1){ - - /* Check the 'looking for data in first page' special case; - bisection would 'fail' because our search target was before the - first PCM granule position fencepost. */ - - if(got_page && - begin == vf->dataoffsets[link] && - ogg_page_serialno(&og)==vf->serialnos[link]){ - - /* Yes, this is the beginning-of-stream case. We already have - our page, right at the beginning of PCM data. Set state - and return. */ - - vf->pcm_offset=total; - - if(link!=vf->current_link){ - /* Different link; dump entire decode machine */ - _decode_clear(vf); - - vf->current_link=link; - vf->current_serialno=vf->serialnos[link]; - vf->ready_state=STREAMSET; - - }else{ - vorbis_synthesis_restart(&vf->vd); - } - - ogg_stream_reset_serialno(&vf->os,vf->current_serialno); - ogg_stream_pagein(&vf->os,&og); - - }else - goto seek_error; - - }else{ - - /* Bisection found our page. seek to it, update pcm offset. Easier case than - raw_seek, don't keep packets preceding granulepos. */ - - ogg_page og; - ogg_packet op; - + /* found our page. seek to it, update pcm offset. Easier case than + raw_seek, don't keep packets preceeding granulepos. */ + { + /* seek */ - result=_seek_helper(vf,best); + _seek_helper(vf,best); vf->pcm_offset=-1; - if(result) goto seek_error; - result=_get_next_page(vf,&og,-1); - if(result<0) goto seek_error; - - if(link!=vf->current_link){ - /* Different link; dump entire decode machine */ - _decode_clear(vf); - - vf->current_link=link; - vf->current_serialno=vf->serialnos[link]; - vf->ready_state=STREAMSET; - - }else{ - vorbis_synthesis_restart(&vf->vd); + + if(_get_next_page(vf,&og,-1)<0){ + tremor_ogg_page_release(&og); + return OV_EOF; /* shouldn't happen */ } - ogg_stream_reset_serialno(&vf->os,vf->current_serialno); - ogg_stream_pagein(&vf->os,&og); + tremor_ogg_stream_pagein(vf->os,&og); /* pull out all but last packet; the one with granulepos */ while(1){ - result=ogg_stream_packetpeek(&vf->os,&op); - if(result==0){ - /* No packet returned; we exited the bisection with 'best' - pointing to a page with a granule position, so the packet - finishing this page ('best') originated on a preceding - page. Keep fetching previous pages until we get one with - a granulepos or without the 'continued' flag set. Then - just use raw_seek for simplicity. */ - /* Do not rewind past the beginning of link data; if we do, - it's either a bug or a broken stream */ - result=best; - while(result>vf->dataoffsets[link]){ - result=_get_prev_page(vf,result,&og); - if(result<0) goto seek_error; - if(ogg_page_serialno(&og)==vf->current_serialno && - (ogg_page_granulepos(&og)>-1 || - !ogg_page_continued(&og))){ - return ov_raw_seek(vf,result); - } - } - } - if(result<0){ - result = OV_EBADPACKET; - goto seek_error; - } - if(op.granulepos!=-1){ - vf->pcm_offset=op.granulepos-vf->pcmlengths[vf->current_link*2]; - if(vf->pcm_offset<0)vf->pcm_offset=0; - vf->pcm_offset+=total; - break; - }else - result=ogg_stream_packetout(&vf->os,NULL); + result=tremor_ogg_stream_packetpeek(vf->os,&op); + if(result==0){ + /* !!! the packet finishing this page originated on a + preceeding page. Keep fetching previous pages until we + get one with a granulepos or without the 'continued' flag + set. Then just use raw_seek for simplicity. */ + + _seek_helper(vf,best); + + while(1){ + result=_get_prev_page(vf,&og); + if(result<0) goto seek_error; + if(tremor_ogg_page_granulepos(&og)>-1 || + !tremor_ogg_page_continued(&og)){ + return ov_raw_seek(vf,result); + } + vf->offset=result; + } + } + if(result<0){ + result = OV_EBADPACKET; + goto seek_error; + } + if(op.granulepos!=-1){ + vf->pcm_offset=op.granulepos-vf->pcmlengths[vf->current_link*2]; + if(vf->pcm_offset<0)vf->pcm_offset=0; + vf->pcm_offset+=total; + break; + }else + result=tremor_ogg_stream_packetout(vf->os,NULL); } } } - + /* verify result */ if(vf->pcm_offset>pos || pos>ov_pcm_total(vf,-1)){ result=OV_EFAULT; @@ -1645,89 +1284,98 @@ int ov_pcm_seek_page(OggVorbis_File *vf,ogg_int64_t pos){ } vf->bittrack=0; vf->samptrack=0; - return(0); + tremor_ogg_page_release(&og); + tremor_ogg_packet_release(&op); + return 0; + seek_error: + + tremor_ogg_page_release(&og); + tremor_ogg_packet_release(&op); + /* dump machine so we're in a known state */ vf->pcm_offset=-1; _decode_clear(vf); return (int)result; } -/* seek to a sample offset relative to the decompressed pcm stream +/* seek to a sample offset relative to the decompressed pcm stream returns zero on success, nonzero on failure */ -int ov_pcm_seek(OggVorbis_File *vf,ogg_int64_t pos){ +int ov_pcm_seek(TremorOggVorbis_File *vf,tremor_ogg_int64_t pos){ + tremor_ogg_packet op={0,0,0,0,0,0}; + tremor_ogg_page og={0,0,0,0}; int thisblock,lastblock=0; int ret=ov_pcm_seek_page(vf,pos); - if(ret<0)return(ret); - if((ret=_make_decode_ready(vf)))return ret; + if(ret<0)return ret; + if(_make_decode_ready(vf))return OV_EBADLINK; /* discard leading packets we don't need for the lapping of the position we want; don't decode them */ while(1){ - ogg_packet op; - ogg_page og; - int ret=ogg_stream_packetpeek(&vf->os,&op); + int ret=tremor_ogg_stream_packetpeek(vf->os,&op); if(ret>0){ - thisblock=vorbis_packet_blocksize(vf->vi+vf->current_link,&op); + thisblock=vorbis_packet_blocksize(&vf->vi,&op); if(thisblock<0){ - ogg_stream_packetout(&vf->os,NULL); - continue; /* non audio packet */ + tremor_ogg_stream_packetout(vf->os,NULL); + continue; /* non audio packet */ } if(lastblock)vf->pcm_offset+=(lastblock+thisblock)>>2; - + if(vf->pcm_offset+((thisblock+ - vorbis_info_blocksize(vf->vi,1))>>2)>=pos)break; - + vorbis_info_blocksize(&vf->vi,1))>>2)>=pos)break; + /* remove the packet from packet queue and track its granulepos */ - ogg_stream_packetout(&vf->os,NULL); - vorbis_synthesis_trackonly(&vf->vb,&op); /* set up a vb with - only tracking, no - pcm_decode */ - vorbis_synthesis_blockin(&vf->vd,&vf->vb); - + tremor_ogg_stream_packetout(vf->os,NULL); + vorbis_dsp_synthesis(vf->vd,&op,0); /* set up a vb with + only tracking, no + pcm_decode */ + /* end of logical stream case is hard, especially with exact - length positioning. */ - + length positioning. */ + if(op.granulepos>-1){ - int i; - /* always believe the stream markers */ - vf->pcm_offset=op.granulepos-vf->pcmlengths[vf->current_link*2]; - if(vf->pcm_offset<0)vf->pcm_offset=0; - for(i=0;icurrent_link;i++) - vf->pcm_offset+=vf->pcmlengths[i*2+1]; + int i; + /* always believe the stream markers */ + vf->pcm_offset=op.granulepos-vf->pcmlengths[vf->current_link*2]; + if(vf->pcm_offset<0)vf->pcm_offset=0; + for(i=0;icurrent_link;i++) + vf->pcm_offset+=vf->pcmlengths[i*2+1]; } - + lastblock=thisblock; - + }else{ if(ret<0 && ret!=OV_HOLE)break; - + /* suck in a new page */ if(_get_next_page(vf,&og,-1)<0)break; - if(ogg_page_bos(&og))_decode_clear(vf); - + if(vf->current_serialno!=tremor_ogg_page_serialno(&og))_decode_clear(vf); + if(vf->ready_statelinks;link++) - if(vf->serialnos[link]==serialno)break; - if(link==vf->links) continue; - vf->current_link=link; - - vf->ready_state=STREAMSET; - vf->current_serialno=ogg_page_serialno(&og); - ogg_stream_reset_serialno(&vf->os,serialno); - ret=_make_decode_ready(vf); - if(ret)return ret; - lastblock=0; + int link,ret; + + vf->current_serialno=tremor_ogg_page_serialno(&og); + for(link=0;linklinks;link++) + if(vf->serialnos[link]==vf->current_serialno)break; + if(link==vf->links){ + tremor_ogg_page_release(&og); + tremor_ogg_packet_release(&op); + return OV_EBADLINK; + } + + + vf->current_link=link; + ret=_fetch_headers(vf,&vf->vi,&vf->vc,&vf->current_serialno,&og); + if(ret) return ret; + if(_make_decode_ready(vf))return OV_EBADLINK; + lastblock=0; } - ogg_stream_pagein(&vf->os,&og); + tremor_ogg_stream_pagein(vf->os,&og); } } @@ -1736,104 +1384,107 @@ int ov_pcm_seek(OggVorbis_File *vf,ogg_int64_t pos){ /* discard samples until we reach the desired position. Crossing a logical bitstream boundary with abandon is OK. */ while(vf->pcm_offsetpcm_offset; - long samples=vorbis_synthesis_pcmout(&vf->vd,NULL); + tremor_ogg_int64_t target=pos-vf->pcm_offset; + long samples=vorbis_dsp_pcmout(vf->vd,NULL,0); if(samples>target)samples=target; - vorbis_synthesis_read(&vf->vd,samples); + vorbis_dsp_read(vf->vd,samples); vf->pcm_offset+=samples; - + if(samplespcm_offset=ov_pcm_total(vf,-1); /* eof */ + if(_fetch_and_process_packet(vf,1,1)<=0) + vf->pcm_offset=ov_pcm_total(vf,-1); /* eof */ } + + tremor_ogg_page_release(&og); + tremor_ogg_packet_release(&op); return 0; } -/* seek to a playback time relative to the decompressed pcm stream +/* seek to a playback time relative to the decompressed pcm stream returns zero on success, nonzero on failure */ -int ov_time_seek(OggVorbis_File *vf,ogg_int64_t milliseconds){ +int ov_time_seek(TremorOggVorbis_File *vf,tremor_ogg_int64_t milliseconds){ /* translate time to PCM position and call ov_pcm_seek */ int link=-1; - ogg_int64_t pcm_total=0; - ogg_int64_t time_total=0; - - if(vf->ready_stateseekable)return(OV_ENOSEEK); - if(milliseconds<0)return(OV_EINVAL); + tremor_ogg_int64_t pcm_total=ov_pcm_total(vf,-1); + tremor_ogg_int64_t time_total=ov_time_total(vf,-1); + if(vf->ready_stateseekable)return OV_ENOSEEK; + if(milliseconds<0 || milliseconds>time_total)return OV_EINVAL; + /* which bitstream section does this time offset occur in? */ - for(link=0;linklinks;link++){ - ogg_int64_t addsec = ov_time_total(vf,link); - if(millisecondspcmlengths[link*2+1]; + for(link=vf->links-1;link>=0;link--){ + pcm_total-=vf->pcmlengths[link*2+1]; + time_total-=ov_time_total(vf,link); + if(milliseconds>=time_total)break; } - if(link==vf->links)return(OV_EINVAL); - /* enough information to convert time offset to pcm offset */ { - ogg_int64_t target=pcm_total+(milliseconds-time_total)*vf->vi[link].rate/1000; - return(ov_pcm_seek(vf,target)); + int ret=_set_link_number(vf,link); + if(ret)return ret; + return + ov_pcm_seek(vf,pcm_total+(milliseconds-time_total)* + vf->vi.rate/1000); } } /* page-granularity version of ov_time_seek returns zero on success, nonzero on failure */ -int ov_time_seek_page(OggVorbis_File *vf,ogg_int64_t milliseconds){ +int ov_time_seek_page(TremorOggVorbis_File *vf,tremor_ogg_int64_t milliseconds){ /* translate time to PCM position and call ov_pcm_seek */ int link=-1; - ogg_int64_t pcm_total=0; - ogg_int64_t time_total=0; - - if(vf->ready_stateseekable)return(OV_ENOSEEK); - if(milliseconds<0)return(OV_EINVAL); + tremor_ogg_int64_t pcm_total=ov_pcm_total(vf,-1); + tremor_ogg_int64_t time_total=ov_time_total(vf,-1); + if(vf->ready_stateseekable)return OV_ENOSEEK; + if(milliseconds<0 || milliseconds>time_total)return OV_EINVAL; + /* which bitstream section does this time offset occur in? */ - for(link=0;linklinks;link++){ - ogg_int64_t addsec = ov_time_total(vf,link); - if(millisecondspcmlengths[link*2+1]; + for(link=vf->links-1;link>=0;link--){ + pcm_total-=vf->pcmlengths[link*2+1]; + time_total-=ov_time_total(vf,link); + if(milliseconds>=time_total)break; } - if(link==vf->links)return(OV_EINVAL); - /* enough information to convert time offset to pcm offset */ { - ogg_int64_t target=pcm_total+(milliseconds-time_total)*vf->vi[link].rate/1000; - return(ov_pcm_seek_page(vf,target)); + int ret=_set_link_number(vf,link); + if(ret)return ret; + return + ov_pcm_seek_page(vf,pcm_total+(milliseconds-time_total)* + vf->vi.rate/1000); } } /* tell the current stream offset cursor. Note that seek followed by tell will likely not give the set offset due to caching */ -ogg_int64_t ov_raw_tell(OggVorbis_File *vf){ - if(vf->ready_stateoffset); +tremor_ogg_int64_t ov_raw_tell(TremorOggVorbis_File *vf){ + if(vf->ready_stateoffset; } /* return PCM offset (sample) of next PCM sample to be read */ -ogg_int64_t ov_pcm_tell(OggVorbis_File *vf){ - if(vf->ready_statepcm_offset); +tremor_ogg_int64_t ov_pcm_tell(TremorOggVorbis_File *vf){ + if(vf->ready_statepcm_offset; } /* return time offset (milliseconds) of next PCM sample to be read */ -ogg_int64_t ov_time_tell(OggVorbis_File *vf){ +tremor_ogg_int64_t ov_time_tell(TremorOggVorbis_File *vf){ int link=0; - ogg_int64_t pcm_total=0; - ogg_int64_t time_total=0; - - if(vf->ready_stateready_stateseekable){ pcm_total=ov_pcm_total(vf,-1); time_total=ov_time_total(vf,-1); - + /* which bitstream section does this time offset occur in? */ for(link=vf->links-1;link>=0;link--){ pcm_total-=vf->pcmlengths[link*2+1]; @@ -1842,50 +1493,38 @@ ogg_int64_t ov_time_tell(OggVorbis_File *vf){ } } - return(time_total+(1000*vf->pcm_offset-pcm_total)/vf->vi[link].rate); + return time_total+(1000*vf->pcm_offset-pcm_total)/vf->vi.rate; } /* link: -1) return the vorbis_info struct for the bitstream section currently being decoded 0-n) to request information for a specific bitstream section - + In the case of a non-seekable bitstream, any call returns the current bitstream. NULL in the case that the machine is not initialized */ -vorbis_info *ov_info(OggVorbis_File *vf,int link){ +vorbis_info *ov_info(TremorOggVorbis_File *vf,int link){ if(vf->seekable){ - if(link<0) - if(vf->ready_state>=STREAMSET) - return vf->vi+vf->current_link; - else - return vf->vi; - else - if(link>=vf->links) - return NULL; - else - return vf->vi+link; - }else{ - return vf->vi; + if(link>=vf->links)return NULL; + if(link>=0){ + int ret=_set_link_number_preserve_pos(vf,link); + if(ret)return NULL; + } } + return &vf->vi; } /* grr, strong typing, grr, no templates/inheritence, grr */ -vorbis_comment *ov_comment(OggVorbis_File *vf,int link){ +vorbis_comment *ov_comment(TremorOggVorbis_File *vf,int link){ if(vf->seekable){ - if(link<0) - if(vf->ready_state>=STREAMSET) - return vf->vc+vf->current_link; - else - return vf->vc; - else - if(link>=vf->links) - return NULL; - else - return vf->vc+link; - }else{ - return vf->vc; + if(link>=vf->links)return NULL; + if(link>=0){ + int ret=_set_link_number_preserve_pos(vf,link); + if(ret)return NULL; + } } + return &vf->vc; } /* up to this point, everything could more or less hide the multiple @@ -1904,65 +1543,47 @@ vorbis_comment *ov_comment(OggVorbis_File *vf,int link){ functions above are aware of this dichotomy). input values: buffer) a buffer to hold packed PCM data for return - bytes_req) the byte length requested to be placed into buffer + length) the byte length requested to be placed into buffer return values: <0) error/hole in data (OV_HOLE), partial open (OV_EINVAL) 0) EOF - n) number of bytes of PCM actually returned. The - below works on a packet-by-packet basis, so the - return length is not related to the 'length' passed - in, just guaranteed to fit. + n) number of bytes of PCM actually returned. The + below works on a packet-by-packet basis, so the + return length is not related to the 'length' passed + in, just guaranteed to fit. - *section) set to the logical bitstream number */ + *section) set to the logical bitstream number */ -long ov_read(OggVorbis_File *vf,char *buffer,int bytes_req,int *bitstream){ - int i,j; +long ov_read(TremorOggVorbis_File *vf,void *buffer,int bytes_req,int *bitstream){ - ogg_int32_t **pcm; long samples; + long channels; - if(vf->ready_stateready_stateready_state==INITSET){ - samples=vorbis_synthesis_pcmout(&vf->vd,&pcm); - if(samples)break; + channels=vf->vi.channels; + samples=vorbis_dsp_pcmout(vf->vd,buffer,(bytes_req>>1)/channels); + if(samples){ + if(samples>0){ + vorbis_dsp_read(vf->vd,samples); + vf->pcm_offset+=samples; + if(bitstream)*bitstream=vf->current_link; + return samples*2*channels; + } + return samples; + } } /* suck in another packet */ { - int ret=_fetch_and_process_packet(vf,NULL,1,1); + int ret=_fetch_and_process_packet(vf,1,1); if(ret==OV_EOF) - return(0); + return 0; if(ret<=0) - return(ret); + return ret; } } - - if(samples>0){ - - /* yay! proceed to pack data into the byte buffer */ - - long channels=ov_info(vf,-1)->channels; - - if(samples>(bytes_req/(2*channels))) - samples=bytes_req/(2*channels); - - for(i=0;i>9); - dest+=channels; - } - } - - vorbis_synthesis_read(&vf->vd,samples); - vf->pcm_offset+=samples; - if(bitstream)*bitstream=vf->current_link; - return(samples*2*channels); - }else{ - return(samples); - } } diff --git a/lib/tremor/vorbisidec.pc.in b/lib/tremor/vorbisidec.pc.in index 56fa6567..9c095242 100644 --- a/lib/tremor/vorbisidec.pc.in +++ b/lib/tremor/vorbisidec.pc.in @@ -8,7 +8,7 @@ includedir=@includedir@ Name: vorbisidec Description: vorbisidec is the integer Ogg Vorbis library Version: @VERSION@ -Requires.private: ogg +Requires: ogg Conflicts: -Libs: -L${libdir} -lvorbisidec +Libs: -L${libdir} -lvorbisidec -lm Cflags: -I${includedir} diff --git a/lib/tremor/win32/VS2005/libogg.vsprops b/lib/tremor/win32/VS2005/libogg.vsprops deleted file mode 100644 index dca12081..00000000 --- a/lib/tremor/win32/VS2005/libogg.vsprops +++ /dev/null @@ -1,19 +0,0 @@ - - - - - - diff --git a/lib/tremor/win32/VS2005/libtremor/libtremor.vcproj b/lib/tremor/win32/VS2005/libtremor/libtremor.vcproj deleted file mode 100644 index c18654f6..00000000 --- a/lib/tremor/win32/VS2005/libtremor/libtremor.vcproj +++ /dev/null @@ -1,865 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/lib/tremor/win32/VS2008/libogg.vsprops b/lib/tremor/win32/VS2008/libogg.vsprops deleted file mode 100644 index 807b74a6..00000000 --- a/lib/tremor/win32/VS2008/libogg.vsprops +++ /dev/null @@ -1,19 +0,0 @@ - - - - - - diff --git a/lib/tremor/win32/VS2008/libtremor/libtremor.vcproj b/lib/tremor/win32/VS2008/libtremor/libtremor.vcproj deleted file mode 100644 index 7edb39b9..00000000 --- a/lib/tremor/win32/VS2008/libtremor/libtremor.vcproj +++ /dev/null @@ -1,865 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/lib/tremor/window.c b/lib/tremor/window.c deleted file mode 100644 index 006a1ee6..00000000 --- a/lib/tremor/window.c +++ /dev/null @@ -1,83 +0,0 @@ -/******************************************************************** - * * - * THIS FILE IS PART OF THE OggVorbis 'TREMOR' CODEC SOURCE CODE. * - * * - * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS * - * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE * - * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. * - * * - * THE OggVorbis 'TREMOR' SOURCE CODE IS (C) COPYRIGHT 1994-2002 * - * BY THE Xiph.Org FOUNDATION http://www.xiph.org/ * - * * - ******************************************************************** - - function: window functions - - ********************************************************************/ - -#include -#include -#include "misc.h" -#include "window.h" -#include "window_lookup.h" - -const void *_vorbis_window(int type, int left){ - - switch(type){ - case 0: - - switch(left){ - case 32: - return vwin64; - case 64: - return vwin128; - case 128: - return vwin256; - case 256: - return vwin512; - case 512: - return vwin1024; - case 1024: - return vwin2048; - case 2048: - return vwin4096; - case 4096: - return vwin8192; - default: - return(0); - } - break; - default: - return(0); - } -} - -void _vorbis_apply_window(ogg_int32_t *d,const void *window_p[2], - long *blocksizes, - int lW,int W,int nW){ - - LOOKUP_T *window[2]={window_p[0],window_p[1]}; - long n=blocksizes[W]; - long ln=blocksizes[lW]; - long rn=blocksizes[nW]; - - long leftbegin=n/4-ln/4; - long leftend=leftbegin+ln/2; - - long rightbegin=n/2+n/4-rn/4; - long rightend=rightbegin+rn/2; - - int i,p; - - for(i=0;i +#include "os_types.h" -static const LOOKUP_T vwin64[32] = { +static LOOKUP_T vwin64[32] = { X(0x001f0003), X(0x01168c98), X(0x030333c8), X(0x05dfe3a4), X(0x09a49562), X(0x0e45df18), X(0x13b47ef2), X(0x19dcf676), X(0x20a74d83), X(0x27f7137c), X(0x2fabb05a), X(0x37a1105a), @@ -29,7 +29,7 @@ static const LOOKUP_T vwin64[32] = { X(0x7fdd78a5), X(0x7ff6ec6d), X(0x7ffed0e9), X(0x7ffffc3f), }; -static const LOOKUP_T vwin128[64] = { +static LOOKUP_T vwin128[64] = { X(0x0007c04d), X(0x0045bb89), X(0x00c18b87), X(0x017ae294), X(0x02714a4e), X(0x03a4217a), X(0x05129952), X(0x06bbb24f), X(0x089e38a1), X(0x0ab8c073), X(0x0d09a228), X(0x0f8ef6bd), @@ -48,7 +48,7 @@ static const LOOKUP_T vwin128[64] = { X(0x7ffdcf39), X(0x7fff6dac), X(0x7fffed01), X(0x7fffffc4), }; -static const LOOKUP_T vwin256[128] = { +static LOOKUP_T vwin256[128] = { X(0x0001f018), X(0x00117066), X(0x00306e9e), X(0x005ee5f1), X(0x009ccf26), X(0x00ea208b), X(0x0146cdea), X(0x01b2c87f), X(0x022dfedf), X(0x02b85ced), X(0x0351cbbd), X(0x03fa317f), @@ -83,7 +83,7 @@ static const LOOKUP_T vwin256[128] = { X(0x7fffdcd2), X(0x7ffff6d6), X(0x7ffffed0), X(0x7ffffffc), }; -static const LOOKUP_T vwin512[256] = { +static LOOKUP_T vwin512[256] = { X(0x00007c06), X(0x00045c32), X(0x000c1c62), X(0x0017bc4c), X(0x00273b7a), X(0x003a9955), X(0x0051d51c), X(0x006cede7), X(0x008be2a9), X(0x00aeb22a), X(0x00d55b0d), X(0x00ffdbcc), @@ -150,7 +150,7 @@ static const LOOKUP_T vwin512[256] = { X(0x7ffffdcd), X(0x7fffff6d), X(0x7fffffed), X(0x7fffffff), }; -static const LOOKUP_T vwin1024[512] = { +static LOOKUP_T vwin1024[512] = { X(0x00001f02), X(0x0001170e), X(0x00030724), X(0x0005ef40), X(0x0009cf59), X(0x000ea767), X(0x0014775e), X(0x001b3f2e), X(0x0022fec8), X(0x002bb618), X(0x00356508), X(0x00400b81), @@ -281,7 +281,7 @@ static const LOOKUP_T vwin1024[512] = { X(0x7fffffdd), X(0x7ffffff7), X(0x7fffffff), X(0x7fffffff), }; -static const LOOKUP_T vwin2048[1024] = { +static LOOKUP_T vwin2048[1024] = { X(0x000007c0), X(0x000045c4), X(0x0000c1ca), X(0x00017bd3), X(0x000273de), X(0x0003a9eb), X(0x00051df9), X(0x0006d007), X(0x0008c014), X(0x000aee1e), X(0x000d5a25), X(0x00100428), @@ -540,7 +540,7 @@ static const LOOKUP_T vwin2048[1024] = { X(0x7ffffffe), X(0x7fffffff), X(0x7fffffff), X(0x7fffffff), }; -static const LOOKUP_T vwin4096[2048] = { +static LOOKUP_T vwin4096[2048] = { X(0x000001f0), X(0x00001171), X(0x00003072), X(0x00005ef5), X(0x00009cf8), X(0x0000ea7c), X(0x00014780), X(0x0001b405), X(0x0002300b), X(0x0002bb91), X(0x00035698), X(0x0004011e), @@ -1055,7 +1055,9 @@ static const LOOKUP_T vwin4096[2048] = { X(0x7fffffff), X(0x7fffffff), X(0x7fffffff), X(0x7fffffff), }; -static const LOOKUP_T vwin8192[4096] = { +#ifndef LIMIT_TO_64kHz + +static LOOKUP_T vwin8192[4096] = { X(0x0000007c), X(0x0000045c), X(0x00000c1d), X(0x000017bd), X(0x0000273e), X(0x00003a9f), X(0x000051e0), X(0x00006d02), X(0x00008c03), X(0x0000aee5), X(0x0000d5a7), X(0x00010049), @@ -2082,3 +2084,4 @@ static const LOOKUP_T vwin8192[4096] = { X(0x7fffffff), X(0x7fffffff), X(0x7fffffff), X(0x7fffffff), }; +#endif diff --git a/src/codecs/include/vorbis.hpp b/src/codecs/include/vorbis.hpp index 673b67a0..b96a0407 100644 --- a/src/codecs/include/vorbis.hpp +++ b/src/codecs/include/vorbis.hpp @@ -14,8 +14,6 @@ #include #include "ivorbisfile.h" -#include "ogg/ogg.h" -#include "opus.h" #include "sample.hpp" #include "span.hpp" @@ -41,7 +39,7 @@ class TremorVorbisDecoder : public ICodec { private: std::shared_ptr input_; - std::unique_ptr vorbis_; + std::unique_ptr vorbis_; }; } // namespace codecs diff --git a/src/codecs/vorbis.cpp b/src/codecs/vorbis.cpp index c373ebf5..7fb53f1b 100644 --- a/src/codecs/vorbis.cpp +++ b/src/codecs/vorbis.cpp @@ -4,31 +4,20 @@ * SPDX-License-Identifier: GPL-3.0-only */ -#include "ivorbiscodec.h" -#include "ivorbisfile.h" -#include "ogg/config_types.h" -#include "opus.hpp" - -#include -#include +#include "vorbis.hpp" #include #include #include #include "esp_heap_caps.h" -#include "mad.h" +#include "esp_log.h" +#include "ivorbiscodec.h" +#include "ivorbisfile.h" #include "codec.hpp" -#include "esp_log.h" -#include "ogg/ogg.h" -#include "opus.h" -#include "opus_defines.h" -#include "opus_types.h" -#include "result.hpp" #include "sample.hpp" #include "types.hpp" -#include "vorbis.hpp" namespace codecs { @@ -39,7 +28,7 @@ static size_t read_cb(void* ptr, size_t size, size_t nmemb, void* instance) { return source->Read({reinterpret_cast(ptr), size * nmemb}); } -static int seek_cb(void* instance, ogg_int64_t offset, int whence) { +static int seek_cb(void* instance, tremor_ogg_int64_t offset, int whence) { IStream* source = reinterpret_cast(instance); if (!source->CanSeek()) { return -1; @@ -80,8 +69,8 @@ static const ov_callbacks kCallbacks{ TremorVorbisDecoder::TremorVorbisDecoder() : input_(), - vorbis_(reinterpret_cast( - heap_caps_malloc(sizeof(OggVorbis_File), + vorbis_(reinterpret_cast( + heap_caps_malloc(sizeof(TremorOggVorbis_File), MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT))) {} TremorVorbisDecoder::~TremorVorbisDecoder() { From 66f68aac0dc1cd7b0f2e133071d7f5c01a4edf8e Mon Sep 17 00:00:00 2001 From: jacqueline Date: Wed, 14 Feb 2024 12:23:26 +1100 Subject: [PATCH 4/9] version bump --- tools/cmake/common.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/cmake/common.cmake b/tools/cmake/common.cmake index 2665c67b..b97d2e85 100644 --- a/tools/cmake/common.cmake +++ b/tools/cmake/common.cmake @@ -5,7 +5,7 @@ # For more information about build system see # https://docs.espressif.com/projects/esp-idf/en/latest/api-guides/build-system.html -set(PROJECT_VER "0.5.0") +set(PROJECT_VER "0.5.1") # esp-idf sets the C++ standard weird. Set cmake vars to match. set(CMAKE_CXX_STANDARD 23) From f772ab9f206b7356019f529cb4a98d5023962970 Mon Sep 17 00:00:00 2001 From: jacqueline Date: Wed, 14 Feb 2024 13:28:05 +1100 Subject: [PATCH 5/9] put the big opus alloc back into spiram it's not clear to me that it helps *that* much, since the ogg allocs are in internal ram anyway, and the memory pressure is just a bit much --- lib/opusfile/include/custom_support.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/opusfile/include/custom_support.h b/lib/opusfile/include/custom_support.h index d99cc5e2..a5748989 100644 --- a/lib/opusfile/include/custom_support.h +++ b/lib/opusfile/include/custom_support.h @@ -8,7 +8,7 @@ static OPUS_INLINE void *opus_alloc (size_t size) { - return heap_caps_malloc(size, MALLOC_CAP_8BIT | MALLOC_CAP_INTERNAL); + return heap_caps_malloc(size, MALLOC_CAP_SPIRAM); } static OPUS_INLINE void opus_free (void *ptr) From 4bc77f901b1597b7cbc9ab7f4e0e354a7c93ed43 Mon Sep 17 00:00:00 2001 From: jacqueline Date: Wed, 14 Feb 2024 16:56:49 +1100 Subject: [PATCH 6/9] Tweak opus build flags and allocs This gets us to ~40% of one core cpu usage during playback. Good enough for a while I reckon! Paid for the internal ram usage by reclaiming some stack size headroom. --- lib/opusfile/CMakeLists.txt | 6 ++++++ lib/opusfile/include/custom_support.h | 10 ++++------ src/dev_console/include/console.hpp | 2 +- src/tasks/tasks.cpp | 12 +++++------- 4 files changed, 16 insertions(+), 14 deletions(-) diff --git a/lib/opusfile/CMakeLists.txt b/lib/opusfile/CMakeLists.txt index f9b5e4ce..fe958b67 100644 --- a/lib/opusfile/CMakeLists.txt +++ b/lib/opusfile/CMakeLists.txt @@ -11,6 +11,11 @@ set(CMAKE_POLICY_DEFAULT_CMP0077 NEW) set(OPUS_FIXED_POINT ON) set(OPUS_ENABLE_FLOAT_API OFF) + +set(OPUS_VAR_ARRAYS OFF) +set(OPUS_USE_ALLOCA ON) +set(OPUS_NONTHREADSAFE_PSEUDOSTACK OFF) + set(OPUS_INSTALL_PKG_CONFIG_MODULE OFF) set(OPUS_INSTALL_CMAKE_CONFIG_MODULE OFF) set(OPUS_BUILD_TESTING OFF) @@ -18,5 +23,6 @@ set(OPUS_BUILD_SHARED_LIBS OFF) add_subdirectory($ENV{PROJ_PATH}/lib/opus ${CMAKE_CURRENT_BINARY_DIR}/opus) target_compile_definitions(opus PRIVATE CUSTOM_SUPPORT) +target_compile_options(opus PRIVATE -Os -DSMALL_FOOTPRINT -funroll-loops -ffast-math) target_include_directories(opus PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/include) target_link_libraries(${COMPONENT_LIB} PUBLIC opus) diff --git a/lib/opusfile/include/custom_support.h b/lib/opusfile/include/custom_support.h index a5748989..60cab623 100644 --- a/lib/opusfile/include/custom_support.h +++ b/lib/opusfile/include/custom_support.h @@ -6,12 +6,10 @@ #define OVERRIDE_OPUS_ALLOC #define OVERRIDE_OPUS_FREE -static OPUS_INLINE void *opus_alloc (size_t size) -{ - return heap_caps_malloc(size, MALLOC_CAP_SPIRAM); +static OPUS_INLINE void* opus_alloc(size_t size) { + return heap_caps_malloc(size, MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT); } -static OPUS_INLINE void opus_free (void *ptr) -{ - heap_caps_free(ptr); +static OPUS_INLINE void opus_free(void* ptr) { + heap_caps_free(ptr); } diff --git a/src/dev_console/include/console.hpp b/src/dev_console/include/console.hpp index fd4050c2..fedf3632 100644 --- a/src/dev_console/include/console.hpp +++ b/src/dev_console/include/console.hpp @@ -18,7 +18,7 @@ class Console { auto Launch() -> void; protected: - virtual auto GetStackSizeKiB() -> uint16_t { return 16; } + virtual auto GetStackSizeKiB() -> uint16_t { return 8; } virtual auto RegisterExtraComponents() -> void {} private: diff --git a/src/tasks/tasks.cpp b/src/tasks/tasks.cpp index d53eface..aa382655 100644 --- a/src/tasks/tasks.cpp +++ b/src/tasks/tasks.cpp @@ -39,22 +39,20 @@ auto AllocateStack() -> cpp::span; // usually written with embedded use cases in mind. template <> auto AllocateStack() -> cpp::span { - constexpr std::size_t size = 24 * 1024; + constexpr std::size_t size = 20 * 1024; static StackType_t sStack[size]; return {sStack, size}; } -// LVGL requires only a relatively small stack. However, it can be allocated in -// PSRAM so we give it a bit of headroom for safety. +// LVGL requires only a relatively small stack. Lua's stack is allocated +// separately. template <> auto AllocateStack() -> cpp::span { - constexpr std::size_t size = 16 * 1024; + constexpr std::size_t size = 14 * 1024; static StackType_t sStack[size]; return {sStack, size}; } template <> -// PCM conversion and resampling uses a very small amount of stack. It works -// entirely with PSRAM-allocated buffers, so no real speed gain from allocating -// it internally. +// PCM conversion and resampling uses a very small amount of stack. auto AllocateStack() -> cpp::span { constexpr std::size_t size = 4 * 1024; static StackType_t sStack[size]; From 10770e0f5445bd39e5778a104fafd1788f9f62d7 Mon Sep 17 00:00:00 2001 From: jacqueline Date: Wed, 14 Feb 2024 17:47:46 +1100 Subject: [PATCH 7/9] Use -Ofast for all codecs that don't break with it --- lib/libmad/CMakeLists.txt | 1 + lib/miniflac/CMakeLists.txt | 1 + lib/tremor/CMakeLists.txt | 2 +- 3 files changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/libmad/CMakeLists.txt b/lib/libmad/CMakeLists.txt index a5e19394..e56cabaf 100644 --- a/lib/libmad/CMakeLists.txt +++ b/lib/libmad/CMakeLists.txt @@ -41,5 +41,6 @@ target_compile_options(${COMPONENT_LIB} $<$:-Wno-implicit-function-declaration> $<$:-Wno-stringop-overflow> $<$:-fPIC> + -Ofast ) diff --git a/lib/miniflac/CMakeLists.txt b/lib/miniflac/CMakeLists.txt index 68df4ca5..7ea6940f 100644 --- a/lib/miniflac/CMakeLists.txt +++ b/lib/miniflac/CMakeLists.txt @@ -2,3 +2,4 @@ # # SPDX-License-Identifier: GPL-3.0-only idf_component_register(SRCS miniflac.c INCLUDE_DIRS .) +target_compile_options("${COMPONENT_LIB}" PRIVATE -Ofast) diff --git a/lib/tremor/CMakeLists.txt b/lib/tremor/CMakeLists.txt index e44f9084..530c0493 100644 --- a/lib/tremor/CMakeLists.txt +++ b/lib/tremor/CMakeLists.txt @@ -5,4 +5,4 @@ idf_component_register( SRCS bitwise.c codebook.c dsp.c floor0.c floor1.c floor_lookup.c framing.c info.c mapping0.c mdct.c misc.c res012.c vorbisfile.c INCLUDE_DIRS ".") -target_compile_options("${COMPONENT_LIB}" PRIVATE -Wno-error=misleading-indentation -Wno-error=maybe-uninitialized -Wno-error=char-subscripts -Wno-error=unused-label) +target_compile_options("${COMPONENT_LIB}" PRIVATE -Ofast -Wno-error=misleading-indentation -Wno-error=maybe-uninitialized -Wno-error=char-subscripts -Wno-error=unused-label) From c5917658e6a0fcc77971237c80bb4e47f3e8bf9e Mon Sep 17 00:00:00 2001 From: jacqueline Date: Wed, 14 Feb 2024 17:48:13 +1100 Subject: [PATCH 8/9] Cram one of the flac samples buffers into internal ram Can't quite fit the second... yet. Just one is a pretty reasonable speedup, though! Probably bc we're not hammering the spiram cache so hard. --- src/codecs/miniflac.cpp | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/codecs/miniflac.cpp b/src/codecs/miniflac.cpp index ace73466..74eafb3b 100644 --- a/src/codecs/miniflac.cpp +++ b/src/codecs/miniflac.cpp @@ -30,9 +30,16 @@ MiniFlacDecoder::MiniFlacDecoder() current_sample_() { miniflac_init(flac_.get(), MINIFLAC_CONTAINER_UNKNOWN); for (int i = 0; i < samples_by_channel_.size(); i++) { - // Full decoded frames too big to fit in internal ram :( + uint32_t caps; + if (i == 0) { + caps = MALLOC_CAP_8BIT | MALLOC_CAP_INTERNAL; + } else { + // FIXME: We can *almost* fit two channels into internal ram, but we're a + // few KiB shy of being able to do it safely. + caps = MALLOC_CAP_SPIRAM; + } samples_by_channel_[i] = reinterpret_cast( - heap_caps_malloc(kMaxFrameSize * sizeof(int32_t), MALLOC_CAP_SPIRAM)); + heap_caps_malloc(kMaxFrameSize * sizeof(int32_t), caps)); } } From 4509ab8d6e341f7f7d92ac6e9d63ad822fe3441b Mon Sep 17 00:00:00 2001 From: jacqueline Date: Thu, 15 Feb 2024 09:38:02 +1100 Subject: [PATCH 9/9] version bump --- tools/cmake/common.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/cmake/common.cmake b/tools/cmake/common.cmake index b97d2e85..ca269b27 100644 --- a/tools/cmake/common.cmake +++ b/tools/cmake/common.cmake @@ -5,7 +5,7 @@ # For more information about build system see # https://docs.espressif.com/projects/esp-idf/en/latest/api-guides/build-system.html -set(PROJECT_VER "0.5.1") +set(PROJECT_VER "0.5.2") # esp-idf sets the C++ standard weird. Set cmake vars to match. set(CMAKE_CXX_STANDARD 23)