• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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:
YuvFramesThread(YuvFramesCapturer * capturer)45   explicit YuvFramesThread(YuvFramesCapturer* capturer)
46       : capturer_(capturer),
47         finished_(false) {
48   }
49 
~YuvFramesThread()50   virtual ~YuvFramesThread() {
51     Stop();
52   }
53 
54   // Override virtual method of parent Thread. Context: Worker Thread.
Run()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.
OnMessage(rtc::Message *)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.
Finished() const81   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.
YuvFramesCapturer()101 YuvFramesCapturer::YuvFramesCapturer()
102     : frames_generator_thread(NULL),
103       width_(640),
104       height_(480),
105       frame_index_(0),
106       barcode_interval_(1) {
107 }
108 
~YuvFramesCapturer()109 YuvFramesCapturer::~YuvFramesCapturer() {
110   Stop();
111   delete[] static_cast<char*>(captured_frame_.data);
112 }
113 
Init()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 
Start(const VideoFormat & capture_format)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 
IsRunning()156 bool YuvFramesCapturer::IsRunning() {
157   return frames_generator_thread && !frames_generator_thread->Finished();
158 }
159 
Stop()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 
GetPreferredFourccs(std::vector<uint32_t> * fourccs)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.
ReadFrame(bool first_frame)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 
GetBarcodeValue()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