Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / content / renderer / media / pepper_to_video_track_adapter.cc
blobde636f98dfab50e40319f0f4d726eac180e264e8
1 // Copyright (c) 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "content/renderer/media/pepper_to_video_track_adapter.h"
7 #include <string>
9 #include "base/base64.h"
10 #include "base/logging.h"
11 #include "base/rand_util.h"
12 #include "base/strings/utf_string_conversions.h"
13 #include "base/trace_event/trace_event.h"
14 #include "content/renderer/media/media_stream.h"
15 #include "content/renderer/media/media_stream_registry_interface.h"
16 #include "content/renderer/media/media_stream_video_source.h"
17 #include "content/renderer/media/media_stream_video_track.h"
18 #include "content/renderer/pepper/ppb_image_data_impl.h"
19 #include "content/renderer/render_thread_impl.h"
20 #include "media/base/video_capture_types.h"
21 #include "media/base/video_frame_pool.h"
22 #include "third_party/WebKit/public/platform/WebMediaStreamTrack.h"
23 #include "third_party/WebKit/public/platform/WebURL.h"
24 #include "third_party/WebKit/public/web/WebMediaStreamRegistry.h"
25 #include "third_party/libyuv/include/libyuv/convert.h"
26 #include "url/gurl.h"
28 namespace content {
30 // PpFrameWriter implements MediaStreamVideoSource and can therefore provide
31 // video frames to MediaStreamVideoTracks. It also implements
32 // FrameWriterInterface, which will be used by Pepper plugins (notably the
33 // Effects plugin) to inject the processed frame.
34 class PpFrameWriter : public MediaStreamVideoSource,
35 public FrameWriterInterface,
36 public base::SupportsWeakPtr<PpFrameWriter> {
37 public:
38 PpFrameWriter();
39 virtual ~PpFrameWriter();
41 // FrameWriterInterface implementation.
42 // This method will be called by the Pepper host from render thread.
43 void PutFrame(PPB_ImageData_Impl* image_data, int64 time_stamp_ns) override;
45 protected:
46 // MediaStreamVideoSource implementation.
47 void GetCurrentSupportedFormats(
48 int max_requested_width,
49 int max_requested_height,
50 double max_requested_frame_rate,
51 const VideoCaptureDeviceFormatsCB& callback) override;
52 void StartSourceImpl(
53 const media::VideoCaptureFormat& format,
54 const blink::WebMediaConstraints& constraints,
55 const VideoCaptureDeliverFrameCB& frame_callback) override;
56 void StopSourceImpl() override;
58 private:
59 media::VideoFramePool frame_pool_;
61 class FrameWriterDelegate;
62 scoped_refptr<FrameWriterDelegate> delegate_;
64 DISALLOW_COPY_AND_ASSIGN(PpFrameWriter);
67 class PpFrameWriter::FrameWriterDelegate
68 : public base::RefCountedThreadSafe<FrameWriterDelegate> {
69 public:
70 FrameWriterDelegate(
71 scoped_refptr<base::SingleThreadTaskRunner> io_task_runner,
72 const VideoCaptureDeliverFrameCB& new_frame_callback);
74 void DeliverFrame(const scoped_refptr<media::VideoFrame>& frame);
75 private:
76 friend class base::RefCountedThreadSafe<FrameWriterDelegate>;
77 virtual ~FrameWriterDelegate();
79 void DeliverFrameOnIO(const scoped_refptr<media::VideoFrame>& frame);
81 scoped_refptr<base::SingleThreadTaskRunner> io_task_runner_;
82 VideoCaptureDeliverFrameCB new_frame_callback_;
85 PpFrameWriter::FrameWriterDelegate::FrameWriterDelegate(
86 scoped_refptr<base::SingleThreadTaskRunner> io_task_runner,
87 const VideoCaptureDeliverFrameCB& new_frame_callback)
88 : io_task_runner_(io_task_runner), new_frame_callback_(new_frame_callback) {
91 PpFrameWriter::FrameWriterDelegate::~FrameWriterDelegate() {
94 void PpFrameWriter::FrameWriterDelegate::DeliverFrame(
95 const scoped_refptr<media::VideoFrame>& frame) {
96 io_task_runner_->PostTask(
97 FROM_HERE,
98 base::Bind(&FrameWriterDelegate::DeliverFrameOnIO, this, frame));
101 void PpFrameWriter::FrameWriterDelegate::DeliverFrameOnIO(
102 const scoped_refptr<media::VideoFrame>& frame) {
103 DCHECK(io_task_runner_->BelongsToCurrentThread());
104 // The local time when this frame is generated is unknown so give a null
105 // value to |estimated_capture_time|.
106 new_frame_callback_.Run(frame, base::TimeTicks());
109 PpFrameWriter::PpFrameWriter() {
110 DVLOG(3) << "PpFrameWriter ctor";
113 PpFrameWriter::~PpFrameWriter() {
114 DVLOG(3) << "PpFrameWriter dtor";
117 void PpFrameWriter::GetCurrentSupportedFormats(
118 int max_requested_width,
119 int max_requested_height,
120 double max_requested_frame_rate,
121 const VideoCaptureDeviceFormatsCB& callback) {
122 DCHECK(CalledOnValidThread());
123 DVLOG(3) << "PpFrameWriter::GetCurrentSupportedFormats()";
124 // Since the input is free to change the resolution at any point in time
125 // the supported formats are unknown.
126 media::VideoCaptureFormats formats;
127 callback.Run(formats);
130 void PpFrameWriter::StartSourceImpl(
131 const media::VideoCaptureFormat& format,
132 const blink::WebMediaConstraints& constraints,
133 const VideoCaptureDeliverFrameCB& frame_callback) {
134 DCHECK(CalledOnValidThread());
135 DCHECK(!delegate_.get());
136 DVLOG(3) << "PpFrameWriter::StartSourceImpl()";
137 delegate_ = new FrameWriterDelegate(io_task_runner(), frame_callback);
138 OnStartDone(MEDIA_DEVICE_OK);
141 void PpFrameWriter::StopSourceImpl() {
142 DCHECK(CalledOnValidThread());
145 // Note: PutFrame must copy or process image_data directly in this function,
146 // because it may be overwritten as soon as we return from this function.
147 void PpFrameWriter::PutFrame(PPB_ImageData_Impl* image_data,
148 int64 time_stamp_ns) {
149 DCHECK(CalledOnValidThread());
150 TRACE_EVENT0("video", "PpFrameWriter::PutFrame");
151 DVLOG(3) << "PpFrameWriter::PutFrame()";
153 if (!image_data) {
154 LOG(ERROR) << "PpFrameWriter::PutFrame - Called with NULL image_data.";
155 return;
157 ImageDataAutoMapper mapper(image_data);
158 if (!mapper.is_valid()) {
159 LOG(ERROR) << "PpFrameWriter::PutFrame - "
160 << "The image could not be mapped and is unusable.";
161 return;
163 const SkBitmap* bitmap = image_data->GetMappedBitmap();
164 if (!bitmap) {
165 LOG(ERROR) << "PpFrameWriter::PutFrame - "
166 << "The image_data's mapped bitmap is NULL.";
167 return;
170 const uint8* src_data = static_cast<uint8*>(bitmap->getPixels());
171 const int src_stride = static_cast<int>(bitmap->rowBytes());
172 const int width = bitmap->width();
173 const int height = bitmap->height();
175 // We only support PP_IMAGEDATAFORMAT_BGRA_PREMUL at the moment.
176 DCHECK(image_data->format() == PP_IMAGEDATAFORMAT_BGRA_PREMUL);
178 const gfx::Size frame_size(width, height);
180 if (state() != MediaStreamVideoSource::STARTED)
181 return;
183 const base::TimeDelta timestamp = base::TimeDelta::FromMicroseconds(
184 time_stamp_ns / base::Time::kNanosecondsPerMicrosecond);
186 scoped_refptr<media::VideoFrame> new_frame =
187 frame_pool_.CreateFrame(media::PIXEL_FORMAT_YV12, frame_size,
188 gfx::Rect(frame_size), frame_size, timestamp);
190 libyuv::ARGBToI420(src_data,
191 src_stride,
192 new_frame->data(media::VideoFrame::kYPlane),
193 new_frame->stride(media::VideoFrame::kYPlane),
194 new_frame->data(media::VideoFrame::kUPlane),
195 new_frame->stride(media::VideoFrame::kUPlane),
196 new_frame->data(media::VideoFrame::kVPlane),
197 new_frame->stride(media::VideoFrame::kVPlane),
198 width,
199 height);
201 delegate_->DeliverFrame(new_frame);
204 // PpFrameWriterProxy is a helper class to make sure the user won't use
205 // PpFrameWriter after it is released (IOW its owner - WebMediaStreamSource -
206 // is released).
207 class PpFrameWriterProxy : public FrameWriterInterface {
208 public:
209 explicit PpFrameWriterProxy(const base::WeakPtr<PpFrameWriter>& writer)
210 : writer_(writer) {
211 DCHECK(writer_ != NULL);
214 ~PpFrameWriterProxy() override {}
216 void PutFrame(PPB_ImageData_Impl* image_data, int64 time_stamp_ns) override {
217 writer_->PutFrame(image_data, time_stamp_ns);
220 private:
221 base::WeakPtr<PpFrameWriter> writer_;
223 DISALLOW_COPY_AND_ASSIGN(PpFrameWriterProxy);
226 bool PepperToVideoTrackAdapter::Open(MediaStreamRegistryInterface* registry,
227 const std::string& url,
228 FrameWriterInterface** frame_writer) {
229 DVLOG(3) << "PepperToVideoTrackAdapter::Open";
230 blink::WebMediaStream stream;
231 if (registry) {
232 stream = registry->GetMediaStream(url);
233 } else {
234 stream =
235 blink::WebMediaStreamRegistry::lookupMediaStreamDescriptor(GURL(url));
237 if (stream.isNull()) {
238 LOG(ERROR) << "PepperToVideoTrackAdapter::Open - invalid url: " << url;
239 return false;
242 // Create a new native video track and add it to |stream|.
243 std::string track_id;
244 // According to spec, a media stream source's id should be unique per
245 // application. There's no easy way to strictly achieve that. The id
246 // generated with this method should be unique for most of the cases but
247 // theoretically it's possible we can get an id that's duplicated with the
248 // existing sources.
249 base::Base64Encode(base::RandBytesAsString(64), &track_id);
251 PpFrameWriter* writer = new PpFrameWriter();
253 // Create a new webkit video track.
254 blink::WebMediaStreamSource webkit_source;
255 blink::WebMediaStreamSource::Type type =
256 blink::WebMediaStreamSource::TypeVideo;
257 blink::WebString webkit_track_id = base::UTF8ToUTF16(track_id);
258 webkit_source.initialize(webkit_track_id, type, webkit_track_id,
259 false /* remote */, true /* readonly */);
260 webkit_source.setExtraData(writer);
262 blink::WebMediaConstraints constraints;
263 constraints.initialize();
264 bool track_enabled = true;
266 stream.addTrack(MediaStreamVideoTrack::CreateVideoTrack(
267 writer, constraints, MediaStreamVideoSource::ConstraintsCallback(),
268 track_enabled));
270 *frame_writer = new PpFrameWriterProxy(writer->AsWeakPtr());
271 return true;
274 } // namespace content