| Index: content/renderer/media/webrtc/video_destination_handler.cc
 | 
| diff --git a/content/renderer/media/webrtc/video_destination_handler.cc b/content/renderer/media/webrtc/video_destination_handler.cc
 | 
| index 88d0fa3baa36f9f176e014b3f8c3ee50bc8454bf..160537165d7912e4c514f6d49272f9dd60d0adde 100644
 | 
| --- a/content/renderer/media/webrtc/video_destination_handler.cc
 | 
| +++ b/content/renderer/media/webrtc/video_destination_handler.cc
 | 
| @@ -29,113 +29,115 @@ class PpFrameWriter::FrameWriterDelegate
 | 
|      : public base::RefCountedThreadSafe<FrameWriterDelegate> {
 | 
|   public:
 | 
|    FrameWriterDelegate(
 | 
| -      const scoped_refptr<base::MessageLoopProxy>& io_message_loop_proxy,
 | 
| -      const VideoCaptureDeliverFrameCB& new_frame_callback);
 | 
| +      const scoped_refptr<base::MessageLoopProxy>& io_message_loop_proxy);
 | 
| +
 | 
| +  // Starts forwarding frames to |frame_callback| on the  IO-thread that are
 | 
| +  // delivered to this class by calling DeliverFrame on the main render thread.
 | 
| +  void StartDeliver(const VideoCaptureDeliverFrameCB& frame_callback);
 | 
| +  void StopDeliver();
 | 
| +
 | 
| +  void DeliverFrame(const scoped_refptr<PPB_ImageData_Impl>& image_data,
 | 
| +                    int64 time_stamp_ns);
 | 
|  
 | 
| -  void DeliverFrame(const scoped_refptr<media::VideoFrame>& frame,
 | 
| -                    const media::VideoCaptureFormat& format);
 | 
|   private:
 | 
|    friend class base::RefCountedThreadSafe<FrameWriterDelegate>;
 | 
|    virtual ~FrameWriterDelegate();
 | 
|  
 | 
| -  void DeliverFrameOnIO(const scoped_refptr<media::VideoFrame>& frame,
 | 
| -                        const media::VideoCaptureFormat& format);
 | 
| +  void StartDeliverOnIO(const VideoCaptureDeliverFrameCB& frame_callback);
 | 
| +  void StopDeliverOnIO();
 | 
| +
 | 
| +  void DeliverFrameOnIO(uint8* data, int stride, int width, int height,
 | 
| +                        int64 time_stamp_ns);
 | 
| +  void FrameDelivered(const scoped_refptr<PPB_ImageData_Impl>& image_data);
 | 
|  
 | 
|    scoped_refptr<base::MessageLoopProxy> io_message_loop_;
 | 
| +
 | 
| +  // |frame_pool_| and |new_frame_callback_| are only used on the IO-thread.
 | 
| +  media::VideoFramePool frame_pool_;
 | 
|    VideoCaptureDeliverFrameCB new_frame_callback_;
 | 
| +
 | 
| +  // Used to DCHECK that we are called on the main render thread.
 | 
| +  base::ThreadChecker thread_checker_;
 | 
|  };
 | 
|  
 | 
|  PpFrameWriter::FrameWriterDelegate::FrameWriterDelegate(
 | 
| -    const scoped_refptr<base::MessageLoopProxy>& io_message_loop_proxy,
 | 
| -    const VideoCaptureDeliverFrameCB& new_frame_callback)
 | 
| -    : io_message_loop_(io_message_loop_proxy),
 | 
| -      new_frame_callback_(new_frame_callback) {
 | 
| +    const scoped_refptr<base::MessageLoopProxy>& io_message_loop_proxy)
 | 
| +    : io_message_loop_(io_message_loop_proxy) {
 | 
|  }
 | 
|  
 | 
|  PpFrameWriter::FrameWriterDelegate::~FrameWriterDelegate() {
 | 
|  }
 | 
|  
 | 
| -void PpFrameWriter::FrameWriterDelegate::DeliverFrame(
 | 
| -    const scoped_refptr<media::VideoFrame>& frame,
 | 
| -    const media::VideoCaptureFormat& format) {
 | 
| +void PpFrameWriter::FrameWriterDelegate::StartDeliver(
 | 
| +    const VideoCaptureDeliverFrameCB& frame_callback) {
 | 
| +  DCHECK(thread_checker_.CalledOnValidThread());
 | 
|    io_message_loop_->PostTask(
 | 
|        FROM_HERE,
 | 
| -      base::Bind(&FrameWriterDelegate::DeliverFrameOnIO,
 | 
| -                 this, frame, format));
 | 
| -}
 | 
| -
 | 
| -void PpFrameWriter::FrameWriterDelegate::DeliverFrameOnIO(
 | 
| -     const scoped_refptr<media::VideoFrame>& frame,
 | 
| -     const media::VideoCaptureFormat& format) {
 | 
| -  DCHECK(io_message_loop_->BelongsToCurrentThread());
 | 
| -  // The local time when this frame is generated is unknown so give a null
 | 
| -  // value to |estimated_capture_time|.
 | 
| -  new_frame_callback_.Run(frame, format, base::TimeTicks());
 | 
| +      base::Bind(&FrameWriterDelegate::StartDeliverOnIO, this,
 | 
| +                 frame_callback));
 | 
|  }
 | 
|  
 | 
| -PpFrameWriter::PpFrameWriter() {
 | 
| -  DVLOG(3) << "PpFrameWriter ctor";
 | 
| -}
 | 
| -
 | 
| -PpFrameWriter::~PpFrameWriter() {
 | 
| -  DVLOG(3) << "PpFrameWriter dtor";
 | 
| -}
 | 
| -
 | 
| -void PpFrameWriter::GetCurrentSupportedFormats(
 | 
| -    int max_requested_width,
 | 
| -    int max_requested_height,
 | 
| -    double max_requested_frame_rate,
 | 
| -    const VideoCaptureDeviceFormatsCB& callback) {
 | 
| -  DCHECK(CalledOnValidThread());
 | 
| -  DVLOG(3) << "PpFrameWriter::GetCurrentSupportedFormats()";
 | 
| -  // Since the input is free to change the resolution at any point in time
 | 
| -  // the supported formats are unknown.
 | 
| -  media::VideoCaptureFormats formats;
 | 
| -  callback.Run(formats);
 | 
| -}
 | 
| -
 | 
| -void PpFrameWriter::StartSourceImpl(
 | 
| -    const media::VideoCaptureFormat& format,
 | 
| -    const VideoCaptureDeliverFrameCB& frame_callback) {
 | 
| -  DCHECK(CalledOnValidThread());
 | 
| -  DCHECK(!delegate_.get());
 | 
| -  DVLOG(3) << "PpFrameWriter::StartSourceImpl()";
 | 
| -  delegate_ = new FrameWriterDelegate(io_message_loop(), frame_callback);
 | 
| -  OnStartDone(MEDIA_DEVICE_OK);
 | 
| -}
 | 
| -
 | 
| -void PpFrameWriter::StopSourceImpl() {
 | 
| -  DCHECK(CalledOnValidThread());
 | 
| +void PpFrameWriter::FrameWriterDelegate::StopDeliver() {
 | 
| +  DCHECK(thread_checker_.CalledOnValidThread());
 | 
| +  io_message_loop_->PostTask(
 | 
| +      FROM_HERE,
 | 
| +      base::Bind(&FrameWriterDelegate::StopDeliverOnIO, this));
 | 
|  }
 | 
|  
 | 
| -void PpFrameWriter::PutFrame(PPB_ImageData_Impl* image_data,
 | 
| -                             int64 time_stamp_ns) {
 | 
| -  DCHECK(CalledOnValidThread());
 | 
| -  TRACE_EVENT0("video", "PpFrameWriter::PutFrame");
 | 
| -  DVLOG(3) << "PpFrameWriter::PutFrame()";
 | 
| -
 | 
| -  if (!image_data) {
 | 
| -    LOG(ERROR) << "PpFrameWriter::PutFrame - Called with NULL image_data.";
 | 
| -    return;
 | 
| -  }
 | 
| -  ImageDataAutoMapper mapper(image_data);
 | 
| -  if (!mapper.is_valid()) {
 | 
| +void PpFrameWriter::FrameWriterDelegate::DeliverFrame(
 | 
| +    const scoped_refptr<PPB_ImageData_Impl>& image_data,
 | 
| +    int64 time_stamp_ns) {
 | 
| +  DCHECK(thread_checker_.CalledOnValidThread());
 | 
| +  TRACE_EVENT0("video", "PpFrameWriter::FrameWriterDelegate::DeliverFrame");
 | 
| +  if (!image_data->Map()) {
 | 
|      LOG(ERROR) << "PpFrameWriter::PutFrame - "
 | 
|                 << "The image could not be mapped and is unusable.";
 | 
|      return;
 | 
|    }
 | 
| +
 | 
|    const SkBitmap* bitmap = image_data->GetMappedBitmap();
 | 
|    if (!bitmap) {
 | 
|      LOG(ERROR) << "PpFrameWriter::PutFrame - "
 | 
|                 << "The image_data's mapped bitmap is NULL.";
 | 
|      return;
 | 
|    }
 | 
| +  io_message_loop_->PostTaskAndReply(
 | 
| +      FROM_HERE,
 | 
| +      base::Bind(&FrameWriterDelegate::DeliverFrameOnIO, this,
 | 
| +                 static_cast<uint8*>(bitmap->getPixels()),
 | 
| +                 bitmap->rowBytes(),
 | 
| +                 bitmap->width(),
 | 
| +                 bitmap->height(),
 | 
| +                 time_stamp_ns),
 | 
| +      base::Bind(&FrameWriterDelegate::FrameDelivered, this,
 | 
| +                 image_data));
 | 
| +}
 | 
|  
 | 
| -  const gfx::Size frame_size(bitmap->width(), bitmap->height());
 | 
| +void PpFrameWriter::FrameWriterDelegate::FrameDelivered(
 | 
| +    const scoped_refptr<PPB_ImageData_Impl>& image_data) {
 | 
| +  DCHECK(thread_checker_.CalledOnValidThread());
 | 
| +  image_data->Unmap();
 | 
| +}
 | 
| +
 | 
| +void PpFrameWriter::FrameWriterDelegate::StartDeliverOnIO(
 | 
| +    const VideoCaptureDeliverFrameCB& frame_callback) {
 | 
| +  DCHECK(io_message_loop_->BelongsToCurrentThread());
 | 
| +  new_frame_callback_ = frame_callback;
 | 
| +}
 | 
| +void PpFrameWriter::FrameWriterDelegate::StopDeliverOnIO() {
 | 
| +  DCHECK(io_message_loop_->BelongsToCurrentThread());
 | 
| +  new_frame_callback_.Reset();
 | 
| +}
 | 
| +
 | 
| +void PpFrameWriter::FrameWriterDelegate::DeliverFrameOnIO(
 | 
| +    uint8* data, int stride, int width, int height, int64 time_stamp_ns) {
 | 
| +  DCHECK(io_message_loop_->BelongsToCurrentThread());
 | 
| +  TRACE_EVENT0("video", "PpFrameWriter::FrameWriterDelegate::DeliverFrameOnIO");
 | 
|  
 | 
| -  if (state() != MediaStreamVideoSource::STARTED)
 | 
| +  if (new_frame_callback_.is_null())
 | 
|      return;
 | 
|  
 | 
| +  const gfx::Size frame_size(width, height);
 | 
|    const base::TimeDelta timestamp = base::TimeDelta::FromMicroseconds(
 | 
|        time_stamp_ns / base::Time::kNanosecondsPerMicrosecond);
 | 
|  
 | 
| @@ -151,8 +153,8 @@ void PpFrameWriter::PutFrame(PPB_ImageData_Impl* image_data,
 | 
|        MediaStreamVideoSource::kUnknownFrameRate,
 | 
|        media::PIXEL_FORMAT_YV12);
 | 
|  
 | 
| -  libyuv::BGRAToI420(reinterpret_cast<uint8*>(bitmap->getPixels()),
 | 
| -                     bitmap->rowBytes(),
 | 
| +  libyuv::BGRAToI420(data,
 | 
| +                     stride,
 | 
|                       new_frame->data(media::VideoFrame::kYPlane),
 | 
|                       new_frame->stride(media::VideoFrame::kYPlane),
 | 
|                       new_frame->data(media::VideoFrame::kUPlane),
 | 
| @@ -161,36 +163,58 @@ void PpFrameWriter::PutFrame(PPB_ImageData_Impl* image_data,
 | 
|                       new_frame->stride(media::VideoFrame::kVPlane),
 | 
|                       frame_size.width(), frame_size.height());
 | 
|  
 | 
| -  delegate_->DeliverFrame(new_frame, format);
 | 
| +  // The local time when this frame is generated is unknown so give a null
 | 
| +  // value to |estimated_capture_time|.
 | 
| +  new_frame_callback_.Run(new_frame, format, base::TimeTicks());
 | 
|  }
 | 
|  
 | 
| -// PpFrameWriterProxy is a helper class to make sure the user won't use
 | 
| -// PpFrameWriter after it is released (IOW its owner - WebMediaStreamSource -
 | 
| -// is released).
 | 
| -class PpFrameWriterProxy : public FrameWriterInterface {
 | 
| - public:
 | 
| -  explicit PpFrameWriterProxy(const base::WeakPtr<PpFrameWriter>& writer)
 | 
| -      : writer_(writer) {
 | 
| -    DCHECK(writer_ != NULL);
 | 
| -  }
 | 
| +PpFrameWriter::PpFrameWriter() {
 | 
| +  DVLOG(3) << "PpFrameWriter ctor";
 | 
| +  delegate_ = new FrameWriterDelegate(io_message_loop());
 | 
| +}
 | 
|  
 | 
| -  virtual ~PpFrameWriterProxy() {}
 | 
| +PpFrameWriter::~PpFrameWriter() {
 | 
| +  DVLOG(3) << "PpFrameWriter dtor";
 | 
| +}
 | 
|  
 | 
| -  virtual void PutFrame(PPB_ImageData_Impl* image_data,
 | 
| -                        int64 time_stamp_ns) override {
 | 
| -    writer_->PutFrame(image_data, time_stamp_ns);
 | 
| -  }
 | 
| +VideoDestinationHandler::FrameWriterCallback
 | 
| +PpFrameWriter::GetFrameWriterCallback() {
 | 
| +  DCHECK(CalledOnValidThread());
 | 
| +  return base::Bind(&PpFrameWriter::FrameWriterDelegate::DeliverFrame,
 | 
| +                    delegate_);
 | 
| +}
 | 
|  
 | 
| - private:
 | 
| -  base::WeakPtr<PpFrameWriter> writer_;
 | 
| +void PpFrameWriter::GetCurrentSupportedFormats(
 | 
| +    int max_requested_width,
 | 
| +    int max_requested_height,
 | 
| +    double max_requested_frame_rate,
 | 
| +    const VideoCaptureDeviceFormatsCB& callback) {
 | 
| +  DCHECK(CalledOnValidThread());
 | 
| +  DVLOG(3) << "PpFrameWriter::GetCurrentSupportedFormats()";
 | 
| +  // Since the input is free to change the resolution at any point in time
 | 
| +  // the supported formats are unknown.
 | 
| +  media::VideoCaptureFormats formats;
 | 
| +  callback.Run(formats);
 | 
| +}
 | 
|  
 | 
| -  DISALLOW_COPY_AND_ASSIGN(PpFrameWriterProxy);
 | 
| -};
 | 
| +void PpFrameWriter::StartSourceImpl(
 | 
| +    const media::VideoCaptureFormat& format,
 | 
| +    const VideoCaptureDeliverFrameCB& frame_callback) {
 | 
| +  DCHECK(CalledOnValidThread());
 | 
| +  DVLOG(3) << "PpFrameWriter::StartSourceImpl()";
 | 
| +  delegate_->StartDeliver(frame_callback);
 | 
| +  OnStartDone(MEDIA_DEVICE_OK);
 | 
| +}
 | 
| +
 | 
| +void PpFrameWriter::StopSourceImpl() {
 | 
| +  DCHECK(CalledOnValidThread());
 | 
| +  delegate_->StopDeliver();
 | 
| +}
 | 
|  
 | 
|  bool VideoDestinationHandler::Open(
 | 
|      MediaStreamRegistryInterface* registry,
 | 
|      const std::string& url,
 | 
| -    FrameWriterInterface** frame_writer) {
 | 
| +    FrameWriterCallback* frame_writer) {
 | 
|    DVLOG(3) << "VideoDestinationHandler::Open";
 | 
|    blink::WebMediaStream stream;
 | 
|    if (registry) {
 | 
| @@ -214,6 +238,7 @@ bool VideoDestinationHandler::Open(
 | 
|    base::Base64Encode(base::RandBytesAsString(64), &track_id);
 | 
|  
 | 
|    PpFrameWriter* writer = new PpFrameWriter();
 | 
| +  *frame_writer = writer->GetFrameWriterCallback();
 | 
|  
 | 
|    // Create a new webkit video track.
 | 
|    blink::WebMediaStreamSource webkit_source;
 | 
| @@ -231,7 +256,6 @@ bool VideoDestinationHandler::Open(
 | 
|        writer, constraints, MediaStreamVideoSource::ConstraintsCallback(),
 | 
|        track_enabled));
 | 
|  
 | 
| -  *frame_writer = new PpFrameWriterProxy(writer->AsWeakPtr());
 | 
|    return true;
 | 
|  }
 | 
|  
 | 
| 
 |