1// Copyright 2014 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 <list> 6 7#include "base/basictypes.h" 8#include "base/bind.h" 9#include "base/memory/ref_counted.h" 10#include "base/memory/scoped_ptr.h" 11#include "base/threading/thread.h" 12#include "base/time/time.h" 13#include "chromecast/media/cma/base/balanced_media_task_runner_factory.h" 14#include "chromecast/media/cma/base/decoder_buffer_base.h" 15#include "chromecast/media/cma/filters/demuxer_stream_adapter.h" 16#include "media/base/audio_decoder_config.h" 17#include "media/base/decoder_buffer.h" 18#include "media/base/demuxer_stream.h" 19#include "media/base/video_decoder_config.h" 20#include "testing/gtest/include/gtest/gtest.h" 21 22namespace chromecast { 23namespace media { 24 25namespace { 26 27class DummyDemuxerStream : public ::media::DemuxerStream { 28 public: 29 // Creates a demuxer stream which provides frames either with a delay 30 // or instantly. The scheduling pattern is the following: 31 // - provides |delayed_frame_count| frames with a delay, 32 // - then provides the following |cycle_count| - |delayed_frame_count| 33 // instantly, 34 // - then provides |delayed_frame_count| frames with a delay, 35 // - ... and so on. 36 // Special cases: 37 // - all frames are delayed: |delayed_frame_count| = |cycle_count| 38 // - all frames are provided instantly: |delayed_frame_count| = 0 39 // |config_idx| is a list of frame index before which there is 40 // a change of decoder configuration. 41 DummyDemuxerStream(int cycle_count, 42 int delayed_frame_count, 43 const std::list<int>& config_idx); 44 virtual ~DummyDemuxerStream(); 45 46 // ::media::DemuxerStream implementation. 47 virtual void Read(const ReadCB& read_cb) OVERRIDE; 48 virtual ::media::AudioDecoderConfig audio_decoder_config() OVERRIDE; 49 virtual ::media::VideoDecoderConfig video_decoder_config() OVERRIDE; 50 virtual Type type() OVERRIDE; 51 virtual bool SupportsConfigChanges() OVERRIDE; 52 virtual ::media::VideoRotation video_rotation() OVERRIDE; 53 54 bool has_pending_read() const { 55 return has_pending_read_; 56 } 57 58 private: 59 void DoRead(const ReadCB& read_cb); 60 61 // Demuxer configuration. 62 const int cycle_count_; 63 const int delayed_frame_count_; 64 std::list<int> config_idx_; 65 66 // Number of frames sent so far. 67 int frame_count_; 68 69 bool has_pending_read_; 70 71 DISALLOW_COPY_AND_ASSIGN(DummyDemuxerStream); 72}; 73 74DummyDemuxerStream::DummyDemuxerStream( 75 int cycle_count, 76 int delayed_frame_count, 77 const std::list<int>& config_idx) 78 : cycle_count_(cycle_count), 79 delayed_frame_count_(delayed_frame_count), 80 config_idx_(config_idx), 81 frame_count_(0), 82 has_pending_read_(false) { 83 DCHECK_LE(delayed_frame_count, cycle_count); 84} 85 86DummyDemuxerStream::~DummyDemuxerStream() { 87} 88 89void DummyDemuxerStream::Read(const ReadCB& read_cb) { 90 has_pending_read_ = true; 91 if (!config_idx_.empty() && config_idx_.front() == frame_count_) { 92 config_idx_.pop_front(); 93 has_pending_read_ = false; 94 read_cb.Run(kConfigChanged, 95 scoped_refptr< ::media::DecoderBuffer>()); 96 return; 97 } 98 99 if ((frame_count_ % cycle_count_) < delayed_frame_count_) { 100 base::MessageLoopProxy::current()->PostDelayedTask( 101 FROM_HERE, 102 base::Bind(&DummyDemuxerStream::DoRead, base::Unretained(this), 103 read_cb), 104 base::TimeDelta::FromMilliseconds(20)); 105 return; 106 } 107 DoRead(read_cb); 108} 109 110::media::AudioDecoderConfig DummyDemuxerStream::audio_decoder_config() { 111 LOG(FATAL) << "DummyDemuxerStream is a video DemuxerStream"; 112 return ::media::AudioDecoderConfig(); 113} 114 115::media::VideoDecoderConfig DummyDemuxerStream::video_decoder_config() { 116 gfx::Size coded_size(640, 480); 117 gfx::Rect visible_rect(640, 480); 118 gfx::Size natural_size(640, 480); 119 return ::media::VideoDecoderConfig( 120 ::media::kCodecH264, 121 ::media::VIDEO_CODEC_PROFILE_UNKNOWN, 122 ::media::VideoFrame::YV12, 123 coded_size, 124 visible_rect, 125 natural_size, 126 NULL, 0, 127 false); 128} 129 130::media::DemuxerStream::Type DummyDemuxerStream::type() { 131 return VIDEO; 132} 133 134bool DummyDemuxerStream::SupportsConfigChanges() { 135 return true; 136} 137 138::media::VideoRotation DummyDemuxerStream::video_rotation() { 139 return ::media::VIDEO_ROTATION_0; 140} 141 142void DummyDemuxerStream::DoRead(const ReadCB& read_cb) { 143 has_pending_read_ = false; 144 scoped_refptr< ::media::DecoderBuffer> buffer( 145 new ::media::DecoderBuffer(16)); 146 buffer->set_timestamp(frame_count_ * base::TimeDelta::FromMilliseconds(40)); 147 frame_count_++; 148 read_cb.Run(kOk, buffer); 149} 150 151} // namespace 152 153class DemuxerStreamAdapterTest : public testing::Test { 154 public: 155 DemuxerStreamAdapterTest(); 156 virtual ~DemuxerStreamAdapterTest(); 157 158 void Initialize(::media::DemuxerStream* demuxer_stream); 159 void Start(); 160 161 protected: 162 void OnTestTimeout(); 163 void OnNewFrame(const scoped_refptr<DecoderBufferBase>& buffer, 164 const ::media::AudioDecoderConfig& audio_config, 165 const ::media::VideoDecoderConfig& video_config); 166 void OnFlushCompleted(); 167 168 // Total number of frames to request. 169 int total_frames_; 170 171 // Number of demuxer read before issuing an early flush. 172 int early_flush_idx_; 173 bool use_post_task_for_flush_; 174 175 // Number of expected read frames. 176 int total_expected_frames_; 177 178 // Number of frames actually read so far. 179 int frame_received_count_; 180 181 // List of expected frame indices with decoder config changes. 182 std::list<int> config_idx_; 183 184 scoped_ptr<DummyDemuxerStream> demuxer_stream_; 185 186 scoped_ptr<CodedFrameProvider> coded_frame_provider_; 187 188 DISALLOW_COPY_AND_ASSIGN(DemuxerStreamAdapterTest); 189}; 190 191DemuxerStreamAdapterTest::DemuxerStreamAdapterTest() 192 : use_post_task_for_flush_(false) { 193} 194 195DemuxerStreamAdapterTest::~DemuxerStreamAdapterTest() { 196} 197 198void DemuxerStreamAdapterTest::Initialize( 199 ::media::DemuxerStream* demuxer_stream) { 200 coded_frame_provider_.reset( 201 new DemuxerStreamAdapter( 202 base::MessageLoopProxy::current(), 203 scoped_refptr<BalancedMediaTaskRunnerFactory>(), 204 demuxer_stream)); 205} 206 207void DemuxerStreamAdapterTest::Start() { 208 frame_received_count_ = 0; 209 210 // TODO(damienv): currently, test assertions which fail do not trigger the 211 // exit of the unit test, the message loop is still running. Find a different 212 // way to exit the unit test. 213 base::MessageLoop::current()->PostDelayedTask( 214 FROM_HERE, 215 base::Bind(&DemuxerStreamAdapterTest::OnTestTimeout, 216 base::Unretained(this)), 217 base::TimeDelta::FromSeconds(5)); 218 219 coded_frame_provider_->Read( 220 base::Bind(&DemuxerStreamAdapterTest::OnNewFrame, 221 base::Unretained(this))); 222} 223 224void DemuxerStreamAdapterTest::OnTestTimeout() { 225 ADD_FAILURE() << "Test timed out"; 226 if (base::MessageLoop::current()) 227 base::MessageLoop::current()->QuitWhenIdle(); 228} 229 230void DemuxerStreamAdapterTest::OnNewFrame( 231 const scoped_refptr<DecoderBufferBase>& buffer, 232 const ::media::AudioDecoderConfig& audio_config, 233 const ::media::VideoDecoderConfig& video_config) { 234 if (video_config.IsValidConfig()) { 235 ASSERT_GT(config_idx_.size(), 0); 236 ASSERT_EQ(frame_received_count_, config_idx_.front()); 237 config_idx_.pop_front(); 238 } 239 240 ASSERT_TRUE(buffer.get() != NULL); 241 ASSERT_EQ(buffer->timestamp(), 242 frame_received_count_ * base::TimeDelta::FromMilliseconds(40)); 243 frame_received_count_++; 244 245 if (frame_received_count_ >= total_frames_) { 246 coded_frame_provider_->Flush( 247 base::Bind(&DemuxerStreamAdapterTest::OnFlushCompleted, 248 base::Unretained(this))); 249 return; 250 } 251 252 coded_frame_provider_->Read( 253 base::Bind(&DemuxerStreamAdapterTest::OnNewFrame, 254 base::Unretained(this))); 255 256 ASSERT_LE(frame_received_count_, early_flush_idx_); 257 if (frame_received_count_ == early_flush_idx_) { 258 base::Closure flush_cb = 259 base::Bind(&DemuxerStreamAdapterTest::OnFlushCompleted, 260 base::Unretained(this)); 261 if (use_post_task_for_flush_) { 262 base::MessageLoop::current()->PostTask( 263 FROM_HERE, 264 base::Bind(&CodedFrameProvider::Flush, 265 base::Unretained(coded_frame_provider_.get()), 266 flush_cb)); 267 } else { 268 coded_frame_provider_->Flush(flush_cb); 269 } 270 return; 271 } 272} 273 274void DemuxerStreamAdapterTest::OnFlushCompleted() { 275 ASSERT_EQ(frame_received_count_, total_expected_frames_); 276 ASSERT_FALSE(demuxer_stream_->has_pending_read()); 277 base::MessageLoop::current()->QuitWhenIdle(); 278} 279 280TEST_F(DemuxerStreamAdapterTest, NoDelay) { 281 total_frames_ = 10; 282 early_flush_idx_ = total_frames_; // No early flush. 283 total_expected_frames_ = 10; 284 config_idx_.push_back(0); 285 config_idx_.push_back(5); 286 287 int cycle_count = 1; 288 int delayed_frame_count = 0; 289 demuxer_stream_.reset( 290 new DummyDemuxerStream( 291 cycle_count, delayed_frame_count, config_idx_)); 292 293 scoped_ptr<base::MessageLoop> message_loop(new base::MessageLoop()); 294 Initialize(demuxer_stream_.get()); 295 message_loop->PostTask( 296 FROM_HERE, 297 base::Bind(&DemuxerStreamAdapterTest::Start, base::Unretained(this))); 298 message_loop->Run(); 299} 300 301TEST_F(DemuxerStreamAdapterTest, AllDelayed) { 302 total_frames_ = 10; 303 early_flush_idx_ = total_frames_; // No early flush. 304 total_expected_frames_ = 10; 305 config_idx_.push_back(0); 306 config_idx_.push_back(5); 307 308 int cycle_count = 1; 309 int delayed_frame_count = 1; 310 demuxer_stream_.reset( 311 new DummyDemuxerStream( 312 cycle_count, delayed_frame_count, config_idx_)); 313 314 scoped_ptr<base::MessageLoop> message_loop(new base::MessageLoop()); 315 Initialize(demuxer_stream_.get()); 316 message_loop->PostTask( 317 FROM_HERE, 318 base::Bind(&DemuxerStreamAdapterTest::Start, base::Unretained(this))); 319 message_loop->Run(); 320} 321 322TEST_F(DemuxerStreamAdapterTest, AllDelayedEarlyFlush) { 323 total_frames_ = 10; 324 early_flush_idx_ = 5; 325 use_post_task_for_flush_ = true; 326 total_expected_frames_ = 5; 327 config_idx_.push_back(0); 328 config_idx_.push_back(3); 329 330 int cycle_count = 1; 331 int delayed_frame_count = 1; 332 demuxer_stream_.reset( 333 new DummyDemuxerStream( 334 cycle_count, delayed_frame_count, config_idx_)); 335 336 scoped_ptr<base::MessageLoop> message_loop(new base::MessageLoop()); 337 Initialize(demuxer_stream_.get()); 338 message_loop->PostTask( 339 FROM_HERE, 340 base::Bind(&DemuxerStreamAdapterTest::Start, base::Unretained(this))); 341 message_loop->Run(); 342} 343 344} // namespace media 345} // namespace chromecast 346