1
    2
    3
    4
    5
    6
    7
    8
    9
   10
   11
   12
   13
   14
   15
   16
   17
   18
   19
   20
   21
   22
   23
   24
   25
   26
   27
   28
   29
   30
   31
   32
   33
   34
   35
   36
   37
   38
   39
   40
   41
   42
   43
   44
   45
   46
   47
   48
   49
   50
   51
   52
   53
   54
   55
   56
   57
   58
   59
   60
   61
   62
   63
   64
   65
   66
   67
   68
   69
   70
   71
   72
   73
   74
   75
   76
   77
   78
   79
   80
   81
   82
   83
   84
   85
   86
   87
   88
   89
   90
   91
   92
   93
   94
   95
   96
   97
   98
   99
  100
  101
  102
  103
  104
  105
  106
  107
  108
  109
  110
  111
  112
  113
  114
  115
  116
  117
  118
  119
  120
  121
  122
  123
  124
  125
  126
  127
  128
  129
  130
  131
  132
  133
  134

media / gpu / android / ndk_audio_encoder.h [blame]

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