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