summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--chrome/chrome_tests.gypi1
-rw-r--r--content/content_renderer.gypi10
-rw-r--r--content/renderer/media/capture_video_decoder.cc271
-rw-r--r--content/renderer/media/capture_video_decoder.h103
-rw-r--r--content/renderer/media/capture_video_decoder_unittest.cc172
-rw-r--r--content/renderer/media/media_stream_impl.cc49
-rw-r--r--content/renderer/media/media_stream_impl.h33
-rw-r--r--content/renderer/media/video_capture_impl.cc150
-rw-r--r--content/renderer/media/video_capture_impl.h29
-rw-r--r--content/renderer/media/video_capture_impl_manager.h6
-rw-r--r--content/renderer/media/video_capture_module_impl.cc217
-rw-r--r--content/renderer/media/video_capture_module_impl.h85
-rw-r--r--content/renderer/media/video_capture_module_impl_device_info.cc85
-rw-r--r--content/renderer/media/video_capture_module_impl_device_info.h54
-rw-r--r--content/renderer/render_view.cc9
-rw-r--r--content/renderer/render_view.h4
-rw-r--r--media/video/capture/video_capture.h8
-rw-r--r--webkit/glue/media/media_stream_client.h33
-rw-r--r--webkit/glue/webmediaplayer_impl.cc18
-rw-r--r--webkit/glue/webmediaplayer_impl.h6
-rw-r--r--webkit/support/webkit_support.cc3
-rw-r--r--webkit/tools/test_shell/test_webview_delegate.cc3
22 files changed, 1259 insertions, 90 deletions
diff --git a/chrome/chrome_tests.gypi b/chrome/chrome_tests.gypi
index fcc312c..e75d5de 100644
--- a/chrome/chrome_tests.gypi
+++ b/chrome/chrome_tests.gypi
@@ -2037,6 +2037,7 @@
'../content/renderer/active_notification_tracker_unittest.cc',
'../content/renderer/media/audio_message_filter_unittest.cc',
'../content/renderer/media/audio_renderer_impl_unittest.cc',
+ '../content/renderer/media/capture_video_decoder_unittest.cc',
'../content/renderer/media/media_stream_dispatcher_unittest.cc',
'../content/renderer/media/rtc_video_decoder_unittest.cc',
'../content/renderer/media/video_capture_impl_unittest.cc',
diff --git a/content/content_renderer.gypi b/content/content_renderer.gypi
index 33a13a1..6c3c2bf 100644
--- a/content/content_renderer.gypi
+++ b/content/content_renderer.gypi
@@ -68,9 +68,13 @@
'renderer/media/audio_message_filter.h',
'renderer/media/audio_renderer_impl.cc',
'renderer/media/audio_renderer_impl.h',
+ 'renderer/media/capture_video_decoder.cc',
+ 'renderer/media/capture_video_decoder.h',
'renderer/media/media_stream_dispatcher.cc',
'renderer/media/media_stream_dispatcher.h',
'renderer/media/media_stream_dispatcher_eventhandler.h',
+ 'renderer/media/media_stream_impl.cc',
+ 'renderer/media/media_stream_impl.h',
'renderer/media/rtc_video_decoder.cc',
'renderer/media/rtc_video_decoder.h',
'renderer/media/video_capture_impl.cc',
@@ -212,6 +216,12 @@
'../third_party/webrtc/video_engine/main/source/video_engine_core.gyp:video_engine_core',
'../third_party/webrtc/voice_engine/main/source/voice_engine_core.gyp:voice_engine_core',
],
+ 'sources': [
+ 'renderer/media/video_capture_module_impl.cc',
+ 'renderer/media/video_capture_module_impl.h',
+ 'renderer/media/video_capture_module_impl_device_info.cc',
+ 'renderer/media/video_capture_module_impl_device_info.h',
+ ],
}],
],
},
diff --git a/content/renderer/media/capture_video_decoder.cc b/content/renderer/media/capture_video_decoder.cc
new file mode 100644
index 0000000..359b8c7
--- /dev/null
+++ b/content/renderer/media/capture_video_decoder.cc
@@ -0,0 +1,271 @@
+// Copyright (c) 2011 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/capture_video_decoder.h"
+
+#include "content/renderer/media/video_capture_impl_manager.h"
+#include "media/base/filter_host.h"
+#include "media/base/limits.h"
+#include "media/base/media_format.h"
+
+CaptureVideoDecoder::CaptureVideoDecoder(
+ base::MessageLoopProxy* message_loop_proxy,
+ media::VideoCaptureSessionId video_stream_id,
+ VideoCaptureImplManager* vc_manager,
+ const media::VideoCapture::VideoCaptureCapability& capability)
+ : message_loop_proxy_(message_loop_proxy),
+ vc_manager_(vc_manager),
+ capability_(capability),
+ state_(kUnInitialized),
+ pending_stop_cb_(NULL),
+ video_stream_id_(video_stream_id),
+ capture_engine_(NULL) {
+ DCHECK(vc_manager);
+}
+
+CaptureVideoDecoder::~CaptureVideoDecoder() {}
+
+void CaptureVideoDecoder::Initialize(media::DemuxerStream* demuxer_stream,
+ media::FilterCallback* filter_callback,
+ media::StatisticsCallback* stat_callback) {
+ message_loop_proxy_->PostTask(
+ FROM_HERE,
+ NewRunnableMethod(this,
+ &CaptureVideoDecoder::InitializeOnDecoderThread,
+ make_scoped_refptr(demuxer_stream),
+ filter_callback, stat_callback));
+}
+
+const media::MediaFormat& CaptureVideoDecoder::media_format() {
+ return media_format_;
+}
+
+void CaptureVideoDecoder::ProduceVideoFrame(
+ scoped_refptr<media::VideoFrame> video_frame) {
+ message_loop_proxy_->PostTask(
+ FROM_HERE,
+ NewRunnableMethod(
+ this,
+ &CaptureVideoDecoder::ProduceVideoFrameOnDecoderThread, video_frame));
+}
+
+bool CaptureVideoDecoder::ProvidesBuffer() {
+ return true;
+}
+
+void CaptureVideoDecoder::Play(media::FilterCallback* callback) {
+ message_loop_proxy_->PostTask(
+ FROM_HERE,
+ NewRunnableMethod(this,
+ &CaptureVideoDecoder::PlayOnDecoderThread,
+ callback));
+}
+
+void CaptureVideoDecoder::Pause(media::FilterCallback* callback) {
+ message_loop_proxy_->PostTask(
+ FROM_HERE,
+ NewRunnableMethod(this,
+ &CaptureVideoDecoder::PauseOnDecoderThread,
+ callback));
+}
+
+void CaptureVideoDecoder::Stop(media::FilterCallback* callback) {
+ message_loop_proxy_->PostTask(
+ FROM_HERE,
+ NewRunnableMethod(this,
+ &CaptureVideoDecoder::StopOnDecoderThread,
+ callback));
+}
+
+void CaptureVideoDecoder::Seek(base::TimeDelta time,
+ const media::FilterStatusCB& cb) {
+ message_loop_proxy_->PostTask(
+ FROM_HERE,
+ NewRunnableMethod(this,
+ &CaptureVideoDecoder::SeekOnDecoderThread,
+ time,
+ cb));
+}
+
+void CaptureVideoDecoder::OnStarted(media::VideoCapture* capture) {
+ NOTIMPLEMENTED();
+}
+
+void CaptureVideoDecoder::OnStopped(media::VideoCapture* capture) {
+ message_loop_proxy_->PostTask(
+ FROM_HERE,
+ NewRunnableMethod(this,
+ &CaptureVideoDecoder::OnStoppedOnDecoderThread,
+ capture));
+}
+
+void CaptureVideoDecoder::OnPaused(media::VideoCapture* capture) {
+ NOTIMPLEMENTED();
+}
+
+void CaptureVideoDecoder::OnError(media::VideoCapture* capture,
+ int error_code) {
+ NOTIMPLEMENTED();
+}
+
+void CaptureVideoDecoder::OnBufferReady(
+ media::VideoCapture* capture,
+ scoped_refptr<media::VideoCapture::VideoFrameBuffer> buf) {
+ DCHECK(buf);
+ message_loop_proxy_->PostTask(
+ FROM_HERE,
+ NewRunnableMethod(this,
+ &CaptureVideoDecoder::OnBufferReadyOnDecoderThread,
+ capture,
+ buf));
+}
+
+void CaptureVideoDecoder::OnDeviceInfoReceived(
+ media::VideoCapture* capture,
+ const media::VideoCaptureParams& device_info) {
+ NOTIMPLEMENTED();
+}
+
+void CaptureVideoDecoder::InitializeOnDecoderThread(
+ media::DemuxerStream* demuxer_stream,
+ media::FilterCallback* filter_callback,
+ media::StatisticsCallback* stat_callback) {
+ VLOG(1) << "InitializeOnDecoderThread.";
+ DCHECK(message_loop_proxy_->BelongsToCurrentThread());
+
+ capture_engine_ = vc_manager_->AddDevice(video_stream_id_, this);
+
+ available_frames_.clear();
+ media_format_.SetAsInteger(media::MediaFormat::kWidth, capability_.width);
+ media_format_.SetAsInteger(media::MediaFormat::kHeight, capability_.height);
+ media_format_.SetAsInteger(
+ media::MediaFormat::kSurfaceFormat,
+ static_cast<int>(media::VideoFrame::YV12));
+
+ statistics_callback_.reset(stat_callback);
+ filter_callback->Run();
+ delete filter_callback;
+ state_ = kNormal;
+}
+
+void CaptureVideoDecoder::ProduceVideoFrameOnDecoderThread(
+ scoped_refptr<media::VideoFrame> video_frame) {
+ DCHECK(message_loop_proxy_->BelongsToCurrentThread());
+ available_frames_.push_back(video_frame);
+}
+
+void CaptureVideoDecoder::PlayOnDecoderThread(media::FilterCallback* callback) {
+ VLOG(1) << "PlayOnDecoderThread.";
+ DCHECK(message_loop_proxy_->BelongsToCurrentThread());
+ callback->Run();
+ delete callback;
+}
+
+void CaptureVideoDecoder::PauseOnDecoderThread(
+ media::FilterCallback* callback) {
+ VLOG(1) << "PauseOnDecoderThread.";
+ DCHECK(message_loop_proxy_->BelongsToCurrentThread());
+ state_ = kPaused;
+ media::VideoDecoder::Pause(callback);
+}
+
+void CaptureVideoDecoder::StopOnDecoderThread(media::FilterCallback* callback) {
+ VLOG(1) << "StopOnDecoderThread.";
+ DCHECK(message_loop_proxy_->BelongsToCurrentThread());
+ pending_stop_cb_ = callback;
+ state_ = kStopped;
+ capture_engine_->StopCapture(this);
+}
+
+void CaptureVideoDecoder::SeekOnDecoderThread(base::TimeDelta time,
+ const media::FilterStatusCB& cb) {
+ VLOG(1) << "SeekOnDecoderThread.";
+ DCHECK(message_loop_proxy_->BelongsToCurrentThread());
+
+ state_ = kSeeking;
+ // Create output buffer pool and pass the frames to renderer
+ // so that the renderer can complete the seeking
+ for (size_t i = 0; i < media::Limits::kMaxVideoFrames; ++i) {
+ VideoFrameReady(media::VideoFrame::CreateBlackFrame(capability_.width,
+ capability_.height));
+ }
+
+ cb.Run(media::PIPELINE_OK);
+ state_ = kNormal;
+ capture_engine_->StartCapture(this, capability_);
+}
+
+void CaptureVideoDecoder::OnStoppedOnDecoderThread(
+ media::VideoCapture* capture) {
+ VLOG(1) << "OnStoppedOnDecoderThread.";
+ DCHECK(message_loop_proxy_->BelongsToCurrentThread());
+ if (pending_stop_cb_) {
+ pending_stop_cb_->Run();
+ delete pending_stop_cb_;
+ pending_stop_cb_ = NULL;
+ }
+ vc_manager_->RemoveDevice(video_stream_id_, this);
+}
+
+void CaptureVideoDecoder::OnBufferReadyOnDecoderThread(
+ media::VideoCapture* capture,
+ scoped_refptr<media::VideoCapture::VideoFrameBuffer> buf) {
+ DCHECK(message_loop_proxy_->BelongsToCurrentThread());
+
+ if (available_frames_.size() == 0 || kNormal != state_) {
+ capture->FeedBuffer(buf);
+ return;
+ }
+
+ scoped_refptr<media::VideoFrame> video_frame = available_frames_.front();
+ available_frames_.pop_front();
+
+ if (buf->width != capability_.width || buf->height != capability_.height) {
+ capability_.width = buf->width;
+ capability_.height = buf->height;
+ media_format_.SetAsInteger(media::MediaFormat::kWidth, capability_.width);
+ media_format_.SetAsInteger(media::MediaFormat::kHeight, capability_.height);
+ host()->SetVideoSize(capability_.width, capability_.height);
+ }
+
+ // Check if there's a size change.
+ if (static_cast<int>(video_frame->width()) != capability_.width ||
+ static_cast<int>(video_frame->height()) != capability_.height) {
+ // Allocate new buffer based on the new size.
+ video_frame = media::VideoFrame::CreateFrame(media::VideoFrame::YV12,
+ capability_.width,
+ capability_.height,
+ media::kNoTimestamp,
+ media::kNoTimestamp);
+ }
+
+ video_frame->SetTimestamp(buf->timestamp - start_time_);
+ video_frame->SetDuration(base::TimeDelta::FromMilliseconds(33));
+
+ uint8* buffer = buf->memory_pointer;
+
+ // TODO(wjia): de-duplicating pixel date copying code.
+ uint8* y_plane = video_frame->data(media::VideoFrame::kYPlane);
+ for (size_t row = 0; row < video_frame->height(); ++row) {
+ memcpy(y_plane, buffer, capability_.width);
+ y_plane += video_frame->stride(media::VideoFrame::kYPlane);
+ buffer += capability_.width;
+ }
+ size_t uv_width = capability_.width / 2;
+ uint8* u_plane = video_frame->data(media::VideoFrame::kUPlane);
+ for (size_t row = 0; row < video_frame->height(); row += 2) {
+ memcpy(u_plane, buffer, uv_width);
+ u_plane += video_frame->stride(media::VideoFrame::kUPlane);
+ buffer += uv_width;
+ }
+ uint8* v_plane = video_frame->data(media::VideoFrame::kVPlane);
+ for (size_t row = 0; row < video_frame->height(); row += 2) {
+ memcpy(v_plane, buffer, uv_width);
+ v_plane += video_frame->stride(media::VideoFrame::kVPlane);
+ buffer += uv_width;
+ }
+
+ VideoFrameReady(video_frame);
+ capture->FeedBuffer(buf);
+}
diff --git a/content/renderer/media/capture_video_decoder.h b/content/renderer/media/capture_video_decoder.h
new file mode 100644
index 0000000..2ca923f
--- /dev/null
+++ b/content/renderer/media/capture_video_decoder.h
@@ -0,0 +1,103 @@
+// Copyright (c) 2011 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_CAPTURE_VIDEO_DECODER_H_
+#define CONTENT_RENDERER_MEDIA_CAPTURE_VIDEO_DECODER_H_
+
+#include <deque>
+
+#include "base/time.h"
+#include "media/base/filters.h"
+#include "media/base/video_frame.h"
+#include "media/video/capture/video_capture.h"
+
+namespace base {
+class MessageLoopProxy;
+}
+class VideoCaptureImplManager;
+
+// A filter takes raw frames from video capture engine and passes them to media
+// engine as a video decoder filter.
+class CaptureVideoDecoder
+ : public media::VideoDecoder,
+ public media::VideoCapture::EventHandler {
+ public:
+ CaptureVideoDecoder(
+ base::MessageLoopProxy* message_loop_proxy,
+ media::VideoCaptureSessionId video_stream_id,
+ VideoCaptureImplManager* vc_manager,
+ const media::VideoCapture::VideoCaptureCapability& capability);
+ virtual ~CaptureVideoDecoder();
+
+ // Filter implementation.
+ virtual void Play(media::FilterCallback* callback);
+ virtual void Seek(base::TimeDelta time, const media::FilterStatusCB& cb);
+ virtual void Pause(media::FilterCallback* callback);
+ virtual void Stop(media::FilterCallback* callback);
+
+ // Decoder implementation.
+ virtual void Initialize(media::DemuxerStream* demuxer_stream,
+ media::FilterCallback* filter_callback,
+ media::StatisticsCallback* stat_callback);
+ virtual const media::MediaFormat& media_format();
+ virtual void ProduceVideoFrame(scoped_refptr<media::VideoFrame> video_frame);
+ virtual bool ProvidesBuffer();
+
+ // VideoCapture::EventHandler implementation.
+ virtual void OnStarted(media::VideoCapture* capture);
+ virtual void OnStopped(media::VideoCapture* capture);
+ virtual void OnPaused(media::VideoCapture* capture);
+ virtual void OnError(media::VideoCapture* capture, int error_code);
+ virtual void OnBufferReady(
+ media::VideoCapture* capture,
+ scoped_refptr<media::VideoCapture::VideoFrameBuffer> buf);
+ virtual void OnDeviceInfoReceived(
+ media::VideoCapture* capture,
+ const media::VideoCaptureParams& device_info);
+
+ private:
+ friend class CaptureVideoDecoderTest;
+
+ enum DecoderState {
+ kUnInitialized,
+ kNormal,
+ kSeeking,
+ kStopped,
+ kPaused
+ };
+
+ void PlayOnDecoderThread(media::FilterCallback* callback);
+ void SeekOnDecoderThread(base::TimeDelta time,
+ const media::FilterStatusCB& cb);
+ void PauseOnDecoderThread(media::FilterCallback* callback);
+ void StopOnDecoderThread(media::FilterCallback* callback);
+
+ void InitializeOnDecoderThread(media::DemuxerStream* demuxer_stream,
+ media::FilterCallback* filter_callback,
+ media::StatisticsCallback* stat_callback);
+ void ProduceVideoFrameOnDecoderThread(
+ scoped_refptr<media::VideoFrame> video_frame);
+
+ void OnStoppedOnDecoderThread(media::VideoCapture* capture);
+ void OnBufferReadyOnDecoderThread(
+ media::VideoCapture* capture,
+ scoped_refptr<media::VideoCapture::VideoFrameBuffer> buf);
+
+ scoped_refptr<base::MessageLoopProxy> message_loop_proxy_;
+ scoped_refptr<VideoCaptureImplManager> vc_manager_;
+ media::VideoCapture::VideoCaptureCapability capability_;
+ DecoderState state_;
+ media::MediaFormat media_format_;
+ std::deque<scoped_refptr<media::VideoFrame> > available_frames_;
+ media::FilterCallback* pending_stop_cb_;
+ scoped_ptr<media::StatisticsCallback> statistics_callback_;
+
+ media::VideoCaptureSessionId video_stream_id_;
+ media::VideoCapture* capture_engine_;
+ base::Time start_time_;
+
+ DISALLOW_COPY_AND_ASSIGN(CaptureVideoDecoder);
+};
+
+#endif // CONTENT_RENDERER_MEDIA_CAPTURE_VIDEO_DECODER_H_
diff --git a/content/renderer/media/capture_video_decoder_unittest.cc b/content/renderer/media/capture_video_decoder_unittest.cc
new file mode 100644
index 0000000..6852bee
--- /dev/null
+++ b/content/renderer/media/capture_video_decoder_unittest.cc
@@ -0,0 +1,172 @@
+// Copyright (c) 2011 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/bind.h"
+#include "content/renderer/media/capture_video_decoder.h"
+#include "content/renderer/media/video_capture_impl.h"
+#include "content/renderer/media/video_capture_impl_manager.h"
+#include "media/base/filters.h"
+#include "media/base/limits.h"
+#include "media/base/mock_callback.h"
+#include "media/base/mock_filter_host.h"
+#include "media/base/mock_filters.h"
+#include "media/base/mock_task.h"
+#include "media/base/pipeline_status.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using ::testing::_;
+using ::testing::AnyNumber;
+using ::testing::Return;
+using ::testing::StrictMock;
+
+static const media::VideoCaptureSessionId kVideoStreamId = 1;
+
+ACTION_P(ReturnFrameFromRenderer, decoder) {
+ decoder->ProduceVideoFrame(arg0);
+}
+
+ACTION_P3(CreateDataBufferFromCapture, decoder, vc_impl, data_buffer_number) {
+ for (int i = 0; i < data_buffer_number; i++) {
+ media::VideoCapture::VideoFrameBuffer* buffer;
+ buffer = new media::VideoCapture::VideoFrameBuffer();
+ buffer->width = arg1.width;
+ buffer->height = arg1.height;
+ int length = buffer->width * buffer->height * 3 / 2;
+ buffer->memory_pointer = new uint8[length];
+ buffer->buffer_size = length;
+ decoder->OnBufferReady(vc_impl, buffer);
+ }
+}
+
+ACTION(DeleteDataBuffer) {
+ delete[] arg0->memory_pointer;
+}
+
+ACTION_P2(CaptureStopped, decoder, vc_impl) {
+ decoder->OnStopped(vc_impl);
+}
+
+class MockVideoCaptureImpl : public VideoCaptureImpl {
+ public:
+ MockVideoCaptureImpl(const media::VideoCaptureSessionId id,
+ scoped_refptr<base::MessageLoopProxy> ml_proxy,
+ VideoCaptureMessageFilter* filter)
+ : VideoCaptureImpl(id, ml_proxy, filter) {
+ }
+ virtual ~MockVideoCaptureImpl() {}
+
+ MOCK_METHOD2(StartCapture,
+ void(media::VideoCapture::EventHandler* handler,
+ const VideoCaptureCapability& capability));
+ MOCK_METHOD1(StopCapture, void(media::VideoCapture::EventHandler* handler));
+ MOCK_METHOD1(FeedBuffer, void(scoped_refptr<VideoFrameBuffer> buffer));
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(MockVideoCaptureImpl);
+};
+
+class MockVideoCaptureImplManager : public VideoCaptureImplManager {
+ public:
+ MockVideoCaptureImplManager() {}
+ virtual ~MockVideoCaptureImplManager() {}
+
+ MOCK_METHOD2(AddDevice,
+ media::VideoCapture*(media::VideoCaptureSessionId id,
+ media::VideoCapture::EventHandler* handler));
+ MOCK_METHOD2(RemoveDevice,
+ void(media::VideoCaptureSessionId id,
+ media::VideoCapture::EventHandler* handler));
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(MockVideoCaptureImplManager);
+};
+
+class CaptureVideoDecoderTest : public ::testing::Test {
+ protected:
+ CaptureVideoDecoderTest() {
+ message_loop_.reset(new MessageLoop(MessageLoop::TYPE_IO));
+ message_loop_proxy_ =
+ base::MessageLoopProxy::CreateForCurrentThread().get();
+ vc_manager_ = new MockVideoCaptureImplManager();
+ media::VideoCapture::VideoCaptureCapability capability;
+ capability.width = 176;
+ capability.height = 144;
+ capability.max_fps = 30;
+ capability.expected_capture_delay = 0;
+ capability.raw_type = media::VideoFrame::I420;
+ capability.interlaced = false;
+ capability.resolution_fixed = false;
+
+ decoder_ = new CaptureVideoDecoder(message_loop_proxy_,
+ kVideoStreamId, vc_manager_, capability);
+ renderer_ = new media::MockVideoRenderer();
+
+ decoder_->set_host(&host_);
+ decoder_->set_consume_video_frame_callback(
+ base::Bind(&media::MockVideoRenderer::ConsumeVideoFrame,
+ base::Unretained(renderer_.get())));
+ EXPECT_CALL(statistics_callback_object_, OnStatistics(_))
+ .Times(AnyNumber());
+ }
+
+ virtual ~CaptureVideoDecoderTest() {
+ message_loop_->RunAllPending();
+ }
+
+ media::StatisticsCallback* NewStatisticsCallback() {
+ return NewCallback(&statistics_callback_object_,
+ &media::MockStatisticsCallback::OnStatistics);
+ }
+
+ // Fixture members.
+ scoped_refptr<CaptureVideoDecoder> decoder_;
+ scoped_refptr<MockVideoCaptureImplManager> vc_manager_;
+ scoped_refptr<media::MockVideoRenderer> renderer_;
+ media::MockStatisticsCallback statistics_callback_object_;
+ StrictMock<media::MockFilterHost> host_;
+ scoped_ptr<MessageLoop> message_loop_;
+ scoped_refptr<base::MessageLoopProxy> message_loop_proxy_;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(CaptureVideoDecoderTest);
+};
+
+TEST_F(CaptureVideoDecoderTest, Play) {
+ int data_buffer_number = 1;
+ media::VideoCapture::EventHandler* capture_client =
+ static_cast<media::VideoCapture::EventHandler*>(decoder_);
+ scoped_ptr<MockVideoCaptureImpl> vc_impl(
+ new MockVideoCaptureImpl(kVideoStreamId,
+ message_loop_proxy_,
+ new VideoCaptureMessageFilter()));
+
+ EXPECT_CALL(*vc_manager_, AddDevice(_, _))
+ .WillOnce(Return(vc_impl.get()));
+ decoder_->Initialize(NULL,
+ media::NewExpectedCallback(),
+ NewStatisticsCallback());
+ message_loop_->RunAllPending();
+
+ EXPECT_CALL(*renderer_, ConsumeVideoFrame(_))
+ .WillRepeatedly(ReturnFrameFromRenderer(decoder_.get()));
+ EXPECT_CALL(*vc_impl, StartCapture(capture_client, _))
+ .Times(1)
+ .WillOnce(CreateDataBufferFromCapture(capture_client, vc_impl.get(),
+ data_buffer_number));
+ EXPECT_CALL(*vc_impl, FeedBuffer(_))
+ .Times(data_buffer_number)
+ .WillRepeatedly(DeleteDataBuffer());
+ decoder_->Seek(base::TimeDelta(),
+ media::NewExpectedStatusCB(media::PIPELINE_OK));
+ decoder_->Play(media::NewExpectedCallback());
+ message_loop_->RunAllPending();
+
+ EXPECT_CALL(*vc_impl, StopCapture(capture_client))
+ .Times(1)
+ .WillOnce(CaptureStopped(capture_client, vc_impl.get()));
+ EXPECT_CALL(*vc_manager_, RemoveDevice(_, _))
+ .WillOnce(Return());
+ decoder_->Stop(media::NewExpectedCallback());
+ message_loop_->RunAllPending();
+}
diff --git a/content/renderer/media/media_stream_impl.cc b/content/renderer/media/media_stream_impl.cc
new file mode 100644
index 0000000..20ad098
--- /dev/null
+++ b/content/renderer/media/media_stream_impl.cc
@@ -0,0 +1,49 @@
+// Copyright (c) 2011 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/media_stream_impl.h"
+
+#include "base/string_util.h"
+#include "content/renderer/media/capture_video_decoder.h"
+#include "content/renderer/media/video_capture_impl_manager.h"
+#include "googleurl/src/gurl.h"
+#include "media/base/message_loop_factory.h"
+#include "media/base/pipeline.h"
+
+namespace {
+
+static const int kVideoCaptureWidth = 352;
+static const int kVideoCaptureHeight = 288;
+static const int kVideoCaptureFramePerSecond = 30;
+
+static const int kStartOpenSessionId = 1;
+
+} // namespace
+
+MediaStreamImpl::MediaStreamImpl(VideoCaptureImplManager* vc_manager)
+ : vc_manager_(vc_manager) {
+}
+
+MediaStreamImpl::~MediaStreamImpl() {}
+
+scoped_refptr<media::VideoDecoder> MediaStreamImpl::GetVideoDecoder(
+ const GURL& url, media::MessageLoopFactory* message_loop_factory) {
+ bool raw_media = (url.spec().find(media::kRawMediaScheme) == 0);
+ media::VideoDecoder* decoder = NULL;
+ if (raw_media) {
+ media::VideoCapture::VideoCaptureCapability capability;
+ capability.width = kVideoCaptureWidth;
+ capability.height = kVideoCaptureHeight;
+ capability.max_fps = kVideoCaptureFramePerSecond;
+ capability.expected_capture_delay = 0;
+ capability.raw_type = media::VideoFrame::I420;
+ capability.interlaced = false;
+ capability.resolution_fixed = false;
+
+ decoder = new CaptureVideoDecoder(
+ message_loop_factory->GetMessageLoopProxy("CaptureVideoDecoder").get(),
+ kStartOpenSessionId, vc_manager_.get(), capability);
+ }
+ return decoder;
+}
diff --git a/content/renderer/media/media_stream_impl.h b/content/renderer/media/media_stream_impl.h
new file mode 100644
index 0000000..b338a31
--- /dev/null
+++ b/content/renderer/media/media_stream_impl.h
@@ -0,0 +1,33 @@
+// Copyright (c) 2011 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_STREAM_MEDIA_STREAM_IMPL_H_
+#define CONTENT_RENDERER_MEDIA_STREAM_MEDIA_STREAM_IMPL_H_
+
+#include "base/basictypes.h"
+#include "base/memory/ref_counted.h"
+#include "webkit/glue/media/media_stream_client.h"
+
+class VideoCaptureImplManager;
+
+// A implementation of StreamClient to provide supporting functions, such as
+// GetVideoDecoder.
+class MediaStreamImpl
+ : public webkit_glue::MediaStreamClient,
+ public base::RefCountedThreadSafe<MediaStreamImpl> {
+ public:
+ explicit MediaStreamImpl(VideoCaptureImplManager* vc_manager);
+ virtual ~MediaStreamImpl();
+
+ // Implement webkit_glue::StreamClient.
+ virtual scoped_refptr<media::VideoDecoder> GetVideoDecoder(
+ const GURL& url, media::MessageLoopFactory* message_loop_factory);
+
+ private:
+ scoped_refptr<VideoCaptureImplManager> vc_manager_;
+
+ DISALLOW_COPY_AND_ASSIGN(MediaStreamImpl);
+};
+
+#endif // CONTENT_RENDERER_MEDIA_STREAM_MEDIA_STREAM_IMPL_H_
diff --git a/content/renderer/media/video_capture_impl.cc b/content/renderer/media/video_capture_impl.cc
index b4236a0..2ac180b 100644
--- a/content/renderer/media/video_capture_impl.cc
+++ b/content/renderer/media/video_capture_impl.cc
@@ -22,15 +22,15 @@ bool VideoCaptureImpl::CaptureStarted() {
}
int VideoCaptureImpl::CaptureWidth() {
- return width_;
+ return current_params_.width;
}
int VideoCaptureImpl::CaptureHeight() {
- return height_;
+ return current_params_.height;
}
int VideoCaptureImpl::CaptureFrameRate() {
- return frame_rate_;
+ return current_params_.frame_per_second;
}
VideoCaptureImpl::VideoCaptureImpl(
@@ -39,17 +39,14 @@ VideoCaptureImpl::VideoCaptureImpl(
VideoCaptureMessageFilter* filter)
: VideoCapture(),
message_filter_(filter),
- session_id_(id),
ml_proxy_(ml_proxy),
device_id_(0),
- width_(0),
- height_(0),
- frame_rate_(0),
video_type_(media::VideoFrame::I420),
- new_width_(0),
- new_height_(0),
state_(kStopped) {
DCHECK(filter);
+ memset(&current_params_, 0, sizeof(current_params_));
+ memset(&new_params_, 0, sizeof(new_params_));
+ current_params_.session_id = new_params_.session_id = id;
}
VideoCaptureImpl::~VideoCaptureImpl() {
@@ -102,6 +99,11 @@ void VideoCaptureImpl::StopCapture(media::VideoCapture::EventHandler* handler) {
NewRunnableMethod(this, &VideoCaptureImpl::DoStopCapture, handler));
}
+void VideoCaptureImpl::FeedBuffer(scoped_refptr<VideoFrameBuffer> buffer) {
+ ml_proxy_->PostTask(FROM_HERE,
+ NewRunnableMethod(this, &VideoCaptureImpl::DoFeedBuffer, buffer));
+}
+
void VideoCaptureImpl::OnBufferCreated(
base::SharedMemoryHandle handle,
int length, int buffer_id) {
@@ -151,7 +153,8 @@ void VideoCaptureImpl::DoStartCapture(
}
if (capability.resolution_fixed && master_clients_.size() &&
- (capability.width != width_ || capability.height != height_)) {
+ (capability.width != current_params_.width ||
+ capability.height != current_params_.height)) {
// Can't have 2 master clients with different resolutions.
handler->OnError(this, 1);
return;
@@ -167,11 +170,14 @@ void VideoCaptureImpl::DoStartCapture(
if (state_ == kStarted) {
// Take the resolution of master client.
if (capability.resolution_fixed &&
- (capability.width != width_ || capability.height != height_)) {
- new_width_ = capability.width;
- new_height_ = capability.height;
+ (capability.width != current_params_.width ||
+ capability.height != current_params_.height ||
+ capability.max_fps != current_params_.frame_per_second)) {
+ new_params_.width = capability.width;
+ new_params_.height = capability.height;
+ new_params_.frame_per_second = capability.max_fps;
DLOG(INFO) << "StartCapture: Got master client with new resolution ("
- << new_width_ << ", " << new_height_ << ") "
+ << new_params_.width << ", " << new_params_.height << ") "
<< "during started, try to restart.";
StopDevice();
}
@@ -181,10 +187,11 @@ void VideoCaptureImpl::DoStartCapture(
if (state_ == kStopping) {
if (capability.resolution_fixed || !pending_start()) {
- new_width_ = capability.width;
- new_height_ = capability.height;
+ new_params_.width = capability.width;
+ new_params_.height = capability.height;
+ new_params_.frame_per_second = capability.max_fps;
DLOG(INFO) << "StartCapture: Got new resolution ("
- << new_width_ << ", " << new_height_ << ") "
+ << new_params_.width << ", " << new_params_.height << ") "
<< ", already in stopping.";
}
handler->OnStarted(this);
@@ -193,12 +200,14 @@ void VideoCaptureImpl::DoStartCapture(
DCHECK_EQ(clients_.size(), 1ul);
video_type_ = capability.raw_type;
- new_width_ = 0;
- new_height_ = 0;
- width_ = capability.width;
- height_ = capability.height;
+ new_params_.width = 0;
+ new_params_.height = 0;
+ new_params_.frame_per_second = 0;
+ current_params_.width = capability.width;
+ current_params_.height = capability.height;
+ current_params_.frame_per_second = capability.max_fps;
DLOG(INFO) << "StartCapture: resolution ("
- << width_ << ", " << height_ << "). ";
+ << current_params_.width << ", " << current_params_.height << ")";
StartCaptureInternal();
}
@@ -229,23 +238,27 @@ void VideoCaptureImpl::DoStopCapture(
// clients, except no client case?
if (clients_.size() > 0) {
DLOG(INFO) << "StopCapture: No master client.";
- int maxw = 0;
- int maxh = 0;
+ int max_width = 0;
+ int max_height = 0;
+ int frame_rate = 0;
for (ClientInfo::iterator it = clients_.begin();
it != clients_.end(); it++) {
- if (it->second.width > maxw && it->second.height > maxh) {
- maxw = it->second.width;
- maxh = it->second.height;
+ if (it->second.width > max_width && it->second.height > max_height) {
+ max_width = it->second.width;
+ max_height = it->second.height;
+ frame_rate = it->second.max_fps;
}
}
if (state_ == kStarted) {
// Only handle resolution reduction.
- if (maxw < width_ && maxh < height_) {
- new_width_ = maxw;
- new_height_ = maxh;
+ if (max_width < current_params_.width &&
+ max_height < current_params_.height) {
+ new_params_.width = max_width;
+ new_params_.height = max_height;
+ new_params_.frame_per_second = frame_rate;
DLOG(INFO) << "StopCapture: New smaller resolution ("
- << new_width_ << ", " << new_height_ << ") "
+ << new_params_.width << ", " << new_params_.height << ") "
<< "), stopping ...";
StopDevice();
}
@@ -253,21 +266,42 @@ void VideoCaptureImpl::DoStopCapture(
}
if (state_ == kStopping) {
- new_width_ = maxw;
- new_height_ = maxh;
+ new_params_.width = max_width;
+ new_params_.height = max_height;
+ new_params_.frame_per_second = frame_rate;
DLOG(INFO) << "StopCapture: New resolution ("
- << new_width_ << ", " << new_height_ << ") "
+ << new_params_.width << ", " << new_params_.height << ") "
<< "), during stopping.";
return;
}
} else {
- new_width_ = width_ = 0;
- new_height_ = height_ = 0;
+ new_params_.width = current_params_.width = 0;
+ new_params_.height = current_params_.height = 0;
+ new_params_.frame_per_second = current_params_.frame_per_second = 0;
DLOG(INFO) << "StopCapture: No more client, stopping ...";
StopDevice();
}
}
+void VideoCaptureImpl::DoFeedBuffer(scoped_refptr<VideoFrameBuffer> buffer) {
+ DCHECK(ml_proxy_->BelongsToCurrentThread());
+ DCHECK(client_side_dibs_.find(buffer) != client_side_dibs_.end());
+
+ CachedDIB::iterator it;
+ for (it = cached_dibs_.begin(); it != cached_dibs_.end(); it++) {
+ if (buffer == it->second->mapped_memory)
+ break;
+ }
+
+ DCHECK(it != cached_dibs_.end());
+ if (client_side_dibs_[buffer] <= 1) {
+ client_side_dibs_.erase(buffer);
+ Send(new VideoCaptureHostMsg_BufferReady(device_id_, it->first));
+ } else {
+ client_side_dibs_[buffer]--;
+ }
+}
+
void VideoCaptureImpl::DoBufferCreated(
base::SharedMemoryHandle handle,
int length, int buffer_id) {
@@ -279,10 +313,10 @@ void VideoCaptureImpl::DoBufferCreated(
base::SharedMemory* dib = new base::SharedMemory(handle, false);
dib->Map(length);
buffer = new VideoFrameBuffer();
- buffer->memory_pointer = dib->memory();
+ buffer->memory_pointer = static_cast<uint8*>(dib->memory());
buffer->buffer_size = length;
- buffer->width = width_;
- buffer->height = height_;
+ buffer->width = current_params_.width;
+ buffer->height = current_params_.height;
DIBBuffer* dib_buffer = new DIBBuffer(dib, buffer);
cached_dibs_[buffer_id] = dib_buffer;
@@ -300,12 +334,10 @@ void VideoCaptureImpl::DoBufferReceived(int buffer_id, base::Time timestamp) {
DCHECK(cached_dibs_.find(buffer_id) != cached_dibs_.end());
buffer = cached_dibs_[buffer_id]->mapped_memory;
- // TODO(wjia): handle buffer sharing with downstream modules.
for (ClientInfo::iterator it = clients_.begin(); it != clients_.end(); it++) {
it->first->OnBufferReady(this, buffer);
}
-
- Send(new VideoCaptureHostMsg_BufferReady(device_id_, buffer_id));
+ client_side_dibs_[buffer] = clients_.size();
}
void VideoCaptureImpl::DoStateChanged(const media::VideoCapture::State& state) {
@@ -321,6 +353,7 @@ void VideoCaptureImpl::DoStateChanged(const media::VideoCapture::State& state) {
case media::VideoCapture::kStopped:
state_ = kStopped;
DLOG(INFO) << "OnStateChanged: stopped!, device_id = " << device_id_;
+ STLDeleteValues(&cached_dibs_);
if (pending_start())
RestartCapture();
break;
@@ -366,19 +399,12 @@ void VideoCaptureImpl::DoDelegateAdded(int32 device_id) {
}
void VideoCaptureImpl::StopDevice() {
- if (!ml_proxy_->BelongsToCurrentThread()) {
- ml_proxy_->PostTask(FROM_HERE,
- NewRunnableMethod(this, &VideoCaptureImpl::StopDevice));
- return;
- }
+ DCHECK(ml_proxy_->BelongsToCurrentThread());
if (state_ == kStarted) {
state_ = kStopping;
Send(new VideoCaptureHostMsg_Stop(device_id_));
- width_ = height_ = 0;
- STLDeleteContainerPairSecondPointers(cached_dibs_.begin(),
- cached_dibs_.end());
- cached_dibs_.clear();
+ current_params_.width = current_params_.height = 0;
}
}
@@ -386,12 +412,16 @@ void VideoCaptureImpl::RestartCapture() {
DCHECK(ml_proxy_->BelongsToCurrentThread());
DCHECK_EQ(state_, kStopped);
- width_ = new_width_;
- height_ = new_height_;
- new_width_ = 0;
- new_height_ = 0;
+ current_params_.width = new_params_.width;
+ current_params_.height = new_params_.height;
+ current_params_.frame_per_second = new_params_.frame_per_second;
- DLOG(INFO) << "RestartCapture, " << width_ << ", " << height_;
+ new_params_.width = 0;
+ new_params_.height = 0;
+ new_params_.frame_per_second = 0;
+
+ DLOG(INFO) << "RestartCapture, " << current_params_.width << ", "
+ << current_params_.height;
StartCaptureInternal();
}
@@ -399,13 +429,7 @@ void VideoCaptureImpl::StartCaptureInternal() {
DCHECK(ml_proxy_->BelongsToCurrentThread());
DCHECK(device_id_);
- media::VideoCaptureParams params;
- params.width = width_;
- params.height = height_;
- params.frame_per_second = frame_rate_;
- params.session_id = session_id_;
-
- Send(new VideoCaptureHostMsg_Start(device_id_, params));
+ Send(new VideoCaptureHostMsg_Start(device_id_, current_params_));
state_ = kStarted;
for (ClientInfo::iterator it = clients_.begin(); it != clients_.end(); it++) {
it->first->OnStarted(this);
diff --git a/content/renderer/media/video_capture_impl.h b/content/renderer/media/video_capture_impl.h
index b603652..d61e8df 100644
--- a/content/renderer/media/video_capture_impl.h
+++ b/content/renderer/media/video_capture_impl.h
@@ -14,7 +14,6 @@
#include "content/renderer/media/video_capture_message_filter.h"
#include "media/video/capture/video_capture.h"
-#include "ui/gfx/surface/transport_dib.h"
namespace base {
class MessageLoopProxy;
@@ -28,6 +27,7 @@ class VideoCaptureImpl
virtual void StartCapture(media::VideoCapture::EventHandler* handler,
const VideoCaptureCapability& capability);
virtual void StopCapture(media::VideoCapture::EventHandler* handler);
+ virtual void FeedBuffer(scoped_refptr<VideoFrameBuffer> buffer);
virtual bool CaptureStarted();
virtual int CaptureWidth();
virtual int CaptureHeight();
@@ -43,18 +43,13 @@ class VideoCaptureImpl
virtual void OnDelegateAdded(int32 device_id);
bool pending_start() {
- return (new_width_ > 0 && new_height_ > 0);
+ return (new_params_.width > 0 && new_params_.height > 0);
}
private:
friend class VideoCaptureImplManager;
friend class VideoCaptureImplTest;
-
- enum State {
- kStarted,
- kStopping,
- kStopped
- };
+ friend class MockVideoCaptureImpl;
struct DIBBuffer {
public:
@@ -74,6 +69,7 @@ class VideoCaptureImpl
void DoStartCapture(media::VideoCapture::EventHandler* handler,
const VideoCaptureCapability& capability);
void DoStopCapture(media::VideoCapture::EventHandler* handler);
+ void DoFeedBuffer(scoped_refptr<VideoFrameBuffer> buffer);
void DoBufferCreated(base::SharedMemoryHandle handle,
int length, int buffer_id);
@@ -92,7 +88,6 @@ class VideoCaptureImpl
virtual void Send(IPC::Message* message);
scoped_refptr<VideoCaptureMessageFilter> message_filter_;
- media::VideoCaptureSessionId session_id_;
scoped_refptr<base::MessageLoopProxy> ml_proxy_;
int device_id_;
@@ -100,6 +95,11 @@ class VideoCaptureImpl
typedef std::map<int, DIBBuffer*> CachedDIB;
CachedDIB cached_dibs_;
+ // DIBs at client side. The mapped value |int| means number of clients which
+ // hold this dib.
+ typedef std::map<media::VideoCapture::VideoFrameBuffer*, int> ClientSideDIB;
+ ClientSideDIB client_side_dibs_;
+
typedef std::map<media::VideoCapture::EventHandler*, VideoCaptureCapability>
ClientInfo;
ClientInfo clients_;
@@ -107,13 +107,14 @@ class VideoCaptureImpl
ClientInfo pending_clients_;
- int width_;
- int height_;
- int frame_rate_;
media::VideoFrame::Format video_type_;
- int new_width_;
- int new_height_;
+ // The parameter is being used in current capture session. A capture session
+ // starts with StartCapture and ends with StopCapture.
+ media::VideoCaptureParams current_params_;
+
+ // The parameter will be used in next capture session.
+ media::VideoCaptureParams new_params_;
State state_;
DISALLOW_COPY_AND_ASSIGN(VideoCaptureImpl);
diff --git a/content/renderer/media/video_capture_impl_manager.h b/content/renderer/media/video_capture_impl_manager.h
index 28c0e42..282eb3c 100644
--- a/content/renderer/media/video_capture_impl_manager.h
+++ b/content/renderer/media/video_capture_impl_manager.h
@@ -31,14 +31,14 @@ class VideoCaptureImplManager
// by |id| to VideoCaptureImplManager's list of opened device list.
// A pointer to VideoCapture is returned to client so that client can
// operate on that pointer, such as StartCaptrue, StopCapture.
- media::VideoCapture* AddDevice(
+ virtual media::VideoCapture* AddDevice(
media::VideoCaptureSessionId id,
media::VideoCapture::EventHandler* handler);
// Called by video capture client |handler| to remove device referenced
// by |id| from VideoCaptureImplManager's list of opened device list.
- void RemoveDevice(media::VideoCaptureSessionId id,
- media::VideoCapture::EventHandler* handler);
+ virtual void RemoveDevice(media::VideoCaptureSessionId id,
+ media::VideoCapture::EventHandler* handler);
VideoCaptureMessageFilter* video_capture_message_filter() const {
return filter_;
diff --git a/content/renderer/media/video_capture_module_impl.cc b/content/renderer/media/video_capture_module_impl.cc
new file mode 100644
index 0000000..ad1f908
--- /dev/null
+++ b/content/renderer/media/video_capture_module_impl.cc
@@ -0,0 +1,217 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/renderer/media/video_capture_module_impl.h"
+
+#include "content/renderer/media/video_capture_impl_manager.h"
+
+// static
+webrtc::VideoCaptureModule* webrtc::VideoCaptureModule::Create(
+ const WebRtc_Word32 id, const WebRtc_UWord8* device_unique_id_utf8) {
+ NOTREACHED();
+ return NULL;
+}
+
+VideoCaptureModuleImpl::VideoCaptureModuleImpl(
+ const media::VideoCaptureSessionId id,
+ VideoCaptureImplManager* vc_manager)
+ : webrtc::videocapturemodule::VideoCaptureImpl(id),
+ session_id_(id),
+ thread_("VideoCaptureModuleImpl"),
+ vc_manager_(vc_manager),
+ state_(media::VideoCapture::kStopped),
+ got_first_frame_(false),
+ width_(-1),
+ height_(-1),
+ frame_rate_(-1),
+ video_type_(webrtc::kVideoI420),
+ capture_engine_(NULL),
+ pending_start_(false) {
+ DCHECK(vc_manager_);
+ Init();
+}
+
+VideoCaptureModuleImpl::~VideoCaptureModuleImpl() {
+ vc_manager_->RemoveDevice(session_id_, this);
+ thread_.Stop();
+}
+
+void VideoCaptureModuleImpl::Init() {
+ thread_.Start();
+ message_loop_proxy_ = thread_.message_loop_proxy();
+ capture_engine_ = vc_manager_->AddDevice(session_id_, this);
+}
+
+WebRtc_Word32 VideoCaptureModuleImpl::StartCapture(
+ const webrtc::VideoCaptureCapability& capability) {
+ message_loop_proxy_->PostTask(
+ FROM_HERE,
+ NewRunnableMethod(this,
+ &VideoCaptureModuleImpl::StartCaptureOnCaptureThread,
+ capability));
+ return 0;
+}
+
+WebRtc_Word32 VideoCaptureModuleImpl::StopCapture() {
+ message_loop_proxy_->PostTask(
+ FROM_HERE,
+ NewRunnableMethod(this,
+ &VideoCaptureModuleImpl::StopCaptureOnCaptureThread));
+ return 0;
+}
+
+bool VideoCaptureModuleImpl::CaptureStarted() {
+ return state_ == media::VideoCapture::kStarted;
+}
+
+WebRtc_Word32 VideoCaptureModuleImpl::CaptureSettings(
+ webrtc::VideoCaptureCapability& settings) {
+ settings.width = width_;
+ settings.height = height_;
+ settings.maxFPS = frame_rate_;
+ settings.expectedCaptureDelay = 120;
+ settings.rawType = webrtc::kVideoI420;
+ return 0;
+}
+
+void VideoCaptureModuleImpl::OnStarted(media::VideoCapture* capture) {
+ NOTIMPLEMENTED();
+}
+
+void VideoCaptureModuleImpl::OnStopped(media::VideoCapture* capture) {
+ message_loop_proxy_->PostTask(
+ FROM_HERE,
+ NewRunnableMethod(this, &VideoCaptureModuleImpl::OnStoppedOnCaptureThread,
+ capture));
+}
+
+void VideoCaptureModuleImpl::OnPaused(media::VideoCapture* capture) {
+ NOTIMPLEMENTED();
+}
+
+void VideoCaptureModuleImpl::OnError(media::VideoCapture* capture,
+ int error_code) {
+ NOTIMPLEMENTED();
+}
+
+void VideoCaptureModuleImpl::OnBufferReady(
+ media::VideoCapture* capture,
+ scoped_refptr<media::VideoCapture::VideoFrameBuffer> buf) {
+ message_loop_proxy_->PostTask(
+ FROM_HERE,
+ NewRunnableMethod(this,
+ &VideoCaptureModuleImpl::OnBufferReadyOnCaptureThread,
+ capture, buf));
+}
+
+void VideoCaptureModuleImpl::OnDeviceInfoReceived(
+ media::VideoCapture* capture,
+ const media::VideoCaptureParams& device_info) {
+ NOTIMPLEMENTED();
+}
+
+void VideoCaptureModuleImpl::StartCaptureOnCaptureThread(
+ const webrtc::VideoCaptureCapability& capability) {
+ DCHECK(message_loop_proxy_->BelongsToCurrentThread());
+ DCHECK_NE(state_, media::VideoCapture::kStarted);
+
+ if (state_ == media::VideoCapture::kStopping) {
+ VLOG(1) << "Got a new StartCapture in Stopping state!!! ";
+ pending_start_ = true;
+ pending_cap_ = capability;
+ return;
+ }
+
+ VLOG(1) << "StartCaptureOnCaptureThread: " << capability.width << ", "
+ << capability.height;
+
+ StartCaptureInternal(capability);
+ return;
+}
+
+void VideoCaptureModuleImpl::StartCaptureInternal(
+ const webrtc::VideoCaptureCapability& capability) {
+ DCHECK(message_loop_proxy_->BelongsToCurrentThread());
+ DCHECK_EQ(capability.rawType, webrtc::kVideoI420);
+
+ video_type_ = capability.rawType;
+ width_ = capability.width;
+ height_ = capability.height;
+ frame_rate_ = capability.maxFPS;
+ state_ = media::VideoCapture::kStarted;
+
+ media::VideoCapture::VideoCaptureCapability cap;
+ cap.width = capability.width;
+ cap.height = capability.height;
+ cap.max_fps = capability.maxFPS;
+ cap.raw_type = media::VideoFrame::I420;
+ cap.resolution_fixed = true;
+ capture_engine_->StartCapture(this, cap);
+}
+
+void VideoCaptureModuleImpl::StopCaptureOnCaptureThread() {
+ DCHECK(message_loop_proxy_->BelongsToCurrentThread());
+
+ if (pending_start_) {
+ VLOG(1) << "Got a StopCapture with one pending start!!! ";
+ pending_start_ = false;
+ return;
+ }
+
+ if (state_ != media::VideoCapture::kStarted) {
+ VLOG(1) << "Got a StopCapture while not started!!! ";
+ return;
+ }
+
+ VLOG(1) << "StopCaptureOnCaptureThread. ";
+ state_ = media::VideoCapture::kStopping;
+
+ capture_engine_->StopCapture(this);
+ return;
+}
+
+void VideoCaptureModuleImpl::OnStoppedOnCaptureThread(
+ media::VideoCapture* capture) {
+ DCHECK(message_loop_proxy_->BelongsToCurrentThread());
+
+ VLOG(1) << "Capture Stopped!!! ";
+ state_ = media::VideoCapture::kStopped;
+ got_first_frame_ = false;
+ width_ = -1;
+ height_ = -1;
+ frame_rate_ = -1;
+
+ if (pending_start_) {
+ VLOG(1) << "restart pending start ";
+ pending_start_ = false;
+ StartCaptureInternal(pending_cap_);
+ }
+}
+
+void VideoCaptureModuleImpl::OnBufferReadyOnCaptureThread(
+ media::VideoCapture* capture,
+ scoped_refptr<media::VideoCapture::VideoFrameBuffer> buf) {
+ DCHECK(message_loop_proxy_->BelongsToCurrentThread());
+
+ if (state_ != media::VideoCapture::kStarted)
+ return;
+
+ if (!got_first_frame_) {
+ got_first_frame_ = true;
+ start_time_ = buf->timestamp;
+ }
+
+ frameInfo_.width = buf->width;
+ frameInfo_.height = buf->height;
+ frameInfo_.rawType = video_type_;
+
+ IncomingFrame(
+ static_cast<WebRtc_UWord8*>(buf->memory_pointer),
+ static_cast<WebRtc_Word32>(buf->buffer_size),
+ frameInfo_,
+ static_cast<WebRtc_Word64>(
+ (buf->timestamp - start_time_).InMicroseconds()));
+
+ capture->FeedBuffer(buf);
+}
diff --git a/content/renderer/media/video_capture_module_impl.h b/content/renderer/media/video_capture_module_impl.h
new file mode 100644
index 0000000..5df07e3
--- /dev/null
+++ b/content/renderer/media/video_capture_module_impl.h
@@ -0,0 +1,85 @@
+// Copyright (c) 2011 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_VIDEO_CAPTURE_MODULE_IMPL_H_
+#define CONTENT_RENDERER_MEDIA_VIDEO_CAPTURE_MODULE_IMPL_H_
+
+#include "base/compiler_specific.h"
+#include "base/threading/thread.h"
+#include "media/video/capture/video_capture.h"
+#include "third_party/webrtc/common_types.h"
+#include "third_party/webrtc/modules/video_capture/main/interface/video_capture_defines.h"
+#include "third_party/webrtc/modules/video_capture/main/source/video_capture_impl.h"
+
+class VideoCaptureImplManager;
+
+// An implementation of webrtc::VideoCaptureModule takes raw frames from video
+// capture engine and passed them to webrtc VideoEngine.
+class VideoCaptureModuleImpl
+ : public webrtc::videocapturemodule::VideoCaptureImpl,
+ public media::VideoCapture::EventHandler {
+ public:
+ VideoCaptureModuleImpl(const media::VideoCaptureSessionId id,
+ VideoCaptureImplManager* vc_manager);
+ virtual ~VideoCaptureModuleImpl();
+
+ // Override webrtc::videocapturemodule::VideoCaptureImpl implementation.
+ virtual WebRtc_Word32 StartCapture(
+ const webrtc::VideoCaptureCapability& capability) OVERRIDE;
+ virtual WebRtc_Word32 StopCapture() OVERRIDE;
+ virtual bool CaptureStarted() OVERRIDE;
+ virtual WebRtc_Word32 CaptureSettings(
+ webrtc::VideoCaptureCapability& settings) OVERRIDE;
+
+ // media::VideoCapture::EventHandler implementation.
+ virtual void OnStarted(media::VideoCapture* capture);
+ virtual void OnStopped(media::VideoCapture* capture);
+ virtual void OnPaused(media::VideoCapture* capture);
+ virtual void OnError(media::VideoCapture* capture, int error_code);
+ virtual void OnBufferReady(
+ media::VideoCapture* capture,
+ scoped_refptr<media::VideoCapture::VideoFrameBuffer> buf);
+ virtual void OnDeviceInfoReceived(
+ media::VideoCapture* capture,
+ const media::VideoCaptureParams& device_info);
+
+ private:
+ void Init();
+
+ void StartCaptureOnCaptureThread(
+ const webrtc::VideoCaptureCapability& capability);
+ void StopCaptureOnCaptureThread();
+ void StartCaptureInternal(const webrtc::VideoCaptureCapability& capability);
+
+ void OnStoppedOnCaptureThread(media::VideoCapture* capture);
+ void OnBufferReadyOnCaptureThread(
+ media::VideoCapture* capture,
+ scoped_refptr<media::VideoCapture::VideoFrameBuffer> buf);
+
+ // The id identifies which video capture device is used for this video
+ // capture session.
+ media::VideoCaptureSessionId session_id_;
+ base::Thread thread_;
+ scoped_refptr<base::MessageLoopProxy> message_loop_proxy_;
+ // The video capture manager handles open/close of video capture devices.
+ scoped_refptr<VideoCaptureImplManager> vc_manager_;
+ media::VideoCapture::State state_;
+ bool got_first_frame_;
+ WebRtc_UWord32 width_;
+ WebRtc_UWord32 height_;
+ WebRtc_Word32 frame_rate_;
+ webrtc::RawVideoType video_type_;
+ webrtc::VideoCaptureCapability frameInfo_;
+ base::Time start_time_;
+ // The video capture module generating raw frame data.
+ media::VideoCapture* capture_engine_;
+ bool pending_start_;
+ webrtc::VideoCaptureCapability pending_cap_;
+
+ DISALLOW_COPY_AND_ASSIGN(VideoCaptureModuleImpl);
+};
+
+DISABLE_RUNNABLE_METHOD_REFCOUNT(VideoCaptureModuleImpl);
+
+#endif // CONTENT_RENDERER_MEDIA_VIDEO_CAPTURE_MODULE_IMPL_H_
diff --git a/content/renderer/media/video_capture_module_impl_device_info.cc b/content/renderer/media/video_capture_module_impl_device_info.cc
new file mode 100644
index 0000000..f647fd5
--- /dev/null
+++ b/content/renderer/media/video_capture_module_impl_device_info.cc
@@ -0,0 +1,85 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/renderer/media/video_capture_module_impl_device_info.h"
+
+#include "base/string_util.h"
+
+static const char* kLocalDeviceName = "chromecamera";
+
+// static
+webrtc::VideoCaptureModule::DeviceInfo*
+webrtc::VideoCaptureModule::CreateDeviceInfo(const WebRtc_Word32 id) {
+ return new VideoCaptureModuleImplDeviceInfo(id);
+}
+
+// static
+void webrtc::VideoCaptureModule::DestroyDeviceInfo(
+ webrtc::VideoCaptureModule::DeviceInfo* device_info) {
+ VideoCaptureModuleImplDeviceInfo* dev_info =
+ static_cast<VideoCaptureModuleImplDeviceInfo*>(device_info);
+ delete dev_info;
+}
+
+VideoCaptureModuleImplDeviceInfo::VideoCaptureModuleImplDeviceInfo(
+ const WebRtc_Word32 id) {
+}
+
+VideoCaptureModuleImplDeviceInfo::~VideoCaptureModuleImplDeviceInfo() {}
+
+WebRtc_UWord32 VideoCaptureModuleImplDeviceInfo::NumberOfDevices() {
+ return 1;
+}
+
+WebRtc_Word32 VideoCaptureModuleImplDeviceInfo::GetDeviceName(
+ WebRtc_UWord32 device_number,
+ WebRtc_UWord8* device_name_utf8,
+ WebRtc_UWord32 device_name_length,
+ WebRtc_UWord8* device_unique_id_utf8,
+ WebRtc_UWord32 device_unique_id_utf8_length,
+ WebRtc_UWord8* /* product_unique_id_utf8 */,
+ WebRtc_UWord32 /* product_unique_id_utf8_length */) {
+ base::strlcpy(reinterpret_cast<char*>(device_name_utf8),
+ kLocalDeviceName, device_name_length);
+
+ base::strlcpy(reinterpret_cast<char*>(device_unique_id_utf8),
+ kLocalDeviceName, device_unique_id_utf8_length);
+
+ return 0;
+}
+
+WebRtc_Word32 VideoCaptureModuleImplDeviceInfo::NumberOfCapabilities(
+ const WebRtc_UWord8* deviceUniqueIdUTF8) {
+ return 0;
+}
+
+WebRtc_Word32 VideoCaptureModuleImplDeviceInfo::GetCapability(
+ const WebRtc_UWord8* deviceUniqueIdUTF8,
+ const WebRtc_UWord32 deviceCapabilityNumber,
+ webrtc::VideoCaptureCapability& capability) {
+ return -1;
+}
+
+WebRtc_Word32 VideoCaptureModuleImplDeviceInfo::GetOrientation(
+ const WebRtc_UWord8* deviceUniqueIdUTF8,
+ webrtc::VideoCaptureRotation& orientation) {
+ orientation = webrtc::kCameraRotate0;
+ return -1;
+}
+
+WebRtc_Word32 VideoCaptureModuleImplDeviceInfo::GetBestMatchedCapability(
+ const WebRtc_UWord8* deviceUniqueIdUTF8,
+ const webrtc::VideoCaptureCapability requested,
+ webrtc::VideoCaptureCapability& resulting) {
+ return -1;
+}
+
+WebRtc_Word32 VideoCaptureModuleImplDeviceInfo::DisplayCaptureSettingsDialogBox(
+ const WebRtc_UWord8* /* device_unique_id_utf8*/,
+ const WebRtc_UWord8* /* dialog_title_utf8*/,
+ void* /* parent_window */,
+ WebRtc_UWord32 /* position_x */,
+ WebRtc_UWord32 /* position_y */) {
+ return -1;
+}
diff --git a/content/renderer/media/video_capture_module_impl_device_info.h b/content/renderer/media/video_capture_module_impl_device_info.h
new file mode 100644
index 0000000..8cf9699
--- /dev/null
+++ b/content/renderer/media/video_capture_module_impl_device_info.h
@@ -0,0 +1,54 @@
+// Copyright (c) 2011 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_VIDEO_CAPTURE_MODULE_IMPL_DEVICE_INFO_H_
+#define CONTENT_RENDERER_MEDIA_VIDEO_CAPTURE_MODULE_IMPL_DEVICE_INFO_H_
+
+#include "base/basictypes.h"
+#include "third_party/webrtc/modules/video_capture/main/interface/video_capture.h"
+
+// An implementation of webrtc::VideoCaptureModule::DeviceInfo returns device
+// information about video capture on Chrome platform. Actually, this is a dummy
+// class. The real device management is done by media stream on Chrome.
+class VideoCaptureModuleImplDeviceInfo
+ : public webrtc::VideoCaptureModule::DeviceInfo {
+ public:
+ explicit VideoCaptureModuleImplDeviceInfo(const WebRtc_Word32 id);
+ virtual ~VideoCaptureModuleImplDeviceInfo();
+
+ // webrtc::VideoCaptureModule::DeviceInfo implementation.
+ virtual WebRtc_UWord32 NumberOfDevices();
+ virtual WebRtc_Word32 GetDeviceName(
+ WebRtc_UWord32 device_number,
+ WebRtc_UWord8* device_name_utf8,
+ WebRtc_UWord32 device_name_length,
+ WebRtc_UWord8* device_unique_id_utf8,
+ WebRtc_UWord32 device_unique_id_utf8_ength,
+ WebRtc_UWord8* product_unique_id_utf8 = 0,
+ WebRtc_UWord32 product_unique_id_utf8_length = 0);
+ virtual WebRtc_Word32 NumberOfCapabilities(
+ const WebRtc_UWord8* deviceUniqueIdUTF8);
+ virtual WebRtc_Word32 GetCapability(
+ const WebRtc_UWord8* deviceUniqueIdUTF8,
+ const WebRtc_UWord32 deviceCapabilityNumber,
+ webrtc::VideoCaptureCapability& capability);
+ virtual WebRtc_Word32 GetOrientation(
+ const WebRtc_UWord8* deviceUniqueIdUTF8,
+ webrtc::VideoCaptureRotation& orientation);
+ virtual WebRtc_Word32 GetBestMatchedCapability(
+ const WebRtc_UWord8* deviceUniqueIdUTF8,
+ const webrtc::VideoCaptureCapability requested,
+ webrtc::VideoCaptureCapability& resulting);
+ virtual WebRtc_Word32 DisplayCaptureSettingsDialogBox(
+ const WebRtc_UWord8* device_unique_id_utf8,
+ const WebRtc_UWord8* dialog_title_utf8,
+ void* parent_window,
+ WebRtc_UWord32 position_x,
+ WebRtc_UWord32 position_y);
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(VideoCaptureModuleImplDeviceInfo);
+};
+
+#endif // CONTENT_RENDERER_MEDIA_VIDEO_CAPTURE_MODULE_IMPL_DEVICE_INFO_H_
diff --git a/content/renderer/render_view.cc b/content/renderer/render_view.cc
index 56271f3..e2d4e2f 100644
--- a/content/renderer/render_view.cc
+++ b/content/renderer/render_view.cc
@@ -48,6 +48,7 @@
#include "content/renderer/load_progress_tracker.h"
#include "content/renderer/media/audio_message_filter.h"
#include "content/renderer/media/audio_renderer_impl.h"
+#include "content/renderer/media/media_stream_impl.h"
#include "content/renderer/navigation_state.h"
#include "content/renderer/notification_provider.h"
#include "content/renderer/p2p/socket_dispatcher.h"
@@ -407,6 +408,11 @@ RenderView::RenderView(RenderThreadBase* render_thread,
new MHTMLGenerator(this);
+ if (command_line.HasSwitch(switches::kEnableMediaStream)) {
+ media_stream_impl_ = new MediaStreamImpl(
+ RenderThread::current()->video_capture_impl_manager());
+ }
+
content::GetContentClient()->renderer()->RenderViewCreated(this);
}
@@ -1937,7 +1943,8 @@ WebMediaPlayer* RenderView::createMediaPlayer(
scoped_ptr<webkit_glue::WebMediaPlayerImpl> result(
new webkit_glue::WebMediaPlayerImpl(client,
collection.release(),
- message_loop_factory.release()));
+ message_loop_factory.release(),
+ media_stream_impl_.get()));
if (!result->Initialize(frame,
cmd_line->HasSwitch(switches::kSimpleDataSource),
video_renderer)) {
diff --git a/content/renderer/render_view.h b/content/renderer/render_view.h
index 34e2fa1..43c1b66 100644
--- a/content/renderer/render_view.h
+++ b/content/renderer/render_view.h
@@ -57,6 +57,7 @@ class FilePath;
class GeolocationDispatcher;
class GURL;
class LoadProgressTracker;
+class MediaStreamImpl;
class NavigationState;
class NotificationProvider;
class P2PSocketDispatcher;
@@ -1094,6 +1095,9 @@ class RenderView : public RenderWidget,
// Device orientation dispatcher attached to this view; lazily initialized.
DeviceOrientationDispatcher* device_orientation_dispatcher_;
+ // MediaStreamImpl attached to this view; lazily initialized.
+ scoped_refptr<MediaStreamImpl> media_stream_impl_;
+
// Handles accessibility requests into the renderer side, as well as
// maintains the cache and other features of the accessibility tree.
scoped_ptr<WebKit::WebAccessibilityCache> accessibility_;
diff --git a/media/video/capture/video_capture.h b/media/video/capture/video_capture.h
index 65789fb..9a197e2 100644
--- a/media/video/capture/video_capture.h
+++ b/media/video/capture/video_capture.h
@@ -24,6 +24,7 @@ class VideoCapture {
kStarted,
kPaused,
kStopped,
+ kStopping,
kError,
};
@@ -42,7 +43,7 @@ class VideoCapture {
int height;
int stride;
size_t buffer_size;
- void* memory_pointer;
+ uint8* memory_pointer;
base::Time timestamp;
private:
@@ -98,9 +99,8 @@ class VideoCapture {
// Request video capture to stop capturing for client |handler|.
virtual void StopCapture(EventHandler* handler) = 0;
- // TODO(wjia): Add FeedBuffer when buffer sharing is needed between video
- // capture and downstream module.
- // virtual void FeedBuffer(scoped_refptr<VideoFrameBuffer> buffer) = 0;
+ // Feed buffer to video capture when done with it.
+ virtual void FeedBuffer(scoped_refptr<VideoFrameBuffer> buffer) = 0;
virtual bool CaptureStarted() = 0;
virtual int CaptureWidth() = 0;
diff --git a/webkit/glue/media/media_stream_client.h b/webkit/glue/media/media_stream_client.h
new file mode 100644
index 0000000..2f51d91
--- /dev/null
+++ b/webkit/glue/media/media_stream_client.h
@@ -0,0 +1,33 @@
+// Copyright (c) 2011 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 WEBKIT_GLUE_MEDIA_MEDIA_STREAM_CLIENT_H_
+#define WEBKIT_GLUE_MEDIA_MEDIA_STREAM_CLIENT_H_
+
+#include "base/memory/ref_counted.h"
+
+class GURL;
+
+namespace media {
+class VideoDecoder;
+class MessageLoopFactory;
+}
+
+namespace webkit_glue {
+
+// Define an interface for media stream client to get some information about
+// the media stream.
+class MediaStreamClient {
+ public:
+ virtual scoped_refptr<media::VideoDecoder> GetVideoDecoder(
+ const GURL& url,
+ media::MessageLoopFactory* message_loop_factory) = 0;
+
+ protected:
+ virtual ~MediaStreamClient() {}
+};
+
+} // namespace webkit_glue
+
+#endif // WEBKIT_GLUE_MEDIA_MEDIA_STREAM_CLIENT_H_
diff --git a/webkit/glue/webmediaplayer_impl.cc b/webkit/glue/webmediaplayer_impl.cc
index acc44bc..102116e 100644
--- a/webkit/glue/webmediaplayer_impl.cc
+++ b/webkit/glue/webmediaplayer_impl.cc
@@ -27,6 +27,7 @@
#include "third_party/WebKit/Source/WebKit/chromium/public/WebVideoFrame.h"
#include "webkit/glue/media/buffered_data_source.h"
#include "webkit/glue/media/simple_data_source.h"
+#include "webkit/glue/media/media_stream_client.h"
#include "webkit/glue/media/video_renderer_impl.h"
#include "webkit/glue/media/web_video_renderer.h"
#include "webkit/glue/webvideoframe_impl.h"
@@ -271,7 +272,8 @@ void WebMediaPlayerImpl::Proxy::PutCurrentFrame(
WebMediaPlayerImpl::WebMediaPlayerImpl(
WebKit::WebMediaPlayerClient* client,
media::FilterCollection* collection,
- media::MessageLoopFactory* message_loop_factory)
+ media::MessageLoopFactory* message_loop_factory,
+ MediaStreamClient* media_stream_client)
: network_state_(WebKit::WebMediaPlayer::Empty),
ready_state_(WebKit::WebMediaPlayer::HaveNothing),
main_loop_(NULL),
@@ -282,7 +284,8 @@ WebMediaPlayerImpl::WebMediaPlayerImpl(
seeking_(false),
playback_rate_(0.0f),
client_(client),
- proxy_(NULL) {
+ proxy_(NULL),
+ media_stream_client_(media_stream_client) {
// Saves the current message loop.
DCHECK(!main_loop_);
main_loop_ = MessageLoop::current();
@@ -377,6 +380,17 @@ void WebMediaPlayerImpl::load(const WebKit::WebURL& url) {
DCHECK(MessageLoop::current() == main_loop_);
DCHECK(proxy_);
+ if (media_stream_client_) {
+ scoped_refptr<media::VideoDecoder> new_decoder =
+ media_stream_client_->GetVideoDecoder(url, message_loop_factory_.get());
+ if (new_decoder.get()) {
+ // Remove the default decoder.
+ scoped_refptr<media::VideoDecoder> old_videodecoder;
+ filter_collection_->SelectVideoDecoder(&old_videodecoder);
+ filter_collection_->AddVideoDecoder(new_decoder.get());
+ }
+ }
+
if (chunk_demuxer_factory_.get() &&
chunk_demuxer_factory_->IsUrlSupported(url.spec())) {
media_data_sink_.reset(chunk_demuxer_factory_->CreateMediaDataSink());
diff --git a/webkit/glue/webmediaplayer_impl.h b/webkit/glue/webmediaplayer_impl.h
index 53cac08..49ede0d 100644
--- a/webkit/glue/webmediaplayer_impl.h
+++ b/webkit/glue/webmediaplayer_impl.h
@@ -79,6 +79,7 @@ class WebFrame;
namespace webkit_glue {
class MediaResourceLoaderBridgeFactory;
+class MediaStreamClient;
class WebVideoRenderer;
class WebMediaPlayerImpl : public WebKit::WebMediaPlayer,
@@ -187,7 +188,8 @@ class WebMediaPlayerImpl : public WebKit::WebMediaPlayer,
// Callers must call |Initialize()| before they can use the object.
WebMediaPlayerImpl(WebKit::WebMediaPlayerClient* client,
media::FilterCollection* collection,
- media::MessageLoopFactory* message_loop_factory);
+ media::MessageLoopFactory* message_loop_factory,
+ MediaStreamClient* media_stream_client);
virtual ~WebMediaPlayerImpl();
// Finalizes initialization of the object.
@@ -331,6 +333,8 @@ class WebMediaPlayerImpl : public WebKit::WebMediaPlayer,
scoped_ptr<media::ChunkDemuxerFactory> chunk_demuxer_factory_;
scoped_ptr<media::MediaDataSink> media_data_sink_;
+ MediaStreamClient* media_stream_client_;
+
#if WEBKIT_USING_CG
scoped_ptr<skia::PlatformCanvas> skia_canvas_;
#endif
diff --git a/webkit/support/webkit_support.cc b/webkit/support/webkit_support.cc
index fd84ee6..18d5c8a 100644
--- a/webkit/support/webkit_support.cc
+++ b/webkit/support/webkit_support.cc
@@ -303,7 +303,8 @@ WebKit::WebMediaPlayer* CreateMediaPlayer(WebFrame* frame,
scoped_ptr<webkit_glue::WebMediaPlayerImpl> result(
new webkit_glue::WebMediaPlayerImpl(client,
collection.release(),
- message_loop_factory.release()));
+ message_loop_factory.release(),
+ NULL));
if (!result->Initialize(frame, false, video_renderer)) {
return NULL;
}
diff --git a/webkit/tools/test_shell/test_webview_delegate.cc b/webkit/tools/test_shell/test_webview_delegate.cc
index 9c6e2b7..61cc860 100644
--- a/webkit/tools/test_shell/test_webview_delegate.cc
+++ b/webkit/tools/test_shell/test_webview_delegate.cc
@@ -623,7 +623,8 @@ WebMediaPlayer* TestWebViewDelegate::createMediaPlayer(
scoped_ptr<webkit_glue::WebMediaPlayerImpl> result(
new webkit_glue::WebMediaPlayerImpl(client,
collection.release(),
- message_loop_factory.release()));
+ message_loop_factory.release(),
+ NULL));
if (!result->Initialize(frame, false, video_renderer)) {
return NULL;
}