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