Home | History | Annotate | Download | only in devices
      1 /*
      2  * libjingle
      3  * Copyright 2004--2014 Google Inc.
      4  *
      5  * Redistribution and use in source and binary forms, with or without
      6  * modification, are permitted provided that the following conditions are met:
      7  *
      8  *  1. Redistributions of source code must retain the above copyright notice,
      9  *     this list of conditions and the following disclaimer.
     10  *  2. Redistributions in binary form must reproduce the above copyright notice,
     11  *     this list of conditions and the following disclaimer in the documentation
     12  *     and/or other materials provided with the distribution.
     13  *  3. The name of the author may not be used to endorse or promote products
     14  *     derived from this software without specific prior written permission.
     15  *
     16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
     17  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
     18  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
     19  * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     20  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
     21  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
     22  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
     23  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
     24  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
     25  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     26  */
     27 
     28 #include "talk/media/devices/yuvframescapturer.h"
     29 
     30 #include "webrtc/base/bytebuffer.h"
     31 #include "webrtc/base/criticalsection.h"
     32 #include "webrtc/base/logging.h"
     33 #include "webrtc/base/thread.h"
     34 
     35 #include "webrtc/system_wrappers/include/clock.h"
     36 
     37 namespace cricket {
     38 ///////////////////////////////////////////////////////////////////////
     39 // Definition of private class YuvFramesThread that periodically generates
     40 // frames.
     41 ///////////////////////////////////////////////////////////////////////
     42 class YuvFramesCapturer::YuvFramesThread
     43     : public rtc::Thread, public rtc::MessageHandler {
     44  public:
     45   explicit YuvFramesThread(YuvFramesCapturer* capturer)
     46       : capturer_(capturer),
     47         finished_(false) {
     48   }
     49 
     50   virtual ~YuvFramesThread() {
     51     Stop();
     52   }
     53 
     54   // Override virtual method of parent Thread. Context: Worker Thread.
     55   virtual void Run() {
     56     // Read the first frame and start the message pump. The pump runs until
     57     // Stop() is called externally or Quit() is called by OnMessage().
     58     int waiting_time_ms = 0;
     59     if (capturer_) {
     60       capturer_->ReadFrame(true);
     61       PostDelayed(waiting_time_ms, this);
     62       Thread::Run();
     63     }
     64 
     65     rtc::CritScope cs(&crit_);
     66     finished_ = true;
     67   }
     68 
     69   // Override virtual method of parent MessageHandler. Context: Worker Thread.
     70   virtual void OnMessage(rtc::Message* /*pmsg*/) {
     71     int waiting_time_ms = 0;
     72     if (capturer_) {
     73       capturer_->ReadFrame(false);
     74       PostDelayed(waiting_time_ms, this);
     75     } else {
     76       Quit();
     77     }
     78   }
     79 
     80   // Check if Run() is finished.
     81   bool Finished() const {
     82     rtc::CritScope cs(&crit_);
     83     return finished_;
     84   }
     85 
     86  private:
     87   YuvFramesCapturer* capturer_;
     88   mutable rtc::CriticalSection crit_;
     89   bool finished_;
     90 
     91   RTC_DISALLOW_COPY_AND_ASSIGN(YuvFramesThread);
     92 };
     93 
     94 /////////////////////////////////////////////////////////////////////
     95 // Implementation of class YuvFramesCapturer.
     96 /////////////////////////////////////////////////////////////////////
     97 
     98 const char* YuvFramesCapturer::kYuvFrameDeviceName = "YuvFramesGenerator";
     99 
    100 // TODO(shaowei): allow width_ and height_ to be configurable.
    101 YuvFramesCapturer::YuvFramesCapturer()
    102     : frames_generator_thread(NULL),
    103       width_(640),
    104       height_(480),
    105       frame_index_(0),
    106       barcode_interval_(1) {
    107 }
    108 
    109 YuvFramesCapturer::~YuvFramesCapturer() {
    110   Stop();
    111   delete[] static_cast<char*>(captured_frame_.data);
    112 }
    113 
    114 void YuvFramesCapturer::Init() {
    115   int size = width_ * height_;
    116   int qsize = size / 4;
    117   frame_generator_ = new YuvFrameGenerator(width_, height_, true);
    118   frame_data_size_ = size + 2 * qsize;
    119   captured_frame_.data = new char[frame_data_size_];
    120   captured_frame_.fourcc = FOURCC_IYUV;
    121   captured_frame_.pixel_height = 1;
    122   captured_frame_.pixel_width = 1;
    123   captured_frame_.width = width_;
    124   captured_frame_.height = height_;
    125   captured_frame_.data_size = frame_data_size_;
    126 
    127   // Enumerate the supported formats. We have only one supported format.
    128   VideoFormat format(width_, height_, VideoFormat::kMinimumInterval,
    129                      FOURCC_IYUV);
    130   std::vector<VideoFormat> supported;
    131   supported.push_back(format);
    132   SetSupportedFormats(supported);
    133 }
    134 
    135 CaptureState YuvFramesCapturer::Start(const VideoFormat& capture_format) {
    136   if (IsRunning()) {
    137     LOG(LS_ERROR) << "Yuv Frame Generator is already running";
    138     return CS_FAILED;
    139   }
    140   SetCaptureFormat(&capture_format);
    141 
    142   barcode_reference_timestamp_millis_ =
    143       static_cast<int64_t>(rtc::Time()) * 1000;
    144   // Create a thread to generate frames.
    145   frames_generator_thread = new YuvFramesThread(this);
    146   bool ret = frames_generator_thread->Start();
    147   if (ret) {
    148     LOG(LS_INFO) << "Yuv Frame Generator started";
    149     return CS_RUNNING;
    150   } else {
    151     LOG(LS_ERROR) << "Yuv Frame Generator failed to start";
    152     return CS_FAILED;
    153   }
    154 }
    155 
    156 bool YuvFramesCapturer::IsRunning() {
    157   return frames_generator_thread && !frames_generator_thread->Finished();
    158 }
    159 
    160 void YuvFramesCapturer::Stop() {
    161   if (frames_generator_thread) {
    162     frames_generator_thread->Stop();
    163     frames_generator_thread = NULL;
    164     LOG(LS_INFO) << "Yuv Frame Generator stopped";
    165   }
    166   SetCaptureFormat(NULL);
    167 }
    168 
    169 bool YuvFramesCapturer::GetPreferredFourccs(std::vector<uint32_t>* fourccs) {
    170   if (!fourccs) {
    171     return false;
    172   }
    173   fourccs->push_back(GetSupportedFormats()->at(0).fourcc);
    174   return true;
    175 }
    176 
    177 // Executed in the context of YuvFramesThread.
    178 void YuvFramesCapturer::ReadFrame(bool first_frame) {
    179   // 1. Signal the previously read frame to downstream.
    180   if (!first_frame) {
    181     SignalFrameCaptured(this, &captured_frame_);
    182   }
    183   uint8_t* buffer = new uint8_t[frame_data_size_];
    184   frame_generator_->GenerateNextFrame(buffer, GetBarcodeValue());
    185   frame_index_++;
    186   memmove(captured_frame_.data, buffer, frame_data_size_);
    187   delete[] buffer;
    188 }
    189 
    190 int32_t YuvFramesCapturer::GetBarcodeValue() {
    191   if (barcode_reference_timestamp_millis_ == -1 ||
    192        frame_index_ % barcode_interval_ != 0) {
    193      return -1;
    194   }
    195   int64_t now_millis = static_cast<int64_t>(rtc::Time()) * 1000;
    196   return static_cast<int32_t>(now_millis - barcode_reference_timestamp_millis_);
    197 }
    198 
    199 }  // namespace cricket
    200