// Copyright 2023 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef MEDIA_GPU_ANDROID_NDK_AUDIO_ENCODER_H_
#define MEDIA_GPU_ANDROID_NDK_AUDIO_ENCODER_H_
#include <memory>
#include "base/android/requires_api.h"
#include "base/thread_annotations.h"
#include "media/base/audio_bus.h"
#include "media/base/audio_encoder.h"
#include "media/base/audio_parameters.h"
#include "media/base/encoder_status.h"
#include "media/formats/mp4/aac.h"
#include "media/gpu/android/ndk_media_codec_wrapper.h"
#include "media/gpu/media_gpu_export.h"
namespace media {
class AudioTimestampHelper;
class ConvertingAudioFifo;
// This class uses the Android NDK (the AMediaCodec APIs) to encode audio.
// It only supports encoding AAC-LC.
// This class must be created, used and destroyed on the same runner; the
// unerlying NdkMediaCodecWrapper handles thread hops from the platform encoding
// thread to `task_runner_`.
// Note: calling flush() forces a lazy re-creation of the underlying
// `media_codec_` on the next Encode() call.
class REQUIRES_ANDROID_API(NDK_MEDIA_CODEC_MIN_API)
MEDIA_GPU_EXPORT NdkAudioEncoder : public AudioEncoder,
public NdkMediaCodecWrapper::Client {
public:
// `runner` - a task runner that will be used for all callbacks and external
// calls to this instance.
explicit NdkAudioEncoder(scoped_refptr<base::SequencedTaskRunner> runner);
NdkAudioEncoder(const NdkAudioEncoder&) = delete;
NdkAudioEncoder& operator=(const NdkAudioEncoder&) = delete;
~NdkAudioEncoder() override;
// AudioEncoder implementation.
void Initialize(const Options& options,
OutputCB output_callback,
EncoderStatusCB done_cb) override;
void Encode(std::unique_ptr<AudioBus> audio_bus,
base::TimeTicks capture_time,
EncoderStatusCB done_cb) override;
// Note: `media_codec_` will be destroyed after a successful flush, to be
// recreated with the same `options_` on the next Encode() call.
void Flush(EncoderStatusCB done_cb) override;
// MediaCodecWrapper::Client implementation.
void OnInputAvailable() override;
void OnOutputAvailable() override;
void OnError(media_status_t error) override;
private:
enum class FlushState {
kNone, // Not currently flushing.
kFlushingInputs, // There is remaining data in `fifo_` left to be fed.
kPendingEOS, // We are waiting for the EOS from the encoder.
kNeedsMediaCodec, // The flush completed, but we need to lazily recreate
// `media_codec_`.
};
bool CreateAndStartMediaCodec();
void ClearMediaCodec();
// Input functions.
void FeedAllInputs();
bool InputReady();
void FeedInput(const AudioBus* audio_bus);
// Flush() related functions.
void MaybeFeedEos();
void FeedEos();
void CompleteFlush();
// Output reading functions.
void DrainOutput();
bool DrainConfig();
// Logging and reporting functions.
void LogError(EncoderStatus status);
void LogAndReportError(EncoderStatus status, EncoderStatusCB done_cb);
void ReportPendingError(EncoderStatusCB done_cb);
void ReportOk(EncoderStatusCB done_cb);
SEQUENCE_CHECKER(sequence_checker_);
// A runner all for callbacks and externals calls to public methods.
const scoped_refptr<base::SequencedTaskRunner> task_runner_;
// The format of encoded chunks outputted through `output_cb_`.
AudioParameters output_params_;
bool error_occurred_ = false;
// Delayed error status to be reported on the next Encode() or Flush() call.
std::optional<EncoderStatus> pending_error_status_;
// What portion of the flushing process we are in, if any.
FlushState flush_state_ GUARDED_BY_CONTEXT(sequence_checker_) =
NdkAudioEncoder::FlushState::kNone;
// Pending callback for Initialize(), Encode() or Flush().
EncoderStatusCB pending_flush_cb_;
// All input received from Encode() not yet sent to `media_codec_`.
std::unique_ptr<ConvertingAudioFifo> fifo_
GUARDED_BY_CONTEXT(sequence_checker_);
std::unique_ptr<AudioTimestampHelper> input_timestamp_tracker_
GUARDED_BY_CONTEXT(sequence_checker_);
std::unique_ptr<AudioTimestampHelper> output_timestamp_tracker_
GUARDED_BY_CONTEXT(sequence_checker_);
std::vector<uint8_t> codec_desc_;
std::vector<uint8_t> temp_header_buffer_;
mp4::AAC aac_config_parser_;
// Platform encoder which actually performs the encoding.
std::unique_ptr<NdkMediaCodecWrapper> media_codec_;
};
} // namespace media
#endif // MEDIA_GPU_ANDROID_NDK_AUDIO_ENCODER_H_