| 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.h" | |
| 6 | |
| 7 #include <deque> | |
| 8 | |
| 9 #include "base/bind.h" | |
| 10 #include "base/memory/singleton.h" | |
| 11 #include "base/message_loop.h" | |
| 12 #include "base/string_util.h" | |
| 13 #include "media/base/data_buffer.h" | |
| 14 #include "media/base/limits.h" | |
| 15 #include "media/base/mock_filters.h" | |
| 16 #include "media/base/test_helpers.h" | |
| 17 #include "media/base/video_frame.h" | |
| 18 #include "testing/gtest/include/gtest/gtest.h" | |
| 19 #include "third_party/libjingle/source/talk/media/base/videoframe.h" | |
| 20 | |
| 21 using ::testing::_; | |
| 22 using ::testing::AnyNumber; | |
| 23 using ::testing::DoAll; | |
| 24 using ::testing::Message; | |
| 25 using ::testing::Return; | |
| 26 using ::testing::ReturnNull; | |
| 27 using ::testing::SetArgumentPointee; | |
| 28 using ::testing::StrictMock; | |
| 29 using ::testing::WithArg; | |
| 30 using ::testing::Invoke; | |
| 31 using media::MockStatisticsCB; | |
| 32 using media::MockVideoRenderer; | |
| 33 using media::NewExpectedClosure; | |
| 34 using media::NewExpectedStatusCB; | |
| 35 using media::PipelineStatistics; | |
| 36 using media::PIPELINE_OK; | |
| 37 using media::StatisticsCB; | |
| 38 | |
| 39 namespace content { | |
| 40 namespace { | |
| 41 | |
| 42 class NullVideoFrame : public cricket::VideoFrame { | |
| 43 public: | |
| 44 NullVideoFrame() {} | |
| 45 virtual ~NullVideoFrame() {} | |
| 46 | |
| 47 virtual bool Reset(uint32 fourcc, int w, int h, int dw, int dh, | |
| 48 uint8 *sample, size_t sample_size, | |
| 49 size_t pixel_width, size_t pixel_height, | |
| 50 int64 elapsed_time, int64 time_stamp, int rotation) | |
| 51 OVERRIDE { | |
| 52 return true; | |
| 53 } | |
| 54 | |
| 55 virtual size_t GetWidth() const OVERRIDE { return 0; } | |
| 56 virtual size_t GetHeight() const OVERRIDE { return 0; } | |
| 57 virtual const uint8 *GetYPlane() const OVERRIDE { return NULL; } | |
| 58 virtual const uint8 *GetUPlane() const OVERRIDE { return NULL; } | |
| 59 virtual const uint8 *GetVPlane() const OVERRIDE { return NULL; } | |
| 60 virtual uint8 *GetYPlane() OVERRIDE { return NULL; } | |
| 61 virtual uint8 *GetUPlane() OVERRIDE { return NULL; } | |
| 62 virtual uint8 *GetVPlane() OVERRIDE { return NULL; } | |
| 63 virtual int32 GetYPitch() const OVERRIDE { return 0; } | |
| 64 virtual int32 GetUPitch() const OVERRIDE { return 0; } | |
| 65 virtual int32 GetVPitch() const OVERRIDE { return 0; } | |
| 66 | |
| 67 virtual size_t GetPixelWidth() const OVERRIDE { return 1; } | |
| 68 virtual size_t GetPixelHeight() const OVERRIDE { return 1; } | |
| 69 virtual int64 GetElapsedTime() const OVERRIDE { return 0; } | |
| 70 virtual int64 GetTimeStamp() const OVERRIDE { return 0; } | |
| 71 virtual void SetElapsedTime(int64 elapsed_time) OVERRIDE {} | |
| 72 virtual void SetTimeStamp(int64 time_stamp) OVERRIDE {} | |
| 73 | |
| 74 virtual int GetRotation() const OVERRIDE { return 0; } | |
| 75 | |
| 76 virtual VideoFrame *Copy() const OVERRIDE { return NULL; } | |
| 77 | |
| 78 virtual bool MakeExclusive() OVERRIDE { return true; } | |
| 79 | |
| 80 virtual size_t CopyToBuffer(uint8 *buffer, size_t size) const OVERRIDE { | |
| 81 return 0; | |
| 82 } | |
| 83 | |
| 84 virtual size_t ConvertToRgbBuffer(uint32 to_fourcc, uint8 *buffer, | |
| 85 size_t size, | |
| 86 int stride_rgb) const OVERRIDE { | |
| 87 return 0; | |
| 88 } | |
| 89 | |
| 90 virtual void StretchToPlanes(uint8 *y, uint8 *u, uint8 *v, | |
| 91 int32 pitchY, int32 pitchU, int32 pitchV, | |
| 92 size_t width, size_t height, | |
| 93 bool interpolate, bool crop) const OVERRIDE { | |
| 94 } | |
| 95 | |
| 96 virtual size_t StretchToBuffer(size_t w, size_t h, uint8 *buffer, size_t size, | |
| 97 bool interpolate, bool crop) const OVERRIDE { | |
| 98 return 0; | |
| 99 } | |
| 100 | |
| 101 virtual void StretchToFrame(VideoFrame *target, bool interpolate, | |
| 102 bool crop) const OVERRIDE { | |
| 103 } | |
| 104 | |
| 105 virtual VideoFrame *Stretch(size_t w, size_t h, bool interpolate, | |
| 106 bool crop) const OVERRIDE { | |
| 107 return NULL; | |
| 108 } | |
| 109 | |
| 110 protected: | |
| 111 virtual VideoFrame* CreateEmptyFrame(int w, int h, | |
| 112 size_t pixel_width, size_t pixel_height, | |
| 113 int64 elapsed_time, | |
| 114 int64 time_stamp) const OVERRIDE { | |
| 115 return NULL; | |
| 116 } | |
| 117 }; | |
| 118 | |
| 119 class MockVideoTrack : public webrtc::VideoTrackInterface { | |
| 120 public: | |
| 121 static MockVideoTrack* Create() { | |
| 122 return new talk_base::RefCountedObject<MockVideoTrack>(); | |
| 123 } | |
| 124 | |
| 125 virtual std::string kind() const OVERRIDE { | |
| 126 NOTIMPLEMENTED(); | |
| 127 return ""; | |
| 128 } | |
| 129 virtual std::string id() const OVERRIDE { | |
| 130 NOTIMPLEMENTED(); | |
| 131 return ""; | |
| 132 } | |
| 133 virtual bool enabled() const OVERRIDE { | |
| 134 NOTIMPLEMENTED(); | |
| 135 return false; | |
| 136 } | |
| 137 virtual TrackState state() const OVERRIDE { | |
| 138 NOTIMPLEMENTED(); | |
| 139 return kEnded; | |
| 140 } | |
| 141 virtual bool set_enabled(bool enable) OVERRIDE { | |
| 142 NOTIMPLEMENTED(); | |
| 143 return false; | |
| 144 } | |
| 145 virtual bool set_state(TrackState new_state) OVERRIDE { | |
| 146 NOTIMPLEMENTED(); | |
| 147 return false; | |
| 148 } | |
| 149 virtual void RegisterObserver(webrtc::ObserverInterface* observer) OVERRIDE { | |
| 150 NOTIMPLEMENTED(); | |
| 151 } | |
| 152 virtual void UnregisterObserver( | |
| 153 webrtc::ObserverInterface* observer) OVERRIDE { | |
| 154 NOTIMPLEMENTED(); | |
| 155 } | |
| 156 virtual webrtc::VideoSourceInterface* GetSource() const OVERRIDE { | |
| 157 NOTIMPLEMENTED(); | |
| 158 return NULL; | |
| 159 } | |
| 160 MOCK_METHOD1(AddRenderer, void(webrtc::VideoRendererInterface* renderer)); | |
| 161 MOCK_METHOD1(RemoveRenderer, void(webrtc::VideoRendererInterface* renderer)); | |
| 162 | |
| 163 virtual cricket::VideoRenderer* FrameInput() OVERRIDE { | |
| 164 NOTIMPLEMENTED(); | |
| 165 return NULL; | |
| 166 } | |
| 167 | |
| 168 protected: | |
| 169 MockVideoTrack() {} | |
| 170 ~MockVideoTrack() {} | |
| 171 }; | |
| 172 | |
| 173 } // namespace | |
| 174 | |
| 175 class RTCVideoDecoderTest : public testing::Test { | |
| 176 protected: | |
| 177 static const int kWidth; | |
| 178 static const int kHeight; | |
| 179 static const PipelineStatistics kStatistics; | |
| 180 | |
| 181 RTCVideoDecoderTest() { | |
| 182 } | |
| 183 | |
| 184 virtual ~RTCVideoDecoderTest() { | |
| 185 } | |
| 186 | |
| 187 virtual void SetUp() OVERRIDE { | |
| 188 video_track_ = MockVideoTrack::Create(); | |
| 189 decoder_ = new RTCVideoDecoder(message_loop_.message_loop_proxy(), | |
| 190 message_loop_.message_loop_proxy(), | |
| 191 video_track_); | |
| 192 read_cb_ = base::Bind(&RTCVideoDecoderTest::FrameReady, | |
| 193 base::Unretained(this)); | |
| 194 | |
| 195 DCHECK(decoder_); | |
| 196 | |
| 197 EXPECT_CALL(statistics_cb_, OnStatistics(_)) | |
| 198 .Times(AnyNumber()); | |
| 199 } | |
| 200 | |
| 201 virtual void TearDown() OVERRIDE { | |
| 202 if (decoder_->state_ == RTCVideoDecoder::kStopped) | |
| 203 return; | |
| 204 Stop(); | |
| 205 } | |
| 206 | |
| 207 void InitializeDecoderSuccessfully() { | |
| 208 EXPECT_CALL(*video_track_, AddRenderer(decoder_.get())); | |
| 209 // Test successful initialization. | |
| 210 decoder_->Initialize( | |
| 211 NULL, NewExpectedStatusCB(PIPELINE_OK), NewStatisticsCB()); | |
| 212 message_loop_.RunUntilIdle(); | |
| 213 } | |
| 214 | |
| 215 void Stop() { | |
| 216 EXPECT_CALL(*video_track_, RemoveRenderer(decoder_.get())); | |
| 217 decoder_->Stop(media::NewExpectedClosure()); | |
| 218 | |
| 219 message_loop_.RunUntilIdle(); | |
| 220 EXPECT_EQ(RTCVideoDecoder::kStopped, decoder_->state_); | |
| 221 } | |
| 222 | |
| 223 StatisticsCB NewStatisticsCB() { | |
| 224 return base::Bind(&MockStatisticsCB::OnStatistics, | |
| 225 base::Unretained(&statistics_cb_)); | |
| 226 } | |
| 227 | |
| 228 void RenderFrame() { | |
| 229 NullVideoFrame video_frame; | |
| 230 decoder_->RenderFrame(&video_frame); | |
| 231 } | |
| 232 | |
| 233 MOCK_METHOD2(FrameReady, void(media::VideoDecoder::Status status, | |
| 234 const scoped_refptr<media::VideoFrame>&)); | |
| 235 | |
| 236 // Fixture members. | |
| 237 scoped_refptr<MockVideoTrack> video_track_; | |
| 238 scoped_refptr<RTCVideoDecoder> decoder_; | |
| 239 MockStatisticsCB statistics_cb_; | |
| 240 MessageLoop message_loop_; | |
| 241 media::VideoDecoder::ReadCB read_cb_; | |
| 242 | |
| 243 private: | |
| 244 DISALLOW_COPY_AND_ASSIGN(RTCVideoDecoderTest); | |
| 245 }; | |
| 246 | |
| 247 const int RTCVideoDecoderTest::kWidth = 640; | |
| 248 const int RTCVideoDecoderTest::kHeight = 480; | |
| 249 const PipelineStatistics RTCVideoDecoderTest::kStatistics; | |
| 250 | |
| 251 MATCHER_P2(HasSize, width, height, "") { | |
| 252 EXPECT_EQ(arg->coded_size().width(), width); | |
| 253 EXPECT_EQ(arg->coded_size().height(), height); | |
| 254 EXPECT_EQ(arg->visible_rect().x(), 0); | |
| 255 EXPECT_EQ(arg->visible_rect().y(), 0); | |
| 256 EXPECT_EQ(arg->visible_rect().width(), width); | |
| 257 EXPECT_EQ(arg->visible_rect().height(), height); | |
| 258 EXPECT_EQ(arg->natural_size().width(), width); | |
| 259 EXPECT_EQ(arg->natural_size().height(), height); | |
| 260 return (arg->coded_size().width() == width) && | |
| 261 (arg->coded_size().height() == height) && | |
| 262 (arg->visible_rect().x() == 0) && | |
| 263 (arg->visible_rect().y() == 0) && | |
| 264 (arg->visible_rect().width() == width) && | |
| 265 (arg->visible_rect().height() == height) && | |
| 266 (arg->natural_size().width() == width) && | |
| 267 (arg->natural_size().height() == height); | |
| 268 } | |
| 269 | |
| 270 TEST_F(RTCVideoDecoderTest, Initialize_Successful) { | |
| 271 InitializeDecoderSuccessfully(); | |
| 272 | |
| 273 EXPECT_CALL(*this, FrameReady(media::VideoDecoder::kOk, | |
| 274 HasSize(kWidth, kHeight))); | |
| 275 decoder_->Read(read_cb_); | |
| 276 RenderFrame(); | |
| 277 } | |
| 278 | |
| 279 TEST_F(RTCVideoDecoderTest, DoReset) { | |
| 280 InitializeDecoderSuccessfully(); | |
| 281 | |
| 282 EXPECT_CALL(*this, FrameReady(media::VideoDecoder::kOk, | |
| 283 scoped_refptr<media::VideoFrame>())); | |
| 284 decoder_->Read(read_cb_); | |
| 285 decoder_->Reset(media::NewExpectedClosure()); | |
| 286 | |
| 287 message_loop_.RunUntilIdle(); | |
| 288 EXPECT_EQ(RTCVideoDecoder::kNormal, decoder_->state_); | |
| 289 } | |
| 290 | |
| 291 TEST_F(RTCVideoDecoderTest, DoRenderFrame) { | |
| 292 InitializeDecoderSuccessfully(); | |
| 293 | |
| 294 for (size_t i = 0; i < media::limits::kMaxVideoFrames; ++i) | |
| 295 RenderFrame(); | |
| 296 | |
| 297 message_loop_.RunUntilIdle(); | |
| 298 EXPECT_EQ(RTCVideoDecoder::kNormal, decoder_->state_); | |
| 299 } | |
| 300 | |
| 301 TEST_F(RTCVideoDecoderTest, DoSetSize) { | |
| 302 InitializeDecoderSuccessfully(); | |
| 303 | |
| 304 EXPECT_CALL(*this, FrameReady(media::VideoDecoder::kOk, | |
| 305 HasSize(kWidth, kHeight))); | |
| 306 decoder_->Read(read_cb_); | |
| 307 RenderFrame(); | |
| 308 message_loop_.RunUntilIdle(); | |
| 309 | |
| 310 int new_width = kWidth * 2; | |
| 311 int new_height = kHeight * 2; | |
| 312 decoder_->SetSize(new_width, new_height); | |
| 313 | |
| 314 EXPECT_CALL(*this, FrameReady(media::VideoDecoder::kOk, | |
| 315 HasSize(new_width, new_height))); | |
| 316 decoder_->Read(read_cb_); | |
| 317 RenderFrame(); | |
| 318 message_loop_.RunUntilIdle(); | |
| 319 } | |
| 320 | |
| 321 TEST_F(RTCVideoDecoderTest, ReadAndShutdown) { | |
| 322 // Test all the Read requests can be fullfilled (which is needed in order to | |
| 323 // teardown the pipeline) even when there's no input frame. | |
| 324 InitializeDecoderSuccessfully(); | |
| 325 | |
| 326 EXPECT_CALL(*this, FrameReady(media::VideoDecoder::kOk, | |
| 327 scoped_refptr<media::VideoFrame>())); | |
| 328 decoder_->Read(read_cb_); | |
| 329 Stop(); | |
| 330 | |
| 331 // Any read after stopping should be immediately satisfied. | |
| 332 EXPECT_CALL(*this, FrameReady(media::VideoDecoder::kOk, | |
| 333 scoped_refptr<media::VideoFrame>())); | |
| 334 decoder_->Read(read_cb_); | |
| 335 message_loop_.RunUntilIdle(); | |
| 336 } | |
| 337 | |
| 338 } // namespace content | |
| OLD | NEW |