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

content / renderer / media / android / stream_texture_wrapper_impl.h [blame]

// Copyright 2016 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef CONTENT_RENDERER_MEDIA_ANDROID_STREAM_TEXTURE_WRAPPER_IMPL_H_
#define CONTENT_RENDERER_MEDIA_ANDROID_STREAM_TEXTURE_WRAPPER_IMPL_H_

#include "base/task/single_thread_task_runner.h"
#include "content/common/content_export.h"
#include "content/renderer/media/android/stream_texture_factory.h"
#include "gpu/command_buffer/common/mailbox.h"
#include "media/base/android/stream_texture_wrapper.h"
#include "media/base/video_frame.h"

namespace content {

// Concrete implementation of StreamTextureWrapper. Any method can be called on
// any thread, but additional threading considerations are listed in the
// comments of individual methods.
//
// The StreamTexture is an abstraction allowing Chrome to wrap a SurfaceOwner
// living in the GPU process. It allows VideoFrames to be created from the
// SurfaceOwner's texture, in the Renderer process.
//
// The general idea behind our use of StreamTexture is as follows:
// - We request the creation of a StreamTexture via the StreamTextureFactory.
// The call is sent to the GPU process via the CommandBuffer. A StreamTexture is
// then created, wrapping a SurfaceOwner. The SurfaceOwner's
// OnFrameAvailable() callback is tied to StreamTexture's OnFrameAvailable(),
// which fires an IPC across the GPU channel.
// - We create a StreamTextureProxy in the Renderer process which listens for
// the IPC fired by the StreamTexture's OnFrameAvailable() callback.
// - We bind the StreamTextureProxy's lifetime to the |compositor_task_runner_|.
// - We create a SharedImage mailbox representing the StreamTexture at a given
// size.
// - We create a VideoFrame which takes ownership of this SharedImage mailbox.
// - When the SurfaceOwner's OnFrameAvailable() callback is fired (and routed
// to the StreamTextureProxy living on the compositor thread), we notify
// |client_| that a new frame is available, via the DidReceiveFrame() callback.
// - When the StreamTextureProxy is destroyed, it delivers a notification over
// the channel, cleaning up the StreamTexture ref in the GPU process.
class CONTENT_EXPORT StreamTextureWrapperImpl
    : public media::StreamTextureWrapper {
 public:
  // |enable_texture_copy| controls the VideoFrameMetadata::COPY_REQUIRED flag,
  // making sure it is correctly set on |current_frame_|, for webview scenarios.
  static media::ScopedStreamTextureWrapper Create(
      bool enable_texture_copy,
      scoped_refptr<StreamTextureFactory> factory,
      scoped_refptr<base::SingleThreadTaskRunner> main_task_runner);

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

  // Creates the underlying StreamTexture, and binds |stream_texture_proxy_| to
  // |compositor_task_runner|.
  //
  // Additional threading considerations:
  //   - Can be called from any thread.
  //   - Initialization will be posted to |main_task_runner_|.
  //   - |init_cb| will be run on the calling thread, and will be passed a bool
  //     indicating whether the initialization was successful.
  //   - New frames will be signaled on |compositor_task_runner| via |client|'s
  //     DidReceiveFrame() method.
  void Initialize(
      const base::RepeatingClosure& received_frame_cb,
      scoped_refptr<base::SingleThreadTaskRunner> compositor_task_runner,
      StreamTextureWrapperInitCB init_cb) override;

  // Should be called when the Video size changes.
  // Can be called from any thread, but runs on |main_task_runner_|.
  void UpdateTextureSize(const gfx::Size& rotated_visible_size) override;

  // Returns the latest frame.
  // N.B: We create a single VideoFrame at initialization time (and update it
  // in UpdateTextureSize()), and repeatedly return it here. The underlying
  // texture's changes are signalled via |client|'s DidReceiveFrame() callback.
  scoped_refptr<media::VideoFrame> GetCurrentFrame() override;

  // Sends the StreamTexture to the browser process, to fulfill the request
  // identified by |request_token|.
  // Uses the gpu::ScopedSurfaceRequestConduit to forward the underlying
  // SurfaceTexture to the ScopedSurfaceRequestManager.
  void ForwardStreamTextureForSurfaceRequest(
      const base::UnguessableToken& request_token) override;

  // Clears the |received_frame_cb| passed in Initialize().
  // Should be safe to call from any thread.
  void ClearReceivedFrameCBOnAnyThread() override;

 private:
  StreamTextureWrapperImpl(
      bool enable_texture_copy,
      scoped_refptr<StreamTextureFactory> factory,
      scoped_refptr<base::SingleThreadTaskRunner> main_task_runner);
  ~StreamTextureWrapperImpl() override;

  // Destroys |this| safely on |main_task_runner_|.
  void Destroy() override;

  void InitializeOnMainThread(const base::RepeatingClosure& received_frame_cb,
                              StreamTextureWrapperInitCB init_cb);

  void CreateVideoFrame(const gpu::Mailbox& mailbox,
                        const gfx::Size& coded_size,
                        const gfx::Rect& visible_rect,
                        const std::optional<gpu::VulkanYCbCrInfo>& ycbcr_info);

  void SetCurrentFrameInternal(scoped_refptr<media::VideoFrame> video_frame);

  bool enable_texture_copy_;

  // Object for calling back the compositor thread to repaint the video when a
  // frame is available. It should be bound to |compositor_task_runner_|.
  ScopedStreamTextureProxy stream_texture_proxy_;

  // Visible size of the video with rotation applied.
  gfx::Size rotated_visible_size_;

  scoped_refptr<StreamTextureFactory> factory_;

  base::Lock current_frame_lock_;
  scoped_refptr<media::VideoFrame> current_frame_;

  scoped_refptr<base::SingleThreadTaskRunner> main_task_runner_;
  scoped_refptr<base::SingleThreadTaskRunner> compositor_task_runner_;

  base::WeakPtrFactory<StreamTextureWrapperImpl> weak_factory_{this};
};

}  // namespace media

#endif  // CONTENT_RENDERER_MEDIA_ANDROID_STREAM_TEXTURE_WRAPPER_IMPL_H_