Home | History | Annotate | Download | only in media
      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/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 "content/renderer/media/media_stream_dependency_factory.h"
     13 #include "content/renderer/media/media_stream_registry_interface.h"
     14 #include "content/renderer/pepper/ppb_image_data_impl.h"
     15 #include "content/renderer/render_thread_impl.h"
     16 #include "third_party/WebKit/public/platform/WebMediaStreamTrack.h"
     17 #include "third_party/WebKit/public/web/WebMediaStreamRegistry.h"
     18 
     19 using cricket::CaptureState;
     20 using cricket::VideoFormat;
     21 using webrtc::VideoTrackInterface;
     22 using webrtc::VideoTrackVector;
     23 
     24 static const cricket::FourCC kEffectColorFormat = cricket::FOURCC_BGRA;
     25 
     26 namespace content {
     27 
     28 PpFrameWriter::PpFrameWriter()
     29     : started_(false) {}
     30 
     31 PpFrameWriter::~PpFrameWriter() {}
     32 
     33 CaptureState PpFrameWriter::Start(const VideoFormat& capture_format) {
     34   base::AutoLock auto_lock(lock_);
     35   if (started_) {
     36     LOG(ERROR) << "PpFrameWriter::Start - "
     37                << "Got a StartCapture when already started!";
     38     return cricket::CS_FAILED;
     39   }
     40   started_ = true;
     41   return cricket::CS_STARTING;
     42 }
     43 
     44 void PpFrameWriter::Stop() {
     45   base::AutoLock auto_lock(lock_);
     46   started_ = false;
     47   SignalStateChange(this, cricket::CS_STOPPED);
     48 }
     49 
     50 bool PpFrameWriter::IsRunning() {
     51   return started_;
     52 }
     53 
     54 bool PpFrameWriter::GetPreferredFourccs(std::vector<uint32>* fourccs) {
     55   if (!fourccs) {
     56     LOG(ERROR) << "PpFrameWriter::GetPreferredFourccs - "
     57                << "fourccs is NULL.";
     58     return false;
     59   }
     60   // The effects plugin output BGRA.
     61   fourccs->push_back(kEffectColorFormat);
     62   return true;
     63 }
     64 
     65 bool PpFrameWriter::GetBestCaptureFormat(const VideoFormat& desired,
     66                                          VideoFormat* best_format) {
     67   if (!best_format) {
     68     LOG(ERROR) << "PpFrameWriter::GetBestCaptureFormat - "
     69                << "best_format is NULL.";
     70     return false;
     71   }
     72 
     73   // Use the desired format as the best format.
     74   best_format->width = desired.width;
     75   best_format->height = desired.height;
     76   best_format->fourcc = kEffectColorFormat;
     77   best_format->interval = desired.interval;
     78   return true;
     79 }
     80 
     81 bool PpFrameWriter::IsScreencast() const {
     82   return false;
     83 }
     84 
     85 void PpFrameWriter::PutFrame(PPB_ImageData_Impl* image_data,
     86                              int64 time_stamp_ns) {
     87   base::AutoLock auto_lock(lock_);
     88   // This assumes the handler of the SignalFrameCaptured won't call Start/Stop.
     89   // TODO(ronghuawu): Avoid the using of lock. One way is to post this call to
     90   // libjingle worker thread, which will require an extra copy of |image_data|.
     91   // However if pepper host can hand over the ownership of |image_data|
     92   // then we can avoid this extra copy.
     93   if (!started_) {
     94     LOG(ERROR) << "PpFrameWriter::PutFrame - "
     95                << "Called when capturer is not started.";
     96     return;
     97   }
     98   if (!image_data) {
     99     LOG(ERROR) << "PpFrameWriter::PutFrame - Called with NULL image_data.";
    100     return;
    101   }
    102   ImageDataAutoMapper mapper(image_data);
    103   if (!mapper.is_valid()) {
    104     LOG(ERROR) << "PpFrameWriter::PutFrame - "
    105                << "The image could not be mapped and is unusable.";
    106     return;
    107   }
    108   const SkBitmap* bitmap = image_data->GetMappedBitmap();
    109   if (!bitmap) {
    110     LOG(ERROR) << "PpFrameWriter::PutFrame - "
    111                << "The image_data's mapped bitmap is NULL.";
    112     return;
    113   }
    114 
    115   cricket::CapturedFrame frame;
    116   frame.elapsed_time = 0;
    117   frame.time_stamp = time_stamp_ns;
    118   frame.pixel_height = 1;
    119   frame.pixel_width = 1;
    120   frame.width = bitmap->width();
    121   frame.height = bitmap->height();
    122   if (image_data->format() == PP_IMAGEDATAFORMAT_BGRA_PREMUL) {
    123     frame.fourcc = cricket::FOURCC_BGRA;
    124   } else {
    125     LOG(ERROR) << "PpFrameWriter::PutFrame - Got RGBA which is not supported.";
    126     return;
    127   }
    128   frame.data_size = bitmap->getSize();
    129   frame.data = bitmap->getPixels();
    130 
    131   // This signals to libJingle that a new VideoFrame is available.
    132   // libJingle have no assumptions on what thread this signal come from.
    133   SignalFrameCaptured(this, &frame);
    134 }
    135 
    136 // PpFrameWriterProxy is a helper class to make sure the user won't use
    137 // PpFrameWriter after it is released (IOW its owner - WebMediaStreamTrack -
    138 // is released).
    139 class PpFrameWriterProxy : public FrameWriterInterface {
    140  public:
    141   PpFrameWriterProxy(VideoTrackInterface* track,
    142                      PpFrameWriter* writer)
    143       : track_(track),
    144         writer_(writer) {
    145     DCHECK(writer_ != NULL);
    146   }
    147 
    148   virtual ~PpFrameWriterProxy() {}
    149 
    150   virtual void PutFrame(PPB_ImageData_Impl* image_data,
    151                         int64 time_stamp_ns) OVERRIDE {
    152     writer_->PutFrame(image_data, time_stamp_ns);
    153   }
    154 
    155  private:
    156   scoped_refptr<VideoTrackInterface> track_;
    157   PpFrameWriter* writer_;
    158 
    159   DISALLOW_COPY_AND_ASSIGN(PpFrameWriterProxy);
    160 };
    161 
    162 bool VideoDestinationHandler::Open(
    163     MediaStreamDependencyFactory* factory,
    164     MediaStreamRegistryInterface* registry,
    165     const std::string& url,
    166     FrameWriterInterface** frame_writer) {
    167   if (!factory) {
    168     factory = RenderThreadImpl::current()->GetMediaStreamDependencyFactory();
    169     DCHECK(factory != NULL);
    170   }
    171   blink::WebMediaStream stream;
    172   if (registry) {
    173     stream = registry->GetMediaStream(url);
    174   } else {
    175     stream =
    176         blink::WebMediaStreamRegistry::lookupMediaStreamDescriptor(GURL(url));
    177   }
    178   if (stream.isNull() || !stream.extraData()) {
    179     LOG(ERROR) << "VideoDestinationHandler::Open - invalid url: " << url;
    180     return false;
    181   }
    182 
    183   // Create a new native video track and add it to |stream|.
    184   std::string track_id;
    185   // According to spec, a media stream track's id should be globally unique.
    186   // There's no easy way to strictly achieve that. The id generated with this
    187   // method should be unique for most of the cases but theoretically it's
    188   // possible we can get an id that's duplicated with the existing tracks.
    189   base::Base64Encode(base::RandBytesAsString(64), &track_id);
    190   PpFrameWriter* writer = new PpFrameWriter();
    191   if (!factory->AddNativeVideoMediaTrack(track_id, &stream, writer)) {
    192     delete writer;
    193     return false;
    194   }
    195 
    196   // Gets a handler to the native video track, which owns the |writer|.
    197   MediaStreamExtraData* extra_data =
    198       static_cast<MediaStreamExtraData*>(stream.extraData());
    199   webrtc::MediaStreamInterface* native_stream = extra_data->stream().get();
    200   DCHECK(native_stream);
    201   VideoTrackVector video_tracks = native_stream->GetVideoTracks();
    202   // Currently one supports one video track per media stream.
    203   DCHECK(video_tracks.size() == 1);
    204 
    205   *frame_writer = new PpFrameWriterProxy(video_tracks[0].get(), writer);
    206   return true;
    207 }
    208 
    209 }  // namespace content
    210 
    211