Chromium Code Reviews| 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.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/message_loop_proxy.h" | |
| 13 #include "base/time.h" | |
| 14 #include "content/renderer/media/native_handle_impl.h" | |
| 15 #include "media/base/decoder_buffer.h" | |
| 16 #include "media/base/yuv_convert.h" | |
| 17 #include "third_party/libjingle/source/talk/base/ratetracker.h" // XXX remove | |
| 18 #include "third_party/webrtc/system_wrappers/interface/ref_count.h" | |
| 19 | |
| 20 | |
| 21 namespace content { | |
| 22 | |
| 23 #define LOG_LINE() VLOG(0) << __FILE__ << ":" << __FUNCTION__ | |
|
Ami GONE FROM CHROMIUM
2013/04/26 00:42:05
Planning to remove before landing?
wuchengli
2013/05/08 15:58:56
Removed.
On 2013/04/26 00:42:05, Ami Fischman wrot
| |
| 24 | |
| 25 // static | |
| 26 const base::TimeDelta RTCVideoDecoderBridge::kDecoderTimeOut = | |
|
Ami GONE FROM CHROMIUM
2013/04/26 00:42:05
Why is this a good idea?
wuchengli
2013/05/08 15:58:56
Removed. Now InitDecode waits for GpuVideoDecoder:
| |
| 27 base::TimeDelta::FromMilliseconds(3000); | |
| 28 | |
| 29 // Helper function that makes sure |read_cb| runs on |message_loop_proxy|. | |
| 30 static void RunOnMessageLoop( | |
|
Ami GONE FROM CHROMIUM
2013/04/26 00:42:05
Any reason this can't be replaced by BindToLoop?
wuchengli
2013/05/08 15:58:56
Removed.
| |
| 31 const media::DemuxerStream::ReadCB& read_cb, | |
| 32 const scoped_refptr<base::MessageLoopProxy>& message_loop_proxy, | |
| 33 media::DemuxerStream::Status status, | |
| 34 const scoped_refptr<media::DecoderBuffer>& buffer) { | |
| 35 if (!message_loop_proxy->BelongsToCurrentThread()) { | |
| 36 message_loop_proxy->PostTask(FROM_HERE, base::Bind( | |
| 37 &RunOnMessageLoop, read_cb, message_loop_proxy, status, buffer)); | |
| 38 return; | |
| 39 } | |
| 40 | |
| 41 read_cb.Run(status, buffer); | |
| 42 } | |
| 43 | |
| 44 void RTCDemuxerStream::Read(const ReadCB& read_cb) { | |
| 45 CHECK(read_cb_.is_null()); | |
| 46 read_cb_ = base::Bind(&RunOnMessageLoop, read_cb, | |
| 47 base::MessageLoopProxy::current()); | |
| 48 | |
| 49 if(!buffer_queue_.IsEmpty()) { | |
| 50 base::ResetAndReturn(&read_cb_).Run( | |
| 51 DemuxerStream::kOk, buffer_queue_.Pop()); | |
| 52 } | |
| 53 } | |
| 54 | |
| 55 const media::AudioDecoderConfig& RTCDemuxerStream::audio_decoder_config() { | |
| 56 CHECK(false) << "Does not support audio."; | |
|
Ami GONE FROM CHROMIUM
2013/04/26 00:42:05
FWIW
LOG(FATAL)
reads slightly more clearly to me
wuchengli
2013/05/08 15:58:56
Done.
| |
| 57 return dummy_audio_decoder_config_; | |
|
Ami GONE FROM CHROMIUM
2013/04/26 00:42:05
this is unreachable, and therefore the member is u
wuchengli
2013/05/08 15:58:56
Removed.
| |
| 58 } | |
| 59 | |
| 60 const media::VideoDecoderConfig& RTCDemuxerStream::video_decoder_config() { | |
| 61 return video_decoder_config_; | |
| 62 } | |
| 63 | |
| 64 media::DemuxerStream::Type RTCDemuxerStream::type() { | |
| 65 return media::DemuxerStream::VIDEO; | |
| 66 } | |
| 67 | |
| 68 void RTCDemuxerStream::EnableBitstreamConverter() { | |
| 69 } | |
|
Ami GONE FROM CHROMIUM
2013/04/26 00:42:05
LOG(FATAL) << "Unreachable!";
wuchengli
2013/05/08 15:58:56
Changed to NOTREACHED();
| |
| 70 | |
| 71 void RTCDemuxerStream::UpdateSize(gfx::Size size) { | |
| 72 gfx::Rect rect(size); | |
| 73 video_decoder_config_.Initialize( | |
| 74 media::kCodecVP8, | |
| 75 media::VP8PROFILE_MAIN, | |
| 76 media::VideoFrame::NATIVE_TEXTURE, | |
| 77 size, rect, size, NULL, 0, false, false); | |
|
Ami GONE FROM CHROMIUM
2013/04/26 00:42:05
Coded==visible==natural sizes/rects?
I suspect the
wuchengli
2013/05/08 15:58:56
Can you explain more? I'm not sure what to put in
| |
| 78 } | |
| 79 | |
| 80 void RTCDemuxerStream::QueueBuffer( | |
| 81 scoped_refptr<media::DecoderBuffer> buffer) { | |
| 82 LOG_LINE(); | |
| 83 LOG_LINE() << " end"; | |
| 84 buffer_queue_.Push(buffer); | |
| 85 | |
| 86 if (!read_cb_.is_null()) { | |
| 87 base::ResetAndReturn(&read_cb_).Run( | |
| 88 DemuxerStream::kOk, buffer_queue_.Pop()); | |
| 89 } | |
| 90 } | |
| 91 | |
| 92 RTCVideoDecoderBridge::RTCVideoDecoderBridge( | |
| 93 scoped_refptr<media::VideoDecoder> video_decoder, | |
| 94 const scoped_refptr<base::MessageLoopProxy>& message_loop) | |
| 95 : video_decoder_(video_decoder), | |
| 96 loop_proxy_(message_loop), | |
| 97 decode_complete_callback_(NULL), | |
| 98 pipeline_status_(media::PIPELINE_OK), | |
| 99 decoder_init_waiter_(false, false), | |
| 100 decoder_reset_waiter_(false, false), | |
| 101 stream_(new RTCDemuxerStream()), | |
| 102 status_(kNoInit), | |
| 103 decoding_error_occured_(false) { | |
| 104 LOG_LINE(); | |
| 105 } | |
| 106 | |
| 107 RTCVideoDecoderBridge::~RTCVideoDecoderBridge() { | |
| 108 LOG_LINE(); | |
| 109 } | |
| 110 | |
| 111 WebRtc_Word32 RTCVideoDecoderBridge::InitDecode( | |
| 112 const webrtc::VideoCodec* codecSettings, | |
| 113 WebRtc_Word32 numberOfCores) { | |
| 114 LOG_LINE(); | |
| 115 if (status_ != kNoInit) { | |
| 116 return WEBRTC_VIDEO_CODEC_ERROR; | |
| 117 } | |
| 118 if (codecSettings->codecType != webrtc::kVideoCodecVP8) { | |
|
Pawel Osciak
2013/04/26 07:08:01
Can this happen if the check in RTCVideoDecoderFac
wuchengli
2013/05/08 15:58:56
All possible codecType are kVideoCodecVP8, kVideoC
| |
| 119 return WEBRTC_VIDEO_CODEC_ERROR; | |
| 120 } | |
| 121 if (codecSettings->codecSpecific.VP8.feedbackModeOn) { | |
| 122 // We don't support feedback mode. | |
| 123 return WEBRTC_VIDEO_CODEC_ERROR; | |
| 124 } | |
| 125 | |
| 126 loop_proxy_->PostTask( | |
| 127 FROM_HERE, | |
| 128 base::Bind(&RTCDemuxerStream::UpdateSize, stream_, | |
| 129 gfx::Size(codecSettings->width, codecSettings->height))); | |
| 130 loop_proxy_->PostTask( | |
| 131 FROM_HERE, | |
| 132 base::Bind(&media::VideoDecoder::Initialize, | |
| 133 video_decoder_, | |
| 134 stream_, | |
| 135 base::Bind(&RTCVideoDecoderBridge::OnUpdatePipelineStatus, | |
| 136 base::Unretained(this)), | |
| 137 base::Bind(&RTCVideoDecoderBridge::OnUpdateStatistics, | |
| 138 base::Unretained(this)))); | |
|
Ami GONE FROM CHROMIUM
2013/04/26 00:42:05
why is this Unretained safe?
| |
| 139 decoder_init_waiter_.TimedWait(kDecoderTimeOut); | |
| 140 if (pipeline_status_ != media::PIPELINE_OK) { | |
| 141 return WEBRTC_VIDEO_CODEC_ERROR; | |
| 142 } | |
|
Pawel Osciak
2013/04/26 07:08:01
No need for braces.
wuchengli
2013/05/08 15:58:56
I added one more line.
| |
| 143 status_ = kInitialized; | |
| 144 LOG_LINE() << "OK"; | |
| 145 return WEBRTC_VIDEO_CODEC_OK; | |
| 146 } | |
| 147 | |
| 148 void RTCVideoDecoderBridge::OnUpdateStatistics( | |
| 149 const media::PipelineStatistics& stats) { | |
| 150 // We don't use statistics for now. | |
| 151 } | |
| 152 | |
| 153 void RTCVideoDecoderBridge::OnUpdatePipelineStatus( | |
| 154 const media::PipelineStatus status) { | |
| 155 VLOG(0) << "RTCVideoDecoderBridge::OnUpdatePipelineStatus. status=" << status; | |
| 156 pipeline_status_ = status; | |
| 157 decoder_init_waiter_.Signal(); | |
| 158 } | |
| 159 | |
| 160 void RTCVideoDecoderBridge::ResetComplete() { | |
| 161 LOG_LINE(); | |
| 162 decoder_reset_waiter_.Signal(); | |
| 163 } | |
| 164 | |
| 165 | |
| 166 WebRtc_Word32 RTCVideoDecoderBridge::Decode( | |
| 167 const webrtc::EncodedImage& inputImage, | |
| 168 bool missingFrames, | |
| 169 const webrtc::RTPFragmentationHeader* fragmentation, | |
| 170 const webrtc::CodecSpecificInfo* codecSpecificInfo, | |
| 171 WebRtc_Word64 renderTimeMs) { | |
|
Ami GONE FROM CHROMIUM
2013/04/26 00:42:05
unused parameters can have their name omitted, whi
wuchengli
2013/05/08 15:58:56
Done.
| |
| 172 VLOG(0) << "RTCVideoDecoderBridge::Decode. status=" << status_; | |
| 173 { | |
| 174 base::AutoLock auto_lock(lock_); | |
|
Pawel Osciak
2013/04/26 07:08:01
Lock usage is mysterious here, especially since th
wuchengli
2013/05/08 15:58:56
decoding_error_occurred_ is read by WebRTC Decodin
| |
| 175 if (decoding_error_occured_) { | |
| 176 // TODO(dwkang): consider creating a SW decoder and falling back to it. | |
|
Ami GONE FROM CHROMIUM
2013/04/26 00:42:05
s/dwkang/wuchengli/g ? :)
wuchengli
2013/05/08 15:58:56
Removed the todo. This doesn't look like the right
| |
| 177 return WEBRTC_VIDEO_CODEC_ERROR; | |
| 178 } | |
| 179 } | |
| 180 if (status_ == kNoInit || decode_complete_callback_ == NULL) { | |
| 181 return WEBRTC_VIDEO_CODEC_UNINITIALIZED; | |
| 182 } | |
|
Pawel Osciak
2013/04/26 07:08:01
Braces not needed and below too.
wuchengli
2013/05/08 15:58:56
Done.
| |
| 183 if (!(status_ == kInitialized || status_ == kDecoding)) { | |
|
Pawel Osciak
2013/04/26 07:08:01
if (status_ != kInitialized && status_ != kDecodin
wuchengli
2013/05/08 15:58:56
Done.
| |
| 184 return WEBRTC_VIDEO_CODEC_ERROR; | |
| 185 } | |
| 186 if (missingFrames || !inputImage._completeFrame) { | |
| 187 // Unlike the SW decoder in libvpx, hw decoder can not handle broken frames. | |
| 188 // Here, we return an error in order to request a key frame. | |
| 189 return WEBRTC_VIDEO_CODEC_ERROR; | |
| 190 } | |
| 191 | |
| 192 if (inputImage._frameType == webrtc::kKeyFrame && | |
| 193 inputImage._encodedWidth != 0 && inputImage._encodedHeight != 0) { | |
| 194 // Only key frame has the size. | |
| 195 gfx::Size new_size(inputImage._encodedWidth, inputImage._encodedHeight); | |
| 196 if (size_ != new_size) { | |
| 197 size_ = new_size; | |
|
Ami GONE FROM CHROMIUM
2013/04/26 00:42:05
member never used; drop?
wuchengli
2013/05/08 15:58:56
This is used so that RTCDemuxerStream::UpdateSize
| |
| 198 loop_proxy_->PostTask( | |
| 199 FROM_HERE, | |
| 200 base::Bind(&RTCDemuxerStream::UpdateSize, stream_, new_size)); | |
|
Ami GONE FROM CHROMIUM
2013/04/26 00:42:05
In this case, you need to signal DemuxerStream::kC
| |
| 201 } | |
| 202 } | |
| 203 scoped_refptr<media::DecoderBuffer> buffer; | |
|
Ami GONE FROM CHROMIUM
2013/04/26 00:42:05
I only got down to here but I think I see your pro
wuchengli
2013/04/26 05:08:08
GpuVideoDecoder::Read is called in RTCVideoDecoder
Ami GONE FROM CHROMIUM
2013/04/26 15:13:34
I see. IIUC the code will wait for each frame to
wuchengli
2013/05/09 15:43:14
The latest patchset does not wait from the GPU pro
| |
| 204 buffer = media::DecoderBuffer::CopyFrom( | |
|
Ami GONE FROM CHROMIUM
2013/04/26 00:42:05
assign on prev line?
wuchengli
2013/05/08 15:58:56
Done.
| |
| 205 inputImage._buffer, inputImage._length); | |
| 206 buffer->SetTimestamp(base::TimeDelta::FromInternalValue( | |
| 207 inputImage._timeStamp)); | |
|
Ami GONE FROM CHROMIUM
2013/04/26 00:42:05
This looks strange; internalvalue is in microsecon
wuchengli
2013/05/09 15:43:14
inputImage._timeStamp is in 90KHz. We need to divi
| |
| 208 | |
| 209 loop_proxy_->PostTask( | |
| 210 FROM_HERE, | |
| 211 base::Bind(&RTCDemuxerStream::QueueBuffer, stream_, buffer)); | |
| 212 | |
| 213 { | |
| 214 base::AutoLock auto_lock(lock_); | |
| 215 for (VideoFrameList::iterator it = ready_video_frames_.begin(); | |
| 216 it != ready_video_frames_.end(); ++it) { | |
| 217 gfx::Rect rect = (*it)->visible_rect(); | |
| 218 decoded_image_.CreateEmptyFrame( | |
| 219 rect.width(), rect.height(), | |
| 220 rect.width(), rect.width() / 2, rect.width() / 2); | |
| 221 webrtc::RefCountImpl<media::NativeHandleImpl>* handle = | |
| 222 new webrtc::RefCountImpl<media::NativeHandleImpl>(); | |
| 223 handle->SetHandle((*it).get()); | |
| 224 decoded_image_.set_native_handle(handle); | |
| 225 decoded_image_.set_timestamp( | |
| 226 static_cast<uint32_t>((*it)->GetTimestamp().InMicroseconds())); | |
| 227 decode_complete_callback_->Decoded(decoded_image_); | |
| 228 decoded_image_.set_native_handle(NULL); | |
| 229 } | |
| 230 ready_video_frames_.clear(); | |
| 231 } | |
| 232 | |
| 233 if (status_ == kInitialized) { | |
| 234 status_ = kDecoding; | |
| 235 RequestFrame(); | |
| 236 } | |
| 237 | |
| 238 return WEBRTC_VIDEO_CODEC_OK; | |
| 239 } | |
| 240 | |
| 241 void RTCVideoDecoderBridge::RequestFrame() { | |
| 242 loop_proxy_->PostTask( | |
| 243 FROM_HERE, | |
| 244 base::Bind(&media::VideoDecoder::Read, | |
| 245 video_decoder_, | |
| 246 base::Bind(&RTCVideoDecoderBridge::FrameReady, | |
| 247 base::AsWeakPtr(this)))); | |
| 248 } | |
| 249 | |
| 250 WebRtc_Word32 RTCVideoDecoderBridge::RegisterDecodeCompleteCallback( | |
| 251 webrtc::DecodedImageCallback* callback) { | |
| 252 decode_complete_callback_ = callback; | |
| 253 return WEBRTC_VIDEO_CODEC_OK; | |
| 254 } | |
| 255 | |
| 256 WebRtc_Word32 RTCVideoDecoderBridge::Release() { | |
| 257 LOG_LINE(); | |
| 258 /*if (status_ == kNoInit) { | |
| 259 return WEBRTC_VIDEO_CODEC_UNINITIALIZED; | |
| 260 } | |
| 261 base::WaitableEvent event(false, false); | |
| 262 loop_proxy_->PostTask( | |
| 263 FROM_HERE, | |
| 264 base::Bind(&media::VideoDecoder::Stop, | |
| 265 video_decoder_, | |
| 266 base::Bind(&base::WaitableEvent::Signal, | |
| 267 base::Unretained(&event)))); | |
| 268 decoder_init_waiter_.Wait(); | |
| 269 status_ = kReleased;*/ | |
| 270 return WEBRTC_VIDEO_CODEC_OK; | |
| 271 } | |
| 272 | |
| 273 WebRtc_Word32 RTCVideoDecoderBridge::Reset() { | |
| 274 LOG_LINE(); | |
| 275 if (status_ == kNoInit) { | |
| 276 LOG(ERROR) << "RTCVideoDecoderBridge::Reset. status==kNoInit"; | |
| 277 return WEBRTC_VIDEO_CODEC_UNINITIALIZED; | |
| 278 } | |
| 279 status_ = kReseting; | |
| 280 base::WaitableEvent event(false, false); | |
|
Pawel Osciak
2013/04/26 07:08:01
unused?
wuchengli
2013/05/08 15:58:56
Removed.
| |
| 281 loop_proxy_->PostTask( | |
| 282 FROM_HERE, | |
| 283 base::Bind(&media::VideoDecoder::Reset, | |
| 284 video_decoder_, | |
| 285 base::Bind(&RTCVideoDecoderBridge::ResetComplete, | |
| 286 base::Unretained(this)))); | |
| 287 decoder_reset_waiter_.Wait(); | |
| 288 status_ = kInitialized; | |
| 289 LOG_LINE() << " OK"; | |
| 290 return WEBRTC_VIDEO_CODEC_OK; | |
| 291 } | |
| 292 | |
| 293 void RTCVideoDecoderBridge::FrameReady( | |
| 294 media::VideoDecoder::Status status, | |
| 295 const scoped_refptr<media::VideoFrame>& frame) { | |
| 296 VLOG(0) << "RTCVideoDecoderBridge::FrameReady. status=" << status | |
| 297 << ". status_=" << status_; | |
| 298 /*{ | |
| 299 static talk_base::RateTracker frame_rate_tracker_; | |
| 300 static base::Time start_time = base::Time::Now(); | |
| 301 base::Time diff = base::Time::Now() - start_time; | |
| 302 VLOG(1) << "RTCVideoDecoderBridge::FrameReady DeliverFrame framerate " | |
| 303 << frame_rate_tracker_.units_second() | |
| 304 << " avg framerate " | |
| 305 << frame_rate_tracker_.total_units() / diff.InSecondsF(); | |
| 306 frame_rate_tracker_.Update(1); | |
| 307 }*/ | |
| 308 | |
| 309 { | |
| 310 base::AutoLock auto_lock(lock_); | |
| 311 if (status != media::VideoDecoder::kOk) { | |
| 312 LOG(ERROR) << "RTCVideoDecoderBridge::FrameReady. status!=kOk"; | |
| 313 decoding_error_occured_ = true; | |
| 314 return; | |
| 315 } | |
| 316 | |
| 317 ready_video_frames_.push_back(frame); | |
|
wuchengli
2013/04/25 12:38:54
How can I call decode_complete_callback_ using web
| |
| 318 } | |
| 319 if (status_ == kDecoding) { | |
| 320 RequestFrame(); | |
| 321 } | |
| 322 } | |
| 323 | |
| 324 } // namespace content | |
| 325 | |
| OLD | NEW |