chromium/media/gpu/android/ndk_audio_encoder.h

// 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_