OLD | NEW |
| (Empty) |
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 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 | |
OLD | NEW |