From 7ca7fb1777609bdc32685d9ecb3451108bc0e51b Mon Sep 17 00:00:00 2001 From: Leonardo Invernizzi Date: Sat, 27 Jul 2024 23:47:20 +0000 Subject: [PATCH 01/26] create PR From 6038d896d41c81b0294f7a71a68be5bf28737fbe Mon Sep 17 00:00:00 2001 From: Leonardo Invernizzi Date: Sun, 28 Jul 2024 14:36:42 +0000 Subject: [PATCH 02/26] Added libvirbis as a 3rd party dependency --- 3rdparty/SConscript | 16 ++++++++++++++++ SConstruct | 10 ++++++++++ scripts/scons_helpers/build-3rdparty.py | 20 ++++++++++++++++++++ 3 files changed, 46 insertions(+) diff --git a/3rdparty/SConscript b/3rdparty/SConscript index dd5338989..8fa093847 100644 --- a/3rdparty/SConscript +++ b/3rdparty/SConscript @@ -20,6 +20,7 @@ thirdparty_versions = { 'libatomic_ops': '7.6.10', 'libunwind': '1.2.1', 'libuv': '1.35.0', + 'libvorbis': '1.3.7', 'ltdl': '2.4.6', 'openfec': '1.4.2.11', 'openssl': '3.0.8', @@ -431,6 +432,21 @@ elif 'google-benchmark' in system_dependencies: subenvs.tests = conf.Finish() +# dep: libvorbis +if 'libvorbis' in autobuild_dependencies: + env.BuildThirdParty(thirdparty_versions, 'libvorbis') + +elif 'libvorbis' in system_dependencies: + conf = Configure(env, custom_tests=env.CustomTests) + + if not conf.AddPkgConfigDependency('vorbis', '--cflags --libs'): + conf.env.AddManualDependency(libs=['vorbis']) + + if not conf.CheckLibWithHeader('vorbis', 'vorbis/vorbisenc.h', 'C'): + env.Die("libvorbis not found (see 'config.log' for details)") + + env = conf.Finish() + # end of deps return_value = (env, subenvs) diff --git a/SConstruct b/SConstruct index 3bb2d1369..d83162585 100644 --- a/SConstruct +++ b/SConstruct @@ -209,6 +209,11 @@ AddOption('--disable-sox', action='store_true', help='disable SoX support in tools') +AddOption('--disable-libvorbis', + dest='disable_libvorbis', + action='store_true', + help='disable libvorbis support') + AddOption('--disable-sndfile', dest='disable_sndfile', action='store_true', @@ -819,6 +824,11 @@ else: 'target_libuv', ]) + if not GetOption('disable_libvorbis'): + env.Append(ROC_TARGETS=[ + 'target_libvorbis', + ]) + if not GetOption('disable_openfec'): env.Append(ROC_TARGETS=[ 'target_openfec', diff --git a/scripts/scons_helpers/build-3rdparty.py b/scripts/scons_helpers/build-3rdparty.py index bec792135..5b65b55e4 100644 --- a/scripts/scons_helpers/build-3rdparty.py +++ b/scripts/scons_helpers/build-3rdparty.py @@ -1438,6 +1438,26 @@ def die(text, *args): install_files(ctx, 'builddir/src/pulse/libpulse-simple.so.0', ctx.pkg_rpath_dir) install_files(ctx, 'builddir/src/libpulsecommon-*.so', ctx.pkg_lib_dir) install_files(ctx, 'builddir/src/libpulsecommon-*.so', ctx.pkg_rpath_dir) +elif ctx.pkg_name == 'libvorbis': + download( + ctx, + 'https://downloads.xiph.org/releases/vorbis/libvorbis-{ctx.pkg_ver}.tar.gz', + 'libvorbis-{ctx.pkg_ver}.tar.gz') + unpack(ctx, + 'libvorbis-{ctx.pkg_ver}.tar.gz', + 'libvorbis-{ctx.pkg_ver}') + changedir(ctx, 'src/libvorbis-{ctx.pkg_ver}') + execute(ctx, './configure --host={host} {vars} {flags} {opts}'.format( + host=ctx.toolchain, + vars=format_vars(ctx), + flags=format_flags(ctx, cflags='-fPIC'), + opts=' '.join([ + '--disable-shared', + '--enable-static', + ]))) + execute_make(ctx) + install_tree(ctx, 'include', ctx.pkg_inc_dir, include=['*.h']) + install_files(ctx, 'lib/.libs/libvorbis.a', ctx.pkg_lib_dir) elif ctx.pkg_name == 'ltdl': download( ctx, From 8a2c53834381a56ab11c460af3b3be0798277e1a Mon Sep 17 00:00:00 2001 From: Leonardo Invernizzi Date: Sun, 28 Jul 2024 15:58:06 +0100 Subject: [PATCH 03/26] Fix --- SConstruct | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/SConstruct b/SConstruct index d83162585..fe27be50d 100644 --- a/SConstruct +++ b/SConstruct @@ -212,7 +212,7 @@ AddOption('--disable-sox', AddOption('--disable-libvorbis', dest='disable_libvorbis', action='store_true', - help='disable libvorbis support') + help='disable libvorbis support in tools') AddOption('--disable-sndfile', dest='disable_sndfile', @@ -824,11 +824,6 @@ else: 'target_libuv', ]) - if not GetOption('disable_libvorbis'): - env.Append(ROC_TARGETS=[ - 'target_libvorbis', - ]) - if not GetOption('disable_openfec'): env.Append(ROC_TARGETS=[ 'target_openfec', @@ -865,6 +860,10 @@ else: env.Append(ROC_TARGETS=[ 'target_pulseaudio', ]) + if not GetOption('disable_libvorbis'): + env.Append(ROC_TARGETS=[ + 'target_libvorbis', + ]) if 'target_gnu' not in env['ROC_TARGETS']: env.Append(ROC_TARGETS=[ From a8e3466da976a648daac747b245a3c4ee55b1d89 Mon Sep 17 00:00:00 2001 From: Leonardo Invernizzi Date: Sun, 28 Jul 2024 16:40:00 +0100 Subject: [PATCH 04/26] Fix --- 3rdparty/SConscript | 34 +++++++++++++++++++--------------- 1 file changed, 19 insertions(+), 15 deletions(-) diff --git a/3rdparty/SConscript b/3rdparty/SConscript index 8fa093847..7be0d1c0b 100644 --- a/3rdparty/SConscript +++ b/3rdparty/SConscript @@ -255,6 +255,25 @@ elif 'sndfile' in system_dependencies: env = conf.Finish() +# dep: libvorbis +if 'libvorbis' in autobuild_dependencies: + env.BuildThirdParty(thirdparty_versions, 'libvorbis') + + conf = Configure(env, custom_tests=env.CustomTests) + + env = conf.Finish() + +elif 'libvorbis' in system_dependencies: + conf = Configure(env, custom_tests=env.CustomTests) + + if not conf.AddPkgConfigDependency('vorbis', '--cflags --libs', exclude_from_pc=True): + conf.env.AddManualDependency(libs=['vorbis'], exclude_from_pc=True) + + if not conf.CheckLibWithHeaderExt('vorbis', 'vorbis/vorbisenc.h', 'C', run=False): + env.Die("libvorbis not found (see 'config.log' for details)") + + env = conf.Finish() + # dep: alsa if 'alsa' in autobuild_dependencies: env.BuildThirdParty(thirdparty_versions, 'alsa') @@ -432,21 +451,6 @@ elif 'google-benchmark' in system_dependencies: subenvs.tests = conf.Finish() -# dep: libvorbis -if 'libvorbis' in autobuild_dependencies: - env.BuildThirdParty(thirdparty_versions, 'libvorbis') - -elif 'libvorbis' in system_dependencies: - conf = Configure(env, custom_tests=env.CustomTests) - - if not conf.AddPkgConfigDependency('vorbis', '--cflags --libs'): - conf.env.AddManualDependency(libs=['vorbis']) - - if not conf.CheckLibWithHeader('vorbis', 'vorbis/vorbisenc.h', 'C'): - env.Die("libvorbis not found (see 'config.log' for details)") - - env = conf.Finish() - # end of deps return_value = (env, subenvs) From 8b0045a33d3777deacad50b3110d569fd20e532c Mon Sep 17 00:00:00 2001 From: Leonardo Invernizzi Date: Sun, 28 Jul 2024 17:24:01 +0100 Subject: [PATCH 05/26] Added libogg dependency --- 3rdparty/SConscript | 23 +++++++++++++++++++++++ SConstruct | 3 +++ scripts/scons_helpers/build-3rdparty.py | 20 ++++++++++++++++++++ 3 files changed, 46 insertions(+) diff --git a/3rdparty/SConscript b/3rdparty/SConscript index 7be0d1c0b..f1938c528 100644 --- a/3rdparty/SConscript +++ b/3rdparty/SConscript @@ -18,6 +18,7 @@ thirdparty_versions = { 'alsa': '1.1.9', 'json-c': '0.12-20140410', 'libatomic_ops': '7.6.10', + 'libogg': '1.3.4', 'libunwind': '1.2.1', 'libuv': '1.35.0', 'libvorbis': '1.3.7', @@ -49,6 +50,9 @@ external_dependencies.add('ragel') if 'pulseaudio' in external_dependencies: external_dependencies.add('sndfile') +if 'libvorbis' in external_dependencies: + external_dependencies.add('libogg') + # on Linux, PulseAudio needs ALSA if meta.platform in ['linux'] and 'pulseaudio' in external_dependencies: external_dependencies.add('alsa') @@ -255,6 +259,25 @@ elif 'sndfile' in system_dependencies: env = conf.Finish() +# dep: libogg +if 'libogg' in autobuild_dependencies: + env.BuildThirdParty(thirdparty_versions, 'libogg') + + conf = Configure(env, custom_tests=env.CustomTests) + + env = conf.Finish() + +elif 'libogg' in system_dependencies: + conf = Configure(subenvs.libs, custom_tests=env.CustomTests) + + if not conf.AddPkgConfigDependency('ogg', '--cflags --libs', exclude_from_pc=True): + conf.env.AddManualDependency(libs=['ogg'], exclude_from_pc=True) + + if not conf.CheckLibWithHeader('ogg', 'ogg/ogg.h', 'C', run=False): + env.Die("libogg not found (see 'config.log' for details)") + + env = conf.Finish() + # dep: libvorbis if 'libvorbis' in autobuild_dependencies: env.BuildThirdParty(thirdparty_versions, 'libvorbis') diff --git a/SConstruct b/SConstruct index fe27be50d..9579c9fe2 100644 --- a/SConstruct +++ b/SConstruct @@ -861,6 +861,9 @@ else: 'target_pulseaudio', ]) if not GetOption('disable_libvorbis'): + env.Append(ROC_TARGETS=[ + 'target_libogg', + ]) env.Append(ROC_TARGETS=[ 'target_libvorbis', ]) diff --git a/scripts/scons_helpers/build-3rdparty.py b/scripts/scons_helpers/build-3rdparty.py index 5b65b55e4..5d31e1718 100644 --- a/scripts/scons_helpers/build-3rdparty.py +++ b/scripts/scons_helpers/build-3rdparty.py @@ -1438,6 +1438,26 @@ def die(text, *args): install_files(ctx, 'builddir/src/pulse/libpulse-simple.so.0', ctx.pkg_rpath_dir) install_files(ctx, 'builddir/src/libpulsecommon-*.so', ctx.pkg_lib_dir) install_files(ctx, 'builddir/src/libpulsecommon-*.so', ctx.pkg_rpath_dir) +elif ctx.pkg_name == 'libogg': + download( + ctx, + 'https://downloads.xiph.org/releases/ogg/libogg-{ctx.pkg_ver}.tar.gz', + 'libogg-{ctx.pkg_ver}.tar.gz') + unpack(ctx, + 'libogg-{ctx.pkg_ver}.tar.gz', + 'libogg-{ctx.pkg_ver}') + changedir(ctx, 'src/libogg-{ctx.pkg_ver}') + execute(ctx, './configure --host={host} {vars} {flags} {opts}'.format( + host=ctx.toolchain, + vars=format_vars(ctx), + flags=format_flags(ctx, cflags='-fPIC'), + opts=' '.join([ + '--disable-shared', + '--enable-static', + ]))) + execute_make(ctx) + install_tree(ctx, 'include', ctx.pkg_inc_dir, include=['*.h']) + install_files(ctx, 'src/.libs/libogg.a', ctx.pkg_lib_dir) elif ctx.pkg_name == 'libvorbis': download( ctx, From 28a2fa425e6e65b6a1b99f769c8b23100b7d80f6 Mon Sep 17 00:00:00 2001 From: Leonardo Invernizzi Date: Sun, 28 Jul 2024 17:29:30 +0100 Subject: [PATCH 06/26] FIx --- 3rdparty/SConscript | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/3rdparty/SConscript b/3rdparty/SConscript index f1938c528..8c98c6f00 100644 --- a/3rdparty/SConscript +++ b/3rdparty/SConscript @@ -268,7 +268,7 @@ if 'libogg' in autobuild_dependencies: env = conf.Finish() elif 'libogg' in system_dependencies: - conf = Configure(subenvs.libs, custom_tests=env.CustomTests) + conf = Configure(env, custom_tests=env.CustomTests) if not conf.AddPkgConfigDependency('ogg', '--cflags --libs', exclude_from_pc=True): conf.env.AddManualDependency(libs=['ogg'], exclude_from_pc=True) From 8ae177e92c72f52131a4e21f72ef9528e9368a5a Mon Sep 17 00:00:00 2001 From: Leonardo Invernizzi Date: Sun, 28 Jul 2024 17:35:22 +0100 Subject: [PATCH 07/26] Fix --- 3rdparty/SConscript | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/3rdparty/SConscript b/3rdparty/SConscript index 8c98c6f00..d09764aac 100644 --- a/3rdparty/SConscript +++ b/3rdparty/SConscript @@ -273,7 +273,7 @@ elif 'libogg' in system_dependencies: if not conf.AddPkgConfigDependency('ogg', '--cflags --libs', exclude_from_pc=True): conf.env.AddManualDependency(libs=['ogg'], exclude_from_pc=True) - if not conf.CheckLibWithHeader('ogg', 'ogg/ogg.h', 'C', run=False): + if not conf.CheckLibWithHeaderExt('ogg', 'ogg/ogg.h', 'C', run=False): env.Die("libogg not found (see 'config.log' for details)") env = conf.Finish() From 6b67c37d0ac02886af73616fc4696232a285983d Mon Sep 17 00:00:00 2001 From: Leonardo Invernizzi Date: Tue, 30 Jul 2024 00:36:02 +0100 Subject: [PATCH 08/26] Fix LibOgg --- scripts/scons_helpers/build-3rdparty.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/scripts/scons_helpers/build-3rdparty.py b/scripts/scons_helpers/build-3rdparty.py index 5d31e1718..4f4fdaab1 100644 --- a/scripts/scons_helpers/build-3rdparty.py +++ b/scripts/scons_helpers/build-3rdparty.py @@ -1456,8 +1456,10 @@ def die(text, *args): '--enable-static', ]))) execute_make(ctx) + execute(ctx, 'make install') install_tree(ctx, 'include', ctx.pkg_inc_dir, include=['*.h']) install_files(ctx, 'src/.libs/libogg.a', ctx.pkg_lib_dir) + install_files(ctx, 'ogg.pc', ctx.pkg_rpath_dir) elif ctx.pkg_name == 'libvorbis': download( ctx, From 0523a1e3e60c8e551f978e704f0056d473ee5751 Mon Sep 17 00:00:00 2001 From: Leonardo Invernizzi Date: Thu, 1 Aug 2024 03:18:39 +0100 Subject: [PATCH 09/26] Create VorbisEncoder --- .../roc_audio/vorbis_encoder.cpp | 74 +++++++++++++++++++ .../roc_audio/vorbis_encoder.h | 41 ++++++++++ 2 files changed, 115 insertions(+) create mode 100644 src/internal_modules/roc_audio/vorbis_encoder.cpp create mode 100644 src/internal_modules/roc_audio/vorbis_encoder.h diff --git a/src/internal_modules/roc_audio/vorbis_encoder.cpp b/src/internal_modules/roc_audio/vorbis_encoder.cpp new file mode 100644 index 000000000..643e69288 --- /dev/null +++ b/src/internal_modules/roc_audio/vorbis_encoder.cpp @@ -0,0 +1,74 @@ +#include "roc_audio/vorbis_encoder.h" +#include "roc_core/panic.h" + +namespace roc { +namespace audio { + +VorbisEncoder::VorbisEncoder(const SampleSpec& sample_spec) + : sample_spec_(sample_spec) + , initialized_(false) + , frame_data_(NULL) + , frame_size_(0) { + vorbis_info_init(&vorbis_info_); + const int num_channels = static_cast(sample_spec_.num_channels()); + const int sample_rate = static_cast(sample_spec_.sample_rate()); + int ret = vorbis_encode_init_vbr(&vorbis_info_, num_channels, sample_rate, 0.0f); + if (ret != 0) { + roc_panic("vorbis encoder: failed to initialize vorbis encoder"); + } + vorbis_comment_init(&vorbis_comment_); + vorbis_comment_add_tag(&vorbis_comment_, "ENCODER", "roc_audio VorbisEncoder"); + + ret = vorbis_analysis_init(&vorbis_dsp_, &vorbis_info_); + if (ret != 0) { + roc_panic("vorbis encoder: failed to initialize vorbis dsp"); + } + + ret = vorbis_block_init(&vorbis_dsp_, &vorbis_block_); + if (ret != 0) { + roc_panic("vorbis encoder: failed to initialize vorbis block"); + } + + ogg_stream_init(&ogg_stream_, 0); + initialized_ = true; +} + +VorbisEncoder::~VorbisEncoder() { + if (initialized_) { + ogg_stream_clear(&ogg_stream_); + vorbis_block_clear(&vorbis_block_); + vorbis_dsp_clear(&vorbis_dsp_); + vorbis_comment_clear(&vorbis_comment_); + vorbis_info_clear(&vorbis_info_); + } +} + +status::StatusCode VorbisEncoder::init_status() const { + return initialized_ ? status::StatusOK : status::StatusNoMem; +} + +size_t VorbisEncoder::encoded_byte_count(size_t n_samples) const { + roc_panic("TODO"); + return 0; +} + +void VorbisEncoder::begin_frame(void* frame_data, size_t frame_size) { + roc_panic_if_not(frame_data); + if (frame_data_) { + roc_panic("vorbis encoder: unpaired begin/end"); + } + frame_data_ = frame_data; + frame_size_ = frame_size; +} + +size_t VorbisEncoder::write_samples(const sample_t* samples, size_t n_samples) { + roc_panic("TODO"); + return 0; +} + +void VorbisEncoder::end_frame() { + roc_panic("TODO"); +} + +} // namespace audio +} // namespace roc diff --git a/src/internal_modules/roc_audio/vorbis_encoder.h b/src/internal_modules/roc_audio/vorbis_encoder.h new file mode 100644 index 000000000..538017a34 --- /dev/null +++ b/src/internal_modules/roc_audio/vorbis_encoder.h @@ -0,0 +1,41 @@ +#ifndef ROC_AUDIO_VORBIS_ENCODER_H_ +#define ROC_AUDIO_VORBIS_ENCODER_H_ + +#include "roc_audio/iframe_encoder.h" +#include "roc_audio/sample_spec.h" +#include + +namespace roc { +namespace audio { + +class VorbisEncoder : public IFrameEncoder { +public: + VorbisEncoder(const SampleSpec& sample_spec); + ~VorbisEncoder(); + + virtual status::StatusCode init_status() const; + + virtual size_t encoded_byte_count(size_t n_samples) const; + + virtual void begin_frame(void* frame_data, size_t frame_size); + + virtual size_t write_samples(const sample_t* samples, size_t n_samples); + + virtual void end_frame(); + +private: + SampleSpec sample_spec_; + bool initialized_; + void* frame_data_; + size_t frame_size_; + ogg_stream_state ogg_stream_; + vorbis_info vorbis_info_; + vorbis_comment vorbis_comment_; + vorbis_dsp_state vorbis_dsp_; + vorbis_block vorbis_block_; +}; + +} // namespace audio +} // namespace roc + +#endif // ROC_AUDIO_VORBIS_ENCODER_H_ From 73c7da5aa89d3ae03e139d713c9ae6c3c20f67b8 Mon Sep 17 00:00:00 2001 From: Leonardo Invernizzi Date: Sun, 4 Aug 2024 02:31:16 +0000 Subject: [PATCH 10/26] Add libogg as dependency of libvorbis --- 3rdparty/SConscript | 10 ++++++---- scripts/scons_helpers/build-3rdparty.py | 1 - src/internal_modules/roc_audio/vorbis_encoder.cpp | 8 ++++++++ src/internal_modules/roc_audio/vorbis_encoder.h | 11 +++++++++++ 4 files changed, 25 insertions(+), 5 deletions(-) diff --git a/3rdparty/SConscript b/3rdparty/SConscript index d09764aac..3bc3c5994 100644 --- a/3rdparty/SConscript +++ b/3rdparty/SConscript @@ -280,11 +280,13 @@ elif 'libogg' in system_dependencies: # dep: libvorbis if 'libvorbis' in autobuild_dependencies: - env.BuildThirdParty(thirdparty_versions, 'libvorbis') - - conf = Configure(env, custom_tests=env.CustomTests) + pa_deps = [ + 'libogg', + ] - env = conf.Finish() + env.BuildThirdParty(thirdparty_versions, 'libogg') + env.BuildThirdParty(thirdparty_versions, 'libvorbis', + deps=pa_deps) elif 'libvorbis' in system_dependencies: conf = Configure(env, custom_tests=env.CustomTests) diff --git a/scripts/scons_helpers/build-3rdparty.py b/scripts/scons_helpers/build-3rdparty.py index 4f4fdaab1..52e6ea77a 100644 --- a/scripts/scons_helpers/build-3rdparty.py +++ b/scripts/scons_helpers/build-3rdparty.py @@ -1456,7 +1456,6 @@ def die(text, *args): '--enable-static', ]))) execute_make(ctx) - execute(ctx, 'make install') install_tree(ctx, 'include', ctx.pkg_inc_dir, include=['*.h']) install_files(ctx, 'src/.libs/libogg.a', ctx.pkg_lib_dir) install_files(ctx, 'ogg.pc', ctx.pkg_rpath_dir) diff --git a/src/internal_modules/roc_audio/vorbis_encoder.cpp b/src/internal_modules/roc_audio/vorbis_encoder.cpp index 643e69288..5c083df3b 100644 --- a/src/internal_modules/roc_audio/vorbis_encoder.cpp +++ b/src/internal_modules/roc_audio/vorbis_encoder.cpp @@ -1,3 +1,11 @@ +/* + * Copyright (c) 2024 Roc Streaming authors + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + #include "roc_audio/vorbis_encoder.h" #include "roc_core/panic.h" diff --git a/src/internal_modules/roc_audio/vorbis_encoder.h b/src/internal_modules/roc_audio/vorbis_encoder.h index 538017a34..332238ed9 100644 --- a/src/internal_modules/roc_audio/vorbis_encoder.h +++ b/src/internal_modules/roc_audio/vorbis_encoder.h @@ -1,3 +1,14 @@ +/* + * Copyright (c) 2024 Roc Streaming authors + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +//! @file roc_audio/vorbis_encoder.h +//! @brief TODO. + #ifndef ROC_AUDIO_VORBIS_ENCODER_H_ #define ROC_AUDIO_VORBIS_ENCODER_H_ From 7ccfe615d15e95c8a658476af4b5dba55db04af2 Mon Sep 17 00:00:00 2001 From: Leonardo Invernizzi Date: Sun, 4 Aug 2024 02:58:28 +0000 Subject: [PATCH 11/26] Added doxygen documentation to Vorbis Encoder --- src/internal_modules/roc_audio/vorbis_encoder.h | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/src/internal_modules/roc_audio/vorbis_encoder.h b/src/internal_modules/roc_audio/vorbis_encoder.h index 332238ed9..1af713528 100644 --- a/src/internal_modules/roc_audio/vorbis_encoder.h +++ b/src/internal_modules/roc_audio/vorbis_encoder.h @@ -19,19 +19,28 @@ namespace roc { namespace audio { +//! Vorbis Encoder. class VorbisEncoder : public IFrameEncoder { public: + //! Initialize. VorbisEncoder(const SampleSpec& sample_spec); + + //! End. ~VorbisEncoder(); + //! Check if the object was successfully constructed. virtual status::StatusCode init_status() const; - virtual size_t encoded_byte_count(size_t n_samples) const; + //! Get encoded frame size in bytes for given number of samples per channel. + virtual size_t encoded_byte_count(size_t num_samples) const; - virtual void begin_frame(void* frame_data, size_t frame_size); + //! Start encoding a new frame. + virtual void begin_frame(void* frame, size_t frame_size); + //! Encode samples. virtual size_t write_samples(const sample_t* samples, size_t n_samples); + //! Finish encoding frame. virtual void end_frame(); private: From 2c7a38a96fc8bf1f5aac19a0c3ac6f111493baf6 Mon Sep 17 00:00:00 2001 From: Leonardo Invernizzi Date: Sun, 4 Aug 2024 05:18:42 +0100 Subject: [PATCH 12/26] Fixed disable libvorbis --- SConstruct | 3 --- .../{ => target_libvorbis/roc_audio}/vorbis_encoder.cpp | 0 .../{ => target_libvorbis/roc_audio}/vorbis_encoder.h | 0 3 files changed, 3 deletions(-) rename src/internal_modules/roc_audio/{ => target_libvorbis/roc_audio}/vorbis_encoder.cpp (100%) rename src/internal_modules/roc_audio/{ => target_libvorbis/roc_audio}/vorbis_encoder.h (100%) diff --git a/SConstruct b/SConstruct index 9579c9fe2..fe27be50d 100644 --- a/SConstruct +++ b/SConstruct @@ -861,9 +861,6 @@ else: 'target_pulseaudio', ]) if not GetOption('disable_libvorbis'): - env.Append(ROC_TARGETS=[ - 'target_libogg', - ]) env.Append(ROC_TARGETS=[ 'target_libvorbis', ]) diff --git a/src/internal_modules/roc_audio/vorbis_encoder.cpp b/src/internal_modules/roc_audio/target_libvorbis/roc_audio/vorbis_encoder.cpp similarity index 100% rename from src/internal_modules/roc_audio/vorbis_encoder.cpp rename to src/internal_modules/roc_audio/target_libvorbis/roc_audio/vorbis_encoder.cpp diff --git a/src/internal_modules/roc_audio/vorbis_encoder.h b/src/internal_modules/roc_audio/target_libvorbis/roc_audio/vorbis_encoder.h similarity index 100% rename from src/internal_modules/roc_audio/vorbis_encoder.h rename to src/internal_modules/roc_audio/target_libvorbis/roc_audio/vorbis_encoder.h From 98475ef3f14470baaa1d07b7cdad04bcd3b43202 Mon Sep 17 00:00:00 2001 From: Leonardo Invernizzi Date: Thu, 8 Aug 2024 17:45:13 +0000 Subject: [PATCH 13/26] Added vorbisenc and vorbisfile libraries --- 3rdparty/SConscript | 17 +---------------- scripts/scons_helpers/build-3rdparty.py | 2 ++ 2 files changed, 3 insertions(+), 16 deletions(-) diff --git a/3rdparty/SConscript b/3rdparty/SConscript index 3bc3c5994..bf39a8ccc 100644 --- a/3rdparty/SConscript +++ b/3rdparty/SConscript @@ -263,21 +263,6 @@ elif 'sndfile' in system_dependencies: if 'libogg' in autobuild_dependencies: env.BuildThirdParty(thirdparty_versions, 'libogg') - conf = Configure(env, custom_tests=env.CustomTests) - - env = conf.Finish() - -elif 'libogg' in system_dependencies: - conf = Configure(env, custom_tests=env.CustomTests) - - if not conf.AddPkgConfigDependency('ogg', '--cflags --libs', exclude_from_pc=True): - conf.env.AddManualDependency(libs=['ogg'], exclude_from_pc=True) - - if not conf.CheckLibWithHeaderExt('ogg', 'ogg/ogg.h', 'C', run=False): - env.Die("libogg not found (see 'config.log' for details)") - - env = conf.Finish() - # dep: libvorbis if 'libvorbis' in autobuild_dependencies: pa_deps = [ @@ -292,7 +277,7 @@ elif 'libvorbis' in system_dependencies: conf = Configure(env, custom_tests=env.CustomTests) if not conf.AddPkgConfigDependency('vorbis', '--cflags --libs', exclude_from_pc=True): - conf.env.AddManualDependency(libs=['vorbis'], exclude_from_pc=True) + conf.env.AddManualDependency(libs=['vorbis', 'vorbisenc', 'vorbisfile'], exclude_from_pc=True) if not conf.CheckLibWithHeaderExt('vorbis', 'vorbis/vorbisenc.h', 'C', run=False): env.Die("libvorbis not found (see 'config.log' for details)") diff --git a/scripts/scons_helpers/build-3rdparty.py b/scripts/scons_helpers/build-3rdparty.py index 52e6ea77a..5451d8ed5 100644 --- a/scripts/scons_helpers/build-3rdparty.py +++ b/scripts/scons_helpers/build-3rdparty.py @@ -1479,6 +1479,8 @@ def die(text, *args): execute_make(ctx) install_tree(ctx, 'include', ctx.pkg_inc_dir, include=['*.h']) install_files(ctx, 'lib/.libs/libvorbis.a', ctx.pkg_lib_dir) + install_files(ctx, 'lib/.libs/libvorbisenc.a', ctx.pkg_lib_dir) + install_files(ctx, 'lib/.libs/libvorbisfile.a', ctx.pkg_lib_dir) elif ctx.pkg_name == 'ltdl': download( ctx, From e483080e0c45bcd440f3d95fab8cfb526a9fc497 Mon Sep 17 00:00:00 2001 From: Leonardo Invernizzi Date: Thu, 8 Aug 2024 18:13:01 +0000 Subject: [PATCH 14/26] Fix opensuse --- scripts/ci_checks/linux-x86_64/opensuse.sh | 2 +- .../roc_audio/target_libvorbis/roc_audio/vorbis_encoder.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/ci_checks/linux-x86_64/opensuse.sh b/scripts/ci_checks/linux-x86_64/opensuse.sh index aa17878e0..2222819fc 100755 --- a/scripts/ci_checks/linux-x86_64/opensuse.sh +++ b/scripts/ci_checks/linux-x86_64/opensuse.sh @@ -7,5 +7,5 @@ scons -Q \ --enable-tests \ --enable-benchmarks \ --enable-examples \ - --build-3rdparty=openfec,cpputest \ + --build-3rdparty=openfec,cpputest,libvorbis \ test diff --git a/src/internal_modules/roc_audio/target_libvorbis/roc_audio/vorbis_encoder.h b/src/internal_modules/roc_audio/target_libvorbis/roc_audio/vorbis_encoder.h index 1af713528..09b9e2ba1 100644 --- a/src/internal_modules/roc_audio/target_libvorbis/roc_audio/vorbis_encoder.h +++ b/src/internal_modules/roc_audio/target_libvorbis/roc_audio/vorbis_encoder.h @@ -6,7 +6,7 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -//! @file roc_audio/vorbis_encoder.h +//! @file roc_audio/target_libvorbis/roc_audio/vorbis_encoder.h //! @brief TODO. #ifndef ROC_AUDIO_VORBIS_ENCODER_H_ From 1d82d0183c4a9985d452bee00e31a26e5677d317 Mon Sep 17 00:00:00 2001 From: Leonardo Invernizzi Date: Fri, 9 Aug 2024 01:48:52 +0000 Subject: [PATCH 15/26] Created vorbis decoder file --- .../roc_audio/vorbis_decoder.cpp | 65 +++++++++++++++++++ .../roc_audio/vorbis_decoder.h | 63 ++++++++++++++++++ .../roc_audio/vorbis_encoder.h | 2 +- 3 files changed, 129 insertions(+), 1 deletion(-) create mode 100644 src/internal_modules/roc_audio/target_libvorbis/roc_audio/vorbis_decoder.cpp create mode 100644 src/internal_modules/roc_audio/target_libvorbis/roc_audio/vorbis_decoder.h diff --git a/src/internal_modules/roc_audio/target_libvorbis/roc_audio/vorbis_decoder.cpp b/src/internal_modules/roc_audio/target_libvorbis/roc_audio/vorbis_decoder.cpp new file mode 100644 index 000000000..6e964f924 --- /dev/null +++ b/src/internal_modules/roc_audio/target_libvorbis/roc_audio/vorbis_decoder.cpp @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2024 Roc Streaming authors + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#include "roc_audio/vorbis_decoder.h" +#include "roc_core/panic.h" + +namespace roc { +namespace audio { + +VorbisDecoder::VorbisDecoder(const SampleSpec& sample_spec) { + // TODO +} + +VorbisDecoder::~VorbisDecoder() { + // TODO +} + +status::StatusCode VorbisDecoder::init_status() const { + return status::StatusOK; +} + +packet::stream_timestamp_t VorbisDecoder::position() const { + roc_panic("TODO"); + return 0; +} + +packet::stream_timestamp_t VorbisDecoder::available() const { + roc_panic("TODO"); + return 0; +} + +size_t VorbisDecoder::decoded_sample_count(const void* frame_data, + size_t frame_size) const { + roc_panic("TODO"); + return 0; +} + +void VorbisDecoder::begin_frame(packet::stream_timestamp_t frame_position, + const void* frame_data, + size_t frame_size) { + roc_panic_if_not(frame_data); + roc_panic("TODO"); +} + +size_t VorbisDecoder::read_samples(sample_t* samples, size_t n_samples) { + roc_panic("TODO"); + return 0; +} + +size_t VorbisDecoder::drop_samples(size_t n_samples) { + roc_panic("TODO"); + return 0; +} + +void VorbisDecoder::end_frame() { + roc_panic("TODO"); +} + +} // namespace audio +} // namespace roc diff --git a/src/internal_modules/roc_audio/target_libvorbis/roc_audio/vorbis_decoder.h b/src/internal_modules/roc_audio/target_libvorbis/roc_audio/vorbis_decoder.h new file mode 100644 index 000000000..3f0101830 --- /dev/null +++ b/src/internal_modules/roc_audio/target_libvorbis/roc_audio/vorbis_decoder.h @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2024 Roc Streaming authors + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +//! @file roc_audio/target_libvorbis/roc_audio/vorbis_decoder.h +//! @brief Vorbis audio decoder. + +#ifndef ROC_AUDIO_VORBIS_DECODER_H_ +#define ROC_AUDIO_VORBIS_DECODER_H_ + +#include "roc_audio/iframe_decoder.h" +#include "roc_audio/sample_spec.h" +#include + +namespace roc { +namespace audio { + +//! Vorbis Decoder. +class VorbisDecoder : public IFrameDecoder { +public: + //! Initialize. + VorbisDecoder(const SampleSpec& sample_spec); + + //! End. + ~VorbisDecoder(); + + //! Check if the object was successfully constructed. + virtual status::StatusCode init_status() const; + + //! Get decoded stream position. + virtual packet::stream_timestamp_t position() const; + + //! Get number of samples available for decoding. + virtual packet::stream_timestamp_t available() const; + + //! Get number of samples per channel that can be decoded from given frame. + virtual size_t decoded_sample_count(const void* frame_data, size_t frame_size) const; + + //! Start decoding a new frame. + virtual void begin_frame(packet::stream_timestamp_t frame_position, + const void* frame_data, + size_t frame_size); + + //! Read samples from current frame. + virtual size_t read_samples(sample_t* samples, size_t n_samples); + + //! Shift samples from current frame. + virtual size_t drop_samples(size_t n_samples); + + //! Finish decoding current frame. + virtual void end_frame(); + +private: +}; + +} // namespace audio +} // namespace roc + +#endif // ROC_AUDIO_VORBIS_DECODER_H_ diff --git a/src/internal_modules/roc_audio/target_libvorbis/roc_audio/vorbis_encoder.h b/src/internal_modules/roc_audio/target_libvorbis/roc_audio/vorbis_encoder.h index 09b9e2ba1..921467520 100644 --- a/src/internal_modules/roc_audio/target_libvorbis/roc_audio/vorbis_encoder.h +++ b/src/internal_modules/roc_audio/target_libvorbis/roc_audio/vorbis_encoder.h @@ -7,7 +7,7 @@ */ //! @file roc_audio/target_libvorbis/roc_audio/vorbis_encoder.h -//! @brief TODO. +//! @brief Vorbis audio decoder. #ifndef ROC_AUDIO_VORBIS_ENCODER_H_ #define ROC_AUDIO_VORBIS_ENCODER_H_ From b4a293242d68fcc34c6c6c49611e61b1b1d3b986 Mon Sep 17 00:00:00 2001 From: Leonardo Invernizzi Date: Fri, 9 Aug 2024 01:53:25 +0000 Subject: [PATCH 16/26] ogg.pc in lib dir --- scripts/scons_helpers/build-3rdparty.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/scons_helpers/build-3rdparty.py b/scripts/scons_helpers/build-3rdparty.py index 5451d8ed5..476c14711 100644 --- a/scripts/scons_helpers/build-3rdparty.py +++ b/scripts/scons_helpers/build-3rdparty.py @@ -1458,7 +1458,7 @@ def die(text, *args): execute_make(ctx) install_tree(ctx, 'include', ctx.pkg_inc_dir, include=['*.h']) install_files(ctx, 'src/.libs/libogg.a', ctx.pkg_lib_dir) - install_files(ctx, 'ogg.pc', ctx.pkg_rpath_dir) + install_files(ctx, 'ogg.pc', ctx.pkg_lib_dir) elif ctx.pkg_name == 'libvorbis': download( ctx, From 8f9fa0367c0de13b9a62cae0d00580b85eae99b3 Mon Sep 17 00:00:00 2001 From: Leonardo Invernizzi Date: Mon, 12 Aug 2024 01:55:33 +0000 Subject: [PATCH 17/26] Implemented VorbisEncoder::encoded_byte_count --- .../roc_audio/vorbis_encoder.cpp | 32 +++++++++++++------ .../roc_audio/vorbis_encoder.h | 1 - 2 files changed, 23 insertions(+), 10 deletions(-) diff --git a/src/internal_modules/roc_audio/target_libvorbis/roc_audio/vorbis_encoder.cpp b/src/internal_modules/roc_audio/target_libvorbis/roc_audio/vorbis_encoder.cpp index 5c083df3b..b9eb200ef 100644 --- a/src/internal_modules/roc_audio/target_libvorbis/roc_audio/vorbis_encoder.cpp +++ b/src/internal_modules/roc_audio/target_libvorbis/roc_audio/vorbis_encoder.cpp @@ -13,19 +13,18 @@ namespace roc { namespace audio { VorbisEncoder::VorbisEncoder(const SampleSpec& sample_spec) - : sample_spec_(sample_spec) - , initialized_(false) + : initialized_(false) , frame_data_(NULL) , frame_size_(0) { vorbis_info_init(&vorbis_info_); - const int num_channels = static_cast(sample_spec_.num_channels()); - const int sample_rate = static_cast(sample_spec_.sample_rate()); + + const int num_channels = static_cast(sample_spec.num_channels()); + const int sample_rate = static_cast(sample_spec.sample_rate()); int ret = vorbis_encode_init_vbr(&vorbis_info_, num_channels, sample_rate, 0.0f); if (ret != 0) { roc_panic("vorbis encoder: failed to initialize vorbis encoder"); } vorbis_comment_init(&vorbis_comment_); - vorbis_comment_add_tag(&vorbis_comment_, "ENCODER", "roc_audio VorbisEncoder"); ret = vorbis_analysis_init(&vorbis_dsp_, &vorbis_info_); if (ret != 0) { @@ -52,12 +51,27 @@ VorbisEncoder::~VorbisEncoder() { } status::StatusCode VorbisEncoder::init_status() const { - return initialized_ ? status::StatusOK : status::StatusNoMem; + return initialized_ ? status::StatusOK : status::StatusAbort; } -size_t VorbisEncoder::encoded_byte_count(size_t n_samples) const { - roc_panic("TODO"); - return 0; +size_t VorbisEncoder::encoded_byte_count(size_t num_samples) const { + if (!initialized_) { + return 0; + } + + if (vorbis_info_.rate <= 0 || vorbis_info_.channels <= 0 + || vorbis_info_.bitrate_nominal <= 0) { + roc_panic("vorbis encoder: vorbis_info structure has invalid values"); + return 0; + } + + // Average number of bits used per sample, per channel. + const size_t bit_width = static_cast( + (vorbis_info_.bitrate_nominal / vorbis_info_.rate) / vorbis_info_.channels); + + const size_t encoded_bytes = (num_samples * bit_width + 7) / 8; + + return encoded_bytes; } void VorbisEncoder::begin_frame(void* frame_data, size_t frame_size) { diff --git a/src/internal_modules/roc_audio/target_libvorbis/roc_audio/vorbis_encoder.h b/src/internal_modules/roc_audio/target_libvorbis/roc_audio/vorbis_encoder.h index 921467520..33043d3d8 100644 --- a/src/internal_modules/roc_audio/target_libvorbis/roc_audio/vorbis_encoder.h +++ b/src/internal_modules/roc_audio/target_libvorbis/roc_audio/vorbis_encoder.h @@ -44,7 +44,6 @@ class VorbisEncoder : public IFrameEncoder { virtual void end_frame(); private: - SampleSpec sample_spec_; bool initialized_; void* frame_data_; size_t frame_size_; From ebf318bde0a343d98980d19d77262c444837223c Mon Sep 17 00:00:00 2001 From: Leonardo Invernizzi Date: Wed, 14 Aug 2024 01:45:22 +0000 Subject: [PATCH 18/26] write_samples WIP --- .../roc_audio/vorbis_encoder.cpp | 114 +++++++++++++++--- .../roc_audio/vorbis_encoder.h | 9 +- 2 files changed, 104 insertions(+), 19 deletions(-) diff --git a/src/internal_modules/roc_audio/target_libvorbis/roc_audio/vorbis_encoder.cpp b/src/internal_modules/roc_audio/target_libvorbis/roc_audio/vorbis_encoder.cpp index b9eb200ef..32f0b8b27 100644 --- a/src/internal_modules/roc_audio/target_libvorbis/roc_audio/vorbis_encoder.cpp +++ b/src/internal_modules/roc_audio/target_libvorbis/roc_audio/vorbis_encoder.cpp @@ -8,6 +8,7 @@ #include "roc_audio/vorbis_encoder.h" #include "roc_core/panic.h" +#include namespace roc { namespace audio { @@ -18,9 +19,9 @@ VorbisEncoder::VorbisEncoder(const SampleSpec& sample_spec) , frame_size_(0) { vorbis_info_init(&vorbis_info_); - const int num_channels = static_cast(sample_spec.num_channels()); - const int sample_rate = static_cast(sample_spec.sample_rate()); - int ret = vorbis_encode_init_vbr(&vorbis_info_, num_channels, sample_rate, 0.0f); + const long num_channels = static_cast(sample_spec.num_channels()); + const long sample_rate = static_cast(sample_spec.sample_rate()); + int ret = vorbis_encode_init_vbr(&vorbis_info_, num_channels, sample_rate, 0.5f); if (ret != 0) { roc_panic("vorbis encoder: failed to initialize vorbis encoder"); } @@ -56,22 +57,16 @@ status::StatusCode VorbisEncoder::init_status() const { size_t VorbisEncoder::encoded_byte_count(size_t num_samples) const { if (!initialized_) { + roc_panic("vorbis encoder: encoder not initialized"); return 0; } - if (vorbis_info_.rate <= 0 || vorbis_info_.channels <= 0 - || vorbis_info_.bitrate_nominal <= 0) { - roc_panic("vorbis encoder: vorbis_info structure has invalid values"); - return 0; - } - - // Average number of bits used per sample, per channel. - const size_t bit_width = static_cast( - (vorbis_info_.bitrate_nominal / vorbis_info_.rate) / vorbis_info_.channels); + const size_t channels = static_cast(vorbis_info_.channels); + // const size_t sample_rate = static_cast(vorbis_info_.rate); + // const size_t bitrate_nominal = static_cast(vorbis_info_.bitrate_nominal); - const size_t encoded_bytes = (num_samples * bit_width + 7) / 8; - - return encoded_bytes; + size_t estimated_bytes = (32 * num_samples * channels) / (8); + return estimated_bytes; } void VorbisEncoder::begin_frame(void* frame_data, size_t frame_size) { @@ -84,12 +79,95 @@ void VorbisEncoder::begin_frame(void* frame_data, size_t frame_size) { } size_t VorbisEncoder::write_samples(const sample_t* samples, size_t n_samples) { - roc_panic("TODO"); - return 0; + if (!initialized_) { + roc_panic("vorbis encoder: encoder not initialized"); + return 0; + } + + if (!samples || n_samples == 0) { + return 0; + } + + buffer_samples_(samples, n_samples); + + size_t total_bytes_written = process_analysis_and_encoding_(); + + vorbis_analysis_wrote(&vorbis_dsp_, 0); + + total_bytes_written += process_analysis_and_encoding_(); + + return total_bytes_written; } void VorbisEncoder::end_frame() { - roc_panic("TODO"); + frame_data_ = NULL; + frame_size_ = 0; +} + +void VorbisEncoder::buffer_samples_(const sample_t* samples, size_t n_samples) { + const int int_n_samples = static_cast(n_samples); + + float** buffer = vorbis_analysis_buffer(&vorbis_dsp_, int_n_samples); + + for (int i = 0; i < int_n_samples; ++i) { + for (int ch = 0; ch < vorbis_info_.channels; ++ch) { + buffer[ch][i] = samples[i * vorbis_info_.channels + ch]; + } + } + + vorbis_analysis_wrote(&vorbis_dsp_, int_n_samples); +} + +size_t VorbisEncoder::process_analysis_and_encoding_() { + size_t total_bytes_written = 0; + + while (vorbis_analysis_blockout(&vorbis_dsp_, &vorbis_block_) == 1) { + vorbis_analysis(&vorbis_block_, NULL); + + vorbis_bitrate_addblock(&vorbis_block_); + + total_bytes_written += extract_and_write_packets_(); + } + + return total_bytes_written; +} + +size_t VorbisEncoder::extract_and_write_packets_() { + size_t bytes_written = 0; + + ogg_packet packet; + while (vorbis_bitrate_flushpacket(&vorbis_dsp_, &packet)) { + ogg_stream_packetin(&ogg_stream_, &packet); + + bytes_written += write_ogg_pages_(); + } + + return bytes_written; +} + +size_t VorbisEncoder::write_ogg_pages_() { + long bytes_written = 0; + + ogg_page page; + while (ogg_stream_pageout(&ogg_stream_, &page)) { + if (bytes_written + page.header_len + page.body_len + > static_cast(frame_size_)) { + roc_panic("vorbis encoder: frame buffer overflow"); + } + + write_to_frame_(page.header, page.header_len, bytes_written); + bytes_written += page.header_len; + + write_to_frame_(page.body, page.body_len, bytes_written); + bytes_written += page.body_len; + } + + return static_cast(bytes_written); +} + +void VorbisEncoder::write_to_frame_(const void* data, long size, long offset) { + const size_t casted_size = static_cast(size); + memcpy(static_cast(frame_data_) + offset, data, casted_size); } } // namespace audio diff --git a/src/internal_modules/roc_audio/target_libvorbis/roc_audio/vorbis_encoder.h b/src/internal_modules/roc_audio/target_libvorbis/roc_audio/vorbis_encoder.h index 33043d3d8..2331b1b08 100644 --- a/src/internal_modules/roc_audio/target_libvorbis/roc_audio/vorbis_encoder.h +++ b/src/internal_modules/roc_audio/target_libvorbis/roc_audio/vorbis_encoder.h @@ -7,13 +7,14 @@ */ //! @file roc_audio/target_libvorbis/roc_audio/vorbis_encoder.h -//! @brief Vorbis audio decoder. +//! @brief Vorbis audio encoder. #ifndef ROC_AUDIO_VORBIS_ENCODER_H_ #define ROC_AUDIO_VORBIS_ENCODER_H_ #include "roc_audio/iframe_encoder.h" #include "roc_audio/sample_spec.h" +#include #include namespace roc { @@ -44,6 +45,12 @@ class VorbisEncoder : public IFrameEncoder { virtual void end_frame(); private: + void buffer_samples_(const sample_t* samples, size_t n_samples); + size_t process_analysis_and_encoding_(); + size_t extract_and_write_packets_(); + size_t write_ogg_pages_(); + void write_to_frame_(const void* data, long size, long offset); + bool initialized_; void* frame_data_; size_t frame_size_; From c09ec150d167943f3d3efacb9d704a310621e6fe Mon Sep 17 00:00:00 2001 From: Leonardo Invernizzi Date: Wed, 14 Aug 2024 02:08:25 +0000 Subject: [PATCH 19/26] Fix IFrame changes --- .../roc_audio/target_libvorbis/roc_audio/vorbis_decoder.cpp | 3 ++- .../roc_audio/target_libvorbis/roc_audio/vorbis_decoder.h | 2 +- .../roc_audio/target_libvorbis/roc_audio/vorbis_encoder.cpp | 5 +++-- .../roc_audio/target_libvorbis/roc_audio/vorbis_encoder.h | 2 +- 4 files changed, 7 insertions(+), 5 deletions(-) diff --git a/src/internal_modules/roc_audio/target_libvorbis/roc_audio/vorbis_decoder.cpp b/src/internal_modules/roc_audio/target_libvorbis/roc_audio/vorbis_decoder.cpp index 6e964f924..444c0b2b6 100644 --- a/src/internal_modules/roc_audio/target_libvorbis/roc_audio/vorbis_decoder.cpp +++ b/src/internal_modules/roc_audio/target_libvorbis/roc_audio/vorbis_decoder.cpp @@ -12,7 +12,8 @@ namespace roc { namespace audio { -VorbisDecoder::VorbisDecoder(const SampleSpec& sample_spec) { +VorbisDecoder::VorbisDecoder(const SampleSpec& sample_spec, core::IArena& arena) + : IFrameDecoder(arena) { // TODO } diff --git a/src/internal_modules/roc_audio/target_libvorbis/roc_audio/vorbis_decoder.h b/src/internal_modules/roc_audio/target_libvorbis/roc_audio/vorbis_decoder.h index 3f0101830..9d760eab7 100644 --- a/src/internal_modules/roc_audio/target_libvorbis/roc_audio/vorbis_decoder.h +++ b/src/internal_modules/roc_audio/target_libvorbis/roc_audio/vorbis_decoder.h @@ -23,7 +23,7 @@ namespace audio { class VorbisDecoder : public IFrameDecoder { public: //! Initialize. - VorbisDecoder(const SampleSpec& sample_spec); + VorbisDecoder(const SampleSpec& sample_spec, core::IArena& arena); //! End. ~VorbisDecoder(); diff --git a/src/internal_modules/roc_audio/target_libvorbis/roc_audio/vorbis_encoder.cpp b/src/internal_modules/roc_audio/target_libvorbis/roc_audio/vorbis_encoder.cpp index 32f0b8b27..e82cd96b6 100644 --- a/src/internal_modules/roc_audio/target_libvorbis/roc_audio/vorbis_encoder.cpp +++ b/src/internal_modules/roc_audio/target_libvorbis/roc_audio/vorbis_encoder.cpp @@ -13,8 +13,9 @@ namespace roc { namespace audio { -VorbisEncoder::VorbisEncoder(const SampleSpec& sample_spec) - : initialized_(false) +VorbisEncoder::VorbisEncoder(const SampleSpec& sample_spec, core::IArena& arena) + : IFrameEncoder(arena) + , initialized_(false) , frame_data_(NULL) , frame_size_(0) { vorbis_info_init(&vorbis_info_); diff --git a/src/internal_modules/roc_audio/target_libvorbis/roc_audio/vorbis_encoder.h b/src/internal_modules/roc_audio/target_libvorbis/roc_audio/vorbis_encoder.h index 2331b1b08..9e6ad8399 100644 --- a/src/internal_modules/roc_audio/target_libvorbis/roc_audio/vorbis_encoder.h +++ b/src/internal_modules/roc_audio/target_libvorbis/roc_audio/vorbis_encoder.h @@ -24,7 +24,7 @@ namespace audio { class VorbisEncoder : public IFrameEncoder { public: //! Initialize. - VorbisEncoder(const SampleSpec& sample_spec); + VorbisEncoder(const SampleSpec& sample_spec, core::IArena& arena); //! End. ~VorbisEncoder(); From bbd1f243b0ae8c0d7c2a28bfbca0c96f56dab554 Mon Sep 17 00:00:00 2001 From: Leonardo Invernizzi Date: Wed, 14 Aug 2024 17:39:57 +0000 Subject: [PATCH 20/26] Maybe fix on mac? --- 3rdparty/SConscript | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/3rdparty/SConscript b/3rdparty/SConscript index bf39a8ccc..336ef7471 100644 --- a/3rdparty/SConscript +++ b/3rdparty/SConscript @@ -274,10 +274,16 @@ if 'libvorbis' in autobuild_dependencies: deps=pa_deps) elif 'libvorbis' in system_dependencies: + vorbis_prefix = None + # macOS: for mac uses brew install + if meta.platform == 'darwin' and not is_crosscompiling: + env.FindBrewPackage('libogg') + vorbis_prefix = env.FindBrewPackage('libvorbis') + conf = Configure(env, custom_tests=env.CustomTests) - if not conf.AddPkgConfigDependency('vorbis', '--cflags --libs', exclude_from_pc=True): - conf.env.AddManualDependency(libs=['vorbis', 'vorbisenc', 'vorbisfile'], exclude_from_pc=True) + if not conf.AddPkgConfigDependency('vorbis', '--cflags --libs', exclude_from_pc=True, add_prefix=vorbis_prefix): + conf.env.AddManualDependency(libs=['vorbis', 'vorbisenc', 'vorbisfile'], exclude_from_pc=True, prefix=vorbis_prefix) if not conf.CheckLibWithHeaderExt('vorbis', 'vorbis/vorbisenc.h', 'C', run=False): env.Die("libvorbis not found (see 'config.log' for details)") From 807555990a42c43a141b44d97975565fb5cb56bf Mon Sep 17 00:00:00 2001 From: Leonardo Invernizzi Date: Fri, 16 Aug 2024 01:40:26 +0000 Subject: [PATCH 21/26] implemented VorbisEncoder::write_samples --- 3rdparty/SConscript | 10 +-- .../roc_audio/vorbis_encoder.cpp | 78 ++++++++----------- .../roc_audio/vorbis_encoder.h | 8 +- 3 files changed, 37 insertions(+), 59 deletions(-) diff --git a/3rdparty/SConscript b/3rdparty/SConscript index 336ef7471..bf39a8ccc 100644 --- a/3rdparty/SConscript +++ b/3rdparty/SConscript @@ -274,16 +274,10 @@ if 'libvorbis' in autobuild_dependencies: deps=pa_deps) elif 'libvorbis' in system_dependencies: - vorbis_prefix = None - # macOS: for mac uses brew install - if meta.platform == 'darwin' and not is_crosscompiling: - env.FindBrewPackage('libogg') - vorbis_prefix = env.FindBrewPackage('libvorbis') - conf = Configure(env, custom_tests=env.CustomTests) - if not conf.AddPkgConfigDependency('vorbis', '--cflags --libs', exclude_from_pc=True, add_prefix=vorbis_prefix): - conf.env.AddManualDependency(libs=['vorbis', 'vorbisenc', 'vorbisfile'], exclude_from_pc=True, prefix=vorbis_prefix) + if not conf.AddPkgConfigDependency('vorbis', '--cflags --libs', exclude_from_pc=True): + conf.env.AddManualDependency(libs=['vorbis', 'vorbisenc', 'vorbisfile'], exclude_from_pc=True) if not conf.CheckLibWithHeaderExt('vorbis', 'vorbis/vorbisenc.h', 'C', run=False): env.Die("libvorbis not found (see 'config.log' for details)") diff --git a/src/internal_modules/roc_audio/target_libvorbis/roc_audio/vorbis_encoder.cpp b/src/internal_modules/roc_audio/target_libvorbis/roc_audio/vorbis_encoder.cpp index e82cd96b6..8622c647e 100644 --- a/src/internal_modules/roc_audio/target_libvorbis/roc_audio/vorbis_encoder.cpp +++ b/src/internal_modules/roc_audio/target_libvorbis/roc_audio/vorbis_encoder.cpp @@ -22,19 +22,19 @@ VorbisEncoder::VorbisEncoder(const SampleSpec& sample_spec, core::IArena& arena) const long num_channels = static_cast(sample_spec.num_channels()); const long sample_rate = static_cast(sample_spec.sample_rate()); - int ret = vorbis_encode_init_vbr(&vorbis_info_, num_channels, sample_rate, 0.5f); - if (ret != 0) { + const float quality = 0.5f; + + if (vorbis_encode_init_vbr(&vorbis_info_, num_channels, sample_rate, quality) != 0) { roc_panic("vorbis encoder: failed to initialize vorbis encoder"); } + vorbis_comment_init(&vorbis_comment_); - ret = vorbis_analysis_init(&vorbis_dsp_, &vorbis_info_); - if (ret != 0) { + if (vorbis_analysis_init(&vorbis_dsp_, &vorbis_info_) != 0) { roc_panic("vorbis encoder: failed to initialize vorbis dsp"); } - ret = vorbis_block_init(&vorbis_dsp_, &vorbis_block_); - if (ret != 0) { + if (vorbis_block_init(&vorbis_dsp_, &vorbis_block_) != 0) { roc_panic("vorbis encoder: failed to initialize vorbis block"); } @@ -56,48 +56,47 @@ status::StatusCode VorbisEncoder::init_status() const { return initialized_ ? status::StatusOK : status::StatusAbort; } -size_t VorbisEncoder::encoded_byte_count(size_t num_samples) const { - if (!initialized_) { - roc_panic("vorbis encoder: encoder not initialized"); - return 0; - } +size_t VorbisEncoder::encoded_byte_count(size_t n_samples) const { + roc_panic_if_not(initialized_); - const size_t channels = static_cast(vorbis_info_.channels); - // const size_t sample_rate = static_cast(vorbis_info_.rate); - // const size_t bitrate_nominal = static_cast(vorbis_info_.bitrate_nominal); + const float nominal_bitrate = vorbis_info_.bitrate_nominal; + const long num_channels = vorbis_info_.channels; + const long sample_rate = vorbis_info_.rate; - size_t estimated_bytes = (32 * num_samples * channels) / (8); - return estimated_bytes; + // Estimated encoded byte count + return static_cast((nominal_bitrate * n_samples * num_channels) + / (sample_rate * 8.0f)); } void VorbisEncoder::begin_frame(void* frame_data, size_t frame_size) { roc_panic_if_not(frame_data); + if (frame_data_) { roc_panic("vorbis encoder: unpaired begin/end"); } + frame_data_ = frame_data; frame_size_ = frame_size; } size_t VorbisEncoder::write_samples(const sample_t* samples, size_t n_samples) { - if (!initialized_) { - roc_panic("vorbis encoder: encoder not initialized"); - return 0; - } + roc_panic_if_not(initialized_); if (!samples || n_samples == 0) { return 0; } buffer_samples_(samples, n_samples); + process_analysis_and_encoding_(); - size_t total_bytes_written = process_analysis_and_encoding_(); - + // Indicate that no more samples are to be written vorbis_analysis_wrote(&vorbis_dsp_, 0); + process_analysis_and_encoding_(); - total_bytes_written += process_analysis_and_encoding_(); - - return total_bytes_written; + // Vorbis encodes with blocks of fixed amount of samples, if the number of samples to + // be encoded are less than the block amount of samples, it fill the rest of the block + // with 0 So the return value is the amount of samples put inside the buffer + return n_samples; } void VorbisEncoder::end_frame() { @@ -119,51 +118,36 @@ void VorbisEncoder::buffer_samples_(const sample_t* samples, size_t n_samples) { vorbis_analysis_wrote(&vorbis_dsp_, int_n_samples); } -size_t VorbisEncoder::process_analysis_and_encoding_() { - size_t total_bytes_written = 0; - +void VorbisEncoder::process_analysis_and_encoding_() { while (vorbis_analysis_blockout(&vorbis_dsp_, &vorbis_block_) == 1) { vorbis_analysis(&vorbis_block_, NULL); vorbis_bitrate_addblock(&vorbis_block_); - total_bytes_written += extract_and_write_packets_(); + extract_and_write_packets_(); } - - return total_bytes_written; } -size_t VorbisEncoder::extract_and_write_packets_() { - size_t bytes_written = 0; - +void VorbisEncoder::extract_and_write_packets_() { ogg_packet packet; + while (vorbis_bitrate_flushpacket(&vorbis_dsp_, &packet)) { ogg_stream_packetin(&ogg_stream_, &packet); - - bytes_written += write_ogg_pages_(); + write_ogg_pages_(); } - - return bytes_written; } -size_t VorbisEncoder::write_ogg_pages_() { +void VorbisEncoder::write_ogg_pages_() { long bytes_written = 0; - ogg_page page; - while (ogg_stream_pageout(&ogg_stream_, &page)) { - if (bytes_written + page.header_len + page.body_len - > static_cast(frame_size_)) { - roc_panic("vorbis encoder: frame buffer overflow"); - } + while (ogg_stream_pageout(&ogg_stream_, &page)) { write_to_frame_(page.header, page.header_len, bytes_written); bytes_written += page.header_len; write_to_frame_(page.body, page.body_len, bytes_written); bytes_written += page.body_len; } - - return static_cast(bytes_written); } void VorbisEncoder::write_to_frame_(const void* data, long size, long offset) { diff --git a/src/internal_modules/roc_audio/target_libvorbis/roc_audio/vorbis_encoder.h b/src/internal_modules/roc_audio/target_libvorbis/roc_audio/vorbis_encoder.h index 9e6ad8399..f3a07e406 100644 --- a/src/internal_modules/roc_audio/target_libvorbis/roc_audio/vorbis_encoder.h +++ b/src/internal_modules/roc_audio/target_libvorbis/roc_audio/vorbis_encoder.h @@ -33,7 +33,7 @@ class VorbisEncoder : public IFrameEncoder { virtual status::StatusCode init_status() const; //! Get encoded frame size in bytes for given number of samples per channel. - virtual size_t encoded_byte_count(size_t num_samples) const; + virtual size_t encoded_byte_count(size_t n_samples) const; //! Start encoding a new frame. virtual void begin_frame(void* frame, size_t frame_size); @@ -46,9 +46,9 @@ class VorbisEncoder : public IFrameEncoder { private: void buffer_samples_(const sample_t* samples, size_t n_samples); - size_t process_analysis_and_encoding_(); - size_t extract_and_write_packets_(); - size_t write_ogg_pages_(); + void process_analysis_and_encoding_(); + void extract_and_write_packets_(); + void write_ogg_pages_(); void write_to_frame_(const void* data, long size, long offset); bool initialized_; From f18795b2d3249b6b369d58ebb72dcfb42d4dde9e Mon Sep 17 00:00:00 2001 From: Leonardo Invernizzi Date: Fri, 16 Aug 2024 02:45:43 +0000 Subject: [PATCH 22/26] refactor and finish VorbisEncoder --- .../roc_audio/vorbis_encoder.cpp | 77 +++++++------------ .../roc_audio/vorbis_encoder.h | 10 +-- 2 files changed, 31 insertions(+), 56 deletions(-) diff --git a/src/internal_modules/roc_audio/target_libvorbis/roc_audio/vorbis_encoder.cpp b/src/internal_modules/roc_audio/target_libvorbis/roc_audio/vorbis_encoder.cpp index 8622c647e..8cde22bb0 100644 --- a/src/internal_modules/roc_audio/target_libvorbis/roc_audio/vorbis_encoder.cpp +++ b/src/internal_modules/roc_audio/target_libvorbis/roc_audio/vorbis_encoder.cpp @@ -8,7 +8,6 @@ #include "roc_audio/vorbis_encoder.h" #include "roc_core/panic.h" -#include namespace roc { namespace audio { @@ -17,7 +16,8 @@ VorbisEncoder::VorbisEncoder(const SampleSpec& sample_spec, core::IArena& arena) : IFrameEncoder(arena) , initialized_(false) , frame_data_(NULL) - , frame_size_(0) { + , frame_size_(0) + , current_position_(0) { vorbis_info_init(&vorbis_info_); const long num_channels = static_cast(sample_spec.num_channels()); @@ -28,8 +28,6 @@ VorbisEncoder::VorbisEncoder(const SampleSpec& sample_spec, core::IArena& arena) roc_panic("vorbis encoder: failed to initialize vorbis encoder"); } - vorbis_comment_init(&vorbis_comment_); - if (vorbis_analysis_init(&vorbis_dsp_, &vorbis_info_) != 0) { roc_panic("vorbis encoder: failed to initialize vorbis dsp"); } @@ -38,16 +36,13 @@ VorbisEncoder::VorbisEncoder(const SampleSpec& sample_spec, core::IArena& arena) roc_panic("vorbis encoder: failed to initialize vorbis block"); } - ogg_stream_init(&ogg_stream_, 0); initialized_ = true; } VorbisEncoder::~VorbisEncoder() { if (initialized_) { - ogg_stream_clear(&ogg_stream_); vorbis_block_clear(&vorbis_block_); vorbis_dsp_clear(&vorbis_dsp_); - vorbis_comment_clear(&vorbis_comment_); vorbis_info_clear(&vorbis_info_); } } @@ -59,13 +54,14 @@ status::StatusCode VorbisEncoder::init_status() const { size_t VorbisEncoder::encoded_byte_count(size_t n_samples) const { roc_panic_if_not(initialized_); - const float nominal_bitrate = vorbis_info_.bitrate_nominal; - const long num_channels = vorbis_info_.channels; - const long sample_rate = vorbis_info_.rate; + const size_t nominal_bitrate = static_cast(vorbis_info_.bitrate_nominal); + const size_t num_channels = static_cast(vorbis_info_.channels); + const size_t sample_rate = static_cast(vorbis_info_.rate); + + const size_t total_num_bits = nominal_bitrate * n_samples * num_channels; // Estimated encoded byte count - return static_cast((nominal_bitrate * n_samples * num_channels) - / (sample_rate * 8.0f)); + return total_num_bits / (sample_rate * 8); } void VorbisEncoder::begin_frame(void* frame_data, size_t frame_size) { @@ -75,8 +71,9 @@ void VorbisEncoder::begin_frame(void* frame_data, size_t frame_size) { roc_panic("vorbis encoder: unpaired begin/end"); } - frame_data_ = frame_data; + frame_data_ = static_cast(frame_data); frame_size_ = frame_size; + current_position_ = 0; } size_t VorbisEncoder::write_samples(const sample_t* samples, size_t n_samples) { @@ -87,19 +84,19 @@ size_t VorbisEncoder::write_samples(const sample_t* samples, size_t n_samples) { } buffer_samples_(samples, n_samples); - process_analysis_and_encoding_(); - // Indicate that no more samples are to be written - vorbis_analysis_wrote(&vorbis_dsp_, 0); - process_analysis_and_encoding_(); + process_encoding_(); - // Vorbis encodes with blocks of fixed amount of samples, if the number of samples to - // be encoded are less than the block amount of samples, it fill the rest of the block - // with 0 So the return value is the amount of samples put inside the buffer return n_samples; } void VorbisEncoder::end_frame() { + // Indicate that no more samples are to be written + vorbis_analysis_wrote(&vorbis_dsp_, 0); + + // Encode the remaining data + process_encoding_(); + frame_data_ = NULL; frame_size_ = 0; } @@ -118,42 +115,24 @@ void VorbisEncoder::buffer_samples_(const sample_t* samples, size_t n_samples) { vorbis_analysis_wrote(&vorbis_dsp_, int_n_samples); } -void VorbisEncoder::process_analysis_and_encoding_() { +void VorbisEncoder::process_encoding_() { + ogg_packet packet; while (vorbis_analysis_blockout(&vorbis_dsp_, &vorbis_block_) == 1) { - vorbis_analysis(&vorbis_block_, NULL); - + vorbis_analysis(&vorbis_block_, 0); vorbis_bitrate_addblock(&vorbis_block_); - extract_and_write_packets_(); - } -} - -void VorbisEncoder::extract_and_write_packets_() { - ogg_packet packet; - - while (vorbis_bitrate_flushpacket(&vorbis_dsp_, &packet)) { - ogg_stream_packetin(&ogg_stream_, &packet); - write_ogg_pages_(); - } -} - -void VorbisEncoder::write_ogg_pages_() { - long bytes_written = 0; - ogg_page page; + while (vorbis_bitrate_flushpacket(&vorbis_dsp_, &packet)) { + const size_t packet_bytes = static_cast(packet.bytes); - while (ogg_stream_pageout(&ogg_stream_, &page)) { - write_to_frame_(page.header, page.header_len, bytes_written); - bytes_written += page.header_len; + if (current_position_ + packet_bytes > frame_size_) { + return; + } - write_to_frame_(page.body, page.body_len, bytes_written); - bytes_written += page.body_len; + memcpy(frame_data_ + current_position_, packet.packet, packet_bytes); + current_position_ += packet_bytes; + } } } -void VorbisEncoder::write_to_frame_(const void* data, long size, long offset) { - const size_t casted_size = static_cast(size); - memcpy(static_cast(frame_data_) + offset, data, casted_size); -} - } // namespace audio } // namespace roc diff --git a/src/internal_modules/roc_audio/target_libvorbis/roc_audio/vorbis_encoder.h b/src/internal_modules/roc_audio/target_libvorbis/roc_audio/vorbis_encoder.h index f3a07e406..da4737b28 100644 --- a/src/internal_modules/roc_audio/target_libvorbis/roc_audio/vorbis_encoder.h +++ b/src/internal_modules/roc_audio/target_libvorbis/roc_audio/vorbis_encoder.h @@ -46,17 +46,13 @@ class VorbisEncoder : public IFrameEncoder { private: void buffer_samples_(const sample_t* samples, size_t n_samples); - void process_analysis_and_encoding_(); - void extract_and_write_packets_(); - void write_ogg_pages_(); - void write_to_frame_(const void* data, long size, long offset); + void process_encoding_(); bool initialized_; - void* frame_data_; + uint8_t* frame_data_; size_t frame_size_; - ogg_stream_state ogg_stream_; + size_t current_position_; vorbis_info vorbis_info_; - vorbis_comment vorbis_comment_; vorbis_dsp_state vorbis_dsp_; vorbis_block vorbis_block_; }; From 83b2bd6225f3833b0ca93d65f86edf11804658b3 Mon Sep 17 00:00:00 2001 From: Leonardo Invernizzi Date: Sat, 17 Aug 2024 04:36:24 +0000 Subject: [PATCH 23/26] VornisDecoder WIP --- .../roc_audio/vorbis_decoder.cpp | 106 ++++++++++++++++-- .../roc_audio/vorbis_decoder.h | 19 +++- 2 files changed, 112 insertions(+), 13 deletions(-) diff --git a/src/internal_modules/roc_audio/target_libvorbis/roc_audio/vorbis_decoder.cpp b/src/internal_modules/roc_audio/target_libvorbis/roc_audio/vorbis_decoder.cpp index 444c0b2b6..f9adad48e 100644 --- a/src/internal_modules/roc_audio/target_libvorbis/roc_audio/vorbis_decoder.cpp +++ b/src/internal_modules/roc_audio/target_libvorbis/roc_audio/vorbis_decoder.cpp @@ -13,39 +13,103 @@ namespace roc { namespace audio { VorbisDecoder::VorbisDecoder(const SampleSpec& sample_spec, core::IArena& arena) - : IFrameDecoder(arena) { - // TODO + : IFrameDecoder(arena) + , initialized_(false) + , current_position_(0) + , available_samples_(0) + , pcm_samples_(NULL) + , current_sample_pos_(0) + , total_samples_in_frame_(0) + , headers_read_(false) { + vorbis_info_init(&vorbis_info_); + vorbis_comment_init(&vorbis_comment_); + ogg_sync_init(&ogg_sync_); + + initialized_ = true; } VorbisDecoder::~VorbisDecoder() { - // TODO + if (initialized_) { + vorbis_block_clear(&vorbis_block_); + vorbis_dsp_clear(&vorbis_dsp_); + vorbis_info_clear(&vorbis_info_); + ogg_sync_clear(&ogg_sync_); + } } status::StatusCode VorbisDecoder::init_status() const { - return status::StatusOK; + return initialized_ ? status::StatusOK : status::StatusAbort; } packet::stream_timestamp_t VorbisDecoder::position() const { - roc_panic("TODO"); - return 0; + return current_position_; } packet::stream_timestamp_t VorbisDecoder::available() const { - roc_panic("TODO"); - return 0; + return available_samples_; } size_t VorbisDecoder::decoded_sample_count(const void* frame_data, size_t frame_size) const { - roc_panic("TODO"); - return 0; + const size_t nominal_bitrate = static_cast(vorbis_info_.bitrate_nominal); + const size_t num_channels = static_cast(vorbis_info_.channels); + + return frame_size * 8 / (nominal_bitrate / num_channels); } void VorbisDecoder::begin_frame(packet::stream_timestamp_t frame_position, const void* frame_data, size_t frame_size) { - roc_panic_if_not(frame_data); - roc_panic("TODO"); + roc_panic_if_not(initialized_); + + current_position_ = frame_position; + available_samples_ = 0; + current_sample_pos_ = 0; + total_samples_in_frame_ = 0; + + // Ogg sync to handle the input data + char* buffer = ogg_sync_buffer(&ogg_sync_, static_cast(frame_size)); + memcpy(buffer, frame_data, frame_size); + ogg_sync_wrote(&ogg_sync_, static_cast(frame_size)); + + // Read headers if not already done + if (!headers_read_) { + ogg_page ogg_page; + while (ogg_sync_pageout(&ogg_sync_, &ogg_page) == 1) { + ogg_stream_pagein(&ogg_stream_, &ogg_page); + + ogg_packet header_packet; + while (ogg_stream_packetout(&ogg_stream_, &header_packet) == 1) { + if (vorbis_synthesis_idheader(&header_packet)) { + if (vorbis_synthesis_headerin(&vorbis_info_, &vorbis_comment_, + &header_packet) + < 0) { + roc_panic("vorbis decoder: invalid header packet"); + } + } + + if (ogg_stream_packetout(&ogg_stream_, &header_packet) != 1) { + break; + } + } + + // Check if we have read all three headers + if (vorbis_synthesis_init(&vorbis_dsp_, &vorbis_info_) == 0) { + vorbis_block_init(&vorbis_dsp_, &vorbis_block_); + headers_read_ = true; + break; + } + } + } + + // Extract packets from the buffer + ogg_page ogg_page; + while (ogg_sync_pageout(&ogg_sync_, &ogg_page) == 1) { + ogg_stream_pagein(&ogg_stream_, &ogg_page); + while (ogg_stream_packetout(&ogg_stream_, ¤t_packet_) == 1) { + process_packet_(); + } + } } size_t VorbisDecoder::read_samples(sample_t* samples, size_t n_samples) { @@ -62,5 +126,23 @@ void VorbisDecoder::end_frame() { roc_panic("TODO"); } +void VorbisDecoder::process_packet_() { + if (vorbis_synthesis(&vorbis_block_, ¤t_packet_) != 0) { + return; + } + + vorbis_synthesis_blockin(&vorbis_dsp_, &vorbis_block_); + + while (true) { + total_samples_in_frame_ = vorbis_synthesis_pcmout(&vorbis_dsp_, &pcm_samples_); + if (total_samples_in_frame_ <= 0) { + break; + } + + available_samples_ += static_cast(total_samples_in_frame_); + vorbis_synthesis_read(&vorbis_dsp_, total_samples_in_frame_); + } +} + } // namespace audio } // namespace roc diff --git a/src/internal_modules/roc_audio/target_libvorbis/roc_audio/vorbis_decoder.h b/src/internal_modules/roc_audio/target_libvorbis/roc_audio/vorbis_decoder.h index 9d760eab7..607a92bc6 100644 --- a/src/internal_modules/roc_audio/target_libvorbis/roc_audio/vorbis_decoder.h +++ b/src/internal_modules/roc_audio/target_libvorbis/roc_audio/vorbis_decoder.h @@ -14,7 +14,7 @@ #include "roc_audio/iframe_decoder.h" #include "roc_audio/sample_spec.h" -#include +#include namespace roc { namespace audio { @@ -55,6 +55,23 @@ class VorbisDecoder : public IFrameDecoder { virtual void end_frame(); private: + void process_packet_(); + + bool initialized_; + vorbis_info vorbis_info_; + vorbis_comment vorbis_comment_; + vorbis_dsp_state vorbis_dsp_; + vorbis_block vorbis_block_; + ogg_packet current_packet_; + ogg_sync_state ogg_sync_; + ogg_stream_state ogg_stream_; + + packet::stream_timestamp_t current_position_; + size_t available_samples_; + float** pcm_samples_; + int current_sample_pos_; + int total_samples_in_frame_; + bool headers_read_; }; } // namespace audio From 0e43c8a06e69e52e05d654c9cd5d473bb362b7a6 Mon Sep 17 00:00:00 2001 From: Leonardo Invernizzi Date: Mon, 26 Aug 2024 00:55:03 +0000 Subject: [PATCH 24/26] Introduced frame headers --- .../roc_audio/iframe_encoder.h | 12 ++ .../roc_audio/pcm_encoder.cpp | 8 ++ src/internal_modules/roc_audio/pcm_encoder.h | 6 + .../roc_audio/vorbis_encoder.cpp | 126 ++++++++++++++++-- .../roc_audio/vorbis_encoder.h | 22 +++ 5 files changed, 160 insertions(+), 14 deletions(-) diff --git a/src/internal_modules/roc_audio/iframe_encoder.h b/src/internal_modules/roc_audio/iframe_encoder.h index bc9e6eeda..f2053d5ad 100644 --- a/src/internal_modules/roc_audio/iframe_encoder.h +++ b/src/internal_modules/roc_audio/iframe_encoder.h @@ -36,6 +36,18 @@ class IFrameEncoder : public core::ArenaAllocation { //! Get encoded frame size in bytes for given number of samples (per channel). virtual size_t encoded_byte_count(size_t n_samples) const = 0; + //! Get ponter of headers. + //! + //! @returns + //! A pointer to the headers. May return NULL if not applicable. + virtual const uint8_t* get_headers_frame() const = 0; + + //! Get the size of the headers. + //! + //! @returns + //! Size of the headers in bytes. + virtual size_t get_headers_frame_size() const = 0; + //! Start encoding a new frame. //! //! @remarks diff --git a/src/internal_modules/roc_audio/pcm_encoder.cpp b/src/internal_modules/roc_audio/pcm_encoder.cpp index 49ef31433..bbcb5b229 100644 --- a/src/internal_modules/roc_audio/pcm_encoder.cpp +++ b/src/internal_modules/roc_audio/pcm_encoder.cpp @@ -33,6 +33,14 @@ size_t PcmEncoder::encoded_byte_count(size_t num_samples) const { return pcm_mapper_.output_byte_count(num_samples * n_chans_); } +const uint8_t* PcmEncoder::get_headers_frame() const { + return NULL; +} + +size_t PcmEncoder::get_headers_frame_size() const { + return 0; +} + void PcmEncoder::begin_frame(void* frame_data, size_t frame_size) { roc_panic_if_not(frame_data); diff --git a/src/internal_modules/roc_audio/pcm_encoder.h b/src/internal_modules/roc_audio/pcm_encoder.h index 775b7a1c9..552d38f5b 100644 --- a/src/internal_modules/roc_audio/pcm_encoder.h +++ b/src/internal_modules/roc_audio/pcm_encoder.h @@ -35,6 +35,12 @@ class PcmEncoder : public IFrameEncoder, public core::NonCopyable<> { //! Get encoded frame size in bytes for given number of samples per channel. virtual size_t encoded_byte_count(size_t num_samples) const; + //! Get headers frame. + const uint8_t* get_headers_frame() const; + + //! Get the size of the headers. + size_t get_headers_frame_size() const; + //! Start encoding a new frame. virtual void begin_frame(void* frame, size_t frame_size); diff --git a/src/internal_modules/roc_audio/target_libvorbis/roc_audio/vorbis_encoder.cpp b/src/internal_modules/roc_audio/target_libvorbis/roc_audio/vorbis_encoder.cpp index 8cde22bb0..1ab08729a 100644 --- a/src/internal_modules/roc_audio/target_libvorbis/roc_audio/vorbis_encoder.cpp +++ b/src/internal_modules/roc_audio/target_libvorbis/roc_audio/vorbis_encoder.cpp @@ -17,24 +17,15 @@ VorbisEncoder::VorbisEncoder(const SampleSpec& sample_spec, core::IArena& arena) , initialized_(false) , frame_data_(NULL) , frame_size_(0) - , current_position_(0) { - vorbis_info_init(&vorbis_info_); - + , current_position_(0) + , headers_frame_(NULL) + , headers_frame_size_(0) { const long num_channels = static_cast(sample_spec.num_channels()); const long sample_rate = static_cast(sample_spec.sample_rate()); - const float quality = 0.5f; - - if (vorbis_encode_init_vbr(&vorbis_info_, num_channels, sample_rate, quality) != 0) { - roc_panic("vorbis encoder: failed to initialize vorbis encoder"); - } - if (vorbis_analysis_init(&vorbis_dsp_, &vorbis_info_) != 0) { - roc_panic("vorbis encoder: failed to initialize vorbis dsp"); - } + initialize_structures_(num_channels, sample_rate); - if (vorbis_block_init(&vorbis_dsp_, &vorbis_block_) != 0) { - roc_panic("vorbis encoder: failed to initialize vorbis block"); - } + create_headers_frame_(); initialized_ = true; } @@ -44,6 +35,11 @@ VorbisEncoder::~VorbisEncoder() { vorbis_block_clear(&vorbis_block_); vorbis_dsp_clear(&vorbis_dsp_); vorbis_info_clear(&vorbis_info_); + vorbis_comment_clear(&vorbis_comment_); + ogg_stream_clear(&ogg_stream_); + if (headers_frame_) { + free(headers_frame_); + } } } @@ -64,6 +60,14 @@ size_t VorbisEncoder::encoded_byte_count(size_t n_samples) const { return total_num_bits / (sample_rate * 8); } +const uint8_t* VorbisEncoder::get_headers_frame() const { + return headers_frame_; +} + +size_t VorbisEncoder::get_headers_frame_size() const { + return headers_frame_size_; +} + void VorbisEncoder::begin_frame(void* frame_data, size_t frame_size) { roc_panic_if_not(frame_data); @@ -91,6 +95,8 @@ size_t VorbisEncoder::write_samples(const sample_t* samples, size_t n_samples) { } void VorbisEncoder::end_frame() { + roc_panic_if_not(initialized_); + // Indicate that no more samples are to be written vorbis_analysis_wrote(&vorbis_dsp_, 0); @@ -101,6 +107,98 @@ void VorbisEncoder::end_frame() { frame_size_ = 0; } +void VorbisEncoder::initialize_structures_(long num_channels, long sample_rate) { + vorbis_info_init(&vorbis_info_); + vorbis_comment_init(&vorbis_comment_); + + const float quality = 0.5f; + + // Initialize vorbis_info structure + if (vorbis_encode_init_vbr(&vorbis_info_, num_channels, sample_rate, quality) != 0) { + roc_panic("vorbis encoder: failed to initialize vorbis encoder"); + } + + // Initialize vorbis_dsp_state for encoding + if (vorbis_analysis_init(&vorbis_dsp_, &vorbis_info_) != 0) { + roc_panic("vorbis encoder: failed to initialize vorbis dsp"); + } + + // Initialize ogg_stream_state for the stream + if (ogg_stream_init(&ogg_stream_, 0) != 0) { + roc_panic("vorbis encoder: failed to initialize ogg stream"); + } + + // Initialize vorbis_block for encoding + if (vorbis_block_init(&vorbis_dsp_, &vorbis_block_) != 0) { + roc_panic("vorbis encoder: failed to initialize vorbis block"); + } +} + +void VorbisEncoder::create_headers_frame_() { + ogg_packet header_packet; + ogg_packet header_comment; + ogg_packet header_codebook; + + if (vorbis_analysis_headerout(&vorbis_dsp_, &vorbis_comment_, &header_packet, + &header_comment, &header_codebook) + != 0) { + roc_panic("vorbis encoder: failed to create vorbis headers"); + } + + headers_frame_size_ = + calculate_total_headers_size_(header_packet, header_comment, header_codebook); + + headers_frame_ = static_cast(malloc(headers_frame_size_)); + if (!headers_frame_) { + roc_panic("vorbis encoder: failed to allocate memory for headers"); + } + + copy_headers_to_memory_(header_packet, header_comment, header_codebook); +} + +size_t VorbisEncoder::calculate_total_headers_size_(ogg_packet& header_packet, + ogg_packet& header_comment, + ogg_packet& header_codebook) { + ogg_page ogg_page; + long total_size = 0; + + insert_headers_into_stream_(header_packet, header_comment, header_codebook); + + while (ogg_stream_flush(&ogg_stream_, &ogg_page)) { + total_size += ogg_page.header_len + ogg_page.body_len; + } + + return static_cast(total_size); +} + +void VorbisEncoder::copy_headers_to_memory_(ogg_packet& header_packet, + ogg_packet& header_comment, + ogg_packet& header_codebook) { + ogg_page ogg_page; + size_t offset = 0; + + insert_headers_into_stream_(header_packet, header_comment, header_codebook); + + while (ogg_stream_flush(&ogg_stream_, &ogg_page)) { + const size_t header_len = static_cast(ogg_page.header_len); + const size_t body_len = static_cast(ogg_page.body_len); + + memcpy(headers_frame_ + offset, ogg_page.header, header_len); + offset += header_len; + memcpy(headers_frame_ + offset, ogg_page.body, body_len); + offset += body_len; + } +} + +void VorbisEncoder::insert_headers_into_stream_(ogg_packet& header_packet, + ogg_packet& header_comment, + ogg_packet& header_codebook) { + ogg_stream_reset(&ogg_stream_); + ogg_stream_packetin(&ogg_stream_, &header_packet); + ogg_stream_packetin(&ogg_stream_, &header_comment); + ogg_stream_packetin(&ogg_stream_, &header_codebook); +} + void VorbisEncoder::buffer_samples_(const sample_t* samples, size_t n_samples) { const int int_n_samples = static_cast(n_samples); diff --git a/src/internal_modules/roc_audio/target_libvorbis/roc_audio/vorbis_encoder.h b/src/internal_modules/roc_audio/target_libvorbis/roc_audio/vorbis_encoder.h index da4737b28..c16180a59 100644 --- a/src/internal_modules/roc_audio/target_libvorbis/roc_audio/vorbis_encoder.h +++ b/src/internal_modules/roc_audio/target_libvorbis/roc_audio/vorbis_encoder.h @@ -35,6 +35,12 @@ class VorbisEncoder : public IFrameEncoder { //! Get encoded frame size in bytes for given number of samples per channel. virtual size_t encoded_byte_count(size_t n_samples) const; + //! Get combined Vorbis headers. + const uint8_t* get_headers_frame() const; + + //! Get the size of the combined headers. + size_t get_headers_frame_size() const; + //! Start encoding a new frame. virtual void begin_frame(void* frame, size_t frame_size); @@ -45,6 +51,17 @@ class VorbisEncoder : public IFrameEncoder { virtual void end_frame(); private: + void initialize_structures_(long num_channels, long sample_rate); + void create_headers_frame_(); + size_t calculate_total_headers_size_(ogg_packet& header_packet, + ogg_packet& header_comment, + ogg_packet& header_codebook); + void copy_headers_to_memory_(ogg_packet& header_packet, + ogg_packet& header_comment, + ogg_packet& header_codebook); + void insert_headers_into_stream_(ogg_packet& header_packet, + ogg_packet& header_comment, + ogg_packet& header_codebook); void buffer_samples_(const sample_t* samples, size_t n_samples); void process_encoding_(); @@ -53,8 +70,13 @@ class VorbisEncoder : public IFrameEncoder { size_t frame_size_; size_t current_position_; vorbis_info vorbis_info_; + vorbis_comment vorbis_comment_; vorbis_dsp_state vorbis_dsp_; vorbis_block vorbis_block_; + ogg_stream_state ogg_stream_; + + uint8_t* headers_frame_; + size_t headers_frame_size_; }; } // namespace audio From c86176f42cf80b39d78b8c44da46b0a63f00ff88 Mon Sep 17 00:00:00 2001 From: Leonardo Invernizzi Date: Tue, 27 Aug 2024 02:33:00 +0000 Subject: [PATCH 25/26] Added decoder headers --- .../roc_audio/iframe_decoder.h | 21 ++++ .../roc_audio/pcm_decoder.cpp | 4 + src/internal_modules/roc_audio/pcm_decoder.h | 3 + .../roc_audio/vorbis_decoder.cpp | 117 ++++++++++++------ .../roc_audio/vorbis_decoder.h | 15 ++- 5 files changed, 112 insertions(+), 48 deletions(-) diff --git a/src/internal_modules/roc_audio/iframe_decoder.h b/src/internal_modules/roc_audio/iframe_decoder.h index cd7b0f6de..6c795c0b6 100644 --- a/src/internal_modules/roc_audio/iframe_decoder.h +++ b/src/internal_modules/roc_audio/iframe_decoder.h @@ -33,6 +33,27 @@ class IFrameDecoder : public core::ArenaAllocation { //! Check if the object was successfully constructed. virtual status::StatusCode init_status() const = 0; + //! Initialize the decoder with codec-specific headers. + //! + //! @b Parameters + //! - @p headers - pointer to the buffer containing codec-specific header data. + //! - @p headers_size - size of the header buffer in bytes. + //! + //! @remarks + //! This function sets up the decoder using the provided headers, which contain + //! essential configuration information for decoding the audio stream. The headers + //! must be in the format required by the specific codec. This function must be + //! called before decoding any frames. + //! + //! @returns + //! - true if the headers are successfully processed and the decoder is initialized. + //! - false if there is an error in processing the headers. + //! + //! @pre + //! Must be called before begin_frame(), read_samples(), drop_samples(), or + //! end_frame(). + virtual bool initialize_headers(const uint8_t* headers, size_t headers_size) = 0; + //! Get decoded stream position. //! //! @returns diff --git a/src/internal_modules/roc_audio/pcm_decoder.cpp b/src/internal_modules/roc_audio/pcm_decoder.cpp index 96f1c732d..4f5b90c90 100644 --- a/src/internal_modules/roc_audio/pcm_decoder.cpp +++ b/src/internal_modules/roc_audio/pcm_decoder.cpp @@ -32,6 +32,10 @@ status::StatusCode PcmDecoder::init_status() const { return status::StatusOK; } +bool PcmDecoder::initialize_headers(const uint8_t* headers, size_t headers_size) { + return true; +} + packet::stream_timestamp_t PcmDecoder::position() const { return stream_pos_; } diff --git a/src/internal_modules/roc_audio/pcm_decoder.h b/src/internal_modules/roc_audio/pcm_decoder.h index 5da76007e..7d9ab04d2 100644 --- a/src/internal_modules/roc_audio/pcm_decoder.h +++ b/src/internal_modules/roc_audio/pcm_decoder.h @@ -32,6 +32,9 @@ class PcmDecoder : public IFrameDecoder, public core::NonCopyable<> { //! Check if the object was successfully constructed. virtual status::StatusCode init_status() const; + //! Get the header information before start decoding + virtual bool initialize_headers(const uint8_t* headers, size_t headers_size); + //! Get current stream position. virtual packet::stream_timestamp_t position() const; diff --git a/src/internal_modules/roc_audio/target_libvorbis/roc_audio/vorbis_decoder.cpp b/src/internal_modules/roc_audio/target_libvorbis/roc_audio/vorbis_decoder.cpp index f9adad48e..84c1f6457 100644 --- a/src/internal_modules/roc_audio/target_libvorbis/roc_audio/vorbis_decoder.cpp +++ b/src/internal_modules/roc_audio/target_libvorbis/roc_audio/vorbis_decoder.cpp @@ -24,7 +24,7 @@ VorbisDecoder::VorbisDecoder(const SampleSpec& sample_spec, core::IArena& arena) vorbis_info_init(&vorbis_info_); vorbis_comment_init(&vorbis_comment_); ogg_sync_init(&ogg_sync_); - + ogg_stream_init(&ogg_stream_, 0); initialized_ = true; } @@ -33,7 +33,9 @@ VorbisDecoder::~VorbisDecoder() { vorbis_block_clear(&vorbis_block_); vorbis_dsp_clear(&vorbis_dsp_); vorbis_info_clear(&vorbis_info_); + vorbis_comment_clear(&vorbis_comment_); ogg_sync_clear(&ogg_sync_); + ogg_stream_clear(&ogg_stream_); } } @@ -57,52 +59,101 @@ size_t VorbisDecoder::decoded_sample_count(const void* frame_data, return frame_size * 8 / (nominal_bitrate / num_channels); } +bool VorbisDecoder::initialize_headers(const uint8_t* headers, size_t headers_size) { + roc_panic_if_not(headers); + + // Reset ogg_sync state to ensure clean reading + ogg_sync_reset(&ogg_sync_); + + // Add the combined headers to the ogg_sync state + add_data_to_ogg_sync_(headers, headers_size); + + // Process the headers to initialize decoder state + if (!read_headers_()) { + return false; + } + + headers_read_ = true; + return true; +} + void VorbisDecoder::begin_frame(packet::stream_timestamp_t frame_position, const void* frame_data, size_t frame_size) { roc_panic_if_not(initialized_); + reset_frame_state_(frame_position); + + add_data_to_ogg_sync_(frame_data, frame_size); + + process_frame_packets_(); +} + +size_t VorbisDecoder::read_samples(sample_t* samples, size_t n_samples) { + roc_panic("TODO"); + return 0; +} + +size_t VorbisDecoder::drop_samples(size_t n_samples) { + roc_panic("TODO"); + return 0; +} + +void VorbisDecoder::end_frame() { + roc_panic("TODO"); +} + +void VorbisDecoder::reset_frame_state_(packet::stream_timestamp_t frame_position) { current_position_ = frame_position; available_samples_ = 0; current_sample_pos_ = 0; total_samples_in_frame_ = 0; +} - // Ogg sync to handle the input data +void VorbisDecoder::add_data_to_ogg_sync_(const void* frame_data, size_t frame_size) { char* buffer = ogg_sync_buffer(&ogg_sync_, static_cast(frame_size)); memcpy(buffer, frame_data, frame_size); ogg_sync_wrote(&ogg_sync_, static_cast(frame_size)); +} - // Read headers if not already done - if (!headers_read_) { - ogg_page ogg_page; - while (ogg_sync_pageout(&ogg_sync_, &ogg_page) == 1) { - ogg_stream_pagein(&ogg_stream_, &ogg_page); - - ogg_packet header_packet; - while (ogg_stream_packetout(&ogg_stream_, &header_packet) == 1) { - if (vorbis_synthesis_idheader(&header_packet)) { - if (vorbis_synthesis_headerin(&vorbis_info_, &vorbis_comment_, - &header_packet) - < 0) { - roc_panic("vorbis decoder: invalid header packet"); - } - } +bool VorbisDecoder::read_headers_() { + ogg_page ogg_page; + int header_count = 0; - if (ogg_stream_packetout(&ogg_stream_, &header_packet) != 1) { - break; - } + // Loop to extract pages from the sync state + while (ogg_sync_pageout(&ogg_sync_, &ogg_page) == 1) { + if (ogg_stream_pagein(&ogg_stream_, &ogg_page) < 0) { + return false; + } + + ogg_packet header_packet; + + // Loop to extract packets from the stream state + while (ogg_stream_packetout(&ogg_stream_, &header_packet) == 1) { + // Pass the header to vorbis_synthesis_headerin regardless of type + if (vorbis_synthesis_headerin(&vorbis_info_, &vorbis_comment_, &header_packet) + < 0) { + return false; } - // Check if we have read all three headers - if (vorbis_synthesis_init(&vorbis_dsp_, &vorbis_info_) == 0) { - vorbis_block_init(&vorbis_dsp_, &vorbis_block_); - headers_read_ = true; - break; + header_count++; + + // After processing three headers, initialize DSP and block + if (header_count == 3) { + if (vorbis_synthesis_init(&vorbis_dsp_, &vorbis_info_) == 0) { + if (vorbis_block_init(&vorbis_dsp_, &vorbis_block_) == 0) { + headers_read_ = true; + return true; + } + } } } } - // Extract packets from the buffer + return false; +} + +void VorbisDecoder::process_frame_packets_() { ogg_page ogg_page; while (ogg_sync_pageout(&ogg_sync_, &ogg_page) == 1) { ogg_stream_pagein(&ogg_stream_, &ogg_page); @@ -112,20 +163,6 @@ void VorbisDecoder::begin_frame(packet::stream_timestamp_t frame_position, } } -size_t VorbisDecoder::read_samples(sample_t* samples, size_t n_samples) { - roc_panic("TODO"); - return 0; -} - -size_t VorbisDecoder::drop_samples(size_t n_samples) { - roc_panic("TODO"); - return 0; -} - -void VorbisDecoder::end_frame() { - roc_panic("TODO"); -} - void VorbisDecoder::process_packet_() { if (vorbis_synthesis(&vorbis_block_, ¤t_packet_) != 0) { return; diff --git a/src/internal_modules/roc_audio/target_libvorbis/roc_audio/vorbis_decoder.h b/src/internal_modules/roc_audio/target_libvorbis/roc_audio/vorbis_decoder.h index 607a92bc6..2fd984cdb 100644 --- a/src/internal_modules/roc_audio/target_libvorbis/roc_audio/vorbis_decoder.h +++ b/src/internal_modules/roc_audio/target_libvorbis/roc_audio/vorbis_decoder.h @@ -1,11 +1,3 @@ -/* - * Copyright (c) 2024 Roc Streaming authors - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. - */ - //! @file roc_audio/target_libvorbis/roc_audio/vorbis_decoder.h //! @brief Vorbis audio decoder. @@ -40,6 +32,9 @@ class VorbisDecoder : public IFrameDecoder { //! Get number of samples per channel that can be decoded from given frame. virtual size_t decoded_sample_count(const void* frame_data, size_t frame_size) const; + //! Initialize decoder with combined Vorbis headers. + bool initialize_headers(const uint8_t* headers, size_t headers_size); + //! Start decoding a new frame. virtual void begin_frame(packet::stream_timestamp_t frame_position, const void* frame_data, @@ -55,6 +50,10 @@ class VorbisDecoder : public IFrameDecoder { virtual void end_frame(); private: + void reset_frame_state_(packet::stream_timestamp_t frame_position); + void add_data_to_ogg_sync_(const void* frame_data, size_t frame_size); + bool read_headers_(); + void process_frame_packets_(); void process_packet_(); bool initialized_; From 2a54aaa90a84acc1efbe4a35626ab8497a0e2464 Mon Sep 17 00:00:00 2001 From: Leonardo Invernizzi Date: Tue, 27 Aug 2024 03:40:53 +0100 Subject: [PATCH 26/26] Fix --- .../roc_audio/target_libvorbis/roc_audio/vorbis_decoder.h | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/internal_modules/roc_audio/target_libvorbis/roc_audio/vorbis_decoder.h b/src/internal_modules/roc_audio/target_libvorbis/roc_audio/vorbis_decoder.h index 2fd984cdb..c3bea80f0 100644 --- a/src/internal_modules/roc_audio/target_libvorbis/roc_audio/vorbis_decoder.h +++ b/src/internal_modules/roc_audio/target_libvorbis/roc_audio/vorbis_decoder.h @@ -1,3 +1,11 @@ +/* + * Copyright (c) 2024 Roc Streaming authors + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + //! @file roc_audio/target_libvorbis/roc_audio/vorbis_decoder.h //! @brief Vorbis audio decoder.