Home | History | Annotate | Download | only in webrtc
      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
    237