Histograms for H264EncoderImpl/H264DecoderImpl

initialization and errors.

The stats are counts using enumeration, an instance of
H264EncoderImpl/H264DecoderImpl will report at most 1 Init
and 1 Error for its entire lifetime. This is to avoid
spamming reports if initialization or coding fails and it
retries in a loop. The Init stats will give us an idea of
usage counts for the encoder/decoder. The Error stats will
give us an idea of how many of these usages encounters some
type of problem, such as encode or decode errors.

- WebRTC.Video.H264EncoderImpl.Event:
  * kH264EncoderEventInit: Occurs at InitEncode.
  * kH264EncoderEventError: Occurs if any type of error
    occurs during initialization or encoding.
- WebRTC.Video.H264DecoderImpl.Event:
  * kH264DecoderEventInit: Occurs at InitDecode.
  * kH264DecoderEventError: Occurs if any type of error
    occurs during initialization, AVGetBuffer2 or decoding.

Chromium sibling CL:
https://codereview.chromium.org/1719273002/

BUG=chromium:500605, chromium:468365

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

Cr-Commit-Position: refs/heads/master@{#11736}
This commit is contained in:
hbos
2016-02-24 03:03:05 -08:00
committed by Commit bot
parent 0ab8e81e12
commit 12f4cda086
4 changed files with 114 additions and 10 deletions

View File

@ -24,6 +24,7 @@ extern "C" {
#include "webrtc/base/criticalsection.h"
#include "webrtc/base/keep_ref_until_done.h"
#include "webrtc/base/logging.h"
#include "webrtc/system_wrappers/include/metrics.h"
namespace webrtc {
@ -34,6 +35,13 @@ const size_t kYPlaneIndex = 0;
const size_t kUPlaneIndex = 1;
const size_t kVPlaneIndex = 2;
// Used by histograms. Values of entries should not be changed.
enum H264DecoderImplEvent {
kH264DecoderEventInit = 0,
kH264DecoderEventError = 1,
kH264DecoderEventMax = 16,
};
#if defined(WEBRTC_INITIALIZE_FFMPEG)
rtc::CriticalSection ffmpeg_init_lock;
@ -109,6 +117,7 @@ int H264DecoderImpl::AVGetBuffer2(
static_cast<unsigned int>(height), 0, nullptr);
if (ret < 0) {
LOG(LS_ERROR) << "Invalid picture size " << width << "x" << height;
decoder->ReportError();
return ret;
}
@ -158,7 +167,9 @@ void H264DecoderImpl::AVFreeBuffer2(void* opaque, uint8_t* data) {
}
H264DecoderImpl::H264DecoderImpl() : pool_(true),
decoded_image_callback_(nullptr) {
decoded_image_callback_(nullptr),
has_reported_init_(false),
has_reported_error_(false) {
}
H264DecoderImpl::~H264DecoderImpl() {
@ -167,8 +178,10 @@ H264DecoderImpl::~H264DecoderImpl() {
int32_t H264DecoderImpl::InitDecode(const VideoCodec* codec_settings,
int32_t number_of_cores) {
ReportInit();
if (codec_settings &&
codec_settings->codecType != kVideoCodecH264) {
ReportError();
return WEBRTC_VIDEO_CODEC_ERR_PARAMETER;
}
@ -186,8 +199,10 @@ int32_t H264DecoderImpl::InitDecode(const VideoCodec* codec_settings,
// Release necessary in case of re-initializing.
int32_t ret = Release();
if (ret != WEBRTC_VIDEO_CODEC_OK)
if (ret != WEBRTC_VIDEO_CODEC_OK) {
ReportError();
return ret;
}
RTC_DCHECK(!av_context_);
// Initialize AVCodecContext.
@ -222,12 +237,14 @@ int32_t H264DecoderImpl::InitDecode(const VideoCodec* codec_settings,
// been compiled/initialized with the correct set of codecs.
LOG(LS_ERROR) << "FFmpeg H.264 decoder not found.";
Release();
ReportError();
return WEBRTC_VIDEO_CODEC_ERROR;
}
int res = avcodec_open2(av_context_.get(), codec, nullptr);
if (res < 0) {
LOG(LS_ERROR) << "avcodec_open2 error: " << res;
Release();
ReportError();
return WEBRTC_VIDEO_CODEC_ERROR;
}
@ -252,17 +269,23 @@ int32_t H264DecoderImpl::Decode(const EncodedImage& input_image,
const RTPFragmentationHeader* /*fragmentation*/,
const CodecSpecificInfo* codec_specific_info,
int64_t /*render_time_ms*/) {
if (!IsInitialized())
if (!IsInitialized()) {
ReportError();
return WEBRTC_VIDEO_CODEC_UNINITIALIZED;
}
if (!decoded_image_callback_) {
LOG(LS_WARNING) << "InitDecode() has been called, but a callback function "
"has not been set with RegisterDecodeCompleteCallback()";
ReportError();
return WEBRTC_VIDEO_CODEC_UNINITIALIZED;
}
if (!input_image._buffer || !input_image._length)
if (!input_image._buffer || !input_image._length) {
ReportError();
return WEBRTC_VIDEO_CODEC_ERR_PARAMETER;
}
if (codec_specific_info &&
codec_specific_info->codecType != kVideoCodecH264) {
ReportError();
return WEBRTC_VIDEO_CODEC_ERR_PARAMETER;
}
@ -282,6 +305,7 @@ int32_t H264DecoderImpl::Decode(const EncodedImage& input_image,
packet.data = input_image._buffer;
if (input_image._length >
static_cast<size_t>(std::numeric_limits<int>::max())) {
ReportError();
return WEBRTC_VIDEO_CODEC_ERROR;
}
packet.size = static_cast<int>(input_image._length);
@ -294,12 +318,14 @@ int32_t H264DecoderImpl::Decode(const EncodedImage& input_image,
&packet);
if (result < 0) {
LOG(LS_ERROR) << "avcodec_decode_video2 error: " << result;
ReportError();
return WEBRTC_VIDEO_CODEC_ERROR;
}
// |result| is number of bytes used, which should be all of them.
if (result != packet.size) {
LOG(LS_ERROR) << "avcodec_decode_video2 consumed " << result << " bytes "
"when " << packet.size << " bytes were expected.";
ReportError();
return WEBRTC_VIDEO_CODEC_ERROR;
}
@ -349,4 +375,22 @@ bool H264DecoderImpl::IsInitialized() const {
return av_context_ != nullptr;
}
void H264DecoderImpl::ReportInit() {
if (has_reported_init_)
return;
RTC_HISTOGRAM_ENUMERATION("WebRTC.Video.H264DecoderImpl.Event",
kH264DecoderEventInit,
kH264DecoderEventMax);
has_reported_init_ = true;
}
void H264DecoderImpl::ReportError() {
if (has_reported_error_)
return;
RTC_HISTOGRAM_ENUMERATION("WebRTC.Video.H264DecoderImpl.Event",
kH264DecoderEventError,
kH264DecoderEventMax);
has_reported_error_ = true;
}
} // namespace webrtc

View File

@ -62,11 +62,18 @@ class H264DecoderImpl : public H264Decoder {
bool IsInitialized() const;
// Reports statistics with histograms.
void ReportInit();
void ReportError();
I420BufferPool pool_;
rtc::scoped_ptr<AVCodecContext, AVCodecContextDeleter> av_context_;
rtc::scoped_ptr<AVFrame, AVFrameDeleter> av_frame_;
DecodedImageCallback* decoded_image_callback_;
bool has_reported_init_;
bool has_reported_error_;
};
} // namespace webrtc

View File

@ -20,6 +20,7 @@
#include "webrtc/base/checks.h"
#include "webrtc/base/logging.h"
#include "webrtc/common_video/libyuv/include/webrtc_libyuv.h"
#include "webrtc/system_wrappers/include/metrics.h"
namespace webrtc {
@ -27,6 +28,13 @@ namespace {
const bool kOpenH264EncoderDetailedLogging = false;
// Used by histograms. Values of entries should not be changed.
enum H264EncoderImplEvent {
kH264EncoderEventInit = 0,
kH264EncoderEventError = 1,
kH264EncoderEventMax = 16,
};
int NumberOfThreads(int width, int height, int number_of_cores) {
// TODO(hbos): In Chromium, multiple threads do not work with sandbox on Mac,
// see crbug.com/583348. Until further investigated, only use one thread.
@ -141,7 +149,9 @@ static void RtpFragmentize(EncodedImage* encoded_image,
H264EncoderImpl::H264EncoderImpl()
: openh264_encoder_(nullptr),
encoded_image_callback_(nullptr) {
encoded_image_callback_(nullptr),
has_reported_init_(false),
has_reported_error_(false) {
}
H264EncoderImpl::~H264EncoderImpl() {
@ -151,18 +161,26 @@ H264EncoderImpl::~H264EncoderImpl() {
int32_t H264EncoderImpl::InitEncode(const VideoCodec* codec_settings,
int32_t number_of_cores,
size_t /*max_payload_size*/) {
ReportInit();
if (!codec_settings ||
codec_settings->codecType != kVideoCodecH264) {
ReportError();
return WEBRTC_VIDEO_CODEC_ERR_PARAMETER;
}
if (codec_settings->maxFramerate == 0)
if (codec_settings->maxFramerate == 0) {
ReportError();
return WEBRTC_VIDEO_CODEC_ERR_PARAMETER;
if (codec_settings->width < 1 || codec_settings->height < 1)
}
if (codec_settings->width < 1 || codec_settings->height < 1) {
ReportError();
return WEBRTC_VIDEO_CODEC_ERR_PARAMETER;
}
int32_t release_ret = Release();
if (release_ret != WEBRTC_VIDEO_CODEC_OK)
if (release_ret != WEBRTC_VIDEO_CODEC_OK) {
ReportError();
return release_ret;
}
RTC_DCHECK(!openh264_encoder_);
// Create encoder.
@ -170,6 +188,7 @@ int32_t H264EncoderImpl::InitEncode(const VideoCodec* codec_settings,
// Failed to create encoder.
LOG(LS_ERROR) << "Failed to create OpenH264 encoder";
RTC_DCHECK(!openh264_encoder_);
ReportError();
return WEBRTC_VIDEO_CODEC_ERROR;
}
RTC_DCHECK(openh264_encoder_);
@ -196,6 +215,7 @@ int32_t H264EncoderImpl::InitEncode(const VideoCodec* codec_settings,
} else if (codec_settings_.mode == kScreensharing) {
init_params.iUsageType = SCREEN_CONTENT_REAL_TIME;
} else {
ReportError();
return WEBRTC_VIDEO_CODEC_ERR_PARAMETER;
}
init_params.iPicWidth = codec_settings_.width;
@ -236,6 +256,7 @@ int32_t H264EncoderImpl::InitEncode(const VideoCodec* codec_settings,
if (openh264_encoder_->InitializeExt(&init_params) != 0) {
LOG(LS_ERROR) << "Failed to initialize OpenH264 encoder";
Release();
ReportError();
return WEBRTC_VIDEO_CODEC_ERROR;
}
int video_format = EVideoFormatType::videoFormatI420;
@ -299,13 +320,18 @@ int32_t H264EncoderImpl::SetRates(uint32_t bitrate, uint32_t framerate) {
int32_t H264EncoderImpl::Encode(
const VideoFrame& frame, const CodecSpecificInfo* codec_specific_info,
const std::vector<FrameType>* frame_types) {
if (!IsInitialized())
if (!IsInitialized()) {
ReportError();
return WEBRTC_VIDEO_CODEC_UNINITIALIZED;
if (frame.IsZeroSize())
}
if (frame.IsZeroSize()) {
ReportError();
return WEBRTC_VIDEO_CODEC_ERR_PARAMETER;
}
if (!encoded_image_callback_) {
LOG(LS_WARNING) << "InitEncode() has been called, but a callback function "
<< "has not been set with RegisterEncodeCompleteCallback()";
ReportError();
return WEBRTC_VIDEO_CODEC_UNINITIALIZED;
}
if (frame.width() != codec_settings_.width ||
@ -313,6 +339,7 @@ int32_t H264EncoderImpl::Encode(
LOG(LS_WARNING) << "Encoder initialized for " << codec_settings_.width
<< "x" << codec_settings_.height << " but trying to encode "
<< frame.width() << "x" << frame.height() << " frame.";
ReportError();
return WEBRTC_VIDEO_CODEC_ERR_SIZE;
}
@ -357,6 +384,7 @@ int32_t H264EncoderImpl::Encode(
if (enc_ret != 0) {
LOG(LS_ERROR) << "OpenH264 frame encoding failed, EncodeFrame returned "
<< enc_ret << ".";
ReportError();
return WEBRTC_VIDEO_CODEC_ERROR;
}
@ -389,6 +417,24 @@ bool H264EncoderImpl::IsInitialized() const {
return openh264_encoder_ != nullptr;
}
void H264EncoderImpl::ReportInit() {
if (has_reported_init_)
return;
RTC_HISTOGRAM_ENUMERATION("WebRTC.Video.H264EncoderImpl.Event",
kH264EncoderEventInit,
kH264EncoderEventMax);
has_reported_init_ = true;
}
void H264EncoderImpl::ReportError() {
if (has_reported_error_)
return;
RTC_HISTOGRAM_ENUMERATION("WebRTC.Video.H264EncoderImpl.Event",
kH264EncoderEventError,
kH264EncoderEventMax);
has_reported_error_ = true;
}
int32_t H264EncoderImpl::SetChannelParameters(
uint32_t packet_loss, int64_t rtt) {
return WEBRTC_VIDEO_CODEC_OK;

View File

@ -57,12 +57,19 @@ class H264EncoderImpl : public H264Encoder {
private:
bool IsInitialized() const;
// Reports statistics with histograms.
void ReportInit();
void ReportError();
ISVCEncoder* openh264_encoder_;
VideoCodec codec_settings_;
EncodedImage encoded_image_;
rtc::scoped_ptr<uint8_t[]> encoded_image_buffer_;
EncodedImageCallback* encoded_image_callback_;
bool has_reported_init_;
bool has_reported_error_;
};
} // namespace webrtc