1/*
2 *  Copyright (c) 2013 The WebRTC project authors. All Rights Reserved.
3 *
4 *  Use of this source code is governed by a BSD-style license
5 *  that can be found in the LICENSE file in the root of the source
6 *  tree. An additional intellectual property rights grant can be found
7 *  in the file PATENTS.  All contributing project authors may
8 *  be found in the AUTHORS file in the root of the source tree.
9 */
10
11#include "webrtc/test/frame_generator_capturer.h"
12
13#include "webrtc/test/frame_generator.h"
14#include "webrtc/system_wrappers/interface/clock.h"
15#include "webrtc/system_wrappers/interface/critical_section_wrapper.h"
16#include "webrtc/system_wrappers/interface/event_wrapper.h"
17#include "webrtc/system_wrappers/interface/sleep.h"
18#include "webrtc/system_wrappers/interface/thread_wrapper.h"
19#include "webrtc/video_send_stream.h"
20
21namespace webrtc {
22namespace test {
23
24FrameGeneratorCapturer* FrameGeneratorCapturer::Create(
25    VideoSendStreamInput* input,
26    size_t width,
27    size_t height,
28    int target_fps,
29    Clock* clock) {
30  FrameGeneratorCapturer* capturer = new FrameGeneratorCapturer(
31      clock, input, FrameGenerator::Create(width, height), target_fps);
32  if (!capturer->Init()) {
33    delete capturer;
34    return NULL;
35  }
36
37  return capturer;
38}
39
40FrameGeneratorCapturer* FrameGeneratorCapturer::CreateFromYuvFile(
41    VideoSendStreamInput* input,
42    const char* file_name,
43    size_t width,
44    size_t height,
45    int target_fps,
46    Clock* clock) {
47  FrameGeneratorCapturer* capturer = new FrameGeneratorCapturer(
48      clock,
49      input,
50      FrameGenerator::CreateFromYuvFile(file_name, width, height),
51      target_fps);
52  if (!capturer->Init()) {
53    delete capturer;
54    return NULL;
55  }
56
57  return capturer;
58}
59
60FrameGeneratorCapturer::FrameGeneratorCapturer(Clock* clock,
61                                               VideoSendStreamInput* input,
62                                               FrameGenerator* frame_generator,
63                                               int target_fps)
64    : VideoCapturer(input),
65      clock_(clock),
66      sending_(false),
67      tick_(EventWrapper::Create()),
68      lock_(CriticalSectionWrapper::CreateCriticalSection()),
69      frame_generator_(frame_generator),
70      target_fps_(target_fps),
71      first_frame_capture_time_(-1) {
72  assert(input != NULL);
73  assert(frame_generator != NULL);
74  assert(target_fps > 0);
75}
76
77FrameGeneratorCapturer::~FrameGeneratorCapturer() {
78  Stop();
79
80  if (thread_.get() != NULL)
81    thread_->Stop();
82}
83
84bool FrameGeneratorCapturer::Init() {
85  // This check is added because frame_generator_ might be file based and should
86  // not crash because a file moved.
87  if (frame_generator_.get() == NULL)
88    return false;
89
90  if (!tick_->StartTimer(true, 1000 / target_fps_))
91    return false;
92  thread_.reset(ThreadWrapper::CreateThread(FrameGeneratorCapturer::Run,
93                                            this,
94                                            webrtc::kHighPriority,
95                                            "FrameGeneratorCapturer"));
96  if (thread_.get() == NULL)
97    return false;
98  unsigned int thread_id;
99  if (!thread_->Start(thread_id)) {
100    thread_.reset();
101    return false;
102  }
103  return true;
104}
105
106bool FrameGeneratorCapturer::Run(void* obj) {
107  static_cast<FrameGeneratorCapturer*>(obj)->InsertFrame();
108  return true;
109}
110
111void FrameGeneratorCapturer::InsertFrame() {
112  {
113    CriticalSectionScoped cs(lock_.get());
114    if (sending_) {
115      I420VideoFrame* frame = frame_generator_->NextFrame();
116      frame->set_render_time_ms(clock_->CurrentNtpInMilliseconds());
117      if (first_frame_capture_time_ == -1) {
118        first_frame_capture_time_ = frame->render_time_ms();
119      }
120      input_->SwapFrame(frame);
121    }
122  }
123  tick_->Wait(WEBRTC_EVENT_INFINITE);
124}
125
126void FrameGeneratorCapturer::Start() {
127  CriticalSectionScoped cs(lock_.get());
128  sending_ = true;
129}
130
131void FrameGeneratorCapturer::Stop() {
132  CriticalSectionScoped cs(lock_.get());
133  sending_ = false;
134}
135}  // test
136}  // webrtc
137