blob: fec4d091e8769438a47bc9840aa8c38ab141a140 [file] [log] [blame]
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "content/renderer/media/rtc_video_capturer.h"
#include "base/bind.h"
#include "base/debug/trace_event.h"
namespace content {
RtcVideoCapturer::RtcVideoCapturer(const media::VideoCaptureSessionId id,
VideoCaptureImplManager* vc_manager,
bool is_screencast)
: is_screencast_(is_screencast),
delegate_(new RtcVideoCaptureDelegate(id, vc_manager)),
state_(VIDEO_CAPTURE_STATE_STOPPED) {}
RtcVideoCapturer::~RtcVideoCapturer() {
DCHECK(VIDEO_CAPTURE_STATE_STOPPED);
DVLOG(3) << " RtcVideoCapturer::dtor";
}
cricket::CaptureState RtcVideoCapturer::Start(
const cricket::VideoFormat& capture_format) {
DVLOG(3) << " RtcVideoCapturer::Start ";
if (state_ == VIDEO_CAPTURE_STATE_STARTED) {
DVLOG(1) << "Got a StartCapture when already started!!! ";
return cricket::CS_FAILED;
}
media::VideoCaptureCapability cap;
cap.width = capture_format.width;
cap.height = capture_format.height;
cap.frame_rate = capture_format.framerate();
cap.color = media::PIXEL_FORMAT_I420;
SetCaptureFormat(&capture_format);
state_ = VIDEO_CAPTURE_STATE_STARTED;
first_frame_timestamp_ = media::kNoTimestamp();
delegate_->StartCapture(
cap,
base::Bind(&RtcVideoCapturer::OnFrameCaptured, base::Unretained(this)),
base::Bind(&RtcVideoCapturer::OnStateChange, base::Unretained(this)));
// Update the desired aspect ratio so that later the video frame can be
// cropped to meet the requirement if the camera returns a different
// resolution than the |cap|.
UpdateAspectRatio(cap.width, cap.height);
return cricket::CS_STARTING;
}
void RtcVideoCapturer::Stop() {
DVLOG(3) << " RtcVideoCapturer::Stop ";
if (state_ == VIDEO_CAPTURE_STATE_STOPPED) {
DVLOG(1) << "Got a StopCapture while not started.";
return;
}
SetCaptureFormat(NULL);
state_ = VIDEO_CAPTURE_STATE_STOPPED;
delegate_->StopCapture();
SignalStateChange(this, cricket::CS_STOPPED);
}
bool RtcVideoCapturer::IsRunning() {
return state_ == VIDEO_CAPTURE_STATE_STARTED;
}
bool RtcVideoCapturer::GetPreferredFourccs(std::vector<uint32>* fourccs) {
if (!fourccs)
return false;
fourccs->push_back(cricket::FOURCC_I420);
return true;
}
bool RtcVideoCapturer::IsScreencast() const {
return is_screencast_;
}
bool RtcVideoCapturer::GetBestCaptureFormat(const cricket::VideoFormat& desired,
cricket::VideoFormat* best_format) {
if (!best_format) {
return false;
}
// Chrome does not support capability enumeration.
// Use the desired format as the best format.
best_format->width = desired.width;
best_format->height = desired.height;
best_format->fourcc = cricket::FOURCC_I420;
best_format->interval = desired.interval;
return true;
}
void RtcVideoCapturer::OnFrameCaptured(
const scoped_refptr<media::VideoFrame>& frame) {
if (first_frame_timestamp_ == media::kNoTimestamp())
first_frame_timestamp_ = frame->GetTimestamp();
// Currently, |fourcc| is always I420.
cricket::CapturedFrame captured_frame;
captured_frame.width = frame->coded_size().width();
captured_frame.height = frame->coded_size().height();
captured_frame.fourcc = cricket::FOURCC_I420;
// cricket::CapturedFrame time is in nanoseconds.
captured_frame.elapsed_time =
(frame->GetTimestamp() - first_frame_timestamp_).InMicroseconds() *
base::Time::kNanosecondsPerMicrosecond;
captured_frame.time_stamp = frame->GetTimestamp().InMicroseconds() *
base::Time::kNanosecondsPerMicrosecond;
// TODO(sheu): we assume contiguous layout of image planes.
captured_frame.data = frame->data(0);
captured_frame.data_size =
media::VideoFrame::AllocationSize(frame->format(), frame->coded_size());
captured_frame.pixel_height = 1;
captured_frame.pixel_width = 1;
TRACE_EVENT_INSTANT2(
"rtc_video_capturer",
"OnFrameCaptured",
TRACE_EVENT_SCOPE_THREAD,
"elapsed time",
captured_frame.elapsed_time,
"timestamp_ms",
captured_frame.time_stamp / talk_base::kNumNanosecsPerMillisec);
// This signals to libJingle that a new VideoFrame is available.
// libJingle have no assumptions on what thread this signal come from.
SignalFrameCaptured(this, &captured_frame);
}
void RtcVideoCapturer::OnStateChange(
RtcVideoCaptureDelegate::CaptureState state) {
cricket::CaptureState converted_state = cricket::CS_FAILED;
DVLOG(3) << " RtcVideoCapturer::OnStateChange " << state;
switch (state) {
case RtcVideoCaptureDelegate::CAPTURE_STOPPED:
converted_state = cricket::CS_STOPPED;
break;
case RtcVideoCaptureDelegate::CAPTURE_RUNNING:
converted_state = cricket::CS_RUNNING;
break;
case RtcVideoCaptureDelegate::CAPTURE_FAILED:
// TODO(perkj): Update the comments in the the definition of
// cricket::CS_FAILED. According to the comments, cricket::CS_FAILED
// means that the capturer failed to start. But here and in libjingle it
// is also used if an error occur during capturing.
converted_state = cricket::CS_FAILED;
break;
default:
NOTREACHED();
break;
}
SignalStateChange(this, converted_state);
}
} // namespace content