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
  135
  136
  137
  138
  139
  140
  141
  142
  143
  144
  145
  146
  147
  148
  149
  150
  151
  152
  153
  154
  155
  156
  157
  158
  159
  160
  161
  162
  163
  164
  165
  166
  167
  168
  169
  170
  171
  172
  173
  174
  175
  176
  177
  178
  179
  180
  181
  182
  183
  184
  185
  186
  187

media / fuchsia / common / stream_processor_helper.h [blame]

// Copyright 2019 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_FUCHSIA_COMMON_STREAM_PROCESSOR_HELPER_H_
#define MEDIA_FUCHSIA_COMMON_STREAM_PROCESSOR_HELPER_H_

#include <fuchsia/media/cpp/fidl.h>
#include <fuchsia/sysmem/cpp/fidl.h>

#include <forward_list>

#include "base/containers/flat_map.h"
#include "base/functional/callback.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/weak_ptr.h"
#include "base/threading/thread_checker.h"
#include "base/time/time.h"
#include "media/base/media_export.h"

namespace media {

// Helper class of fuchsia::media::StreamProcessor. It's responsible for:
// 1. Data validation check.
// 2. Stream/Buffer life time management.
// 3. Configure StreamProcessor and input/output buffer settings.
class MEDIA_EXPORT StreamProcessorHelper {
 public:
  class MEDIA_EXPORT IoPacket {
   public:
    IoPacket(size_t index,
             size_t offset,
             size_t size,
             base::TimeDelta timestamp,
             bool unit_end,
             bool key_frame,
             base::OnceClosure destroy_cb);

    IoPacket(const IoPacket&) = delete;
    IoPacket& operator=(const IoPacket&) = delete;

    ~IoPacket();

    IoPacket(IoPacket&&);
    IoPacket& operator=(IoPacket&&);

    size_t buffer_index() const { return index_; }
    size_t offset() const { return offset_; }
    size_t size() const { return size_; }
    base::TimeDelta timestamp() const { return timestamp_; }
    bool unit_end() const { return unit_end_; }
    bool key_frame() const { return key_frame_; }
    const fuchsia::media::FormatDetails& format() const { return format_; }
    void set_format(fuchsia::media::FormatDetails format) {
      format_ = std::move(format);
    }

    // Adds a |closure| that will be called when the packet is destroyed.
    void AddOnDestroyClosure(base::OnceClosure closure);

   private:
    size_t index_;
    size_t offset_;
    size_t size_;
    base::TimeDelta timestamp_;
    bool unit_end_;
    bool key_frame_;
    fuchsia::media::FormatDetails format_;
    std::forward_list<base::OnceClosure> destroy_callbacks_;
  };

  class Client {
   public:
    // Allocate input buffers with the given constraints. Clients should call
    // SetInputBufferCollectionToken to finish the buffer allocation flow.
    // Implementing this method is optional if a client chooses to allocate
    // input buffers before input constraints are returned from the
    // StreamProcessor.
    virtual void OnStreamProcessorAllocateInputBuffers(
        const fuchsia::media::StreamBufferConstraints& stream_constraints) {}

    // Allocate output buffers with the given constraints. Client should call
    // CompleteOutputBuffersAllocation to finish the buffer allocation flow.
    virtual void OnStreamProcessorAllocateOutputBuffers(
        const fuchsia::media::StreamBufferConstraints& stream_constraints) = 0;

    // Called when all the pushed packets are processed.
    virtual void OnStreamProcessorEndOfStream() = 0;

    // Called when output format is available.
    virtual void OnStreamProcessorOutputFormat(
        fuchsia::media::StreamOutputFormat format) = 0;

    // Called when output packet is available. Deleting |packet| will notify
    // StreamProcessor the output buffer is available to be re-used. Client
    // should delete |packet| on the same thread as this function.
    virtual void OnStreamProcessorOutputPacket(IoPacket packet) = 0;

    // Only available for decryption, which indicates currently the
    // StreamProcessor doesn't have the content key to process.
    virtual void OnStreamProcessorNoKey() = 0;

    // Called when any fatal errors happens.
    virtual void OnStreamProcessorError() = 0;

   protected:
    virtual ~Client() = default;
  };

  StreamProcessorHelper(fuchsia::media::StreamProcessorPtr processor,
                        Client* client);

  StreamProcessorHelper(const StreamProcessorHelper&) = delete;
  StreamProcessorHelper& operator=(const StreamProcessorHelper&) = delete;

  ~StreamProcessorHelper();

  // Process one packet. Caller can reuse the underlying buffer when the
  // |packet| is destroyed.
  void Process(IoPacket packet);

  // Push End-Of-Stream to StreamProcessor. No more data should be sent to
  // StreamProcessor without calling Reset.
  void ProcessEos();

  // Sets buffer collection tocken to use for input buffers.
  void SetInputBufferCollectionToken(
      fuchsia::sysmem2::BufferCollectionTokenPtr token);

  // Provide output BufferCollectionToken to finish StreamProcessor buffer
  // setup flow. Should be called only after AllocateOutputBuffers.
  void CompleteOutputBuffersAllocation(
      fuchsia::sysmem2::BufferCollectionTokenPtr token);

  // Closes the current stream and starts a new one. After that all packets
  // passed to Process() will be sent with a new |stream_lifetime_ordinal|
  // value.
  void Reset();

 private:
  // Event handlers for |processor_|.
  void OnStreamFailed(uint64_t stream_lifetime_ordinal,
                      fuchsia::media::StreamError error);
  void OnInputConstraints(
      fuchsia::media::StreamBufferConstraints input_constraints);
  void OnFreeInputPacket(fuchsia::media::PacketHeader free_input_packet);
  void OnOutputConstraints(
      fuchsia::media::StreamOutputConstraints output_constraints);
  void OnOutputFormat(fuchsia::media::StreamOutputFormat output_format);
  void OnOutputPacket(fuchsia::media::Packet output_packet,
                      bool error_detected_before,
                      bool error_detected_during);
  void OnOutputEndOfStream(uint64_t stream_lifetime_ordinal,
                           bool error_detected_before);

  void OnError();

  void OnRecycleOutputBuffer(uint64_t buffer_lifetime_ordinal,
                             uint32_t packet_index);

  uint64_t stream_lifetime_ordinal_ = 1;

  // Set to true if we've sent an input packet with the current
  // stream_lifetime_ordinal_.
  bool active_stream_ = false;

  // Map from packet index to corresponding input IoPacket. IoPacket should be
  // owned by this class until StreamProcessor released the buffer.
  base::flat_map<size_t, IoPacket> input_packets_;

  // Output buffers.
  uint64_t output_buffer_lifetime_ordinal_ = 1;
  fuchsia::media::StreamBufferConstraints output_buffer_constraints_;

  fuchsia::media::StreamProcessorPtr processor_;
  const raw_ptr<Client> client_;

  // FIDL interfaces are thread-affine (see crbug.com/1012875).
  THREAD_CHECKER(thread_checker_);

  base::WeakPtr<StreamProcessorHelper> weak_this_;
  base::WeakPtrFactory<StreamProcessorHelper> weak_factory_;
};

}  // namespace media

#endif  // MEDIA_FUCHSIA_COMMON_STREAM_PROCESSOR_HELPER_H_