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 "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/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 // TODO(magjed): Chrome OS is not ready for switching from BGRA to ARGB.
161 // Remove this once http://crbug/434007 is fixed. We have a corresponding
162 // problem when we send frames to the effects plugin in PepperVideoSourceHost.
163 #if defined(OS_CHROMEOS)
164 auto libyuv_xxxx_to_i420
= &libyuv::BGRAToI420
;
166 auto libyuv_xxxx_to_i420
= &libyuv::ARGBToI420
;
168 libyuv_xxxx_to_i420(src_data
,
170 new_frame
->data(media::VideoFrame::kYPlane
),
171 new_frame
->stride(media::VideoFrame::kYPlane
),
172 new_frame
->data(media::VideoFrame::kUPlane
),
173 new_frame
->stride(media::VideoFrame::kUPlane
),
174 new_frame
->data(media::VideoFrame::kVPlane
),
175 new_frame
->stride(media::VideoFrame::kVPlane
),
179 delegate_
->DeliverFrame(new_frame
, format
);
182 // PpFrameWriterProxy is a helper class to make sure the user won't use
183 // PpFrameWriter after it is released (IOW its owner - WebMediaStreamSource -
185 class PpFrameWriterProxy
: public FrameWriterInterface
{
187 explicit PpFrameWriterProxy(const base::WeakPtr
<PpFrameWriter
>& writer
)
189 DCHECK(writer_
!= NULL
);
192 ~PpFrameWriterProxy() override
{}
194 void PutFrame(PPB_ImageData_Impl
* image_data
, int64 time_stamp_ns
) override
{
195 writer_
->PutFrame(image_data
, time_stamp_ns
);
199 base::WeakPtr
<PpFrameWriter
> writer_
;
201 DISALLOW_COPY_AND_ASSIGN(PpFrameWriterProxy
);
204 bool VideoDestinationHandler::Open(
205 MediaStreamRegistryInterface
* registry
,
206 const std::string
& url
,
207 FrameWriterInterface
** frame_writer
) {
208 DVLOG(3) << "VideoDestinationHandler::Open";
209 blink::WebMediaStream stream
;
211 stream
= registry
->GetMediaStream(url
);
214 blink::WebMediaStreamRegistry::lookupMediaStreamDescriptor(GURL(url
));
216 if (stream
.isNull()) {
217 LOG(ERROR
) << "VideoDestinationHandler::Open - invalid url: " << url
;
221 // Create a new native video track and add it to |stream|.
222 std::string track_id
;
223 // According to spec, a media stream source's id should be unique per
224 // application. There's no easy way to strictly achieve that. The id
225 // generated with this method should be unique for most of the cases but
226 // theoretically it's possible we can get an id that's duplicated with the
228 base::Base64Encode(base::RandBytesAsString(64), &track_id
);
230 PpFrameWriter
* writer
= new PpFrameWriter();
232 // Create a new webkit video track.
233 blink::WebMediaStreamSource webkit_source
;
234 blink::WebMediaStreamSource::Type type
=
235 blink::WebMediaStreamSource::TypeVideo
;
236 blink::WebString webkit_track_id
= base::UTF8ToUTF16(track_id
);
237 webkit_source
.initialize(webkit_track_id
, type
, webkit_track_id
,
238 false /* remote */, true /* readonly */);
239 webkit_source
.setExtraData(writer
);
241 blink::WebMediaConstraints constraints
;
242 constraints
.initialize();
243 bool track_enabled
= true;
245 stream
.addTrack(MediaStreamVideoTrack::CreateVideoTrack(
246 writer
, constraints
, MediaStreamVideoSource::ConstraintsCallback(),
249 *frame_writer
= new PpFrameWriterProxy(writer
->AsWeakPtr());
253 } // namespace content