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/logging.h"
11 #include "base/rand_util.h"
12 #include "base/strings/utf_string_conversions.h"
13 #include "content/renderer/media/media_stream.h"
14 #include "content/renderer/media/media_stream_registry_interface.h"
15 #include "content/renderer/media/media_stream_video_track.h"
16 #include "content/renderer/pepper/ppb_image_data_impl.h"
17 #include "content/renderer/render_thread_impl.h"
18 #include "media/video/capture/video_capture_types.h"
19 #include "third_party/WebKit/public/platform/WebMediaStreamTrack.h"
20 #include "third_party/WebKit/public/platform/WebURL.h"
21 #include "third_party/WebKit/public/web/WebMediaStreamRegistry.h"
22 #include "third_party/libyuv/include/libyuv/convert.h"
27 class PpFrameWriter::FrameWriterDelegate
28 : public base::RefCountedThreadSafe<FrameWriterDelegate> {
31 const scoped_refptr<base::MessageLoopProxy>& io_message_loop_proxy,
32 const VideoCaptureDeliverFrameCB& new_frame_callback);
34 void DeliverFrame(const scoped_refptr<media::VideoFrame>& frame,
35 const media::VideoCaptureFormat& format);
37 friend class base::RefCountedThreadSafe<FrameWriterDelegate>;
38 virtual ~FrameWriterDelegate();
40 void DeliverFrameOnIO(const scoped_refptr<media::VideoFrame>& frame,
41 const media::VideoCaptureFormat& format);
43 scoped_refptr<base::MessageLoopProxy> io_message_loop_;
44 VideoCaptureDeliverFrameCB new_frame_callback_;
47 PpFrameWriter::FrameWriterDelegate::FrameWriterDelegate(
48 const scoped_refptr<base::MessageLoopProxy>& io_message_loop_proxy,
49 const VideoCaptureDeliverFrameCB& new_frame_callback)
50 : io_message_loop_(io_message_loop_proxy),
51 new_frame_callback_(new_frame_callback) {
54 PpFrameWriter::FrameWriterDelegate::~FrameWriterDelegate() {
57 void PpFrameWriter::FrameWriterDelegate::DeliverFrame(
58 const scoped_refptr<media::VideoFrame>& frame,
59 const media::VideoCaptureFormat& format) {
60 io_message_loop_->PostTask(
62 base::Bind(&FrameWriterDelegate::DeliverFrameOnIO,
63 this, frame, format));
66 void PpFrameWriter::FrameWriterDelegate::DeliverFrameOnIO(
67 const scoped_refptr<media::VideoFrame>& frame,
68 const media::VideoCaptureFormat& format) {
69 DCHECK(io_message_loop_->BelongsToCurrentThread());
70 // The local time when this frame is generated is unknown so give a null
71 // value to |estimated_capture_time|.
72 new_frame_callback_.Run(frame, format, base::TimeTicks());
75 PpFrameWriter::PpFrameWriter() {
76 DVLOG(3) << "PpFrameWriter ctor";
79 PpFrameWriter::~PpFrameWriter() {
80 DVLOG(3) << "PpFrameWriter dtor";
83 void PpFrameWriter::GetCurrentSupportedFormats(
84 int max_requested_width,
85 int max_requested_height,
86 double max_requested_frame_rate,
87 const VideoCaptureDeviceFormatsCB& callback) {
88 DCHECK(CalledOnValidThread());
89 DVLOG(3) << "PpFrameWriter::GetCurrentSupportedFormats()";
90 // Since the input is free to change the resolution at any point in time
91 // the supported formats are unknown.
92 media::VideoCaptureFormats formats;
93 callback.Run(formats);
96 void PpFrameWriter::StartSourceImpl(
97 const media::VideoCaptureParams& params,
98 const VideoCaptureDeliverFrameCB& frame_callback) {
99 DCHECK(CalledOnValidThread());
101 DVLOG(3) << "PpFrameWriter::StartSourceImpl()";
102 delegate_ = new FrameWriterDelegate(io_message_loop(), frame_callback);
103 OnStartDone(MEDIA_DEVICE_OK);
106 void PpFrameWriter::StopSourceImpl() {
107 DCHECK(CalledOnValidThread());
110 void PpFrameWriter::PutFrame(PPB_ImageData_Impl* image_data,
111 int64 time_stamp_ns) {
112 DCHECK(CalledOnValidThread());
113 DVLOG(3) << "PpFrameWriter::PutFrame()";
116 LOG(ERROR) << "PpFrameWriter::PutFrame - Called with NULL image_data.";
119 ImageDataAutoMapper mapper(image_data);
120 if (!mapper.is_valid()) {
121 LOG(ERROR) << "PpFrameWriter::PutFrame - "
122 << "The image could not be mapped and is unusable.";
125 const SkBitmap* bitmap = image_data->GetMappedBitmap();
127 LOG(ERROR) << "PpFrameWriter::PutFrame - "
128 << "The image_data's mapped bitmap is NULL.";
132 const gfx::Size frame_size(bitmap->width(), bitmap->height());
134 if (state() != MediaStreamVideoSource::STARTED)
137 const base::TimeDelta timestamp = base::TimeDelta::FromMicroseconds(
138 time_stamp_ns / base::Time::kNanosecondsPerMicrosecond);
140 // TODO(perkj): It would be more efficient to use I420 here. Using YV12 will
141 // force a copy into a tightly packed I420 frame in
142 // WebRtcVideoCapturerAdapter before the frame is delivered to libJingle.
144 scoped_refptr<media::VideoFrame> new_frame =
145 frame_pool_.CreateFrame(media::VideoFrame::YV12, frame_size,
146 gfx::Rect(frame_size), frame_size, timestamp);
147 media::VideoCaptureFormat format(
149 MediaStreamVideoSource::kDefaultFrameRate,
150 media::PIXEL_FORMAT_YV12);
152 libyuv::BGRAToI420(reinterpret_cast<uint8*>(bitmap->getPixels()),
154 new_frame->data(media::VideoFrame::kYPlane),
155 new_frame->stride(media::VideoFrame::kYPlane),
156 new_frame->data(media::VideoFrame::kUPlane),
157 new_frame->stride(media::VideoFrame::kUPlane),
158 new_frame->data(media::VideoFrame::kVPlane),
159 new_frame->stride(media::VideoFrame::kVPlane),
160 frame_size.width(), frame_size.height());
162 delegate_->DeliverFrame(new_frame, format);
165 // PpFrameWriterProxy is a helper class to make sure the user won't use
166 // PpFrameWriter after it is released (IOW its owner - WebMediaStreamSource -
168 class PpFrameWriterProxy : public FrameWriterInterface {
170 explicit PpFrameWriterProxy(const base::WeakPtr<PpFrameWriter>& writer)
172 DCHECK(writer_ != NULL);
175 virtual ~PpFrameWriterProxy() {}
177 virtual void PutFrame(PPB_ImageData_Impl* image_data,
178 int64 time_stamp_ns) OVERRIDE {
179 writer_->PutFrame(image_data, time_stamp_ns);
183 base::WeakPtr<PpFrameWriter> writer_;
185 DISALLOW_COPY_AND_ASSIGN(PpFrameWriterProxy);
188 bool VideoDestinationHandler::Open(
189 MediaStreamRegistryInterface* registry,
190 const std::string& url,
191 FrameWriterInterface** frame_writer) {
192 DVLOG(3) << "VideoDestinationHandler::Open";
193 blink::WebMediaStream stream;
195 stream = registry->GetMediaStream(url);
198 blink::WebMediaStreamRegistry::lookupMediaStreamDescriptor(GURL(url));
200 if (stream.isNull()) {
201 LOG(ERROR) << "VideoDestinationHandler::Open - invalid url: " << url;
205 // Create a new native video track and add it to |stream|.
206 std::string track_id;
207 // According to spec, a media stream source's id should be unique per
208 // application. There's no easy way to strictly achieve that. The id
209 // generated with this method should be unique for most of the cases but
210 // theoretically it's possible we can get an id that's duplicated with the
212 base::Base64Encode(base::RandBytesAsString(64), &track_id);
214 PpFrameWriter* writer = new PpFrameWriter();
216 // Create a new webkit video track.
217 blink::WebMediaStreamSource webkit_source;
218 blink::WebMediaStreamSource::Type type =
219 blink::WebMediaStreamSource::TypeVideo;
220 blink::WebString webkit_track_id = base::UTF8ToUTF16(track_id);
221 webkit_source.initialize(webkit_track_id, type, webkit_track_id);
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(),
232 *frame_writer = new PpFrameWriterProxy(writer->AsWeakPtr());
236 } // namespace content