Home | History | Annotate | Download | only in apprtc
      1 /*
      2  *  Copyright 2015 The WebRTC Project Authors. All rights reserved.
      3  *
      4  *  Use of this source code is governed by a BSD-style license
      5  *  that can be found in the LICENSE file in the root of the source
      6  *  tree. An additional intellectual property rights grant can be found
      7  *  in the file PATENTS.  All contributing project authors may
      8  *  be found in the AUTHORS file in the root of the source tree.
      9  */
     10 
     11 package org.appspot.apprtc;
     12 
     13 import android.widget.SeekBar;
     14 import android.widget.TextView;
     15 
     16 import org.webrtc.CameraEnumerationAndroid.CaptureFormat;
     17 
     18 import java.util.Arrays;
     19 import java.util.Collections;
     20 import java.util.Comparator;
     21 import java.util.List;
     22 
     23 /**
     24  * Control capture format based on a seekbar listener.
     25  */
     26 public class CaptureQualityController implements SeekBar.OnSeekBarChangeListener {
     27   private final List<CaptureFormat> formats = Arrays.asList(
     28       new CaptureFormat(1280, 720, 0, 30000),
     29       new CaptureFormat(640, 480, 0, 30000),
     30       new CaptureFormat(320, 240, 0, 30000),
     31       new CaptureFormat(256, 144, 0, 30000));
     32   // Prioritize framerate below this threshold and resolution above the threshold.
     33   private static final int FRAMERATE_THRESHOLD = 15;
     34   private TextView captureFormatText;
     35   private CallFragment.OnCallEvents callEvents;
     36   private int width = 0;
     37   private int height = 0;
     38   private int framerate = 0;
     39   private double targetBandwidth = 0;
     40 
     41   public CaptureQualityController(
     42       TextView captureFormatText, CallFragment.OnCallEvents callEvents) {
     43     this.captureFormatText = captureFormatText;
     44     this.callEvents = callEvents;
     45   }
     46 
     47   private final Comparator<CaptureFormat> compareFormats = new Comparator<CaptureFormat>() {
     48     @Override
     49     public int compare(CaptureFormat first, CaptureFormat second) {
     50       int firstFps = calculateFramerate(targetBandwidth, first);
     51       int secondFps = calculateFramerate(targetBandwidth, second);
     52 
     53      if (firstFps >= FRAMERATE_THRESHOLD && secondFps >= FRAMERATE_THRESHOLD
     54          || firstFps == secondFps) {
     55         // Compare resolution.
     56         return first.width * first.height - second.width * second.height;
     57      } else {
     58         // Compare fps.
     59         return firstFps - secondFps;
     60      }
     61     }
     62   };
     63 
     64   @Override
     65   public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
     66     if (progress == 0) {
     67       width = 0;
     68       height = 0;
     69       framerate = 0;
     70       captureFormatText.setText("Muted");
     71       return;
     72     }
     73 
     74     // Extract max bandwidth (in millipixels / second).
     75     long maxCaptureBandwidth = java.lang.Long.MIN_VALUE;
     76     for (CaptureFormat format : formats) {
     77       maxCaptureBandwidth = Math.max(maxCaptureBandwidth,
     78           (long) format.width * format.height * format.maxFramerate);
     79     }
     80 
     81     // Fraction between 0 and 1.
     82     double bandwidthFraction = (double) progress / 100.0;
     83     // Make a log-scale transformation, still between 0 and 1.
     84     final double kExpConstant = 3.0;
     85     bandwidthFraction =
     86         (Math.exp(kExpConstant * bandwidthFraction) - 1) / (Math.exp(kExpConstant) - 1);
     87     targetBandwidth = bandwidthFraction * maxCaptureBandwidth;
     88 
     89     // Choose the best format given a target bandwidth.
     90     final CaptureFormat bestFormat = Collections.max(formats, compareFormats);
     91     width = bestFormat.width;
     92     height = bestFormat.height;
     93     framerate = calculateFramerate(targetBandwidth, bestFormat);
     94     captureFormatText.setText(width + "x" + height + " @ " + framerate + "fps");
     95   }
     96 
     97   @Override
     98   public void onStartTrackingTouch(SeekBar seekBar) {
     99   }
    100 
    101   @Override
    102   public void onStopTrackingTouch(SeekBar seekBar) {
    103     callEvents.onCaptureFormatChange(width, height, framerate);
    104   }
    105 
    106   // Return the highest frame rate possible based on bandwidth and format.
    107   private int calculateFramerate(double bandwidth, CaptureFormat format) {
    108     return (int) Math.round(Math.min(format.maxFramerate,
    109         (int) Math.round(bandwidth / (format.width * format.height))) / 1000.0);
    110   }
    111 }
    112 
    113