diff options
27 files changed, 1295 insertions, 19 deletions
diff --git a/chrome/browser/chromeos/login/chrome_restart_request.cc b/chrome/browser/chromeos/login/chrome_restart_request.cc index 8809966..5096919 100644 --- a/chrome/browser/chromeos/login/chrome_restart_request.cc +++ b/chrome/browser/chromeos/login/chrome_restart_request.cc @@ -90,6 +90,7 @@ std::string DeriveCommandLine(const GURL& start_url, ::switches::kEnableBeginFrameScheduling, ::switches::kEnableBrowserInputController, ::switches::kEnableCompositingForFixedPosition, + ::switches::kEnableEncodedScreenCapture, ::switches::kEnableEncryptedMedia, ::switches::kEnableGestureTapHighlight, ::switches::kDisableGestureTapHighlight, 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(); diff --git a/ipc/ipc_message_start.h b/ipc/ipc_message_start.h index bf80df0..2ebb832 100644 --- a/ipc/ipc_message_start.h +++ b/ipc/ipc_message_start.h @@ -86,7 +86,8 @@ enum IPCMessageStart { WebSocketMsgStart, NaClHostMsgStart, WebRTCIdentityMsgStart, - LastIPCMsgStart // Must come last. + EncodedVideoCaptureMsgStart, + LastIPCMsgStart // Must come last. }; #endif // IPC_IPC_MESSAGE_START_H_ diff --git a/media/base/encoded_bitstream_buffer.cc b/media/base/encoded_bitstream_buffer.cc new file mode 100644 index 0000000..3689015 --- /dev/null +++ b/media/base/encoded_bitstream_buffer.cc @@ -0,0 +1,50 @@ +// 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 "media/base/encoded_bitstream_buffer.h" + +#include "base/logging.h" + +namespace media { + +EncodedBitstreamBuffer::EncodedBitstreamBuffer( + int buffer_id, + uint8* buffer, + uint32 size, + base::SharedMemoryHandle handle, + const media::BufferEncodingMetadata& metadata, + const base::Closure& destroy_cb) + : buffer_id_(buffer_id), + buffer_(buffer), + size_(size), + shared_memory_handle_(handle), + metadata_(metadata), + destroy_cb_(destroy_cb) { +} + +EncodedBitstreamBuffer::~EncodedBitstreamBuffer() { + destroy_cb_.Run(); +} + +int EncodedBitstreamBuffer::buffer_id() const { + return buffer_id_; +} + +const uint8* EncodedBitstreamBuffer::buffer() const { + return buffer_; +} + +uint32 EncodedBitstreamBuffer::size() const { + return size_; +} + +base::SharedMemoryHandle EncodedBitstreamBuffer::shared_memory_handle() const { + return shared_memory_handle_; +} + +const media::BufferEncodingMetadata& EncodedBitstreamBuffer::metadata() const { + return metadata_; +} + +} // namespace media diff --git a/media/base/encoded_bitstream_buffer.h b/media/base/encoded_bitstream_buffer.h new file mode 100644 index 0000000..6fe24c8 --- /dev/null +++ b/media/base/encoded_bitstream_buffer.h @@ -0,0 +1,52 @@ +// 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 MEDIA_BASE_ENCODED_BITSTREAM_BUFFER_H_ +#define MEDIA_BASE_ENCODED_BITSTREAM_BUFFER_H_ + +#include "base/callback_forward.h" +#include "base/memory/ref_counted.h" +#include "base/shared_memory.h" +#include "base/time/time.h" +#include "media/base/media_export.h" +#include "media/video/video_encode_types.h" + +namespace media { + +// General encoded video bitstream buffer. +class MEDIA_EXPORT EncodedBitstreamBuffer : + public base::RefCountedThreadSafe<EncodedBitstreamBuffer> { + public: + EncodedBitstreamBuffer(int buffer_id, + uint8* buffer, + uint32 size, + base::SharedMemoryHandle handle, + const media::BufferEncodingMetadata& metadata, + const base::Closure& destroy_cb); + // Accessors for properties. + int buffer_id() const; + const uint8* buffer() const; + uint32 size() const; + base::SharedMemoryHandle shared_memory_handle() const; + const media::BufferEncodingMetadata& metadata() const; + + protected: + // Destructor that deallocates the buffers. + virtual ~EncodedBitstreamBuffer(); + friend class base::RefCountedThreadSafe<EncodedBitstreamBuffer>; + + private: + int buffer_id_; + uint8* buffer_; + uint32 size_; + const base::SharedMemoryHandle shared_memory_handle_; + media::BufferEncodingMetadata metadata_; + const base::Closure destroy_cb_; + + DISALLOW_COPY_AND_ASSIGN(EncodedBitstreamBuffer); +}; + +} // namespace media + +#endif // MEDIA_BASE_ENCODED_BITSTREAM_BUFFER_H_ diff --git a/media/media.gyp b/media/media.gyp index 10ee0f8..88b28dc 100644 --- a/media/media.gyp +++ b/media/media.gyp @@ -258,6 +258,8 @@ 'base/demuxer_stream.h', 'base/djb2.cc', 'base/djb2.h', + 'base/encoded_bitstream_buffer.cc', + 'base/encoded_bitstream_buffer.h', 'base/filter_collection.cc', 'base/filter_collection.h', 'base/media.cc', @@ -413,10 +415,12 @@ 'video/capture/win/video_capture_device_mf_win.h', 'video/capture/win/video_capture_device_win.cc', 'video/capture/win/video_capture_device_win.h', + 'video/encoded_video_source.h', 'video/picture.cc', 'video/picture.h', 'video/video_decode_accelerator.cc', 'video/video_decode_accelerator.h', + 'video/video_encode_types.h', 'webm/webm_audio_client.cc', 'webm/webm_audio_client.h', 'webm/webm_cluster_parser.cc', diff --git a/media/video/encoded_video_source.h b/media/video/encoded_video_source.h new file mode 100644 index 0000000..e2ce201 --- /dev/null +++ b/media/video/encoded_video_source.h @@ -0,0 +1,76 @@ +// 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 MEDIA_VIDEO_ENCODED_VIDEO_SOURCE_H_ +#define MEDIA_VIDEO_ENCODED_VIDEO_SOURCE_H_ + +#include "base/memory/ref_counted.h" +#include "media/base/encoded_bitstream_buffer.h" +#include "media/video/video_encode_types.h" + +namespace media { + +// Class to represent any encoded video source. Anything that provides encoded +// video can be an EncodedVideoSource. Notable examples of this can be video +// encoder and webcam that has encoding capabilities. +// TODO(hshi): merge this with VEA interface. http://crbug.com/248334. +class EncodedVideoSource { + public: + class Client { + public: + // Notifies client that bitstream is opened successfully. The |params| + // contains the actual encoding parameters chosen by the browser process. + // It may be different from the params requested in OpenBitstream(). + virtual void OnOpened(const VideoEncodingParameters& params) = 0; + + // Notifies client that bitstream is closed. After this call it is + // guaranteed that client will not receive further calls. + virtual void OnClosed() = 0; + + // Delivers an encoded bitstream buffer to the client. + virtual void OnBufferReady( + scoped_refptr<const EncodedBitstreamBuffer> buffer) = 0; + + // Notifies client that encoding parameters has changed. The |params| + // contains the current encoding parameters chosen by the browser process. + // It may be different from the params requested in TrySetBitstreamConfig(). + virtual void OnConfigChanged( + const RuntimeVideoEncodingParameters& params) = 0; + }; + + // Callback is invoked once RequestCapabilities() is complete. + typedef base::Callback<void(const VideoEncodingCapabilities& capabilities)> + RequestCapabilitiesCallback; + + // RequestCapabilities initiates an asynchronous query for the types of + // encoded bitstream supported by the encoder. This call should be invoked + // only once. EncodedVideoSource will invoke |callback| when capabilities + // become available. + virtual void RequestCapabilities( + const RequestCapabilitiesCallback& callback) = 0; + + // OpenBitstream opens the bitstream on the encoded video source. Only one + // bitstream can be opened for an encoded video source. + virtual void OpenBitstream(Client* client, + const VideoEncodingParameters& params) = 0; + + // CloseBitstream closes the bitstream. + virtual void CloseBitstream() = 0; + + // ReturnBitstreamBuffer notifies that the data within the buffer has been + // processed and it can be reused to encode upcoming bitstream. + virtual void ReturnBitstreamBuffer( + scoped_refptr<const media::EncodedBitstreamBuffer> buffer) = 0; + + // TrySetBitstreamConfig requests to change encoding parameters. Old config + // must be considered valid until OnConfigChanged is invoked on the client + // signaling successful change. + virtual void TrySetBitstreamConfig( + const RuntimeVideoEncodingParameters& params) = 0; +}; + +} // namespace media + +#endif // MEDIA_VIDEO_ENCODED_VIDEO_SOURCE_H_ + diff --git a/media/video/video_encode_types.h b/media/video/video_encode_types.h new file mode 100644 index 0000000..0372019 --- /dev/null +++ b/media/video/video_encode_types.h @@ -0,0 +1,51 @@ +// 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 MEDIA_VIDEO_VIDEO_ENCODE_TYPES_H_ +#define MEDIA_VIDEO_VIDEO_ENCODE_TYPES_H_ + +#include <map> +#include <ostream> +#include <vector> + +#include "base/time/time.h" +#include "media/base/video_decoder_config.h" +#include "ui/gfx/size.h" + +namespace media { + +// Data to represent limitations for a particular encoder config. +struct VideoEncodingConfig { + VideoCodec codec_type; + std::string codec_name; + gfx::Size max_resolution; + int max_frames_per_second; + int max_bitrate; +}; + +typedef std::vector<VideoEncodingConfig> VideoEncodingCapabilities; + +// Encoding parameters that can be configured during streaming without removing +// the bitstream first. +struct RuntimeVideoEncodingParameters { + int target_bitrate; + int max_bitrate; + int frames_per_second; +}; + +// Generic video encoding parameters to be configured during initialization +// time. +struct VideoEncodingParameters { + std::string codec_name; + gfx::Size resolution; + RuntimeVideoEncodingParameters runtime_params; +}; + +struct BufferEncodingMetadata { + base::Time timestamp; + bool key_frame; +}; + +} // namespace media + +#endif // MEDIA_VIDEO_VIDEO_ENCODE_TYPES_H_ |