chromium/chromeos/ash/services/recording/recording_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 CHROMEOS_ASH_SERVICES_RECORDING_RECORDING_ENCODER_H_
#define CHROMEOS_ASH_SERVICES_RECORDING_RECORDING_ENCODER_H_

#include "base/functional/callback_forward.h"
#include "base/memory/scoped_refptr.h"
#include "base/sequence_checker.h"
#include "base/thread_annotations.h"
#include "base/time/time.h"
#include "chromeos/ash/services/recording/recording_file_io_helper.h"
#include "chromeos/ash/services/recording/rgb_video_frame.h"
#include "media/base/encoder_status.h"
#include "media/base/video_encoder.h"
#include "media/base/video_types.h"

namespace media {
class AudioBus;
class VideoFrame;
}  // namespace media

namespace recording {

namespace mojom {
enum class RecordingStatus;
}  // namespace mojom

// Defines a callback type to notify the user of RecordingEncoder of a failure
// while encoding audio or video frames.
using OnFailureCallback =
    base::OnceCallback<void(mojom::RecordingStatus status)>;

// Defines a callback that can be retrieved from the encoder in order to be
// called repeatedly by the client to provide the audio buses along with their
// timestamps so that they can get encoded and muxed with the video frames.
using EncodeAudioCallback =
    base::RepeatingCallback<void(std::unique_ptr<media::AudioBus> audio_bus,
                                 base::TimeTicks audio_capture_time)>;

// Defines a common interface for encoding audio and video frames. The concrete
// implementation classes decides how encoding is done, and the type of the
// underlying actual encoders.
class RecordingEncoder : public RecordingFileIoHelper::Delegate {
 public:
  // Defines an interface for the actual encoders types to provide the
  // capabilities that they support.
  class Capabilities {
   public:
    Capabilities() = default;
    Capabilities(const Capabilities&) = delete;
    Capabilities& operator=(const Capabilities&) = delete;
    virtual ~Capabilities() = default;

    // Returns the pixel format that the encoder supports, which should be used
    // to initialize the frame sink video capturer in the GPU. Video frames
    // received from the capturer should be in this pixel format.
    virtual media::VideoPixelFormat GetSupportedPixelFormat() const = 0;

    // Returns whether the encoder supports size changes of the video frames
    // during recording (e.g. due to screen rotation, DSF changes, ... etc.).
    // Size changes during recording require a reconfiguration of the video
    // encoder.
    virtual bool SupportsVideoFrameSizeChanges() const = 0;

    // Returns whether the encoder supports the extracted `RgbVideoFrame` from
    // the `media::VideoFrame` directly. This allows us to discard the
    // `media::VideoFrame` very early upon reception so that it can be returned
    // immediately to viz capturer buffer pool (see b/316588576).
    virtual bool SupportsRgbVideoFrame() const = 0;
  };

  explicit RecordingEncoder(OnFailureCallback on_failure_callback);
  RecordingEncoder(const RecordingEncoder&) = delete;
  RecordingEncoder& operator=(const RecordingEncoder&) = delete;
  ~RecordingEncoder() override;

  bool did_failure_occur() const {
    DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
    return !on_failure_callback_;
  }

  // Creates and initializes the video encoder if none exists, or recreates and
  // reinitializes it otherwise (if the underlying encoder type supports this
  // behavior, i.e. when the video frame dimensions may need to change
  // dynamically (such as when a recorded window gets moved to a display with
  // different bounds)).
  virtual void InitializeVideoEncoder(
      const media::VideoEncoder::Options& video_encoder_options) = 0;

  // Encodes and muxes the given video `frame`. Clients must check first
  // `Capabilities::SupportsRgbVideoFrame()` to determine which frame type to
  // provide (i.e. `media::VideoFrame` or `RgbVideoFrame`.
  virtual void EncodeVideo(scoped_refptr<media::VideoFrame> frame) = 0;
  virtual void EncodeRgbVideo(RgbVideoFrame rgb_video_frame) = 0;

  // Returns a callback bound to this object that can be called repeatedly by
  // the client to provide the audio buses along with their timestamps so that
  // they can get encoded and muxed by the encoder.
  // Note that the underlying encoder type may not support encoding audio (e.g.
  // the GIF encoder).
  virtual EncodeAudioCallback GetEncodeAudioCallback() = 0;

  // Audio and video encoders as well as the WebmMuxer may buffer several frames
  // before they're processed. It is important to flush all those buffers before
  // releasing this object so as not to drop the final portion of the recording.
  // `on_done` will be called when all remaining buffered frames have been
  // processed and written to the output file.
  // By default, `on_done` will be called on the same sequence on which this
  // encoder is running, unless the caller binds it to another sequence by means
  // of `base::BindPostTask()`.
  virtual void FlushAndFinalize(base::OnceClosure on_done) = 0;

  // RecordingFileIoHelper::Delegate:
  void NotifyFailure(mojom::RecordingStatus status) override;

 protected:
  // Called by both the audio and video encoders to provide the `status` of
  // encoding tasks.
  void OnEncoderStatus(bool for_video, media::EncoderStatus status);

  SEQUENCE_CHECKER(sequence_checker_);

  // A callback triggered when a failure happens during encoding. Once
  // triggered, this callback is null, and therefore indicates that a failure
  // occurred (See `did_failure_occur()` above).
  // This has to be the first thing created, so it's the last thing that gets
  // destroyed, since any failure in the encoders or muxer relies on this
  // callback to notify the service about the failure.
  // See https://crbug.com/1255090.
  OnFailureCallback on_failure_callback_ GUARDED_BY_CONTEXT(sequence_checker_);
};

}  // namespace recording

#endif  // CHROMEOS_ASH_SERVICES_RECORDING_RECORDING_ENCODER_H_