1 /*
2 * libjingle
3 * Copyright 2011, 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/app/webrtc/test/fakevideocapturemodule.h"
29
30 #include "talk/app/webrtc/test/fileframesource.h"
31 #include "talk/app/webrtc/test/i420framesource.h"
32 #include "talk/app/webrtc/test/staticframesource.h"
33 #include "talk/base/refcount.h"
34 #include "talk/base/stream.h"
35 #include "talk/base/thread.h"
36
37 #ifdef WEBRTC_RELATIVE_PATH
38 #include "modules/video_capture/main/interface/video_capture_defines.h"
39 #include "modules/video_capture/main/interface/video_capture_factory.h"
40 #else
41 #include "third_party/webrtc/files/include/video_capture_defines.h"
42 #include "third_party/webrtc/files/include/video_capture_factory.h"
43 #endif
44
45 static const int kStartFrameRate = 30;
46 static const int kStartWidth = 352;
47 static const int kStartHeight = 288;
48 static const uint32 kStartTimeStamp = 2000;
49
FakeVideoCaptureModule(talk_base::Thread * camera_thread)50 FakeVideoCaptureModule::FakeVideoCaptureModule(talk_base::Thread* camera_thread)
51 : frame_source_(NULL),
52 camera_thread_(camera_thread),
53 video_capture_(NULL),
54 started_(false),
55 capture_started_(false),
56 sent_frames_(0),
57 next_frame_time_(0),
58 time_per_frame_ms_(0),
59 fps_(0),
60 width_(0),
61 height_(0) {}
62
~FakeVideoCaptureModule()63 FakeVideoCaptureModule::~FakeVideoCaptureModule() {
64 StopCapturing();
65 // The memory associated with video_capture_ is owned by impl_.
66 }
67
68 FakeVideoCaptureModule*
Create(talk_base::Thread * camera_thread)69 FakeVideoCaptureModule::Create(talk_base::Thread* camera_thread) {
70 talk_base::RefCountedObject<FakeVideoCaptureModule>* capture_module =
71 new talk_base::RefCountedObject<FakeVideoCaptureModule>(camera_thread);
72 if (!capture_module->Init(new StaticFrameSource())) {
73 delete capture_module;
74 return NULL;
75 }
76 return capture_module;
77 }
78
79 FakeVideoCaptureModule*
Create(talk_base::Thread * camera_thread,const std::string & file_name)80 FakeVideoCaptureModule::Create(talk_base::Thread* camera_thread,
81 const std::string& file_name) {
82 talk_base::RefCountedObject<FakeVideoCaptureModule>* capture_module =
83 new talk_base::RefCountedObject<FakeVideoCaptureModule>(camera_thread);
84 if (!capture_module->Init(FileFrameSource::Create(file_name))) {
85 delete capture_module;
86 return NULL;
87 }
88 return capture_module;
89 }
90
StartCapturing()91 void FakeVideoCaptureModule::StartCapturing() {
92 camera_thread_->Clear(this);
93 // Only one post, no need to add any data to post.
94 camera_thread_->Post(this);
95 }
96
StopCapturing()97 void FakeVideoCaptureModule::StopCapturing() {
98 camera_thread_->Clear(this);
99 }
100
RegisterFrameSource(I420FrameSource * frame_source)101 bool FakeVideoCaptureModule::RegisterFrameSource(
102 I420FrameSource* frame_source) {
103 if (frame_source == NULL) {
104 return false;
105 }
106 frame_source_ = frame_source;
107 frame_source_->SetFrameSize(width_, height_);
108 return true;
109 }
110
111 // TODO: deal with the rounding error.
SetFrameRate(int fps)112 bool FakeVideoCaptureModule::SetFrameRate(int fps) {
113 if (fps <= 0) {
114 return false;
115 }
116 fps_ = fps;
117 time_per_frame_ms_ = 1000 / fps;
118 return true;
119 }
120
SetSize(int width,int height)121 void FakeVideoCaptureModule::SetSize(int width, int height) {
122 width_ = width;
123 height_ = height;
124 image_.reset(new uint8[GetI420FrameLengthInBytes()]);
125 if (frame_source_ != NULL) {
126 frame_source_->SetFrameSize(width_, height_);
127 }
128 }
129
Init(I420FrameSource * frame_source)130 bool FakeVideoCaptureModule::Init(I420FrameSource* frame_source) {
131 if (!RegisterFrameSource(frame_source)) {
132 return false;
133 }
134 SetSize(kStartWidth, kStartHeight);
135 impl_ = webrtc::VideoCaptureFactory::Create(0, // id
136 video_capture_);
137 if (impl_.get() == NULL) {
138 return false;
139 }
140 if (video_capture_ == NULL) {
141 return false;
142 }
143 if (!SetFrameRate(kStartFrameRate)) {
144 return false;
145 }
146 return true;
147 }
148
149 // TODO: handle time wrapparound.
GenerateNewFrame()150 void FakeVideoCaptureModule::GenerateNewFrame() {
151 if (!started_) {
152 next_frame_time_ = talk_base::Time();
153 started_ = true;
154 }
155 size_t read = 0;
156 if (frame_source_->GetFrame(image_.get(), &read)) {
157 ASSERT(read == GetI420FrameLengthInBytes());
158
159 webrtc::VideoCaptureCapability capability;
160 capability.width = width_;
161 capability.height = height_;
162 capability.rawType = webrtc::kVideoI420;
163 video_capture_->IncomingFrame(image_.get(), GetI420FrameLengthInBytes(),
164 capability, GetTimestamp());
165 ++sent_frames_;
166 }
167 else {
168 ASSERT(false);
169 }
170 next_frame_time_ += time_per_frame_ms_;
171 const uint32 current_time = talk_base::Time();
172 const uint32 wait_time = (next_frame_time_ > current_time) ?
173 next_frame_time_ - current_time : 0;
174 camera_thread_->PostDelayed(wait_time, this);
175 }
176
GetI420FrameLengthInBytes()177 size_t FakeVideoCaptureModule::GetI420FrameLengthInBytes() {
178 return webrtc_testing::GetI420FrameLengthInBytes(width_, height_);
179 }
180
181 // TODO: handle timestamp wrapparound.
GetTimestamp()182 uint32 FakeVideoCaptureModule::GetTimestamp() {
183 return kStartTimeStamp + sent_frames_ * time_per_frame_ms_;
184 }
185