diff options
author | hshi@chromium.org <hshi@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-07-02 20:03:42 +0000 |
---|---|---|
committer | hshi@chromium.org <hshi@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-07-02 20:03:42 +0000 |
commit | 76bf7f58d93256dfa5867b6730e446517ead2a30 (patch) | |
tree | 184a18d6d0ed95cfb13303ca6af1fb3b6ed8d44f /content | |
parent | 9c1daf729ceb981ca1650999a15d31d8dc0d1294 (diff) | |
download | chromium_src-76bf7f58d93256dfa5867b6730e446517ead2a30.zip chromium_src-76bf7f58d93256dfa5867b6730e446517ead2a30.tar.gz chromium_src-76bf7f58d93256dfa5867b6730e446517ead2a30.tar.bz2 |
Define EncodedVideoSource and RtcCapturedEncodingVideoCapturer.
Defined the interfaces for EVS (EncodedVideoSource) and related IPC messages
between renderer and browser processes for the purpose of encoded screen capture.
Added RtcCapturedEncodingVideoCapturerFactory which implements the
libjingle::WebRtcVideoEncoderFactory class, and the corresponding
RtcCapturedEncodingVideoCapturer which implements the webrtc::VideoEncoder.
Modify MediaStreamDependencyFactory and inject RtcCapturedEncodingVideoCaptureFactory
in PeerConnectionFactory. For the time being, the factory will only be instantiated
for Chrome OS and ARM.
BUG=238515
TEST=trybot
Review URL: https://chromiumcodereview.appspot.com/16320005
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@209760 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'content')
20 files changed, 1059 insertions, 18 deletions
diff --git a/content/browser/renderer_host/render_process_host_impl.cc b/content/browser/renderer_host/render_process_host_impl.cc index 03f28d7..4a7c8b8 100644 --- a/content/browser/renderer_host/render_process_host_impl.cc +++ b/content/browser/renderer_host/render_process_host_impl.cc @@ -954,6 +954,9 @@ void RenderProcessHostImpl::PropagateBrowserCommandLineToRenderer( switches::kDefaultTileHeight, switches::kMaxUntiledLayerWidth, switches::kMaxUntiledLayerHeight, +#if defined(OS_CHROMEOS) + switches::kEnableEncodedScreenCapture, +#endif switches::kEnableViewport, switches::kEnableInbandTextTracks, switches::kEnableOpusPlayback, diff --git a/content/common/content_message_generator.h b/content/common/content_message_generator.h index 174a63b..e7f0786 100644 --- a/content/common/content_message_generator.h +++ b/content/common/content_message_generator.h @@ -31,6 +31,7 @@ #include "content/common/input_messages.h" #include "content/common/java_bridge_messages.h" #include "content/common/media/audio_messages.h" +#include "content/common/media/encoded_video_capture_messages.h" #include "content/common/media/midi_messages.h" #if defined(OS_ANDROID) #include "content/common/media/media_player_messages_android.h" diff --git a/content/common/media/encoded_video_capture_messages.h b/content/common/media/encoded_video_capture_messages.h new file mode 100644 index 0000000..8de6fb9 --- /dev/null +++ b/content/common/media/encoded_video_capture_messages.h @@ -0,0 +1,128 @@ +// Copyright 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 "base/memory/shared_memory.h" +#include "ipc/ipc_message_macros.h" +#include "media/video/capture/video_capture_types.h" +#include "media/video/video_encode_types.h" + +#undef IPC_MESSAGE_EXPORT +#define IPC_MESSAGE_EXPORT CONTENT_EXPORT +#define IPC_MESSAGE_START EncodedVideoCaptureMsgStart + +#if !defined(OS_ANDROID) +IPC_ENUM_TRAITS(media::VideoCodec) +#endif // !defined(OS_ANDROID) + +IPC_STRUCT_TRAITS_BEGIN(media::VideoEncodingConfig) + IPC_STRUCT_TRAITS_MEMBER(codec_type) + IPC_STRUCT_TRAITS_MEMBER(codec_name) + IPC_STRUCT_TRAITS_MEMBER(max_resolution) + IPC_STRUCT_TRAITS_MEMBER(max_frames_per_second) + IPC_STRUCT_TRAITS_MEMBER(max_bitrate) +IPC_STRUCT_TRAITS_END() + +IPC_STRUCT_TRAITS_BEGIN(media::RuntimeVideoEncodingParameters) + IPC_STRUCT_TRAITS_MEMBER(target_bitrate) + IPC_STRUCT_TRAITS_MEMBER(max_bitrate) + IPC_STRUCT_TRAITS_MEMBER(frames_per_second) +IPC_STRUCT_TRAITS_END() + +IPC_STRUCT_TRAITS_BEGIN(media::VideoEncodingParameters) + IPC_STRUCT_TRAITS_MEMBER(codec_name) + IPC_STRUCT_TRAITS_MEMBER(resolution) + IPC_STRUCT_TRAITS_MEMBER(runtime_params) +IPC_STRUCT_TRAITS_END() + +IPC_STRUCT_TRAITS_BEGIN(media::BufferEncodingMetadata) + IPC_STRUCT_TRAITS_MEMBER(timestamp) + IPC_STRUCT_TRAITS_MEMBER(key_frame) +IPC_STRUCT_TRAITS_END() + +//------------------------------------------------------------------------------ +// Renderer Source Messages +// These are messages from the renderer to the browser process. + +// Queries the encoding capabilities for the device. A successful request +// results in EncoderVideoSourceMessage_CapabilitiesAvailable message. +IPC_MESSAGE_CONTROL2(EncodedVideoCaptureHostMsg_GetCapabilities, + int /* device_id */, + media::VideoCaptureSessionId /* session_id */) + +// Message from renderer to browser process to create a bitstream with specific +// parameters. A successful request results in beginning of streaming and +// EncoderVideoCaptureMsg_BitstreamCreated message to renderer. A failed request +// triggers EncodedVideoCaptureMsg_BitstreamDestroyed message. |session_id| is +// the capture session id returned by the MediaStreamManager. The renderer is +// responsible for generating unique |device_id| within its context that will be +// used to identify bitstreams in IPC. +IPC_MESSAGE_CONTROL3(EncodedVideoCaptureHostMsg_OpenBitstream, + int /* device_id */, + media::VideoCaptureSessionId /* session_id */, + media::VideoEncodingParameters /* params */) + +// Stops streaming a bitstream. When browser has finalized the bitstream it will +// trigger EncodedVideoCaptureMsg_BitstreamClosed message back to renderer. +// Renderer must be prepared to receive EncodedVideoCaptureMsg_BitstreamReady +// messages until it receives EncodedVideoCaptureMsg_BitstreamClosed message. +IPC_MESSAGE_CONTROL1(EncodedVideoCaptureHostMsg_CloseBitstream, + int /* device_id */) + +// Sets a stream's bitstream configuration. Will always result in +// EncodedVideoCaptureMsg_BitstreamConfigChanged message containing +// currently active parameters, regardless of whether this call succeeded or +// not. +IPC_MESSAGE_CONTROL2(EncodedVideoCaptureHostMsg_TryConfigureBitstream, + int /* device_id */, + media::RuntimeVideoEncodingParameters /* params */) + +// Notifies that the data within a buffer has been processed and it can be +// reused to encode upcoming bitstream. +IPC_MESSAGE_CONTROL2(EncodedVideoCaptureHostMsg_BitstreamBufferConsumed, + int /* device_id */, + int /* buffer_id */) + +//------------------------------------------------------------------------------ +// Renderer Messages +// These are messages from the browser to the renderer process. + +// Reports the encoding capabilities of the device. +IPC_MESSAGE_CONTROL2(EncodedVideoCaptureMsg_CapabilitiesAvailable, + int /* device_id */, + media::VideoEncodingCapabilities /* capabilities */) + +// Acknowledges a request to open an encoded video bitstream. When this message +// occurs, bitstream can be considered to be streaming, and renderer should be +// ready to start accepting EncodedVideoCaptureMsg_BitstreamReady messages and +// buffers contained within them. Shared memory buffers used to deliver the +// bitstream are assigned with buffer IDs as specified by the buffers parameter. +// All buffers have the same size as indicated by |buffer_size|. +IPC_MESSAGE_CONTROL4(EncodedVideoCaptureMsg_BitstreamOpened, + int /* device_id */, + media::VideoEncodingParameters /* params */, + std::vector<base::SharedMemoryHandle> /* buffers */, + uint32 /* buffer_size */) + +// Acknowledges a request to close an encoded video bitstream. +IPC_MESSAGE_CONTROL1(EncodedVideoCaptureMsg_BitstreamClosed, + int /* device_id */) + +// Informs the clients of the current encoding parameters, regardless of whether +// the previous request to change them has been successful or not. It is usually +// called in response to EncodedVideoCaptureHostMsg_TryConfigureBitstream +// at runtime, but can occur also as a result of config change initiated by +// encoder or other clients in the system, e.g. if there are multiple clients +// and bitstream config change is requested from one client, all clients should +// be prepared to handle the configuration change. +IPC_MESSAGE_CONTROL2(EncodedVideoCaptureMsg_BitstreamConfigChanged, + int /* device_id */, + media::RuntimeVideoEncodingParameters /* current_params */) + +// Indicates that a bitstream buffer is available for the stream. The value of +// |size| indicates the amount of valid bitstream data (in bytes). +IPC_MESSAGE_CONTROL4(EncodedVideoCaptureMsg_BitstreamReady, + int /* device_id */, + int /* buffer_id */, + uint32 /* size */, + media::BufferEncodingMetadata /* metadata */) diff --git a/content/content_common.gypi b/content/content_common.gypi index 85762d1..c029c29 100644 --- a/content/content_common.gypi +++ b/content/content_common.gypi @@ -259,6 +259,7 @@ 'common/mac/font_loader.h', 'common/mac/font_loader.mm', 'common/media/audio_messages.h', + 'common/media/encoded_video_capture_messages.h', 'common/media/media_param_traits.cc', 'common/media/media_param_traits.h', 'common/media/media_player_messages_android.h', diff --git a/content/content_renderer.gypi b/content/content_renderer.gypi index 0c70df5..4cd7c39 100644 --- a/content/content_renderer.gypi +++ b/content/content_renderer.gypi @@ -447,6 +447,10 @@ 'renderer/media/rtc_data_channel_handler.h', 'renderer/media/rtc_dtmf_sender_handler.cc', 'renderer/media/rtc_dtmf_sender_handler.h', + 'renderer/media/rtc_encoding_video_capturer.cc', + 'renderer/media/rtc_encoding_video_capturer.h', + 'renderer/media/rtc_encoding_video_capturer_factory.cc', + 'renderer/media/rtc_encoding_video_capturer_factory.h', 'renderer/media/rtc_media_constraints.cc', 'renderer/media/rtc_media_constraints.h', 'renderer/media/rtc_peer_connection_handler.cc', diff --git a/content/public/common/content_switches.cc b/content/public/common/content_switches.cc index 6e1f7b9..aaad345 100644 --- a/content/public/common/content_switches.cc +++ b/content/public/common/content_switches.cc @@ -318,6 +318,11 @@ const char kEnableDeviceMotion[] = "enable-device-motion"; // Enables restarting interrupted downloads. const char kEnableDownloadResumption[] = "enable-download-resumption"; +#if defined(OS_CHROMEOS) +// Enables hardware-encoded screen capture. +const char kEnableEncodedScreenCapture[] = "enable-encoded-screen-capture"; +#endif + // Enables WebKit features that are in development. const char kEnableExperimentalWebKitFeatures[] = "enable-experimental-webkit-features"; diff --git a/content/public/common/content_switches.h b/content/public/common/content_switches.h index 2edb22e..7218b239 100644 --- a/content/public/common/content_switches.h +++ b/content/public/common/content_switches.h @@ -35,6 +35,9 @@ extern const char kDisableBackingStoreLimit[]; CONTENT_EXPORT extern const char kDisableDatabases[]; extern const char kDisableDesktopNotifications[]; CONTENT_EXPORT extern const char kDisableDeviceOrientation[]; +#if defined(OS_CHROMEOS) +CONTENT_EXPORT extern const char kEnableEncodedScreenCapture[]; +#endif #if defined(OS_ANDROID) CONTENT_EXPORT extern const char kEnableExperimentalWebGL[]; #else diff --git a/content/renderer/media/media_stream_dependency_factory.cc b/content/renderer/media/media_stream_dependency_factory.cc index e334a04..8a6558e 100644 --- a/content/renderer/media/media_stream_dependency_factory.cc +++ b/content/renderer/media/media_stream_dependency_factory.cc @@ -11,6 +11,7 @@ #include "base/synchronization/waitable_event.h" #include "content/public/common/content_switches.h" #include "content/renderer/media/media_stream_source_extra_data.h" +#include "content/renderer/media/rtc_encoding_video_capturer_factory.h" #include "content/renderer/media/rtc_media_constraints.h" #include "content/renderer/media/rtc_peer_connection_handler.h" #include "content/renderer/media/rtc_video_capturer.h" @@ -487,17 +488,32 @@ bool MediaStreamDependencyFactory::CreatePeerConnectionFactory() { audio_device_ = new WebRtcAudioDeviceImpl(); cricket::WebRtcVideoDecoderFactory* decoder_factory = NULL; + cricket::WebRtcVideoEncoderFactory* encoder_factory = NULL; + #if defined(GOOGLE_TV) // PeerConnectionFactory will hold the ownership of this // VideoDecoderFactory. decoder_factory = decoder_factory_tv_ = new RTCVideoDecoderFactoryTv; #endif +#if defined(OS_CHROMEOS) + const CommandLine& command_line = *CommandLine::ForCurrentProcess(); + if (command_line.HasSwitch(switches::kEnableEncodedScreenCapture)) { + // PeerConnectionFactory owns the encoder factory. Pass a weak pointer of + // encoder factory to |vc_manager_| because the manager outlives it. + RtcEncodingVideoCapturerFactory* rtc_encoding_capturer_factory = + new RtcEncodingVideoCapturerFactory(); + encoder_factory = rtc_encoding_capturer_factory; + vc_manager_->set_encoding_capturer_factory( + rtc_encoding_capturer_factory->AsWeakPtr()); + } +#endif + scoped_refptr<webrtc::PeerConnectionFactoryInterface> factory( webrtc::CreatePeerConnectionFactory(worker_thread_, signaling_thread_, audio_device_.get(), - NULL, + encoder_factory, decoder_factory)); if (factory.get()) pc_factory_ = factory; diff --git a/content/renderer/media/rtc_encoding_video_capturer.cc b/content/renderer/media/rtc_encoding_video_capturer.cc new file mode 100644 index 0000000..87367ef --- /dev/null +++ b/content/renderer/media/rtc_encoding_video_capturer.cc @@ -0,0 +1,228 @@ +// Copyright 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/rtc_encoding_video_capturer.h" + +#include "base/logging.h" +#include "media/base/encoded_bitstream_buffer.h" + +namespace content { + +// Client of EncodedVideoSource. This object is created and owned by the +// RtcEncodingVideoCapturer. +class RtcEncodingVideoCapturer::EncodedVideoSourceClient : + public media::EncodedVideoSource::Client { + public: + EncodedVideoSourceClient( + media::EncodedVideoSource* encoded_video_source, + media::VideoEncodingParameters params, + webrtc::VideoCodecType rtc_codec_type); + virtual ~EncodedVideoSourceClient(); + + // media::EncodedVideoSource::Client implementation. + virtual void OnOpened( + const media::VideoEncodingParameters& params) OVERRIDE; + virtual void OnClosed() OVERRIDE; + virtual void OnBufferReady( + scoped_refptr<const media::EncodedBitstreamBuffer> buffer) OVERRIDE; + virtual void OnConfigChanged( + const media::RuntimeVideoEncodingParameters& params) OVERRIDE; + + // Getters and setters for bitstream properties. + media::RuntimeVideoEncodingParameters runtime_params() const; + void set_round_trip_time(base::TimeDelta round_trip_time); + void set_callback(webrtc::EncodedImageCallback* callback); + + private: + // Convert buffer to webrtc types and invoke encode complete callback. + void ReportEncodedFrame( + scoped_refptr<const media::EncodedBitstreamBuffer> buffer); + + media::VideoEncodingParameters params_; + webrtc::VideoCodecType rtc_codec_type_; + bool finished_; + + base::Time time_base_; + base::TimeDelta round_trip_time_; + media::EncodedVideoSource* encoded_video_source_; + webrtc::EncodedImageCallback* callback_; + + DISALLOW_COPY_AND_ASSIGN(EncodedVideoSourceClient); +}; + +RtcEncodingVideoCapturer::EncodedVideoSourceClient::EncodedVideoSourceClient( + media::EncodedVideoSource* encoded_video_source, + media::VideoEncodingParameters params, + webrtc::VideoCodecType rtc_codec_type) + : params_(params), + rtc_codec_type_(rtc_codec_type), + finished_(false), + encoded_video_source_(encoded_video_source), + callback_(NULL) { + DCHECK(encoded_video_source_); + encoded_video_source_->OpenBitstream(this, params); +} + +RtcEncodingVideoCapturer::EncodedVideoSourceClient:: + ~EncodedVideoSourceClient() { + if (!finished_) + encoded_video_source_->CloseBitstream(); +} + +media::RuntimeVideoEncodingParameters + RtcEncodingVideoCapturer::EncodedVideoSourceClient::runtime_params() const { + return params_.runtime_params; +} + +void RtcEncodingVideoCapturer::EncodedVideoSourceClient::set_round_trip_time( + base::TimeDelta round_trip_time) { + round_trip_time_ = round_trip_time; +} + +void RtcEncodingVideoCapturer::EncodedVideoSourceClient::set_callback( + webrtc::EncodedImageCallback* callback) { + DCHECK(!callback_); + callback_ = callback; +} + +void RtcEncodingVideoCapturer::EncodedVideoSourceClient::OnOpened( + const media::VideoEncodingParameters& params) { + params_ = params; +} + +void RtcEncodingVideoCapturer::EncodedVideoSourceClient::OnClosed() { + finished_ = true; +} + +void RtcEncodingVideoCapturer::EncodedVideoSourceClient::OnBufferReady( + scoped_refptr<const media::EncodedBitstreamBuffer> buffer) { + DCHECK(!finished_ && buffer); + + // First buffer constitutes the origin of the time for this bitstream context. + if (time_base_.is_null()) + time_base_ = buffer->metadata().timestamp; + + ReportEncodedFrame(buffer); + encoded_video_source_->ReturnBitstreamBuffer(buffer); +} + +void RtcEncodingVideoCapturer::EncodedVideoSourceClient::OnConfigChanged( + const media::RuntimeVideoEncodingParameters& params) { + params_.runtime_params = params; +} + +void RtcEncodingVideoCapturer::EncodedVideoSourceClient::ReportEncodedFrame( + scoped_refptr<const media::EncodedBitstreamBuffer> buffer) { + if (!callback_) + return; + + webrtc::EncodedImage image; + webrtc::CodecSpecificInfo codecInfo; + webrtc::RTPFragmentationHeader fragHeader; + + // TODO(hshi): remove this const_cast. Unfortunately webrtc::EncodedImage + // defines member |_buffer| of type uint8_t* even though webrtc never modifies + // the buffer contents. + image._buffer = const_cast<uint8_t*>(buffer->buffer()); + image._length = buffer->size(); + image._size = image._length; + + const media::BufferEncodingMetadata& metadata = buffer->metadata(); + base::TimeDelta capture_time = metadata.timestamp - time_base_; + image.capture_time_ms_ = capture_time.InMilliseconds(); + // Convert capture time to 90 kHz RTP timestamp. + image._timeStamp = (capture_time * 90000).InSeconds(); + if (metadata.key_frame) { + image._frameType = webrtc::kKeyFrame; + } else { + image._frameType = webrtc::kDeltaFrame; + } + image._completeFrame = true; + image._encodedWidth = params_.resolution.width(); + image._encodedHeight = params_.resolution.height(); + + // TODO(hshi): generate codec specific info for VP8. + codecInfo.codecType = rtc_codec_type_; + + // Generate header containing a single fragmentation. + fragHeader.VerifyAndAllocateFragmentationHeader(1); + fragHeader.fragmentationOffset[0] = 0; + fragHeader.fragmentationLength[0] = buffer->size(); + fragHeader.fragmentationPlType[0] = 0; + fragHeader.fragmentationTimeDiff[0] = 0; + + callback_->Encoded(image, &codecInfo, &fragHeader); +} + +// RtcEncodingVideoCapturer +RtcEncodingVideoCapturer::RtcEncodingVideoCapturer( + media::EncodedVideoSource* encoded_video_source, + webrtc::VideoCodecType codec_type) + : encoded_video_source_(encoded_video_source), + rtc_codec_type_(codec_type) { +} + +RtcEncodingVideoCapturer::~RtcEncodingVideoCapturer() { +} + +int32_t RtcEncodingVideoCapturer::InitEncode( + const webrtc::VideoCodec* codecSettings, + int32_t numberOfCores, + uint32_t maxPayloadSize) { + DCHECK(!encoded_video_source_client_); + if (codecSettings->codecType != rtc_codec_type_) + return WEBRTC_VIDEO_CODEC_ERR_PARAMETER; + + // Convert |codecSettings| to |params|. + media::VideoEncodingParameters params; + params.codec_name = codecSettings->plName; + params.resolution = gfx::Size(codecSettings->width, codecSettings->height); + params.runtime_params.target_bitrate = codecSettings->startBitrate; + params.runtime_params.max_bitrate = codecSettings->maxBitrate; + params.runtime_params.frames_per_second = codecSettings->maxFramerate; + encoded_video_source_client_.reset(new EncodedVideoSourceClient( + encoded_video_source_, params, rtc_codec_type_)); + return WEBRTC_VIDEO_CODEC_OK; +} + +int32_t RtcEncodingVideoCapturer::Encode( + const webrtc::I420VideoFrame& /* inputImage */, + const webrtc::CodecSpecificInfo* codecSpecificInfo, + const std::vector<webrtc::VideoFrameType>* frame_types) { + // TODO(hshi): request specific frame type. + return WEBRTC_VIDEO_CODEC_OK; +} + +int32_t RtcEncodingVideoCapturer::RegisterEncodeCompleteCallback( + webrtc::EncodedImageCallback* callback) { + DCHECK(encoded_video_source_client_); + encoded_video_source_client_->set_callback(callback); + return WEBRTC_VIDEO_CODEC_OK; +} + +int32_t RtcEncodingVideoCapturer::Release() { + DCHECK(encoded_video_source_client_); + encoded_video_source_client_.reset(NULL); + return WEBRTC_VIDEO_CODEC_OK; +} + +int32_t RtcEncodingVideoCapturer::SetChannelParameters( + uint32_t /* packetLoss */, + int rtt_in_ms) { + if (!encoded_video_source_client_) + return WEBRTC_VIDEO_CODEC_UNINITIALIZED; + encoded_video_source_client_->set_round_trip_time( + base::TimeDelta::FromMilliseconds(rtt_in_ms)); + return WEBRTC_VIDEO_CODEC_OK; +} + +int32_t RtcEncodingVideoCapturer::SetRates(uint32_t newBitRate, + uint32_t frameRate) { + if (!encoded_video_source_client_) + return WEBRTC_VIDEO_CODEC_UNINITIALIZED; + // TODO(hshi): wire up runtime rate control. + return WEBRTC_VIDEO_CODEC_OK; +} + +} // namespace content diff --git a/content/renderer/media/rtc_encoding_video_capturer.h b/content/renderer/media/rtc_encoding_video_capturer.h new file mode 100644 index 0000000..77f9626 --- /dev/null +++ b/content/renderer/media/rtc_encoding_video_capturer.h @@ -0,0 +1,56 @@ +// Copyright 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. + +#ifndef CONTENT_RENDERER_MEDIA_RTC_ENCODING_VIDEO_CAPTURER_H_ +#define CONTENT_RENDERER_MEDIA_RTC_ENCODING_VIDEO_CAPTURER_H_ + +#include "base/memory/ref_counted.h" +#include "media/video/encoded_video_source.h" +#include "media/video/video_encode_types.h" +#include "third_party/libjingle/source/talk/media/webrtc/webrtcvie.h" + +namespace content { + +// Class to represent an encoding capable video capture interface for the +// WebRTC component. This class expects to be registered as an encoder with +// an internal source to the WebRTC stack and will not be able to function as +// an encoder for uncompressed video frames. +class RtcEncodingVideoCapturer : public webrtc::VideoEncoder { + public: + RtcEncodingVideoCapturer(media::EncodedVideoSource* encoded_video_source, + webrtc::VideoCodecType codec_type); + virtual ~RtcEncodingVideoCapturer(); + + // webrtc::VideoEncoder implementation. + virtual int32_t InitEncode(const webrtc::VideoCodec* codecSettings, + int32_t numberOfCores, + uint32_t maxPayloadSize) OVERRIDE; + virtual int32_t Encode( + const webrtc::I420VideoFrame& /* inputImage */, + const webrtc::CodecSpecificInfo* codecSpecificInfo, + const std::vector<webrtc::VideoFrameType>* frame_types) OVERRIDE; + virtual int32_t RegisterEncodeCompleteCallback( + webrtc::EncodedImageCallback* callback) OVERRIDE; + virtual int32_t Release() OVERRIDE; + virtual int32_t SetChannelParameters(uint32_t /* packetLoss */, + int rtt_in_ms) OVERRIDE; + virtual int32_t SetRates(uint32_t newBitRate, + uint32_t frameRate) OVERRIDE; + private: + // Forward declaration for private implementation to represent the + // encoded video source client; + class EncodedVideoSourceClient; + scoped_ptr<EncodedVideoSourceClient> encoded_video_source_client_; + + // Pointer to the underlying EncodedVideoSource object. It is guaranteed to + // outlive the RtcEncodingVideoCapturer. + media::EncodedVideoSource* encoded_video_source_; + webrtc::VideoCodecType rtc_codec_type_; + + DISALLOW_COPY_AND_ASSIGN(RtcEncodingVideoCapturer); +}; + +} // namespace content + +#endif // CONTENT_RENDERER_MEDIA_RTC_ENCODING_VIDEO_CAPTURER_H_ diff --git a/content/renderer/media/rtc_encoding_video_capturer_factory.cc b/content/renderer/media/rtc_encoding_video_capturer_factory.cc new file mode 100644 index 0000000..a699aed --- /dev/null +++ b/content/renderer/media/rtc_encoding_video_capturer_factory.cc @@ -0,0 +1,100 @@ +// Copyright 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/rtc_encoding_video_capturer_factory.h" + +#include "base/bind.h" +#include "base/logging.h" +#include "content/renderer/media/rtc_encoding_video_capturer.h" +#include "media/base/encoded_bitstream_buffer.h" + +namespace content { + +RtcEncodingVideoCapturerFactory::RtcEncodingVideoCapturerFactory() + : encoded_video_source_(NULL) { +} + +RtcEncodingVideoCapturerFactory::~RtcEncodingVideoCapturerFactory() { + DCHECK(encoder_set_.empty()); +} + +void RtcEncodingVideoCapturerFactory::OnEncodedVideoSourceAdded( + media::EncodedVideoSource* source) { + // TODO(hshi): support multiple encoded video sources. + // For now we only support one instance of encoded video source at a time. + DCHECK(!encoded_video_source_); + encoded_video_source_ = source; + source->RequestCapabilities(base::Bind( + &RtcEncodingVideoCapturerFactory::OnCapabilitiesAvailable, + AsWeakPtr())); +} + +void RtcEncodingVideoCapturerFactory::OnEncodedVideoSourceRemoved( + media::EncodedVideoSource* source) { + encoded_video_source_ = NULL; +} + +webrtc::VideoEncoder* RtcEncodingVideoCapturerFactory::CreateVideoEncoder( + webrtc::VideoCodecType type) { + for (size_t i = 0; i < codecs_.size(); ++i) { + if (codecs_[i].type == type) { + RtcEncodingVideoCapturer* capturer = + new RtcEncodingVideoCapturer(encoded_video_source_, type); + encoder_set_.insert(capturer); + return capturer; + } + } + return NULL; +} + +void RtcEncodingVideoCapturerFactory::DestroyVideoEncoder( + webrtc::VideoEncoder* encoder) { + EncoderSet::iterator it = encoder_set_.find(encoder); + if (it != encoder_set_.end()) { + delete encoder; + encoder_set_.erase(it); + } +} + +void RtcEncodingVideoCapturerFactory::AddObserver( + WebRtcVideoEncoderFactory::Observer* observer) { + observers_.AddObserver(observer); +} + +void RtcEncodingVideoCapturerFactory::RemoveObserver( + WebRtcVideoEncoderFactory::Observer* observer) { + observers_.RemoveObserver(observer); +} + +const std::vector<cricket::WebRtcVideoEncoderFactory::VideoCodec>& +RtcEncodingVideoCapturerFactory::codecs() const { + return codecs_; +} + +void RtcEncodingVideoCapturerFactory::OnCapabilitiesAvailable( + const media::VideoEncodingCapabilities& caps) { + codecs_.clear(); + + for (size_t i = 0; i < caps.size(); ++i) { + webrtc::VideoCodecType webrtc_codec_type = webrtc::kVideoCodecGeneric; + switch (caps[i].codec_type) { + case media::kCodecVP8: + webrtc_codec_type = webrtc::kVideoCodecVP8; + break; + default: + break; + } + codecs_.push_back(cricket::WebRtcVideoEncoderFactory::VideoCodec( + webrtc_codec_type, + caps[i].codec_name, + caps[i].max_resolution.width(), + caps[i].max_resolution.height(), + caps[i].max_frames_per_second)); + } + + FOR_EACH_OBSERVER(WebRtcVideoEncoderFactory::Observer, observers_, + OnCodecsAvailable()); +} + +} // namespace content diff --git a/content/renderer/media/rtc_encoding_video_capturer_factory.h b/content/renderer/media/rtc_encoding_video_capturer_factory.h new file mode 100644 index 0000000..1fdf4f5 --- /dev/null +++ b/content/renderer/media/rtc_encoding_video_capturer_factory.h @@ -0,0 +1,61 @@ +// Copyright 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. + +#ifndef CONTENT_RENDERER_MEDIA_RTC_ENCODING_VIDEO_CAPTURER_FACTORY_H_ +#define CONTENT_RENDERER_MEDIA_RTC_ENCODING_VIDEO_CAPTURER_FACTORY_H_ + +#include "base/memory/weak_ptr.h" +#include "base/observer_list.h" +#include "media/video/encoded_video_source.h" +#include "media/video/video_encode_types.h" +#include "third_party/libjingle/source/talk/media/webrtc/webrtcvideoencoderfactory.h" + +namespace content { + +class RtcEncodingVideoCapturer; + +class RtcEncodingVideoCapturerFactory : + public cricket::WebRtcVideoEncoderFactory, + public base::SupportsWeakPtr<RtcEncodingVideoCapturerFactory> { + public: + RtcEncodingVideoCapturerFactory(); + + // WebRtcVideoEncoderFactory interface. + virtual webrtc::VideoEncoder* CreateVideoEncoder( + webrtc::VideoCodecType type) OVERRIDE; + virtual void DestroyVideoEncoder(webrtc::VideoEncoder* encoder) OVERRIDE; + + virtual const std::vector<VideoCodec>& codecs() const OVERRIDE; + + virtual void AddObserver( + WebRtcVideoEncoderFactory::Observer* observer) OVERRIDE; + virtual void RemoveObserver( + WebRtcVideoEncoderFactory::Observer* observer) OVERRIDE; + + // Callback for RequestCapabilities(). + void OnCapabilitiesAvailable(const media::VideoEncodingCapabilities& caps); + + // Invoked when an EncodedVideoSource is added/removed. + void OnEncodedVideoSourceAdded(media::EncodedVideoSource* source); + void OnEncodedVideoSourceRemoved(media::EncodedVideoSource* source); + +private: + virtual ~RtcEncodingVideoCapturerFactory(); + + // Set of registered encoding capable video capturers. + typedef std::set<webrtc::VideoEncoder*> EncoderSet; + + media::EncodedVideoSource* encoded_video_source_; + std::vector<VideoCodec> codecs_; + + EncoderSet encoder_set_; + + ObserverList<WebRtcVideoEncoderFactory::Observer, true> observers_; + + DISALLOW_COPY_AND_ASSIGN(RtcEncodingVideoCapturerFactory); +}; + +} // namespace content + +#endif // CONTENT_RENDERER_MEDIA_RTC_ENCODING_VIDEO_CAPTURER_FACTORY_H_ diff --git a/content/renderer/media/video_capture_impl.cc b/content/renderer/media/video_capture_impl.cc index c6b7bf2..0dbf696 100644 --- a/content/renderer/media/video_capture_impl.cc +++ b/content/renderer/media/video_capture_impl.cc @@ -5,8 +5,10 @@ #include "content/renderer/media/video_capture_impl.h" #include "base/bind.h" +#include "base/callback_helpers.h" #include "base/stl_util.h" #include "content/child/child_process.h" +#include "content/common/media/encoded_video_capture_messages.h" #include "content/common/media/video_capture_messages.h" #include "media/base/limits.h" @@ -58,7 +60,9 @@ VideoCaptureImpl::VideoCaptureImpl( video_type_(media::VideoCaptureCapability::kI420), device_info_available_(false), suspended_(false), - state_(VIDEO_CAPTURE_STATE_STOPPED) { + state_(VIDEO_CAPTURE_STATE_STOPPED), + encoded_video_source_client_(NULL), + bitstream_open_(false) { DCHECK(filter); memset(¤t_params_, 0, sizeof(current_params_)); memset(&device_info_, 0, sizeof(device_info_)); @@ -101,6 +105,83 @@ void VideoCaptureImpl::StopCapture(media::VideoCapture::EventHandler* handler) { base::Unretained(this), handler)); } +void VideoCaptureImpl::RequestCapabilities( + const media::EncodedVideoSource::RequestCapabilitiesCallback& callback) { + capture_message_loop_proxy_->PostTask(FROM_HERE, + base::Bind(&VideoCaptureImpl::DoRequestCapabilitiesOnCaptureThread, + base::Unretained(this), callback)); +} + +void VideoCaptureImpl::StartFetchCapabilities() { + Send(new EncodedVideoCaptureHostMsg_GetCapabilities( + device_id_, current_params_.session_id)); +} + +void VideoCaptureImpl::OpenBitstream( + media::EncodedVideoSource::Client* client, + const media::VideoEncodingParameters& params) { + capture_message_loop_proxy_->PostTask(FROM_HERE, + base::Bind(&VideoCaptureImpl::DoOpenBitstreamOnCaptureThread, + base::Unretained(this), client, params)); +} + +void VideoCaptureImpl::CloseBitstream() { + capture_message_loop_proxy_->PostTask(FROM_HERE, + base::Bind(&VideoCaptureImpl::DoCloseBitstreamOnCaptureThread, + base::Unretained(this))); +} + +void VideoCaptureImpl::ReturnBitstreamBuffer( + scoped_refptr<const media::EncodedBitstreamBuffer> buffer) { + Send(new EncodedVideoCaptureHostMsg_BitstreamBufferConsumed( + device_id_, buffer->buffer_id())); +} + +void VideoCaptureImpl::TrySetBitstreamConfig( + const media::RuntimeVideoEncodingParameters& params) { + Send(new EncodedVideoCaptureHostMsg_TryConfigureBitstream( + device_id_, params)); +} + +void VideoCaptureImpl::OnEncodingCapabilitiesAvailable( + const media::VideoEncodingCapabilities& capabilities) { + capture_message_loop_proxy_->PostTask(FROM_HERE, base::Bind( + &VideoCaptureImpl::DoNotifyCapabilitiesAvailableOnCaptureThread, + base::Unretained(this), capabilities)); +} + +void VideoCaptureImpl::OnEncodedBitstreamOpened( + const media::VideoEncodingParameters& params, + const std::vector<base::SharedMemoryHandle>& buffers, + uint32 buffer_size) { + capture_message_loop_proxy_->PostTask(FROM_HERE, + base::Bind(&VideoCaptureImpl::DoNotifyBitstreamOpenedOnCaptureThread, + base::Unretained(this), params, buffers, buffer_size)); +} + +void VideoCaptureImpl::OnEncodedBitstreamClosed() { + capture_message_loop_proxy_->PostTask(FROM_HERE, + base::Bind(&VideoCaptureImpl::DoNotifyBitstreamClosedOnCaptureThread, + base::Unretained(this))); +} + +void VideoCaptureImpl::OnEncodingConfigChanged( + const media::RuntimeVideoEncodingParameters& params) { + capture_message_loop_proxy_->PostTask(FROM_HERE, + base::Bind( + &VideoCaptureImpl::DoNotifyBitstreamConfigChangedOnCaptureThread, + base::Unretained(this), params)); +} + +void VideoCaptureImpl::OnEncodedBufferReady( + int buffer_id, + uint32 size, + const media::BufferEncodingMetadata& metadata) { + capture_message_loop_proxy_->PostTask(FROM_HERE, + base::Bind(&VideoCaptureImpl::DoNotifyBitstreamBufferReadyOnCaptureThread, + base::Unretained(this), buffer_id, size, metadata)); +} + void VideoCaptureImpl::FeedBuffer(scoped_refptr<VideoFrameBuffer> buffer) { capture_message_loop_proxy_->PostTask(FROM_HERE, base::Bind(&VideoCaptureImpl::DoFeedBufferOnCaptureThread, @@ -306,6 +387,9 @@ void VideoCaptureImpl::DoStateChangedOnCaptureThread(VideoCaptureState state) { switch (state) { case VIDEO_CAPTURE_STATE_STARTED: + if (!encoding_caps_callback_.is_null()) { + StartFetchCapabilities(); + } break; case VIDEO_CAPTURE_STATE_STOPPED: state_ = VIDEO_CAPTURE_STATE_STOPPED; @@ -380,6 +464,118 @@ void VideoCaptureImpl::DoSuspendCaptureOnCaptureThread(bool suspend) { suspended_ = suspend; } +void VideoCaptureImpl::DoRequestCapabilitiesOnCaptureThread( + const RequestCapabilitiesCallback& callback) { + DCHECK(capture_message_loop_proxy_->BelongsToCurrentThread()); + DCHECK(encoding_caps_callback_.is_null()); + encoding_caps_callback_ = callback; + + // Invoke callback immediately if capabilities are already available. + if (!encoding_caps_.empty()) + base::ResetAndReturn(&encoding_caps_callback_).Run(encoding_caps_); +} + +void VideoCaptureImpl::DoOpenBitstreamOnCaptureThread( + media::EncodedVideoSource::Client* client, + const media::VideoEncodingParameters& params) { + DCHECK(capture_message_loop_proxy_->BelongsToCurrentThread()); + DCHECK(!encoded_video_source_client_); + encoded_video_source_client_ = client; + Send(new EncodedVideoCaptureHostMsg_OpenBitstream( + device_id_, current_params_.session_id, params)); +} + +void VideoCaptureImpl::DoCloseBitstreamOnCaptureThread() { + DCHECK(capture_message_loop_proxy_->BelongsToCurrentThread()); + DCHECK(bitstream_open_); + + // Immediately clear EVS client pointer and release bitstream buffers if the + // client requests to close bitstream. Any further encoded capture messages + // from the browser process will be ignored. + bitstream_open_ = false; + for (size_t i = 0; i < bitstream_buffers_.size(); ++i) { + bitstream_buffers_[i]->Close(); + delete bitstream_buffers_[i]; + } + bitstream_buffers_.clear(); + encoded_video_source_client_ = NULL; + + Send(new EncodedVideoCaptureHostMsg_CloseBitstream(device_id_)); +} + +void VideoCaptureImpl::DoNotifyBitstreamOpenedOnCaptureThread( + const media::VideoEncodingParameters& params, + const std::vector<base::SharedMemoryHandle>& buffers, + uint32 buffer_size) { + DCHECK(capture_message_loop_proxy_->BelongsToCurrentThread()); + DCHECK(!bitstream_open_ && bitstream_buffers_.empty()); + if (!encoded_video_source_client_) + return; + bitstream_open_ = true; + for (size_t i = 0; i < buffers.size(); ++i) { + base::SharedMemory* shm = new base::SharedMemory(buffers[i], true); + CHECK(shm->Map(buffer_size)); + bitstream_buffers_.push_back(shm); + } + encoded_video_source_client_->OnOpened(params); +} + +void VideoCaptureImpl::DoNotifyBitstreamClosedOnCaptureThread() { + DCHECK(capture_message_loop_proxy_->BelongsToCurrentThread()); + + // Ignore the BitstreamClosed message if bitstream has already been closed + // by the EVS client. + if (!bitstream_open_) + return; + + // The bitstream may still be open when we receive BitstreamClosed message + // if the request to close bitstream comes from the browser process. + bitstream_open_ = false; + for (size_t i = 0; i < bitstream_buffers_.size(); ++i) { + bitstream_buffers_[i]->Close(); + delete bitstream_buffers_[i]; + } + bitstream_buffers_.clear(); + if (encoded_video_source_client_) { + encoded_video_source_client_->OnClosed(); + encoded_video_source_client_ = NULL; + } +} + +void VideoCaptureImpl::DoNotifyBitstreamConfigChangedOnCaptureThread( + const media::RuntimeVideoEncodingParameters& params) { + DCHECK(capture_message_loop_proxy_->BelongsToCurrentThread()); + if (!encoded_video_source_client_) + return; + encoded_video_source_client_->OnConfigChanged(params); +} + +void VideoCaptureImpl::DoNotifyBitstreamBufferReadyOnCaptureThread( + int buffer_id, + uint32 size, + const media::BufferEncodingMetadata& metadata) { + DCHECK(capture_message_loop_proxy_->BelongsToCurrentThread()); + if (!encoded_video_source_client_) + return; + if (buffer_id >= 0 && + static_cast<size_t>(buffer_id) < bitstream_buffers_.size()) { + base::SharedMemory* shm = bitstream_buffers_.at(buffer_id); + scoped_refptr<media::EncodedBitstreamBuffer> buffer = + new media::EncodedBitstreamBuffer( + buffer_id, (uint8*)shm->memory(), size, shm->handle(), + metadata, base::Bind(&base::DoNothing)); + encoded_video_source_client_->OnBufferReady(buffer); + } +} + +void VideoCaptureImpl::DoNotifyCapabilitiesAvailableOnCaptureThread( + const media::VideoEncodingCapabilities& capabilities) { + DCHECK(capture_message_loop_proxy_->BelongsToCurrentThread()); + encoding_caps_ = capabilities; + if (!encoding_caps_callback_.is_null()) + base::ResetAndReturn(&encoding_caps_callback_).Run(encoding_caps_); +} + void VideoCaptureImpl::StopDevice() { DCHECK(capture_message_loop_proxy_->BelongsToCurrentThread()); diff --git a/content/renderer/media/video_capture_impl.h b/content/renderer/media/video_capture_impl.h index a7af55b..779aece 100644 --- a/content/renderer/media/video_capture_impl.h +++ b/content/renderer/media/video_capture_impl.h @@ -38,6 +38,7 @@ #include "content/renderer/media/video_capture_message_filter.h" #include "media/video/capture/video_capture.h" #include "media/video/capture/video_capture_types.h" +#include "media/video/encoded_video_source.h" namespace base { class MessageLoopProxy; @@ -46,7 +47,9 @@ class MessageLoopProxy; namespace content { class CONTENT_EXPORT VideoCaptureImpl - : public media::VideoCapture, public VideoCaptureMessageFilter::Delegate { + : public media::VideoCapture, + public VideoCaptureMessageFilter::Delegate, + public media::EncodedVideoSource { public: // media::VideoCapture interface. virtual void StartCapture( @@ -67,6 +70,31 @@ class CONTENT_EXPORT VideoCaptureImpl virtual void OnDeviceInfoReceived( const media::VideoCaptureParams& device_info) OVERRIDE; virtual void OnDelegateAdded(int32 device_id) OVERRIDE; + virtual void OnEncodingCapabilitiesAvailable( + const media::VideoEncodingCapabilities& capabilities) OVERRIDE; + virtual void OnEncodedBitstreamOpened( + const media::VideoEncodingParameters& params, + const std::vector<base::SharedMemoryHandle>& buffers, + uint32 buffer_size) OVERRIDE; + virtual void OnEncodedBitstreamClosed() OVERRIDE; + virtual void OnEncodingConfigChanged( + const media::RuntimeVideoEncodingParameters& params) OVERRIDE; + virtual void OnEncodedBufferReady( + int buffer_id, + uint32 size, + const media::BufferEncodingMetadata& metadata) OVERRIDE; + + // media::EncodedVideoSource interface. + virtual void RequestCapabilities( + const RequestCapabilitiesCallback& callback) OVERRIDE; + virtual void OpenBitstream( + media::EncodedVideoSource::Client* client, + const media::VideoEncodingParameters& params) OVERRIDE; + virtual void CloseBitstream() OVERRIDE; + virtual void ReturnBitstreamBuffer( + scoped_refptr<const media::EncodedBitstreamBuffer> buffer) OVERRIDE; + virtual void TrySetBitstreamConfig( + const media::RuntimeVideoEncodingParameters& params) OVERRIDE; // Stop/resume delivering video frames to clients, based on flag |suspend|. virtual void SuspendCapture(bool suspend); @@ -101,6 +129,26 @@ class CONTENT_EXPORT VideoCaptureImpl void DoSuspendCaptureOnCaptureThread(bool suspend); + void StartFetchCapabilities(); + void DoRequestCapabilitiesOnCaptureThread( + const RequestCapabilitiesCallback& callback); + void DoOpenBitstreamOnCaptureThread( + media::EncodedVideoSource::Client* client, + const media::VideoEncodingParameters& params); + void DoCloseBitstreamOnCaptureThread(); + void DoNotifyBitstreamOpenedOnCaptureThread( + const media::VideoEncodingParameters& params, + const std::vector<base::SharedMemoryHandle>& buffers, + uint32 buffer_size); + void DoNotifyBitstreamClosedOnCaptureThread(); + void DoNotifyBitstreamConfigChangedOnCaptureThread( + const media::RuntimeVideoEncodingParameters& params); + void DoNotifyBitstreamBufferReadyOnCaptureThread( + int buffer_id, uint32 size, + const media::BufferEncodingMetadata& metadata); + void DoNotifyCapabilitiesAvailableOnCaptureThread( + const media::VideoEncodingCapabilities& capabilities); + void Init(); void DeInit(base::Closure task); void DoDeInitOnCaptureThread(base::Closure task); @@ -143,6 +191,20 @@ class CONTENT_EXPORT VideoCaptureImpl bool suspended_; VideoCaptureState state_; + // Video encoding capabilities as reported by the device. + media::VideoEncodingCapabilities encoding_caps_; + // Callback for RequestCapabilities(). + RequestCapabilitiesCallback encoding_caps_callback_; + // Pointer to the EVS client. + media::EncodedVideoSource::Client* encoded_video_source_client_; + // Bitstream buffers returned by the video capture device. Unowned. + std::vector<base::SharedMemory*> bitstream_buffers_; + // |bitstream_open_| is set to true when renderer receives BitstreamOpened + // message acknowledging an OpenBitstream request, and is set to false when + // the EVS client requests to close bitstream, or when renderer receives + // BitstreamClosed message from the browser procses. + bool bitstream_open_; + DISALLOW_COPY_AND_ASSIGN(VideoCaptureImpl); }; diff --git a/content/renderer/media/video_capture_impl_manager.cc b/content/renderer/media/video_capture_impl_manager.cc index 672fbd4..cd49543 100644 --- a/content/renderer/media/video_capture_impl_manager.cc +++ b/content/renderer/media/video_capture_impl_manager.cc @@ -6,6 +6,7 @@ #include "base/bind.h" #include "base/stl_util.h" +#include "content/renderer/media/rtc_encoding_video_capturer_factory.h" #include "content/renderer/media/video_capture_impl.h" #include "content/renderer/media/video_capture_message_filter.h" @@ -30,6 +31,8 @@ media::VideoCapture* VideoCaptureImplManager::AddDevice( new VideoCaptureImpl(id, message_loop_proxy_.get(), filter_.get()); devices_[id] = new Device(vc, handler); vc->Init(); + if (encoding_capturer_factory_) + encoding_capturer_factory_->OnEncodedVideoSourceAdded(vc); return vc; } @@ -59,6 +62,9 @@ void VideoCaptureImplManager::RemoveDevice( if (size == it->second->clients.size() || size > 1) return; + if (encoding_capturer_factory_) + encoding_capturer_factory_->OnEncodedVideoSourceRemoved(devices_[id]->vc); + devices_[id]->vc->DeInit(base::Bind(&VideoCaptureImplManager::FreeDevice, this, devices_[id]->vc)); delete devices_[id]; diff --git a/content/renderer/media/video_capture_impl_manager.h b/content/renderer/media/video_capture_impl_manager.h index e942201..9b26b20 100644 --- a/content/renderer/media/video_capture_impl_manager.h +++ b/content/renderer/media/video_capture_impl_manager.h @@ -13,14 +13,17 @@ #include <list> #include <map> +#include "base/memory/weak_ptr.h" #include "base/message_loop/message_loop_proxy.h" #include "base/threading/thread.h" #include "base/synchronization/lock.h" #include "content/common/content_export.h" #include "media/video/capture/video_capture.h" +#include "media/video/encoded_video_source.h" namespace content { +class RtcEncodingVideoCapturerFactory; class VideoCaptureImpl; class VideoCaptureMessageFilter; @@ -50,6 +53,11 @@ class CONTENT_EXPORT VideoCaptureImplManager return filter_.get(); } + void set_encoding_capturer_factory(base::WeakPtr< + RtcEncodingVideoCapturerFactory> encoding_capturer_factory) { + encoding_capturer_factory_ = encoding_capturer_factory; + } + protected: virtual ~VideoCaptureImplManager(); @@ -74,6 +82,12 @@ class CONTENT_EXPORT VideoCaptureImplManager base::Thread thread_; scoped_refptr<base::MessageLoopProxy> message_loop_proxy_; + // The encoding capturer factory is created by MediaStreamDependencyFactory + // and owned by its PeerConnectionFactory. It is passed to the manager + // as a weak pointer at CreatePeerConnectionFactory time because the + // PeerConnectionFactory may be released earlier than the manager. + base::WeakPtr<RtcEncodingVideoCapturerFactory> encoding_capturer_factory_; + DISALLOW_COPY_AND_ASSIGN(VideoCaptureImplManager); }; diff --git a/content/renderer/media/video_capture_impl_unittest.cc b/content/renderer/media/video_capture_impl_unittest.cc index 8befed0..0c64190 100644 --- a/content/renderer/media/video_capture_impl_unittest.cc +++ b/content/renderer/media/video_capture_impl_unittest.cc @@ -4,6 +4,7 @@ #include "base/message_loop.h" #include "content/child/child_process.h" +#include "content/common/media/encoded_video_capture_messages.h" #include "content/common/media/video_capture_messages.h" #include "content/renderer/media/video_capture_impl.h" #include "testing/gmock/include/gmock/gmock.h" @@ -79,6 +80,16 @@ class VideoCaptureImplTest : public ::testing::Test { IPC_MESSAGE_HANDLER(VideoCaptureHostMsg_Stop, DeviceStopCapture) IPC_MESSAGE_HANDLER(VideoCaptureHostMsg_BufferReady, DeviceReceiveEmptyBuffer) + IPC_MESSAGE_HANDLER(EncodedVideoCaptureHostMsg_GetCapabilities, + DeviceGetEncodingCapabilities) + IPC_MESSAGE_HANDLER(EncodedVideoCaptureHostMsg_OpenBitstream, + DeviceOpenEncodedBitstream) + IPC_MESSAGE_HANDLER(EncodedVideoCaptureHostMsg_CloseBitstream, + DeviceCloseEncodedBitstream) + IPC_MESSAGE_HANDLER(EncodedVideoCaptureHostMsg_TryConfigureBitstream, + DeviceSetEncodingConfig) + IPC_MESSAGE_HANDLER(EncodedVideoCaptureHostMsg_BitstreamBufferConsumed, + DeviceReturnEncodedBuffer) IPC_MESSAGE_UNHANDLED(handled = false) IPC_END_MESSAGE_MAP() EXPECT_TRUE(handled); @@ -99,6 +110,20 @@ class VideoCaptureImplTest : public ::testing::Test { } void DeviceReceiveEmptyBuffer(int device_id, int buffer_id) {} + + void DeviceGetEncodingCapabilities( + int device_id, media::VideoCaptureSessionId session_id) {} + + void DeviceOpenEncodedBitstream(int device_id, + media::VideoCaptureSessionId session_id, + media::VideoEncodingParameters params) {} + + void DeviceCloseEncodedBitstream(int device_id) {} + + void DeviceSetEncodingConfig( + int device_id, media::RuntimeVideoEncodingParameters params) {} + + void DeviceReturnEncodedBuffer(int device_id, int buffer_id) {} }; VideoCaptureImplTest() { diff --git a/content/renderer/media/video_capture_message_filter.cc b/content/renderer/media/video_capture_message_filter.cc index 4d59729..0a4bb61 100644 --- a/content/renderer/media/video_capture_message_filter.cc +++ b/content/renderer/media/video_capture_message_filter.cc @@ -4,6 +4,7 @@ #include "content/renderer/media/video_capture_message_filter.h" +#include "content/common/media/encoded_video_capture_messages.h" #include "content/common/media/video_capture_messages.h" #include "content/common/view_messages.h" @@ -61,7 +62,17 @@ bool VideoCaptureMessageFilter::OnMessageReceived(const IPC::Message& message) { IPC_MESSAGE_HANDLER(VideoCaptureMsg_StateChanged, OnDeviceStateChanged) IPC_MESSAGE_HANDLER(VideoCaptureMsg_NewBuffer, OnBufferCreated) IPC_MESSAGE_HANDLER(VideoCaptureMsg_DeviceInfo, OnDeviceInfoReceived) - IPC_MESSAGE_UNHANDLED(handled = false) + IPC_MESSAGE_HANDLER(EncodedVideoCaptureMsg_CapabilitiesAvailable, + OnCapabilitiesAvailable) + IPC_MESSAGE_HANDLER(EncodedVideoCaptureMsg_BitstreamOpened, + OnBitstreamOpened) + IPC_MESSAGE_HANDLER(EncodedVideoCaptureMsg_BitstreamClosed, + OnBitstreamClosed) + IPC_MESSAGE_HANDLER(EncodedVideoCaptureMsg_BitstreamConfigChanged, + OnBitstreamConfigChanged) + IPC_MESSAGE_HANDLER(EncodedVideoCaptureMsg_BitstreamReady, + OnBitstreamReady); + IPC_MESSAGE_UNHANDLED(handled = false) IPC_END_MESSAGE_MAP() return handled; } @@ -90,15 +101,18 @@ void VideoCaptureMessageFilter::OnChannelClosing() { VideoCaptureMessageFilter::~VideoCaptureMessageFilter() {} +VideoCaptureMessageFilter::Delegate* VideoCaptureMessageFilter::find_delegate( + int device_id) const { + Delegates::const_iterator i = delegates_.find(device_id); + return i != delegates_.end() ? i->second : NULL; +} + void VideoCaptureMessageFilter::OnBufferCreated( int device_id, base::SharedMemoryHandle handle, int length, int buffer_id) { - Delegate* delegate = NULL; - if (delegates_.find(device_id) != delegates_.end()) - delegate = delegates_.find(device_id)->second; - + Delegate* delegate = find_delegate(device_id); if (!delegate) { DLOG(WARNING) << "OnBufferCreated: Got video frame buffer for a " "non-existent or removed video capture."; @@ -117,10 +131,7 @@ void VideoCaptureMessageFilter::OnBufferReceived( int device_id, int buffer_id, base::Time timestamp) { - Delegate* delegate = NULL; - if (delegates_.find(device_id) != delegates_.end()) - delegate = delegates_.find(device_id)->second; - + Delegate* delegate = find_delegate(device_id); if (!delegate) { DLOG(WARNING) << "OnBufferReceived: Got video frame buffer for a " "non-existent or removed video capture."; @@ -137,9 +148,7 @@ void VideoCaptureMessageFilter::OnBufferReceived( void VideoCaptureMessageFilter::OnDeviceStateChanged( int device_id, VideoCaptureState state) { - Delegate* delegate = NULL; - if (delegates_.find(device_id) != delegates_.end()) - delegate = delegates_.find(device_id)->second; + Delegate* delegate = find_delegate(device_id); if (!delegate) { DLOG(WARNING) << "OnDeviceStateChanged: Got video capture event for a " "non-existent or removed video capture."; @@ -151,9 +160,7 @@ void VideoCaptureMessageFilter::OnDeviceStateChanged( void VideoCaptureMessageFilter::OnDeviceInfoReceived( int device_id, const media::VideoCaptureParams& params) { - Delegate* delegate = NULL; - if (delegates_.find(device_id) != delegates_.end()) - delegate = delegates_.find(device_id)->second; + Delegate* delegate = find_delegate(device_id); if (!delegate) { DLOG(WARNING) << "OnDeviceInfoReceived: Got video capture event for a " "non-existent or removed video capture."; @@ -162,4 +169,64 @@ void VideoCaptureMessageFilter::OnDeviceInfoReceived( delegate->OnDeviceInfoReceived(params); } +void VideoCaptureMessageFilter::OnCapabilitiesAvailable( + int device_id, + media::VideoEncodingCapabilities capabilities) { + Delegate* delegate = find_delegate(device_id); + if (!delegate) { + DLOG(WARNING) << "OnCapabilitiesAvailable: Got video capture event for a " + "non-existent or removed video capture."; + return; + } + delegate->OnEncodingCapabilitiesAvailable(capabilities); +} + +void VideoCaptureMessageFilter::OnBitstreamOpened( + int device_id, + media::VideoEncodingParameters params, + std::vector<base::SharedMemoryHandle> buffers, + uint32 buffer_size) { + Delegate* delegate = find_delegate(device_id); + if (!delegate) { + DLOG(WARNING) << "OnBitstreamOpened: Got video capture event for a " + "non-existent or removed video capture."; + return; + } + delegate->OnEncodedBitstreamOpened(params, buffers, buffer_size); +} + +void VideoCaptureMessageFilter::OnBitstreamClosed(int device_id) { + Delegate* delegate = find_delegate(device_id); + if (!delegate) { + DLOG(WARNING) << "OnBitstreamClosed: Got video capture event for a " + "non-existent or removed video capture."; + return; + } + delegate->OnEncodedBitstreamClosed(); +} + +void VideoCaptureMessageFilter::OnBitstreamConfigChanged( + int device_id, + media::RuntimeVideoEncodingParameters params) { + Delegate* delegate = find_delegate(device_id); + if (!delegate) { + DLOG(WARNING) << "OnBitstreamConfigChanged: Got video capture event for a " + "non-existent or removed video capture."; + return; + } + delegate->OnEncodingConfigChanged(params); +} + +void VideoCaptureMessageFilter::OnBitstreamReady( + int device_id, int buffer_id, uint32 size, + media::BufferEncodingMetadata metadata) { + Delegate* delegate = find_delegate(device_id); + if (!delegate) { + DLOG(WARNING) << "OnBitstreamReady: Got video capture event for a " + "non-existent or removed video capture."; + return; + } + delegate->OnEncodedBufferReady(buffer_id, size, metadata); +} + } // namespace content diff --git a/content/renderer/media/video_capture_message_filter.h b/content/renderer/media/video_capture_message_filter.h index 3499540..e4ee732 100644 --- a/content/renderer/media/video_capture_message_filter.h +++ b/content/renderer/media/video_capture_message_filter.h @@ -18,6 +18,7 @@ #include "content/common/media/video_capture.h" #include "ipc/ipc_channel_proxy.h" #include "media/video/capture/video_capture.h" +#include "media/video/encoded_video_source.h" namespace content { @@ -46,6 +47,31 @@ class CONTENT_EXPORT VideoCaptureMessageFilter // |device_id| is the device id for the delegate. virtual void OnDelegateAdded(int32 device_id) = 0; + // Called when the encoding capabilities is received from video capture + // device in the browser process. + virtual void OnEncodingCapabilitiesAvailable( + const media::VideoEncodingCapabilities& capabilities) = 0; + + // Called when a bitstream is opened on a video capture device. + virtual void OnEncodedBitstreamOpened( + const media::VideoEncodingParameters& params, + const std::vector<base::SharedMemoryHandle>& buffers, + uint32 buffer_size) = 0; + + // Called when a bitstream is closed on a video capture device. + virtual void OnEncodedBitstreamClosed() = 0; + + // Called when encoding parameters has changed. + virtual void OnEncodingConfigChanged( + const media::RuntimeVideoEncodingParameters& params) = 0; + + // Called when an encoded bitstream buffer is received from video capture + // device in the browser process. + virtual void OnEncodedBufferReady( + int buffer_id, + uint32 size, + const media::BufferEncodingMetadata& metadata) = 0; + protected: virtual ~Delegate() {} }; @@ -92,6 +118,30 @@ class CONTENT_EXPORT VideoCaptureMessageFilter void OnDeviceInfoReceived(int device_id, const media::VideoCaptureParams& params); + // Receive encoding capabilities from browser process. + void OnCapabilitiesAvailable(int device_id, + media::VideoEncodingCapabilities capabilities); + + // Bitstream is opened on video capture device. + void OnBitstreamOpened(int device_id, + media::VideoEncodingParameters params, + std::vector<base::SharedMemoryHandle> buffers, + uint32 buffer_size); + + // Bitstream is closed on video capture device. + void OnBitstreamClosed(int device_id); + + // Receive current encoding parameters from browser process. + void OnBitstreamConfigChanged(int device_id, + media::RuntimeVideoEncodingParameters params); + + // Receive an encoded bitstream buffer from browser process. + void OnBitstreamReady(int device_id, int buffer_id, uint32 size, + media::BufferEncodingMetadata metadata); + + // Finds the delegate associated with |device_id|, NULL if not found. + Delegate* find_delegate(int device_id) const; + // A map of device ids to delegates. Delegates delegates_; Delegates pending_delegates_; diff --git a/content/renderer/media/video_capture_message_filter_unittest.cc b/content/renderer/media/video_capture_message_filter_unittest.cc index b0ffbc7..99178ce 100644 --- a/content/renderer/media/video_capture_message_filter_unittest.cc +++ b/content/renderer/media/video_capture_message_filter_unittest.cc @@ -50,6 +50,21 @@ class MockVideoCaptureDelegate : public VideoCaptureMessageFilter::Delegate { device_id_ = device_id; } + // TODO(hshi): implement the following methods for encoded video capture. + virtual void OnEncodingCapabilitiesAvailable( + const media::VideoEncodingCapabilities& capabilities) OVERRIDE {} + virtual void OnEncodedBitstreamOpened( + const media::VideoEncodingParameters& params, + const std::vector<base::SharedMemoryHandle>& buffers, + uint32 buffer_size) OVERRIDE {} + virtual void OnEncodedBitstreamClosed() OVERRIDE {} + virtual void OnEncodingConfigChanged( + const media::RuntimeVideoEncodingParameters& params) OVERRIDE {} + virtual void OnEncodedBufferReady( + int buffer_id, + uint32 size, + const media::BufferEncodingMetadata& metadata) OVERRIDE {} + void Reset() { buffer_created_ = false; handle_ = base::SharedMemory::NULLHandle(); |