Home | History | Annotate | Download | only in base
      1 // libjingle
      2 // Copyright 2010 Google Inc.
      3 //
      4 // Redistribution and use in source and binary forms, with or without
      5 // modification, are permitted provided that the following conditions are met:
      6 //
      7 //  1. Redistributions of source code must retain the above copyright notice,
      8 //     this list of conditions and the following disclaimer.
      9 //  2. Redistributions in binary form must reproduce the above copyright notice,
     10 //     this list of conditions and the following disclaimer in the documentation
     11 //     and/or other materials provided with the distribution.
     12 //  3. The name of the author may not be used to endorse or promote products
     13 //     derived from this software without specific prior written permission.
     14 //
     15 // THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
     16 // WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
     17 // MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
     18 // EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     19 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
     20 // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
     21 // OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
     22 // WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
     23 // OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
     24 // ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     25 //
     26 // Implementation file of class VideoCapturer.
     27 
     28 #include "talk/media/base/videocapturer.h"
     29 
     30 #include <algorithm>
     31 
     32 #if !defined(DISABLE_YUV)
     33 #include "libyuv/scale_argb.h"
     34 #endif
     35 #include "talk/media/base/videoframefactory.h"
     36 #include "talk/media/base/videoprocessor.h"
     37 #include "webrtc/base/common.h"
     38 #include "webrtc/base/logging.h"
     39 #include "webrtc/base/systeminfo.h"
     40 
     41 #if defined(HAVE_WEBRTC_VIDEO)
     42 #include "talk/media/webrtc/webrtcvideoframe.h"
     43 #include "talk/media/webrtc/webrtcvideoframefactory.h"
     44 #endif  // HAVE_WEBRTC_VIDEO
     45 
     46 namespace cricket {
     47 
     48 namespace {
     49 
     50 // TODO(thorcarpenter): This is a BIG hack to flush the system with black
     51 // frames. Frontends should coordinate to update the video state of a muted
     52 // user. When all frontends to this consider removing the black frame business.
     53 const int kNumBlackFramesOnMute = 30;
     54 
     55 // MessageHandler constants.
     56 enum {
     57   MSG_DO_PAUSE = 0,
     58   MSG_DO_UNPAUSE,
     59   MSG_STATE_CHANGE
     60 };
     61 
     62 static const int64 kMaxDistance = ~(static_cast<int64>(1) << 63);
     63 #ifdef LINUX
     64 static const int kYU12Penalty = 16;  // Needs to be higher than MJPG index.
     65 #endif
     66 static const int kDefaultScreencastFps = 5;
     67 typedef rtc::TypedMessageData<CaptureState> StateChangeParams;
     68 
     69 // Limit stats data collections to ~20 seconds of 30fps data before dropping
     70 // old data in case stats aren't reset for long periods of time.
     71 static const size_t kMaxAccumulatorSize = 600;
     72 
     73 }  // namespace
     74 
     75 /////////////////////////////////////////////////////////////////////
     76 // Implementation of struct CapturedFrame
     77 /////////////////////////////////////////////////////////////////////
     78 CapturedFrame::CapturedFrame()
     79     : width(0),
     80       height(0),
     81       fourcc(0),
     82       pixel_width(0),
     83       pixel_height(0),
     84       elapsed_time(0),
     85       time_stamp(0),
     86       data_size(0),
     87       rotation(0),
     88       data(NULL) {}
     89 
     90 // TODO(fbarchard): Remove this function once lmimediaengine stops using it.
     91 bool CapturedFrame::GetDataSize(uint32* size) const {
     92   if (!size || data_size == CapturedFrame::kUnknownDataSize) {
     93     return false;
     94   }
     95   *size = data_size;
     96   return true;
     97 }
     98 
     99 /////////////////////////////////////////////////////////////////////
    100 // Implementation of class VideoCapturer
    101 /////////////////////////////////////////////////////////////////////
    102 VideoCapturer::VideoCapturer()
    103     : thread_(rtc::Thread::Current()),
    104       adapt_frame_drops_data_(kMaxAccumulatorSize),
    105       effect_frame_drops_data_(kMaxAccumulatorSize),
    106       frame_time_data_(kMaxAccumulatorSize) {
    107   Construct();
    108 }
    109 
    110 VideoCapturer::VideoCapturer(rtc::Thread* thread)
    111     : thread_(thread),
    112       adapt_frame_drops_data_(kMaxAccumulatorSize),
    113       effect_frame_drops_data_(kMaxAccumulatorSize),
    114       frame_time_data_(kMaxAccumulatorSize) {
    115   Construct();
    116 }
    117 
    118 void VideoCapturer::Construct() {
    119   ClearAspectRatio();
    120   enable_camera_list_ = false;
    121   square_pixel_aspect_ratio_ = false;
    122   capture_state_ = CS_STOPPED;
    123   SignalFrameCaptured.connect(this, &VideoCapturer::OnFrameCaptured);
    124   scaled_width_ = 0;
    125   scaled_height_ = 0;
    126   screencast_max_pixels_ = 0;
    127   muted_ = false;
    128   black_frame_count_down_ = kNumBlackFramesOnMute;
    129   enable_video_adapter_ = true;
    130   adapt_frame_drops_ = 0;
    131   effect_frame_drops_ = 0;
    132   previous_frame_time_ = 0.0;
    133 #ifdef HAVE_WEBRTC_VIDEO
    134   // There are lots of video capturers out there that don't call
    135   // set_frame_factory.  We can either go change all of them, or we
    136   // can set this default.
    137   // TODO(pthatcher): Remove this hack and require the frame factory
    138   // to be passed in the constructor.
    139   set_frame_factory(new WebRtcVideoFrameFactory());
    140 #endif
    141 }
    142 
    143 const std::vector<VideoFormat>* VideoCapturer::GetSupportedFormats() const {
    144   return &filtered_supported_formats_;
    145 }
    146 
    147 bool VideoCapturer::StartCapturing(const VideoFormat& capture_format) {
    148   previous_frame_time_ = frame_length_time_reporter_.TimerNow();
    149   CaptureState result = Start(capture_format);
    150   const bool success = (result == CS_RUNNING) || (result == CS_STARTING);
    151   if (!success) {
    152     return false;
    153   }
    154   if (result == CS_RUNNING) {
    155     SetCaptureState(result);
    156   }
    157   return true;
    158 }
    159 
    160 void VideoCapturer::UpdateAspectRatio(int ratio_w, int ratio_h) {
    161   if (ratio_w == 0 || ratio_h == 0) {
    162     LOG(LS_WARNING) << "UpdateAspectRatio ignored invalid ratio: "
    163                     << ratio_w << "x" << ratio_h;
    164     return;
    165   }
    166   ratio_w_ = ratio_w;
    167   ratio_h_ = ratio_h;
    168 }
    169 
    170 void VideoCapturer::ClearAspectRatio() {
    171   ratio_w_ = 0;
    172   ratio_h_ = 0;
    173 }
    174 
    175 // Override this to have more control of how your device is started/stopped.
    176 bool VideoCapturer::Pause(bool pause) {
    177   if (pause) {
    178     if (capture_state() == CS_PAUSED) {
    179       return true;
    180     }
    181     bool is_running = capture_state() == CS_STARTING ||
    182         capture_state() == CS_RUNNING;
    183     if (!is_running) {
    184       LOG(LS_ERROR) << "Cannot pause a stopped camera.";
    185       return false;
    186     }
    187     LOG(LS_INFO) << "Pausing a camera.";
    188     rtc::scoped_ptr<VideoFormat> capture_format_when_paused(
    189         capture_format_ ? new VideoFormat(*capture_format_) : NULL);
    190     Stop();
    191     SetCaptureState(CS_PAUSED);
    192     // If you override this function be sure to restore the capture format
    193     // after calling Stop().
    194     SetCaptureFormat(capture_format_when_paused.get());
    195   } else {  // Unpause.
    196     if (capture_state() != CS_PAUSED) {
    197       LOG(LS_WARNING) << "Cannot unpause a camera that hasn't been paused.";
    198       return false;
    199     }
    200     if (!capture_format_) {
    201       LOG(LS_ERROR) << "Missing capture_format_, cannot unpause a camera.";
    202       return false;
    203     }
    204     if (muted_) {
    205       LOG(LS_WARNING) << "Camera cannot be unpaused while muted.";
    206       return false;
    207     }
    208     LOG(LS_INFO) << "Unpausing a camera.";
    209     if (!Start(*capture_format_)) {
    210       LOG(LS_ERROR) << "Camera failed to start when unpausing.";
    211       return false;
    212     }
    213   }
    214   return true;
    215 }
    216 
    217 bool VideoCapturer::Restart(const VideoFormat& capture_format) {
    218   if (!IsRunning()) {
    219     return StartCapturing(capture_format);
    220   }
    221 
    222   if (GetCaptureFormat() != NULL && *GetCaptureFormat() == capture_format) {
    223     // The reqested format is the same; nothing to do.
    224     return true;
    225   }
    226 
    227   Stop();
    228   return StartCapturing(capture_format);
    229 }
    230 
    231 bool VideoCapturer::MuteToBlackThenPause(bool muted) {
    232   if (muted == IsMuted()) {
    233     return true;
    234   }
    235 
    236   LOG(LS_INFO) << (muted ? "Muting" : "Unmuting") << " this video capturer.";
    237   muted_ = muted;  // Do this before calling Pause().
    238   if (muted) {
    239     // Reset black frame count down.
    240     black_frame_count_down_ = kNumBlackFramesOnMute;
    241     // Following frames will be overritten with black, then the camera will be
    242     // paused.
    243     return true;
    244   }
    245   // Start the camera.
    246   thread_->Clear(this, MSG_DO_PAUSE);
    247   return Pause(false);
    248 }
    249 
    250 void VideoCapturer::SetSupportedFormats(
    251     const std::vector<VideoFormat>& formats) {
    252   supported_formats_ = formats;
    253   UpdateFilteredSupportedFormats();
    254 }
    255 
    256 bool VideoCapturer::GetBestCaptureFormat(const VideoFormat& format,
    257                                          VideoFormat* best_format) {
    258   // TODO(fbarchard): Directly support max_format.
    259   UpdateFilteredSupportedFormats();
    260   const std::vector<VideoFormat>* supported_formats = GetSupportedFormats();
    261 
    262   if (supported_formats->empty()) {
    263     return false;
    264   }
    265   LOG(LS_INFO) << " Capture Requested " << format.ToString();
    266   int64 best_distance = kMaxDistance;
    267   std::vector<VideoFormat>::const_iterator best = supported_formats->end();
    268   std::vector<VideoFormat>::const_iterator i;
    269   for (i = supported_formats->begin(); i != supported_formats->end(); ++i) {
    270     int64 distance = GetFormatDistance(format, *i);
    271     // TODO(fbarchard): Reduce to LS_VERBOSE if/when camera capture is
    272     // relatively bug free.
    273     LOG(LS_INFO) << " Supported " << i->ToString() << " distance " << distance;
    274     if (distance < best_distance) {
    275       best_distance = distance;
    276       best = i;
    277     }
    278   }
    279   if (supported_formats->end() == best) {
    280     LOG(LS_ERROR) << " No acceptable camera format found";
    281     return false;
    282   }
    283 
    284   if (best_format) {
    285     best_format->width = best->width;
    286     best_format->height = best->height;
    287     best_format->fourcc = best->fourcc;
    288     best_format->interval = best->interval;
    289     LOG(LS_INFO) << " Best " << best_format->ToString() << " Interval "
    290                  << best_format->interval << " distance " << best_distance;
    291   }
    292   return true;
    293 }
    294 
    295 void VideoCapturer::AddVideoProcessor(VideoProcessor* video_processor) {
    296   rtc::CritScope cs(&crit_);
    297   ASSERT(std::find(video_processors_.begin(), video_processors_.end(),
    298                    video_processor) == video_processors_.end());
    299   video_processors_.push_back(video_processor);
    300 }
    301 
    302 bool VideoCapturer::RemoveVideoProcessor(VideoProcessor* video_processor) {
    303   rtc::CritScope cs(&crit_);
    304   VideoProcessors::iterator found = std::find(
    305       video_processors_.begin(), video_processors_.end(), video_processor);
    306   if (found == video_processors_.end()) {
    307     return false;
    308   }
    309   video_processors_.erase(found);
    310   return true;
    311 }
    312 
    313 void VideoCapturer::ConstrainSupportedFormats(const VideoFormat& max_format) {
    314   max_format_.reset(new VideoFormat(max_format));
    315   LOG(LS_VERBOSE) << " ConstrainSupportedFormats " << max_format.ToString();
    316   UpdateFilteredSupportedFormats();
    317 }
    318 
    319 std::string VideoCapturer::ToString(const CapturedFrame* captured_frame) const {
    320   std::string fourcc_name = GetFourccName(captured_frame->fourcc) + " ";
    321   for (std::string::const_iterator i = fourcc_name.begin();
    322        i < fourcc_name.end(); ++i) {
    323     // Test character is printable; Avoid isprint() which asserts on negatives.
    324     if (*i < 32 || *i >= 127) {
    325       fourcc_name = "";
    326       break;
    327     }
    328   }
    329 
    330   std::ostringstream ss;
    331   ss << fourcc_name << captured_frame->width << "x" << captured_frame->height
    332      << "x" << VideoFormat::IntervalToFpsFloat(captured_frame->elapsed_time);
    333   return ss.str();
    334 }
    335 
    336 void VideoCapturer::GetStats(VariableInfo<int>* adapt_drops_stats,
    337                              VariableInfo<int>* effect_drops_stats,
    338                              VariableInfo<double>* frame_time_stats,
    339                              VideoFormat* last_captured_frame_format) {
    340   rtc::CritScope cs(&frame_stats_crit_);
    341   GetVariableSnapshot(adapt_frame_drops_data_, adapt_drops_stats);
    342   GetVariableSnapshot(effect_frame_drops_data_, effect_drops_stats);
    343   GetVariableSnapshot(frame_time_data_, frame_time_stats);
    344   *last_captured_frame_format = last_captured_frame_format_;
    345 
    346   adapt_frame_drops_data_.Reset();
    347   effect_frame_drops_data_.Reset();
    348   frame_time_data_.Reset();
    349 }
    350 
    351 void VideoCapturer::OnFrameCaptured(VideoCapturer*,
    352                                     const CapturedFrame* captured_frame) {
    353   if (muted_) {
    354     if (black_frame_count_down_ == 0) {
    355       thread_->Post(this, MSG_DO_PAUSE, NULL);
    356     } else {
    357       --black_frame_count_down_;
    358     }
    359   }
    360 
    361   if (SignalVideoFrame.is_empty()) {
    362     return;
    363   }
    364 #if !defined(DISABLE_YUV)
    365   if (IsScreencast()) {
    366     int scaled_width, scaled_height;
    367     if (screencast_max_pixels_ > 0) {
    368       ComputeScaleMaxPixels(captured_frame->width, captured_frame->height,
    369           screencast_max_pixels_, &scaled_width, &scaled_height);
    370     } else {
    371       int desired_screencast_fps = capture_format_.get() ?
    372           VideoFormat::IntervalToFps(capture_format_->interval) :
    373           kDefaultScreencastFps;
    374       ComputeScale(captured_frame->width, captured_frame->height,
    375                    desired_screencast_fps, &scaled_width, &scaled_height);
    376     }
    377 
    378     if (FOURCC_ARGB == captured_frame->fourcc &&
    379         (scaled_width != captured_frame->width ||
    380         scaled_height != captured_frame->height)) {
    381       if (scaled_width != scaled_width_ || scaled_height != scaled_height_) {
    382         LOG(LS_INFO) << "Scaling Screencast from "
    383                      << captured_frame->width << "x"
    384                      << captured_frame->height << " to "
    385                      << scaled_width << "x" << scaled_height;
    386         scaled_width_ = scaled_width;
    387         scaled_height_ = scaled_height;
    388       }
    389       CapturedFrame* modified_frame =
    390           const_cast<CapturedFrame*>(captured_frame);
    391       // Compute new width such that width * height is less than maximum but
    392       // maintains original captured frame aspect ratio.
    393       // Round down width to multiple of 4 so odd width won't round up beyond
    394       // maximum, and so chroma channel is even width to simplify spatial
    395       // resampling.
    396       libyuv::ARGBScale(reinterpret_cast<const uint8*>(captured_frame->data),
    397                         captured_frame->width * 4, captured_frame->width,
    398                         captured_frame->height,
    399                         reinterpret_cast<uint8*>(modified_frame->data),
    400                         scaled_width * 4, scaled_width, scaled_height,
    401                         libyuv::kFilterBilinear);
    402       modified_frame->width = scaled_width;
    403       modified_frame->height = scaled_height;
    404       modified_frame->data_size = scaled_width * 4 * scaled_height;
    405     }
    406   }
    407 
    408   const int kYuy2Bpp = 2;
    409   const int kArgbBpp = 4;
    410   // TODO(fbarchard): Make a helper function to adjust pixels to square.
    411   // TODO(fbarchard): Hook up experiment to scaling.
    412   // TODO(fbarchard): Avoid scale and convert if muted.
    413   // Temporary buffer is scoped here so it will persist until i420_frame.Init()
    414   // makes a copy of the frame, converting to I420.
    415   rtc::scoped_ptr<uint8[]> temp_buffer;
    416   // YUY2 can be scaled vertically using an ARGB scaler.  Aspect ratio is only
    417   // a problem on OSX.  OSX always converts webcams to YUY2 or UYVY.
    418   bool can_scale =
    419       FOURCC_YUY2 == CanonicalFourCC(captured_frame->fourcc) ||
    420       FOURCC_UYVY == CanonicalFourCC(captured_frame->fourcc);
    421 
    422   // If pixels are not square, optionally use vertical scaling to make them
    423   // square.  Square pixels simplify the rest of the pipeline, including
    424   // effects and rendering.
    425   if (can_scale && square_pixel_aspect_ratio_ &&
    426       captured_frame->pixel_width != captured_frame->pixel_height) {
    427     int scaled_width, scaled_height;
    428     // modified_frame points to the captured_frame but with const casted away
    429     // so it can be modified.
    430     CapturedFrame* modified_frame = const_cast<CapturedFrame*>(captured_frame);
    431     // Compute the frame size that makes pixels square pixel aspect ratio.
    432     ComputeScaleToSquarePixels(captured_frame->width, captured_frame->height,
    433                                captured_frame->pixel_width,
    434                                captured_frame->pixel_height,
    435                                &scaled_width, &scaled_height);
    436 
    437     if (scaled_width != scaled_width_ || scaled_height != scaled_height_) {
    438       LOG(LS_INFO) << "Scaling WebCam from "
    439                    << captured_frame->width << "x"
    440                    << captured_frame->height << " to "
    441                    << scaled_width << "x" << scaled_height
    442                    << " for PAR "
    443                    << captured_frame->pixel_width << "x"
    444                    << captured_frame->pixel_height;
    445       scaled_width_ = scaled_width;
    446       scaled_height_ = scaled_height;
    447     }
    448     const int modified_frame_size = scaled_width * scaled_height * kYuy2Bpp;
    449     uint8* temp_buffer_data;
    450     // Pixels are wide and short; Increasing height. Requires temporary buffer.
    451     if (scaled_height > captured_frame->height) {
    452       temp_buffer.reset(new uint8[modified_frame_size]);
    453       temp_buffer_data = temp_buffer.get();
    454     } else {
    455       // Pixels are narrow and tall; Decreasing height. Scale will be done
    456       // in place.
    457       temp_buffer_data = reinterpret_cast<uint8*>(captured_frame->data);
    458     }
    459 
    460     // Use ARGBScaler to vertically scale the YUY2 image, adjusting for 16 bpp.
    461     libyuv::ARGBScale(reinterpret_cast<const uint8*>(captured_frame->data),
    462                       captured_frame->width * kYuy2Bpp,  // Stride for YUY2.
    463                       captured_frame->width * kYuy2Bpp / kArgbBpp,  // Width.
    464                       abs(captured_frame->height),  // Height.
    465                       temp_buffer_data,
    466                       scaled_width * kYuy2Bpp,  // Stride for YUY2.
    467                       scaled_width * kYuy2Bpp / kArgbBpp,  // Width.
    468                       abs(scaled_height),  // New height.
    469                       libyuv::kFilterBilinear);
    470     modified_frame->width = scaled_width;
    471     modified_frame->height = scaled_height;
    472     modified_frame->pixel_width = 1;
    473     modified_frame->pixel_height = 1;
    474     modified_frame->data_size = modified_frame_size;
    475     modified_frame->data = temp_buffer_data;
    476   }
    477 #endif  // !DISABLE_YUV
    478 
    479   // Size to crop captured frame to.  This adjusts the captured frames
    480   // aspect ratio to match the final view aspect ratio, considering pixel
    481   // aspect ratio and rotation.  The final size may be scaled down by video
    482   // adapter to better match ratio_w_ x ratio_h_.
    483   // Note that abs() of frame height is passed in, because source may be
    484   // inverted, but output will be positive.
    485   int desired_width = captured_frame->width;
    486   int desired_height = captured_frame->height;
    487 
    488   // TODO(fbarchard): Improve logic to pad or crop.
    489   // MJPG can crop vertically, but not horizontally.  This logic disables crop.
    490   // Alternatively we could pad the image with black, or implement a 2 step
    491   // crop.
    492   bool can_crop = true;
    493   if (captured_frame->fourcc == FOURCC_MJPG) {
    494     float cam_aspect = static_cast<float>(captured_frame->width) /
    495         static_cast<float>(captured_frame->height);
    496     float view_aspect = static_cast<float>(ratio_w_) /
    497         static_cast<float>(ratio_h_);
    498     can_crop = cam_aspect <= view_aspect;
    499   }
    500   if (can_crop && !IsScreencast()) {
    501     // TODO(ronghuawu): The capturer should always produce the native
    502     // resolution and the cropping should be done in downstream code.
    503     ComputeCrop(ratio_w_, ratio_h_, captured_frame->width,
    504                 abs(captured_frame->height), captured_frame->pixel_width,
    505                 captured_frame->pixel_height, captured_frame->rotation,
    506                 &desired_width, &desired_height);
    507   }
    508 
    509   if (!frame_factory_) {
    510     LOG(LS_ERROR) << "No video frame factory.";
    511     return;
    512   }
    513 
    514   rtc::scoped_ptr<VideoFrame> i420_frame(
    515       frame_factory_->CreateAliasedFrame(
    516           captured_frame, desired_width, desired_height));
    517   if (!i420_frame) {
    518     // TODO(fbarchard): LOG more information about captured frame attributes.
    519     LOG(LS_ERROR) << "Couldn't convert to I420! "
    520                   << "From " << ToString(captured_frame) << " To "
    521                   << desired_width << " x " << desired_height;
    522     return;
    523   }
    524 
    525   VideoFrame* adapted_frame = i420_frame.get();
    526   if (enable_video_adapter_ && !IsScreencast()) {
    527     VideoFrame* out_frame = NULL;
    528     video_adapter_.AdaptFrame(adapted_frame, &out_frame);
    529     if (!out_frame) {
    530       // VideoAdapter dropped the frame.
    531       ++adapt_frame_drops_;
    532       return;
    533     }
    534     adapted_frame = out_frame;
    535   }
    536 
    537   if (!muted_ && !ApplyProcessors(adapted_frame)) {
    538     // Processor dropped the frame.
    539     ++effect_frame_drops_;
    540     return;
    541   }
    542   if (muted_) {
    543     // TODO(pthatcher): Use frame_factory_->CreateBlackFrame() instead.
    544     adapted_frame->SetToBlack();
    545   }
    546   SignalVideoFrame(this, adapted_frame);
    547 
    548   UpdateStats(captured_frame);
    549 }
    550 
    551 void VideoCapturer::SetCaptureState(CaptureState state) {
    552   if (state == capture_state_) {
    553     // Don't trigger a state changed callback if the state hasn't changed.
    554     return;
    555   }
    556   StateChangeParams* state_params = new StateChangeParams(state);
    557   capture_state_ = state;
    558   thread_->Post(this, MSG_STATE_CHANGE, state_params);
    559 }
    560 
    561 void VideoCapturer::OnMessage(rtc::Message* message) {
    562   switch (message->message_id) {
    563     case MSG_STATE_CHANGE: {
    564       rtc::scoped_ptr<StateChangeParams> p(
    565           static_cast<StateChangeParams*>(message->pdata));
    566       SignalStateChange(this, p->data());
    567       break;
    568     }
    569     case MSG_DO_PAUSE: {
    570       Pause(true);
    571       break;
    572     }
    573     case MSG_DO_UNPAUSE: {
    574       Pause(false);
    575       break;
    576     }
    577     default: {
    578       ASSERT(false);
    579     }
    580   }
    581 }
    582 
    583 // Get the distance between the supported and desired formats.
    584 // Prioritization is done according to this algorithm:
    585 // 1) Width closeness. If not same, we prefer wider.
    586 // 2) Height closeness. If not same, we prefer higher.
    587 // 3) Framerate closeness. If not same, we prefer faster.
    588 // 4) Compression. If desired format has a specific fourcc, we need exact match;
    589 //                otherwise, we use preference.
    590 int64 VideoCapturer::GetFormatDistance(const VideoFormat& desired,
    591                                        const VideoFormat& supported) {
    592   int64 distance = kMaxDistance;
    593 
    594   // Check fourcc.
    595   uint32 supported_fourcc = CanonicalFourCC(supported.fourcc);
    596   int64 delta_fourcc = kMaxDistance;
    597   if (FOURCC_ANY == desired.fourcc) {
    598     // Any fourcc is OK for the desired. Use preference to find best fourcc.
    599     std::vector<uint32> preferred_fourccs;
    600     if (!GetPreferredFourccs(&preferred_fourccs)) {
    601       return distance;
    602     }
    603 
    604     for (size_t i = 0; i < preferred_fourccs.size(); ++i) {
    605       if (supported_fourcc == CanonicalFourCC(preferred_fourccs[i])) {
    606         delta_fourcc = i;
    607 #ifdef LINUX
    608         // For HD avoid YU12 which is a software conversion and has 2 bugs
    609         // b/7326348 b/6960899.  Reenable when fixed.
    610         if (supported.height >= 720 && (supported_fourcc == FOURCC_YU12 ||
    611                                         supported_fourcc == FOURCC_YV12)) {
    612           delta_fourcc += kYU12Penalty;
    613         }
    614 #endif
    615         break;
    616       }
    617     }
    618   } else if (supported_fourcc == CanonicalFourCC(desired.fourcc)) {
    619     delta_fourcc = 0;  // Need exact match.
    620   }
    621 
    622   if (kMaxDistance == delta_fourcc) {
    623     // Failed to match fourcc.
    624     return distance;
    625   }
    626 
    627   // Check resolution and fps.
    628   int desired_width = desired.width;
    629   int desired_height = desired.height;
    630   int64 delta_w = supported.width - desired_width;
    631   float supported_fps = VideoFormat::IntervalToFpsFloat(supported.interval);
    632   float delta_fps =
    633       supported_fps - VideoFormat::IntervalToFpsFloat(desired.interval);
    634   // Check height of supported height compared to height we would like it to be.
    635   int64 aspect_h =
    636       desired_width ? supported.width * desired_height / desired_width
    637                     : desired_height;
    638   int64 delta_h = supported.height - aspect_h;
    639 
    640   distance = 0;
    641   // Set high penalty if the supported format is lower than the desired format.
    642   // 3x means we would prefer down to down to 3/4, than up to double.
    643   // But we'd prefer up to double than down to 1/2.  This is conservative,
    644   // strongly avoiding going down in resolution, similar to
    645   // the old method, but not completely ruling it out in extreme situations.
    646   // It also ignores framerate, which is often very low at high resolutions.
    647   // TODO(fbarchard): Improve logic to use weighted factors.
    648   static const int kDownPenalty = -3;
    649   if (delta_w < 0) {
    650     delta_w = delta_w * kDownPenalty;
    651   }
    652   if (delta_h < 0) {
    653     delta_h = delta_h * kDownPenalty;
    654   }
    655   // Require camera fps to be at least 80% of what is requested if resolution
    656   // matches.
    657   // Require camera fps to be at least 96% of what is requested, or higher,
    658   // if resolution differs. 96% allows for slight variations in fps. e.g. 29.97
    659   if (delta_fps < 0) {
    660     float min_desirable_fps = delta_w ?
    661     VideoFormat::IntervalToFpsFloat(desired.interval) * 28.f / 30.f :
    662     VideoFormat::IntervalToFpsFloat(desired.interval) * 23.f / 30.f;
    663     delta_fps = -delta_fps;
    664     if (supported_fps < min_desirable_fps) {
    665       distance |= static_cast<int64>(1) << 62;
    666     } else {
    667       distance |= static_cast<int64>(1) << 15;
    668     }
    669   }
    670   int64 idelta_fps = static_cast<int>(delta_fps);
    671 
    672   // 12 bits for width and height and 8 bits for fps and fourcc.
    673   distance |=
    674       (delta_w << 28) | (delta_h << 16) | (idelta_fps << 8) | delta_fourcc;
    675 
    676   return distance;
    677 }
    678 
    679 bool VideoCapturer::ApplyProcessors(VideoFrame* video_frame) {
    680   bool drop_frame = false;
    681   rtc::CritScope cs(&crit_);
    682   for (VideoProcessors::iterator iter = video_processors_.begin();
    683        iter != video_processors_.end(); ++iter) {
    684     (*iter)->OnFrame(kDummyVideoSsrc, video_frame, &drop_frame);
    685     if (drop_frame) {
    686       return false;
    687     }
    688   }
    689   return true;
    690 }
    691 
    692 void VideoCapturer::UpdateFilteredSupportedFormats() {
    693   filtered_supported_formats_.clear();
    694   filtered_supported_formats_ = supported_formats_;
    695   if (!max_format_) {
    696     return;
    697   }
    698   std::vector<VideoFormat>::iterator iter = filtered_supported_formats_.begin();
    699   while (iter != filtered_supported_formats_.end()) {
    700     if (ShouldFilterFormat(*iter)) {
    701       iter = filtered_supported_formats_.erase(iter);
    702     } else {
    703       ++iter;
    704     }
    705   }
    706   if (filtered_supported_formats_.empty()) {
    707     // The device only captures at resolutions higher than |max_format_| this
    708     // indicates that |max_format_| should be ignored as it is better to capture
    709     // at too high a resolution than to not capture at all.
    710     filtered_supported_formats_ = supported_formats_;
    711   }
    712 }
    713 
    714 bool VideoCapturer::ShouldFilterFormat(const VideoFormat& format) const {
    715   if (!enable_camera_list_) {
    716     return false;
    717   }
    718   return format.width > max_format_->width ||
    719          format.height > max_format_->height;
    720 }
    721 
    722 void VideoCapturer::UpdateStats(const CapturedFrame* captured_frame) {
    723   // Update stats protected from fetches from different thread.
    724   rtc::CritScope cs(&frame_stats_crit_);
    725 
    726   last_captured_frame_format_.width = captured_frame->width;
    727   last_captured_frame_format_.height = captured_frame->height;
    728   // TODO(ronghuawu): Useful to report interval as well?
    729   last_captured_frame_format_.interval = 0;
    730   last_captured_frame_format_.fourcc = captured_frame->fourcc;
    731 
    732   double time_now = frame_length_time_reporter_.TimerNow();
    733   if (previous_frame_time_ != 0.0) {
    734     adapt_frame_drops_data_.AddSample(adapt_frame_drops_);
    735     effect_frame_drops_data_.AddSample(effect_frame_drops_);
    736     frame_time_data_.AddSample(time_now - previous_frame_time_);
    737   }
    738   previous_frame_time_ = time_now;
    739   effect_frame_drops_ = 0;
    740   adapt_frame_drops_ = 0;
    741 }
    742 
    743 template<class T>
    744 void VideoCapturer::GetVariableSnapshot(
    745     const rtc::RollingAccumulator<T>& data,
    746     VariableInfo<T>* stats) {
    747   stats->max_val = data.ComputeMax();
    748   stats->mean = data.ComputeMean();
    749   stats->min_val = data.ComputeMin();
    750   stats->variance = data.ComputeVariance();
    751 }
    752 
    753 }  // namespace cricket
    754