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