webrtcvideocapturer.cc revision 7433a088d2e97993266b66c102b0866aa90b4424
128e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org// libjingle
228e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org// Copyright 2011 Google Inc.
328e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org//
428e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org// Redistribution and use in source and binary forms, with or without
528e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org// modification, are permitted provided that the following conditions are met:
628e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org//
728e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org//  1. Redistributions of source code must retain the above copyright notice,
828e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org//     this list of conditions and the following disclaimer.
928e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org//  2. Redistributions in binary form must reproduce the above copyright notice,
1028e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org//     this list of conditions and the following disclaimer in the documentation
1128e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org//     and/or other materials provided with the distribution.
1228e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org//  3. The name of the author may not be used to endorse or promote products
1328e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org//     derived from this software without specific prior written permission.
1428e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org//
1528e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
1628e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
1728e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
1828e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org// EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
1928e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
2028e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
2128e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org// OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
2228e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
2328e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
2428e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2528e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org//
2628e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org// Implementation of class WebRtcVideoCapturer.
2728e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org
2828e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org#include "talk/media/webrtc/webrtcvideocapturer.h"
2928e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org
3028e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org#ifdef HAVE_CONFIG_H
3128e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org#include <config.h>
3228e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org#endif
3328e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org
3428e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org#ifdef HAVE_WEBRTC_VIDEO
35f6d6ed0c66457170be3f3b2bc214cd7141e441a4wu@webrtc.org#include "talk/base/criticalsection.h"
3628e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org#include "talk/base/logging.h"
3728e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org#include "talk/base/thread.h"
3828e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org#include "talk/base/timeutils.h"
3928e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org#include "talk/media/webrtc/webrtcvideoframe.h"
4028e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org
4128e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org#include "talk/base/win32.h"  // Need this to #include the impl files.
4228e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org#include "webrtc/modules/video_capture/include/video_capture_factory.h"
4328e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org
4428e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.orgnamespace cricket {
4528e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org
4628e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.orgstruct kVideoFourCCEntry {
4728e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org  uint32 fourcc;
4828e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org  webrtc::RawVideoType webrtc_type;
4928e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org};
5028e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org
5128e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org// This indicates our format preferences and defines a mapping between
5228e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org// webrtc::RawVideoType (from video_capture_defines.h) to our FOURCCs.
5328e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.orgstatic kVideoFourCCEntry kSupportedFourCCs[] = {
5428e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org  { FOURCC_I420, webrtc::kVideoI420 },   // 12 bpp, no conversion.
5528e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org  { FOURCC_YV12, webrtc::kVideoYV12 },   // 12 bpp, no conversion.
5628e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org  { FOURCC_NV12, webrtc::kVideoNV12 },   // 12 bpp, fast conversion.
5728e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org  { FOURCC_NV21, webrtc::kVideoNV21 },   // 12 bpp, fast conversion.
5828e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org  { FOURCC_YUY2, webrtc::kVideoYUY2 },   // 16 bpp, fast conversion.
5928e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org  { FOURCC_UYVY, webrtc::kVideoUYVY },   // 16 bpp, fast conversion.
6028e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org  { FOURCC_MJPG, webrtc::kVideoMJPEG },  // compressed, slow conversion.
6128e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org  { FOURCC_ARGB, webrtc::kVideoARGB },   // 32 bpp, slow conversion.
6228e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org  { FOURCC_24BG, webrtc::kVideoRGB24 },  // 24 bpp, slow conversion.
6328e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org};
6428e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org
6528e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.orgclass WebRtcVcmFactory : public WebRtcVcmFactoryInterface {
6628e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org public:
6728e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org  virtual webrtc::VideoCaptureModule* Create(int id, const char* device) {
6828e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org    return webrtc::VideoCaptureFactory::Create(id, device);
6928e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org  }
7028e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org  virtual webrtc::VideoCaptureModule::DeviceInfo* CreateDeviceInfo(int id) {
7128e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org    return webrtc::VideoCaptureFactory::CreateDeviceInfo(id);
7228e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org  }
7328e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org  virtual void DestroyDeviceInfo(webrtc::VideoCaptureModule::DeviceInfo* info) {
7428e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org    delete info;
7528e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org  }
7628e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org};
7728e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org
7828e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.orgstatic bool CapabilityToFormat(const webrtc::VideoCaptureCapability& cap,
7928e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org                               VideoFormat* format) {
8028e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org  uint32 fourcc = 0;
8128e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org  for (size_t i = 0; i < ARRAY_SIZE(kSupportedFourCCs); ++i) {
8228e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org    if (kSupportedFourCCs[i].webrtc_type == cap.rawType) {
8328e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org      fourcc = kSupportedFourCCs[i].fourcc;
8428e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org      break;
8528e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org    }
8628e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org  }
8728e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org  if (fourcc == 0) {
8828e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org    return false;
8928e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org  }
9028e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org
9128e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org  format->fourcc = fourcc;
9228e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org  format->width = cap.width;
9328e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org  format->height = cap.height;
9428e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org  format->interval = VideoFormat::FpsToInterval(cap.maxFPS);
9528e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org  return true;
9628e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org}
9728e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org
9828e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.orgstatic bool FormatToCapability(const VideoFormat& format,
9928e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org                               webrtc::VideoCaptureCapability* cap) {
10028e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org  webrtc::RawVideoType webrtc_type = webrtc::kVideoUnknown;
10128e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org  for (size_t i = 0; i < ARRAY_SIZE(kSupportedFourCCs); ++i) {
10228e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org    if (kSupportedFourCCs[i].fourcc == format.fourcc) {
10328e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org      webrtc_type = kSupportedFourCCs[i].webrtc_type;
10428e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org      break;
10528e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org    }
10628e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org  }
10728e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org  if (webrtc_type == webrtc::kVideoUnknown) {
10828e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org    return false;
10928e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org  }
11028e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org
11128e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org  cap->width = format.width;
11228e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org  cap->height = format.height;
11328e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org  cap->maxFPS = VideoFormat::IntervalToFps(format.interval);
11428e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org  cap->expectedCaptureDelay = 0;
11528e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org  cap->rawType = webrtc_type;
11628e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org  cap->codecType = webrtc::kVideoCodecUnknown;
11728e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org  cap->interlaced = false;
11828e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org  return true;
11928e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org}
12028e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org
12128e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org///////////////////////////////////////////////////////////////////////////
12228e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org// Implementation of class WebRtcVideoCapturer
12328e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org///////////////////////////////////////////////////////////////////////////
12428e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org
12528e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.orgWebRtcVideoCapturer::WebRtcVideoCapturer()
12628e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org    : factory_(new WebRtcVcmFactory),
12728e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org      module_(NULL),
12828e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org      captured_frames_(0) {
12928e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org}
13028e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org
13128e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.orgWebRtcVideoCapturer::WebRtcVideoCapturer(WebRtcVcmFactoryInterface* factory)
13228e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org    : factory_(factory),
13328e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org      module_(NULL),
13428e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org      captured_frames_(0) {
13528e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org}
13628e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org
13728e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.orgWebRtcVideoCapturer::~WebRtcVideoCapturer() {
13828e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org  if (module_) {
13928e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org    module_->Release();
14028e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org  }
14128e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org}
14228e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org
14328e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.orgbool WebRtcVideoCapturer::Init(const Device& device) {
14428e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org  if (module_) {
14528e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org    LOG(LS_ERROR) << "The capturer is already initialized";
14628e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org    return false;
14728e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org  }
14828e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org
14928e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org  webrtc::VideoCaptureModule::DeviceInfo* info = factory_->CreateDeviceInfo(0);
15028e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org  if (!info) {
15128e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org    return false;
15228e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org  }
15328e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org
15428e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org  // Find the desired camera, by name.
15528e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org  // In the future, comparing IDs will be more robust.
15628e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org  // TODO(juberti): Figure what's needed to allow this.
15728e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org  int num_cams = info->NumberOfDevices();
15828e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org  char vcm_id[256] = "";
15928e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org  bool found = false;
16028e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org  for (int index = 0; index < num_cams; ++index) {
16128e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org    char vcm_name[256];
16228e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org    if (info->GetDeviceName(index, vcm_name, ARRAY_SIZE(vcm_name),
16328e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org                            vcm_id, ARRAY_SIZE(vcm_id)) != -1) {
16428e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org      if (device.name == reinterpret_cast<char*>(vcm_name)) {
16528e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org        found = true;
16628e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org        break;
16728e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org      }
16828e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org    }
16928e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org  }
17028e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org  if (!found) {
17128e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org    LOG(LS_WARNING) << "Failed to find capturer for id: " << device.id;
17228e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org    factory_->DestroyDeviceInfo(info);
17328e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org    return false;
17428e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org  }
17528e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org
17628e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org  // Enumerate the supported formats.
17728e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org  // TODO(juberti): Find out why this starts/stops the camera...
17828e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org  std::vector<VideoFormat> supported;
17928e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org  int32_t num_caps = info->NumberOfCapabilities(vcm_id);
18028e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org  for (int32_t i = 0; i < num_caps; ++i) {
18128e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org    webrtc::VideoCaptureCapability cap;
18228e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org    if (info->GetCapability(vcm_id, i, cap) != -1) {
18328e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org      VideoFormat format;
18428e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org      if (CapabilityToFormat(cap, &format)) {
18528e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org        supported.push_back(format);
18628e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org      } else {
18728e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org        LOG(LS_WARNING) << "Ignoring unsupported WebRTC capture format "
18828e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org                        << cap.rawType;
18928e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org      }
19028e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org    }
19128e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org  }
19228e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org  factory_->DestroyDeviceInfo(info);
19328e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org  if (supported.empty()) {
19428e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org    LOG(LS_ERROR) << "Failed to find usable formats for id: " << device.id;
19528e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org    return false;
19628e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org  }
19728e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org
19828e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org  module_ = factory_->Create(0, vcm_id);
19928e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org  if (!module_) {
20028e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org    LOG(LS_ERROR) << "Failed to create capturer for id: " << device.id;
20128e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org    return false;
20228e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org  }
20328e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org
20428e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org  // It is safe to change member attributes now.
20528e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org  module_->AddRef();
20628e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org  SetId(device.id);
20728e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org  SetSupportedFormats(supported);
20828e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org  return true;
20928e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org}
21028e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org
21128e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.orgbool WebRtcVideoCapturer::Init(webrtc::VideoCaptureModule* module) {
21228e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org  if (module_) {
21328e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org    LOG(LS_ERROR) << "The capturer is already initialized";
21428e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org    return false;
21528e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org  }
21628e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org  if (!module) {
21728e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org    LOG(LS_ERROR) << "Invalid VCM supplied";
21828e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org    return false;
21928e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org  }
22028e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org  // TODO(juberti): Set id and formats.
22128e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org  (module_ = module)->AddRef();
22228e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org  return true;
22328e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org}
22428e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org
22528e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.orgbool WebRtcVideoCapturer::GetBestCaptureFormat(const VideoFormat& desired,
22628e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org                                               VideoFormat* best_format) {
22728e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org  if (!best_format) {
22828e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org    return false;
22928e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org  }
23028e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org
23128e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org  if (!VideoCapturer::GetBestCaptureFormat(desired, best_format)) {
23228e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org    // We maybe using a manually injected VCM which doesn't support enum.
23328e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org    // Use the desired format as the best format.
23428e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org    best_format->width = desired.width;
23528e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org    best_format->height = desired.height;
23628e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org    best_format->fourcc = FOURCC_I420;
23728e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org    best_format->interval = desired.interval;
23828e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org    LOG(LS_INFO) << "Failed to find best capture format,"
23928e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org                 << " fall back to the requested format "
24028e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org                 << best_format->ToString();
24128e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org  }
24228e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org  return true;
24328e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org}
24428e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org
24528e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.orgCaptureState WebRtcVideoCapturer::Start(const VideoFormat& capture_format) {
24628e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org  if (!module_) {
24728e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org    LOG(LS_ERROR) << "The capturer has not been initialized";
24828e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org    return CS_NO_DEVICE;
24928e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org  }
25028e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org
25128e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org  // TODO(hellner): weird to return failure when it is in fact actually running.
25228e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org  if (IsRunning()) {
25328e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org    LOG(LS_ERROR) << "The capturer is already running";
25428e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org    return CS_FAILED;
25528e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org  }
25628e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org
25728e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org  SetCaptureFormat(&capture_format);
25828e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org
25928e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org  webrtc::VideoCaptureCapability cap;
26028e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org  if (!FormatToCapability(capture_format, &cap)) {
26128e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org    LOG(LS_ERROR) << "Invalid capture format specified";
26228e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org    return CS_FAILED;
26328e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org  }
26428e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org
26528e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org  std::string camera_id(GetId());
26628e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org  uint32 start = talk_base::Time();
2677433a088d2e97993266b66c102b0866aa90b4424mallinath@webrtc.org  module_->RegisterCaptureDataCallback(*this);
2687433a088d2e97993266b66c102b0866aa90b4424mallinath@webrtc.org  if (module_->StartCapture(cap) != 0) {
26928e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org    LOG(LS_ERROR) << "Camera '" << camera_id << "' failed to start";
27028e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org    return CS_FAILED;
27128e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org  }
27228e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org
27328e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org  LOG(LS_INFO) << "Camera '" << camera_id << "' started with format "
27428e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org               << capture_format.ToString() << ", elapsed time "
27528e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org               << talk_base::TimeSince(start) << " ms";
27628e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org
27728e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org  captured_frames_ = 0;
27828e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org  SetCaptureState(CS_RUNNING);
27928e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org  return CS_STARTING;
28028e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org}
28128e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org
282f6d6ed0c66457170be3f3b2bc214cd7141e441a4wu@webrtc.org// Critical section blocks Stop from shutting down during callbacks from capture
283f6d6ed0c66457170be3f3b2bc214cd7141e441a4wu@webrtc.org// thread to OnIncomingCapturedFrame. Note that the crit is try-locked in
284f6d6ed0c66457170be3f3b2bc214cd7141e441a4wu@webrtc.org// OnFrameCaptured, as the lock ordering between this and the system component
285f6d6ed0c66457170be3f3b2bc214cd7141e441a4wu@webrtc.org// controlling the camera is reversed: system frame -> OnIncomingCapturedFrame;
286f6d6ed0c66457170be3f3b2bc214cd7141e441a4wu@webrtc.org// Stop -> system stop camera).
28728e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.orgvoid WebRtcVideoCapturer::Stop() {
288f6d6ed0c66457170be3f3b2bc214cd7141e441a4wu@webrtc.org  talk_base::CritScope cs(&critical_section_stopping_);
28928e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org  if (IsRunning()) {
29028e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org    talk_base::Thread::Current()->Clear(this);
29128e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org    module_->StopCapture();
29228e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org    module_->DeRegisterCaptureDataCallback();
29328e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org
29428e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org    // TODO(juberti): Determine if the VCM exposes any drop stats we can use.
29528e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org    double drop_ratio = 0.0;
29628e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org    std::string camera_id(GetId());
29728e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org    LOG(LS_INFO) << "Camera '" << camera_id << "' stopped after capturing "
29828e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org                 << captured_frames_ << " frames and dropping "
29928e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org                 << drop_ratio << "%";
30028e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org  }
30128e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org  SetCaptureFormat(NULL);
30228e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org}
30328e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org
30428e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.orgbool WebRtcVideoCapturer::IsRunning() {
30528e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org  return (module_ != NULL && module_->CaptureStarted());
30628e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org}
30728e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org
30828e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.orgbool WebRtcVideoCapturer::GetPreferredFourccs(
30928e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org    std::vector<uint32>* fourccs) {
31028e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org  if (!fourccs) {
31128e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org    return false;
31228e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org  }
31328e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org
31428e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org  fourccs->clear();
31528e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org  for (size_t i = 0; i < ARRAY_SIZE(kSupportedFourCCs); ++i) {
31628e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org    fourccs->push_back(kSupportedFourCCs[i].fourcc);
31728e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org  }
31828e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org  return true;
31928e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org}
32028e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org
32128e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.orgvoid WebRtcVideoCapturer::OnIncomingCapturedFrame(const int32_t id,
32228e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org    webrtc::I420VideoFrame& sample) {
323f6d6ed0c66457170be3f3b2bc214cd7141e441a4wu@webrtc.org  // This would be a normal CritScope, except that it's possible that:
324f6d6ed0c66457170be3f3b2bc214cd7141e441a4wu@webrtc.org  // (1) whatever system component producing this frame has taken a lock, and
325f6d6ed0c66457170be3f3b2bc214cd7141e441a4wu@webrtc.org  // (2) Stop() probably calls back into that system component, which may take
326f6d6ed0c66457170be3f3b2bc214cd7141e441a4wu@webrtc.org  // the same lock. Due to the reversed order, we have to try-lock in order to
327f6d6ed0c66457170be3f3b2bc214cd7141e441a4wu@webrtc.org  // avoid a potential deadlock. Besides, if we can't enter because we're
328f6d6ed0c66457170be3f3b2bc214cd7141e441a4wu@webrtc.org  // stopping, we may as well drop the frame.
329f6d6ed0c66457170be3f3b2bc214cd7141e441a4wu@webrtc.org  talk_base::TryCritScope cs(&critical_section_stopping_);
330f6d6ed0c66457170be3f3b2bc214cd7141e441a4wu@webrtc.org  if (!cs.locked() || !IsRunning()) {
331f6d6ed0c66457170be3f3b2bc214cd7141e441a4wu@webrtc.org    // Capturer has been stopped or is in the process of stopping.
332f6d6ed0c66457170be3f3b2bc214cd7141e441a4wu@webrtc.org    return;
333f6d6ed0c66457170be3f3b2bc214cd7141e441a4wu@webrtc.org  }
33428e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org
33528e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org  ++captured_frames_;
33628e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org  // Log the size and pixel aspect ratio of the first captured frame.
33728e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org  if (1 == captured_frames_) {
33828e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org    LOG(LS_INFO) << "Captured frame size "
33928e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org                 << sample.width() << "x" << sample.height()
34028e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org                 << ". Expected format " << GetCaptureFormat()->ToString();
34128e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org  }
34228e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org
34328e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org  // Signal down stream components on captured frame.
34428e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org  // The CapturedFrame class doesn't support planes. We have to ExtractBuffer
34528e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org  // to one block for it.
34628e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org  int length = webrtc::CalcBufferSize(webrtc::kI420,
34728e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org                                      sample.width(), sample.height());
34816d6254e8c6c865ca65cc943e03fa635dc5c6a63wu@webrtc.org  capture_buffer_.resize(length);
34916d6254e8c6c865ca65cc943e03fa635dc5c6a63wu@webrtc.org  // TODO(ronghuawu): Refactor the WebRtcCapturedFrame to avoid memory copy.
35016d6254e8c6c865ca65cc943e03fa635dc5c6a63wu@webrtc.org  webrtc::ExtractBuffer(sample, length, &capture_buffer_[0]);
35116d6254e8c6c865ca65cc943e03fa635dc5c6a63wu@webrtc.org  WebRtcCapturedFrame frame(sample, &capture_buffer_[0], length);
35228e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org  SignalFrameCaptured(this, &frame);
35328e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org}
35428e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org
35528e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.orgvoid WebRtcVideoCapturer::OnCaptureDelayChanged(const int32_t id,
35628e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org                                                const int32_t delay) {
35728e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org  LOG(LS_INFO) << "Capture delay changed to " << delay << " ms";
35828e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org}
35928e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org
36028e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org// WebRtcCapturedFrame
36128e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.orgWebRtcCapturedFrame::WebRtcCapturedFrame(const webrtc::I420VideoFrame& sample,
36228e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org                                         void* buffer,
36328e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org                                         int length) {
36428e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org  width = sample.width();
36528e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org  height = sample.height();
36628e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org  fourcc = FOURCC_I420;
36728e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org  // TODO(hellner): Support pixel aspect ratio (for OSX).
36828e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org  pixel_width = 1;
36928e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org  pixel_height = 1;
37028e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org  // Convert units from VideoFrame RenderTimeMs to CapturedFrame (nanoseconds).
37128e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org  elapsed_time = sample.render_time_ms() * talk_base::kNumNanosecsPerMillisec;
37228e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org  time_stamp = elapsed_time;
37328e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org  data_size = length;
37428e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org  data = buffer;
37528e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org}
37628e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org
37728e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org}  // namespace cricket
37828e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org
37928e20752806a492f5a6a5d343c02f9556f39b1cdhenrike@webrtc.org#endif  // HAVE_WEBRTC_VIDEO
380