1 // Copyright (c) 2013 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 "media/filters/fake_demuxer_stream.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/message_loop/message_loop.h" 12 #include "media/base/bind_to_loop.h" 13 #include "media/base/decoder_buffer.h" 14 #include "media/base/test_helpers.h" 15 #include "media/base/video_frame.h" 16 #include "ui/gfx/rect.h" 17 #include "ui/gfx/size.h" 18 19 namespace media { 20 21 static const int kStartTimestampMs = 0; 22 static const int kDurationMs = 30; 23 static const int kStartWidth = 320; 24 static const int kStartHeight = 240; 25 static const int kWidthDelta = 4; 26 static const int kHeightDelta = 3; 27 28 FakeDemuxerStream::FakeDemuxerStream(int num_configs, 29 int num_buffers_in_one_config, 30 bool is_encrypted) 31 : message_loop_(base::MessageLoopProxy::current()), 32 num_configs_left_(num_configs), 33 num_buffers_in_one_config_(num_buffers_in_one_config), 34 is_encrypted_(is_encrypted), 35 num_buffers_left_in_current_config_(num_buffers_in_one_config), 36 num_buffers_returned_(0), 37 current_timestamp_(base::TimeDelta::FromMilliseconds(kStartTimestampMs)), 38 duration_(base::TimeDelta::FromMilliseconds(kDurationMs)), 39 next_coded_size_(kStartWidth, kStartHeight), 40 next_read_num_(0), 41 read_to_hold_(-1) { 42 DCHECK_GT(num_configs_left_, 0); 43 DCHECK_GT(num_buffers_in_one_config_, 0); 44 UpdateVideoDecoderConfig(); 45 } 46 47 FakeDemuxerStream::~FakeDemuxerStream() {} 48 49 void FakeDemuxerStream::Read(const ReadCB& read_cb) { 50 DCHECK(message_loop_->BelongsToCurrentThread()); 51 DCHECK(read_cb_.is_null()); 52 53 read_cb_ = BindToCurrentLoop(read_cb); 54 55 if (read_to_hold_ == next_read_num_) 56 return; 57 58 DCHECK(read_to_hold_ == -1 || read_to_hold_ > next_read_num_); 59 DoRead(); 60 } 61 62 AudioDecoderConfig FakeDemuxerStream::audio_decoder_config() { 63 DCHECK(message_loop_->BelongsToCurrentThread()); 64 NOTREACHED(); 65 return AudioDecoderConfig(); 66 } 67 68 VideoDecoderConfig FakeDemuxerStream::video_decoder_config() { 69 DCHECK(message_loop_->BelongsToCurrentThread()); 70 return video_decoder_config_; 71 } 72 73 // TODO(xhwang): Support audio if needed. 74 DemuxerStream::Type FakeDemuxerStream::type() { 75 DCHECK(message_loop_->BelongsToCurrentThread()); 76 return VIDEO; 77 } 78 79 void FakeDemuxerStream::EnableBitstreamConverter() { 80 DCHECK(message_loop_->BelongsToCurrentThread()); 81 } 82 83 void FakeDemuxerStream::HoldNextRead() { 84 DCHECK(message_loop_->BelongsToCurrentThread()); 85 read_to_hold_ = next_read_num_; 86 } 87 88 void FakeDemuxerStream::HoldNextConfigChangeRead() { 89 DCHECK(message_loop_->BelongsToCurrentThread()); 90 // Set |read_to_hold_| to be the next config change read. 91 read_to_hold_ = next_read_num_ + num_buffers_in_one_config_ - 92 next_read_num_ % (num_buffers_in_one_config_ + 1); 93 } 94 95 void FakeDemuxerStream::SatisfyRead() { 96 DCHECK(message_loop_->BelongsToCurrentThread()); 97 DCHECK_EQ(read_to_hold_, next_read_num_); 98 DCHECK(!read_cb_.is_null()); 99 100 read_to_hold_ = -1; 101 DoRead(); 102 } 103 104 void FakeDemuxerStream::Reset() { 105 read_to_hold_ = -1; 106 107 if (!read_cb_.is_null()) 108 base::ResetAndReturn(&read_cb_).Run(kAborted, NULL); 109 } 110 111 void FakeDemuxerStream::UpdateVideoDecoderConfig() { 112 const gfx::Rect kVisibleRect(kStartWidth, kStartHeight); 113 video_decoder_config_.Initialize( 114 kCodecVP8, VIDEO_CODEC_PROFILE_UNKNOWN, VideoFrame::YV12, 115 next_coded_size_, kVisibleRect, next_coded_size_, 116 NULL, 0, is_encrypted_, false); 117 next_coded_size_.Enlarge(kWidthDelta, kHeightDelta); 118 } 119 120 void FakeDemuxerStream::DoRead() { 121 DCHECK(message_loop_->BelongsToCurrentThread()); 122 DCHECK(!read_cb_.is_null()); 123 124 next_read_num_++; 125 126 if (num_buffers_left_in_current_config_ == 0) { 127 // End of stream. 128 if (num_configs_left_ == 0) { 129 base::ResetAndReturn(&read_cb_).Run(kOk, 130 DecoderBuffer::CreateEOSBuffer()); 131 return; 132 } 133 134 // Config change. 135 num_buffers_left_in_current_config_ = num_buffers_in_one_config_; 136 UpdateVideoDecoderConfig(); 137 base::ResetAndReturn(&read_cb_).Run(kConfigChanged, NULL); 138 return; 139 } 140 141 scoped_refptr<DecoderBuffer> buffer = CreateFakeVideoBufferForTest( 142 video_decoder_config_, current_timestamp_, duration_); 143 144 // TODO(xhwang): Output out-of-order buffers if needed. 145 buffer->set_timestamp(current_timestamp_); 146 buffer->set_duration(duration_); 147 current_timestamp_ += duration_; 148 149 num_buffers_left_in_current_config_--; 150 if (num_buffers_left_in_current_config_ == 0) 151 num_configs_left_--; 152 153 num_buffers_returned_++; 154 base::ResetAndReturn(&read_cb_).Run(kOk, buffer); 155 } 156 157 } // namespace media 158