2
// Copyright 2004--2011 Google Inc.
4
// Redistribution and use in source and binary forms, with or without
5
// modification, are permitted provided that the following conditions are met:
7
// 1. Redistributions of source code must retain the above copyright notice,
8
// this list of conditions and the following disclaimer.
9
// 2. Redistributions in binary form must reproduce the above copyright notice,
10
// this list of conditions and the following disclaimer in the documentation
11
// and/or other materials provided with the distribution.
12
// 3. The name of the author may not be used to endorse or promote products
13
// derived from this software without specific prior written permission.
15
// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
16
// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
17
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
18
// EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
19
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
20
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
21
// OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
22
// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
23
// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
24
// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26
// Implementation of class WebRtcVideoCapturer.
32
#ifdef HAVE_WEBRTC_VIDEO
33
#include "talk/session/phone/webrtcvideocapturer.h"
34
#include "talk/base/logging.h"
35
#include "talk/base/thread.h"
36
#include "talk/base/timeutils.h"
37
#include "talk/session/phone/webrtcvideoframe.h"
39
#include "talk/base/win32.h" // Need this to #include the impl files
40
#ifdef WEBRTC_RELATIVE_PATH
41
#include "modules/video_capture/main/interface/video_capture_factory.h"
43
#include "third_party/webrtc/files/include/video_capture_factory.h"
48
struct kVideoFourCCEntry {
50
webrtc::RawVideoType webrtc_type;
53
// This indicates our format preferences and defines a mapping between
54
// webrtc::RawVideoType (from video_capture_defines.h) to our FOURCCs.
55
static kVideoFourCCEntry kSupportedFourCCs[] = {
56
{ FOURCC_I420, webrtc::kVideoI420 }, // 12 bpp, no conversion
57
{ FOURCC_YV12, webrtc::kVideoYV12 }, // 12 bpp, no conversion
58
{ FOURCC_NV12, webrtc::kVideoNV12 }, // 12 bpp, fast conversion
59
{ FOURCC_NV21, webrtc::kVideoNV21 }, // 12 bpp, fast conversion
60
{ FOURCC_YUY2, webrtc::kVideoYUY2 }, // 16 bpp, fast conversion
61
{ FOURCC_UYVY, webrtc::kVideoUYVY }, // 16 bpp, fast conversion
62
{ FOURCC_MJPG, webrtc::kVideoMJPEG }, // compressed, slow conversion
63
{ FOURCC_ARGB, webrtc::kVideoARGB }, // 32 bpp, slow conversion
64
{ FOURCC_24BG, webrtc::kVideoRGB24 }, // 32 bpp, slow conversion
67
class WebRtcVcmFactory : public WebRtcVcmFactoryInterface {
69
virtual webrtc::VideoCaptureModule* Create(int id,
71
return webrtc::VideoCaptureFactory::Create(id, device);
73
virtual webrtc::VideoCaptureModule::DeviceInfo* CreateDeviceInfo(int id) {
74
return webrtc::VideoCaptureFactory::CreateDeviceInfo(id);
76
virtual void DestroyDeviceInfo(webrtc::VideoCaptureModule::DeviceInfo* info) {
81
static bool CapabilityToFormat(const webrtc::VideoCaptureCapability& cap,
82
VideoFormat* format) {
84
for (size_t i = 0; i < ARRAY_SIZE(kSupportedFourCCs); ++i) {
85
if (kSupportedFourCCs[i].webrtc_type == cap.rawType) {
86
fourcc = kSupportedFourCCs[i].fourcc;
94
format->fourcc = fourcc;
95
format->width = cap.width;
96
format->height = cap.height;
97
format->interval = VideoFormat::FpsToInterval(cap.maxFPS);
101
static bool FormatToCapability(const VideoFormat& format,
102
webrtc::VideoCaptureCapability* cap) {
103
webrtc::RawVideoType webrtc_type = webrtc::kVideoUnknown;
104
for (size_t i = 0; i < ARRAY_SIZE(kSupportedFourCCs); ++i) {
105
if (kSupportedFourCCs[i].fourcc == format.fourcc) {
106
webrtc_type = kSupportedFourCCs[i].webrtc_type;
110
if (webrtc_type == webrtc::kVideoUnknown) {
114
cap->width = format.width;
115
cap->height = format.height;
116
cap->maxFPS = VideoFormat::IntervalToFps(format.interval);
117
cap->expectedCaptureDelay = 0;
118
cap->rawType = webrtc_type;
119
cap->codecType = webrtc::kVideoCodecUnknown;
120
cap->interlaced = false;
124
///////////////////////////////////////////////////////////////////////////
125
// Implementation of class WebRtcVideoCapturer
126
///////////////////////////////////////////////////////////////////////////
128
WebRtcVideoCapturer::WebRtcVideoCapturer()
129
: factory_(new WebRtcVcmFactory),
131
captured_frames_(0) {
134
WebRtcVideoCapturer::WebRtcVideoCapturer(WebRtcVcmFactoryInterface* factory)
137
captured_frames_(0) {
140
WebRtcVideoCapturer::~WebRtcVideoCapturer() {
146
bool WebRtcVideoCapturer::Init(const Device& device) {
148
LOG(LS_ERROR) << "The capturer is already initialized";
152
webrtc::VideoCaptureModule::DeviceInfo* info = factory_->CreateDeviceInfo(0);
157
// Find the desired camera, by name.
158
// In the future, comparing IDs will be more robust.
159
// TODO: Figure what's needed to allow this.
160
int num_cams = info->NumberOfDevices();
161
char vcm_id[256] = "";
163
for (int index = 0; index < num_cams; ++index) {
165
if (info->GetDeviceName(index, vcm_name, ARRAY_SIZE(vcm_name),
166
vcm_id, ARRAY_SIZE(vcm_id)) != -1) {
167
if (device.name == reinterpret_cast<char*>(vcm_name)) {
174
LOG(LS_WARNING) << "Failed to find capturer for id: " << device.id;
175
factory_->DestroyDeviceInfo(info);
179
// Enumerate the supported formats.
180
// TODO: Find out why this starts/stops the camera...
181
std::vector<VideoFormat> supported;
182
WebRtc_UWord32 num_caps = info->NumberOfCapabilities(vcm_id);
183
for (WebRtc_UWord8 i = 0; i < num_caps; ++i) {
184
webrtc::VideoCaptureCapability cap;
185
if (info->GetCapability(vcm_id, i, cap) != -1) {
187
if (CapabilityToFormat(cap, &format)) {
188
supported.push_back(format);
190
LOG(LS_WARNING) << "Ignoring unsupported WebRTC capture format "
195
factory_->DestroyDeviceInfo(info);
196
if (supported.empty()) {
197
LOG(LS_ERROR) << "Failed to find usable formats for id: " << device.id;
201
module_ = factory_->Create(0, vcm_id);
203
LOG(LS_ERROR) << "Failed to create capturer for id: " << device.id;
207
// It is safe to change member attributes now.
210
SetSupportedFormats(supported);
214
bool WebRtcVideoCapturer::Init(webrtc::VideoCaptureModule* module) {
216
LOG(LS_ERROR) << "The capturer is already initialized";
220
LOG(LS_ERROR) << "Invalid VCM supplied";
223
// TODO: Set id and formats.
224
(module_ = module)->AddRef();
228
bool WebRtcVideoCapturer::GetBestCaptureFormat(const VideoFormat& desired,
229
VideoFormat* best_format) {
234
if (!VideoCapturer::GetBestCaptureFormat(desired, best_format)) {
235
// If the vcm has a list of the supported format, but didn't find the
236
// best match, then we should return fail.
237
if (GetSupportedFormats()) {
241
// We maybe using a manually injected VCM which doesn't support enum.
242
// Use the desired format as the best format.
243
best_format->width = desired.width;
244
best_format->height = desired.height;
245
best_format->fourcc = FOURCC_I420;
246
best_format->interval = desired.interval;
247
LOG(LS_INFO) << "Failed to find best capture format,"
248
<< " fall back to the requested format "
249
<< best_format->ToString();
254
CaptureResult WebRtcVideoCapturer::Start(const VideoFormat& capture_format) {
256
LOG(LS_ERROR) << "The capturer has not been initialized";
261
LOG(LS_ERROR) << "The capturer is already running";
265
SetCaptureFormat(&capture_format);
267
webrtc::VideoCaptureCapability cap;
268
if (!FormatToCapability(capture_format, &cap)) {
269
LOG(LS_ERROR) << "Invalid capture format specified";
273
std::string camera_id(GetId());
274
uint32 start = talk_base::Time();
275
if (module_->RegisterCaptureDataCallback(*this) != 0 ||
276
module_->StartCapture(cap) != 0) {
277
LOG(LS_ERROR) << "Camera '" << camera_id << "' failed to start";
281
LOG(LS_INFO) << "Camera '" << camera_id << "' started with format "
282
<< capture_format.ToString() << ", elapsed time "
283
<< talk_base::TimeSince(start) << " ms";
285
captured_frames_ = 0;
286
talk_base::Thread::Current()->Post(this);
290
void WebRtcVideoCapturer::Stop() {
292
talk_base::Thread::Current()->Clear(this);
293
module_->StopCapture();
294
module_->DeRegisterCaptureDataCallback();
296
// TODO: Determine if the VCM exposes any drop stats we can use.
297
double drop_ratio = 0.0;
298
std::string camera_id(GetId());
299
LOG(LS_INFO) << "Camera '" << camera_id << "' stopped after capturing "
300
<< captured_frames_ << " frames and dropping "
301
<< drop_ratio << "%";
303
SetCaptureFormat(NULL);
306
bool WebRtcVideoCapturer::IsRunning() {
307
return (module_ != NULL && module_->CaptureStarted());
310
bool WebRtcVideoCapturer::GetPreferredFourccs(
311
std::vector<uint32>* fourccs) {
317
for (size_t i = 0; i < ARRAY_SIZE(kSupportedFourCCs); ++i) {
318
fourccs->push_back(kSupportedFourCCs[i].fourcc);
323
void WebRtcVideoCapturer::OnMessage(talk_base::Message* message) {
324
// TODO: Fire SignalCaptureEvent appropriately.
325
SignalStartResult(this, CR_SUCCESS);
328
void WebRtcVideoCapturer::OnIncomingCapturedFrame(const WebRtc_Word32 id,
329
webrtc::VideoFrame& sample, webrtc::VideoCodecType codec_type) {
331
ASSERT(codec_type == webrtc::kVideoCodecUnknown);
334
// Log the size and pixel aspect ratio of the first captured frame.
335
if (1 == captured_frames_) {
336
LOG(LS_INFO) << "Captured frame size "
337
<< sample.Width() << "x" << sample.Height()
338
<< ". Expected format " << GetCaptureFormat()->ToString();
341
// Signal down stream components on captured frame.
342
WebRtcCapturedFrame frame(sample);
343
SignalFrameCaptured(this, &frame);
346
void WebRtcVideoCapturer::OnCaptureDelayChanged(
347
const WebRtc_Word32 id, const WebRtc_Word32 delay) {
348
LOG(LS_INFO) << "Capture delay changed to " << delay << " ms";
351
// WebRtcCapturedFrame
352
WebRtcCapturedFrame::WebRtcCapturedFrame(const webrtc::VideoFrame& sample) {
353
width = sample.Width();
354
height = sample.Height();
355
fourcc = FOURCC_I420;
358
// convert units from VideoFrame RenderTimeMs
359
// to CapturedFrame (nanoseconds)
360
elapsed_time = sample.RenderTimeMs() * talk_base::kNumNanosecsPerMillisec;
361
time_stamp = elapsed_time;
362
data_size = sample.Length();
363
data = const_cast<WebRtc_UWord8*>(sample.Buffer());
366
} // namespace cricket
368
#endif // HAVE_WEBRTC_VIDEO