OLD | NEW |
(Empty) | |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. |
| 4 |
| 5 #include "content/renderer/media/rtc_video_decoder_bridge_tv.h" |
| 6 |
| 7 #include "base/bind.h" |
| 8 #include "base/callback_helpers.h" |
| 9 #include "base/location.h" |
| 10 #include "base/logging.h" |
| 11 #include "base/memory/ref_counted.h" |
| 12 #include "base/memory/singleton.h" |
| 13 #include "base/message_loop_proxy.h" |
| 14 #include "base/time.h" |
| 15 #include "media/base/decoder_buffer.h" |
| 16 #include "third_party/libjingle/source/talk/base/ratetracker.h" |
| 17 |
| 18 namespace content { |
| 19 |
| 20 // Helper function that makes sure |read_cb| runs on |message_loop_proxy|. |
| 21 static void RunOnMessageLoop( |
| 22 const media::DemuxerStream::ReadCB& read_cb, |
| 23 const scoped_refptr<base::MessageLoopProxy>& message_loop_proxy, |
| 24 media::DemuxerStream::Status status, |
| 25 const scoped_refptr<media::DecoderBuffer>& buffer) { |
| 26 if (!message_loop_proxy->BelongsToCurrentThread()) { |
| 27 message_loop_proxy->PostTask(FROM_HERE, base::Bind( |
| 28 &RunOnMessageLoop, read_cb, message_loop_proxy, status, buffer)); |
| 29 return; |
| 30 } |
| 31 read_cb.Run(status, buffer); |
| 32 } |
| 33 |
| 34 //////////////////////////////////////////////////////////////////////////////// |
| 35 |
| 36 class RTCDemuxerStream : public media::DemuxerStream { |
| 37 public: |
| 38 explicit RTCDemuxerStream(const gfx::Size& size); |
| 39 // media::DemuxerStream implementation. |
| 40 virtual void Read(const ReadCB& read_cb) OVERRIDE; |
| 41 virtual const media::AudioDecoderConfig& audio_decoder_config() OVERRIDE; |
| 42 virtual const media::VideoDecoderConfig& video_decoder_config() OVERRIDE; |
| 43 virtual Type type() OVERRIDE; |
| 44 virtual void EnableBitstreamConverter() OVERRIDE; |
| 45 |
| 46 void UpdateSize(const gfx::Size& size); |
| 47 void QueueBuffer(scoped_refptr<media::DecoderBuffer> buffer); |
| 48 |
| 49 protected: |
| 50 friend class base::RefCountedThreadSafe<RTCDemuxerStream>; |
| 51 |
| 52 virtual ~RTCDemuxerStream(); |
| 53 |
| 54 private: |
| 55 media::DecoderBufferQueue buffer_queue_; |
| 56 ReadCB read_cb_; |
| 57 |
| 58 media::AudioDecoderConfig dummy_audio_decoder_config_; |
| 59 media::VideoDecoderConfig video_decoder_config_; |
| 60 talk_base::RateTracker frame_rate_tracker_; |
| 61 }; |
| 62 |
| 63 RTCDemuxerStream::RTCDemuxerStream(const gfx::Size& size) |
| 64 : video_decoder_config_( |
| 65 media::kCodecVP8, |
| 66 media::VP8PROFILE_MAIN, |
| 67 media::VideoFrame::NATIVE_TEXTURE, |
| 68 size, gfx::Rect(size), size, NULL, 0, false) { |
| 69 } |
| 70 |
| 71 RTCDemuxerStream::~RTCDemuxerStream() {} |
| 72 |
| 73 const media::AudioDecoderConfig& RTCDemuxerStream::audio_decoder_config() { |
| 74 DCHECK(false) << "Does not support audio."; |
| 75 return dummy_audio_decoder_config_; |
| 76 } |
| 77 |
| 78 const media::VideoDecoderConfig& RTCDemuxerStream::video_decoder_config() { |
| 79 return video_decoder_config_; |
| 80 } |
| 81 |
| 82 media::DemuxerStream::Type RTCDemuxerStream::type() { |
| 83 return media::DemuxerStream::VIDEO; |
| 84 } |
| 85 |
| 86 void RTCDemuxerStream::EnableBitstreamConverter() { |
| 87 } |
| 88 |
| 89 void RTCDemuxerStream::UpdateSize(const gfx::Size& size) { |
| 90 video_decoder_config_.Initialize( |
| 91 media::kCodecVP8, |
| 92 media::VP8PROFILE_MAIN, |
| 93 media::VideoFrame::NATIVE_TEXTURE, |
| 94 size, gfx::Rect(size), size, NULL, 0, false, false); |
| 95 } |
| 96 |
| 97 void RTCDemuxerStream::QueueBuffer( |
| 98 scoped_refptr<media::DecoderBuffer> buffer) { |
| 99 buffer_queue_.Push(buffer); |
| 100 frame_rate_tracker_.Update(1); |
| 101 DLOG(INFO) << "frame rate received : " << frame_rate_tracker_.units_second(); |
| 102 |
| 103 if (!read_cb_.is_null()) { |
| 104 base::ResetAndReturn(&read_cb_).Run( |
| 105 DemuxerStream::kOk, buffer_queue_.Pop()); |
| 106 } |
| 107 } |
| 108 |
| 109 //////////////////////////////////////////////////////////////////////////////// |
| 110 |
| 111 RTCDemuxerProxy::RTCDemuxerProxy( |
| 112 const scoped_refptr<base::MessageLoopProxy>& message_loop) |
| 113 : loop_proxy_(message_loop), |
| 114 stream_(NULL), |
| 115 host_(NULL) { |
| 116 } |
| 117 |
| 118 RTCDemuxerProxy::~RTCDemuxerProxy() {} |
| 119 |
| 120 void RTCDemuxerProxy::Initialize(media::DemuxerHost* host, |
| 121 const media::PipelineStatusCB& cb) { |
| 122 host_ = host; |
| 123 init_cb_ = cb; |
| 124 } |
| 125 |
| 126 scoped_refptr<media::DemuxerStream> RTCDemuxerProxy::GetStream( |
| 127 media::DemuxerStream::Type type) { |
| 128 if (type == media::DemuxerStream::VIDEO) |
| 129 return stream_; |
| 130 return NULL; |
| 131 } |
| 132 |
| 133 base::TimeDelta RTCDemuxerProxy::GetStartTime() const { |
| 134 return base::TimeDelta(); |
| 135 } |
| 136 |
| 137 void RTCDemuxerProxy::UpdateSize(const gfx::Size& size) { |
| 138 if (!loop_proxy_->BelongsToCurrentThread()) { |
| 139 loop_proxy_->PostTask(FROM_HERE, base::Bind( |
| 140 &RTCDemuxerProxy::UpdateSize, this, size)); |
| 141 return; |
| 142 } |
| 143 if (stream_) { |
| 144 stream_->UpdateSize(size); |
| 145 } else { |
| 146 stream_ = new RTCDemuxerStream(size); |
| 147 if (!init_cb_.is_null()) |
| 148 base::ResetAndReturn(&init_cb_).Run(media::PIPELINE_OK); |
| 149 } |
| 150 } |
| 151 |
| 152 void RTCDemuxerProxy::QueueBuffer( |
| 153 scoped_refptr<media::DecoderBuffer> buffer) { |
| 154 if (!loop_proxy_->BelongsToCurrentThread()) { |
| 155 loop_proxy_->PostTask(FROM_HERE, base::Bind( |
| 156 &RTCDemuxerProxy::QueueBuffer, this, buffer)); |
| 157 return; |
| 158 } |
| 159 stream_->QueueBuffer(buffer); |
| 160 } |
| 161 |
| 162 void RTCDemuxerStream::Read(const ReadCB& read_cb) { |
| 163 CHECK(read_cb_.is_null()); |
| 164 read_cb_ = base::Bind(&RunOnMessageLoop, read_cb, |
| 165 base::MessageLoopProxy::current()); |
| 166 |
| 167 if(!buffer_queue_.IsEmpty()) { |
| 168 base::ResetAndReturn(&read_cb_).Run( |
| 169 DemuxerStream::kOk, buffer_queue_.Pop()); |
| 170 } |
| 171 } |
| 172 |
| 173 //////////////////////////////////////////////////////////////////////////////// |
| 174 |
| 175 class RTCVideoDecoderBridgeTvImpl : public RTCVideoDecoderBridgeTv { |
| 176 public: |
| 177 static RTCVideoDecoderBridgeTvImpl* GetInstance() { |
| 178 return Singleton<RTCVideoDecoderBridgeTvImpl>::get(); |
| 179 } |
| 180 RTCVideoDecoderBridgeTvImpl(); |
| 181 virtual ~RTCVideoDecoderBridgeTvImpl(); |
| 182 |
| 183 // webrtc::VideoDecoder implementation. |
| 184 virtual WebRtc_Word32 InitDecode( |
| 185 const webrtc::VideoCodec* codecSettings, |
| 186 WebRtc_Word32 numberOfCores) OVERRIDE; |
| 187 virtual WebRtc_Word32 Decode( |
| 188 const webrtc::EncodedImage& inputImage, |
| 189 bool missingFrames, |
| 190 const webrtc::RTPFragmentationHeader* fragmentation, |
| 191 const webrtc::CodecSpecificInfo* codecSpecificInfo = NULL, |
| 192 WebRtc_Word64 renderTimeMs = -1) OVERRIDE; |
| 193 virtual WebRtc_Word32 RegisterDecodeCompleteCallback( |
| 194 webrtc::DecodedImageCallback* callback) OVERRIDE; |
| 195 virtual WebRtc_Word32 Release() OVERRIDE; |
| 196 virtual WebRtc_Word32 Reset() OVERRIDE; |
| 197 |
| 198 bool RegisterDemuxer(scoped_refptr<RTCDemuxerProxy> demuxer) OVERRIDE; |
| 199 bool AcquireOwnership() OVERRIDE; |
| 200 void ReleaseOwnership() OVERRIDE; |
| 201 |
| 202 private: |
| 203 friend struct DefaultSingletonTraits<RTCVideoDecoderBridgeTv>; |
| 204 |
| 205 static const base::TimeDelta kDecoderTimeOut; |
| 206 enum Status { |
| 207 kNoInit, |
| 208 kInitialized, |
| 209 }; |
| 210 |
| 211 base::TimeDelta first_render_wall_time_; |
| 212 |
| 213 webrtc::DecodedImageCallback* decode_complete_callback_; |
| 214 scoped_refptr<RTCDemuxerProxy> demuxer_; |
| 215 gfx::Size size_; |
| 216 Status status_; |
| 217 bool being_used_; |
| 218 bool first_frame_; |
| 219 |
| 220 DISALLOW_COPY_AND_ASSIGN(RTCVideoDecoderBridgeTvImpl); |
| 221 }; |
| 222 |
| 223 RTCVideoDecoderBridgeTvImpl::RTCVideoDecoderBridgeTvImpl() |
| 224 : decode_complete_callback_(NULL), |
| 225 status_(kNoInit), |
| 226 being_used_(false), |
| 227 first_frame_(true) { |
| 228 } |
| 229 |
| 230 RTCVideoDecoderBridgeTvImpl::~RTCVideoDecoderBridgeTvImpl() { |
| 231 } |
| 232 |
| 233 bool RTCVideoDecoderBridgeTvImpl::AcquireOwnership() { |
| 234 if (being_used_) { |
| 235 return false; |
| 236 } |
| 237 being_used_ = true; |
| 238 return true; |
| 239 } |
| 240 |
| 241 void RTCVideoDecoderBridgeTvImpl::ReleaseOwnership() { |
| 242 DCHECK(being_used_); |
| 243 being_used_ = false; |
| 244 } |
| 245 |
| 246 WebRtc_Word32 RTCVideoDecoderBridgeTvImpl::InitDecode( |
| 247 const webrtc::VideoCodec* codecSettings, |
| 248 WebRtc_Word32 numberOfCores) { |
| 249 if (status_ != kNoInit) { |
| 250 return WEBRTC_VIDEO_CODEC_ERROR; |
| 251 } |
| 252 if (codecSettings->codecType != webrtc::kVideoCodecVP8) { |
| 253 return WEBRTC_VIDEO_CODEC_ERROR; |
| 254 } |
| 255 if (codecSettings->codecSpecific.VP8.feedbackModeOn) { |
| 256 // We don't support feedback mode. |
| 257 return WEBRTC_VIDEO_CODEC_ERROR; |
| 258 } |
| 259 size_ = gfx::Size(codecSettings->width, codecSettings->height); |
| 260 status_ = kInitialized; |
| 261 if (demuxer_) |
| 262 demuxer_->UpdateSize(size_); |
| 263 |
| 264 return WEBRTC_VIDEO_CODEC_OK; |
| 265 } |
| 266 |
| 267 WebRtc_Word32 RTCVideoDecoderBridgeTvImpl::Decode( |
| 268 const webrtc::EncodedImage& inputImage, |
| 269 bool missingFrames, |
| 270 const webrtc::RTPFragmentationHeader* fragmentation, |
| 271 const webrtc::CodecSpecificInfo* codecSpecificInfo, |
| 272 WebRtc_Word64 renderTimeMs) { |
| 273 if (status_ == kNoInit || decode_complete_callback_ == NULL) { |
| 274 return WEBRTC_VIDEO_CODEC_UNINITIALIZED; |
| 275 } |
| 276 if (!status_ == kInitialized) { |
| 277 return WEBRTC_VIDEO_CODEC_ERROR; |
| 278 } |
| 279 if (missingFrames || !inputImage._completeFrame) { |
| 280 // Unlike the SW decoder in libvpx, hw decoder can not handle broken frames. |
| 281 // Here, we return an error in order to request a key frame. |
| 282 return WEBRTC_VIDEO_CODEC_ERROR; |
| 283 } |
| 284 if (!demuxer_) { |
| 285 // Drop frames until demuxer is up and running. We'll request key frame |
| 286 // once demuxer is ready. |
| 287 return WEBRTC_VIDEO_CODEC_NO_OUTPUT; |
| 288 } |
| 289 |
| 290 if (first_frame_ && inputImage._frameType != webrtc::kKeyFrame) { |
| 291 // If the first frame is not the key frame, return an error to request a key |
| 292 // frame. |
| 293 return WEBRTC_VIDEO_CODEC_ERROR; |
| 294 } |
| 295 first_frame_ = false; |
| 296 if (inputImage._frameType == webrtc::kKeyFrame && |
| 297 inputImage._encodedWidth != 0 && inputImage._encodedHeight != 0) { |
| 298 // Only key frame has the size. |
| 299 gfx::Size new_size(inputImage._encodedWidth, inputImage._encodedHeight); |
| 300 if (size_ != new_size) { |
| 301 size_ = new_size; |
| 302 demuxer_->UpdateSize(new_size); |
| 303 } |
| 304 } |
| 305 scoped_refptr<media::DecoderBuffer> buffer; |
| 306 buffer = media::DecoderBuffer::CopyFrom( |
| 307 inputImage._buffer, inputImage._length); |
| 308 |
| 309 demuxer_->QueueBuffer(buffer); |
| 310 |
| 311 return WEBRTC_VIDEO_CODEC_NO_OUTPUT; |
| 312 } |
| 313 |
| 314 WebRtc_Word32 RTCVideoDecoderBridgeTvImpl::RegisterDecodeCompleteCallback( |
| 315 webrtc::DecodedImageCallback* callback) { |
| 316 decode_complete_callback_ = callback; |
| 317 return WEBRTC_VIDEO_CODEC_OK; |
| 318 } |
| 319 |
| 320 WebRtc_Word32 RTCVideoDecoderBridgeTvImpl::Release() { |
| 321 demuxer_ = NULL; |
| 322 status_ = kNoInit; |
| 323 return WEBRTC_VIDEO_CODEC_OK; |
| 324 } |
| 325 |
| 326 WebRtc_Word32 RTCVideoDecoderBridgeTvImpl::Reset() { |
| 327 return WEBRTC_VIDEO_CODEC_OK; |
| 328 } |
| 329 |
| 330 bool RTCVideoDecoderBridgeTvImpl::RegisterDemuxer( |
| 331 scoped_refptr<RTCDemuxerProxy> demuxer) { |
| 332 if (demuxer_) { |
| 333 return false; |
| 334 } |
| 335 demuxer_ = demuxer; |
| 336 // If this is initialized before demuxer is set, update the demuxer with size |
| 337 // information. |
| 338 if (status_ == kInitialized) |
| 339 demuxer_->UpdateSize(size_); |
| 340 first_frame_ = true; |
| 341 return true; |
| 342 } |
| 343 |
| 344 //////////////////////////////////////////////////////////////////////////////// |
| 345 |
| 346 // static |
| 347 RTCVideoDecoderBridgeTv* RTCVideoDecoderBridgeTv::Get() { |
| 348 return RTCVideoDecoderBridgeTvImpl::GetInstance(); |
| 349 } |
| 350 |
| 351 } // namespace content |
OLD | NEW |