| Index: content/renderer/media/webrtc/video_destination_handler.cc
|
| diff --git a/content/renderer/media/video_destination_handler.cc b/content/renderer/media/webrtc/video_destination_handler.cc
|
| similarity index 40%
|
| rename from content/renderer/media/video_destination_handler.cc
|
| rename to content/renderer/media/webrtc/video_destination_handler.cc
|
| index a76ca8974d855aa24476d9354ec7b6766848d951..ca3d4e45ffabc05c62e53bc147a09a0ffb04fd15 100644
|
| --- a/content/renderer/media/video_destination_handler.cc
|
| +++ b/content/renderer/media/webrtc/video_destination_handler.cc
|
| @@ -2,102 +2,65 @@
|
| // Use of this source code is governed by a BSD-style license that can be
|
| // found in the LICENSE file.
|
|
|
| -#include "content/renderer/media/video_destination_handler.h"
|
| +#include "content/renderer/media/webrtc/video_destination_handler.h"
|
|
|
| #include <string>
|
|
|
| #include "base/base64.h"
|
| #include "base/logging.h"
|
| #include "base/rand_util.h"
|
| +#include "base/strings/utf_string_conversions.h"
|
| #include "content/renderer/media/media_stream.h"
|
| #include "content/renderer/media/media_stream_dependency_factory.h"
|
| #include "content/renderer/media/media_stream_registry_interface.h"
|
| +#include "content/renderer/media/media_stream_video_track.h"
|
| #include "content/renderer/pepper/ppb_image_data_impl.h"
|
| #include "content/renderer/render_thread_impl.h"
|
| +#include "media/video/capture/video_capture_types.h"
|
| #include "third_party/WebKit/public/platform/WebMediaStreamTrack.h"
|
| #include "third_party/WebKit/public/platform/WebURL.h"
|
| #include "third_party/WebKit/public/web/WebMediaStreamRegistry.h"
|
| +#include "third_party/libyuv/include/libyuv/convert.h"
|
| #include "url/gurl.h"
|
|
|
| -using cricket::CaptureState;
|
| -using cricket::VideoFormat;
|
| -using webrtc::VideoTrackInterface;
|
| -using webrtc::VideoTrackVector;
|
| -
|
| -static const cricket::FourCC kEffectColorFormat = cricket::FOURCC_BGRA;
|
| -
|
| namespace content {
|
|
|
| -PpFrameWriter::PpFrameWriter()
|
| - : started_(false) {}
|
| -
|
| -PpFrameWriter::~PpFrameWriter() {}
|
| -
|
| -CaptureState PpFrameWriter::Start(const VideoFormat& capture_format) {
|
| - base::AutoLock auto_lock(lock_);
|
| - if (started_) {
|
| - LOG(ERROR) << "PpFrameWriter::Start - "
|
| - << "Got a StartCapture when already started!";
|
| - return cricket::CS_FAILED;
|
| - }
|
| - started_ = true;
|
| - return cricket::CS_STARTING;
|
| -}
|
| -
|
| -void PpFrameWriter::Stop() {
|
| - base::AutoLock auto_lock(lock_);
|
| - started_ = false;
|
| - SignalStateChange(this, cricket::CS_STOPPED);
|
| +PpFrameWriter::PpFrameWriter(MediaStreamDependencyFactory* factory)
|
| + : MediaStreamVideoSource(factory), first_frame_received_(false) {
|
| + DVLOG(3) << "PpFrameWriter ctor";
|
| }
|
|
|
| -bool PpFrameWriter::IsRunning() {
|
| - return started_;
|
| +PpFrameWriter::~PpFrameWriter() {
|
| + DVLOG(3) << "PpFrameWriter dtor";
|
| }
|
|
|
| -bool PpFrameWriter::GetPreferredFourccs(std::vector<uint32>* fourccs) {
|
| - if (!fourccs) {
|
| - LOG(ERROR) << "PpFrameWriter::GetPreferredFourccs - "
|
| - << "fourccs is NULL.";
|
| - return false;
|
| +void PpFrameWriter::GetCurrentSupportedFormats(int max_requested_width,
|
| + int max_requested_height) {
|
| + DCHECK(CalledOnValidThread());
|
| + DVLOG(3) << "PpFrameWriter::GetCurrentSupportedFormats()";
|
| + if (format_.IsValid()) {
|
| + media::VideoCaptureFormats formats;
|
| + formats.push_back(format_);
|
| + OnSupportedFormats(formats);
|
| }
|
| - // The effects plugin output BGRA.
|
| - fourccs->push_back(kEffectColorFormat);
|
| - return true;
|
| }
|
|
|
| -bool PpFrameWriter::GetBestCaptureFormat(const VideoFormat& desired,
|
| - VideoFormat* best_format) {
|
| - if (!best_format) {
|
| - LOG(ERROR) << "PpFrameWriter::GetBestCaptureFormat - "
|
| - << "best_format is NULL.";
|
| - return false;
|
| - }
|
| -
|
| - // Use the desired format as the best format.
|
| - best_format->width = desired.width;
|
| - best_format->height = desired.height;
|
| - best_format->fourcc = kEffectColorFormat;
|
| - best_format->interval = desired.interval;
|
| - return true;
|
| +void PpFrameWriter::StartSourceImpl(
|
| + const media::VideoCaptureParams& params) {
|
| + DCHECK(CalledOnValidThread());
|
| + DVLOG(3) << "PpFrameWriter::StartSourceImpl()";
|
| + OnStartDone(true);
|
| }
|
|
|
| -bool PpFrameWriter::IsScreencast() const {
|
| - return false;
|
| +void PpFrameWriter::StopSourceImpl() {
|
| + DCHECK(CalledOnValidThread());
|
| }
|
|
|
| void PpFrameWriter::PutFrame(PPB_ImageData_Impl* image_data,
|
| int64 time_stamp_ns) {
|
| - base::AutoLock auto_lock(lock_);
|
| - // This assumes the handler of the SignalFrameCaptured won't call Start/Stop.
|
| - // TODO(ronghuawu): Avoid the using of lock. One way is to post this call to
|
| - // libjingle worker thread, which will require an extra copy of |image_data|.
|
| - // However if pepper host can hand over the ownership of |image_data|
|
| - // then we can avoid this extra copy.
|
| - if (!started_) {
|
| - LOG(ERROR) << "PpFrameWriter::PutFrame - "
|
| - << "Called when capturer is not started.";
|
| - return;
|
| - }
|
| + DCHECK(CalledOnValidThread());
|
| + DVLOG(3) << "PpFrameWriter::PutFrame()";
|
| +
|
| if (!image_data) {
|
| LOG(ERROR) << "PpFrameWriter::PutFrame - Called with NULL image_data.";
|
| return;
|
| @@ -115,36 +78,51 @@ void PpFrameWriter::PutFrame(PPB_ImageData_Impl* image_data,
|
| return;
|
| }
|
|
|
| - cricket::CapturedFrame frame;
|
| - frame.elapsed_time = 0;
|
| - frame.time_stamp = time_stamp_ns;
|
| - frame.pixel_height = 1;
|
| - frame.pixel_width = 1;
|
| - frame.width = bitmap->width();
|
| - frame.height = bitmap->height();
|
| - if (image_data->format() == PP_IMAGEDATAFORMAT_BGRA_PREMUL) {
|
| - frame.fourcc = cricket::FOURCC_BGRA;
|
| - } else {
|
| - LOG(ERROR) << "PpFrameWriter::PutFrame - Got RGBA which is not supported.";
|
| - return;
|
| + const gfx::Size frame_size(bitmap->width(), bitmap->height());
|
| +
|
| + if (!first_frame_received_) {
|
| + first_frame_received_ = true;
|
| + format_ = media::VideoCaptureFormat(
|
| + frame_size,
|
| + MediaStreamVideoSource::kDefaultFrameRate,
|
| + media::PIXEL_FORMAT_I420);
|
| + if (state() == MediaStreamVideoSource::RETRIEVING_CAPABILITIES) {
|
| + media::VideoCaptureFormats formats;
|
| + formats.push_back(format_);
|
| + OnSupportedFormats(formats);
|
| + }
|
| }
|
| - frame.data_size = bitmap->getSize();
|
| - frame.data = bitmap->getPixels();
|
|
|
| - // This signals to libJingle that a new VideoFrame is available.
|
| - // libJingle have no assumptions on what thread this signal come from.
|
| - SignalFrameCaptured(this, &frame);
|
| + if (state() != MediaStreamVideoSource::STARTED)
|
| + return;
|
| +
|
| + const base::TimeDelta timestamp = base::TimeDelta::FromMilliseconds(
|
| + time_stamp_ns / talk_base::kNumNanosecsPerMillisec);
|
| +
|
| + scoped_refptr<media::VideoFrame> new_frame =
|
| + frame_pool_.CreateFrame(media::VideoFrame::I420, frame_size,
|
| + gfx::Rect(frame_size), frame_size, timestamp);
|
| +
|
| + libyuv::BGRAToI420(reinterpret_cast<uint8*>(bitmap->getPixels()),
|
| + bitmap->rowBytes(),
|
| + new_frame->data(media::VideoFrame::kYPlane),
|
| + new_frame->stride(media::VideoFrame::kYPlane),
|
| + new_frame->data(media::VideoFrame::kUPlane),
|
| + new_frame->stride(media::VideoFrame::kUPlane),
|
| + new_frame->data(media::VideoFrame::kVPlane),
|
| + new_frame->stride(media::VideoFrame::kVPlane),
|
| + frame_size.width(), frame_size.height());
|
| +
|
| + DeliverVideoFrame(new_frame);
|
| }
|
|
|
| // PpFrameWriterProxy is a helper class to make sure the user won't use
|
| -// PpFrameWriter after it is released (IOW its owner - WebMediaStreamTrack -
|
| +// PpFrameWriter after it is released (IOW its owner - WebMediaStreamSource -
|
| // is released).
|
| class PpFrameWriterProxy : public FrameWriterInterface {
|
| public:
|
| - PpFrameWriterProxy(VideoTrackInterface* track,
|
| - PpFrameWriter* writer)
|
| - : track_(track),
|
| - writer_(writer) {
|
| + explicit PpFrameWriterProxy(const base::WeakPtr<PpFrameWriter>& writer)
|
| + : writer_(writer) {
|
| DCHECK(writer_ != NULL);
|
| }
|
|
|
| @@ -156,8 +134,7 @@ class PpFrameWriterProxy : public FrameWriterInterface {
|
| }
|
|
|
| private:
|
| - scoped_refptr<VideoTrackInterface> track_;
|
| - PpFrameWriter* writer_;
|
| + base::WeakPtr<PpFrameWriter> writer_;
|
|
|
| DISALLOW_COPY_AND_ASSIGN(PpFrameWriterProxy);
|
| };
|
| @@ -167,6 +144,7 @@ bool VideoDestinationHandler::Open(
|
| MediaStreamRegistryInterface* registry,
|
| const std::string& url,
|
| FrameWriterInterface** frame_writer) {
|
| + DVLOG(3) << "VideoDestinationHandler::Open";
|
| if (!factory) {
|
| factory = RenderThreadImpl::current()->GetMediaStreamDependencyFactory();
|
| DCHECK(factory != NULL);
|
| @@ -178,32 +156,38 @@ bool VideoDestinationHandler::Open(
|
| stream =
|
| blink::WebMediaStreamRegistry::lookupMediaStreamDescriptor(GURL(url));
|
| }
|
| - if (stream.isNull() || !stream.extraData()) {
|
| + if (stream.isNull()) {
|
| LOG(ERROR) << "VideoDestinationHandler::Open - invalid url: " << url;
|
| return false;
|
| }
|
|
|
| // Create a new native video track and add it to |stream|.
|
| std::string track_id;
|
| - // According to spec, a media stream track's id should be globally unique.
|
| - // There's no easy way to strictly achieve that. The id generated with this
|
| - // method should be unique for most of the cases but theoretically it's
|
| - // possible we can get an id that's duplicated with the existing tracks.
|
| + // According to spec, a media stream source's id should be unique per
|
| + // application. There's no easy way to strictly achieve that. The id
|
| + // generated with this method should be unique for most of the cases but
|
| + // theoretically it's possible we can get an id that's duplicated with the
|
| + // existing sources.
|
| base::Base64Encode(base::RandBytesAsString(64), &track_id);
|
| - PpFrameWriter* writer = new PpFrameWriter();
|
| - if (!factory->AddNativeVideoMediaTrack(track_id, &stream, writer)) {
|
| - delete writer;
|
| - return false;
|
| - }
|
| + PpFrameWriter* writer = new PpFrameWriter(factory);
|
| +
|
| + // Create a new webkit video track.
|
| + blink::WebMediaStreamSource webkit_source;
|
| + blink::WebMediaStreamSource::Type type =
|
| + blink::WebMediaStreamSource::TypeVideo;
|
| + blink::WebString webkit_track_id = base::UTF8ToUTF16(track_id);
|
| + webkit_source.initialize(webkit_track_id, type, webkit_track_id);
|
| + webkit_source.setExtraData(writer);
|
| +
|
| + blink::WebMediaConstraints constraints;
|
| + constraints.initialize();
|
| + bool track_enabled = true;
|
|
|
| - // Gets a handler to the native video track, which owns the |writer|.
|
| - webrtc::MediaStreamInterface* native_stream = MediaStream::GetAdapter(stream);
|
| - DCHECK(native_stream);
|
| - VideoTrackVector video_tracks = native_stream->GetVideoTracks();
|
| - // Currently one supports one video track per media stream.
|
| - DCHECK(video_tracks.size() == 1);
|
| + stream.addTrack(MediaStreamVideoTrack::CreateVideoTrack(
|
| + writer, constraints, MediaStreamVideoSource::ConstraintsCallback(),
|
| + track_enabled, factory));
|
|
|
| - *frame_writer = new PpFrameWriterProxy(video_tracks[0].get(), writer);
|
| + *frame_writer = new PpFrameWriterProxy(writer->AsWeakPtr());
|
| return true;
|
| }
|
|
|
|
|