Upstream version 10.39.225.0
[platform/framework/web/crosswalk.git] / src / content / renderer / media / webrtc / video_destination_handler.cc
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.
4
5 #include "content/renderer/media/webrtc/video_destination_handler.h"
6
7 #include <string>
8
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"
23 #include "url/gurl.h"
24
25 namespace content {
26
27 class PpFrameWriter::FrameWriterDelegate
28     : public base::RefCountedThreadSafe<FrameWriterDelegate> {
29  public:
30   FrameWriterDelegate(
31       const scoped_refptr<base::MessageLoopProxy>& io_message_loop_proxy,
32       const VideoCaptureDeliverFrameCB& new_frame_callback);
33
34   void DeliverFrame(const scoped_refptr<media::VideoFrame>& frame,
35                     const media::VideoCaptureFormat& format);
36  private:
37   friend class base::RefCountedThreadSafe<FrameWriterDelegate>;
38   virtual ~FrameWriterDelegate();
39
40   void DeliverFrameOnIO(const scoped_refptr<media::VideoFrame>& frame,
41                         const media::VideoCaptureFormat& format);
42
43   scoped_refptr<base::MessageLoopProxy> io_message_loop_;
44   VideoCaptureDeliverFrameCB new_frame_callback_;
45 };
46
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) {
52 }
53
54 PpFrameWriter::FrameWriterDelegate::~FrameWriterDelegate() {
55 }
56
57 void PpFrameWriter::FrameWriterDelegate::DeliverFrame(
58     const scoped_refptr<media::VideoFrame>& frame,
59     const media::VideoCaptureFormat& format) {
60   io_message_loop_->PostTask(
61       FROM_HERE,
62       base::Bind(&FrameWriterDelegate::DeliverFrameOnIO,
63                  this, frame, format));
64 }
65
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());
73 }
74
75 PpFrameWriter::PpFrameWriter() {
76   DVLOG(3) << "PpFrameWriter ctor";
77 }
78
79 PpFrameWriter::~PpFrameWriter() {
80   DVLOG(3) << "PpFrameWriter dtor";
81 }
82
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);
94 }
95
96 void PpFrameWriter::StartSourceImpl(
97     const media::VideoCaptureFormat& format,
98     const VideoCaptureDeliverFrameCB& frame_callback) {
99   DCHECK(CalledOnValidThread());
100   DCHECK(!delegate_.get());
101   DVLOG(3) << "PpFrameWriter::StartSourceImpl()";
102   delegate_ = new FrameWriterDelegate(io_message_loop(), frame_callback);
103   OnStartDone(MEDIA_DEVICE_OK);
104 }
105
106 void PpFrameWriter::StopSourceImpl() {
107   DCHECK(CalledOnValidThread());
108 }
109
110 void PpFrameWriter::PutFrame(PPB_ImageData_Impl* image_data,
111                              int64 time_stamp_ns) {
112   DCHECK(CalledOnValidThread());
113   DVLOG(3) << "PpFrameWriter::PutFrame()";
114
115   if (!image_data) {
116     LOG(ERROR) << "PpFrameWriter::PutFrame - Called with NULL image_data.";
117     return;
118   }
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.";
123     return;
124   }
125   const SkBitmap* bitmap = image_data->GetMappedBitmap();
126   if (!bitmap) {
127     LOG(ERROR) << "PpFrameWriter::PutFrame - "
128                << "The image_data's mapped bitmap is NULL.";
129     return;
130   }
131
132   const gfx::Size frame_size(bitmap->width(), bitmap->height());
133
134   if (state() != MediaStreamVideoSource::STARTED)
135     return;
136
137   const base::TimeDelta timestamp = base::TimeDelta::FromMicroseconds(
138       time_stamp_ns / base::Time::kNanosecondsPerMicrosecond);
139
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.
143   // crbug/359587.
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(
148       frame_size,
149       MediaStreamVideoSource::kUnknownFrameRate,
150       media::PIXEL_FORMAT_YV12);
151
152   libyuv::BGRAToI420(reinterpret_cast<uint8*>(bitmap->getPixels()),
153                      bitmap->rowBytes(),
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());
161
162   delegate_->DeliverFrame(new_frame, format);
163 }
164
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);
173   }
174
175   virtual ~PpFrameWriterProxy() {}
176
177   virtual void PutFrame(PPB_ImageData_Impl* image_data,
178                         int64 time_stamp_ns) OVERRIDE {
179     writer_->PutFrame(image_data, time_stamp_ns);
180   }
181
182  private:
183   base::WeakPtr<PpFrameWriter> writer_;
184
185   DISALLOW_COPY_AND_ASSIGN(PpFrameWriterProxy);
186 };
187
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;
194   if (registry) {
195     stream = registry->GetMediaStream(url);
196   } else {
197     stream =
198         blink::WebMediaStreamRegistry::lookupMediaStreamDescriptor(GURL(url));
199   }
200   if (stream.isNull()) {
201     LOG(ERROR) << "VideoDestinationHandler::Open - invalid url: " << url;
202     return false;
203   }
204
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
211   // existing sources.
212   base::Base64Encode(base::RandBytesAsString(64), &track_id);
213
214   PpFrameWriter* writer = new PpFrameWriter();
215
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);
223
224   blink::WebMediaConstraints constraints;
225   constraints.initialize();
226   bool track_enabled = true;
227
228   stream.addTrack(MediaStreamVideoTrack::CreateVideoTrack(
229       writer, constraints, MediaStreamVideoSource::ConstraintsCallback(),
230       track_enabled));
231
232   *frame_writer = new PpFrameWriterProxy(writer->AsWeakPtr());
233   return true;
234 }
235
236 }  // namespace content