Bug 1063883: use multiples of macroblocks for qm_select downscaling r=pkerr

This commit is contained in:
Randell Jesup 2014-09-06 08:20:10 -04:00
parent 76d7f5c6fa
commit af3712e640
8 changed files with 63 additions and 4 deletions

View File

@ -597,6 +597,15 @@ WebrtcVideoConduit::ConfigureSendMediaCodec(const VideoCodecConfig* codecConfig)
// width/height will be overridden on the first frame
video_codec.width = 320;
video_codec.height = 240;
#ifdef MOZ_WEBRTC_OMX
if (codecConfig->mType == webrtc::kVideoCodecH264) {
video_codec.resolution_divisor = 16;
} else {
video_codec.resolution_divisor = 1; // We could try using it to handle odd resolutions
}
#else
video_codec.resolution_divisor = 1; // We could try using it to handle odd resolutions
#endif
video_codec.qpMax = 56;
video_codec.numberOfSimulcastStreams = 1;
video_codec.mode = webrtc::kRealtimeVideo;
@ -1303,6 +1312,9 @@ WebrtcVideoConduit::CodecConfigToWebRTCCodec(const VideoCodecConfig* codecInfo,
if (cinst.codecType == webrtc::kVideoCodecH264)
{
#ifdef MOZ_WEBRTC_OMX
cinst.resolution_divisor = 16;
#endif
cinst.codecSpecific.H264.profile = codecInfo->mProfile;
cinst.codecSpecific.H264.constraints = codecInfo->mConstraints;
cinst.codecSpecific.H264.level = codecInfo->mLevel;

View File

@ -671,6 +671,8 @@ struct VideoCodec
unsigned short width;
unsigned short height;
// width & height modulo resolution_divisor must be 0
unsigned char resolution_divisor;
unsigned int startBitrate; // kilobits/sec.
unsigned int maxBitrate; // kilobits/sec.

View File

@ -92,6 +92,8 @@ bool VCMCodecDataBase::Codec(int list_id,
settings->maxFramerate = VCM_DEFAULT_FRAME_RATE;
settings->width = VCM_DEFAULT_CODEC_WIDTH;
settings->height = VCM_DEFAULT_CODEC_HEIGHT;
// consider using 2 to avoid deal with 'odd' downscales
settings->resolution_divisor = 1; // may not actually be needed
settings->numberOfSimulcastStreams = 0;
settings->qpMax = 56;
settings->codecSpecific.VP8.resilience = kResilientStream;
@ -118,6 +120,7 @@ bool VCMCodecDataBase::Codec(int list_id,
settings->maxFramerate = VCM_DEFAULT_FRAME_RATE;
settings->width = VCM_DEFAULT_CODEC_WIDTH;
settings->height = VCM_DEFAULT_CODEC_HEIGHT;
settings->resolution_divisor = 1;
settings->minBitrate = VCM_MIN_BITRATE;
settings->numberOfSimulcastStreams = 0;
return true;
@ -318,6 +321,7 @@ bool VCMCodecDataBase::RequiresEncoderReset(const VideoCodec& new_send_codec) {
new_send_codec.plType != send_codec_.plType ||
new_send_codec.width != send_codec_.width ||
new_send_codec.height != send_codec_.height ||
new_send_codec.resolution_divisor != send_codec_.resolution_divisor ||
new_send_codec.maxBitrate != send_codec_.maxBitrate ||
new_send_codec.minBitrate != send_codec_.minBitrate ||
new_send_codec.qpMax != send_codec_.qpMax ||

View File

@ -114,7 +114,7 @@ MediaOptimization::~MediaOptimization(void) {
}
void MediaOptimization::Reset() {
SetEncodingData(kVideoCodecUnknown, 0, 0, 0, 0, 0, 0, max_payload_size_);
SetEncodingData(kVideoCodecUnknown, 0, 0, 0, 0, 0, 1, 0, max_payload_size_);
memset(incoming_frame_times_, -1, sizeof(incoming_frame_times_));
incoming_frame_rate_ = 0.0;
frame_dropper_->Reset();
@ -128,6 +128,8 @@ void MediaOptimization::Reset() {
target_bit_rate_ = 0;
codec_width_ = 0;
codec_height_ = 0;
min_width_ = 0;
min_height_ = 0;
user_frame_rate_ = 0;
key_frame_cnt_ = 0;
delta_frame_cnt_ = 0;
@ -138,12 +140,24 @@ void MediaOptimization::Reset() {
num_layers_ = 1;
}
// Euclid's algorithm
// on arm, binary may be faster, but we do this rarely
static int GreatestCommonDenominator(int a, int b) {
while (b != 0) {
int t = b;
b = a % b;
a = t;
}
return a;
}
void MediaOptimization::SetEncodingData(VideoCodecType send_codec_type,
int32_t max_bit_rate,
uint32_t frame_rate,
uint32_t target_bitrate,
uint16_t width,
uint16_t height,
uint8_t divisor,
int num_layers,
int32_t mtu) {
// Everything codec specific should be reset here since this means the codec
@ -167,6 +181,9 @@ void MediaOptimization::SetEncodingData(VideoCodecType send_codec_type,
user_frame_rate_ = static_cast<float>(frame_rate);
codec_width_ = width;
codec_height_ = height;
int gcd = GreatestCommonDenominator(codec_width_, codec_height_);
min_width_ = gcd ? (codec_width_/gcd * divisor) : 0;
min_height_ = gcd ? (codec_height_/gcd * divisor) : 0;
num_layers_ = (num_layers <= 1) ? 1 : num_layers; // Can also be zero.
max_payload_size_ = mtu;
qm_resolution_->Initialize(target_bitrate_kbps,
@ -555,13 +572,26 @@ bool MediaOptimization::QMUpdate(
codec_width_ = qm->codec_width;
codec_height_ = qm->codec_height;
}
// handle codec limitations on input resolutions
if (codec_width_ % min_width_ != 0 || codec_height_ % min_height_ != 0) {
// XXX find a better algorithm for selecting sizes
// This uses the GCD to find options that meet alignment requirements
// (divisor) and at the same time retain the aspect ratio exactly.
codec_width_ = ((codec_width_ + min_width_-1)/min_width_)*min_width_;
codec_height_ = ((codec_height_ + min_height_-1)/min_height_)*min_height_;
// to avoid confusion later
qm->codec_width = codec_width_;
qm->codec_height = codec_height_;
}
WEBRTC_TRACE(webrtc::kTraceDebug,
webrtc::kTraceVideoCoding,
id_,
"Resolution change from QM select: W = %d, H = %d, FR = %f",
qm->codec_width,
qm->codec_height,
"Resolution change from QM select: W = %d (%d), H = %d (%d), FR = %f",
qm->codec_width, codec_width_,
qm->codec_height, codec_height_,
qm->frame_rate);
// Update VPM with new target frame rate and frame size.

View File

@ -46,6 +46,7 @@ class MediaOptimization {
uint32_t bit_rate,
uint16_t width,
uint16_t height,
uint8_t divisor,
int num_temporal_layers,
int32_t mtu);
@ -133,6 +134,8 @@ class MediaOptimization {
VideoCodecType send_codec_type_;
uint16_t codec_width_;
uint16_t codec_height_;
uint16_t min_width_;
uint16_t min_height_;
float user_frame_rate_;
scoped_ptr<FrameDropper> frame_dropper_;
scoped_ptr<VCMLossProtectionLogic> loss_prot_logic_;

View File

@ -328,6 +328,8 @@ void VCMQmResolution::UpdateRates(float target_bitrate,
// Initialize() state are kept in |down_action_history_|.
// 4) The total amount of down-sampling (spatial and/or temporal) from the
// Initialize() state (native resolution) is limited by various factors.
// 5) If the codec can't handle arbitrary input resolutions, limit to %16==0
// i.e. for h.264
int VCMQmResolution::SelectResolution(VCMResolutionScale** qm) {
if (!init_) {
return VCM_UNINITIALIZED;

View File

@ -42,6 +42,11 @@ struct VCMResolutionScale {
bool change_resolution_temporal;
};
// Other possibilities:
// aspect 1.333*
// kQQVGA = 160x120
// k??? 192x144
// k??? 256x192 (good step between 320x240 and 160x120)
enum ImageType {
kQCIF = 0, // 176x144
kHCIF, // 264x216 = half(~3/4x3/4) CIF.

View File

@ -161,6 +161,7 @@ int32_t VideoSender::RegisterSendCodec(const VideoCodec* sendCodec,
sendCodec->startBitrate * 1000,
sendCodec->width,
sendCodec->height,
sendCodec->resolution_divisor,
numLayers,
maxPayloadSize);
return VCM_OK;