Home | History | Annotate | Download | only in capture
      1 // Copyright (c) 2012 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/video/capture/fake_video_capture_device.h"
      6 
      7 #include <string>
      8 
      9 #include "base/bind.h"
     10 #include "base/memory/scoped_ptr.h"
     11 #include "base/strings/stringprintf.h"
     12 #include "media/audio/fake_audio_input_stream.h"
     13 #include "third_party/skia/include/core/SkBitmap.h"
     14 #include "third_party/skia/include/core/SkCanvas.h"
     15 #include "third_party/skia/include/core/SkPaint.h"
     16 
     17 namespace media {
     18 
     19 static const int kFakeCaptureTimeoutMs = 50;
     20 static const int kFakeCaptureBeepCycle = 20;  // Visual beep every 1s.
     21 static const int kFakeCaptureCapabilityChangePeriod = 30;
     22 enum { kNumberOfFakeDevices = 2 };
     23 
     24 bool FakeVideoCaptureDevice::fail_next_create_ = false;
     25 base::subtle::Atomic32 FakeVideoCaptureDevice::number_of_devices_ =
     26     kNumberOfFakeDevices;
     27 
     28 // static
     29 size_t FakeVideoCaptureDevice::NumberOfFakeDevices(void) {
     30   return number_of_devices_;
     31 }
     32 
     33 // static
     34 void FakeVideoCaptureDevice::GetDeviceNames(Names* const device_names) {
     35   // Empty the name list.
     36   device_names->erase(device_names->begin(), device_names->end());
     37 
     38   int number_of_devices = base::subtle::NoBarrier_Load(&number_of_devices_);
     39   for (int32 n = 0; n < number_of_devices; n++) {
     40     Name name(base::StringPrintf("fake_device_%d", n),
     41               base::StringPrintf("/dev/video%d", n));
     42     device_names->push_back(name);
     43   }
     44 }
     45 
     46 // static
     47 void FakeVideoCaptureDevice::GetDeviceSupportedFormats(
     48     const Name& device,
     49     VideoCaptureFormats* supported_formats) {
     50 
     51   supported_formats->clear();
     52   VideoCaptureFormat capture_format_640x480;
     53   capture_format_640x480.pixel_format = media::PIXEL_FORMAT_I420;
     54   capture_format_640x480.frame_size.SetSize(640, 480);
     55   capture_format_640x480.frame_rate = 1000 / kFakeCaptureTimeoutMs;
     56   supported_formats->push_back(capture_format_640x480);
     57   VideoCaptureFormat capture_format_320x240;
     58   capture_format_320x240.pixel_format = media::PIXEL_FORMAT_I420;
     59   capture_format_320x240.frame_size.SetSize(320, 240);
     60   capture_format_320x240.frame_rate = 1000 / kFakeCaptureTimeoutMs;
     61   supported_formats->push_back(capture_format_320x240);
     62 }
     63 
     64 // static
     65 VideoCaptureDevice* FakeVideoCaptureDevice::Create(const Name& device_name) {
     66   if (fail_next_create_) {
     67     fail_next_create_ = false;
     68     return NULL;
     69   }
     70   int number_of_devices = base::subtle::NoBarrier_Load(&number_of_devices_);
     71   for (int32 n = 0; n < number_of_devices; ++n) {
     72     std::string possible_id = base::StringPrintf("/dev/video%d", n);
     73     if (device_name.id().compare(possible_id) == 0) {
     74       return new FakeVideoCaptureDevice();
     75     }
     76   }
     77   return NULL;
     78 }
     79 
     80 // static
     81 void FakeVideoCaptureDevice::SetFailNextCreate() {
     82   fail_next_create_ = true;
     83 }
     84 
     85 // static
     86 void FakeVideoCaptureDevice::SetNumberOfFakeDevices(size_t number_of_devices) {
     87   base::subtle::NoBarrier_AtomicExchange(&number_of_devices_,
     88                                          number_of_devices);
     89 }
     90 
     91 FakeVideoCaptureDevice::FakeVideoCaptureDevice()
     92     : capture_thread_("CaptureThread"),
     93       frame_count_(0),
     94       format_roster_index_(0) {}
     95 
     96 FakeVideoCaptureDevice::~FakeVideoCaptureDevice() {
     97   DCHECK(thread_checker_.CalledOnValidThread());
     98   DCHECK(!capture_thread_.IsRunning());
     99 }
    100 
    101 void FakeVideoCaptureDevice::AllocateAndStart(
    102     const VideoCaptureParams& params,
    103     scoped_ptr<VideoCaptureDevice::Client> client) {
    104   DCHECK(thread_checker_.CalledOnValidThread());
    105   DCHECK(!capture_thread_.IsRunning());
    106 
    107   capture_thread_.Start();
    108   capture_thread_.message_loop()->PostTask(
    109       FROM_HERE,
    110       base::Bind(&FakeVideoCaptureDevice::OnAllocateAndStart,
    111                  base::Unretained(this),
    112                  params,
    113                  base::Passed(&client)));
    114 }
    115 
    116 void FakeVideoCaptureDevice::StopAndDeAllocate() {
    117   DCHECK(thread_checker_.CalledOnValidThread());
    118   DCHECK(capture_thread_.IsRunning());
    119   capture_thread_.message_loop()->PostTask(
    120       FROM_HERE,
    121       base::Bind(&FakeVideoCaptureDevice::OnStopAndDeAllocate,
    122                  base::Unretained(this)));
    123   capture_thread_.Stop();
    124 }
    125 
    126 void FakeVideoCaptureDevice::OnAllocateAndStart(
    127     const VideoCaptureParams& params,
    128     scoped_ptr<VideoCaptureDevice::Client> client) {
    129   DCHECK_EQ(capture_thread_.message_loop(), base::MessageLoop::current());
    130   client_ = client.Pass();
    131   capture_format_.pixel_format = PIXEL_FORMAT_I420;
    132   capture_format_.frame_rate = 30;
    133   if (params.requested_format.frame_size.width() > 320)
    134     capture_format_.frame_size.SetSize(640, 480);
    135   else
    136     capture_format_.frame_size.SetSize(320, 240);
    137   if (params.allow_resolution_change)
    138     PopulateFormatRoster();
    139   const size_t fake_frame_size =
    140       VideoFrame::AllocationSize(VideoFrame::I420, capture_format_.frame_size);
    141   fake_frame_.reset(new uint8[fake_frame_size]);
    142 
    143   capture_thread_.message_loop()->PostTask(
    144       FROM_HERE,
    145       base::Bind(&FakeVideoCaptureDevice::OnCaptureTask,
    146                  base::Unretained(this)));
    147 }
    148 
    149 void FakeVideoCaptureDevice::OnStopAndDeAllocate() {
    150   DCHECK_EQ(capture_thread_.message_loop(), base::MessageLoop::current());
    151   client_.reset();
    152 }
    153 
    154 void FakeVideoCaptureDevice::OnCaptureTask() {
    155   if (!client_)
    156     return;
    157 
    158   const size_t frame_size =
    159       VideoFrame::AllocationSize(VideoFrame::I420, capture_format_.frame_size);
    160   memset(fake_frame_.get(), 0, frame_size);
    161 
    162   SkBitmap bitmap;
    163   bitmap.setConfig(SkBitmap::kA8_Config,
    164                    capture_format_.frame_size.width(),
    165                    capture_format_.frame_size.height(),
    166                    capture_format_.frame_size.width()),
    167       bitmap.setPixels(fake_frame_.get());
    168 
    169   SkCanvas canvas(bitmap);
    170 
    171   // Draw a sweeping circle to show an animation.
    172   int radius = std::min(capture_format_.frame_size.width(),
    173                         capture_format_.frame_size.height()) /
    174                4;
    175   SkRect rect =
    176       SkRect::MakeXYWH(capture_format_.frame_size.width() / 2 - radius,
    177                        capture_format_.frame_size.height() / 2 - radius,
    178                        2 * radius,
    179                        2 * radius);
    180 
    181   SkPaint paint;
    182   paint.setStyle(SkPaint::kFill_Style);
    183 
    184   // Only Y plane is being drawn and this gives 50% grey on the Y
    185   // plane. The result is a light green color in RGB space.
    186   paint.setAlpha(128);
    187 
    188   int end_angle = (frame_count_ % kFakeCaptureBeepCycle * 360) /
    189       kFakeCaptureBeepCycle;
    190   if (!end_angle)
    191     end_angle = 360;
    192   canvas.drawArc(rect, 0, end_angle, true, paint);
    193 
    194   // Draw current time.
    195   int elapsed_ms = kFakeCaptureTimeoutMs * frame_count_;
    196   int milliseconds = elapsed_ms % 1000;
    197   int seconds = (elapsed_ms / 1000) % 60;
    198   int minutes = (elapsed_ms / 1000 / 60) % 60;
    199   int hours = (elapsed_ms / 1000 / 60 / 60) % 60;
    200 
    201   std::string time_string =
    202       base::StringPrintf("%d:%02d:%02d:%03d %d", hours, minutes,
    203                          seconds, milliseconds, frame_count_);
    204   canvas.scale(3, 3);
    205   canvas.drawText(time_string.data(), time_string.length(), 30, 20,
    206                   paint);
    207 
    208   if (frame_count_ % kFakeCaptureBeepCycle == 0) {
    209     // Generate a synchronized beep sound if there is one audio input
    210     // stream created.
    211     FakeAudioInputStream::BeepOnce();
    212   }
    213 
    214   frame_count_++;
    215 
    216   // Give the captured frame to the client.
    217   client_->OnIncomingCapturedFrame(fake_frame_.get(),
    218                                    frame_size,
    219                                    base::Time::Now(),
    220                                    0,
    221                                    capture_format_);
    222   if (!(frame_count_ % kFakeCaptureCapabilityChangePeriod) &&
    223       format_roster_.size() > 0U) {
    224     Reallocate();
    225   }
    226   // Reschedule next CaptureTask.
    227   capture_thread_.message_loop()->PostDelayedTask(
    228       FROM_HERE,
    229       base::Bind(&FakeVideoCaptureDevice::OnCaptureTask,
    230                  base::Unretained(this)),
    231       base::TimeDelta::FromMilliseconds(kFakeCaptureTimeoutMs));
    232 }
    233 
    234 void FakeVideoCaptureDevice::Reallocate() {
    235   DCHECK_EQ(capture_thread_.message_loop(), base::MessageLoop::current());
    236   capture_format_ =
    237       format_roster_.at(++format_roster_index_ % format_roster_.size());
    238   DCHECK_EQ(capture_format_.pixel_format, PIXEL_FORMAT_I420);
    239   DVLOG(3) << "Reallocating FakeVideoCaptureDevice, new capture resolution "
    240            << capture_format_.frame_size.ToString();
    241 
    242   const size_t fake_frame_size =
    243       VideoFrame::AllocationSize(VideoFrame::I420, capture_format_.frame_size);
    244   fake_frame_.reset(new uint8[fake_frame_size]);
    245 }
    246 
    247 void FakeVideoCaptureDevice::PopulateFormatRoster() {
    248   DCHECK_EQ(capture_thread_.message_loop(), base::MessageLoop::current());
    249   format_roster_.push_back(
    250       media::VideoCaptureFormat(gfx::Size(320, 240), 30, PIXEL_FORMAT_I420));
    251   format_roster_.push_back(
    252       media::VideoCaptureFormat(gfx::Size(640, 480), 30, PIXEL_FORMAT_I420));
    253   format_roster_.push_back(
    254       media::VideoCaptureFormat(gfx::Size(800, 600), 30, PIXEL_FORMAT_I420));
    255 
    256   format_roster_index_ = 0;
    257 }
    258 
    259 }  // namespace media
    260