From 12f4cda0867b7264f0ad65b2b00e592de9a2a753 Mon Sep 17 00:00:00 2001 From: hbos Date: Wed, 24 Feb 2016 03:03:05 -0800 Subject: [PATCH] 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} --- .../codecs/h264/h264_decoder_impl.cc | 52 +++++++++++++++-- .../codecs/h264/h264_decoder_impl.h | 7 +++ .../codecs/h264/h264_encoder_impl.cc | 58 +++++++++++++++++-- .../codecs/h264/h264_encoder_impl.h | 7 +++ 4 files changed, 114 insertions(+), 10 deletions(-) diff --git a/webrtc/modules/video_coding/codecs/h264/h264_decoder_impl.cc b/webrtc/modules/video_coding/codecs/h264/h264_decoder_impl.cc index a28f41d101..e98666d073 100644 --- a/webrtc/modules/video_coding/codecs/h264/h264_decoder_impl.cc +++ b/webrtc/modules/video_coding/codecs/h264/h264_decoder_impl.cc @@ -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(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(std::numeric_limits::max())) { + ReportError(); return WEBRTC_VIDEO_CODEC_ERROR; } packet.size = static_cast(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 diff --git a/webrtc/modules/video_coding/codecs/h264/h264_decoder_impl.h b/webrtc/modules/video_coding/codecs/h264/h264_decoder_impl.h index e464ffbcdd..c88955480e 100644 --- a/webrtc/modules/video_coding/codecs/h264/h264_decoder_impl.h +++ b/webrtc/modules/video_coding/codecs/h264/h264_decoder_impl.h @@ -62,11 +62,18 @@ class H264DecoderImpl : public H264Decoder { bool IsInitialized() const; + // Reports statistics with histograms. + void ReportInit(); + void ReportError(); + I420BufferPool pool_; rtc::scoped_ptr av_context_; rtc::scoped_ptr av_frame_; DecodedImageCallback* decoded_image_callback_; + + bool has_reported_init_; + bool has_reported_error_; }; } // namespace webrtc diff --git a/webrtc/modules/video_coding/codecs/h264/h264_encoder_impl.cc b/webrtc/modules/video_coding/codecs/h264/h264_encoder_impl.cc index 99402607c1..03c1c8eeac 100644 --- a/webrtc/modules/video_coding/codecs/h264/h264_encoder_impl.cc +++ b/webrtc/modules/video_coding/codecs/h264/h264_encoder_impl.cc @@ -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* 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; diff --git a/webrtc/modules/video_coding/codecs/h264/h264_encoder_impl.h b/webrtc/modules/video_coding/codecs/h264/h264_encoder_impl.h index 0bf06ac404..0ac3b4ea54 100644 --- a/webrtc/modules/video_coding/codecs/h264/h264_encoder_impl.h +++ b/webrtc/modules/video_coding/codecs/h264/h264_encoder_impl.h @@ -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 encoded_image_buffer_; EncodedImageCallback* encoded_image_callback_; + + bool has_reported_init_; + bool has_reported_error_; }; } // namespace webrtc