Upstream version 9.38.198.0
[platform/framework/web/crosswalk.git] / src / third_party / libjingle / source / talk / media / devices / yuvframescapturer.cc
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
10 namespace cricket {
11 ///////////////////////////////////////////////////////////////////////
12 // Definition of private class YuvFramesThread that periodically generates
13 // frames.
14 ///////////////////////////////////////////////////////////////////////
15 class 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
71 const char* YuvFramesCapturer::kYuvFrameDeviceName = "YuvFramesGenerator";
72
73 // TODO(shaowei): allow width_ and height_ to be configurable.
74 YuvFramesCapturer::YuvFramesCapturer()
75     : frames_generator_thread(NULL),
76       width_(640),
77       height_(480),
78       frame_index_(0),
79       barcode_interval_(1) {
80 }
81
82 YuvFramesCapturer::~YuvFramesCapturer() {
83   Stop();
84   delete[] static_cast<char*>(captured_frame_.data);
85 }
86
87 void 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
108 CaptureState 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
129 bool YuvFramesCapturer::IsRunning() {
130   return frames_generator_thread && !frames_generator_thread->Finished();
131 }
132
133 void 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
142 bool 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.
151 void 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
164 int32 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