10e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org// libjingle
20e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org// Copyright 2010 Google Inc.
30e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org//
40e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org// Redistribution and use in source and binary forms, with or without
50e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org// modification, are permitted provided that the following conditions are met:
60e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org//
70e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org//  1. Redistributions of source code must retain the above copyright notice,
80e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org//     this list of conditions and the following disclaimer.
90e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org//  2. Redistributions in binary form must reproduce the above copyright notice,
100e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org//     this list of conditions and the following disclaimer in the documentation
110e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org//     and/or other materials provided with the distribution.
120e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org//  3. The name of the author may not be used to endorse or promote products
130e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org//     derived from this software without specific prior written permission.
140e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org//
150e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
160e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
170e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
180e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org// EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
190e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
200e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
210e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org// OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
220e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
230e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
240e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
250e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org//
260e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org// Implementation file of class VideoCapturer.
270e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
280e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org#include "talk/media/base/videocapturer.h"
290e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
300e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org#include <algorithm>
310e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
320e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org#if !defined(DISABLE_YUV)
330e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org#include "libyuv/scale_argb.h"
340e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org#endif
35cf81adffe15fa8ea0f333432e41f6d504148f18abuildbot@webrtc.org#include "talk/media/base/videoframefactory.h"
36cf81adffe15fa8ea0f333432e41f6d504148f18abuildbot@webrtc.org#include "talk/media/base/videoprocessor.h"
372a86ce22ccc387dfa6f8a98ce3eba5c1e6f9e538buildbot@webrtc.org#include "webrtc/base/common.h"
382a86ce22ccc387dfa6f8a98ce3eba5c1e6f9e538buildbot@webrtc.org#include "webrtc/base/logging.h"
392a86ce22ccc387dfa6f8a98ce3eba5c1e6f9e538buildbot@webrtc.org#include "webrtc/base/systeminfo.h"
400e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
410e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org#if defined(HAVE_WEBRTC_VIDEO)
420e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org#include "talk/media/webrtc/webrtcvideoframe.h"
432a0553609b5b6d1d4dce0366b334dc9ef8aa4d65buildbot@webrtc.org#include "talk/media/webrtc/webrtcvideoframefactory.h"
440e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org#endif  // HAVE_WEBRTC_VIDEO
450e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
460e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orgnamespace cricket {
470e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
480e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orgnamespace {
490e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
500e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org// TODO(thorcarpenter): This is a BIG hack to flush the system with black
510e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org// frames. Frontends should coordinate to update the video state of a muted
520e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org// user. When all frontends to this consider removing the black frame business.
530e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orgconst int kNumBlackFramesOnMute = 30;
540e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
550e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org// MessageHandler constants.
560e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orgenum {
570e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  MSG_DO_PAUSE = 0,
580e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  MSG_DO_UNPAUSE,
590e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  MSG_STATE_CHANGE
600e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org};
610e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
620e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orgstatic const int64 kMaxDistance = ~(static_cast<int64>(1) << 63);
63c47d0d933f5c12781b4be695de79a709255bc8afhenrike@webrtc.org#ifdef LINUX
640e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orgstatic const int kYU12Penalty = 16;  // Needs to be higher than MJPG index.
65c47d0d933f5c12781b4be695de79a709255bc8afhenrike@webrtc.org#endif
660e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orgstatic const int kDefaultScreencastFps = 5;
672a86ce22ccc387dfa6f8a98ce3eba5c1e6f9e538buildbot@webrtc.orgtypedef rtc::TypedMessageData<CaptureState> StateChangeParams;
680e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
697587c5e0b2fb5100b52bf271370ee1369ba18690henrike@webrtc.org// Limit stats data collections to ~20 seconds of 30fps data before dropping
707587c5e0b2fb5100b52bf271370ee1369ba18690henrike@webrtc.org// old data in case stats aren't reset for long periods of time.
717587c5e0b2fb5100b52bf271370ee1369ba18690henrike@webrtc.orgstatic const size_t kMaxAccumulatorSize = 600;
727587c5e0b2fb5100b52bf271370ee1369ba18690henrike@webrtc.org
730e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org}  // namespace
740e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
750e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org/////////////////////////////////////////////////////////////////////
760e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org// Implementation of struct CapturedFrame
770e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org/////////////////////////////////////////////////////////////////////
780e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orgCapturedFrame::CapturedFrame()
790e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    : width(0),
800e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      height(0),
810e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      fourcc(0),
820e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      pixel_width(0),
830e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      pixel_height(0),
840e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      elapsed_time(0),
850e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      time_stamp(0),
860e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      data_size(0),
870e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      rotation(0),
880e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      data(NULL) {}
890e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
900e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org// TODO(fbarchard): Remove this function once lmimediaengine stops using it.
910e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orgbool CapturedFrame::GetDataSize(uint32* size) const {
920e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  if (!size || data_size == CapturedFrame::kUnknownDataSize) {
930e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    return false;
940e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  }
950e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  *size = data_size;
960e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  return true;
970e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org}
980e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
990e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org/////////////////////////////////////////////////////////////////////
1000e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org// Implementation of class VideoCapturer
1010e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org/////////////////////////////////////////////////////////////////////
1027587c5e0b2fb5100b52bf271370ee1369ba18690henrike@webrtc.orgVideoCapturer::VideoCapturer()
1032a86ce22ccc387dfa6f8a98ce3eba5c1e6f9e538buildbot@webrtc.org    : thread_(rtc::Thread::Current()),
1047587c5e0b2fb5100b52bf271370ee1369ba18690henrike@webrtc.org      adapt_frame_drops_data_(kMaxAccumulatorSize),
1057587c5e0b2fb5100b52bf271370ee1369ba18690henrike@webrtc.org      effect_frame_drops_data_(kMaxAccumulatorSize),
1067587c5e0b2fb5100b52bf271370ee1369ba18690henrike@webrtc.org      frame_time_data_(kMaxAccumulatorSize) {
1070e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  Construct();
1080e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org}
1090e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
1102a86ce22ccc387dfa6f8a98ce3eba5c1e6f9e538buildbot@webrtc.orgVideoCapturer::VideoCapturer(rtc::Thread* thread)
1117587c5e0b2fb5100b52bf271370ee1369ba18690henrike@webrtc.org    : thread_(thread),
1127587c5e0b2fb5100b52bf271370ee1369ba18690henrike@webrtc.org      adapt_frame_drops_data_(kMaxAccumulatorSize),
1137587c5e0b2fb5100b52bf271370ee1369ba18690henrike@webrtc.org      effect_frame_drops_data_(kMaxAccumulatorSize),
1147587c5e0b2fb5100b52bf271370ee1369ba18690henrike@webrtc.org      frame_time_data_(kMaxAccumulatorSize) {
1150e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  Construct();
1160e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org}
1170e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
1180e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orgvoid VideoCapturer::Construct() {
1190e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  ClearAspectRatio();
1200e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  enable_camera_list_ = false;
1212007187dab65bb5d6f602355216534d6dd4ceaf2mallinath@webrtc.org  square_pixel_aspect_ratio_ = false;
1220e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  capture_state_ = CS_STOPPED;
1230e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  SignalFrameCaptured.connect(this, &VideoCapturer::OnFrameCaptured);
1240e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  scaled_width_ = 0;
1250e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  scaled_height_ = 0;
126952740e2dafeb2599d21778eb2e1b8f1c8f2bb07wu@webrtc.org  screencast_max_pixels_ = 0;
1270e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  muted_ = false;
1280e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  black_frame_count_down_ = kNumBlackFramesOnMute;
129e8b0cc3bf706964d657fdb25f0c5791c5a7aa3d7henrike@webrtc.org  enable_video_adapter_ = true;
1307587c5e0b2fb5100b52bf271370ee1369ba18690henrike@webrtc.org  adapt_frame_drops_ = 0;
1317587c5e0b2fb5100b52bf271370ee1369ba18690henrike@webrtc.org  effect_frame_drops_ = 0;
1327587c5e0b2fb5100b52bf271370ee1369ba18690henrike@webrtc.org  previous_frame_time_ = 0.0;
1333541181607ffe656d8db759a6095864d9f72248dbuildbot@webrtc.org#ifdef HAVE_WEBRTC_VIDEO
1343541181607ffe656d8db759a6095864d9f72248dbuildbot@webrtc.org  // There are lots of video capturers out there that don't call
1353541181607ffe656d8db759a6095864d9f72248dbuildbot@webrtc.org  // set_frame_factory.  We can either go change all of them, or we
1363541181607ffe656d8db759a6095864d9f72248dbuildbot@webrtc.org  // can set this default.
1373541181607ffe656d8db759a6095864d9f72248dbuildbot@webrtc.org  // TODO(pthatcher): Remove this hack and require the frame factory
1383541181607ffe656d8db759a6095864d9f72248dbuildbot@webrtc.org  // to be passed in the constructor.
1393541181607ffe656d8db759a6095864d9f72248dbuildbot@webrtc.org  set_frame_factory(new WebRtcVideoFrameFactory());
1403541181607ffe656d8db759a6095864d9f72248dbuildbot@webrtc.org#endif
1410e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org}
1420e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
1430e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orgconst std::vector<VideoFormat>* VideoCapturer::GetSupportedFormats() const {
1440e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  return &filtered_supported_formats_;
1450e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org}
1460e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
1470e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orgbool VideoCapturer::StartCapturing(const VideoFormat& capture_format) {
1487587c5e0b2fb5100b52bf271370ee1369ba18690henrike@webrtc.org  previous_frame_time_ = frame_length_time_reporter_.TimerNow();
1490e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  CaptureState result = Start(capture_format);
1500e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  const bool success = (result == CS_RUNNING) || (result == CS_STARTING);
1510e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  if (!success) {
1520e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    return false;
1530e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  }
1540e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  if (result == CS_RUNNING) {
1550e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    SetCaptureState(result);
1560e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  }
1570e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  return true;
1580e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org}
1590e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
1600e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orgvoid VideoCapturer::UpdateAspectRatio(int ratio_w, int ratio_h) {
1610e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  if (ratio_w == 0 || ratio_h == 0) {
1620e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    LOG(LS_WARNING) << "UpdateAspectRatio ignored invalid ratio: "
1630e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org                    << ratio_w << "x" << ratio_h;
1640e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    return;
1650e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  }
1660e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  ratio_w_ = ratio_w;
1670e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  ratio_h_ = ratio_h;
1680e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org}
1690e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
1700e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orgvoid VideoCapturer::ClearAspectRatio() {
1710e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  ratio_w_ = 0;
1720e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  ratio_h_ = 0;
1730e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org}
1740e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
1750e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org// Override this to have more control of how your device is started/stopped.
1760e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orgbool VideoCapturer::Pause(bool pause) {
1770e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  if (pause) {
1780e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    if (capture_state() == CS_PAUSED) {
1790e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      return true;
1800e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    }
1810e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    bool is_running = capture_state() == CS_STARTING ||
1820e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org        capture_state() == CS_RUNNING;
1830e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    if (!is_running) {
1840e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      LOG(LS_ERROR) << "Cannot pause a stopped camera.";
1850e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      return false;
1860e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    }
1870e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    LOG(LS_INFO) << "Pausing a camera.";
1882a86ce22ccc387dfa6f8a98ce3eba5c1e6f9e538buildbot@webrtc.org    rtc::scoped_ptr<VideoFormat> capture_format_when_paused(
1890e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org        capture_format_ ? new VideoFormat(*capture_format_) : NULL);
1900e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    Stop();
1910e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    SetCaptureState(CS_PAUSED);
1920e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    // If you override this function be sure to restore the capture format
1930e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    // after calling Stop().
1940e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    SetCaptureFormat(capture_format_when_paused.get());
1950e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  } else {  // Unpause.
1960e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    if (capture_state() != CS_PAUSED) {
1970e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      LOG(LS_WARNING) << "Cannot unpause a camera that hasn't been paused.";
1980e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      return false;
1990e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    }
2000e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    if (!capture_format_) {
2010e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      LOG(LS_ERROR) << "Missing capture_format_, cannot unpause a camera.";
2020e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      return false;
2030e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    }
2040e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    if (muted_) {
2050e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      LOG(LS_WARNING) << "Camera cannot be unpaused while muted.";
2060e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      return false;
2070e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    }
2080e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    LOG(LS_INFO) << "Unpausing a camera.";
2090e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    if (!Start(*capture_format_)) {
2100e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      LOG(LS_ERROR) << "Camera failed to start when unpausing.";
2110e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      return false;
2120e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    }
2130e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  }
2140e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  return true;
2150e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org}
2160e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
2170e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orgbool VideoCapturer::Restart(const VideoFormat& capture_format) {
2180e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  if (!IsRunning()) {
2190e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    return StartCapturing(capture_format);
2200e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  }
2210e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
2220e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  if (GetCaptureFormat() != NULL && *GetCaptureFormat() == capture_format) {
2230e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    // The reqested format is the same; nothing to do.
2240e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    return true;
2250e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  }
2260e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
2270e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  Stop();
2280e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  return StartCapturing(capture_format);
2290e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org}
2300e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
2310e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orgbool VideoCapturer::MuteToBlackThenPause(bool muted) {
2320e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  if (muted == IsMuted()) {
2330e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    return true;
2340e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  }
2350e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
2360e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  LOG(LS_INFO) << (muted ? "Muting" : "Unmuting") << " this video capturer.";
2370e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  muted_ = muted;  // Do this before calling Pause().
2380e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  if (muted) {
2390e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    // Reset black frame count down.
2400e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    black_frame_count_down_ = kNumBlackFramesOnMute;
2410e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    // Following frames will be overritten with black, then the camera will be
2420e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    // paused.
2430e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    return true;
2440e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  }
2450e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  // Start the camera.
2460e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  thread_->Clear(this, MSG_DO_PAUSE);
2470e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  return Pause(false);
2480e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org}
2490e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
2500e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orgvoid VideoCapturer::SetSupportedFormats(
2510e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    const std::vector<VideoFormat>& formats) {
2520e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  supported_formats_ = formats;
2530e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  UpdateFilteredSupportedFormats();
2540e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org}
2550e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
2560e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orgbool VideoCapturer::GetBestCaptureFormat(const VideoFormat& format,
2570e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org                                         VideoFormat* best_format) {
2580e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  // TODO(fbarchard): Directly support max_format.
2590e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  UpdateFilteredSupportedFormats();
2600e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  const std::vector<VideoFormat>* supported_formats = GetSupportedFormats();
2610e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
2620e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  if (supported_formats->empty()) {
2630e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    return false;
2640e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  }
2650e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  LOG(LS_INFO) << " Capture Requested " << format.ToString();
2660e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  int64 best_distance = kMaxDistance;
2670e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  std::vector<VideoFormat>::const_iterator best = supported_formats->end();
2680e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  std::vector<VideoFormat>::const_iterator i;
2690e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  for (i = supported_formats->begin(); i != supported_formats->end(); ++i) {
2700e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    int64 distance = GetFormatDistance(format, *i);
2710e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    // TODO(fbarchard): Reduce to LS_VERBOSE if/when camera capture is
2720e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    // relatively bug free.
2730e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    LOG(LS_INFO) << " Supported " << i->ToString() << " distance " << distance;
2740e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    if (distance < best_distance) {
2750e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      best_distance = distance;
2760e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      best = i;
2770e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    }
2780e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  }
2790e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  if (supported_formats->end() == best) {
2800e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    LOG(LS_ERROR) << " No acceptable camera format found";
2810e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    return false;
2820e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  }
2830e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
2840e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  if (best_format) {
2850e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    best_format->width = best->width;
2860e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    best_format->height = best->height;
2870e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    best_format->fourcc = best->fourcc;
288f32dd31e14521d7f845e7776af6d44d411573370sergeyu@chromium.org    best_format->interval = best->interval;
2890e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    LOG(LS_INFO) << " Best " << best_format->ToString() << " Interval "
2900e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org                 << best_format->interval << " distance " << best_distance;
2910e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  }
2920e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  return true;
2930e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org}
2940e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
2950e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orgvoid VideoCapturer::AddVideoProcessor(VideoProcessor* video_processor) {
2962a86ce22ccc387dfa6f8a98ce3eba5c1e6f9e538buildbot@webrtc.org  rtc::CritScope cs(&crit_);
2970e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  ASSERT(std::find(video_processors_.begin(), video_processors_.end(),
2980e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org                   video_processor) == video_processors_.end());
2990e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  video_processors_.push_back(video_processor);
3000e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org}
3010e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
3020e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orgbool VideoCapturer::RemoveVideoProcessor(VideoProcessor* video_processor) {
3032a86ce22ccc387dfa6f8a98ce3eba5c1e6f9e538buildbot@webrtc.org  rtc::CritScope cs(&crit_);
3040e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  VideoProcessors::iterator found = std::find(
3050e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      video_processors_.begin(), video_processors_.end(), video_processor);
3060e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  if (found == video_processors_.end()) {
3070e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    return false;
3080e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  }
3090e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  video_processors_.erase(found);
3100e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  return true;
3110e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org}
3120e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
3130e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orgvoid VideoCapturer::ConstrainSupportedFormats(const VideoFormat& max_format) {
3140e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  max_format_.reset(new VideoFormat(max_format));
3150e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  LOG(LS_VERBOSE) << " ConstrainSupportedFormats " << max_format.ToString();
3160e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  UpdateFilteredSupportedFormats();
3170e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org}
3180e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
3190e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orgstd::string VideoCapturer::ToString(const CapturedFrame* captured_frame) const {
3200e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  std::string fourcc_name = GetFourccName(captured_frame->fourcc) + " ";
3210e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  for (std::string::const_iterator i = fourcc_name.begin();
3220e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org       i < fourcc_name.end(); ++i) {
3230e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    // Test character is printable; Avoid isprint() which asserts on negatives.
3240e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    if (*i < 32 || *i >= 127) {
3250e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      fourcc_name = "";
3260e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      break;
3270e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    }
3280e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  }
3290e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
3300e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  std::ostringstream ss;
3310e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  ss << fourcc_name << captured_frame->width << "x" << captured_frame->height
332f32dd31e14521d7f845e7776af6d44d411573370sergeyu@chromium.org     << "x" << VideoFormat::IntervalToFpsFloat(captured_frame->elapsed_time);
3330e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  return ss.str();
3340e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org}
3350e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
3367587c5e0b2fb5100b52bf271370ee1369ba18690henrike@webrtc.orgvoid VideoCapturer::GetStats(VariableInfo<int>* adapt_drops_stats,
3377587c5e0b2fb5100b52bf271370ee1369ba18690henrike@webrtc.org                             VariableInfo<int>* effect_drops_stats,
3383657d9107db9ffd3dfbe996b9a3af57e4818efb4buildbot@webrtc.org                             VariableInfo<double>* frame_time_stats,
3393657d9107db9ffd3dfbe996b9a3af57e4818efb4buildbot@webrtc.org                             VideoFormat* last_captured_frame_format) {
3402a86ce22ccc387dfa6f8a98ce3eba5c1e6f9e538buildbot@webrtc.org  rtc::CritScope cs(&frame_stats_crit_);
3417587c5e0b2fb5100b52bf271370ee1369ba18690henrike@webrtc.org  GetVariableSnapshot(adapt_frame_drops_data_, adapt_drops_stats);
3427587c5e0b2fb5100b52bf271370ee1369ba18690henrike@webrtc.org  GetVariableSnapshot(effect_frame_drops_data_, effect_drops_stats);
3437587c5e0b2fb5100b52bf271370ee1369ba18690henrike@webrtc.org  GetVariableSnapshot(frame_time_data_, frame_time_stats);
3443657d9107db9ffd3dfbe996b9a3af57e4818efb4buildbot@webrtc.org  *last_captured_frame_format = last_captured_frame_format_;
3457587c5e0b2fb5100b52bf271370ee1369ba18690henrike@webrtc.org
3467587c5e0b2fb5100b52bf271370ee1369ba18690henrike@webrtc.org  adapt_frame_drops_data_.Reset();
3477587c5e0b2fb5100b52bf271370ee1369ba18690henrike@webrtc.org  effect_frame_drops_data_.Reset();
3487587c5e0b2fb5100b52bf271370ee1369ba18690henrike@webrtc.org  frame_time_data_.Reset();
3497587c5e0b2fb5100b52bf271370ee1369ba18690henrike@webrtc.org}
3507587c5e0b2fb5100b52bf271370ee1369ba18690henrike@webrtc.org
3510e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orgvoid VideoCapturer::OnFrameCaptured(VideoCapturer*,
3520e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org                                    const CapturedFrame* captured_frame) {
3530e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  if (muted_) {
3540e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    if (black_frame_count_down_ == 0) {
3550e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      thread_->Post(this, MSG_DO_PAUSE, NULL);
3560e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    } else {
3570e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      --black_frame_count_down_;
3580e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    }
3590e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  }
3600e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
3610e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  if (SignalVideoFrame.is_empty()) {
3620e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    return;
3630e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  }
3640e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org#if !defined(DISABLE_YUV)
3650e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  if (IsScreencast()) {
3660e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    int scaled_width, scaled_height;
367952740e2dafeb2599d21778eb2e1b8f1c8f2bb07wu@webrtc.org    if (screencast_max_pixels_ > 0) {
368952740e2dafeb2599d21778eb2e1b8f1c8f2bb07wu@webrtc.org      ComputeScaleMaxPixels(captured_frame->width, captured_frame->height,
369952740e2dafeb2599d21778eb2e1b8f1c8f2bb07wu@webrtc.org          screencast_max_pixels_, &scaled_width, &scaled_height);
370952740e2dafeb2599d21778eb2e1b8f1c8f2bb07wu@webrtc.org    } else {
371952740e2dafeb2599d21778eb2e1b8f1c8f2bb07wu@webrtc.org      int desired_screencast_fps = capture_format_.get() ?
372952740e2dafeb2599d21778eb2e1b8f1c8f2bb07wu@webrtc.org          VideoFormat::IntervalToFps(capture_format_->interval) :
373952740e2dafeb2599d21778eb2e1b8f1c8f2bb07wu@webrtc.org          kDefaultScreencastFps;
374952740e2dafeb2599d21778eb2e1b8f1c8f2bb07wu@webrtc.org      ComputeScale(captured_frame->width, captured_frame->height,
375952740e2dafeb2599d21778eb2e1b8f1c8f2bb07wu@webrtc.org                   desired_screencast_fps, &scaled_width, &scaled_height);
376952740e2dafeb2599d21778eb2e1b8f1c8f2bb07wu@webrtc.org    }
3770e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
3780e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    if (FOURCC_ARGB == captured_frame->fourcc &&
379a487db2aeda23ade81f0b2e5fd4d50f874d06a9csergeyu@chromium.org        (scaled_width != captured_frame->width ||
3802007187dab65bb5d6f602355216534d6dd4ceaf2mallinath@webrtc.org        scaled_height != captured_frame->height)) {
3812007187dab65bb5d6f602355216534d6dd4ceaf2mallinath@webrtc.org      if (scaled_width != scaled_width_ || scaled_height != scaled_height_) {
3822007187dab65bb5d6f602355216534d6dd4ceaf2mallinath@webrtc.org        LOG(LS_INFO) << "Scaling Screencast from "
3832007187dab65bb5d6f602355216534d6dd4ceaf2mallinath@webrtc.org                     << captured_frame->width << "x"
3842007187dab65bb5d6f602355216534d6dd4ceaf2mallinath@webrtc.org                     << captured_frame->height << " to "
3852007187dab65bb5d6f602355216534d6dd4ceaf2mallinath@webrtc.org                     << scaled_width << "x" << scaled_height;
3862007187dab65bb5d6f602355216534d6dd4ceaf2mallinath@webrtc.org        scaled_width_ = scaled_width;
3872007187dab65bb5d6f602355216534d6dd4ceaf2mallinath@webrtc.org        scaled_height_ = scaled_height;
3882007187dab65bb5d6f602355216534d6dd4ceaf2mallinath@webrtc.org      }
3892007187dab65bb5d6f602355216534d6dd4ceaf2mallinath@webrtc.org      CapturedFrame* modified_frame =
3902007187dab65bb5d6f602355216534d6dd4ceaf2mallinath@webrtc.org          const_cast<CapturedFrame*>(captured_frame);
3910e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      // Compute new width such that width * height is less than maximum but
3920e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      // maintains original captured frame aspect ratio.
3930e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      // Round down width to multiple of 4 so odd width won't round up beyond
3940e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      // maximum, and so chroma channel is even width to simplify spatial
3950e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      // resampling.
3960e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      libyuv::ARGBScale(reinterpret_cast<const uint8*>(captured_frame->data),
3970e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org                        captured_frame->width * 4, captured_frame->width,
3980e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org                        captured_frame->height,
3992007187dab65bb5d6f602355216534d6dd4ceaf2mallinath@webrtc.org                        reinterpret_cast<uint8*>(modified_frame->data),
4000e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org                        scaled_width * 4, scaled_width, scaled_height,
4010e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org                        libyuv::kFilterBilinear);
4022007187dab65bb5d6f602355216534d6dd4ceaf2mallinath@webrtc.org      modified_frame->width = scaled_width;
4032007187dab65bb5d6f602355216534d6dd4ceaf2mallinath@webrtc.org      modified_frame->height = scaled_height;
4042007187dab65bb5d6f602355216534d6dd4ceaf2mallinath@webrtc.org      modified_frame->data_size = scaled_width * 4 * scaled_height;
4052007187dab65bb5d6f602355216534d6dd4ceaf2mallinath@webrtc.org    }
4062007187dab65bb5d6f602355216534d6dd4ceaf2mallinath@webrtc.org  }
4072007187dab65bb5d6f602355216534d6dd4ceaf2mallinath@webrtc.org
4082007187dab65bb5d6f602355216534d6dd4ceaf2mallinath@webrtc.org  const int kYuy2Bpp = 2;
4092007187dab65bb5d6f602355216534d6dd4ceaf2mallinath@webrtc.org  const int kArgbBpp = 4;
4102007187dab65bb5d6f602355216534d6dd4ceaf2mallinath@webrtc.org  // TODO(fbarchard): Make a helper function to adjust pixels to square.
4112007187dab65bb5d6f602355216534d6dd4ceaf2mallinath@webrtc.org  // TODO(fbarchard): Hook up experiment to scaling.
4122007187dab65bb5d6f602355216534d6dd4ceaf2mallinath@webrtc.org  // TODO(fbarchard): Avoid scale and convert if muted.
4132007187dab65bb5d6f602355216534d6dd4ceaf2mallinath@webrtc.org  // Temporary buffer is scoped here so it will persist until i420_frame.Init()
4142007187dab65bb5d6f602355216534d6dd4ceaf2mallinath@webrtc.org  // makes a copy of the frame, converting to I420.
4152a86ce22ccc387dfa6f8a98ce3eba5c1e6f9e538buildbot@webrtc.org  rtc::scoped_ptr<uint8[]> temp_buffer;
4162007187dab65bb5d6f602355216534d6dd4ceaf2mallinath@webrtc.org  // YUY2 can be scaled vertically using an ARGB scaler.  Aspect ratio is only
4172007187dab65bb5d6f602355216534d6dd4ceaf2mallinath@webrtc.org  // a problem on OSX.  OSX always converts webcams to YUY2 or UYVY.
4182007187dab65bb5d6f602355216534d6dd4ceaf2mallinath@webrtc.org  bool can_scale =
4192007187dab65bb5d6f602355216534d6dd4ceaf2mallinath@webrtc.org      FOURCC_YUY2 == CanonicalFourCC(captured_frame->fourcc) ||
4202007187dab65bb5d6f602355216534d6dd4ceaf2mallinath@webrtc.org      FOURCC_UYVY == CanonicalFourCC(captured_frame->fourcc);
4212007187dab65bb5d6f602355216534d6dd4ceaf2mallinath@webrtc.org
4222007187dab65bb5d6f602355216534d6dd4ceaf2mallinath@webrtc.org  // If pixels are not square, optionally use vertical scaling to make them
4232007187dab65bb5d6f602355216534d6dd4ceaf2mallinath@webrtc.org  // square.  Square pixels simplify the rest of the pipeline, including
4242007187dab65bb5d6f602355216534d6dd4ceaf2mallinath@webrtc.org  // effects and rendering.
4252007187dab65bb5d6f602355216534d6dd4ceaf2mallinath@webrtc.org  if (can_scale && square_pixel_aspect_ratio_ &&
4262007187dab65bb5d6f602355216534d6dd4ceaf2mallinath@webrtc.org      captured_frame->pixel_width != captured_frame->pixel_height) {
4272007187dab65bb5d6f602355216534d6dd4ceaf2mallinath@webrtc.org    int scaled_width, scaled_height;
4282007187dab65bb5d6f602355216534d6dd4ceaf2mallinath@webrtc.org    // modified_frame points to the captured_frame but with const casted away
4292007187dab65bb5d6f602355216534d6dd4ceaf2mallinath@webrtc.org    // so it can be modified.
4302007187dab65bb5d6f602355216534d6dd4ceaf2mallinath@webrtc.org    CapturedFrame* modified_frame = const_cast<CapturedFrame*>(captured_frame);
4312007187dab65bb5d6f602355216534d6dd4ceaf2mallinath@webrtc.org    // Compute the frame size that makes pixels square pixel aspect ratio.
4322007187dab65bb5d6f602355216534d6dd4ceaf2mallinath@webrtc.org    ComputeScaleToSquarePixels(captured_frame->width, captured_frame->height,
4332007187dab65bb5d6f602355216534d6dd4ceaf2mallinath@webrtc.org                               captured_frame->pixel_width,
4342007187dab65bb5d6f602355216534d6dd4ceaf2mallinath@webrtc.org                               captured_frame->pixel_height,
4352007187dab65bb5d6f602355216534d6dd4ceaf2mallinath@webrtc.org                               &scaled_width, &scaled_height);
4362007187dab65bb5d6f602355216534d6dd4ceaf2mallinath@webrtc.org
4372007187dab65bb5d6f602355216534d6dd4ceaf2mallinath@webrtc.org    if (scaled_width != scaled_width_ || scaled_height != scaled_height_) {
4382007187dab65bb5d6f602355216534d6dd4ceaf2mallinath@webrtc.org      LOG(LS_INFO) << "Scaling WebCam from "
4392007187dab65bb5d6f602355216534d6dd4ceaf2mallinath@webrtc.org                   << captured_frame->width << "x"
4402007187dab65bb5d6f602355216534d6dd4ceaf2mallinath@webrtc.org                   << captured_frame->height << " to "
4412007187dab65bb5d6f602355216534d6dd4ceaf2mallinath@webrtc.org                   << scaled_width << "x" << scaled_height
4422007187dab65bb5d6f602355216534d6dd4ceaf2mallinath@webrtc.org                   << " for PAR "
4432007187dab65bb5d6f602355216534d6dd4ceaf2mallinath@webrtc.org                   << captured_frame->pixel_width << "x"
4442007187dab65bb5d6f602355216534d6dd4ceaf2mallinath@webrtc.org                   << captured_frame->pixel_height;
4452007187dab65bb5d6f602355216534d6dd4ceaf2mallinath@webrtc.org      scaled_width_ = scaled_width;
4462007187dab65bb5d6f602355216534d6dd4ceaf2mallinath@webrtc.org      scaled_height_ = scaled_height;
4470e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    }
4482007187dab65bb5d6f602355216534d6dd4ceaf2mallinath@webrtc.org    const int modified_frame_size = scaled_width * scaled_height * kYuy2Bpp;
4492007187dab65bb5d6f602355216534d6dd4ceaf2mallinath@webrtc.org    uint8* temp_buffer_data;
4502007187dab65bb5d6f602355216534d6dd4ceaf2mallinath@webrtc.org    // Pixels are wide and short; Increasing height. Requires temporary buffer.
4512007187dab65bb5d6f602355216534d6dd4ceaf2mallinath@webrtc.org    if (scaled_height > captured_frame->height) {
4522007187dab65bb5d6f602355216534d6dd4ceaf2mallinath@webrtc.org      temp_buffer.reset(new uint8[modified_frame_size]);
4532007187dab65bb5d6f602355216534d6dd4ceaf2mallinath@webrtc.org      temp_buffer_data = temp_buffer.get();
4542007187dab65bb5d6f602355216534d6dd4ceaf2mallinath@webrtc.org    } else {
4552007187dab65bb5d6f602355216534d6dd4ceaf2mallinath@webrtc.org      // Pixels are narrow and tall; Decreasing height. Scale will be done
4562007187dab65bb5d6f602355216534d6dd4ceaf2mallinath@webrtc.org      // in place.
4572007187dab65bb5d6f602355216534d6dd4ceaf2mallinath@webrtc.org      temp_buffer_data = reinterpret_cast<uint8*>(captured_frame->data);
4582007187dab65bb5d6f602355216534d6dd4ceaf2mallinath@webrtc.org    }
4592007187dab65bb5d6f602355216534d6dd4ceaf2mallinath@webrtc.org
4602007187dab65bb5d6f602355216534d6dd4ceaf2mallinath@webrtc.org    // Use ARGBScaler to vertically scale the YUY2 image, adjusting for 16 bpp.
4612007187dab65bb5d6f602355216534d6dd4ceaf2mallinath@webrtc.org    libyuv::ARGBScale(reinterpret_cast<const uint8*>(captured_frame->data),
4622007187dab65bb5d6f602355216534d6dd4ceaf2mallinath@webrtc.org                      captured_frame->width * kYuy2Bpp,  // Stride for YUY2.
4632007187dab65bb5d6f602355216534d6dd4ceaf2mallinath@webrtc.org                      captured_frame->width * kYuy2Bpp / kArgbBpp,  // Width.
4642007187dab65bb5d6f602355216534d6dd4ceaf2mallinath@webrtc.org                      abs(captured_frame->height),  // Height.
4652007187dab65bb5d6f602355216534d6dd4ceaf2mallinath@webrtc.org                      temp_buffer_data,
4662007187dab65bb5d6f602355216534d6dd4ceaf2mallinath@webrtc.org                      scaled_width * kYuy2Bpp,  // Stride for YUY2.
4672007187dab65bb5d6f602355216534d6dd4ceaf2mallinath@webrtc.org                      scaled_width * kYuy2Bpp / kArgbBpp,  // Width.
4682007187dab65bb5d6f602355216534d6dd4ceaf2mallinath@webrtc.org                      abs(scaled_height),  // New height.
4692007187dab65bb5d6f602355216534d6dd4ceaf2mallinath@webrtc.org                      libyuv::kFilterBilinear);
4702007187dab65bb5d6f602355216534d6dd4ceaf2mallinath@webrtc.org    modified_frame->width = scaled_width;
4712007187dab65bb5d6f602355216534d6dd4ceaf2mallinath@webrtc.org    modified_frame->height = scaled_height;
4722007187dab65bb5d6f602355216534d6dd4ceaf2mallinath@webrtc.org    modified_frame->pixel_width = 1;
4732007187dab65bb5d6f602355216534d6dd4ceaf2mallinath@webrtc.org    modified_frame->pixel_height = 1;
4742007187dab65bb5d6f602355216534d6dd4ceaf2mallinath@webrtc.org    modified_frame->data_size = modified_frame_size;
4752007187dab65bb5d6f602355216534d6dd4ceaf2mallinath@webrtc.org    modified_frame->data = temp_buffer_data;
4760e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  }
4770e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org#endif  // !DISABLE_YUV
4782007187dab65bb5d6f602355216534d6dd4ceaf2mallinath@webrtc.org
4792007187dab65bb5d6f602355216534d6dd4ceaf2mallinath@webrtc.org  // Size to crop captured frame to.  This adjusts the captured frames
4802007187dab65bb5d6f602355216534d6dd4ceaf2mallinath@webrtc.org  // aspect ratio to match the final view aspect ratio, considering pixel
4810e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  // aspect ratio and rotation.  The final size may be scaled down by video
4820e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  // adapter to better match ratio_w_ x ratio_h_.
4830e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  // Note that abs() of frame height is passed in, because source may be
4840e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  // inverted, but output will be positive.
4850e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  int desired_width = captured_frame->width;
4860e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  int desired_height = captured_frame->height;
4870e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
4880e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  // TODO(fbarchard): Improve logic to pad or crop.
4890e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  // MJPG can crop vertically, but not horizontally.  This logic disables crop.
4900e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  // Alternatively we could pad the image with black, or implement a 2 step
4910e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  // crop.
4920e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  bool can_crop = true;
4930e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  if (captured_frame->fourcc == FOURCC_MJPG) {
4940e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    float cam_aspect = static_cast<float>(captured_frame->width) /
4950e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org        static_cast<float>(captured_frame->height);
4960e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    float view_aspect = static_cast<float>(ratio_w_) /
4970e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org        static_cast<float>(ratio_h_);
4980e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    can_crop = cam_aspect <= view_aspect;
4990e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  }
5000e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  if (can_crop && !IsScreencast()) {
5010e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    // TODO(ronghuawu): The capturer should always produce the native
5020e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    // resolution and the cropping should be done in downstream code.
5030e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    ComputeCrop(ratio_w_, ratio_h_, captured_frame->width,
5040e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org                abs(captured_frame->height), captured_frame->pixel_width,
5050e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org                captured_frame->pixel_height, captured_frame->rotation,
5060e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org                &desired_width, &desired_height);
5070e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  }
5080e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
5092a0553609b5b6d1d4dce0366b334dc9ef8aa4d65buildbot@webrtc.org  if (!frame_factory_) {
5102a0553609b5b6d1d4dce0366b334dc9ef8aa4d65buildbot@webrtc.org    LOG(LS_ERROR) << "No video frame factory.";
5112a0553609b5b6d1d4dce0366b334dc9ef8aa4d65buildbot@webrtc.org    return;
5122a0553609b5b6d1d4dce0366b334dc9ef8aa4d65buildbot@webrtc.org  }
5132a0553609b5b6d1d4dce0366b334dc9ef8aa4d65buildbot@webrtc.org
5142a0553609b5b6d1d4dce0366b334dc9ef8aa4d65buildbot@webrtc.org  rtc::scoped_ptr<VideoFrame> i420_frame(
5152a0553609b5b6d1d4dce0366b334dc9ef8aa4d65buildbot@webrtc.org      frame_factory_->CreateAliasedFrame(
5162a0553609b5b6d1d4dce0366b334dc9ef8aa4d65buildbot@webrtc.org          captured_frame, desired_width, desired_height));
5172a0553609b5b6d1d4dce0366b334dc9ef8aa4d65buildbot@webrtc.org  if (!i420_frame) {
5180e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    // TODO(fbarchard): LOG more information about captured frame attributes.
5190e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    LOG(LS_ERROR) << "Couldn't convert to I420! "
5200e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org                  << "From " << ToString(captured_frame) << " To "
5210e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org                  << desired_width << " x " << desired_height;
5220e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    return;
5230e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  }
524b881d27f23e9a8f52dc6a60fc66ebd75f9c2f15cmallinath@webrtc.org
5252a0553609b5b6d1d4dce0366b334dc9ef8aa4d65buildbot@webrtc.org  VideoFrame* adapted_frame = i420_frame.get();
526e8b0cc3bf706964d657fdb25f0c5791c5a7aa3d7henrike@webrtc.org  if (enable_video_adapter_ && !IsScreencast()) {
527b881d27f23e9a8f52dc6a60fc66ebd75f9c2f15cmallinath@webrtc.org    VideoFrame* out_frame = NULL;
528e8b0cc3bf706964d657fdb25f0c5791c5a7aa3d7henrike@webrtc.org    video_adapter_.AdaptFrame(adapted_frame, &out_frame);
529b881d27f23e9a8f52dc6a60fc66ebd75f9c2f15cmallinath@webrtc.org    if (!out_frame) {
5307587c5e0b2fb5100b52bf271370ee1369ba18690henrike@webrtc.org      // VideoAdapter dropped the frame.
5317587c5e0b2fb5100b52bf271370ee1369ba18690henrike@webrtc.org      ++adapt_frame_drops_;
5327587c5e0b2fb5100b52bf271370ee1369ba18690henrike@webrtc.org      return;
533b881d27f23e9a8f52dc6a60fc66ebd75f9c2f15cmallinath@webrtc.org    }
534b881d27f23e9a8f52dc6a60fc66ebd75f9c2f15cmallinath@webrtc.org    adapted_frame = out_frame;
535b881d27f23e9a8f52dc6a60fc66ebd75f9c2f15cmallinath@webrtc.org  }
536b881d27f23e9a8f52dc6a60fc66ebd75f9c2f15cmallinath@webrtc.org
537b881d27f23e9a8f52dc6a60fc66ebd75f9c2f15cmallinath@webrtc.org  if (!muted_ && !ApplyProcessors(adapted_frame)) {
5380e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    // Processor dropped the frame.
5397587c5e0b2fb5100b52bf271370ee1369ba18690henrike@webrtc.org    ++effect_frame_drops_;
5400e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    return;
5410e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  }
5420e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  if (muted_) {
5432a0553609b5b6d1d4dce0366b334dc9ef8aa4d65buildbot@webrtc.org    // TODO(pthatcher): Use frame_factory_->CreateBlackFrame() instead.
544b881d27f23e9a8f52dc6a60fc66ebd75f9c2f15cmallinath@webrtc.org    adapted_frame->SetToBlack();
5450e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  }
546b881d27f23e9a8f52dc6a60fc66ebd75f9c2f15cmallinath@webrtc.org  SignalVideoFrame(this, adapted_frame);
5477587c5e0b2fb5100b52bf271370ee1369ba18690henrike@webrtc.org
5483657d9107db9ffd3dfbe996b9a3af57e4818efb4buildbot@webrtc.org  UpdateStats(captured_frame);
5490e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org}
5500e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
5510e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orgvoid VideoCapturer::SetCaptureState(CaptureState state) {
5520e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  if (state == capture_state_) {
5530e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    // Don't trigger a state changed callback if the state hasn't changed.
5540e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    return;
5550e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  }
5560e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  StateChangeParams* state_params = new StateChangeParams(state);
5570e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  capture_state_ = state;
5580e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  thread_->Post(this, MSG_STATE_CHANGE, state_params);
5590e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org}
5600e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
5612a86ce22ccc387dfa6f8a98ce3eba5c1e6f9e538buildbot@webrtc.orgvoid VideoCapturer::OnMessage(rtc::Message* message) {
5620e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  switch (message->message_id) {
5630e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    case MSG_STATE_CHANGE: {
5642a86ce22ccc387dfa6f8a98ce3eba5c1e6f9e538buildbot@webrtc.org      rtc::scoped_ptr<StateChangeParams> p(
5650e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org          static_cast<StateChangeParams*>(message->pdata));
5660e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      SignalStateChange(this, p->data());
5670e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      break;
5680e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    }
5690e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    case MSG_DO_PAUSE: {
5700e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      Pause(true);
5710e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      break;
5720e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    }
5730e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    case MSG_DO_UNPAUSE: {
5740e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      Pause(false);
5750e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      break;
5760e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    }
5770e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    default: {
5780e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      ASSERT(false);
5790e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    }
5800e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  }
5810e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org}
5820e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
5830e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org// Get the distance between the supported and desired formats.
5840e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org// Prioritization is done according to this algorithm:
5850e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org// 1) Width closeness. If not same, we prefer wider.
5860e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org// 2) Height closeness. If not same, we prefer higher.
5870e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org// 3) Framerate closeness. If not same, we prefer faster.
5880e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org// 4) Compression. If desired format has a specific fourcc, we need exact match;
5890e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org//                otherwise, we use preference.
5900e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orgint64 VideoCapturer::GetFormatDistance(const VideoFormat& desired,
5910e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org                                       const VideoFormat& supported) {
5920e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  int64 distance = kMaxDistance;
5930e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
5940e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  // Check fourcc.
5950e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  uint32 supported_fourcc = CanonicalFourCC(supported.fourcc);
5960e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  int64 delta_fourcc = kMaxDistance;
5970e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  if (FOURCC_ANY == desired.fourcc) {
5980e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    // Any fourcc is OK for the desired. Use preference to find best fourcc.
5990e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    std::vector<uint32> preferred_fourccs;
6000e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    if (!GetPreferredFourccs(&preferred_fourccs)) {
6010e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      return distance;
6020e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    }
6030e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
6040e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    for (size_t i = 0; i < preferred_fourccs.size(); ++i) {
6050e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      if (supported_fourcc == CanonicalFourCC(preferred_fourccs[i])) {
6060e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org        delta_fourcc = i;
6070e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org#ifdef LINUX
6080e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org        // For HD avoid YU12 which is a software conversion and has 2 bugs
6090e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org        // b/7326348 b/6960899.  Reenable when fixed.
6100e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org        if (supported.height >= 720 && (supported_fourcc == FOURCC_YU12 ||
6110e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org                                        supported_fourcc == FOURCC_YV12)) {
6120e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org          delta_fourcc += kYU12Penalty;
6130e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org        }
6140e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org#endif
6150e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org        break;
6160e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      }
6170e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    }
6180e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  } else if (supported_fourcc == CanonicalFourCC(desired.fourcc)) {
6190e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    delta_fourcc = 0;  // Need exact match.
6200e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  }
6210e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
6220e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  if (kMaxDistance == delta_fourcc) {
6230e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    // Failed to match fourcc.
6240e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    return distance;
6250e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  }
6260e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
6270e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  // Check resolution and fps.
6280e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  int desired_width = desired.width;
6290e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  int desired_height = desired.height;
6300e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  int64 delta_w = supported.width - desired_width;
631f32dd31e14521d7f845e7776af6d44d411573370sergeyu@chromium.org  float supported_fps = VideoFormat::IntervalToFpsFloat(supported.interval);
632f32dd31e14521d7f845e7776af6d44d411573370sergeyu@chromium.org  float delta_fps =
633f32dd31e14521d7f845e7776af6d44d411573370sergeyu@chromium.org      supported_fps - VideoFormat::IntervalToFpsFloat(desired.interval);
6340e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  // Check height of supported height compared to height we would like it to be.
6350e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  int64 aspect_h =
6360e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      desired_width ? supported.width * desired_height / desired_width
6370e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org                    : desired_height;
6380e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  int64 delta_h = supported.height - aspect_h;
6390e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
6400e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  distance = 0;
6410e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  // Set high penalty if the supported format is lower than the desired format.
6420e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  // 3x means we would prefer down to down to 3/4, than up to double.
6430e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  // But we'd prefer up to double than down to 1/2.  This is conservative,
6440e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  // strongly avoiding going down in resolution, similar to
6450e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  // the old method, but not completely ruling it out in extreme situations.
6460e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  // It also ignores framerate, which is often very low at high resolutions.
6470e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  // TODO(fbarchard): Improve logic to use weighted factors.
6480e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  static const int kDownPenalty = -3;
6490e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  if (delta_w < 0) {
6500e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    delta_w = delta_w * kDownPenalty;
6510e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  }
6520e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  if (delta_h < 0) {
6530e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    delta_h = delta_h * kDownPenalty;
6540e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  }
6550e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  // Require camera fps to be at least 80% of what is requested if resolution
6560e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  // matches.
6570e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  // Require camera fps to be at least 96% of what is requested, or higher,
6580e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  // if resolution differs. 96% allows for slight variations in fps. e.g. 29.97
6590e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  if (delta_fps < 0) {
660f32dd31e14521d7f845e7776af6d44d411573370sergeyu@chromium.org    float min_desirable_fps = delta_w ?
661f32dd31e14521d7f845e7776af6d44d411573370sergeyu@chromium.org    VideoFormat::IntervalToFpsFloat(desired.interval) * 28.f / 30.f :
662f32dd31e14521d7f845e7776af6d44d411573370sergeyu@chromium.org    VideoFormat::IntervalToFpsFloat(desired.interval) * 23.f / 30.f;
6630e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    delta_fps = -delta_fps;
6640e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    if (supported_fps < min_desirable_fps) {
6650e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      distance |= static_cast<int64>(1) << 62;
6660e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    } else {
6670e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      distance |= static_cast<int64>(1) << 15;
6680e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    }
6690e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  }
670f32dd31e14521d7f845e7776af6d44d411573370sergeyu@chromium.org  int64 idelta_fps = static_cast<int>(delta_fps);
6710e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
6720e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  // 12 bits for width and height and 8 bits for fps and fourcc.
6730e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  distance |=
674f32dd31e14521d7f845e7776af6d44d411573370sergeyu@chromium.org      (delta_w << 28) | (delta_h << 16) | (idelta_fps << 8) | delta_fourcc;
6750e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
6760e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  return distance;
6770e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org}
6780e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
6790e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orgbool VideoCapturer::ApplyProcessors(VideoFrame* video_frame) {
6800e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  bool drop_frame = false;
6812a86ce22ccc387dfa6f8a98ce3eba5c1e6f9e538buildbot@webrtc.org  rtc::CritScope cs(&crit_);
6820e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  for (VideoProcessors::iterator iter = video_processors_.begin();
6830e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org       iter != video_processors_.end(); ++iter) {
6840e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    (*iter)->OnFrame(kDummyVideoSsrc, video_frame, &drop_frame);
6850e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    if (drop_frame) {
6860e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      return false;
6870e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    }
6880e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  }
6890e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  return true;
6900e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org}
6910e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
6920e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orgvoid VideoCapturer::UpdateFilteredSupportedFormats() {
6930e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  filtered_supported_formats_.clear();
6940e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  filtered_supported_formats_ = supported_formats_;
6950e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  if (!max_format_) {
6960e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    return;
6970e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  }
6980e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  std::vector<VideoFormat>::iterator iter = filtered_supported_formats_.begin();
6990e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  while (iter != filtered_supported_formats_.end()) {
7000e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    if (ShouldFilterFormat(*iter)) {
7010e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      iter = filtered_supported_formats_.erase(iter);
7020e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    } else {
7030e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      ++iter;
7040e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    }
7050e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  }
7060e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  if (filtered_supported_formats_.empty()) {
7070e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    // The device only captures at resolutions higher than |max_format_| this
7080e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    // indicates that |max_format_| should be ignored as it is better to capture
7090e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    // at too high a resolution than to not capture at all.
7100e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    filtered_supported_formats_ = supported_formats_;
7110e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  }
7120e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org}
7130e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
7140e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orgbool VideoCapturer::ShouldFilterFormat(const VideoFormat& format) const {
7150e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  if (!enable_camera_list_) {
7160e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    return false;
7170e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  }
7180e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  return format.width > max_format_->width ||
7190e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org         format.height > max_format_->height;
7200e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org}
7210e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
7223657d9107db9ffd3dfbe996b9a3af57e4818efb4buildbot@webrtc.orgvoid VideoCapturer::UpdateStats(const CapturedFrame* captured_frame) {
7233657d9107db9ffd3dfbe996b9a3af57e4818efb4buildbot@webrtc.org  // Update stats protected from fetches from different thread.
7242a86ce22ccc387dfa6f8a98ce3eba5c1e6f9e538buildbot@webrtc.org  rtc::CritScope cs(&frame_stats_crit_);
7253657d9107db9ffd3dfbe996b9a3af57e4818efb4buildbot@webrtc.org
7263657d9107db9ffd3dfbe996b9a3af57e4818efb4buildbot@webrtc.org  last_captured_frame_format_.width = captured_frame->width;
7273657d9107db9ffd3dfbe996b9a3af57e4818efb4buildbot@webrtc.org  last_captured_frame_format_.height = captured_frame->height;
7283657d9107db9ffd3dfbe996b9a3af57e4818efb4buildbot@webrtc.org  // TODO(ronghuawu): Useful to report interval as well?
7293657d9107db9ffd3dfbe996b9a3af57e4818efb4buildbot@webrtc.org  last_captured_frame_format_.interval = 0;
7303657d9107db9ffd3dfbe996b9a3af57e4818efb4buildbot@webrtc.org  last_captured_frame_format_.fourcc = captured_frame->fourcc;
7313657d9107db9ffd3dfbe996b9a3af57e4818efb4buildbot@webrtc.org
7323657d9107db9ffd3dfbe996b9a3af57e4818efb4buildbot@webrtc.org  double time_now = frame_length_time_reporter_.TimerNow();
7333657d9107db9ffd3dfbe996b9a3af57e4818efb4buildbot@webrtc.org  if (previous_frame_time_ != 0.0) {
7343657d9107db9ffd3dfbe996b9a3af57e4818efb4buildbot@webrtc.org    adapt_frame_drops_data_.AddSample(adapt_frame_drops_);
7353657d9107db9ffd3dfbe996b9a3af57e4818efb4buildbot@webrtc.org    effect_frame_drops_data_.AddSample(effect_frame_drops_);
7363657d9107db9ffd3dfbe996b9a3af57e4818efb4buildbot@webrtc.org    frame_time_data_.AddSample(time_now - previous_frame_time_);
7373657d9107db9ffd3dfbe996b9a3af57e4818efb4buildbot@webrtc.org  }
7383657d9107db9ffd3dfbe996b9a3af57e4818efb4buildbot@webrtc.org  previous_frame_time_ = time_now;
7393657d9107db9ffd3dfbe996b9a3af57e4818efb4buildbot@webrtc.org  effect_frame_drops_ = 0;
7403657d9107db9ffd3dfbe996b9a3af57e4818efb4buildbot@webrtc.org  adapt_frame_drops_ = 0;
7413657d9107db9ffd3dfbe996b9a3af57e4818efb4buildbot@webrtc.org}
7423657d9107db9ffd3dfbe996b9a3af57e4818efb4buildbot@webrtc.org
7437587c5e0b2fb5100b52bf271370ee1369ba18690henrike@webrtc.orgtemplate<class T>
7447587c5e0b2fb5100b52bf271370ee1369ba18690henrike@webrtc.orgvoid VideoCapturer::GetVariableSnapshot(
7452a86ce22ccc387dfa6f8a98ce3eba5c1e6f9e538buildbot@webrtc.org    const rtc::RollingAccumulator<T>& data,
7467587c5e0b2fb5100b52bf271370ee1369ba18690henrike@webrtc.org    VariableInfo<T>* stats) {
7477587c5e0b2fb5100b52bf271370ee1369ba18690henrike@webrtc.org  stats->max_val = data.ComputeMax();
7487587c5e0b2fb5100b52bf271370ee1369ba18690henrike@webrtc.org  stats->mean = data.ComputeMean();
7497587c5e0b2fb5100b52bf271370ee1369ba18690henrike@webrtc.org  stats->min_val = data.ComputeMin();
7507587c5e0b2fb5100b52bf271370ee1369ba18690henrike@webrtc.org  stats->variance = data.ComputeVariance();
7517587c5e0b2fb5100b52bf271370ee1369ba18690henrike@webrtc.org}
7527587c5e0b2fb5100b52bf271370ee1369ba18690henrike@webrtc.org
7530e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org}  // namespace cricket
754