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