diff --git a/iamf/cli/codec/flac_decoder.h b/iamf/cli/codec/flac_decoder.h index 186be8b..9c39505 100644 --- a/iamf/cli/codec/flac_decoder.h +++ b/iamf/cli/codec/flac_decoder.h @@ -66,8 +66,25 @@ class FlacDecoder : public DecoderBase { */ std::vector GetEncodedFrame() const { return encoded_frame_; } + /*!\brief Sets a decoded FLAC frame in decoder.decoded_frame_. + * + * \param decoded_frame Decoded FLAC frame. + */ + void SetDecodedFrame(const std::vector>& decoded_frame) { + decoded_frame_ = decoded_frame; + } + + /*!\brief Retrieves the decoded FLAC frame in decoder.decoded_frame_. + * + * \return Vector of decoded FLAC samples. + */ + std::vector> GetDecodedFrame() const { + return decoded_frame_; + } + private: std::vector encoded_frame_ = {}; + std::vector> decoded_frame_ = {}; const FlacDecoderConfig decoder_config_; }; diff --git a/iamf/cli/codec/flac_decoder_stream_callbacks.cc b/iamf/cli/codec/flac_decoder_stream_callbacks.cc index be07c35..e2aa2ea 100644 --- a/iamf/cli/codec/flac_decoder_stream_callbacks.cc +++ b/iamf/cli/codec/flac_decoder_stream_callbacks.cc @@ -13,9 +13,12 @@ #include "iamf/cli/codec/flac_decoder_stream_callbacks.h" #include +#include +#include #include "absl/log/log.h" #include "iamf/cli/codec/flac_decoder.h" +#include "include/FLAC/format.h" #include "include/FLAC/ordinals.h" #include "include/FLAC/stream_decoder.h" @@ -44,4 +47,23 @@ FLAC__StreamDecoderReadStatus LibFlacReadCallback( return FLAC__STREAM_DECODER_READ_STATUS_CONTINUE; } +FLAC__StreamDecoderWriteStatus LibFlacWriteCallback( + const FLAC__StreamDecoder* /*decoder*/, const FLAC__Frame* frame, + const FLAC__int32* const buffer[], void* client_data) { + std::vector> decoded_samples(frame->header.channels); + auto* flac_decoder = static_cast(client_data); + const auto num_samples_per_channel = frame->header.blocksize; + // Note: libFLAC represents data in a planar fashion, so each channel is + // stored in a separate array. + for (int i = 0; i < frame->header.channels; ++i) { + decoded_samples[i].resize(num_samples_per_channel); + const FLAC__int32* const channel_buffer = buffer[i]; + for (int j = 0; j < num_samples_per_channel; ++j) { + decoded_samples[i][j] = static_cast(channel_buffer[j]); + } + } + flac_decoder->SetDecodedFrame(decoded_samples); + return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE; +} + } // namespace iamf_tools diff --git a/iamf/cli/codec/flac_decoder_stream_callbacks.h b/iamf/cli/codec/flac_decoder_stream_callbacks.h index 1419217..b2bee33 100644 --- a/iamf/cli/codec/flac_decoder_stream_callbacks.h +++ b/iamf/cli/codec/flac_decoder_stream_callbacks.h @@ -15,6 +15,7 @@ #include +#include "include/FLAC/format.h" #include "include/FLAC/ordinals.h" #include "include/FLAC/stream_decoder.h" @@ -38,6 +39,28 @@ FLAC__StreamDecoderReadStatus LibFlacReadCallback( const FLAC__StreamDecoder* decoder, FLAC__byte buffer[], size_t* bytes, void* client_data); +/*!\brief Writes a decoded flac frame to an instance of FlacDecoder. + * + * This callback function is used to write out a decoded frame from the libflac + * decoder. + * + * \param decoder Unused libflac stream decoder. This parameter is not used in + * this implementation, but is included to override the libflac + * signature. + * \param frame libflac encoded frame metadata. + * \param buffer Array of pointers to decoded channels of data. Each pointer + * will point to an array of signed samples of length + * `frame->header.blocksize`. Channels will be ordered according to the + * FLAC specification. + * \param client_data Universal pointer, which in this case should point to + * FlacDecoder. + * + * \return A libflac write status indicating whether the write was successful. + */ +FLAC__StreamDecoderWriteStatus LibFlacWriteCallback( + const FLAC__StreamDecoder* /*decoder*/, const FLAC__Frame* frame, + const FLAC__int32* const buffer[], void* client_data); + } // namespace iamf_tools #endif // CLI_CODEC_FLAC_DECODER_STREAM_CALLBACKS_H_ diff --git a/iamf/cli/codec/tests/flac_decoder_stream_callbacks_test.cc b/iamf/cli/codec/tests/flac_decoder_stream_callbacks_test.cc index 693fec3..c77e064 100644 --- a/iamf/cli/codec/tests/flac_decoder_stream_callbacks_test.cc +++ b/iamf/cli/codec/tests/flac_decoder_stream_callbacks_test.cc @@ -22,6 +22,7 @@ #include "iamf/obu/codec_config.h" #include "iamf/obu/decoder_config/flac_decoder_config.h" #include "iamf/obu/obu_header.h" +#include "include/FLAC/format.h" #include "include/FLAC/ordinals.h" #include "include/FLAC/stream_decoder.h" @@ -76,5 +77,37 @@ TEST_F(FlacDecoderStreamCallbacksTest, ReadCallbackSuccess) { EXPECT_THAT(buffer, ElementsAreArray(encoded_frame)); } +TEST_F(FlacDecoderStreamCallbacksTest, WriteCallbackSuccess32BitSamples) { + FLAC__Frame frame; + frame.header.channels = 2; + frame.header.blocksize = 3; + frame.header.bits_per_sample = 32; + FLAC__int32 channel_0[] = {1, 0x7fffffff, 3}; + FLAC__int32 channel_1[] = {2, 3, 4}; + const FLAC__int32 *const buffer[] = {channel_0, channel_1}; + auto status = LibFlacWriteCallback(/*stream_decoder=*/nullptr, &frame, buffer, + &flac_decoder_); + EXPECT_EQ(status, FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE); + EXPECT_THAT(flac_decoder_.GetDecodedFrame(), + ElementsAreArray(std::vector>( + {{1, 0x7fffffff, 3}, {2, 3, 4}}))); +} + +TEST_F(FlacDecoderStreamCallbacksTest, WriteCallbackSuccess16BitSamples) { + FLAC__Frame frame; + frame.header.channels = 2; + frame.header.blocksize = 2; + frame.header.bits_per_sample = 16; + FLAC__int32 channel_0[] = {0x11110000, 0x7fff0000}; + FLAC__int32 channel_1[] = {0x01010000, 0x22220000}; + const FLAC__int32 *const buffer[] = {channel_0, channel_1}; + auto status = LibFlacWriteCallback(/*stream_decoder=*/nullptr, &frame, buffer, + &flac_decoder_); + EXPECT_EQ(status, FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE); + EXPECT_THAT(flac_decoder_.GetDecodedFrame(), + ElementsAreArray(std::vector>( + {{0x11110000, 0x7fff0000}, {0x01010000, 0x22220000}}))); +} + } // namespace } // namespace iamf_tools