Index: content/renderer/media/rtc_video_decoder_factory_tv.cc |
diff --git a/content/renderer/media/rtc_video_decoder_factory_tv.cc b/content/renderer/media/rtc_video_decoder_factory_tv.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..922251e09dc4d2279e67b33bed949ba6a97265d8 |
--- /dev/null |
+++ b/content/renderer/media/rtc_video_decoder_factory_tv.cc |
@@ -0,0 +1,237 @@ |
+// Copyright (c) 2013 The Chromium Authors. All rights reserved. |
+// Use of this source code is governed by a BSD-style license that can be |
+// found in the LICENSE file. |
+ |
+#include "content/renderer/media/rtc_video_decoder_factory_tv.h" |
+ |
+#include "base/callback_helpers.h" |
+#include "content/renderer/media/rtc_video_decoder_bridge_tv.h" |
+#include "media/base/bind_to_loop.h" |
+#include "media/base/decoder_buffer.h" |
+#include "third_party/libjingle/source/talk/base/ratetracker.h" |
+ |
+using media::DemuxerStream; |
+ |
+namespace content { |
+ |
+// RTCDemuxerStream ------------------------------------------------------------ |
+ |
+class RTCDemuxerStream : public DemuxerStream { |
+ public: |
+ explicit RTCDemuxerStream(const gfx::Size& size); |
+ virtual ~RTCDemuxerStream(); |
+ |
+ // DemuxerStream implementation. |
+ virtual void Read(const ReadCB& read_cb) OVERRIDE; |
+ virtual const media::AudioDecoderConfig& audio_decoder_config() OVERRIDE; |
+ virtual const media::VideoDecoderConfig& video_decoder_config() OVERRIDE; |
+ virtual Type type() OVERRIDE; |
+ virtual void EnableBitstreamConverter() OVERRIDE; |
+ |
+ void QueueBuffer(scoped_refptr<media::DecoderBuffer> buffer, |
+ const base::Closure& done_cb, |
+ const gfx::Size& new_size); |
+ void Destroy(); |
+ |
+ private: |
+ struct BufferEntry { |
+ BufferEntry(const scoped_refptr<media::DecoderBuffer>& decoder_buffer_param, |
+ const base::Closure& done_cb_param, |
+ const gfx::Size& new_size_param) |
+ : decoder_buffer(decoder_buffer_param), |
+ done_cb(done_cb_param), |
+ new_size(new_size_param) {} |
+ |
+ scoped_refptr<media::DecoderBuffer> decoder_buffer; |
+ base::Closure done_cb; |
+ // When |!new_size.isEmpty()|, it means that config change with new size |
+ // |new_size| happened. |
+ gfx::Size new_size; |
+ }; |
+ |
+ void RunReadCallback_Locked(); |
+ |
+ base::Lock lock_; |
+ bool is_destroyed_; |
+ std::queue<BufferEntry> buffer_queue_; |
+ ReadCB read_cb_; |
+ base::Closure pending_done_cb_; |
+ |
+ media::AudioDecoderConfig dummy_audio_decoder_config_; |
+ media::VideoDecoderConfig video_decoder_config_; |
+ talk_base::RateTracker frame_rate_tracker_; |
+}; |
+ |
+RTCDemuxerStream::RTCDemuxerStream(const gfx::Size& size) |
+ : is_destroyed_(false), |
+ video_decoder_config_(media::kCodecVP8, |
+ media::VP8PROFILE_MAIN, |
+ media::VideoFrame::NATIVE_TEXTURE, |
+ size, |
+ gfx::Rect(size), |
+ size, |
+ NULL, |
+ 0, |
+ false) {} |
+ |
+RTCDemuxerStream::~RTCDemuxerStream() { CHECK(is_destroyed_); } |
+ |
+const media::AudioDecoderConfig& RTCDemuxerStream::audio_decoder_config() { |
+ LOG(FATAL) << "Does not support audio."; |
+ return dummy_audio_decoder_config_; |
+} |
+ |
+const media::VideoDecoderConfig& RTCDemuxerStream::video_decoder_config() { |
+ base::AutoLock lock(lock_); |
ycheo (away)
2013/05/14 13:28:09
Do you need this?
wonsik
2013/05/14 14:18:55
I think so, since video_decoder_config_ may change
|
+ return video_decoder_config_; |
+} |
+ |
+DemuxerStream::Type RTCDemuxerStream::type() { return DemuxerStream::VIDEO; } |
+ |
+void RTCDemuxerStream::EnableBitstreamConverter() { |
+ LOG(FATAL) << "Not reachable."; |
+} |
+ |
+void RTCDemuxerStream::QueueBuffer(scoped_refptr<media::DecoderBuffer> buffer, |
+ const base::Closure& done_cb, |
+ const gfx::Size& new_size) { |
+ base::AutoLock lock(lock_); |
+ if (is_destroyed_) |
+ return; |
+ buffer_queue_.push(BufferEntry(buffer, done_cb, new_size)); |
+ if (buffer) |
+ frame_rate_tracker_.Update(1); |
+ DLOG(INFO) << "frame rate received : " << frame_rate_tracker_.units_second(); |
+ RunReadCallback_Locked(); |
+} |
+ |
+void RTCDemuxerStream::Read(const ReadCB& read_cb) { |
+ base::AutoLock lock(lock_); |
+ CHECK(read_cb_.is_null()); |
+ // A call to |Read| operation means that |MediaSourceDelegate| is done with |
+ // the previous buffer. |
+ if (!pending_done_cb_.is_null()) |
+ base::ResetAndReturn(&pending_done_cb_).Run(); |
+ read_cb_ = media::BindToLoop(base::MessageLoopProxy::current(), read_cb); |
+ RunReadCallback_Locked(); |
+} |
+ |
+void RTCDemuxerStream::Destroy() { |
+ base::AutoLock lock(lock_); |
+ CHECK(!is_destroyed_); |
+ is_destroyed_ = true; |
+ if (!read_cb_.is_null()) |
+ base::ResetAndReturn(&read_cb_).Run(DemuxerStream::kAborted, NULL); |
+} |
+ |
+void RTCDemuxerStream::RunReadCallback_Locked() { |
+ if (read_cb_.is_null() || buffer_queue_.empty()) |
+ return; |
+ |
+ BufferEntry& front = buffer_queue_.front(); |
+ if (!front.new_size.IsEmpty()) { |
+ // No VideoFrame actually reaches cc in Google TV case. We just make |
+ // coded_size == visible_rect == natural_size here. |
+ video_decoder_config_.Initialize(media::kCodecVP8, |
+ media::VP8PROFILE_MAIN, |
+ media::VideoFrame::NATIVE_TEXTURE, |
+ front.new_size, |
+ gfx::Rect(front.new_size), |
+ front.new_size, |
+ NULL, |
+ 0, |
+ false, |
+ false); |
+ base::ResetAndReturn(&read_cb_).Run(DemuxerStream::kConfigChanged, NULL); |
+ front.new_size.SetSize(0, 0); |
+ return; |
+ } |
+ DCHECK(pending_done_cb_.is_null()); |
+ pending_done_cb_ = front.done_cb; |
+ base::ResetAndReturn(&read_cb_).Run(DemuxerStream::kOk, front.decoder_buffer); |
+ buffer_queue_.pop(); |
+} |
+ |
+// RTCVideoDecoderFactoryTv ---------------------------------------------------- |
+ |
+RTCVideoDecoderFactoryTv::RTCVideoDecoderFactoryTv() {} |
+RTCVideoDecoderFactoryTv::~RTCVideoDecoderFactoryTv() {} |
+ |
+webrtc::VideoDecoder* RTCVideoDecoderFactoryTv::CreateVideoDecoder( |
+ webrtc::VideoCodecType type) { |
+ base::AutoLock lock(lock_); |
+ // One decoder at a time! |
+ if (decoder_) |
+ return NULL; |
+ if (type == webrtc::kVideoCodecVP8) { |
+ decoder_.reset(new RTCVideoDecoderBridgeTv(this)); |
+ return decoder_.get(); |
+ } |
+ // returning NULL will make WebRTC fall back to SW decoder. |
+ return NULL; |
+} |
+ |
+void RTCVideoDecoderFactoryTv::DestroyVideoDecoder( |
+ webrtc::VideoDecoder* decoder) { |
+ base::AutoLock lock(lock_); |
+ CHECK(decoder_.get() == decoder); |
+ decoder_.reset(); |
+} |
+ |
+bool RTCVideoDecoderFactoryTv::AcquireDemuxer() { |
+ base::AutoLock lock(lock_); |
+ if (is_acquired_) |
+ return false; |
+ is_acquired_ = true; |
+ return true; |
+} |
+ |
+void RTCVideoDecoderFactoryTv::ReleaseDemuxer() { |
+ base::AutoLock lock(lock_); |
+ CHECK(is_acquired_); |
+ is_acquired_ = false; |
+ // Clean up internal state as a demuxer. |
+ init_cb_.Reset(); |
+ if (stream_) { |
+ stream_->Destroy(); |
+ stream_.reset(); |
+ } |
+} |
+ |
+void RTCVideoDecoderFactoryTv::Initialize(media::DemuxerHost*, |
+ const media::PipelineStatusCB& cb) { |
+ base::AutoLock lock(lock_); |
+ init_cb_ = cb; |
+ if (!stream_) |
+ base::ResetAndReturn(&init_cb_).Run(media::PIPELINE_OK); |
+} |
+ |
+DemuxerStream* RTCVideoDecoderFactoryTv::GetStream(DemuxerStream::Type type) { |
dwkang1
2013/05/14 13:24:07
Same question for this. Can we say this will be ca
wonsik
2013/05/14 14:18:55
Yes. GetStream will only be called after init_cb_
|
+ base::AutoLock lock(lock_); |
+ if (type == DemuxerStream::VIDEO) |
+ return stream_.get(); |
+ return NULL; |
+} |
+ |
+base::TimeDelta RTCVideoDecoderFactoryTv::GetStartTime() const { |
+ return base::TimeDelta(); |
+} |
+ |
+void RTCVideoDecoderFactoryTv::InitializeStream(const gfx::Size& size) { |
+ base::AutoLock lock(lock_); |
+ CHECK(!stream_); |
+ stream_.reset(new RTCDemuxerStream(size)); |
+ if (!init_cb_.is_null()) |
+ base::ResetAndReturn(&init_cb_).Run(media::PIPELINE_OK); |
+} |
+ |
+void RTCVideoDecoderFactoryTv::QueueBuffer( |
+ scoped_refptr<media::DecoderBuffer> buffer, |
+ const base::Closure& done_cb, |
+ const gfx::Size& new_size) { |
+ base::AutoLock lock(lock_); |
+ CHECK(stream_); |
+ stream_->QueueBuffer(buffer, done_cb, new_size); |
+} |
+ |
+} // namespace content |