1#include "talk/media/devices/yuvframescapturer.h" 2 3#include "webrtc/base/bytebuffer.h" 4#include "webrtc/base/criticalsection.h" 5#include "webrtc/base/logging.h" 6#include "webrtc/base/thread.h" 7 8#include "webrtc/system_wrappers/interface/clock.h" 9 10namespace cricket { 11/////////////////////////////////////////////////////////////////////// 12// Definition of private class YuvFramesThread that periodically generates 13// frames. 14/////////////////////////////////////////////////////////////////////// 15class YuvFramesCapturer::YuvFramesThread 16 : public rtc::Thread, public rtc::MessageHandler { 17 public: 18 explicit YuvFramesThread(YuvFramesCapturer* capturer) 19 : capturer_(capturer), 20 finished_(false) { 21 } 22 23 virtual ~YuvFramesThread() { 24 Stop(); 25 } 26 27 // Override virtual method of parent Thread. Context: Worker Thread. 28 virtual void Run() { 29 // Read the first frame and start the message pump. The pump runs until 30 // Stop() is called externally or Quit() is called by OnMessage(). 31 int waiting_time_ms = 0; 32 if (capturer_) { 33 capturer_->ReadFrame(true); 34 PostDelayed(waiting_time_ms, this); 35 Thread::Run(); 36 } 37 38 rtc::CritScope cs(&crit_); 39 finished_ = true; 40 } 41 42 // Override virtual method of parent MessageHandler. Context: Worker Thread. 43 virtual void OnMessage(rtc::Message* /*pmsg*/) { 44 int waiting_time_ms = 0; 45 if (capturer_) { 46 capturer_->ReadFrame(false); 47 PostDelayed(waiting_time_ms, this); 48 } else { 49 Quit(); 50 } 51 } 52 53 // Check if Run() is finished. 54 bool Finished() const { 55 rtc::CritScope cs(&crit_); 56 return finished_; 57 } 58 59 private: 60 YuvFramesCapturer* capturer_; 61 mutable rtc::CriticalSection crit_; 62 bool finished_; 63 64 DISALLOW_COPY_AND_ASSIGN(YuvFramesThread); 65}; 66 67///////////////////////////////////////////////////////////////////// 68// Implementation of class YuvFramesCapturer. 69///////////////////////////////////////////////////////////////////// 70 71const char* YuvFramesCapturer::kYuvFrameDeviceName = "YuvFramesGenerator"; 72 73// TODO(shaowei): allow width_ and height_ to be configurable. 74YuvFramesCapturer::YuvFramesCapturer() 75 : frames_generator_thread(NULL), 76 width_(640), 77 height_(480), 78 frame_index_(0), 79 barcode_interval_(1) { 80} 81 82YuvFramesCapturer::~YuvFramesCapturer() { 83 Stop(); 84 delete[] static_cast<char*>(captured_frame_.data); 85} 86 87void YuvFramesCapturer::Init() { 88 int size = width_ * height_; 89 int qsize = size / 4; 90 frame_generator_ = new YuvFrameGenerator(width_, height_, true); 91 frame_data_size_ = size + 2 * qsize; 92 captured_frame_.data = new char[frame_data_size_]; 93 captured_frame_.fourcc = FOURCC_IYUV; 94 captured_frame_.pixel_height = 1; 95 captured_frame_.pixel_width = 1; 96 captured_frame_.width = width_; 97 captured_frame_.height = height_; 98 captured_frame_.data_size = frame_data_size_; 99 100 // Enumerate the supported formats. We have only one supported format. 101 VideoFormat format(width_, height_, VideoFormat::kMinimumInterval, 102 FOURCC_IYUV); 103 std::vector<VideoFormat> supported; 104 supported.push_back(format); 105 SetSupportedFormats(supported); 106} 107 108CaptureState YuvFramesCapturer::Start(const VideoFormat& capture_format) { 109 if (IsRunning()) { 110 LOG(LS_ERROR) << "Yuv Frame Generator is already running"; 111 return CS_FAILED; 112 } 113 SetCaptureFormat(&capture_format); 114 115 barcode_reference_timestamp_millis_ = 116 static_cast<int64>(rtc::Time()) * 1000; 117 // Create a thread to generate frames. 118 frames_generator_thread = new YuvFramesThread(this); 119 bool ret = frames_generator_thread->Start(); 120 if (ret) { 121 LOG(LS_INFO) << "Yuv Frame Generator started"; 122 return CS_RUNNING; 123 } else { 124 LOG(LS_ERROR) << "Yuv Frame Generator failed to start"; 125 return CS_FAILED; 126 } 127} 128 129bool YuvFramesCapturer::IsRunning() { 130 return frames_generator_thread && !frames_generator_thread->Finished(); 131} 132 133void YuvFramesCapturer::Stop() { 134 if (frames_generator_thread) { 135 frames_generator_thread->Stop(); 136 frames_generator_thread = NULL; 137 LOG(LS_INFO) << "Yuv Frame Generator stopped"; 138 } 139 SetCaptureFormat(NULL); 140} 141 142bool YuvFramesCapturer::GetPreferredFourccs(std::vector<uint32>* fourccs) { 143 if (!fourccs) { 144 return false; 145 } 146 fourccs->push_back(GetSupportedFormats()->at(0).fourcc); 147 return true; 148} 149 150// Executed in the context of YuvFramesThread. 151void YuvFramesCapturer::ReadFrame(bool first_frame) { 152 // 1. Signal the previously read frame to downstream. 153 if (!first_frame) { 154 SignalFrameCaptured(this, &captured_frame_); 155 } 156 uint8* buffer = new uint8[frame_data_size_]; 157 frame_generator_->GenerateNextFrame(buffer, GetBarcodeValue()); 158 frame_index_++; 159 memmove(captured_frame_.data, buffer, frame_data_size_); 160 delete[] buffer; 161} 162 163 164int32 YuvFramesCapturer::GetBarcodeValue() { 165 if (barcode_reference_timestamp_millis_ == -1 || 166 frame_index_ % barcode_interval_ != 0) { 167 return -1; 168 } 169 int64 now_millis = static_cast<int64>(rtc::Time()) * 1000; 170 return static_cast<int32>(now_millis - barcode_reference_timestamp_millis_); 171} 172 173} // namespace cricket 174