diff options
author | perkj@chromium.org <perkj@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2014-04-03 12:10:45 +0000 |
---|---|---|
committer | perkj@chromium.org <perkj@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2014-04-03 12:10:45 +0000 |
commit | f83821b30d54ac9566e4178b4efe62582ff1702e (patch) | |
tree | 9bf62fd2af0859b436a8a862fa9e538468f36144 | |
parent | ee46bbacd745d533fbd027a721e146e6ee357890 (diff) | |
download | chromium_src-f83821b30d54ac9566e4178b4efe62582ff1702e.zip chromium_src-f83821b30d54ac9566e4178b4efe62582ff1702e.tar.gz chromium_src-f83821b30d54ac9566e4178b4efe62582ff1702e.tar.bz2 |
Refactor VideoDestinationHandler to implement MediaStreamVideoSource.
VideoDestinationHandler is moved to media/webrtc since it needs to use libyuv. It also make sence since its a private API only used for WebRtc.
This cl also remove the WebRtcVideoCaptureAdapter::SetCurrrentFormat and make sure video resolution constraints are not passed to libJingle. Libjingle do not need to know the capture resolution or the used resolution constraints and that is infact how
VideoDestionationHandler can work today.
This is needed to simplify the adapter and the use of MediaStreamVideoSource since its currently not possible to call WebRtcVideoCaptureAdapter::SetCurrrentFormat before the MediaStreamVideoSource::OnSupportedFormat has been called.
BUG=334243
// TBR Jam for gyp changes, yzshen for the header file path change in Pepper.
R=joi@chromium.org, ronghuawu@chromium.org
TBR=jam, yzshen1
Review URL: https://codereview.chromium.org/212973002
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@261364 0039d316-1c4b-4281-b951-d872f2087c98
18 files changed, 442 insertions, 440 deletions
diff --git a/content/content_renderer.gypi b/content/content_renderer.gypi index 0cf05f0..e993306 100644 --- a/content/content_renderer.gypi +++ b/content/content_renderer.gypi @@ -701,14 +701,14 @@ 'renderer/media/rtc_video_encoder_factory.h', 'renderer/media/rtc_video_renderer.cc', 'renderer/media/rtc_video_renderer.h', - 'renderer/media/video_destination_handler.cc', - 'renderer/media/video_destination_handler.h', 'renderer/media/video_source_handler.cc', 'renderer/media/video_source_handler.h', 'renderer/media/webaudio_capturer_source.cc', 'renderer/media/webaudio_capturer_source.h', 'renderer/media/webrtc/media_stream_track_metrics.cc', 'renderer/media/webrtc/media_stream_track_metrics.h', + 'renderer/media/webrtc/video_destination_handler.cc', + 'renderer/media/webrtc/video_destination_handler.h', 'renderer/media/webrtc/webrtc_audio_sink_adapter.cc', 'renderer/media/webrtc/webrtc_audio_sink_adapter.h', 'renderer/media/webrtc/webrtc_local_audio_track_adapter.cc', @@ -780,8 +780,8 @@ ], 'sources!': [ 'renderer/media/pepper_platform_video_decoder.cc', - 'renderer/media/video_destination_handler.cc', - 'renderer/media/video_destination_handler.h', + 'renderer/media/webrtc/video_destination_handler.cc', + 'renderer/media/webrtc/video_destination_handler.h', 'renderer/render_widget_fullscreen_pepper.cc', 'renderer/render_widget_fullscreen_pepper.h', ], diff --git a/content/content_tests.gypi b/content/content_tests.gypi index 53dd279..2289ef4 100644 --- a/content/content_tests.gypi +++ b/content/content_tests.gypi @@ -564,6 +564,8 @@ 'renderer/media/media_stream_video_capture_source_unittest.cc', 'renderer/media/media_stream_video_source_unittest.cc', 'renderer/media/media_stream_video_track_unittest.cc', + 'renderer/media/mock_media_stream_video_sink.cc', + 'renderer/media/mock_media_stream_video_sink.h', 'renderer/media/mock_media_stream_video_source.cc', 'renderer/media/mock_media_stream_video_source.h', 'renderer/media/render_media_log_unittest.cc', @@ -572,7 +574,6 @@ 'renderer/media/video_capture_impl_manager_unittest.cc', 'renderer/media/video_capture_impl_unittest.cc', 'renderer/media/video_capture_message_filter_unittest.cc', - 'renderer/media/video_destination_handler_unittest.cc', 'renderer/media/video_frame_compositor_unittest.cc', 'renderer/media/webaudiosourceprovider_impl_unittest.cc', 'renderer/npapi/webplugin_impl_unittest.cc', @@ -703,7 +704,7 @@ 'sources!': [ 'browser/plugin_loader_posix_unittest.cc', 'renderer/media/media_stream_video_source_unittest.cc', - 'renderer/media/video_destination_handler_unittest.cc', + 'renderer/media/webrtc/video_destination_handler_unittest.cc', ], }], ['enable_webrtc==1', { @@ -725,6 +726,7 @@ 'renderer/media/rtc_video_decoder_unittest.cc', 'renderer/media/video_source_handler_unittest.cc', 'renderer/media/webrtc/media_stream_track_metrics_unittest.cc', + 'renderer/media/webrtc/video_destination_handler_unittest.cc', 'renderer/media/webrtc/webrtc_local_audio_track_adapter_unittest.cc', 'renderer/media/webrtc/webrtc_video_capturer_adapter_unittest.cc', 'renderer/media/webrtc_audio_capturer_unittest.cc', diff --git a/content/renderer/media/media_stream_video_source.cc b/content/renderer/media/media_stream_video_source.cc index 243d361..6091726 100644 --- a/content/renderer/media/media_stream_video_source.cc +++ b/content/renderer/media/media_stream_video_source.cc @@ -26,6 +26,17 @@ const char MediaStreamVideoSource::kMinHeight[] = "minHeight"; const char MediaStreamVideoSource::kMaxFrameRate[] = "maxFrameRate"; const char MediaStreamVideoSource::kMinFrameRate[] = "minFrameRate"; +const char* kSupportedConstraints[] = { + MediaStreamVideoSource::kMaxAspectRatio, + MediaStreamVideoSource::kMinAspectRatio, + MediaStreamVideoSource::kMaxWidth, + MediaStreamVideoSource::kMinWidth, + MediaStreamVideoSource::kMaxHeight, + MediaStreamVideoSource::kMinHeight, + MediaStreamVideoSource::kMaxFrameRate, + MediaStreamVideoSource::kMinFrameRate, +}; + const int MediaStreamVideoSource::kDefaultWidth = 640; const int MediaStreamVideoSource::kDefaultHeight = 480; const int MediaStreamVideoSource::kDefaultFrameRate = 30; @@ -283,6 +294,15 @@ MediaStreamVideoSource* MediaStreamVideoSource::GetVideoSource( return static_cast<MediaStreamVideoSource*>(source.extraData()); } +//static +bool MediaStreamVideoSource::IsConstraintSupported(const std::string& name) { + for (size_t i = 0; i < arraysize(kSupportedConstraints); ++i) { + if (kSupportedConstraints[i] == name) + return true; + } + return false; +} + MediaStreamVideoSource::MediaStreamVideoSource( MediaStreamDependencyFactory* factory) : state_(NEW), @@ -354,7 +374,6 @@ void MediaStreamVideoSource::InitAdapter() { device_info().device.type == MEDIA_TAB_VIDEO_CAPTURE || device_info().device.type == MEDIA_DESKTOP_VIDEO_CAPTURE; capture_adapter_ = factory_->CreateVideoCapturer(is_screencast); - capture_adapter_->SetRequestedFormat(current_format_); adapter_ = factory_->CreateVideoSource(capture_adapter_, current_constraints_); } diff --git a/content/renderer/media/media_stream_video_source.h b/content/renderer/media/media_stream_video_source.h index 651f003..11eacca 100644 --- a/content/renderer/media/media_stream_video_source.h +++ b/content/renderer/media/media_stream_video_source.h @@ -66,6 +66,9 @@ class CONTENT_EXPORT MediaStreamVideoSource // exist. webrtc::VideoSourceInterface* GetAdapter(); + // Return true if |name| is a constraint supported by MediaStreamVideoSource. + static bool IsConstraintSupported(const std::string& name); + // Constraint keys used by a video source. // Specified by draft-alvestrand-constraints-resolution-00b static const char kMinAspectRatio[]; // minAspectRatio @@ -120,6 +123,15 @@ class CONTENT_EXPORT MediaStreamVideoSource // method has been called, MediaStreamVideoSource may be deleted. virtual void StopSourceImpl() = 0; + enum State { + NEW, + RETRIEVING_CAPABILITIES, + STARTING, + STARTED, + ENDED + }; + State state() { return state_; } + private: // Creates a webrtc::VideoSourceInterface used by libjingle. void InitAdapter(); @@ -140,13 +152,6 @@ class CONTENT_EXPORT MediaStreamVideoSource // AddTrack match the format that was used to start the device. void FinalizeAddTrack(); - enum State { - NEW, - RETRIEVING_CAPABILITIES, - STARTING, - STARTED, - ENDED - }; State state_; media::VideoCaptureFormat current_format_; diff --git a/content/renderer/media/media_stream_video_source_unittest.cc b/content/renderer/media/media_stream_video_source_unittest.cc index 5a360ca..b3392da 100644 --- a/content/renderer/media/media_stream_video_source_unittest.cc +++ b/content/renderer/media/media_stream_video_source_unittest.cc @@ -383,4 +383,26 @@ TEST_F(MediaStreamVideoSourceTest, DeliverSmallerSizeWhenTooLargeMax) { 1280, 720); } +TEST_F(MediaStreamVideoSourceTest, IsConstraintSupported) { + EXPECT_TRUE(MediaStreamVideoSource::IsConstraintSupported( + MediaStreamVideoSource::kMaxFrameRate)); + EXPECT_TRUE(MediaStreamVideoSource::IsConstraintSupported( + MediaStreamVideoSource::kMinFrameRate)); + EXPECT_TRUE(MediaStreamVideoSource::IsConstraintSupported( + MediaStreamVideoSource::kMaxWidth)); + EXPECT_TRUE(MediaStreamVideoSource::IsConstraintSupported( + MediaStreamVideoSource::kMinWidth)); + EXPECT_TRUE(MediaStreamVideoSource::IsConstraintSupported( + MediaStreamVideoSource::kMaxHeight)); + EXPECT_TRUE(MediaStreamVideoSource::IsConstraintSupported( + MediaStreamVideoSource::kMinHeight)); + EXPECT_TRUE(MediaStreamVideoSource::IsConstraintSupported( + MediaStreamVideoSource::kMaxAspectRatio)); + EXPECT_TRUE(MediaStreamVideoSource::IsConstraintSupported( + MediaStreamVideoSource::kMinAspectRatio)); + + EXPECT_FALSE(MediaStreamVideoSource::IsConstraintSupported( + "googCpuAdaptation")); +} + } // namespace content diff --git a/content/renderer/media/media_stream_video_track_unittest.cc b/content/renderer/media/media_stream_video_track_unittest.cc index 242b9ce..d2e8482 100644 --- a/content/renderer/media/media_stream_video_track_unittest.cc +++ b/content/renderer/media/media_stream_video_track_unittest.cc @@ -5,43 +5,13 @@ #include "base/strings/utf_string_conversions.h" #include "content/renderer/media/media_stream_video_track.h" #include "content/renderer/media/mock_media_stream_dependency_factory.h" +#include "content/renderer/media/mock_media_stream_video_sink.h" #include "content/renderer/media/mock_media_stream_video_source.h" #include "media/base/video_frame.h" #include "testing/gtest/include/gtest/gtest.h" namespace content { -class MockVideoSink : public MediaStreamVideoSink { - public: - MockVideoSink() - : number_of_frames_(0), enabled_(true), - state_(blink::WebMediaStreamSource::ReadyStateLive) { - } - - virtual void OnVideoFrame( - const scoped_refptr<media::VideoFrame>& frame) OVERRIDE { - ++number_of_frames_; - } - - virtual void OnReadyStateChanged( - blink::WebMediaStreamSource::ReadyState state) OVERRIDE { - state_ = state; - } - - virtual void OnEnabledChanged(bool enabled) OVERRIDE { - enabled_ = enabled; - } - - int number_of_frames() const { return number_of_frames_; } - bool enabled() const { return enabled_; } - blink::WebMediaStreamSource::ReadyState state() const { return state_; } - - private: - int number_of_frames_; - bool enabled_; - blink::WebMediaStreamSource::ReadyState state_; -}; - class MediaStreamVideoTrackTest : public ::testing::Test { public: MediaStreamVideoTrackTest() @@ -84,7 +54,7 @@ TEST_F(MediaStreamVideoTrackTest, GetAdapter) { } TEST_F(MediaStreamVideoTrackTest, AddAndRemoveSink) { - MockVideoSink sink; + MockMediaStreamVideoSink sink; blink::WebMediaStreamTrack track = CreateTrack(); MediaStreamVideoSink::AddToVideoTrack(&sink, track); @@ -105,7 +75,7 @@ TEST_F(MediaStreamVideoTrackTest, AddAndRemoveSink) { } TEST_F(MediaStreamVideoTrackTest, SetEnabled) { - MockVideoSink sink; + MockMediaStreamVideoSink sink; blink::WebMediaStreamTrack track = CreateTrack(); MediaStreamVideoSink::AddToVideoTrack(&sink, track); @@ -131,7 +101,7 @@ TEST_F(MediaStreamVideoTrackTest, SetEnabled) { } TEST_F(MediaStreamVideoTrackTest, SourceStopped) { - MockVideoSink sink; + MockMediaStreamVideoSink sink; blink::WebMediaStreamTrack track = CreateTrack(); MediaStreamVideoSink::AddToVideoTrack(&sink, track); EXPECT_EQ(blink::WebMediaStreamSource::ReadyStateLive, sink.state()); diff --git a/content/renderer/media/mock_media_stream_dependency_factory.cc b/content/renderer/media/mock_media_stream_dependency_factory.cc index f934cce..1441d32 100644 --- a/content/renderer/media/mock_media_stream_dependency_factory.cc +++ b/content/renderer/media/mock_media_stream_dependency_factory.cc @@ -130,10 +130,6 @@ class MockRtcVideoCapturer : public WebRtcVideoCapturerAdapter { height_(0) { } - virtual void SetRequestedFormat( - const media::VideoCaptureFormat& format) OVERRIDE { - } - virtual void OnFrameCaptured( const scoped_refptr<media::VideoFrame>& frame) OVERRIDE { ++number_of_capturered_frames_; diff --git a/content/renderer/media/mock_media_stream_video_sink.cc b/content/renderer/media/mock_media_stream_video_sink.cc new file mode 100644 index 0000000..af09244 --- /dev/null +++ b/content/renderer/media/mock_media_stream_video_sink.cc @@ -0,0 +1,31 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "content/renderer/media/mock_media_stream_video_sink.h" + +namespace content { + +MockMediaStreamVideoSink::MockMediaStreamVideoSink() + : number_of_frames_(0), + enabled_(true), + format_(media::VideoFrame::UNKNOWN), + state_(blink::WebMediaStreamSource::ReadyStateLive) { +} + +void MockMediaStreamVideoSink::OnVideoFrame( + const scoped_refptr<media::VideoFrame>& frame) { + ++number_of_frames_; + format_ = frame->format(); +} + +void MockMediaStreamVideoSink::OnReadyStateChanged( + blink::WebMediaStreamSource::ReadyState state) { + state_ = state; +} + +void MockMediaStreamVideoSink::OnEnabledChanged(bool enabled) { + enabled_ = enabled; +} + +} // namespace content diff --git a/content/renderer/media/mock_media_stream_video_sink.h b/content/renderer/media/mock_media_stream_video_sink.h new file mode 100644 index 0000000..5802f8a --- /dev/null +++ b/content/renderer/media/mock_media_stream_video_sink.h @@ -0,0 +1,38 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CONTENT_RENDERER_MEDIA_MOCK_MEDIA_STREAM_VIDEO_SINK_H_ +#define CONTENT_RENDERER_MEDIA_MOCK_MEDIA_STREAM_VIDEO_SINK_H_ + +#include "content/public/renderer/media_stream_video_sink.h" + +#include "media/base/video_frame.h" + +namespace content { + +class MockMediaStreamVideoSink : public MediaStreamVideoSink { + public: + MockMediaStreamVideoSink(); + + virtual void OnVideoFrame( + const scoped_refptr<media::VideoFrame>& frame) OVERRIDE; + virtual void OnReadyStateChanged( + blink::WebMediaStreamSource::ReadyState state) OVERRIDE; + virtual void OnEnabledChanged(bool enabled) OVERRIDE; + + int number_of_frames() const { return number_of_frames_; } + media::VideoFrame::Format format() const { return format_; } + bool enabled() const { return enabled_; } + blink::WebMediaStreamSource::ReadyState state() const { return state_; } + + private: + int number_of_frames_; + bool enabled_; + media::VideoFrame::Format format_; + blink::WebMediaStreamSource::ReadyState state_; +}; + +} // namespace content + +#endif diff --git a/content/renderer/media/rtc_media_constraints.cc b/content/renderer/media/rtc_media_constraints.cc index a476be3..7f8b79d 100644 --- a/content/renderer/media/rtc_media_constraints.cc +++ b/content/renderer/media/rtc_media_constraints.cc @@ -8,6 +8,7 @@ #include "base/logging.h" #include "base/strings/string_util.h" #include "content/common/media/media_stream_options.h" +#include "content/renderer/media/media_stream_video_source.h" #include "third_party/WebKit/public/platform/WebMediaConstraints.h" #include "third_party/WebKit/public/platform/WebCString.h" #include "third_party/WebKit/public/platform/WebString.h" @@ -33,6 +34,10 @@ void GetNativeMediaConstraints( if (new_constraint.key == kMediaStreamSourceInfoId) continue; + // Ignore constraints that are handled by Chrome in MediaStreamVideoSource. + if (MediaStreamVideoSource::IsConstraintSupported(new_constraint.key)) + continue; + DVLOG(3) << "MediaStreamConstraints:" << new_constraint.key << " : " << new_constraint.value; native_constraints->push_back(new_constraint); diff --git a/content/renderer/media/video_destination_handler.cc b/content/renderer/media/video_destination_handler.cc deleted file mode 100644 index a76ca89..0000000 --- a/content/renderer/media/video_destination_handler.cc +++ /dev/null @@ -1,211 +0,0 @@ -// Copyright (c) 2013 The Chromium Authors. All rights reserved. -// 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 <string> - -#include "base/base64.h" -#include "base/logging.h" -#include "base/rand_util.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/pepper/ppb_image_data_impl.h" -#include "content/renderer/render_thread_impl.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 "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); -} - -bool PpFrameWriter::IsRunning() { - return started_; -} - -bool PpFrameWriter::GetPreferredFourccs(std::vector<uint32>* fourccs) { - if (!fourccs) { - LOG(ERROR) << "PpFrameWriter::GetPreferredFourccs - " - << "fourccs is NULL."; - return false; - } - // 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; -} - -bool PpFrameWriter::IsScreencast() const { - return false; -} - -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; - } - if (!image_data) { - LOG(ERROR) << "PpFrameWriter::PutFrame - Called with NULL image_data."; - return; - } - ImageDataAutoMapper mapper(image_data); - if (!mapper.is_valid()) { - 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; - } - - 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; - } - 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); -} - -// PpFrameWriterProxy is a helper class to make sure the user won't use -// PpFrameWriter after it is released (IOW its owner - WebMediaStreamTrack - -// is released). -class PpFrameWriterProxy : public FrameWriterInterface { - public: - PpFrameWriterProxy(VideoTrackInterface* track, - PpFrameWriter* writer) - : track_(track), - writer_(writer) { - DCHECK(writer_ != NULL); - } - - virtual ~PpFrameWriterProxy() {} - - virtual void PutFrame(PPB_ImageData_Impl* image_data, - int64 time_stamp_ns) OVERRIDE { - writer_->PutFrame(image_data, time_stamp_ns); - } - - private: - scoped_refptr<VideoTrackInterface> track_; - PpFrameWriter* writer_; - - DISALLOW_COPY_AND_ASSIGN(PpFrameWriterProxy); -}; - -bool VideoDestinationHandler::Open( - MediaStreamDependencyFactory* factory, - MediaStreamRegistryInterface* registry, - const std::string& url, - FrameWriterInterface** frame_writer) { - if (!factory) { - factory = RenderThreadImpl::current()->GetMediaStreamDependencyFactory(); - DCHECK(factory != NULL); - } - blink::WebMediaStream stream; - if (registry) { - stream = registry->GetMediaStream(url); - } else { - stream = - blink::WebMediaStreamRegistry::lookupMediaStreamDescriptor(GURL(url)); - } - if (stream.isNull() || !stream.extraData()) { - 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. - base::Base64Encode(base::RandBytesAsString(64), &track_id); - PpFrameWriter* writer = new PpFrameWriter(); - if (!factory->AddNativeVideoMediaTrack(track_id, &stream, writer)) { - delete writer; - return false; - } - - // 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); - - *frame_writer = new PpFrameWriterProxy(video_tracks[0].get(), writer); - return true; -} - -} // namespace content - diff --git a/content/renderer/media/video_destination_handler_unittest.cc b/content/renderer/media/video_destination_handler_unittest.cc deleted file mode 100644 index f220f9f..0000000 --- a/content/renderer/media/video_destination_handler_unittest.cc +++ /dev/null @@ -1,126 +0,0 @@ -// Copyright (c) 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include <string> - -#include "base/strings/utf_string_conversions.h" -#include "content/renderer/media/media_stream.h" -#include "content/renderer/media/mock_media_stream_dependency_factory.h" -#include "content/renderer/media/mock_media_stream_registry.h" -#include "content/renderer/media/video_destination_handler.h" -#include "testing/gmock/include/gmock/gmock.h" -#include "testing/gtest/include/gtest/gtest.h" -#include "third_party/WebKit/public/platform/WebMediaStreamTrack.h" -#include "third_party/WebKit/public/platform/WebString.h" - -using cricket::CapturedFrame; -using cricket::CaptureState; -using cricket::VideoCapturer; -using cricket::VideoFormat; -using cricket::VideoFormatPod; - -namespace content { - -static const std::string kTestStreamUrl = "stream_url"; -static const std::string kUnknownStreamUrl = "unknown_stream_url"; -static const VideoFormatPod kTestFormat = { - 640, 360, FPS_TO_INTERVAL(30), cricket::FOURCC_ANY -}; - -class PpFrameWriterTest - : public ::testing::Test, - public sigslot::has_slots<> { - public: - PpFrameWriterTest() - : last_capture_state_(cricket::CS_FAILED), - captured_frame_count_(0), - captured_frame_(NULL) { - writer_.SignalStateChange.connect(this, &PpFrameWriterTest::OnStateChange); - writer_.SignalFrameCaptured.connect( - this, &PpFrameWriterTest::OnFrameCaptured); - } - - void OnStateChange(VideoCapturer* capturer, CaptureState state) { - last_capture_state_ = state; - } - - void OnFrameCaptured(VideoCapturer* capturer, const CapturedFrame* frame) { - ++captured_frame_count_; - captured_frame_ = const_cast<CapturedFrame*>(frame); - } - - protected: - PpFrameWriter writer_; - CaptureState last_capture_state_; - int captured_frame_count_; - CapturedFrame* captured_frame_; -}; - -class VideoDestinationHandlerTest : public ::testing::Test { - public: - VideoDestinationHandlerTest() : registry_(&factory_) { - registry_.Init(kTestStreamUrl); - } - - protected: - MockMediaStreamDependencyFactory factory_; - MockMediaStreamRegistry registry_; -}; - -TEST_F(PpFrameWriterTest, StartStop) { - EXPECT_FALSE(writer_.IsRunning()); - EXPECT_EQ(cricket::CS_STARTING, writer_.Start(VideoFormat(kTestFormat))); - EXPECT_TRUE(writer_.IsRunning()); - EXPECT_EQ(cricket::CS_FAILED, writer_.Start(VideoFormat(kTestFormat))); - writer_.Stop(); - EXPECT_EQ(cricket::CS_STOPPED, last_capture_state_); -} - -TEST_F(PpFrameWriterTest, GetPreferredFourccs) { - std::vector<uint32> fourccs; - EXPECT_TRUE(writer_.GetPreferredFourccs(&fourccs)); - EXPECT_EQ(1u, fourccs.size()); - EXPECT_EQ(cricket::FOURCC_BGRA, fourccs[0]); -} - -TEST_F(PpFrameWriterTest, GetBestCaptureFormat) { - VideoFormat desired(kTestFormat); - VideoFormat best_format; - EXPECT_FALSE(writer_.GetBestCaptureFormat(desired, NULL)); - EXPECT_TRUE(writer_.GetBestCaptureFormat(desired, &best_format)); - EXPECT_EQ(cricket::FOURCC_BGRA, best_format.fourcc); - - desired.fourcc = best_format.fourcc; - EXPECT_EQ(desired, best_format); -} - -TEST_F(VideoDestinationHandlerTest, Open) { - FrameWriterInterface* frame_writer = NULL; - // Unknow url will return false. - EXPECT_FALSE(VideoDestinationHandler::Open(&factory_, ®istry_, - kUnknownStreamUrl, &frame_writer)); - EXPECT_TRUE(VideoDestinationHandler::Open(&factory_, ®istry_, - kTestStreamUrl, &frame_writer)); - EXPECT_TRUE(frame_writer); - - // Verify the video track has been added. - const blink::WebMediaStream test_stream = registry_.test_stream(); - blink::WebVector<blink::WebMediaStreamTrack> video_tracks; - test_stream.videoTracks(video_tracks); - EXPECT_EQ(1u, video_tracks.size()); - - // Verify the native video track has been added. - MediaStream* native_stream = MediaStream::GetMediaStream(test_stream); - DCHECK(native_stream); - webrtc::MediaStreamInterface* webrtc_stream = - MediaStream::GetAdapter(test_stream); - DCHECK(webrtc_stream); - webrtc::VideoTrackVector webrtc_video_tracks = - webrtc_stream->GetVideoTracks(); - EXPECT_EQ(1u, webrtc_video_tracks.size()); - - delete frame_writer; -} - -} // namespace content diff --git a/content/renderer/media/webrtc/video_destination_handler.cc b/content/renderer/media/webrtc/video_destination_handler.cc new file mode 100644 index 0000000..ca3d4e4 --- /dev/null +++ b/content/renderer/media/webrtc/video_destination_handler.cc @@ -0,0 +1,195 @@ +// Copyright (c) 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#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" + +namespace content { + +PpFrameWriter::PpFrameWriter(MediaStreamDependencyFactory* factory) + : MediaStreamVideoSource(factory), first_frame_received_(false) { + DVLOG(3) << "PpFrameWriter ctor"; +} + +PpFrameWriter::~PpFrameWriter() { + DVLOG(3) << "PpFrameWriter dtor"; +} + +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); + } +} + +void PpFrameWriter::StartSourceImpl( + const media::VideoCaptureParams& params) { + DCHECK(CalledOnValidThread()); + DVLOG(3) << "PpFrameWriter::StartSourceImpl()"; + OnStartDone(true); +} + +void PpFrameWriter::StopSourceImpl() { + DCHECK(CalledOnValidThread()); +} + +void PpFrameWriter::PutFrame(PPB_ImageData_Impl* image_data, + int64 time_stamp_ns) { + DCHECK(CalledOnValidThread()); + 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()) { + 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; + } + + 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); + } + } + + 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 - WebMediaStreamSource - +// is released). +class PpFrameWriterProxy : public FrameWriterInterface { + public: + explicit PpFrameWriterProxy(const base::WeakPtr<PpFrameWriter>& writer) + : writer_(writer) { + DCHECK(writer_ != NULL); + } + + virtual ~PpFrameWriterProxy() {} + + virtual void PutFrame(PPB_ImageData_Impl* image_data, + int64 time_stamp_ns) OVERRIDE { + writer_->PutFrame(image_data, time_stamp_ns); + } + + private: + base::WeakPtr<PpFrameWriter> writer_; + + DISALLOW_COPY_AND_ASSIGN(PpFrameWriterProxy); +}; + +bool VideoDestinationHandler::Open( + MediaStreamDependencyFactory* factory, + MediaStreamRegistryInterface* registry, + const std::string& url, + FrameWriterInterface** frame_writer) { + DVLOG(3) << "VideoDestinationHandler::Open"; + if (!factory) { + factory = RenderThreadImpl::current()->GetMediaStreamDependencyFactory(); + DCHECK(factory != NULL); + } + blink::WebMediaStream stream; + if (registry) { + stream = registry->GetMediaStream(url); + } else { + stream = + blink::WebMediaStreamRegistry::lookupMediaStreamDescriptor(GURL(url)); + } + 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 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(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; + + stream.addTrack(MediaStreamVideoTrack::CreateVideoTrack( + writer, constraints, MediaStreamVideoSource::ConstraintsCallback(), + track_enabled, factory)); + + *frame_writer = new PpFrameWriterProxy(writer->AsWeakPtr()); + return true; +} + +} // namespace content + diff --git a/content/renderer/media/video_destination_handler.h b/content/renderer/media/webrtc/video_destination_handler.h index 578fe22..e490002 100644 --- a/content/renderer/media/video_destination_handler.h +++ b/content/renderer/media/webrtc/video_destination_handler.h @@ -2,16 +2,17 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef CONTENT_RENDERER_MEDIA_VIDEO_DESTINATION_HANDLER_H_ -#define CONTENT_RENDERER_MEDIA_VIDEO_DESTINATION_HANDLER_H_ +#ifndef CONTENT_RENDERER_MEDIA_WEBRTC_VIDEO_DESTINATION_HANDLER_H_ +#define CONTENT_RENDERER_MEDIA_WEBRTC_VIDEO_DESTINATION_HANDLER_H_ #include <string> #include <vector> #include "base/compiler_specific.h" -#include "base/synchronization/lock.h" +#include "base/memory/weak_ptr.h" #include "content/common/content_export.h" -#include "third_party/libjingle/source/talk/media/base/videocapturer.h" +#include "content/renderer/media/media_stream_video_source.h" +#include "media/base/video_frame_pool.h" namespace content { @@ -30,43 +31,40 @@ class CONTENT_EXPORT FrameWriterInterface { virtual ~FrameWriterInterface() {} }; -// PpFrameWriter implements cricket::VideoCapturer so that it can be used in -// the native video track's video source. It also implements +// PpFrameWriter implements MediaStreamVideoSource and can therefore provide +// video frames to MediaStreamVideoTracks. It also implements // FrameWriterInterface, which will be used by the effects pepper plugin to // inject the processed frame. class CONTENT_EXPORT PpFrameWriter - : public NON_EXPORTED_BASE(cricket::VideoCapturer), - public FrameWriterInterface { + : NON_EXPORTED_BASE(public MediaStreamVideoSource), + public FrameWriterInterface, + NON_EXPORTED_BASE(public base::SupportsWeakPtr<PpFrameWriter>) { public: - PpFrameWriter(); + explicit PpFrameWriter(MediaStreamDependencyFactory* factory); virtual ~PpFrameWriter(); - // cricket::VideoCapturer implementation. - // These methods are accessed from a libJingle worker thread. - virtual cricket::CaptureState Start( - const cricket::VideoFormat& capture_format) OVERRIDE; - virtual void Stop() OVERRIDE; - virtual bool IsRunning() OVERRIDE; - virtual bool GetPreferredFourccs(std::vector<uint32>* fourccs) OVERRIDE; - virtual bool GetBestCaptureFormat(const cricket::VideoFormat& desired, - cricket::VideoFormat* best_format) OVERRIDE; - virtual bool IsScreencast() const OVERRIDE; - // FrameWriterInterface implementation. // This method will be called by the Pepper host from render thread. virtual void PutFrame(PPB_ImageData_Impl* image_data, int64 time_stamp_ns) OVERRIDE; + protected: + // MediaStreamVideoSource implementation. + virtual void GetCurrentSupportedFormats(int max_requested_width, + int max_requested_height) OVERRIDE; + virtual void StartSourceImpl( + const media::VideoCaptureParams& params) OVERRIDE; + virtual void StopSourceImpl() OVERRIDE; private: - bool started_; - // |lock_| is used to protect |started_| which will be accessed from different - // threads - libjingle worker thread and render thread. - base::Lock lock_; + // |format_| is the format currently received by this source. + media::VideoCaptureFormat format_; + bool first_frame_received_; + media::VideoFramePool frame_pool_; DISALLOW_COPY_AND_ASSIGN(PpFrameWriter); }; -// VideoDestinationHandler is a glue class between the webrtc MediaStream and +// VideoDestinationHandler is a glue class between the content MediaStream and // the effects pepper plugin host. class CONTENT_EXPORT VideoDestinationHandler { public: diff --git a/content/renderer/media/webrtc/video_destination_handler_unittest.cc b/content/renderer/media/webrtc/video_destination_handler_unittest.cc new file mode 100644 index 0000000..7a99b38 --- /dev/null +++ b/content/renderer/media/webrtc/video_destination_handler_unittest.cc @@ -0,0 +1,83 @@ +// Copyright (c) 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include <string> + +#include "base/strings/utf_string_conversions.h" +#include "content/renderer/media/media_stream.h" +#include "content/renderer/media/media_stream_video_track.h" +#include "content/renderer/media/mock_media_stream_dependency_factory.h" +#include "content/renderer/media/mock_media_stream_registry.h" +#include "content/renderer/media/mock_media_stream_video_sink.h" +#include "content/renderer/media/webrtc/video_destination_handler.h" +#include "content/renderer/pepper/pepper_plugin_instance_impl.h" +#include "content/renderer/pepper/ppb_image_data_impl.h" +#include "content/test/ppapi_unittest.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "third_party/WebKit/public/platform/WebMediaStreamTrack.h" +#include "third_party/WebKit/public/platform/WebString.h" + +namespace content { + +static const std::string kTestStreamUrl = "stream_url"; +static const std::string kUnknownStreamUrl = "unknown_stream_url"; + +class VideoDestinationHandlerTest : public PpapiUnittest { + public: + VideoDestinationHandlerTest() : registry_(&factory_) { + registry_.Init(kTestStreamUrl); + } + + protected: + MockMediaStreamDependencyFactory factory_; + MockMediaStreamRegistry registry_; +}; + +TEST_F(VideoDestinationHandlerTest, Open) { + FrameWriterInterface* frame_writer = NULL; + // Unknow url will return false. + EXPECT_FALSE(VideoDestinationHandler::Open(&factory_, ®istry_, + kUnknownStreamUrl, &frame_writer)); + EXPECT_TRUE(VideoDestinationHandler::Open(&factory_, ®istry_, + kTestStreamUrl, &frame_writer)); + // The |frame_writer| is a proxy and is owned by who call Open. + delete frame_writer; +} + +TEST_F(VideoDestinationHandlerTest, PutFrame) { + FrameWriterInterface* frame_writer = NULL; + EXPECT_TRUE(VideoDestinationHandler::Open(&factory_, ®istry_, + kTestStreamUrl, &frame_writer)); + ASSERT_TRUE(frame_writer); + + // Verify the video track has been added. + const blink::WebMediaStream test_stream = registry_.test_stream(); + blink::WebVector<blink::WebMediaStreamTrack> video_tracks; + test_stream.videoTracks(video_tracks); + ASSERT_EQ(1u, video_tracks.size()); + + // Verify the native video track has been added. + MediaStreamVideoTrack* native_track = + MediaStreamVideoTrack::GetVideoTrack(video_tracks[0]); + ASSERT_TRUE(native_track != NULL); + + MockMediaStreamVideoSink sink; + native_track->AddSink(&sink); + + scoped_refptr<PPB_ImageData_Impl> image( + new PPB_ImageData_Impl(instance()->pp_instance(), + PPB_ImageData_Impl::ForTest())); + image->Init(PP_IMAGEDATAFORMAT_BGRA_PREMUL, 640, 360, true); + frame_writer->PutFrame(image, 10); + EXPECT_EQ(1, sink.number_of_frames()); + // TODO(perkj): Verify that the track output I420 when + // https://codereview.chromium.org/213423006/ is landed. + + native_track->RemoveSink(&sink); + + // The |frame_writer| is a proxy and is owned by who call Open. + delete frame_writer; +} + +} // namespace content diff --git a/content/renderer/media/webrtc/webrtc_video_capturer_adapter.cc b/content/renderer/media/webrtc/webrtc_video_capturer_adapter.cc index 6d6f7ff..d028b3f 100644 --- a/content/renderer/media/webrtc/webrtc_video_capturer_adapter.cc +++ b/content/renderer/media/webrtc/webrtc_video_capturer_adapter.cc @@ -24,25 +24,6 @@ WebRtcVideoCapturerAdapter::~WebRtcVideoCapturerAdapter() { base::AlignedFree(buffer_); } -void WebRtcVideoCapturerAdapter::SetRequestedFormat( - const media::VideoCaptureFormat& format) { - DCHECK_EQ(media::PIXEL_FORMAT_I420, format.pixel_format); - DVLOG(3) << "WebRtcVideoCapturerAdapter::SetRequestedFormat" - << " w = " << format.frame_size.width() - << " h = " << format.frame_size.height(); - cricket::VideoFormat supported_format(format.frame_size.width(), - format.frame_size.height(), - cricket::VideoFormat::FpsToInterval( - format.frame_rate), - cricket::FOURCC_I420); - SetCaptureFormat(&supported_format); - - // Update the desired aspect ratio so that later the video frame can be - // cropped to meet the requirement if the camera returns a different - // resolution than the |request|. - UpdateAspectRatio(format.frame_size.width(), format.frame_size.height()); -} - cricket::CaptureState WebRtcVideoCapturerAdapter::Start( const cricket::VideoFormat& capture_format) { DCHECK(!running_); diff --git a/content/renderer/media/webrtc/webrtc_video_capturer_adapter.h b/content/renderer/media/webrtc/webrtc_video_capturer_adapter.h index ca453e0..753bf3c 100644 --- a/content/renderer/media/webrtc/webrtc_video_capturer_adapter.h +++ b/content/renderer/media/webrtc/webrtc_video_capturer_adapter.h @@ -25,12 +25,6 @@ class CONTENT_EXPORT WebRtcVideoCapturerAdapter explicit WebRtcVideoCapturerAdapter(bool is_screencast); virtual ~WebRtcVideoCapturerAdapter(); - // Sets the requested format. cricket::VideoCapturer may try to scale or - // crop to this format if the frame delivered in OnFrameCaptured is not in - // this format. - // This method is virtual for testing purposes. - virtual void SetRequestedFormat(const media::VideoCaptureFormat& format); - // This method is virtual for testing purposes. virtual void OnFrameCaptured(const scoped_refptr<media::VideoFrame>& frame); diff --git a/content/renderer/pepper/pepper_video_destination_host.h b/content/renderer/pepper/pepper_video_destination_host.h index 1f48190..277b668 100644 --- a/content/renderer/pepper/pepper_video_destination_host.h +++ b/content/renderer/pepper/pepper_video_destination_host.h @@ -9,7 +9,7 @@ #include "base/memory/scoped_ptr.h" #include "base/memory/weak_ptr.h" #include "content/common/content_export.h" -#include "content/renderer/media/video_destination_handler.h" +#include "content/renderer/media/webrtc/video_destination_handler.h" #include "ppapi/c/pp_time.h" #include "ppapi/host/resource_host.h" |