Pin Chrome's shortcut to the Win10 Start menu on install and OS upgrade.
[chromium-blink-merge.git] / content / renderer / media / webrtc / video_destination_handler.cc
blob5aaa4272cc43eb77d182eb5b1ec38621705b2bf5
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/webrtc/video_destination_handler.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_track.h"
17 #include "content/renderer/pepper/ppb_image_data_impl.h"
18 #include "content/renderer/render_thread_impl.h"
19 #include "media/base/video_capture_types.h"
20 #include "third_party/WebKit/public/platform/WebMediaStreamTrack.h"
21 #include "third_party/WebKit/public/platform/WebURL.h"
22 #include "third_party/WebKit/public/web/WebMediaStreamRegistry.h"
23 #include "third_party/libyuv/include/libyuv/convert.h"
24 #include "url/gurl.h"
26 namespace content {
28 class PpFrameWriter::FrameWriterDelegate
29 : public base::RefCountedThreadSafe<FrameWriterDelegate> {
30 public:
31 FrameWriterDelegate(
32 scoped_refptr<base::SingleThreadTaskRunner> io_task_runner,
33 const VideoCaptureDeliverFrameCB& new_frame_callback);
35 void DeliverFrame(const scoped_refptr<media::VideoFrame>& frame);
36 private:
37 friend class base::RefCountedThreadSafe<FrameWriterDelegate>;
38 virtual ~FrameWriterDelegate();
40 void DeliverFrameOnIO(const scoped_refptr<media::VideoFrame>& frame);
42 scoped_refptr<base::SingleThreadTaskRunner> io_task_runner_;
43 VideoCaptureDeliverFrameCB new_frame_callback_;
46 PpFrameWriter::FrameWriterDelegate::FrameWriterDelegate(
47 scoped_refptr<base::SingleThreadTaskRunner> io_task_runner,
48 const VideoCaptureDeliverFrameCB& new_frame_callback)
49 : io_task_runner_(io_task_runner), new_frame_callback_(new_frame_callback) {
52 PpFrameWriter::FrameWriterDelegate::~FrameWriterDelegate() {
55 void PpFrameWriter::FrameWriterDelegate::DeliverFrame(
56 const scoped_refptr<media::VideoFrame>& frame) {
57 io_task_runner_->PostTask(
58 FROM_HERE,
59 base::Bind(&FrameWriterDelegate::DeliverFrameOnIO, this, frame));
62 void PpFrameWriter::FrameWriterDelegate::DeliverFrameOnIO(
63 const scoped_refptr<media::VideoFrame>& frame) {
64 DCHECK(io_task_runner_->BelongsToCurrentThread());
65 // The local time when this frame is generated is unknown so give a null
66 // value to |estimated_capture_time|.
67 new_frame_callback_.Run(frame, base::TimeTicks());
70 PpFrameWriter::PpFrameWriter() {
71 DVLOG(3) << "PpFrameWriter ctor";
74 PpFrameWriter::~PpFrameWriter() {
75 DVLOG(3) << "PpFrameWriter dtor";
78 void PpFrameWriter::GetCurrentSupportedFormats(
79 int max_requested_width,
80 int max_requested_height,
81 double max_requested_frame_rate,
82 const VideoCaptureDeviceFormatsCB& callback) {
83 DCHECK(CalledOnValidThread());
84 DVLOG(3) << "PpFrameWriter::GetCurrentSupportedFormats()";
85 // Since the input is free to change the resolution at any point in time
86 // the supported formats are unknown.
87 media::VideoCaptureFormats formats;
88 callback.Run(formats);
91 void PpFrameWriter::StartSourceImpl(
92 const media::VideoCaptureFormat& format,
93 const blink::WebMediaConstraints& constraints,
94 const VideoCaptureDeliverFrameCB& frame_callback) {
95 DCHECK(CalledOnValidThread());
96 DCHECK(!delegate_.get());
97 DVLOG(3) << "PpFrameWriter::StartSourceImpl()";
98 delegate_ = new FrameWriterDelegate(io_task_runner(), frame_callback);
99 OnStartDone(MEDIA_DEVICE_OK);
102 void PpFrameWriter::StopSourceImpl() {
103 DCHECK(CalledOnValidThread());
106 // Note: PutFrame must copy or process image_data directly in this function,
107 // because it may be overwritten as soon as we return from this function.
108 void PpFrameWriter::PutFrame(PPB_ImageData_Impl* image_data,
109 int64 time_stamp_ns) {
110 DCHECK(CalledOnValidThread());
111 TRACE_EVENT0("video", "PpFrameWriter::PutFrame");
112 DVLOG(3) << "PpFrameWriter::PutFrame()";
114 if (!image_data) {
115 LOG(ERROR) << "PpFrameWriter::PutFrame - Called with NULL image_data.";
116 return;
118 ImageDataAutoMapper mapper(image_data);
119 if (!mapper.is_valid()) {
120 LOG(ERROR) << "PpFrameWriter::PutFrame - "
121 << "The image could not be mapped and is unusable.";
122 return;
124 const SkBitmap* bitmap = image_data->GetMappedBitmap();
125 if (!bitmap) {
126 LOG(ERROR) << "PpFrameWriter::PutFrame - "
127 << "The image_data's mapped bitmap is NULL.";
128 return;
131 const uint8* src_data = static_cast<uint8*>(bitmap->getPixels());
132 const int src_stride = static_cast<int>(bitmap->rowBytes());
133 const int width = bitmap->width();
134 const int height = bitmap->height();
136 // We only support PP_IMAGEDATAFORMAT_BGRA_PREMUL at the moment.
137 DCHECK(image_data->format() == PP_IMAGEDATAFORMAT_BGRA_PREMUL);
139 const gfx::Size frame_size(width, height);
141 if (state() != MediaStreamVideoSource::STARTED)
142 return;
144 const base::TimeDelta timestamp = base::TimeDelta::FromMicroseconds(
145 time_stamp_ns / base::Time::kNanosecondsPerMicrosecond);
147 scoped_refptr<media::VideoFrame> new_frame =
148 frame_pool_.CreateFrame(media::PIXEL_FORMAT_YV12, frame_size,
149 gfx::Rect(frame_size), frame_size, timestamp);
151 libyuv::ARGBToI420(src_data,
152 src_stride,
153 new_frame->data(media::VideoFrame::kYPlane),
154 new_frame->stride(media::VideoFrame::kYPlane),
155 new_frame->data(media::VideoFrame::kUPlane),
156 new_frame->stride(media::VideoFrame::kUPlane),
157 new_frame->data(media::VideoFrame::kVPlane),
158 new_frame->stride(media::VideoFrame::kVPlane),
159 width,
160 height);
162 delegate_->DeliverFrame(new_frame);
165 // PpFrameWriterProxy is a helper class to make sure the user won't use
166 // PpFrameWriter after it is released (IOW its owner - WebMediaStreamSource -
167 // is released).
168 class PpFrameWriterProxy : public FrameWriterInterface {
169 public:
170 explicit PpFrameWriterProxy(const base::WeakPtr<PpFrameWriter>& writer)
171 : writer_(writer) {
172 DCHECK(writer_ != NULL);
175 ~PpFrameWriterProxy() override {}
177 void PutFrame(PPB_ImageData_Impl* image_data, int64 time_stamp_ns) override {
178 writer_->PutFrame(image_data, time_stamp_ns);
181 private:
182 base::WeakPtr<PpFrameWriter> writer_;
184 DISALLOW_COPY_AND_ASSIGN(PpFrameWriterProxy);
187 bool VideoDestinationHandler::Open(
188 MediaStreamRegistryInterface* registry,
189 const std::string& url,
190 FrameWriterInterface** frame_writer) {
191 DVLOG(3) << "VideoDestinationHandler::Open";
192 blink::WebMediaStream stream;
193 if (registry) {
194 stream = registry->GetMediaStream(url);
195 } else {
196 stream =
197 blink::WebMediaStreamRegistry::lookupMediaStreamDescriptor(GURL(url));
199 if (stream.isNull()) {
200 LOG(ERROR) << "VideoDestinationHandler::Open - invalid url: " << url;
201 return false;
204 // Create a new native video track and add it to |stream|.
205 std::string track_id;
206 // According to spec, a media stream source's id should be unique per
207 // application. There's no easy way to strictly achieve that. The id
208 // generated with this method should be unique for most of the cases but
209 // theoretically it's possible we can get an id that's duplicated with the
210 // existing sources.
211 base::Base64Encode(base::RandBytesAsString(64), &track_id);
213 PpFrameWriter* writer = new PpFrameWriter();
215 // Create a new webkit video track.
216 blink::WebMediaStreamSource webkit_source;
217 blink::WebMediaStreamSource::Type type =
218 blink::WebMediaStreamSource::TypeVideo;
219 blink::WebString webkit_track_id = base::UTF8ToUTF16(track_id);
220 webkit_source.initialize(webkit_track_id, type, webkit_track_id,
221 false /* remote */, true /* readonly */);
222 webkit_source.setExtraData(writer);
224 blink::WebMediaConstraints constraints;
225 constraints.initialize();
226 bool track_enabled = true;
228 stream.addTrack(MediaStreamVideoTrack::CreateVideoTrack(
229 writer, constraints, MediaStreamVideoSource::ConstraintsCallback(),
230 track_enabled));
232 *frame_writer = new PpFrameWriterProxy(writer->AsWeakPtr());
233 return true;
236 } // namespace content