| Index: media/video/capture/fake_video_capture_device.cc
|
| diff --git a/media/video/capture/fake_video_capture_device.cc b/media/video/capture/fake_video_capture_device.cc
|
| index 34f8f20d701d8b3e2accd3b433db342a2b5b8ebe..43fa6f9105d251c1c75fdbbbea98c7abd64d0778 100644
|
| --- a/media/video/capture/fake_video_capture_device.cc
|
| +++ b/media/video/capture/fake_video_capture_device.cc
|
| @@ -10,31 +10,41 @@
|
| #include "base/memory/scoped_ptr.h"
|
| #include "base/strings/stringprintf.h"
|
| #include "media/audio/fake_audio_input_stream.h"
|
| +#include "media/base/encoded_bitstream_buffer.h"
|
| #include "third_party/skia/include/core/SkBitmap.h"
|
| #include "third_party/skia/include/core/SkCanvas.h"
|
| #include "third_party/skia/include/core/SkPaint.h"
|
|
|
| namespace media {
|
|
|
| -static const int kFakeCaptureTimeoutMs = 50;
|
| -static const int kFakeCaptureBeepCycle = 20; // Visual beep every 1s.
|
| +namespace {
|
| +
|
| +const int kFakeCaptureTimeoutMs = 50;
|
| +const int kFakeCaptureBeepCycle = 20; // Visual beep every 1s.
|
| enum { kNumberOfFakeDevices = 2 };
|
|
|
| +} // anonymous namespace
|
| +
|
| bool FakeVideoCaptureDevice::fail_next_create_ = false;
|
|
|
| -void FakeVideoCaptureDevice::GetDeviceNames(Names* const device_names) {
|
| +void FakeVideoCaptureDevice::GetDeviceNames(Names* const device_names,
|
| + bool encoded_capture) {
|
| // Empty the name list.
|
| device_names->erase(device_names->begin(), device_names->end());
|
|
|
| for (int n = 0; n < kNumberOfFakeDevices; n++) {
|
| Name name;
|
| name.unique_id = base::StringPrintf("/dev/video%d", n);
|
| - name.device_name = base::StringPrintf("fake_device_%d", n);
|
| + name.device_name = base::StringPrintf(
|
| + "fake_%sdevice_%d",
|
| + (encoded_capture ? "encoded_" : ""),
|
| + n);
|
| device_names->push_back(name);
|
| }
|
| }
|
|
|
| -VideoCaptureDevice* FakeVideoCaptureDevice::Create(const Name& device_name) {
|
| +VideoCaptureDevice* FakeVideoCaptureDevice::Create(const Name& device_name,
|
| + bool encoded_capture) {
|
| if (fail_next_create_) {
|
| fail_next_create_ = false;
|
| return NULL;
|
| @@ -42,7 +52,7 @@ VideoCaptureDevice* FakeVideoCaptureDevice::Create(const Name& device_name) {
|
| for (int n = 0; n < kNumberOfFakeDevices; ++n) {
|
| std::string possible_id = base::StringPrintf("/dev/video%d", n);
|
| if (device_name.unique_id.compare(possible_id) == 0) {
|
| - return new FakeVideoCaptureDevice(device_name);
|
| + return new FakeVideoCaptureDevice(device_name, encoded_capture);
|
| }
|
| }
|
| return NULL;
|
| @@ -52,8 +62,10 @@ void FakeVideoCaptureDevice::SetFailNextCreate() {
|
| fail_next_create_ = true;
|
| }
|
|
|
| -FakeVideoCaptureDevice::FakeVideoCaptureDevice(const Name& device_name)
|
| +FakeVideoCaptureDevice::FakeVideoCaptureDevice(const Name& device_name,
|
| + bool encoded_capture)
|
| : device_name_(device_name),
|
| + encoded_capture_(encoded_capture),
|
| observer_(NULL),
|
| state_(kIdle),
|
| capture_thread_("CaptureThread"),
|
| @@ -69,39 +81,71 @@ FakeVideoCaptureDevice::~FakeVideoCaptureDevice() {
|
| DCHECK(!capture_thread_.IsRunning());
|
| }
|
|
|
| +VideoEncodingCapability FakeVideoCaptureDevice::GetEncodingCapability() {
|
| + media::VideoEncodingCapability capability;
|
| + if (encoded_capture_) {
|
| + media::VideoEncodingConfig config;
|
| + config.codec_type = kCodecVP8;
|
| + config.codec_name = "VP8";
|
| + config.max_resolution.SetSize(640, 480);
|
| + config.max_frames_per_second = 30;
|
| + config.max_bitrate = 1024 * 1024;
|
| + capability.push_back(config);
|
| + }
|
| + return capability;
|
| +}
|
| +
|
| +void FakeVideoCaptureDevice::TryConfigureEncodedBitstream(
|
| + const RuntimeVideoEncodingParameters& params) {
|
| + DCHECK(encoded_capture_);
|
| + DCHECK(observer_);
|
| + observer_->OnBitstreamConfigChanged(params);
|
| +}
|
| +
|
| void FakeVideoCaptureDevice::Allocate(int width,
|
| - int height,
|
| - int frame_rate,
|
| - EventHandler* observer) {
|
| + int height,
|
| + int frame_rate,
|
| + EventHandler* observer) {
|
| if (state_ != kIdle) {
|
| return; // Wrong state.
|
| }
|
|
|
| + DCHECK(!observer_);
|
| observer_ = observer;
|
| - VideoCaptureCapability current_settings;
|
| - current_settings.color = VideoCaptureCapability::kI420;
|
| - current_settings.expected_capture_delay = 0;
|
| - current_settings.interlaced = false;
|
| - if (width > 320) { // VGA
|
| - current_settings.width = 640;
|
| - current_settings.height = 480;
|
| - current_settings.frame_rate = 30;
|
| - } else { // QVGA
|
| - current_settings.width = 320;
|
| - current_settings.height = 240;
|
| - current_settings.frame_rate = 30;
|
| - }
|
| + state_ = kAllocated;
|
|
|
| - size_t fake_frame_size =
|
| - current_settings.width * current_settings.height * 3 / 2;
|
| - fake_frame_.reset(new uint8[fake_frame_size]);
|
| - memset(fake_frame_.get(), 0, fake_frame_size);
|
| - frame_size_ = fake_frame_size;
|
| - frame_width_ = current_settings.width;
|
| - frame_height_ = current_settings.height;
|
| + if (encoded_capture_) {
|
| + media::VideoEncodingParameters params;
|
| + params.codec_name = std::string("VP8");
|
| + params.resolution.SetSize(640, 480);
|
| + params.frames_per_second = 30;
|
| + params.runtime_params.average_bitrate = 0;
|
| + params.runtime_params.max_bitrate = 1024;
|
| + observer_->OnEncodedFrameInfo(params);
|
| + } else {
|
| + VideoCaptureCapability current_settings;
|
| + current_settings.color = VideoCaptureCapability::kI420;
|
| + current_settings.expected_capture_delay = 0;
|
| + current_settings.interlaced = false;
|
| + if (width > 320) { // VGA
|
| + current_settings.width = 640;
|
| + current_settings.height = 480;
|
| + current_settings.frame_rate = 30;
|
| + } else { // QVGA
|
| + current_settings.width = 320;
|
| + current_settings.height = 240;
|
| + current_settings.frame_rate = 30;
|
| + }
|
|
|
| - state_ = kAllocated;
|
| - observer_->OnFrameInfo(current_settings);
|
| + size_t fake_frame_size =
|
| + current_settings.width * current_settings.height * 3 / 2;
|
| + fake_frame_.reset(new uint8[fake_frame_size]);
|
| + memset(fake_frame_.get(), 0, fake_frame_size);
|
| + frame_size_ = fake_frame_size;
|
| + frame_width_ = current_settings.width;
|
| + frame_height_ = current_settings.height;
|
| + observer_->OnFrameInfo(current_settings);
|
| + }
|
| }
|
|
|
| void FakeVideoCaptureDevice::Start() {
|
| @@ -130,6 +174,7 @@ void FakeVideoCaptureDevice::DeAllocate() {
|
| }
|
| capture_thread_.Stop();
|
| state_ = kIdle;
|
| + observer_ = NULL;
|
| }
|
|
|
| const VideoCaptureDevice::Name& FakeVideoCaptureDevice::device_name() {
|
| @@ -143,57 +188,70 @@ void FakeVideoCaptureDevice::OnCaptureTask() {
|
|
|
| memset(fake_frame_.get(), 0, frame_size_);
|
|
|
| - SkBitmap bitmap;
|
| - bitmap.setConfig(SkBitmap::kA8_Config, frame_width_, frame_height_,
|
| - frame_width_);
|
| - bitmap.setPixels(fake_frame_.get());
|
| -
|
| - SkCanvas canvas(bitmap);
|
| -
|
| - // Draw a sweeping circle to show an animation.
|
| - int radius = std::min(frame_width_, frame_height_) / 4;
|
| - SkRect rect = SkRect::MakeXYWH(
|
| - frame_width_ / 2 - radius, frame_height_ / 2 - radius,
|
| - 2 * radius, 2 * radius);
|
| -
|
| - SkPaint paint;
|
| - paint.setStyle(SkPaint::kFill_Style);
|
| -
|
| - // Only Y plane is being drawn and this gives 50% grey on the Y
|
| - // plane. The result is a light green color in RGB space.
|
| - paint.setAlpha(128);
|
| -
|
| - int end_angle = (frame_count_ % kFakeCaptureBeepCycle * 360) /
|
| - kFakeCaptureBeepCycle;
|
| - if (!end_angle)
|
| - end_angle = 360;
|
| - canvas.drawArc(rect, 0, end_angle, true, paint);
|
| -
|
| - // Draw current time.
|
| - int elapsed_ms = kFakeCaptureTimeoutMs * frame_count_;
|
| - int milliseconds = elapsed_ms % 1000;
|
| - int seconds = (elapsed_ms / 1000) % 60;
|
| - int minutes = (elapsed_ms / 1000 / 60) % 60;
|
| - int hours = (elapsed_ms / 1000 / 60 / 60) % 60;
|
| -
|
| - std::string time_string =
|
| - base::StringPrintf("%d:%02d:%02d:%03d %d", hours, minutes,
|
| - seconds, milliseconds, frame_count_);
|
| - canvas.scale(3, 3);
|
| - canvas.drawText(time_string.data(), time_string.length(), 30, 20,
|
| - paint);
|
| -
|
| - if (frame_count_ % kFakeCaptureBeepCycle == 0) {
|
| - // Generate a synchronized beep sound if there is one audio input
|
| - // stream created.
|
| - FakeAudioInputStream::BeepOnce();
|
| - }
|
| -
|
| - frame_count_++;
|
| -
|
| - // Give the captured frame to the observer.
|
| - observer_->OnIncomingCapturedFrame(
|
| - fake_frame_.get(), frame_size_, base::Time::Now(), 0, false, false);
|
| + if (encoded_capture_) {
|
| + // Just return empty frames.
|
| + scoped_refptr<media::EncodedBitstreamBuffer> buffer =
|
| + observer_->ReserveOutputEncodedBitstreamBuffer();
|
| + if (buffer) {
|
| + observer_->OnIncomingCapturedEncodedBitstreamBuffer(
|
| + buffer,
|
| + 0,
|
| + base::Time::Now());
|
| + }
|
| + } else {
|
| + SkBitmap bitmap;
|
| + bitmap.setConfig(SkBitmap::kA8_Config, frame_width_, frame_height_,
|
| + frame_width_);
|
| + bitmap.setPixels(fake_frame_.get());
|
| +
|
| + SkCanvas canvas(bitmap);
|
| +
|
| + // Draw a sweeping circle to show an animation.
|
| + int radius = std::min(frame_width_, frame_height_) / 4;
|
| + SkRect rect = SkRect::MakeXYWH(
|
| + frame_width_ / 2 - radius, frame_height_ / 2 - radius,
|
| + 2 * radius, 2 * radius);
|
| +
|
| + SkPaint paint;
|
| + paint.setStyle(SkPaint::kFill_Style);
|
| +
|
| + // Only Y plane is being drawn and this gives 50% grey on the Y
|
| + // plane. The result is a light green color in RGB space.
|
| + paint.setAlpha(128);
|
| +
|
| + int end_angle = (frame_count_ % kFakeCaptureBeepCycle * 360) /
|
| + kFakeCaptureBeepCycle;
|
| + if (!end_angle)
|
| + end_angle = 360;
|
| + canvas.drawArc(rect, 0, end_angle, true, paint);
|
| +
|
| + // Draw current time.
|
| + int elapsed_ms = kFakeCaptureTimeoutMs * frame_count_;
|
| + int milliseconds = elapsed_ms % 1000;
|
| + int seconds = (elapsed_ms / 1000) % 60;
|
| + int minutes = (elapsed_ms / 1000 / 60) % 60;
|
| + int hours = (elapsed_ms / 1000 / 60 / 60) % 60;
|
| +
|
| + std::string time_string =
|
| + base::StringPrintf("%d:%02d:%02d:%03d %d", hours, minutes,
|
| + seconds, milliseconds, frame_count_);
|
| + canvas.scale(3, 3);
|
| + canvas.drawText(time_string.data(), time_string.length(), 30, 20,
|
| + paint);
|
| +
|
| + if (frame_count_ % kFakeCaptureBeepCycle == 0) {
|
| + // Generate a synchronized beep sound if there is one audio input
|
| + // stream created.
|
| + FakeAudioInputStream::BeepOnce();
|
| + }
|
| +
|
| + frame_count_++;
|
| +
|
| + // Give the captured frame to the observer.
|
| + observer_->OnIncomingCapturedFrame(
|
| + fake_frame_.get(), frame_size_, base::Time::Now(), 0, false, false);
|
| + }
|
| +
|
| // Reschedule next CaptureTask.
|
| capture_thread_.message_loop()->PostDelayedTask(
|
| FROM_HERE,
|
|
|