Add stats for average QP per frame for VP8 (for received video streams):

"WebRTC.Video.Decoded.VP8.Qp"

BUG=chromium:512752

Review URL: https://codereview.webrtc.org/1340623002

Cr-Commit-Position: refs/heads/master@{#10349}
This commit is contained in:
asapersson 2015-10-20 23:55:26 -07:00 committed by Commit bot
parent 47dcb23393
commit 86b016027d
16 changed files with 180 additions and 39 deletions

View File

@ -795,8 +795,11 @@ bool MediaCodecVideoEncoder::DeliverPendingOutputs(JNIEnv* jni) {
header.fragmentationLength[0] = image->_length;
header.fragmentationPlType[0] = 0;
header.fragmentationTimeDiff[0] = 0;
if (scale_)
quality_scaler_.ReportQP(webrtc::vp8::GetQP(payload));
if (scale_) {
int qp;
if (webrtc::vp8::GetQp(payload, payload_size, &qp))
quality_scaler_.ReportQP(qp);
}
} else if (codecType_ == kVideoCodecH264) {
if (scale_) {
h264_bitstream_parser_.ParseBitstream(payload, payload_size);

View File

@ -96,8 +96,10 @@ source_set("video_coding_utility") {
"utility/frame_dropper.cc",
"utility/include/frame_dropper.h",
"utility/include/moving_average.h",
"utility/include/qp_parser.h",
"utility/include/quality_scaler.h",
"utility/include/vp8_header_parser.h",
"utility/qp_parser.cc",
"utility/quality_scaler.cc",
"utility/vp8_header_parser.cc",
]

View File

@ -132,7 +132,7 @@ public:
// to have. Usually MTU - overhead.
//
// Return value : VCM_OK, on success.
// < 0, on error.
// < 0, on error.
virtual int32_t RegisterSendCodec(const VideoCodec* sendCodec,
uint32_t numberOfCores,
uint32_t maxPayloadSize) = 0;
@ -154,7 +154,7 @@ public:
// - currentSendCodec : Address where the sendCodec will be written.
//
// Return value : VCM_OK, on success.
// < 0, on error.
// < 0, on error.
//
// NOTE: The returned codec information is not guaranteed to be current when
// the call returns. This method acquires a lock that is aligned with
@ -180,7 +180,7 @@ public:
// - payloadType : The payload type bound which this encoder is bound to.
//
// Return value : VCM_OK, on success.
// < 0, on error.
// < 0, on error.
virtual int32_t RegisterExternalEncoder(VideoEncoder* externalEncoder,
uint8_t payloadType,
bool internalSource = false) = 0;
@ -232,7 +232,7 @@ public:
// scenario
//
// Return value : VCM_OK, on success.
// < 0, on error.
// < 0, on error.
virtual int32_t SetReceiveChannelParameters(int64_t rtt) = 0;
// Register a transport callback which will be called to deliver the encoded data and
@ -242,7 +242,7 @@ public:
// - transport : The callback object to register.
//
// Return value : VCM_OK, on success.
// < 0, on error.
// < 0, on error.
virtual int32_t RegisterTransportCallback(VCMPacketizationCallback* transport) = 0;
// Register video output information callback which will be called to deliver information
@ -253,7 +253,7 @@ public:
// - outputInformation : The callback object to register.
//
// Return value : VCM_OK, on success.
// < 0, on error.
// < 0, on error.
virtual int32_t RegisterSendStatisticsCallback(
VCMSendStatisticsCallback* sendStats) = 0;
@ -264,7 +264,7 @@ public:
// - protection : The callback object to register.
//
// Return value : VCM_OK, on success.
// < 0, on error.
// < 0, on error.
virtual int32_t RegisterProtectionCallback(VCMProtectionCallback* protection) = 0;
// Enable or disable a video protection method.
@ -275,7 +275,7 @@ public:
// it should be disabled.
//
// Return value : VCM_OK, on success.
// < 0, on error.
// < 0, on error.
virtual int32_t SetVideoProtection(VCMVideoProtection videoProtection,
bool enable) = 0;
@ -289,7 +289,7 @@ public:
// - codecSpecificInfo : Extra codec information, e.g., pre-parsed in-band signaling.
//
// Return value : VCM_OK, on success.
// < 0, on error.
// < 0, on error.
virtual int32_t AddVideoFrame(
const VideoFrame& videoFrame,
const VideoContentMetrics* contentMetrics = NULL,
@ -298,7 +298,7 @@ public:
// Next frame encoded should be an intra frame (keyframe).
//
// Return value : VCM_OK, on success.
// < 0, on error.
// < 0, on error.
virtual int32_t IntraFrameRequest(int stream_index) = 0;
// Frame Dropper enable. Can be used to disable the frame dropping when the encoder
@ -310,7 +310,7 @@ public:
// - enable : True to enable the setting, false to disable it.
//
// Return value : VCM_OK, on success.
// < 0, on error.
// < 0, on error.
virtual int32_t EnableFrameDropper(bool enable) = 0;
@ -329,7 +329,7 @@ public:
// to be decoded until the first key frame has been decoded.
//
// Return value : VCM_OK, on success.
// < 0, on error.
// < 0, on error.
virtual int32_t RegisterReceiveCodec(const VideoCodec* receiveCodec,
int32_t numberOfCores,
bool requireKeyFrame = false) = 0;
@ -346,7 +346,7 @@ public:
// object can make sure to render at a given time in ms.
//
// Return value : VCM_OK, on success.
// < 0, on error.
// < 0, on error.
virtual int32_t RegisterExternalDecoder(VideoDecoder* externalDecoder,
uint8_t payloadType,
bool internalRenderTiming) = 0;
@ -360,7 +360,7 @@ public:
// De-register with a NULL pointer.
//
// Return value : VCM_OK, on success.
// < 0, on error.
// < 0, on error.
virtual int32_t RegisterReceiveCallback(VCMReceiveCallback* receiveCallback) = 0;
// Register a receive statistics callback which will be called to deliver information
@ -371,7 +371,7 @@ public:
// - receiveStats : The callback object to register.
//
// Return value : VCM_OK, on success.
// < 0, on error.
// < 0, on error.
virtual int32_t RegisterReceiveStatisticsCallback(
VCMReceiveStatisticsCallback* receiveStats) = 0;
@ -383,7 +383,7 @@ public:
// - decoderTiming : The callback object to register.
//
// Return value : VCM_OK, on success.
// < 0, on error.
// < 0, on error.
virtual int32_t RegisterDecoderTimingCallback(
VCMDecoderTimingCallback* decoderTiming) = 0;
@ -396,7 +396,7 @@ public:
// De-register with a NULL pointer.
//
// Return value : VCM_OK, on success.
// < 0, on error.
// < 0, on error.
virtual int32_t RegisterFrameTypeCallback(
VCMFrameTypeCallback* frameTypeCallback) = 0;
@ -407,7 +407,7 @@ public:
// - callback : The callback to be registered in the VCM.
//
// Return value : VCM_OK, on success.
// <0, on error.
// <0, on error.
virtual int32_t RegisterPacketRequestCallback(
VCMPacketRequestCallback* callback) = 0;
@ -416,7 +416,7 @@ public:
// Should be called as often as possible to get the most out of the decoder.
//
// Return value : VCM_OK, on success.
// < 0, on error.
// < 0, on error.
virtual int32_t Decode(uint16_t maxWaitTimeMs = 200) = 0;
// Registers a callback which conveys the size of the render buffer.
@ -426,7 +426,7 @@ public:
// Reset the decoder state to the initial state.
//
// Return value : VCM_OK, on success.
// < 0, on error.
// < 0, on error.
virtual int32_t ResetDecoder() = 0;
// API to get the codec which is currently used for decoding by the module.
@ -435,7 +435,7 @@ public:
// - currentReceiveCodec : Settings for the codec to be registered.
//
// Return value : VCM_OK, on success.
// < 0, on error.
// < 0, on error.
virtual int32_t ReceiveCodec(VideoCodec* currentReceiveCodec) const = 0;
// API to get the codec type currently used for decoding by the module.
@ -454,7 +454,7 @@ public:
// - rtpInfo : The parsed header.
//
// Return value : VCM_OK, on success.
// < 0, on error.
// < 0, on error.
virtual int32_t IncomingPacket(const uint8_t* incomingPayload,
size_t payloadLength,
const WebRtcRTPHeader& rtpInfo) = 0;
@ -467,7 +467,7 @@ public:
// - minPlayoutDelayMs : Additional delay in ms.
//
// Return value : VCM_OK, on success.
// < 0, on error.
// < 0, on error.
virtual int32_t SetMinimumPlayoutDelay(uint32_t minPlayoutDelayMs) = 0;
// Set the time required by the renderer to render a frame.
@ -476,7 +476,7 @@ public:
// - timeMS : The time in ms required by the renderer to render a frame.
//
// Return value : VCM_OK, on success.
// < 0, on error.
// < 0, on error.
virtual int32_t SetRenderDelay(uint32_t timeMS) = 0;
// The total delay desired by the VCM. Can be less than the minimum

View File

@ -25,6 +25,7 @@
#include "webrtc/modules/video_coding/main/source/media_optimization.h"
#include "webrtc/modules/video_coding/main/source/receiver.h"
#include "webrtc/modules/video_coding/main/source/timing.h"
#include "webrtc/modules/video_coding/utility/include/qp_parser.h"
#include "webrtc/system_wrappers/interface/clock.h"
#include "webrtc/system_wrappers/interface/critical_section_wrapper.h"
@ -237,6 +238,7 @@ class VideoReceiver {
VCMProcessTimer _receiveStatsTimer;
VCMProcessTimer _retransmissionTimer;
VCMProcessTimer _keyRequestTimer;
QpParser qp_parser_;
};
} // namespace vcm

View File

@ -302,7 +302,12 @@ int32_t VideoReceiver::Decode(uint16_t maxWaitTimeMs) {
if (pre_decode_image_callback_) {
EncodedImage encoded_image(frame->EncodedImage());
pre_decode_image_callback_->Encoded(encoded_image, NULL, NULL);
int qp = -1;
if (qp_parser_.GetQp(*frame, &qp)) {
encoded_image.qp_ = qp;
}
pre_decode_image_callback_->Encoded(
encoded_image, frame->CodecSpecific(), NULL);
}
#ifdef DEBUG_DECODER_BIT_STREAM

View File

@ -0,0 +1,30 @@
/*
* Copyright (c) 2015 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#ifndef WEBRTC_MODULES_VIDEO_CODING_UTILITY_QP_PARSER_H_
#define WEBRTC_MODULES_VIDEO_CODING_UTILITY_QP_PARSER_H_
#include "webrtc/modules/video_coding/main/source/encoded_frame.h"
namespace webrtc {
class QpParser {
public:
QpParser() {}
~QpParser() {}
// Parses an encoded |frame| and extracts the |qp|.
// Returns true on success, false otherwise.
bool GetQp(const VCMEncodedFrame& frame, int* qp);
};
} // namespace webrtc
#endif // WEBRTC_MODULES_VIDEO_CODING_UTILITY_QP_PARSER_H_

View File

@ -66,7 +66,9 @@ const uint8_t kVP8NewRange[128] = {
241, 243, 245, 247, 249, 251, 253, 127
};
int GetQP(uint8_t* buf);
// Gets the QP, QP range: [0, 127].
// Returns true on success, false otherwise.
bool GetQp(const uint8_t* buf, size_t length, int* qp);
} // namespace vp8

View File

@ -0,0 +1,28 @@
/*
* Copyright (c) 2015 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include "webrtc/modules/video_coding/utility/include/qp_parser.h"
#include "webrtc/common_types.h"
#include "webrtc/modules/video_coding/utility/include/vp8_header_parser.h"
namespace webrtc {
bool QpParser::GetQp(const VCMEncodedFrame& frame, int* qp) {
switch (frame.CodecSpecific()->codecType) {
case kVideoCodecVP8:
// QP range: [0, 127].
return vp8::GetQp(frame.Buffer(), frame.Length(), qp);
default:
return false;
}
}
} // namespace webrtc

View File

@ -21,8 +21,10 @@
'frame_dropper.cc',
'include/frame_dropper.h',
'include/moving_average.h',
'include/qp_parser.h',
'include/quality_scaler.h',
'include/vp8_header_parser.h',
'qp_parser.cc',
'quality_scaler.cc',
'vp8_header_parser.cc',
],

View File

@ -12,9 +12,15 @@
#include "webrtc/modules/video_coding/utility/include/vp8_header_parser.h"
#include "webrtc/system_wrappers/interface/logging.h"
namespace webrtc {
namespace vp8 {
namespace {
const size_t kCommonPayloadHeaderLength = 3;
const size_t kKeyPayloadHeaderLength = 10;
} // namespace
static uint32_t BSwap32(uint32_t x) {
return (x >> 24) | ((x >> 8) & 0xff00) | ((x << 8) & 0xff0000) | (x << 24);
@ -156,18 +162,26 @@ static void ParseFilterHeader(VP8BitReader* br) {
}
}
int GetQP(uint8_t* buf) {
bool GetQp(const uint8_t* buf, size_t length, int* qp) {
if (length < kCommonPayloadHeaderLength) {
LOG(LS_WARNING) << "Failed to get QP, invalid length.";
return false;
}
VP8BitReader br;
const uint32_t bits = buf[0] | (buf[1] << 8) | (buf[2] << 16);
int key_frame = !(bits & 1);
// Size of first partition in bytes.
int partition_length = (bits >> 5);
// Skip past uncompressed header: 10bytes for key, 3bytes for delta frames.
uint32_t partition_length = (bits >> 5);
size_t header_length = kCommonPayloadHeaderLength;
if (key_frame) {
buf += 10;
} else {
buf += 3;
header_length = kKeyPayloadHeaderLength;
}
if (header_length + partition_length > length) {
LOG(LS_WARNING) << "Failed to get QP, invalid length: " << length;
return false;
}
buf += header_length;
VP8InitBitReader(&br, buf, buf + partition_length);
if (key_frame) {
// Color space and pixel type.
@ -180,7 +194,12 @@ int GetQP(uint8_t* buf) {
VP8GetValue(&br, 2);
// Base QP.
const int base_q0 = VP8GetValue(&br, 7);
return base_q0;
if (br.eof_ == 1) {
LOG(LS_WARNING) << "Failed to get QP, end of file reached.";
return false;
}
*qp = base_q0;
return true;
}
} // namespace vp8

View File

@ -72,6 +72,9 @@
#define RTC_HISTOGRAM_COUNTS_100(name, sample) RTC_HISTOGRAM_COUNTS( \
name, sample, 1, 100, 50)
#define RTC_HISTOGRAM_COUNTS_200(name, sample) RTC_HISTOGRAM_COUNTS( \
name, sample, 1, 200, 50)
#define RTC_HISTOGRAM_COUNTS_1000(name, sample) RTC_HISTOGRAM_COUNTS( \
name, sample, 1, 1000, 50)

View File

@ -13,6 +13,7 @@
#include <cmath>
#include "webrtc/base/checks.h"
#include "webrtc/modules/video_coding/codecs/interface/video_codec_interface.h"
#include "webrtc/system_wrappers/interface/clock.h"
#include "webrtc/system_wrappers/interface/critical_section_wrapper.h"
#include "webrtc/system_wrappers/interface/metrics.h"
@ -53,6 +54,10 @@ void ReceiveStatisticsProxy::UpdateHistograms() {
RTC_HISTOGRAM_COUNTS_10000("WebRTC.Video.ReceivedWidthInPixels", width);
RTC_HISTOGRAM_COUNTS_10000("WebRTC.Video.ReceivedHeightInPixels", height);
}
int qp = qp_counters_.vp8.Avg(kMinRequiredSamples);
if (qp != -1)
RTC_HISTOGRAM_COUNTS_200("WebRTC.Video.Decoded.Vp8.Qp", qp);
// TODO(asapersson): DecoderTiming() is call periodically (each 1000ms) and
// not per frame. Change decode time to include every frame.
const int kMinRequiredDecodeSamples = 5;
@ -180,6 +185,17 @@ void ReceiveStatisticsProxy::OnDiscardedPacketsUpdated(int discarded_packets) {
stats_.discarded_packets = discarded_packets;
}
void ReceiveStatisticsProxy::OnPreDecode(
const EncodedImage& encoded_image,
const CodecSpecificInfo* codec_specific_info) {
if (codec_specific_info == nullptr || encoded_image.qp_ == -1) {
return;
}
if (codec_specific_info->codecType == kVideoCodecVP8) {
qp_counters_.vp8.Add(encoded_image.qp_);
}
}
void ReceiveStatisticsProxy::SampleCounter::Add(int sample) {
sum += sample;
++num_samples;

View File

@ -30,6 +30,7 @@ namespace webrtc {
class Clock;
class ViECodec;
class ViEDecoderObserver;
struct CodecSpecificInfo;
class ReceiveStatisticsProxy : public VCMReceiveStatisticsCallback,
public RtcpStatisticsCallback,
@ -54,6 +55,9 @@ class ReceiveStatisticsProxy : public VCMReceiveStatisticsCallback,
int render_delay_ms,
int64_t rtt_ms);
void OnPreDecode(const EncodedImage& encoded_image,
const CodecSpecificInfo* codec_specific_info);
// Overrides VCMReceiveStatisticsCallback.
void OnReceiveRatesUpdated(uint32_t bitRate, uint32_t frameRate) override;
void OnFrameCountsUpdated(const FrameCounts& frame_counts) override;
@ -82,6 +86,9 @@ class ReceiveStatisticsProxy : public VCMReceiveStatisticsCallback,
int sum;
int num_samples;
};
struct QpCounters {
SampleCounter vp8;
};
void UpdateHistograms() EXCLUSIVE_LOCKS_REQUIRED(crit_);
@ -98,6 +105,7 @@ class ReceiveStatisticsProxy : public VCMReceiveStatisticsCallback,
SampleCounter decode_time_counter_ GUARDED_BY(crit_);
SampleCounter delay_counter_ GUARDED_BY(crit_);
ReportBlockStats report_block_stats_ GUARDED_BY(crit_);
QpCounters qp_counters_; // Only accessed on the decoding thread.
};
} // namespace webrtc

View File

@ -19,7 +19,6 @@
#include "webrtc/system_wrappers/interface/clock.h"
#include "webrtc/system_wrappers/interface/logging.h"
#include "webrtc/video/receive_statistics_proxy.h"
#include "webrtc/video_encoder.h"
#include "webrtc/video_engine/call_stats.h"
#include "webrtc/video_receive_stream.h"
@ -277,8 +276,7 @@ VideoReceiveStream::VideoReceiveStream(int num_cpu_cores,
incoming_video_stream_->SetExternalCallback(this);
vie_channel_->SetIncomingVideoStream(incoming_video_stream_.get());
if (config.pre_decode_callback)
vie_channel_->RegisterPreDecodeImageCallback(&encoded_frame_proxy_);
vie_channel_->RegisterPreDecodeImageCallback(this);
vie_channel_->RegisterPreRenderCallback(this);
}
@ -364,6 +362,21 @@ int VideoReceiveStream::RenderFrame(const uint32_t /*stream_id*/,
return 0;
}
// TODO(asapersson): Consider moving callback from video_encoder.h or
// creating a different callback.
int32_t VideoReceiveStream::Encoded(
const EncodedImage& encoded_image,
const CodecSpecificInfo* codec_specific_info,
const RTPFragmentationHeader* fragmentation) {
stats_proxy_->OnPreDecode(encoded_image, codec_specific_info);
if (config_.pre_decode_callback) {
// TODO(asapersson): Remove EncodedFrameCallbackAdapter.
encoded_frame_proxy_.Encoded(
encoded_image, codec_specific_info, fragmentation);
}
return 0;
}
void VideoReceiveStream::SignalNetworkState(NetworkState state) {
vie_channel_->SetRTCPMode(state == kNetworkUp ? config_.rtp.rtcp_mode
: RtcpMode::kOff);

View File

@ -22,6 +22,7 @@
#include "webrtc/system_wrappers/interface/clock.h"
#include "webrtc/video/encoded_frame_callback_adapter.h"
#include "webrtc/video/receive_statistics_proxy.h"
#include "webrtc/video_encoder.h"
#include "webrtc/video_engine/vie_channel.h"
#include "webrtc/video_engine/vie_channel_group.h"
#include "webrtc/video_engine/vie_encoder.h"
@ -35,7 +36,8 @@ namespace internal {
class VideoReceiveStream : public webrtc::VideoReceiveStream,
public I420FrameCallback,
public VideoRenderCallback {
public VideoRenderCallback,
public EncodedImageCallback {
public:
VideoReceiveStream(int num_cpu_cores,
ChannelGroup* channel_group,
@ -63,6 +65,11 @@ class VideoReceiveStream : public webrtc::VideoReceiveStream,
int RenderFrame(const uint32_t /*stream_id*/,
const VideoFrame& video_frame) override;
// Overrides EncodedImageCallback.
int32_t Encoded(const EncodedImage& encoded_image,
const CodecSpecificInfo* codec_specific_info,
const RTPFragmentationHeader* fragmentation) override;
const Config& config() const { return config_; }
void SetSyncChannel(VoiceEngine* voice_engine, int audio_channel_id);

View File

@ -199,6 +199,7 @@ class EncodedImage {
size_t _size;
bool _completeFrame = false;
AdaptReason adapt_reason_;
int qp_ = -1; // Quantizer value.
};
} // namespace webrtc