15976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org// libjingle
25976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org// Copyright 2010 Google Inc.
35976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org//
45976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org// Redistribution and use in source and binary forms, with or without
55976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org// modification, are permitted provided that the following conditions are met:
65976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org//
75976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org//  1. Redistributions of source code must retain the above copyright notice,
85976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org//     this list of conditions and the following disclaimer.
95976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org//  2. Redistributions in binary form must reproduce the above copyright notice,
105976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org//     this list of conditions and the following disclaimer in the documentation
115976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org//     and/or other materials provided with the distribution.
125976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org//  3. The name of the author may not be used to endorse or promote products
135976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org//     derived from this software without specific prior written permission.
145976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org//
155976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
165976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
175976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
185976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org// EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
195976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
205976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
215976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org// OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
225976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
235976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
245976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
255976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org//
265976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org// Implementation file of class VideoCapturer.
275976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
285976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org#include "talk/media/base/videocapturer.h"
295976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
305976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org#include <algorithm>
315976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
325976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org#if !defined(DISABLE_YUV)
335976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org#include "libyuv/scale_argb.h"
345976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org#endif
355976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org#include "talk/base/common.h"
365976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org#include "talk/base/logging.h"
375976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org#include "talk/base/systeminfo.h"
385976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org#include "talk/media/base/videoprocessor.h"
395976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
405976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org#if defined(HAVE_WEBRTC_VIDEO)
415976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org#include "talk/media/webrtc/webrtcvideoframe.h"
425976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org#endif  // HAVE_WEBRTC_VIDEO
435976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
445976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
455976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgnamespace cricket {
465976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
475976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgnamespace {
485976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
495976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org// TODO(thorcarpenter): This is a BIG hack to flush the system with black
505976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org// frames. Frontends should coordinate to update the video state of a muted
515976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org// user. When all frontends to this consider removing the black frame business.
525976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgconst int kNumBlackFramesOnMute = 30;
535976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
545976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org// MessageHandler constants.
555976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgenum {
565976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  MSG_DO_PAUSE = 0,
575976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  MSG_DO_UNPAUSE,
585976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  MSG_STATE_CHANGE
595976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org};
605976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
615976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgstatic const int64 kMaxDistance = ~(static_cast<int64>(1) << 63);
625976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgstatic const int kYU12Penalty = 16;  // Needs to be higher than MJPG index.
635976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgstatic const int kDefaultScreencastFps = 5;
645976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgtypedef talk_base::TypedMessageData<CaptureState> StateChangeParams;
655976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
665976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org}  // namespace
675976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
685976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org/////////////////////////////////////////////////////////////////////
695976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org// Implementation of struct CapturedFrame
705976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org/////////////////////////////////////////////////////////////////////
715976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgCapturedFrame::CapturedFrame()
725976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    : width(0),
735976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      height(0),
745976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      fourcc(0),
755976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      pixel_width(0),
765976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      pixel_height(0),
775976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      elapsed_time(0),
785976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      time_stamp(0),
795976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      data_size(0),
805976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      rotation(0),
815976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      data(NULL) {}
825976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
835976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org// TODO(fbarchard): Remove this function once lmimediaengine stops using it.
845976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgbool CapturedFrame::GetDataSize(uint32* size) const {
855976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  if (!size || data_size == CapturedFrame::kUnknownDataSize) {
865976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    return false;
875976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
885976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  *size = data_size;
895976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  return true;
905976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org}
915976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
925976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org/////////////////////////////////////////////////////////////////////
935976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org// Implementation of class VideoCapturer
945976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org/////////////////////////////////////////////////////////////////////
955976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgVideoCapturer::VideoCapturer() : thread_(talk_base::Thread::Current()) {
965976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  Construct();
975976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org}
985976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
995976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgVideoCapturer::VideoCapturer(talk_base::Thread* thread) : thread_(thread) {
1005976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  Construct();
1015976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org}
1025976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
1035976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgvoid VideoCapturer::Construct() {
1045976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  ClearAspectRatio();
1055976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  enable_camera_list_ = false;
1065976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  capture_state_ = CS_STOPPED;
1075976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  SignalFrameCaptured.connect(this, &VideoCapturer::OnFrameCaptured);
1085976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  scaled_width_ = 0;
1095976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  scaled_height_ = 0;
1105976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  muted_ = false;
1115976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  black_frame_count_down_ = kNumBlackFramesOnMute;
1125976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org}
1135976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
1145976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgconst std::vector<VideoFormat>* VideoCapturer::GetSupportedFormats() const {
1155976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  return &filtered_supported_formats_;
1165976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org}
1175976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
1185976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgbool VideoCapturer::StartCapturing(const VideoFormat& capture_format) {
1195976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  CaptureState result = Start(capture_format);
1205976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  const bool success = (result == CS_RUNNING) || (result == CS_STARTING);
1215976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  if (!success) {
1225976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    return false;
1235976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
1245976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  if (result == CS_RUNNING) {
1255976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    SetCaptureState(result);
1265976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
1275976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  return true;
1285976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org}
1295976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
1305976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgvoid VideoCapturer::UpdateAspectRatio(int ratio_w, int ratio_h) {
1315976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  if (ratio_w == 0 || ratio_h == 0) {
1325976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    LOG(LS_WARNING) << "UpdateAspectRatio ignored invalid ratio: "
1335976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org                    << ratio_w << "x" << ratio_h;
1345976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    return;
1355976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
1365976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  ratio_w_ = ratio_w;
1375976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  ratio_h_ = ratio_h;
1385976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org}
1395976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
1405976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgvoid VideoCapturer::ClearAspectRatio() {
1415976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  ratio_w_ = 0;
1425976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  ratio_h_ = 0;
1435976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org}
1445976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
1455976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org// Override this to have more control of how your device is started/stopped.
1465976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgbool VideoCapturer::Pause(bool pause) {
1475976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  if (pause) {
1485976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    if (capture_state() == CS_PAUSED) {
1495976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      return true;
1505976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    }
1515976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    bool is_running = capture_state() == CS_STARTING ||
1525976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        capture_state() == CS_RUNNING;
1535976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    if (!is_running) {
1545976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      LOG(LS_ERROR) << "Cannot pause a stopped camera.";
1555976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      return false;
1565976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    }
1575976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    LOG(LS_INFO) << "Pausing a camera.";
1585976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    talk_base::scoped_ptr<VideoFormat> capture_format_when_paused(
1595976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        capture_format_ ? new VideoFormat(*capture_format_) : NULL);
1605976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    Stop();
1615976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    SetCaptureState(CS_PAUSED);
1625976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    // If you override this function be sure to restore the capture format
1635976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    // after calling Stop().
1645976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    SetCaptureFormat(capture_format_when_paused.get());
1655976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  } else {  // Unpause.
1665976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    if (capture_state() != CS_PAUSED) {
1675976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      LOG(LS_WARNING) << "Cannot unpause a camera that hasn't been paused.";
1685976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      return false;
1695976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    }
1705976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    if (!capture_format_) {
1715976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      LOG(LS_ERROR) << "Missing capture_format_, cannot unpause a camera.";
1725976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      return false;
1735976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    }
1745976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    if (muted_) {
1755976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      LOG(LS_WARNING) << "Camera cannot be unpaused while muted.";
1765976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      return false;
1775976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    }
1785976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    LOG(LS_INFO) << "Unpausing a camera.";
1795976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    if (!Start(*capture_format_)) {
1805976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      LOG(LS_ERROR) << "Camera failed to start when unpausing.";
1815976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      return false;
1825976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    }
1835976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
1845976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  return true;
1855976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org}
1865976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
1875976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgbool VideoCapturer::Restart(const VideoFormat& capture_format) {
1885976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  if (!IsRunning()) {
1895976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    return StartCapturing(capture_format);
1905976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
1915976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
1925976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  if (GetCaptureFormat() != NULL && *GetCaptureFormat() == capture_format) {
1935976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    // The reqested format is the same; nothing to do.
1945976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    return true;
1955976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
1965976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
1975976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  Stop();
1985976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  return StartCapturing(capture_format);
1995976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org}
2005976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
2015976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgbool VideoCapturer::MuteToBlackThenPause(bool muted) {
2025976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  if (muted == IsMuted()) {
2035976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    return true;
2045976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
2055976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
2065976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  LOG(LS_INFO) << (muted ? "Muting" : "Unmuting") << " this video capturer.";
2075976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  muted_ = muted;  // Do this before calling Pause().
2085976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  if (muted) {
2095976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    // Reset black frame count down.
2105976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    black_frame_count_down_ = kNumBlackFramesOnMute;
2115976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    // Following frames will be overritten with black, then the camera will be
2125976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    // paused.
2135976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    return true;
2145976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
2155976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  // Start the camera.
2165976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  thread_->Clear(this, MSG_DO_PAUSE);
2175976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  return Pause(false);
2185976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org}
2195976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
2205976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgvoid VideoCapturer::SetSupportedFormats(
2215976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    const std::vector<VideoFormat>& formats) {
2225976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  supported_formats_ = formats;
2235976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  UpdateFilteredSupportedFormats();
2245976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org}
2255976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
2265976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgbool VideoCapturer::GetBestCaptureFormat(const VideoFormat& format,
2275976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org                                         VideoFormat* best_format) {
2285976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  // TODO(fbarchard): Directly support max_format.
2295976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  UpdateFilteredSupportedFormats();
2305976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  const std::vector<VideoFormat>* supported_formats = GetSupportedFormats();
2315976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
2325976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  if (supported_formats->empty()) {
2335976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    return false;
2345976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
2355976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  LOG(LS_INFO) << " Capture Requested " << format.ToString();
2365976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  int64 best_distance = kMaxDistance;
2375976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  std::vector<VideoFormat>::const_iterator best = supported_formats->end();
2385976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  std::vector<VideoFormat>::const_iterator i;
2395976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  for (i = supported_formats->begin(); i != supported_formats->end(); ++i) {
2405976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    int64 distance = GetFormatDistance(format, *i);
2415976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    // TODO(fbarchard): Reduce to LS_VERBOSE if/when camera capture is
2425976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    // relatively bug free.
2435976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    LOG(LS_INFO) << " Supported " << i->ToString() << " distance " << distance;
2445976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    if (distance < best_distance) {
2455976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      best_distance = distance;
2465976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      best = i;
2475976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    }
2485976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
2495976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  if (supported_formats->end() == best) {
2505976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    LOG(LS_ERROR) << " No acceptable camera format found";
2515976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    return false;
2525976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
2535976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
2545976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  if (best_format) {
2555976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    best_format->width = best->width;
2565976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    best_format->height = best->height;
2575976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    best_format->fourcc = best->fourcc;
2585976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    best_format->interval = talk_base::_max(format.interval, best->interval);
2595976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    LOG(LS_INFO) << " Best " << best_format->ToString() << " Interval "
2605976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org                 << best_format->interval << " distance " << best_distance;
2615976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
2625976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  return true;
2635976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org}
2645976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
2655976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgvoid VideoCapturer::AddVideoProcessor(VideoProcessor* video_processor) {
2665976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  talk_base::CritScope cs(&crit_);
2675976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  ASSERT(std::find(video_processors_.begin(), video_processors_.end(),
2685976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org                   video_processor) == video_processors_.end());
2695976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  video_processors_.push_back(video_processor);
2705976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org}
2715976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
2725976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgbool VideoCapturer::RemoveVideoProcessor(VideoProcessor* video_processor) {
2735976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  talk_base::CritScope cs(&crit_);
2745976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  VideoProcessors::iterator found = std::find(
2755976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      video_processors_.begin(), video_processors_.end(), video_processor);
2765976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  if (found == video_processors_.end()) {
2775976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    return false;
2785976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
2795976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  video_processors_.erase(found);
2805976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  return true;
2815976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org}
2825976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
2835976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgvoid VideoCapturer::ConstrainSupportedFormats(const VideoFormat& max_format) {
2845976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  max_format_.reset(new VideoFormat(max_format));
2855976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  LOG(LS_VERBOSE) << " ConstrainSupportedFormats " << max_format.ToString();
2865976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  UpdateFilteredSupportedFormats();
2875976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org}
2885976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
2895976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgstd::string VideoCapturer::ToString(const CapturedFrame* captured_frame) const {
2905976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  std::string fourcc_name = GetFourccName(captured_frame->fourcc) + " ";
2915976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  for (std::string::const_iterator i = fourcc_name.begin();
2925976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org       i < fourcc_name.end(); ++i) {
2935976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    // Test character is printable; Avoid isprint() which asserts on negatives.
2945976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    if (*i < 32 || *i >= 127) {
2955976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      fourcc_name = "";
2965976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      break;
2975976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    }
2985976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
2995976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
3005976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  std::ostringstream ss;
3015976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  ss << fourcc_name << captured_frame->width << "x" << captured_frame->height
3025976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org     << "x" << VideoFormat::IntervalToFps(captured_frame->elapsed_time);
3035976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  return ss.str();
3045976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org}
3055976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
3065976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgvoid VideoCapturer::OnFrameCaptured(VideoCapturer*,
3075976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org                                    const CapturedFrame* captured_frame) {
3085976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  if (muted_) {
3095976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    if (black_frame_count_down_ == 0) {
3105976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      thread_->Post(this, MSG_DO_PAUSE, NULL);
3115976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    } else {
3125976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      --black_frame_count_down_;
3135976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    }
3145976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
3155976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
3165976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  if (SignalVideoFrame.is_empty()) {
3175976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    return;
3185976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
3195976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org#if defined(HAVE_WEBRTC_VIDEO)
3205976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org#define VIDEO_FRAME_NAME WebRtcVideoFrame
3215976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org#endif
3225976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org#if defined(VIDEO_FRAME_NAME)
3235976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org#if !defined(DISABLE_YUV)
3245976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  if (IsScreencast()) {
3255976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    int scaled_width, scaled_height;
3265976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    int desired_screencast_fps = capture_format_.get() ?
3275976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        VideoFormat::IntervalToFps(capture_format_->interval) :
3285976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        kDefaultScreencastFps;
3295976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    ComputeScale(captured_frame->width, captured_frame->height,
3305976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org                 desired_screencast_fps, &scaled_width, &scaled_height);
3315976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
3325976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    if (scaled_width != scaled_width_ || scaled_height != scaled_height_) {
3335976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      LOG(LS_VERBOSE) << "Scaling Screencast from "
3345976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org                      << captured_frame->width << "x"
3355976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org                      << captured_frame->height << " to "
3365976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org                      << scaled_width << "x" << scaled_height;
3375976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      scaled_width_ = scaled_width;
3385976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      scaled_height_ = scaled_height;
3395976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    }
3405976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    if (FOURCC_ARGB == captured_frame->fourcc &&
3415976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        (scaled_width != captured_frame->height ||
3425976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org         scaled_height != captured_frame->height)) {
3435976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      CapturedFrame* scaled_frame = const_cast<CapturedFrame*>(captured_frame);
3445976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      // Compute new width such that width * height is less than maximum but
3455976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      // maintains original captured frame aspect ratio.
3465976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      // Round down width to multiple of 4 so odd width won't round up beyond
3475976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      // maximum, and so chroma channel is even width to simplify spatial
3485976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      // resampling.
3495976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      libyuv::ARGBScale(reinterpret_cast<const uint8*>(captured_frame->data),
3505976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org                        captured_frame->width * 4, captured_frame->width,
3515976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org                        captured_frame->height,
3525976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org                        reinterpret_cast<uint8*>(scaled_frame->data),
3535976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org                        scaled_width * 4, scaled_width, scaled_height,
3545976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org                        libyuv::kFilterBilinear);
3555976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      scaled_frame->width = scaled_width;
3565976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      scaled_frame->height = scaled_height;
3575976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      scaled_frame->data_size = scaled_width * 4 * scaled_height;
3585976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    }
3595976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
3605976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org#endif  // !DISABLE_YUV
3615976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        // Size to crop captured frame to.  This adjusts the captured frames
3625976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        // aspect ratio to match the final view aspect ratio, considering pixel
3635976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  // aspect ratio and rotation.  The final size may be scaled down by video
3645976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  // adapter to better match ratio_w_ x ratio_h_.
3655976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  // Note that abs() of frame height is passed in, because source may be
3665976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  // inverted, but output will be positive.
3675976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  int desired_width = captured_frame->width;
3685976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  int desired_height = captured_frame->height;
3695976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
3705976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  // TODO(fbarchard): Improve logic to pad or crop.
3715976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  // MJPG can crop vertically, but not horizontally.  This logic disables crop.
3725976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  // Alternatively we could pad the image with black, or implement a 2 step
3735976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  // crop.
3745976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  bool can_crop = true;
3755976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  if (captured_frame->fourcc == FOURCC_MJPG) {
3765976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    float cam_aspect = static_cast<float>(captured_frame->width) /
3775976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        static_cast<float>(captured_frame->height);
3785976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    float view_aspect = static_cast<float>(ratio_w_) /
3795976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        static_cast<float>(ratio_h_);
3805976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    can_crop = cam_aspect <= view_aspect;
3815976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
3825976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  if (can_crop && !IsScreencast()) {
3835976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    // TODO(ronghuawu): The capturer should always produce the native
3845976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    // resolution and the cropping should be done in downstream code.
3855976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    ComputeCrop(ratio_w_, ratio_h_, captured_frame->width,
3865976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org                abs(captured_frame->height), captured_frame->pixel_width,
3875976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org                captured_frame->pixel_height, captured_frame->rotation,
3885976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org                &desired_width, &desired_height);
3895976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
3905976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
3915976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  VIDEO_FRAME_NAME i420_frame;
3925976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  if (!i420_frame.Init(captured_frame, desired_width, desired_height)) {
3935976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    // TODO(fbarchard): LOG more information about captured frame attributes.
3945976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    LOG(LS_ERROR) << "Couldn't convert to I420! "
3955976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org                  << "From " << ToString(captured_frame) << " To "
3965976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org                  << desired_width << " x " << desired_height;
3975976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    return;
3985976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
3995976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  if (!muted_ && !ApplyProcessors(&i420_frame)) {
4005976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    // Processor dropped the frame.
4015976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    return;
4025976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
4035976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  if (muted_) {
4045976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    i420_frame.SetToBlack();
4055976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
4065976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  SignalVideoFrame(this, &i420_frame);
4075976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org#endif  // VIDEO_FRAME_NAME
4085976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org}
4095976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
4105976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgvoid VideoCapturer::SetCaptureState(CaptureState state) {
4115976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  if (state == capture_state_) {
4125976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    // Don't trigger a state changed callback if the state hasn't changed.
4135976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    return;
4145976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
4155976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  StateChangeParams* state_params = new StateChangeParams(state);
4165976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  capture_state_ = state;
4175976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  thread_->Post(this, MSG_STATE_CHANGE, state_params);
4185976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org}
4195976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
4205976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgvoid VideoCapturer::OnMessage(talk_base::Message* message) {
4215976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  switch (message->message_id) {
4225976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    case MSG_STATE_CHANGE: {
4235976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      talk_base::scoped_ptr<StateChangeParams> p(
4245976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org          static_cast<StateChangeParams*>(message->pdata));
4255976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      SignalStateChange(this, p->data());
4265976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      break;
4275976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    }
4285976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    case MSG_DO_PAUSE: {
4295976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      Pause(true);
4305976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      break;
4315976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    }
4325976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    case MSG_DO_UNPAUSE: {
4335976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      Pause(false);
4345976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      break;
4355976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    }
4365976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    default: {
4375976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      ASSERT(false);
4385976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    }
4395976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
4405976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org}
4415976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
4425976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org// Get the distance between the supported and desired formats.
4435976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org// Prioritization is done according to this algorithm:
4445976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org// 1) Width closeness. If not same, we prefer wider.
4455976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org// 2) Height closeness. If not same, we prefer higher.
4465976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org// 3) Framerate closeness. If not same, we prefer faster.
4475976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org// 4) Compression. If desired format has a specific fourcc, we need exact match;
4485976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org//                otherwise, we use preference.
4495976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgint64 VideoCapturer::GetFormatDistance(const VideoFormat& desired,
4505976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org                                       const VideoFormat& supported) {
4515976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  int64 distance = kMaxDistance;
4525976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
4535976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  // Check fourcc.
4545976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  uint32 supported_fourcc = CanonicalFourCC(supported.fourcc);
4555976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  int64 delta_fourcc = kMaxDistance;
4565976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  if (FOURCC_ANY == desired.fourcc) {
4575976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    // Any fourcc is OK for the desired. Use preference to find best fourcc.
4585976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    std::vector<uint32> preferred_fourccs;
4595976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    if (!GetPreferredFourccs(&preferred_fourccs)) {
4605976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      return distance;
4615976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    }
4625976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
4635976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    for (size_t i = 0; i < preferred_fourccs.size(); ++i) {
4645976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      if (supported_fourcc == CanonicalFourCC(preferred_fourccs[i])) {
4655976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        delta_fourcc = i;
4665976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org#ifdef LINUX
4675976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        // For HD avoid YU12 which is a software conversion and has 2 bugs
4685976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        // b/7326348 b/6960899.  Reenable when fixed.
4695976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        if (supported.height >= 720 && (supported_fourcc == FOURCC_YU12 ||
4705976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org                                        supported_fourcc == FOURCC_YV12)) {
4715976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org          delta_fourcc += kYU12Penalty;
4725976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        }
4735976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org#endif
4745976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        break;
4755976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      }
4765976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    }
4775976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  } else if (supported_fourcc == CanonicalFourCC(desired.fourcc)) {
4785976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    delta_fourcc = 0;  // Need exact match.
4795976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
4805976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
4815976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  if (kMaxDistance == delta_fourcc) {
4825976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    // Failed to match fourcc.
4835976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    return distance;
4845976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
4855976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
4865976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  // Check resolution and fps.
4875976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  int desired_width = desired.width;
4885976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  int desired_height = desired.height;
4895976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  int64 delta_w = supported.width - desired_width;
4905976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  int64 supported_fps = VideoFormat::IntervalToFps(supported.interval);
4915976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  int64 delta_fps =
4925976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      supported_fps - VideoFormat::IntervalToFps(desired.interval);
4935976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  // Check height of supported height compared to height we would like it to be.
4945976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  int64 aspect_h =
4955976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      desired_width ? supported.width * desired_height / desired_width
4965976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org                    : desired_height;
4975976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  int64 delta_h = supported.height - aspect_h;
4985976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
4995976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  distance = 0;
5005976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  // Set high penalty if the supported format is lower than the desired format.
5015976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  // 3x means we would prefer down to down to 3/4, than up to double.
5025976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  // But we'd prefer up to double than down to 1/2.  This is conservative,
5035976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  // strongly avoiding going down in resolution, similar to
5045976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  // the old method, but not completely ruling it out in extreme situations.
5055976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  // It also ignores framerate, which is often very low at high resolutions.
5065976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  // TODO(fbarchard): Improve logic to use weighted factors.
5075976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  static const int kDownPenalty = -3;
5085976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  if (delta_w < 0) {
5095976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    delta_w = delta_w * kDownPenalty;
5105976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
5115976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  if (delta_h < 0) {
5125976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    delta_h = delta_h * kDownPenalty;
5135976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
5145976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  // Require camera fps to be at least 80% of what is requested if resolution
5155976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  // matches.
5165976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  // Require camera fps to be at least 96% of what is requested, or higher,
5175976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  // if resolution differs. 96% allows for slight variations in fps. e.g. 29.97
5185976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  if (delta_fps < 0) {
5195976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    int64 min_desirable_fps = delta_w ?
5205976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    VideoFormat::IntervalToFps(desired.interval) * 29 / 30 :
5215976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    VideoFormat::IntervalToFps(desired.interval) * 24 / 30;
5225976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    delta_fps = -delta_fps;
5235976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    if (supported_fps < min_desirable_fps) {
5245976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      distance |= static_cast<int64>(1) << 62;
5255976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    } else {
5265976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      distance |= static_cast<int64>(1) << 15;
5275976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    }
5285976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
5295976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
5305976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  // 12 bits for width and height and 8 bits for fps and fourcc.
5315976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  distance |=
5325976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      (delta_w << 28) | (delta_h << 16) | (delta_fps << 8) | delta_fourcc;
5335976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
5345976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  return distance;
5355976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org}
5365976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
5375976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgbool VideoCapturer::ApplyProcessors(VideoFrame* video_frame) {
5385976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  bool drop_frame = false;
5395976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  talk_base::CritScope cs(&crit_);
5405976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  for (VideoProcessors::iterator iter = video_processors_.begin();
5415976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org       iter != video_processors_.end(); ++iter) {
5425976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    (*iter)->OnFrame(kDummyVideoSsrc, video_frame, &drop_frame);
5435976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    if (drop_frame) {
5445976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      return false;
5455976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    }
5465976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
5475976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  return true;
5485976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org}
5495976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
5505976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgvoid VideoCapturer::UpdateFilteredSupportedFormats() {
5515976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  filtered_supported_formats_.clear();
5525976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  filtered_supported_formats_ = supported_formats_;
5535976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  if (!max_format_) {
5545976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    return;
5555976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
5565976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  std::vector<VideoFormat>::iterator iter = filtered_supported_formats_.begin();
5575976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  while (iter != filtered_supported_formats_.end()) {
5585976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    if (ShouldFilterFormat(*iter)) {
5595976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      iter = filtered_supported_formats_.erase(iter);
5605976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    } else {
5615976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      ++iter;
5625976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    }
5635976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
5645976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  if (filtered_supported_formats_.empty()) {
5655976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    // The device only captures at resolutions higher than |max_format_| this
5665976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    // indicates that |max_format_| should be ignored as it is better to capture
5675976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    // at too high a resolution than to not capture at all.
5685976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    filtered_supported_formats_ = supported_formats_;
5695976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
5705976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org}
5715976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
5725976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgbool VideoCapturer::ShouldFilterFormat(const VideoFormat& format) const {
5735976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  if (!enable_camera_list_) {
5745976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    return false;
5755976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
5765976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  return format.width > max_format_->width ||
5775976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org         format.height > max_format_->height;
5785976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org}
5795976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
5805976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org}  // namespace cricket
581