parent
b5d86a9497
commit
62d51a304e
File diff suppressed because it is too large
Load Diff
@ -1,297 +0,0 @@ |
||||
/*
|
||||
* libfoxenflac -- Tiny FLAC Decoder Library |
||||
* Copyright (C) 2018-2022 Andreas Stöckel |
||||
* |
||||
* This program is free software: you can redistribute it and/or modify |
||||
* it under the terms of the GNU General Public License as published by |
||||
* the Free Software Foundation; either version 2 of the License, or |
||||
* (at your option) any later version. |
||||
* |
||||
* This program is distributed in the hope that it will be useful, |
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
* GNU General Public License for more details. |
||||
* |
||||
* You should have received a copy of the GNU General Public License |
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/ |
||||
|
||||
/**
|
||||
* @file flac.h |
||||
* |
||||
* Provides a decoder for FLAC (Free Lossless Audio Codec). |
||||
* |
||||
* @author Andreas Stöckel |
||||
*/ |
||||
|
||||
#ifndef FOXEN_FLAC_H |
||||
#define FOXEN_FLAC_H |
||||
|
||||
#include <stdint.h> |
||||
|
||||
#ifndef FX_EXPORT |
||||
#if __EMSCRIPTEN__ |
||||
#import <emscripten.h> |
||||
#define FX_EXPORT EMSCRIPTEN_KEEPALIVE |
||||
#else |
||||
#define FX_EXPORT |
||||
#endif /* __EMSCRIPTEN__ */ |
||||
#endif /* FX_EXPORT */ |
||||
|
||||
#ifdef __cplusplus |
||||
extern "C" { |
||||
#endif |
||||
|
||||
/**
|
||||
* Value returned by the fx_flac_get_streaminfo() method if the given streaminfo |
||||
* key is invalid. |
||||
*/ |
||||
#define FLAC_INVALID_METADATA_KEY 0x7FFFFFFFFFFFFFFFULL |
||||
|
||||
/**
|
||||
* Maximum number of channels that can be encoded in a FLAC stream. |
||||
*/ |
||||
#define FLAC_MAX_CHANNEL_COUNT 8U |
||||
|
||||
/**
|
||||
* Maximum block size that can be used if the stream is encoded in the FLAC |
||||
* Subset format and the sample rate is smaller than 48000 kHz. |
||||
*/ |
||||
#define FLAC_SUBSET_MAX_BLOCK_SIZE_48KHZ 4608U |
||||
|
||||
/**
|
||||
* Maximum block size than can always be safely used if the stream is encoded |
||||
* in the FLAC Subset format. |
||||
*/ |
||||
#define FLAC_SUBSET_MAX_BLOCK_SIZE 16384U |
||||
|
||||
/**
|
||||
* Maximum block size in samples that can be used in a FLAC stream. |
||||
*/ |
||||
#define FLAC_MAX_BLOCK_SIZE 65535U |
||||
|
||||
/**
|
||||
* Opaque struct representing a FLAC decoder. |
||||
*/ |
||||
struct fx_flac; |
||||
|
||||
/**
|
||||
* Typedef for the fx_flac struct. |
||||
*/ |
||||
typedef struct fx_flac fx_flac_t; |
||||
|
||||
/**
|
||||
* Enum representing the state of a FLAC decoder instance. |
||||
*/ |
||||
typedef enum { |
||||
/**
|
||||
* The decoder is in an error state; the decoder cannot recover from this |
||||
* error. This error may for example occur if the data in the stream is |
||||
* invalid, or the stream has a format that is outside the maximum specs |
||||
* that are supported by the decoder. Call fx_flac_reset() and start anew! |
||||
*/ |
||||
FLAC_ERR = -1, |
||||
|
||||
/**
|
||||
* The decoder is currently in its initial state, fx_flac_process() has not |
||||
* been called. |
||||
*/ |
||||
FLAC_INIT = 0, |
||||
|
||||
/**
|
||||
* The decoder found the beginning of the metadata packet! |
||||
*/ |
||||
FLAC_IN_METADATA = 1, |
||||
|
||||
/**
|
||||
* The decoder is done reading the current metadata block, this may be |
||||
* followed by more metadata blocks, in which case the state is reset to |
||||
* FLAC_IN_METADATA. |
||||
*/ |
||||
FLAC_END_OF_METADATA = 2, |
||||
|
||||
/**
|
||||
* The decoder is currently searching for an audio frame. |
||||
*/ |
||||
FLAC_SEARCH_FRAME = 3, |
||||
|
||||
/**
|
||||
* The decoder is currently inside the stream of audio frames. |
||||
*/ |
||||
FLAC_IN_FRAME = 4, |
||||
|
||||
/**
|
||||
* The decoder successfully decoded an entire frame. Write the data to the |
||||
* client. |
||||
*/ |
||||
FLAC_DECODED_FRAME = 5, |
||||
|
||||
/**
|
||||
* The decoder reached the end of a block. |
||||
*/ |
||||
FLAC_END_OF_FRAME = 6 |
||||
} fx_flac_state_t; |
||||
|
||||
/**
|
||||
* Enum used in fx_flac_get_streaminfo() to query metadata about the stream. |
||||
*/ |
||||
typedef enum { |
||||
FLAC_KEY_MIN_BLOCK_SIZE = 0, |
||||
FLAC_KEY_MAX_BLOCK_SIZE = 1, |
||||
FLAC_KEY_MIN_FRAME_SIZE = 2, |
||||
FLAC_KEY_MAX_FRAME_SIZE = 3, |
||||
FLAC_KEY_SAMPLE_RATE = 4, |
||||
FLAC_KEY_N_CHANNELS = 5, |
||||
FLAC_KEY_SAMPLE_SIZE = 6, |
||||
FLAC_KEY_N_SAMPLES = 7, |
||||
FLAC_KEY_MD5_SUM_0 = 128, |
||||
FLAC_KEY_MD5_SUM_1 = 129, |
||||
FLAC_KEY_MD5_SUM_2 = 130, |
||||
FLAC_KEY_MD5_SUM_3 = 131, |
||||
FLAC_KEY_MD5_SUM_4 = 132, |
||||
FLAC_KEY_MD5_SUM_5 = 133, |
||||
FLAC_KEY_MD5_SUM_6 = 134, |
||||
FLAC_KEY_MD5_SUM_7 = 135, |
||||
FLAC_KEY_MD5_SUM_8 = 136, |
||||
FLAC_KEY_MD5_SUM_9 = 137, |
||||
FLAC_KEY_MD5_SUM_A = 138, |
||||
FLAC_KEY_MD5_SUM_B = 139, |
||||
FLAC_KEY_MD5_SUM_C = 140, |
||||
FLAC_KEY_MD5_SUM_D = 141, |
||||
FLAC_KEY_MD5_SUM_E = 142, |
||||
FLAC_KEY_MD5_SUM_F = 143, |
||||
} fx_flac_streaminfo_key_t; |
||||
|
||||
/**
|
||||
* Returns the size of the FLAC decoder instance in bytes. This assumes that the |
||||
* FLAC audio that is being decoded uses the maximum settings, i.e. the largest |
||||
* bit depth and block size. See fx_flac_init() regarding parameters. |
||||
* |
||||
* @return zero if the given parameters are out of range, the number of bytes |
||||
* required to hold the FLAC decoder structure otherwise. |
||||
*/ |
||||
FX_EXPORT uint32_t fx_flac_size(uint32_t max_block_size, uint8_t max_channels); |
||||
|
||||
/**
|
||||
* Initializes the FLAC decoder at the given memory location. Each decoder can |
||||
* decode exactly one stream at a time. |
||||
* |
||||
* @param mem is a pointer at the memory region at which the FLAC decoder should |
||||
* store its private data. The memory region must be at last as large as |
||||
* indicated by fx_flac_size(). May be NULL, in which case NULL is returned. |
||||
* @param max_block_size is the maximum block size for which the FLAC instance |
||||
* will provide a buffer. For streams in the Subset format (which is used per |
||||
* default in most FLAC encoders), max_block_size should can be set to 4608 if |
||||
* the sample rate is <= 48000kHz, otherwise, for larger sample rates, |
||||
* max_block_size must be set to 16384. |
||||
* @param max_channels is the maximum number of channels that will be decoded. |
||||
* @return a pointer at the FLAC decoder instance; note that this pointer may be |
||||
* different from what was passed to mem. However, you may still pass the |
||||
* original `mem` as `inst` parameter to other functions. Returns NULL if the |
||||
* input pointer is NULL or the given parameters are invalid. |
||||
*/ |
||||
FX_EXPORT fx_flac_t *fx_flac_init(void *mem, uint16_t max_block_size, |
||||
uint8_t max_channels); |
||||
|
||||
/**
|
||||
* Macro which calls malloc to allocate memory for a new fx_flac instance. The |
||||
* returned pointer must be freed using free. Returns NULL if the allocation |
||||
* fails or the given parameters are invalid. |
||||
* |
||||
* Note that this code is implemented as a macro to prevent explicitly having |
||||
* a dependency on malloc while still providing a convenient allocation routine. |
||||
*/ |
||||
#define FX_FLAC_ALLOC(max_block_size, max_channels) \ |
||||
(fx_flac_size((max_block_size), (max_channels)) == 0U) \
|
||||
? NULL \
|
||||
: fx_flac_init(malloc(fx_flac_size((max_block_size), (max_channels))), \
|
||||
(max_block_size), (max_channels)) |
||||
|
||||
/**
|
||||
* Returns a new fx_flac instance that is sufficient to decode FLAC streams in |
||||
* the FLAC Subset format with DAT parameters, i.e. up to 48 kHz, and two |
||||
* channels. This will allocate about 40 kiB of memory. |
||||
*/ |
||||
#define FX_FLAC_ALLOC_SUBSET_FORMAT_DAT() \ |
||||
FX_FLAC_ALLOC(FLAC_SUBSET_MAX_BLOCK_SIZE_48KHZ, 2U) |
||||
|
||||
/**
|
||||
* Returns a new fx_flac instance that is sufficient to decode FLAC streams in |
||||
* the FLAC Subset format. This will allocate about 1.5 MiB of memory. |
||||
*/ |
||||
#define FX_FLAC_ALLOC_SUBSET_FORMAT_ANY() \ |
||||
FX_FLAC_ALLOC(FLAC_SUBSET_MAX_BLOCK_SIZE, FLAC_MAX_CHANNEL_COUNT) |
||||
|
||||
/**
|
||||
* Returns a new fx_flac instance that is sufficient to decode any valid FLAC |
||||
* stream. Note that this will allocate between 2-3 MiB of memory. |
||||
*/ |
||||
#define FX_FLAC_ALLOC_DEFAULT() \ |
||||
FX_FLAC_ALLOC(FLAC_MAX_BLOCK_SIZE, FLAC_MAX_CHANNEL_COUNT) |
||||
|
||||
/**
|
||||
* Resets the FLAC decoder. |
||||
* |
||||
* @param inst is the FLAC decoder that should be reset. |
||||
*/ |
||||
FX_EXPORT void fx_flac_reset(fx_flac_t *inst); |
||||
|
||||
/**
|
||||
* Returns the current decoder state. |
||||
* |
||||
* @param inst is the FLAC decoder instance for which the state should be |
||||
* returned. |
||||
* @return the current state of the decoder. |
||||
*/ |
||||
FX_EXPORT fx_flac_state_t fx_flac_get_state(const fx_flac_t *inst); |
||||
|
||||
/**
|
||||
* Returns metadata about the FLAC stream that is currently being parsed. This |
||||
* function may only be called if the decoder is in the state |
||||
* FLAC_END_OF_METADATA or greater, otherwise the result may be undefined |
||||
* (it will likely return zero for most of the metadata keys). |
||||
* |
||||
* @param inst is a pointer at the FLAC decoder instance for which the metadata |
||||
* should be retrieved. |
||||
* @param key is the metadata that should be retrieved. |
||||
* @return the requested metadata value or FLAC_INVALID_METADATA_KEY if the |
||||
* given key is unknown. |
||||
*/ |
||||
FX_EXPORT int64_t fx_flac_get_streaminfo(const fx_flac_t *inst, |
||||
fx_flac_streaminfo_key_t key); |
||||
|
||||
/**
|
||||
* Decodes the given raw FLAC data; the given data must be RAW FLAC data as |
||||
* specified in the FLAC format specification https://xiph.org/flac/format.html
|
||||
* This function will always return right after the decoder transitions to a new |
||||
* relevant state. |
||||
* |
||||
* @param inst is the decoder instance. |
||||
* @param in is a pointer at the encoded bytestream. |
||||
* @param in_len is a pointer at a integer containing the number of valid bytes |
||||
* in "in". After the function returns, in will contain the number of bytes that |
||||
* were actually read. This number may be zero if the decoder is in the FLAC_ERR |
||||
* or FLAC_STREAM_DONE state, or the internal buffers are full and need to be |
||||
* flushed to the provided output first. |
||||
* @param out is a pointer at a memory region that will accept the decoded |
||||
* interleaved audio data. Samples are decoded as 32-bit signed integer; the |
||||
* minimum and maximum value will depend on the original bit depth of the audio |
||||
* stored in the bitstream. If this is NULL, the decoder will silently discard |
||||
* the output. |
||||
* @param out_len is a pointer at an integer containing the number of available |
||||
* signed 32-bit integers at the memory address pointed at by out. After the |
||||
* function returns, this value will contain the number of samples that were |
||||
* written. If this is NULL, the deocder will silently discard the output. |
||||
* @return the current state of the decoder. If the state transitions to |
||||
* FLAC_END_OF_METADATA, FLAC_END_OF_FRAME or FLAC_END_OF_STREAM this function |
||||
* will return immediately; only the data up to the point causing the transition |
||||
* has been read. |
||||
*/ |
||||
FX_EXPORT fx_flac_state_t fx_flac_process(fx_flac_t *inst, const uint8_t *in, |
||||
uint32_t *in_len, int32_t *out, |
||||
uint32_t *out_len); |
||||
|
||||
#ifdef __cplusplus |
||||
} |
||||
#endif |
||||
#endif /* FOXEN_FLAC_H */ |
@ -1,8 +1,4 @@ |
||||
# Copyright 2023 jacqueline <me@jacqueline.id.au> |
||||
# |
||||
# SPDX-License-Identifier: GPL-3.0-only |
||||
|
||||
idf_component_register( |
||||
SRCS "flac.c" |
||||
INCLUDE_DIRS "include" |
||||
) |
||||
idf_component_register(SRCS miniflac.c INCLUDE_DIRS .) |
@ -0,0 +1,5 @@ |
||||
#define MINIFLAC_IMPLEMENTATION |
||||
#define MINIFLAC_API |
||||
#define MINIFLAC_PRIVATE static inline |
||||
|
||||
#include "miniflac.h" |
File diff suppressed because it is too large
Load Diff
@ -1,110 +0,0 @@ |
||||
/*
|
||||
* Copyright 2023 jacqueline <me@jacqueline.id.au> |
||||
* |
||||
* SPDX-License-Identifier: GPL-3.0-only |
||||
*/ |
||||
|
||||
#include "foxenflac.hpp" |
||||
#include <stdint.h> |
||||
#include <sys/_stdint.h> |
||||
|
||||
#include <cstdlib> |
||||
|
||||
#include "esp_log.h" |
||||
#include "foxen/flac.h" |
||||
#include "sample.hpp" |
||||
|
||||
namespace codecs { |
||||
|
||||
[[maybe_unused]] static const char kTag[] = "flac"; |
||||
|
||||
FoxenFlacDecoder::FoxenFlacDecoder() |
||||
: input_(), |
||||
buffer_(), |
||||
flac_(fx_flac_init( |
||||
heap_caps_malloc(fx_flac_size(FLAC_SUBSET_MAX_BLOCK_SIZE_48KHZ, 2), |
||||
MALLOC_CAP_SPIRAM), |
||||
FLAC_SUBSET_MAX_BLOCK_SIZE_48KHZ, |
||||
2)) {} |
||||
|
||||
FoxenFlacDecoder::~FoxenFlacDecoder() { |
||||
free(flac_); |
||||
} |
||||
|
||||
auto FoxenFlacDecoder::OpenStream(std::shared_ptr<IStream> input) |
||||
-> cpp::result<OutputFormat, Error> { |
||||
input_ = input; |
||||
|
||||
bool eof = false; |
||||
fx_flac_state_t state; |
||||
do { |
||||
eof = buffer_.Refill(input_.get()); |
||||
buffer_.ConsumeBytes([&](cpp::span<std::byte> buf) -> size_t { |
||||
uint32_t bytes_used = buf.size(); |
||||
state = |
||||
fx_flac_process(flac_, reinterpret_cast<const uint8_t*>(buf.data()), |
||||
&bytes_used, NULL, NULL); |
||||
return bytes_used; |
||||
}); |
||||
} while (state != FLAC_END_OF_METADATA && !eof); |
||||
|
||||
if (state != FLAC_END_OF_METADATA) { |
||||
if (state == FLAC_ERR) { |
||||
return cpp::fail(Error::kMalformedData); |
||||
} else { |
||||
return cpp::fail(Error::kOutOfInput); |
||||
} |
||||
} |
||||
|
||||
int64_t channels = fx_flac_get_streaminfo(flac_, FLAC_KEY_N_CHANNELS); |
||||
int64_t fs = fx_flac_get_streaminfo(flac_, FLAC_KEY_SAMPLE_RATE); |
||||
if (channels == FLAC_INVALID_METADATA_KEY || |
||||
fs == FLAC_INVALID_METADATA_KEY) { |
||||
return cpp::fail(Error::kMalformedData); |
||||
} |
||||
|
||||
OutputFormat format{ |
||||
.num_channels = static_cast<uint8_t>(channels), |
||||
.sample_rate_hz = static_cast<uint32_t>(fs), |
||||
}; |
||||
|
||||
uint64_t num_samples = fx_flac_get_streaminfo(flac_, FLAC_KEY_N_SAMPLES); |
||||
if (num_samples > 0) { |
||||
format.total_samples = num_samples * channels; |
||||
} |
||||
|
||||
return format; |
||||
} |
||||
|
||||
auto FoxenFlacDecoder::DecodeTo(cpp::span<sample::Sample> output) |
||||
-> cpp::result<OutputInfo, Error> { |
||||
bool is_eof = buffer_.Refill(input_.get()); |
||||
|
||||
cpp::span<int32_t> output32{reinterpret_cast<int32_t*>(output.data()), |
||||
output.size() / 2}; |
||||
uint32_t samples_written = output32.size(); |
||||
|
||||
fx_flac_state_t state; |
||||
buffer_.ConsumeBytes([&](cpp::span<std::byte> buf) -> size_t { |
||||
uint32_t bytes_read = buf.size_bytes(); |
||||
state = fx_flac_process(flac_, reinterpret_cast<const uint8_t*>(buf.data()), |
||||
&bytes_read, output32.data(), &samples_written); |
||||
return bytes_read; |
||||
}); |
||||
if (state == FLAC_ERR) { |
||||
return cpp::fail(Error::kMalformedData); |
||||
} |
||||
|
||||
for (size_t i = 0; i < samples_written; i++) { |
||||
output[i] = output32[i] >> 16; |
||||
} |
||||
|
||||
return OutputInfo{.samples_written = samples_written, |
||||
.is_stream_finished = samples_written == 0 && is_eof}; |
||||
} |
||||
|
||||
auto FoxenFlacDecoder::SeekTo(size_t target) -> cpp::result<void, Error> { |
||||
return {}; |
||||
} |
||||
|
||||
} // namespace codecs
|
@ -0,0 +1,176 @@ |
||||
/*
|
||||
* Copyright 2023 jacqueline <me@jacqueline.id.au> |
||||
* |
||||
* SPDX-License-Identifier: GPL-3.0-only |
||||
*/ |
||||
|
||||
#include "miniflac.hpp" |
||||
#include <stdint.h> |
||||
#include <sys/_stdint.h> |
||||
|
||||
#include <cstdlib> |
||||
|
||||
#include "esp_heap_caps.h" |
||||
#include "esp_log.h" |
||||
#include "miniflac.h" |
||||
#include "result.hpp" |
||||
#include "sample.hpp" |
||||
|
||||
namespace codecs { |
||||
|
||||
[[maybe_unused]] static const char kTag[] = "flac"; |
||||
|
||||
static constexpr size_t kMaxFrameSize = 4608; |
||||
|
||||
MiniFlacDecoder::MiniFlacDecoder() |
||||
: input_(), |
||||
buffer_(), |
||||
flac_(reinterpret_cast<miniflac_t*>( |
||||
heap_caps_malloc(sizeof(miniflac_t), |
||||
MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT))), |
||||
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 :(
|
||||
samples_by_channel_[i] = reinterpret_cast<int32_t*>( |
||||
heap_caps_malloc(kMaxFrameSize * sizeof(int32_t), MALLOC_CAP_SPIRAM)); |
||||
} |
||||
} |
||||
|
||||
MiniFlacDecoder::~MiniFlacDecoder() { |
||||
for (int i = 0; i < samples_by_channel_.size(); i++) { |
||||
heap_caps_free(samples_by_channel_[i]); |
||||
} |
||||
} |
||||
|
||||
auto MiniFlacDecoder::OpenStream(std::shared_ptr<IStream> input) |
||||
-> cpp::result<OutputFormat, Error> { |
||||
input_ = input; |
||||
|
||||
MINIFLAC_RESULT res; |
||||
auto read_until_result = [&](auto fn) { |
||||
while (true) { |
||||
bool eof = buffer_.Refill(input_.get()); |
||||
buffer_.ConsumeBytes(fn); |
||||
if (res == MINIFLAC_CONTINUE && !eof) { |
||||
continue; |
||||
} |
||||
break; |
||||
} |
||||
}; |
||||
|
||||
uint32_t sample_rate = 0; |
||||
|
||||
read_until_result([&](cpp::span<std::byte> buf) -> size_t { |
||||
uint32_t bytes_used = 0; |
||||
res = miniflac_streaminfo_sample_rate( |
||||
flac_.get(), reinterpret_cast<const uint8_t*>(buf.data()), |
||||
buf.size_bytes(), &bytes_used, &sample_rate); |
||||
return bytes_used; |
||||
}); |
||||
|
||||
if (res != MINIFLAC_OK) { |
||||
return cpp::fail(Error::kMalformedData); |
||||
} |
||||
|
||||
uint8_t channels = 0; |
||||
|
||||
read_until_result([&](cpp::span<std::byte> buf) -> size_t { |
||||
uint32_t bytes_used = 0; |
||||
res = miniflac_streaminfo_channels( |
||||
flac_.get(), reinterpret_cast<const uint8_t*>(buf.data()), |
||||
buf.size_bytes(), &bytes_used, &channels); |
||||
return bytes_used; |
||||
}); |
||||
|
||||
if (res != MINIFLAC_OK) { |
||||
return cpp::fail(Error::kMalformedData); |
||||
} |
||||
|
||||
uint64_t total_samples = 0; |
||||
|
||||
read_until_result([&](cpp::span<std::byte> buf) -> size_t { |
||||
uint32_t bytes_used = 0; |
||||
res = miniflac_streaminfo_total_samples( |
||||
flac_.get(), reinterpret_cast<const uint8_t*>(buf.data()), |
||||
buf.size_bytes(), &bytes_used, &total_samples); |
||||
return bytes_used; |
||||
}); |
||||
|
||||
if (res != MINIFLAC_OK) { |
||||
return cpp::fail(Error::kMalformedData); |
||||
} |
||||
|
||||
if (channels == 0 || channels > 2) { |
||||
return cpp::fail(Error::kMalformedData); |
||||
} |
||||
|
||||
OutputFormat format{ |
||||
.num_channels = static_cast<uint8_t>(channels), |
||||
.sample_rate_hz = static_cast<uint32_t>(sample_rate), |
||||
.total_samples = total_samples * channels, |
||||
}; |
||||
|
||||
return format; |
||||
} |
||||
|
||||
auto MiniFlacDecoder::DecodeTo(cpp::span<sample::Sample> output) |
||||
-> cpp::result<OutputInfo, Error> { |
||||
bool is_eof = false; |
||||
|
||||
if (!current_sample_) { |
||||
MINIFLAC_RESULT res = MINIFLAC_CONTINUE; |
||||
while (res == MINIFLAC_CONTINUE && !is_eof) { |
||||
is_eof = buffer_.Refill(input_.get()); |
||||
buffer_.ConsumeBytes([&](cpp::span<std::byte> buf) -> size_t { |
||||
// FIXME: We should do a miniflac_sync first, in order to check that
|
||||
// our sample buffers have enough space for the next frame.
|
||||
uint32_t bytes_read = 0; |
||||
res = miniflac_decode( |
||||
flac_.get(), reinterpret_cast<const uint8_t*>(buf.data()), |
||||
buf.size_bytes(), &bytes_read, samples_by_channel_.data()); |
||||
return bytes_read; |
||||
}); |
||||
} |
||||
|
||||
if (res == MINIFLAC_OK) { |
||||
current_sample_ = 0; |
||||
} else if (is_eof) { |
||||
return OutputInfo{ |
||||
.samples_written = 0, |
||||
.is_stream_finished = true, |
||||
}; |
||||
} else { |
||||
return cpp::fail(Error::kMalformedData); |
||||
} |
||||
} |
||||
|
||||
size_t samples_written = 0; |
||||
if (current_sample_) { |
||||
const uint8_t shift = flac_->frame.header.bps - 16; |
||||
|
||||
while (*current_sample_ < flac_->frame.header.block_size) { |
||||
if (samples_written + flac_->frame.header.channels >= output.size()) { |
||||
// We can't fit the next full PCM frame into the buffer.
|
||||
return OutputInfo{.samples_written = samples_written, |
||||
.is_stream_finished = false}; |
||||
} |
||||
|
||||
for (int channel = 0; channel < flac_->frame.header.channels; channel++) { |
||||
output[samples_written++] = sample::FromSigned( |
||||
samples_by_channel_[channel][*current_sample_] >> shift, 16); |
||||
} |
||||
(*current_sample_)++; |
||||
} |
||||
} |
||||
|
||||
current_sample_.reset(); |
||||
return OutputInfo{.samples_written = samples_written, |
||||
.is_stream_finished = samples_written == 0 && is_eof}; |
||||
} |
||||
|
||||
auto MiniFlacDecoder::SeekTo(size_t target) -> cpp::result<void, Error> { |
||||
return {}; |
||||
} |
||||
|
||||
} // namespace codecs
|
Loading…
Reference in new issue