Commit message: None
CVE: None
Vulnerability description: None

Project: Chrome

ACTION(DeleteDataBuffer) {
  delete[] arg0->memory_pointer;
}

Project: Chrome

ACTION_P2(CaptureStopped, decoder, vc_impl) {
  decoder->OnStopped(vc_impl);
}

Project: Chrome

ACTION_P3(CreateDataBufferFromCapture, decoder, vc_impl, data_buffer_number) {
  for (int i = 0; i < data_buffer_number; i++) {
    media::VideoCapture::VideoFrameBuffer* buffer;
    buffer = new media::VideoCapture::VideoFrameBuffer();
    buffer->width = arg1.width;
    buffer->height = arg1.height;
    int length = buffer->width * buffer->height * 3 / 2;
    buffer->memory_pointer = new uint8[length];
    buffer->buffer_size = length;
    decoder->OnBufferReady(vc_impl, buffer);
  }
}

Project: Chrome

  CaptureVideoDecoderTest() {
    message_loop_.reset(new MessageLoop(MessageLoop::TYPE_IO));
    message_loop_proxy_ =
        base::MessageLoopProxy::current().get();
    vc_manager_ = new MockVideoCaptureImplManager();
    media::VideoCaptureCapability capability;
    capability.width = kWidth;
    capability.height = kHeight;
    capability.frame_rate = kFPS;
    capability.expected_capture_delay = 0;
    capability.color = media::VideoCaptureCapability::kI420;
    capability.interlaced = false;

    decoder_ = new CaptureVideoDecoder(message_loop_proxy_,
                                       kVideoStreamId, vc_manager_, capability);
    EXPECT_CALL(statistics_cb_object_, OnStatistics(_))
        .Times(AnyNumber());

    read_cb_ = base::Bind(&CaptureVideoDecoderTest::FrameReady,
                          base::Unretained(this));

    vc_impl_.reset(new MockVideoCaptureImpl(
        kVideoStreamId, message_loop_proxy_, new VideoCaptureMessageFilter()));
  }

Project: Chrome

  void Initialize() {
    EXPECT_CALL(*this, FrameReady(media::VideoDecoder::kOk, _));
    decoder_->Read(read_cb_);

    EXPECT_CALL(*vc_manager_, AddDevice(_, _))
        .WillOnce(Return(vc_impl_.get()));
    int buffer_count = 1;
    EXPECT_CALL(*vc_impl_, StartCapture(capture_client(), _))
        .Times(1)
        .WillOnce(CreateDataBufferFromCapture(capture_client(),
                                              vc_impl_.get(),
                                              buffer_count));
    EXPECT_CALL(*vc_impl_, FeedBuffer(_))
        .Times(buffer_count)
        .WillRepeatedly(DeleteDataBuffer());

    decoder_->Initialize(NULL,
                         media::NewExpectedStatusCB(media::PIPELINE_OK),
                         NewStatisticsCB());
    message_loop_->RunAllPending();
  }

Project: Chrome

  MockVideoCaptureImpl(const media::VideoCaptureSessionId id,
                       scoped_refptr<base::MessageLoopProxy> ml_proxy,
                       VideoCaptureMessageFilter* filter)
      : VideoCaptureImpl(id, ml_proxy, filter) {
  }

Project: Chrome

  media::StatisticsCB NewStatisticsCB() {
    return base::Bind(&media::MockStatisticsCB::OnStatistics,
                      base::Unretained(&statistics_cb_object_));
  }

Project: Chrome

  void Stop() {
    EXPECT_CALL(*vc_impl_, StopCapture(capture_client()))
        .Times(1)
        .WillOnce(CaptureStopped(capture_client(), vc_impl_.get()));
    EXPECT_CALL(*vc_manager_, RemoveDevice(_, _))
        .WillOnce(Return());
    decoder_->Stop(media::NewExpectedClosure());
    message_loop_->RunAllPending();
  }

Project: Chrome

  media::VideoCapture::EventHandler* capture_client() {
    return static_cast<media::VideoCapture::EventHandler*>(decoder_);
   }

Project: Chrome

  virtual ~MockVideoCaptureImplManager() {}

Project: Chrome

  void InitializeDecoderSuccessfully() {
    decoder_->Initialize(
        NULL, NewExpectedStatusCB(PIPELINE_OK), NewStatisticsCB());
    message_loop_.RunAllPending();
  }

Project: Chrome

  StatisticsCB NewStatisticsCB() {
    return base::Bind(&MockStatisticsCB::OnStatistics,
                      base::Unretained(&statistics_cb_));
   }

Project: Chrome

  NullVideoFrame() {}

Project: Chrome

  RTCVideoDecoderTest() {
    decoder_ = new RTCVideoDecoder(&message_loop_, kUrl);
    renderer_ = new MockVideoRenderer();
    read_cb_ = base::Bind(&RTCVideoDecoderTest::FrameReady,
                          base::Unretained(this));

    DCHECK(decoder_);

    EXPECT_CALL(statistics_cb_, OnStatistics(_))
        .Times(AnyNumber());
  }

Project: Chrome

  virtual ~RTCVideoDecoderTest() {
    message_loop_.RunAllPending();
  }

Project: Chrome

ACTION_P(ReturnBuffer, buffer) {
  arg0.Run(buffer);
}

Project: Chrome

  void DecodeIFrameThenTestFile(const std::string& test_file_name,
                                size_t expected_width,
                                size_t expected_height) {
    Initialize();

    VideoDecoder::DecoderStatus status_a;
    VideoDecoder::DecoderStatus status_b;
    scoped_refptr<VideoFrame> video_frame_a;
    scoped_refptr<VideoFrame> video_frame_b;

    scoped_refptr<DecoderBuffer> buffer = ReadTestDataFile(test_file_name);

    EXPECT_CALL(*demuxer_, Read(_))
        .WillOnce(ReturnBuffer(i_frame_buffer_))
        .WillOnce(ReturnBuffer(buffer))
        .WillRepeatedly(ReturnBuffer(end_of_stream_buffer_));

    EXPECT_CALL(statistics_cb_, OnStatistics(_))
        .Times(2);

    Read(&status_a, &video_frame_a);
    Read(&status_b, &video_frame_b);

    size_t original_width = static_cast<size_t>(kVisibleRect.width());
    size_t original_height = static_cast<size_t>(kVisibleRect.height());

    EXPECT_EQ(status_a, VideoDecoder::kOk);
    EXPECT_EQ(status_b, VideoDecoder::kOk);
    ASSERT_TRUE(video_frame_a);
    ASSERT_TRUE(video_frame_b);
    EXPECT_EQ(original_width, video_frame_a->width());
    EXPECT_EQ(original_height, video_frame_a->height());
    EXPECT_EQ(expected_width, video_frame_b->width());
    EXPECT_EQ(expected_height, video_frame_b->height());
  }

Project: Chrome

  void DecodeSingleFrame(const scoped_refptr<DecoderBuffer>& buffer,
                         VideoDecoder::DecoderStatus* status,
                         scoped_refptr<VideoFrame>* video_frame) {
    EXPECT_CALL(*demuxer_, Read(_))
        .WillOnce(ReturnBuffer(buffer))
        .WillRepeatedly(ReturnBuffer(end_of_stream_buffer_));

    EXPECT_CALL(statistics_cb_, OnStatistics(_));

    Read(status, video_frame);
  }

Project: Chrome

  void EnterDecodingState() {
    VideoDecoder::DecoderStatus status;
    scoped_refptr<VideoFrame> video_frame;
    DecodeSingleFrame(i_frame_buffer_, &status, &video_frame);

    EXPECT_EQ(status, VideoDecoder::kOk);
    ASSERT_TRUE(video_frame);
    EXPECT_FALSE(video_frame->IsEndOfStream());
  }

Project: Chrome

  void EnterEndOfStreamState() {
    scoped_refptr<VideoFrame> video_frame;
    VideoDecoder::DecoderStatus status;
    Read(&status, &video_frame);
    EXPECT_EQ(status, VideoDecoder::kOk);
    ASSERT_TRUE(video_frame);
    EXPECT_TRUE(video_frame->IsEndOfStream());
  }

Project: Chrome

  FFmpegVideoDecoderTest()
      : decryptor_(new AesDecryptor(&decryptor_client_)),
        decoder_(new FFmpegVideoDecoder(base::Bind(&Identity<MessageLoop*>,
                                                   &message_loop_))),
        demuxer_(new StrictMock<MockDemuxerStream>()),
        read_cb_(base::Bind(&FFmpegVideoDecoderTest::FrameReady,
                            base::Unretained(this))) {
    CHECK(FFmpegGlue::GetInstance());

    decoder_->set_decryptor(decryptor_.get());

    frame_buffer_.reset(new uint8[kCodedSize.GetArea()]);
    end_of_stream_buffer_ = DecoderBuffer::CreateEOSBuffer();
    i_frame_buffer_ = ReadTestDataFile("vp8-I-frame-320x240");
    corrupt_i_frame_buffer_ = ReadTestDataFile("vp8-corrupt-I-frame");
    encrypted_i_frame_buffer_ = ReadTestDataFile(
        "vp8-encrypted-I-frame-320x240");

    config_.Initialize(kCodecVP8, VIDEO_CODEC_PROFILE_UNKNOWN,
                       kVideoFormat, kCodedSize, kVisibleRect,
                       kFrameRate.num, kFrameRate.den,
                       kAspectRatio.num, kAspectRatio.den,
                       NULL, 0, true);
  }

Project: Chrome

  void Initialize() {
    InitializeWithConfig(config_);
  }

Project: Chrome

  void InitializeWithConfigAndStatus(const VideoDecoderConfig& config,
                                     PipelineStatus status) {
    EXPECT_CALL(*demuxer_, video_decoder_config())
        .WillOnce(ReturnRef(config));

    decoder_->Initialize(demuxer_, NewExpectedStatusCB(status),
                         base::Bind(&MockStatisticsCB::OnStatistics,
                                    base::Unretained(&statistics_cb_)));

    message_loop_.RunAllPending();
  }

Project: Chrome

  void Read(VideoDecoder::DecoderStatus* status,
            scoped_refptr<VideoFrame>* video_frame) {
    EXPECT_CALL(*this, FrameReady(_, _))
        .WillOnce(DoAll(SaveArg<0>(status), SaveArg<1>(video_frame)));

    decoder_->Read(read_cb_);

    message_loop_.RunAllPending();
   }

Project: Chrome

  void Reset() {
    decoder_->Reset(NewExpectedClosure());
    message_loop_.RunAllPending();
  }

Project: Chrome

  void Stop() {
    decoder_->Stop(NewExpectedClosure());
    message_loop_.RunAllPending();
  }

Project: Chrome

  virtual ~FFmpegVideoDecoderTest() {}

Project: Chrome

void VideoRendererBase::AttemptFlush_Locked() {
  lock_.AssertAcquired();
  DCHECK_EQ(kFlushing, state_);

  ready_frames_.clear();

  if (!pending_paint_ && !pending_read_) {
    state_ = kFlushed;
    current_frame_ = NULL;
    base::ResetAndReturn(&flush_cb_).Run();
  }
}

Project: Chrome

void VideoRendererBase::AttemptRead_Locked() {
  lock_.AssertAcquired();
  DCHECK_NE(kEnded, state_);

  if (pending_read_ ||
      NumFrames_Locked() == limits::kMaxVideoFrames ||
      (!ready_frames_.empty() && ready_frames_.back()->IsEndOfStream()) ||
      state_ == kFlushingDecoder ||
      state_ == kFlushing) {
    return;
  }

  pending_read_ = true;
  decoder_->Read(base::Bind(&VideoRendererBase::FrameReady, this));
}

Project: Chrome

base::TimeDelta VideoRendererBase::CalculateSleepDuration(
    const scoped_refptr<VideoFrame>& next_frame,
    float playback_rate) {
  base::TimeDelta now = host()->GetTime();
  base::TimeDelta this_pts = current_frame_->GetTimestamp();
  base::TimeDelta next_pts;
  if (!next_frame->IsEndOfStream()) {
    next_pts = next_frame->GetTimestamp();
  } else {
    next_pts = this_pts + current_frame_->GetDuration();
  }

  base::TimeDelta sleep = next_pts - now;
  return base::TimeDelta::FromMicroseconds(
      static_cast<int64>(sleep.InMicroseconds() / playback_rate));
}

Project: Chrome

void VideoRendererBase::Flush(const base::Closure& callback) {
  base::AutoLock auto_lock(lock_);
  DCHECK_EQ(state_, kPaused);
  flush_cb_ = callback;
  state_ = kFlushingDecoder;

  base::AutoUnlock auto_unlock(lock_);
  decoder_->Reset(base::Bind(&VideoRendererBase::OnDecoderFlushDone, this));
}

Project: Chrome

bool VideoRendererBase::HasEnded() {
  base::AutoLock auto_lock(lock_);
  return state_ == kEnded;
}

Project: Chrome

void VideoRendererBase::Initialize(const scoped_refptr<VideoDecoder>& decoder,
                                   const PipelineStatusCB& status_cb,
                                   const StatisticsCB& statistics_cb,
                                   const TimeCB& time_cb) {
  base::AutoLock auto_lock(lock_);
  DCHECK(decoder);
  DCHECK(!status_cb.is_null());
  DCHECK(!statistics_cb.is_null());
  DCHECK(!time_cb.is_null());
  DCHECK_EQ(kUninitialized, state_);
  decoder_ = decoder;

  statistics_cb_ = statistics_cb;
  time_cb_ = time_cb;

  host()->SetNaturalVideoSize(decoder_->natural_size());

  state_ = kFlushed;

  set_opaque_cb_.Run(!decoder->HasAlpha());
  set_opaque_cb_.Reset();

  if (!base::PlatformThread::Create(0, this, &thread_)) {
    NOTREACHED() << "Video thread creation failed";
    state_ = kError;
    status_cb.Run(PIPELINE_ERROR_INITIALIZATION_FAILED);
    return;
  }

#if defined(OS_WIN)
  ::SetThreadPriority(thread_, THREAD_PRIORITY_ABOVE_NORMAL);
#endif  // defined(OS_WIN)
  status_cb.Run(PIPELINE_OK);
}

Project: Chrome

int VideoRendererBase::NumFrames_Locked() const {
  lock_.AssertAcquired();
  int outstanding_frames =
      (current_frame_ ? 1 : 0) + (last_available_frame_ ? 1 : 0) +
      (current_frame_ && (current_frame_ == last_available_frame_) ? -1 : 0);
  return ready_frames_.size() + outstanding_frames;
}

Project: Chrome

void VideoRendererBase::OnDecoderFlushDone() {
  base::AutoLock auto_lock(lock_);
  DCHECK_EQ(kFlushingDecoder, state_);
  DCHECK(!pending_read_);

  state_ = kFlushing;
  AttemptFlush_Locked();
}

Project: Chrome

void VideoRendererBase::Pause(const base::Closure& callback) {
  base::AutoLock auto_lock(lock_);
  DCHECK(state_ != kUninitialized || state_ == kError);
  state_ = kPaused;
  callback.Run();
}

Project: Chrome

void VideoRendererBase::Play(const base::Closure& callback) {
  base::AutoLock auto_lock(lock_);
  DCHECK_EQ(kPrerolled, state_);
  state_ = kPlaying;
  callback.Run();
}

Project: Chrome

void VideoRendererBase::PutCurrentFrame(scoped_refptr<VideoFrame> frame) {
  base::AutoLock auto_lock(lock_);

  if (pending_paint_) {
    DCHECK_EQ(current_frame_, frame);
    DCHECK(!pending_paint_with_last_available_);
    pending_paint_ = false;
  } else if (pending_paint_with_last_available_) {
    DCHECK_EQ(last_available_frame_, frame);
    DCHECK(!pending_paint_);
    pending_paint_with_last_available_ = false;
  } else {
    DCHECK(!frame);
  }

  frame_available_.Signal();
  if (state_ == kFlushingDecoder)
    return;

  if (state_ == kFlushing) {
    AttemptFlush_Locked();
    return;
  }

  if (state_ == kError || state_ == kStopped) {
    DoStopOrError_Locked();
  }
}

Project: Chrome

void VideoRendererBase::SetPlaybackRate(float playback_rate) {
  base::AutoLock auto_lock(lock_);
  playback_rate_ = playback_rate;
}

Project: Chrome

void VideoRendererBase::Stop(const base::Closure& callback) {
  if (state_ == kStopped) {
    callback.Run();
    return;
  }

  base::PlatformThreadHandle thread_to_join = base::kNullThreadHandle;
  {
    base::AutoLock auto_lock(lock_);
    state_ = kStopped;

    statistics_cb_.Reset();
    time_cb_.Reset();
    if (!pending_paint_ && !pending_paint_with_last_available_)
      DoStopOrError_Locked();

    if (thread_ != base::kNullThreadHandle) {
      frame_available_.Signal();
      thread_to_join = thread_;
      thread_ = base::kNullThreadHandle;
    }
  }
  if (thread_to_join != base::kNullThreadHandle)
    base::PlatformThread::Join(thread_to_join);

  decoder_->Stop(callback);
}

Project: Chrome

void VideoRendererBase::ThreadMain() {
  base::PlatformThread::SetName("CrVideoRenderer");

  const base::TimeDelta kIdleTimeDelta =
      base::TimeDelta::FromMilliseconds(10);

  uint32 frames_dropped = 0;

  for (;;) {
    if (frames_dropped > 0) {
      PipelineStatistics statistics;
      statistics.video_frames_dropped = frames_dropped;
      statistics_cb_.Run(statistics);

      frames_dropped = 0;
    }

    base::AutoLock auto_lock(lock_);

    if (state_ == kStopped)
      return;

    if (state_ != kPlaying || playback_rate_ == 0) {
      frame_available_.TimedWait(kIdleTimeDelta);
      continue;
    }

    if (ready_frames_.empty()) {
      frame_available_.TimedWait(kIdleTimeDelta);
      continue;
    }

    if (!current_frame_) {
      if (ready_frames_.front()->IsEndOfStream()) {
        state_ = kEnded;
        host()->NotifyEnded();
        ready_frames_.clear();

        continue;
      }

      frame_available_.TimedWait(kIdleTimeDelta);
      continue;
    }

    base::TimeDelta remaining_time =
        CalculateSleepDuration(ready_frames_.front(), playback_rate_);

    if (remaining_time.InMicroseconds() > 0) {
      remaining_time = std::min(remaining_time, kIdleTimeDelta);
      frame_available_.TimedWait(remaining_time);
      continue;
    }




    if (ready_frames_.front()->IsEndOfStream()) {
      state_ = kEnded;
      host()->NotifyEnded();
      ready_frames_.clear();

      continue;
    }

    if (pending_paint_) {
      while (!ready_frames_.empty()) {
        if (ready_frames_.front()->IsEndOfStream())
          break;

        base::TimeDelta remaining_time =
            ready_frames_.front()->GetTimestamp() - host()->GetTime();

        if (remaining_time.InMicroseconds() > 0)
          break;

        if (!drop_frames_)
          break;

        ++frames_dropped;
        ready_frames_.pop_front();
        AttemptRead_Locked();
      }
      frame_available_.TimedWait(kIdleTimeDelta);
      continue;
    }


    DCHECK(!pending_paint_);
    DCHECK(!ready_frames_.empty());
    current_frame_ = ready_frames_.front();
    ready_frames_.pop_front();
    AttemptRead_Locked();

    base::AutoUnlock auto_unlock(lock_);
    paint_cb_.Run();
  }
}

Project: Chrome

VideoRendererBase::VideoRendererBase(const base::Closure& paint_cb,
                                     const SetOpaqueCB& set_opaque_cb,
                                     bool drop_frames)
    : frame_available_(&lock_),
      state_(kUninitialized),
      thread_(base::kNullThreadHandle),
      pending_read_(false),
      pending_paint_(false),
      pending_paint_with_last_available_(false),
      drop_frames_(drop_frames),
      playback_rate_(0),
      paint_cb_(paint_cb),
      set_opaque_cb_(set_opaque_cb) {
  DCHECK(!paint_cb_.is_null());
}

Project: Chrome

VideoRendererBase::~VideoRendererBase() {
  base::AutoLock auto_lock(lock_);
  DCHECK(state_ == kUninitialized || state_ == kStopped) << state_;
 }