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