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"
9 #include "base/base64.h"
10 #include "base/debug/trace_event.h"
11 #include "base/logging.h"
12 #include "base/rand_util.h"
13 #include "base/strings/utf_string_conversions.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/video/capture/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"
28 class PpFrameWriter::FrameWriterDelegate
29 : public base::RefCountedThreadSafe<FrameWriterDelegate> {
32 const scoped_refptr<base::MessageLoopProxy>& io_message_loop_proxy,
33 const VideoCaptureDeliverFrameCB& new_frame_callback);
35 void DeliverFrame(const scoped_refptr<media::VideoFrame>& frame,
36 const media::VideoCaptureFormat& format);
38 friend class base::RefCountedThreadSafe<FrameWriterDelegate>;
39 virtual ~FrameWriterDelegate();
41 void DeliverFrameOnIO(const scoped_refptr<media::VideoFrame>& frame,
42 const media::VideoCaptureFormat& format);
44 scoped_refptr<base::MessageLoopProxy> io_message_loop_;
45 VideoCaptureDeliverFrameCB new_frame_callback_;
48 PpFrameWriter::FrameWriterDelegate::FrameWriterDelegate(
49 const scoped_refptr<base::MessageLoopProxy>& io_message_loop_proxy,
50 const VideoCaptureDeliverFrameCB& new_frame_callback)
51 : io_message_loop_(io_message_loop_proxy),
52 new_frame_callback_(new_frame_callback) {
55 PpFrameWriter::FrameWriterDelegate::~FrameWriterDelegate() {
58 void PpFrameWriter::FrameWriterDelegate::DeliverFrame(
59 const scoped_refptr<media::VideoFrame>& frame,
60 const media::VideoCaptureFormat& format) {
61 io_message_loop_->PostTask(
63 base::Bind(&FrameWriterDelegate::DeliverFrameOnIO,
64 this, frame, format));
67 void PpFrameWriter::FrameWriterDelegate::DeliverFrameOnIO(
68 const scoped_refptr<media::VideoFrame>& frame,
69 const media::VideoCaptureFormat& format) {
70 DCHECK(io_message_loop_->BelongsToCurrentThread());
71 // The local time when this frame is generated is unknown so give a null
72 // value to |estimated_capture_time|.
73 new_frame_callback_.Run(frame, format, base::TimeTicks());
76 PpFrameWriter::PpFrameWriter() {
77 DVLOG(3) << "PpFrameWriter ctor";
80 PpFrameWriter::~PpFrameWriter() {
81 DVLOG(3) << "PpFrameWriter dtor";
84 void PpFrameWriter::GetCurrentSupportedFormats(
85 int max_requested_width,
86 int max_requested_height,
87 double max_requested_frame_rate,
88 const VideoCaptureDeviceFormatsCB& callback) {
89 DCHECK(CalledOnValidThread());
90 DVLOG(3) << "PpFrameWriter::GetCurrentSupportedFormats()";
91 // Since the input is free to change the resolution at any point in time
92 // the supported formats are unknown.
93 media::VideoCaptureFormats formats;
94 callback.Run(formats);
97 void PpFrameWriter::StartSourceImpl(
98 const media::VideoCaptureFormat& format,
99 const VideoCaptureDeliverFrameCB& frame_callback) {
100 DCHECK(CalledOnValidThread());
101 DCHECK(!delegate_.get());
102 DVLOG(3) << "PpFrameWriter::StartSourceImpl()";
103 delegate_ = new FrameWriterDelegate(io_message_loop(), frame_callback);
104 OnStartDone(MEDIA_DEVICE_OK);
107 void PpFrameWriter::StopSourceImpl() {
108 DCHECK(CalledOnValidThread());
111 // Note: PutFrame must copy or process image_data directly in this function,
112 // because it may be overwritten as soon as we return from this function.
113 void PpFrameWriter::PutFrame(PPB_ImageData_Impl* image_data,
114 int64 time_stamp_ns) {
115 DCHECK(CalledOnValidThread());
116 TRACE_EVENT0("video", "PpFrameWriter::PutFrame");
117 DVLOG(3) << "PpFrameWriter::PutFrame()";
120 LOG(ERROR) << "PpFrameWriter::PutFrame - Called with NULL image_data.";
123 ImageDataAutoMapper mapper(image_data);
124 if (!mapper.is_valid()) {
125 LOG(ERROR) << "PpFrameWriter::PutFrame - "
126 << "The image could not be mapped and is unusable.";
129 const SkBitmap* bitmap = image_data->GetMappedBitmap();
131 LOG(ERROR) << "PpFrameWriter::PutFrame - "
132 << "The image_data's mapped bitmap is NULL.";
136 const uint8* src_data = static_cast<uint8*>(bitmap->getPixels());
137 const int src_stride = static_cast<int>(bitmap->rowBytes());
138 const int width = bitmap->width();
139 const int height = bitmap->height();
141 // We only support PP_IMAGEDATAFORMAT_BGRA_PREMUL at the moment.
142 DCHECK(image_data->format() == PP_IMAGEDATAFORMAT_BGRA_PREMUL);
144 const gfx::Size frame_size(width, height);
146 if (state() != MediaStreamVideoSource::STARTED)
149 const base::TimeDelta timestamp = base::TimeDelta::FromMicroseconds(
150 time_stamp_ns / base::Time::kNanosecondsPerMicrosecond);
152 scoped_refptr<media::VideoFrame> new_frame =
153 frame_pool_.CreateFrame(media::VideoFrame::YV12, frame_size,
154 gfx::Rect(frame_size), frame_size, timestamp);
155 media::VideoCaptureFormat format(
157 MediaStreamVideoSource::kUnknownFrameRate,
158 media::PIXEL_FORMAT_YV12);
160 libyuv::ARGBToI420(src_data,
162 new_frame->data(media::VideoFrame::kYPlane),
163 new_frame->stride(media::VideoFrame::kYPlane),
164 new_frame->data(media::VideoFrame::kUPlane),
165 new_frame->stride(media::VideoFrame::kUPlane),
166 new_frame->data(media::VideoFrame::kVPlane),
167 new_frame->stride(media::VideoFrame::kVPlane),
171 delegate_->DeliverFrame(new_frame, format);
174 // PpFrameWriterProxy is a helper class to make sure the user won't use
175 // PpFrameWriter after it is released (IOW its owner - WebMediaStreamSource -
177 class PpFrameWriterProxy : public FrameWriterInterface {
179 explicit PpFrameWriterProxy(const base::WeakPtr<PpFrameWriter>& writer)
181 DCHECK(writer_ != NULL);
184 virtual ~PpFrameWriterProxy() {}
186 virtual void PutFrame(PPB_ImageData_Impl* image_data,
187 int64 time_stamp_ns) override {
188 writer_->PutFrame(image_data, time_stamp_ns);
192 base::WeakPtr<PpFrameWriter> writer_;
194 DISALLOW_COPY_AND_ASSIGN(PpFrameWriterProxy);
197 bool VideoDestinationHandler::Open(
198 MediaStreamRegistryInterface* registry,
199 const std::string& url,
200 FrameWriterInterface** frame_writer) {
201 DVLOG(3) << "VideoDestinationHandler::Open";
202 blink::WebMediaStream stream;
204 stream = registry->GetMediaStream(url);
207 blink::WebMediaStreamRegistry::lookupMediaStreamDescriptor(GURL(url));
209 if (stream.isNull()) {
210 LOG(ERROR) << "VideoDestinationHandler::Open - invalid url: " << url;
214 // Create a new native video track and add it to |stream|.
215 std::string track_id;
216 // According to spec, a media stream source's id should be unique per
217 // application. There's no easy way to strictly achieve that. The id
218 // generated with this method should be unique for most of the cases but
219 // theoretically it's possible we can get an id that's duplicated with the
221 base::Base64Encode(base::RandBytesAsString(64), &track_id);
223 PpFrameWriter* writer = new PpFrameWriter();
225 // Create a new webkit video track.
226 blink::WebMediaStreamSource webkit_source;
227 blink::WebMediaStreamSource::Type type =
228 blink::WebMediaStreamSource::TypeVideo;
229 blink::WebString webkit_track_id = base::UTF8ToUTF16(track_id);
230 webkit_source.initialize(webkit_track_id, type, webkit_track_id);
231 webkit_source.setExtraData(writer);
233 blink::WebMediaConstraints constraints;
234 constraints.initialize();
235 bool track_enabled = true;
237 stream.addTrack(MediaStreamVideoTrack::CreateVideoTrack(
238 writer, constraints, MediaStreamVideoSource::ConstraintsCallback(),
241 *frame_writer = new PpFrameWriterProxy(writer->AsWeakPtr());
245 } // namespace content