namespace media {
-base::TimeDelta VideoRendererImpl::kMaxLastFrameDuration() {
- return base::TimeDelta::FromMilliseconds(250);
-}
-
VideoRendererImpl::VideoRendererImpl(
const scoped_refptr<base::SingleThreadTaskRunner>& task_runner,
ScopedVector<VideoDecoder> decoders,
const SetDecryptorReadyCB& set_decryptor_ready_cb,
const PaintCB& paint_cb,
- const SetOpaqueCB& set_opaque_cb,
bool drop_frames)
: task_runner_(task_runner),
video_frame_stream_(task_runner, decoders.Pass(), set_decryptor_ready_cb),
+ low_delay_(false),
received_end_of_stream_(false),
+ rendered_end_of_stream_(false),
frame_available_(&lock_),
state_(kUninitialized),
thread_(),
drop_frames_(drop_frames),
playback_rate_(0),
paint_cb_(paint_cb),
- set_opaque_cb_(set_opaque_cb),
last_timestamp_(kNoTimestamp()),
frames_decoded_(0),
frames_dropped_(0),
// stream and needs to drain it before flushing it.
ready_frames_.clear();
received_end_of_stream_ = false;
+ rendered_end_of_stream_ = false;
video_frame_stream_.Reset(
base::Bind(&VideoRendererImpl::OnVideoFrameStreamResetDone,
weak_factory_.GetWeakPtr()));
}
void VideoRendererImpl::Initialize(DemuxerStream* stream,
+ bool low_delay,
const PipelineStatusCB& init_cb,
const StatisticsCB& statistics_cb,
const TimeCB& max_time_cb,
DCHECK(!get_duration_cb.is_null());
DCHECK_EQ(kUninitialized, state_);
+ low_delay_ = low_delay;
+
init_cb_ = init_cb;
statistics_cb_ = statistics_cb;
max_time_cb_ = max_time_cb;
video_frame_stream_.Initialize(
stream,
+ low_delay,
statistics_cb,
base::Bind(&VideoRendererImpl::OnVideoFrameStreamInitialized,
weak_factory_.GetWeakPtr()));
}
-void VideoRendererImpl::OnVideoFrameStreamInitialized(bool success,
- bool has_alpha) {
+void VideoRendererImpl::OnVideoFrameStreamInitialized(bool success) {
DCHECK(task_runner_->BelongsToCurrentThread());
base::AutoLock auto_lock(lock_);
// have not populated any buffers yet.
state_ = kFlushed;
- set_opaque_cb_.Run(!has_alpha);
- set_opaque_cb_.Reset();
-
// Create our video thread.
if (!base::PlatformThread::Create(0, this, &thread_)) {
NOTREACHED() << "Video thread creation failed";
// Remain idle until we have the next frame ready for rendering.
if (ready_frames_.empty()) {
- if (received_end_of_stream_) {
- state_ = kEnded;
+ if (received_end_of_stream_ && !rendered_end_of_stream_) {
+ rendered_end_of_stream_ = true;
ended_cb_.Run();
-
- // No need to sleep here as we idle when |state_ != kPlaying|.
- continue;
}
UpdateStatsAndWait_Locked(kIdleTimeDelta);
// the accuracy of our frame timing code. http://crbug.com/149829
if (drop_frames_ && last_timestamp_ != kNoTimestamp()) {
base::TimeDelta now = get_time_cb_.Run();
- base::TimeDelta deadline = ready_frames_.front()->GetTimestamp() +
- (ready_frames_.front()->GetTimestamp() - last_timestamp_) / 2;
+ base::TimeDelta deadline = ready_frames_.front()->timestamp() +
+ (ready_frames_.front()->timestamp() - last_timestamp_) / 2;
if (now > deadline) {
DropNextReadyFrame_Locked();
ready_frames_.pop_front();
frames_decoded_++;
- last_timestamp_ = next_frame->GetTimestamp();
+ last_timestamp_ = next_frame->timestamp();
paint_cb_.Run(next_frame);
lock_.AssertAcquired();
- last_timestamp_ = ready_frames_.front()->GetTimestamp();
+ last_timestamp_ = ready_frames_.front()->timestamp();
ready_frames_.pop_front();
frames_decoded_++;
frames_dropped_++;
// Maintain the latest frame decoded so the correct frame is displayed after
// prerolling has completed.
if (state_ == kPrerolling && preroll_timestamp_ != kNoTimestamp() &&
- frame->GetTimestamp() <= preroll_timestamp_) {
+ frame->timestamp() <= preroll_timestamp_) {
ready_frames_.clear();
}
bool VideoRendererImpl::ShouldTransitionToPrerolled_Locked() {
return state_ == kPrerolling &&
(!video_frame_stream_.CanReadWithoutStalling() ||
- ready_frames_.size() >= static_cast<size_t>(limits::kMaxVideoFrames));
+ ready_frames_.size() >= static_cast<size_t>(limits::kMaxVideoFrames) ||
+ (low_delay_ && ready_frames_.size() > 0));
}
void VideoRendererImpl::AddReadyFrame_Locked(
// frame rate. Another way for this to happen is for the container to state
// a smaller duration than the largest packet timestamp.
base::TimeDelta duration = get_duration_cb_.Run();
- if (frame->GetTimestamp() > duration) {
- frame->SetTimestamp(duration);
+ if (frame->timestamp() > duration) {
+ frame->set_timestamp(duration);
}
ready_frames_.push_back(frame);
DCHECK_LE(ready_frames_.size(),
static_cast<size_t>(limits::kMaxVideoFrames));
- max_time_cb_.Run(frame->GetTimestamp());
+ max_time_cb_.Run(frame->timestamp());
// Avoid needlessly waking up |thread_| unless playing.
if (state_ == kPlaying)
switch (state_) {
case kPaused:
case kPrerolling:
+ case kPrerolled:
case kPlaying:
pending_read_ = true;
video_frame_stream_.Read(base::Bind(&VideoRendererImpl::FrameReady,
case kUninitialized:
case kInitializing:
- case kPrerolled:
case kFlushing:
case kFlushed:
- case kEnded:
case kStopped:
case kError:
return;
DCHECK(!pending_read_);
DCHECK(ready_frames_.empty());
DCHECK(!received_end_of_stream_);
+ DCHECK(!rendered_end_of_stream_);
state_ = kFlushed;
last_timestamp_ = kNoTimestamp();
float playback_rate) {
// Determine the current and next presentation timestamps.
base::TimeDelta now = get_time_cb_.Run();
- base::TimeDelta next_pts = next_frame->GetTimestamp();
+ base::TimeDelta next_pts = next_frame->timestamp();
// Scale our sleep based on the playback rate.
base::TimeDelta sleep = next_pts - now;