Skip to content

Commit

Permalink
Add a class to house FLAC stream callback functions & implement the r…
Browse files Browse the repository at this point in the history
…ead callback.

These are necessary to use the FLAC stream decoder.

Also adds an encoded_frame_ field in flac_decoder.h which is used to store a single encoded frame at a time for later processing. This is necessary because flac stream uses callback functions. Getters & setters are added so that the call back functions can access the data as necessary.

PiperOrigin-RevId: 686183659
  • Loading branch information
Googler authored and felicialim committed Oct 16, 2024
1 parent f4e6706 commit 8db039f
Show file tree
Hide file tree
Showing 6 changed files with 211 additions and 1 deletion.
11 changes: 11 additions & 0 deletions iamf/cli/codec/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -193,3 +193,14 @@ cc_library(
"@com_google_absl//absl/status",
],
)

cc_library(
name = "flac_decoder_stream_callbacks",
srcs = ["flac_decoder_stream_callbacks.cc"],
hdrs = ["flac_decoder_stream_callbacks.h"],
deps = [
":flac_decoder",
"@com_google_absl//absl/log",
"@flac//:src",
],
)
17 changes: 16 additions & 1 deletion iamf/cli/codec/flac_decoder.h
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ class FlacDecoder : public DecoderBase {
*/
absl::Status Initialize() override;

/*!\brief Decodes a Flac audio frame.
/*!\brief Decodes a FLAC audio frame.
*
* \param encoded_frame Frame to decode.
* \param decoded_samples Output decoded frames arranged in (time, sample)
Expand All @@ -52,7 +52,22 @@ class FlacDecoder : public DecoderBase {
const std::vector<uint8_t>& encoded_frame,
std::vector<std::vector<int32_t>>& decoded_samples) override;

/*!\brief Sets an encoded FLAC frame in decoder.encoded_frame_.
*
* \param encoded_frame Encoded FLAC frame.
*/
void SetEncodedFrame(const std::vector<uint8_t>& encoded_frame) {
encoded_frame_ = encoded_frame;
}

/*!\brief Retrieves the encoded frame in decoder.encoded_frame_.
*
* \return Vector of encoded FLAC bytes representing a single frame.
*/
std::vector<uint8_t> GetEncodedFrame() const { return encoded_frame_; }

private:
std::vector<uint8_t> encoded_frame_ = {};
const FlacDecoderConfig decoder_config_;
};

Expand Down
47 changes: 47 additions & 0 deletions iamf/cli/codec/flac_decoder_stream_callbacks.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
/*
* Copyright (c) 2024, Alliance for Open Media. All rights reserved
*
* This source code is subject to the terms of the BSD 3-Clause Clear License
* and the Alliance for Open Media Patent License 1.0. If the BSD 3-Clause Clear
* License was not distributed with this source code in the LICENSE file, you
* can obtain it at www.aomedia.org/license/software-license/bsd-3-c-c. If the
* Alliance for Open Media Patent License 1.0 was not distributed with this
* source code in the PATENTS file, you can obtain it at
* www.aomedia.org/license/patent.
*/

#include "iamf/cli/codec/flac_decoder_stream_callbacks.h"

#include <cstddef>

#include "absl/log/log.h"
#include "iamf/cli/codec/flac_decoder.h"
#include "include/FLAC/ordinals.h"
#include "include/FLAC/stream_decoder.h"

namespace iamf_tools {

FLAC__StreamDecoderReadStatus LibFlacReadCallback(
const FLAC__StreamDecoder* /*decoder*/, FLAC__byte buffer[], size_t* bytes,
void* client_data) {
auto flac_decoder = static_cast<FlacDecoder*>(client_data);
const auto& encoded_frame = flac_decoder->GetEncodedFrame();
if (encoded_frame.empty()) {
// No more data to read.
*bytes = 0;
return FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM;
}
if (encoded_frame.size() > *bytes) {
LOG(ERROR) << "Encoded frame size " << encoded_frame.size()
<< " is larger than the libflac buffer size " << *bytes;
*bytes = 0;
return FLAC__STREAM_DECODER_READ_STATUS_ABORT;
}
for (int i = 0; i < encoded_frame.size(); ++i) {
buffer[i] = encoded_frame[i];
}
*bytes = encoded_frame.size();
return FLAC__STREAM_DECODER_READ_STATUS_CONTINUE;
}

} // namespace iamf_tools
43 changes: 43 additions & 0 deletions iamf/cli/codec/flac_decoder_stream_callbacks.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
/*
* Copyright (c) 2024, Alliance for Open Media. All rights reserved
*
* This source code is subject to the terms of the BSD 3-Clause Clear License
* and the Alliance for Open Media Patent License 1.0. If the BSD 3-Clause Clear
* License was not distributed with this source code in the LICENSE file, you
* can obtain it at www.aomedia.org/license/software-license/bsd-3-c-c. If the
* Alliance for Open Media Patent License 1.0 was not distributed with this
* source code in the PATENTS file, you can obtain it at
* www.aomedia.org/license/patent.
*/

#ifndef CLI_CODEC_FLAC_DECODER_STREAM_CALLBACKS_H_
#define CLI_CODEC_FLAC_DECODER_STREAM_CALLBACKS_H_

#include <cstddef>

#include "include/FLAC/ordinals.h"
#include "include/FLAC/stream_decoder.h"

namespace iamf_tools {
/*!\brief Reads an encoded flac frame into the libflac decoder
*
* This callback function is used whenever the decoder needs more input data.
*
* \param decoder libflac stream decoder
* This parameter is not used in this implementation, but is included to
* override the libflac signature.
* \param buffer Output buffer for the encoded frame.
* \param bytes Maximum size of the buffer; in the case of a successful read,
* this will be set to the actual number of bytes read.
* \param client_data universal pointer, which in this case should point to
* FlacDecoder.
*
* \return A libflac read status indicating whether the read was successful.
*/
FLAC__StreamDecoderReadStatus LibFlacReadCallback(
const FLAC__StreamDecoder* decoder, FLAC__byte buffer[], size_t* bytes,
void* client_data);

} // namespace iamf_tools

#endif // CLI_CODEC_FLAC_DECODER_STREAM_CALLBACKS_H_
14 changes: 14 additions & 0 deletions iamf/cli/codec/tests/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -116,3 +116,17 @@ cc_test(
"@com_google_googletest//:gtest_main",
],
)

cc_test(
name = "flac_decoder_stream_callbacks_test",
srcs = ["flac_decoder_stream_callbacks_test.cc"],
deps = [
"//iamf/cli/codec:flac_decoder",
"//iamf/cli/codec:flac_decoder_stream_callbacks",
"//iamf/obu:codec_config",
"//iamf/obu:obu_header",
"//iamf/obu/decoder_config:flac_decoder_config",
"@com_google_googletest//:gtest_main",
"@flac//:src",
],
)
80 changes: 80 additions & 0 deletions iamf/cli/codec/tests/flac_decoder_stream_callbacks_test.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
/*
* Copyright (c) 2024, Alliance for Open Media. All rights reserved
*
* This source code is subject to the terms of the BSD 3-Clause Clear License
* and the Alliance for Open Media Patent License 1.0. If the BSD 3-Clause Clear
* License was not distributed with this source code in the LICENSE file, you
* can obtain it at www.aomedia.org/license/software-license/bsd-3-c-c. If the
* Alliance for Open Media Patent License 1.0 was not distributed with this
* source code in the PATENTS file, you can obtain it at
* www.aomedia.org/license/patent.
*/

#include "iamf/cli/codec/flac_decoder_stream_callbacks.h"

#include <cstddef>
#include <cstdint>
#include <vector>

#include "gmock/gmock.h"
#include "gtest/gtest.h"
#include "iamf/cli/codec/flac_decoder.h"
#include "iamf/obu/codec_config.h"
#include "iamf/obu/decoder_config/flac_decoder_config.h"
#include "iamf/obu/obu_header.h"
#include "include/FLAC/ordinals.h"
#include "include/FLAC/stream_decoder.h"

namespace iamf_tools {
namespace {

using ::testing::ElementsAreArray;

class FlacDecoderStreamCallbacksTest : public testing::Test {
public:
FlacDecoderStreamCallbacksTest()
: flac_decoder_(FlacDecoder(
(CodecConfigObu(ObuHeader(), 0,
{.codec_id = CodecConfig::kCodecIdFlac,
.num_samples_per_frame = 1024,
.audio_roll_distance = -1,
.decoder_config = FlacDecoderConfig{}})),
/*num_channels=*/2)) {}

protected:
FlacDecoder flac_decoder_;
};

TEST_F(FlacDecoderStreamCallbacksTest, ReadCallbackEmptyFrame) {
FLAC__byte buffer[1024];
size_t bytes = 1024;
auto status = LibFlacReadCallback(/*stream_decoder=*/nullptr, buffer, &bytes,
&flac_decoder_);
EXPECT_EQ(status, FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM);
EXPECT_EQ(bytes, 0);
}

TEST_F(FlacDecoderStreamCallbacksTest, ReadCallbackFrameTooLarge) {
FLAC__byte buffer[1024];
size_t bytes = 1024;
flac_decoder_.SetEncodedFrame(std::vector<uint8_t>(1025));
auto status = LibFlacReadCallback(/*stream_decoder=*/nullptr, buffer, &bytes,
&flac_decoder_);
EXPECT_EQ(status, FLAC__STREAM_DECODER_READ_STATUS_ABORT);
EXPECT_EQ(bytes, 0);
}

TEST_F(FlacDecoderStreamCallbacksTest, ReadCallbackSuccess) {
FLAC__byte buffer[1024];
size_t bytes = 1028;
const std::vector<uint8_t> encoded_frame(1024, 1);
flac_decoder_.SetEncodedFrame(encoded_frame);
auto status = LibFlacReadCallback(/*stream_decoder=*/nullptr, buffer, &bytes,
&flac_decoder_);
EXPECT_EQ(status, FLAC__STREAM_DECODER_READ_STATUS_CONTINUE);
EXPECT_EQ(bytes, 1024);
EXPECT_THAT(buffer, ElementsAreArray(encoded_frame));
}

} // namespace
} // namespace iamf_tools

0 comments on commit 8db039f

Please sign in to comment.