Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(92)

Side by Side Diff: webrtc/modules/video_coding/codecs/h264/h264_decoder_impl.cc

Issue 1716173002: Histograms for H264EncoderImpl/H264DecoderImpl initialization and errors (Closed) Base URL: https://chromium.googlesource.com/external/webrtc.git@master
Patch Set: Renamed "...State" enums to "...Event" Created 4 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 /* 1 /*
2 * Copyright (c) 2015 The WebRTC project authors. All Rights Reserved. 2 * Copyright (c) 2015 The WebRTC project authors. All Rights Reserved.
3 * 3 *
4 * Use of this source code is governed by a BSD-style license 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 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 6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may 7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree. 8 * be found in the AUTHORS file in the root of the source tree.
9 * 9 *
10 */ 10 */
11 11
12 #include "webrtc/modules/video_coding/codecs/h264/h264_decoder_impl.h" 12 #include "webrtc/modules/video_coding/codecs/h264/h264_decoder_impl.h"
13 13
14 #include <algorithm> 14 #include <algorithm>
15 #include <limits> 15 #include <limits>
16 16
17 extern "C" { 17 extern "C" {
18 #include "third_party/ffmpeg/libavcodec/avcodec.h" 18 #include "third_party/ffmpeg/libavcodec/avcodec.h"
19 #include "third_party/ffmpeg/libavformat/avformat.h" 19 #include "third_party/ffmpeg/libavformat/avformat.h"
20 #include "third_party/ffmpeg/libavutil/imgutils.h" 20 #include "third_party/ffmpeg/libavutil/imgutils.h"
21 } // extern "C" 21 } // extern "C"
22 22
23 #include "webrtc/base/checks.h" 23 #include "webrtc/base/checks.h"
24 #include "webrtc/base/criticalsection.h" 24 #include "webrtc/base/criticalsection.h"
25 #include "webrtc/base/keep_ref_until_done.h" 25 #include "webrtc/base/keep_ref_until_done.h"
26 #include "webrtc/base/logging.h" 26 #include "webrtc/base/logging.h"
27 #include "webrtc/system_wrappers/include/metrics.h"
27 28
28 namespace webrtc { 29 namespace webrtc {
29 30
30 namespace { 31 namespace {
31 32
32 const AVPixelFormat kPixelFormat = AV_PIX_FMT_YUV420P; 33 const AVPixelFormat kPixelFormat = AV_PIX_FMT_YUV420P;
33 const size_t kYPlaneIndex = 0; 34 const size_t kYPlaneIndex = 0;
34 const size_t kUPlaneIndex = 1; 35 const size_t kUPlaneIndex = 1;
35 const size_t kVPlaneIndex = 2; 36 const size_t kVPlaneIndex = 2;
36 37
38 // Used by histograms. Values of entries should not be changed.
39 enum H264DecoderImplEvent {
40 kH264DecoderEventInit = 0,
41 kH264DecoderEventError = 1,
42 kH264DecoderEventMax = 16,
hbos 2016/02/23 15:01:22 The example I looked at was WebRTC.Video.Encoder.C
hlundin-webrtc 2016/02/24 09:17:57 I don't know the history behind CodecType. The des
hbos 2016/02/24 11:11:25 Ok. Landed as-is. rkaplow if you know I could adju
rkaplow 2016/02/24 16:10:08 usually people don't even set the numbers here man
43 };
44
37 #if defined(WEBRTC_INITIALIZE_FFMPEG) 45 #if defined(WEBRTC_INITIALIZE_FFMPEG)
38 46
39 rtc::CriticalSection ffmpeg_init_lock; 47 rtc::CriticalSection ffmpeg_init_lock;
40 bool ffmpeg_initialized = false; 48 bool ffmpeg_initialized = false;
41 49
42 // Called by FFmpeg to do mutex operations if initialized using 50 // Called by FFmpeg to do mutex operations if initialized using
43 // |InitializeFFmpeg|. 51 // |InitializeFFmpeg|.
44 int LockManagerOperation(void** lock, AVLockOp op) 52 int LockManagerOperation(void** lock, AVLockOp op)
45 EXCLUSIVE_LOCK_FUNCTION() UNLOCK_FUNCTION() { 53 EXCLUSIVE_LOCK_FUNCTION() UNLOCK_FUNCTION() {
46 switch (op) { 54 switch (op) {
(...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after
102 // (top-left corner) after decoding to avoid visible borders to the right and 110 // (top-left corner) after decoding to avoid visible borders to the right and
103 // bottom of the actual image. 111 // bottom of the actual image.
104 avcodec_align_dimensions(context, &width, &height); 112 avcodec_align_dimensions(context, &width, &height);
105 113
106 RTC_CHECK_GE(width, 0); 114 RTC_CHECK_GE(width, 0);
107 RTC_CHECK_GE(height, 0); 115 RTC_CHECK_GE(height, 0);
108 int ret = av_image_check_size(static_cast<unsigned int>(width), 116 int ret = av_image_check_size(static_cast<unsigned int>(width),
109 static_cast<unsigned int>(height), 0, nullptr); 117 static_cast<unsigned int>(height), 0, nullptr);
110 if (ret < 0) { 118 if (ret < 0) {
111 LOG(LS_ERROR) << "Invalid picture size " << width << "x" << height; 119 LOG(LS_ERROR) << "Invalid picture size " << width << "x" << height;
120 decoder->ReportError();
112 return ret; 121 return ret;
113 } 122 }
114 123
115 // The video frame is stored in |video_frame|. |av_frame| is FFmpeg's version 124 // The video frame is stored in |video_frame|. |av_frame| is FFmpeg's version
116 // of a video frame and will be set up to reference |video_frame|'s buffers. 125 // of a video frame and will be set up to reference |video_frame|'s buffers.
117 VideoFrame* video_frame = new VideoFrame(); 126 VideoFrame* video_frame = new VideoFrame();
118 // FFmpeg expects the initial allocation to be zero-initialized according to 127 // FFmpeg expects the initial allocation to be zero-initialized according to
119 // http://crbug.com/390941. Our pool is set up to zero-initialize new buffers. 128 // http://crbug.com/390941. Our pool is set up to zero-initialize new buffers.
120 video_frame->set_video_frame_buffer( 129 video_frame->set_video_frame_buffer(
121 decoder->pool_.CreateBuffer(width, height)); 130 decoder->pool_.CreateBuffer(width, height));
(...skipping 29 matching lines...) Expand all
151 160
152 void H264DecoderImpl::AVFreeBuffer2(void* opaque, uint8_t* data) { 161 void H264DecoderImpl::AVFreeBuffer2(void* opaque, uint8_t* data) {
153 // The buffer pool recycles the buffer used by |video_frame| when there are no 162 // The buffer pool recycles the buffer used by |video_frame| when there are no
154 // more references to it. |video_frame| is a thin buffer holder and is not 163 // more references to it. |video_frame| is a thin buffer holder and is not
155 // recycled. 164 // recycled.
156 VideoFrame* video_frame = static_cast<VideoFrame*>(opaque); 165 VideoFrame* video_frame = static_cast<VideoFrame*>(opaque);
157 delete video_frame; 166 delete video_frame;
158 } 167 }
159 168
160 H264DecoderImpl::H264DecoderImpl() : pool_(true), 169 H264DecoderImpl::H264DecoderImpl() : pool_(true),
161 decoded_image_callback_(nullptr) { 170 decoded_image_callback_(nullptr),
171 has_reported_init_(false),
172 has_reported_error_(false) {
162 } 173 }
163 174
164 H264DecoderImpl::~H264DecoderImpl() { 175 H264DecoderImpl::~H264DecoderImpl() {
165 Release(); 176 Release();
166 } 177 }
167 178
168 int32_t H264DecoderImpl::InitDecode(const VideoCodec* codec_settings, 179 int32_t H264DecoderImpl::InitDecode(const VideoCodec* codec_settings,
169 int32_t number_of_cores) { 180 int32_t number_of_cores) {
181 ReportInit();
170 if (codec_settings && 182 if (codec_settings &&
171 codec_settings->codecType != kVideoCodecH264) { 183 codec_settings->codecType != kVideoCodecH264) {
184 ReportError();
172 return WEBRTC_VIDEO_CODEC_ERR_PARAMETER; 185 return WEBRTC_VIDEO_CODEC_ERR_PARAMETER;
173 } 186 }
174 187
175 // FFmpeg must have been initialized (with |av_lockmgr_register| and 188 // FFmpeg must have been initialized (with |av_lockmgr_register| and
176 // |av_register_all|) before we proceed. |InitializeFFmpeg| does this, which 189 // |av_register_all|) before we proceed. |InitializeFFmpeg| does this, which
177 // makes sense for WebRTC standalone. In other cases, such as Chromium, FFmpeg 190 // makes sense for WebRTC standalone. In other cases, such as Chromium, FFmpeg
178 // is initialized externally and calling |InitializeFFmpeg| would be 191 // is initialized externally and calling |InitializeFFmpeg| would be
179 // thread-unsafe and result in FFmpeg being initialized twice, which could 192 // thread-unsafe and result in FFmpeg being initialized twice, which could
180 // break other FFmpeg usage. See the |rtc_initialize_ffmpeg| flag. 193 // break other FFmpeg usage. See the |rtc_initialize_ffmpeg| flag.
181 #if defined(WEBRTC_INITIALIZE_FFMPEG) 194 #if defined(WEBRTC_INITIALIZE_FFMPEG)
182 // Make sure FFmpeg has been initialized. Subsequent |InitializeFFmpeg| calls 195 // Make sure FFmpeg has been initialized. Subsequent |InitializeFFmpeg| calls
183 // do nothing. 196 // do nothing.
184 InitializeFFmpeg(); 197 InitializeFFmpeg();
185 #endif 198 #endif
186 199
187 // Release necessary in case of re-initializing. 200 // Release necessary in case of re-initializing.
188 int32_t ret = Release(); 201 int32_t ret = Release();
189 if (ret != WEBRTC_VIDEO_CODEC_OK) 202 if (ret != WEBRTC_VIDEO_CODEC_OK) {
203 ReportError();
190 return ret; 204 return ret;
205 }
191 RTC_DCHECK(!av_context_); 206 RTC_DCHECK(!av_context_);
192 207
193 // Initialize AVCodecContext. 208 // Initialize AVCodecContext.
194 av_context_.reset(avcodec_alloc_context3(nullptr)); 209 av_context_.reset(avcodec_alloc_context3(nullptr));
195 210
196 av_context_->codec_type = AVMEDIA_TYPE_VIDEO; 211 av_context_->codec_type = AVMEDIA_TYPE_VIDEO;
197 av_context_->codec_id = AV_CODEC_ID_H264; 212 av_context_->codec_id = AV_CODEC_ID_H264;
198 if (codec_settings) { 213 if (codec_settings) {
199 av_context_->coded_width = codec_settings->width; 214 av_context_->coded_width = codec_settings->width;
200 av_context_->coded_height = codec_settings->height; 215 av_context_->coded_height = codec_settings->height;
(...skipping 14 matching lines...) Expand all
215 av_context_->opaque = this; 230 av_context_->opaque = this;
216 // Use ref counted frames (av_frame_unref). 231 // Use ref counted frames (av_frame_unref).
217 av_context_->refcounted_frames = 1; // true 232 av_context_->refcounted_frames = 1; // true
218 233
219 AVCodec* codec = avcodec_find_decoder(av_context_->codec_id); 234 AVCodec* codec = avcodec_find_decoder(av_context_->codec_id);
220 if (!codec) { 235 if (!codec) {
221 // This is an indication that FFmpeg has not been initialized or it has not 236 // This is an indication that FFmpeg has not been initialized or it has not
222 // been compiled/initialized with the correct set of codecs. 237 // been compiled/initialized with the correct set of codecs.
223 LOG(LS_ERROR) << "FFmpeg H.264 decoder not found."; 238 LOG(LS_ERROR) << "FFmpeg H.264 decoder not found.";
224 Release(); 239 Release();
240 ReportError();
225 return WEBRTC_VIDEO_CODEC_ERROR; 241 return WEBRTC_VIDEO_CODEC_ERROR;
226 } 242 }
227 int res = avcodec_open2(av_context_.get(), codec, nullptr); 243 int res = avcodec_open2(av_context_.get(), codec, nullptr);
228 if (res < 0) { 244 if (res < 0) {
229 LOG(LS_ERROR) << "avcodec_open2 error: " << res; 245 LOG(LS_ERROR) << "avcodec_open2 error: " << res;
230 Release(); 246 Release();
247 ReportError();
231 return WEBRTC_VIDEO_CODEC_ERROR; 248 return WEBRTC_VIDEO_CODEC_ERROR;
232 } 249 }
233 250
234 av_frame_.reset(av_frame_alloc()); 251 av_frame_.reset(av_frame_alloc());
235 return WEBRTC_VIDEO_CODEC_OK; 252 return WEBRTC_VIDEO_CODEC_OK;
236 } 253 }
237 254
238 int32_t H264DecoderImpl::Release() { 255 int32_t H264DecoderImpl::Release() {
239 av_context_.reset(); 256 av_context_.reset();
240 av_frame_.reset(); 257 av_frame_.reset();
241 return WEBRTC_VIDEO_CODEC_OK; 258 return WEBRTC_VIDEO_CODEC_OK;
242 } 259 }
243 260
244 int32_t H264DecoderImpl::RegisterDecodeCompleteCallback( 261 int32_t H264DecoderImpl::RegisterDecodeCompleteCallback(
245 DecodedImageCallback* callback) { 262 DecodedImageCallback* callback) {
246 decoded_image_callback_ = callback; 263 decoded_image_callback_ = callback;
247 return WEBRTC_VIDEO_CODEC_OK; 264 return WEBRTC_VIDEO_CODEC_OK;
248 } 265 }
249 266
250 int32_t H264DecoderImpl::Decode(const EncodedImage& input_image, 267 int32_t H264DecoderImpl::Decode(const EncodedImage& input_image,
251 bool /*missing_frames*/, 268 bool /*missing_frames*/,
252 const RTPFragmentationHeader* /*fragmentation*/, 269 const RTPFragmentationHeader* /*fragmentation*/,
253 const CodecSpecificInfo* codec_specific_info, 270 const CodecSpecificInfo* codec_specific_info,
254 int64_t /*render_time_ms*/) { 271 int64_t /*render_time_ms*/) {
255 if (!IsInitialized()) 272 if (!IsInitialized()) {
273 ReportError();
256 return WEBRTC_VIDEO_CODEC_UNINITIALIZED; 274 return WEBRTC_VIDEO_CODEC_UNINITIALIZED;
275 }
257 if (!decoded_image_callback_) { 276 if (!decoded_image_callback_) {
258 LOG(LS_WARNING) << "InitDecode() has been called, but a callback function " 277 LOG(LS_WARNING) << "InitDecode() has been called, but a callback function "
259 "has not been set with RegisterDecodeCompleteCallback()"; 278 "has not been set with RegisterDecodeCompleteCallback()";
279 ReportError();
260 return WEBRTC_VIDEO_CODEC_UNINITIALIZED; 280 return WEBRTC_VIDEO_CODEC_UNINITIALIZED;
261 } 281 }
262 if (!input_image._buffer || !input_image._length) 282 if (!input_image._buffer || !input_image._length) {
283 ReportError();
263 return WEBRTC_VIDEO_CODEC_ERR_PARAMETER; 284 return WEBRTC_VIDEO_CODEC_ERR_PARAMETER;
285 }
264 if (codec_specific_info && 286 if (codec_specific_info &&
265 codec_specific_info->codecType != kVideoCodecH264) { 287 codec_specific_info->codecType != kVideoCodecH264) {
288 ReportError();
266 return WEBRTC_VIDEO_CODEC_ERR_PARAMETER; 289 return WEBRTC_VIDEO_CODEC_ERR_PARAMETER;
267 } 290 }
268 291
269 // FFmpeg requires padding due to some optimized bitstream readers reading 32 292 // FFmpeg requires padding due to some optimized bitstream readers reading 32
270 // or 64 bits at once and could read over the end. See avcodec_decode_video2. 293 // or 64 bits at once and could read over the end. See avcodec_decode_video2.
271 RTC_CHECK_GE(input_image._size, input_image._length + 294 RTC_CHECK_GE(input_image._size, input_image._length +
272 EncodedImage::GetBufferPaddingBytes(kVideoCodecH264)); 295 EncodedImage::GetBufferPaddingBytes(kVideoCodecH264));
273 // "If the first 23 bits of the additional bytes are not 0, then damaged MPEG 296 // "If the first 23 bits of the additional bytes are not 0, then damaged MPEG
274 // bitstreams could cause overread and segfault." See 297 // bitstreams could cause overread and segfault." See
275 // AV_INPUT_BUFFER_PADDING_SIZE. We'll zero the entire padding just in case. 298 // AV_INPUT_BUFFER_PADDING_SIZE. We'll zero the entire padding just in case.
276 memset(input_image._buffer + input_image._length, 299 memset(input_image._buffer + input_image._length,
277 0, 300 0,
278 EncodedImage::GetBufferPaddingBytes(kVideoCodecH264)); 301 EncodedImage::GetBufferPaddingBytes(kVideoCodecH264));
279 302
280 AVPacket packet; 303 AVPacket packet;
281 av_init_packet(&packet); 304 av_init_packet(&packet);
282 packet.data = input_image._buffer; 305 packet.data = input_image._buffer;
283 if (input_image._length > 306 if (input_image._length >
284 static_cast<size_t>(std::numeric_limits<int>::max())) { 307 static_cast<size_t>(std::numeric_limits<int>::max())) {
308 ReportError();
285 return WEBRTC_VIDEO_CODEC_ERROR; 309 return WEBRTC_VIDEO_CODEC_ERROR;
286 } 310 }
287 packet.size = static_cast<int>(input_image._length); 311 packet.size = static_cast<int>(input_image._length);
288 av_context_->reordered_opaque = input_image.ntp_time_ms_ * 1000; // ms -> μs 312 av_context_->reordered_opaque = input_image.ntp_time_ms_ * 1000; // ms -> μs
289 313
290 int frame_decoded = 0; 314 int frame_decoded = 0;
291 int result = avcodec_decode_video2(av_context_.get(), 315 int result = avcodec_decode_video2(av_context_.get(),
292 av_frame_.get(), 316 av_frame_.get(),
293 &frame_decoded, 317 &frame_decoded,
294 &packet); 318 &packet);
295 if (result < 0) { 319 if (result < 0) {
296 LOG(LS_ERROR) << "avcodec_decode_video2 error: " << result; 320 LOG(LS_ERROR) << "avcodec_decode_video2 error: " << result;
321 ReportError();
297 return WEBRTC_VIDEO_CODEC_ERROR; 322 return WEBRTC_VIDEO_CODEC_ERROR;
298 } 323 }
299 // |result| is number of bytes used, which should be all of them. 324 // |result| is number of bytes used, which should be all of them.
300 if (result != packet.size) { 325 if (result != packet.size) {
301 LOG(LS_ERROR) << "avcodec_decode_video2 consumed " << result << " bytes " 326 LOG(LS_ERROR) << "avcodec_decode_video2 consumed " << result << " bytes "
302 "when " << packet.size << " bytes were expected."; 327 "when " << packet.size << " bytes were expected.";
328 ReportError();
303 return WEBRTC_VIDEO_CODEC_ERROR; 329 return WEBRTC_VIDEO_CODEC_ERROR;
304 } 330 }
305 331
306 if (!frame_decoded) { 332 if (!frame_decoded) {
307 LOG(LS_WARNING) << "avcodec_decode_video2 successful but no frame was " 333 LOG(LS_WARNING) << "avcodec_decode_video2 successful but no frame was "
308 "decoded."; 334 "decoded.";
309 return WEBRTC_VIDEO_CODEC_OK; 335 return WEBRTC_VIDEO_CODEC_OK;
310 } 336 }
311 337
312 // Obtain the |video_frame| containing the decoded image. 338 // Obtain the |video_frame| containing the decoded image.
(...skipping 29 matching lines...) Expand all
342 LOG(LS_WARNING) << "DecodedImageCallback::Decoded returned " << ret; 368 LOG(LS_WARNING) << "DecodedImageCallback::Decoded returned " << ret;
343 return ret; 369 return ret;
344 } 370 }
345 return WEBRTC_VIDEO_CODEC_OK; 371 return WEBRTC_VIDEO_CODEC_OK;
346 } 372 }
347 373
348 bool H264DecoderImpl::IsInitialized() const { 374 bool H264DecoderImpl::IsInitialized() const {
349 return av_context_ != nullptr; 375 return av_context_ != nullptr;
350 } 376 }
351 377
378 void H264DecoderImpl::ReportInit() {
379 if (has_reported_init_)
380 return;
381 RTC_HISTOGRAM_ENUMERATION("WebRTC.Video.H264DecoderImpl.Event",
382 kH264DecoderEventInit,
383 kH264DecoderEventMax);
384 has_reported_init_ = true;
385 }
386
387 void H264DecoderImpl::ReportError() {
388 if (has_reported_error_)
389 return;
390 RTC_HISTOGRAM_ENUMERATION("WebRTC.Video.H264DecoderImpl.Event",
391 kH264DecoderEventError,
392 kH264DecoderEventMax);
393 has_reported_error_ = true;
394 }
395
352 } // namespace webrtc 396 } // namespace webrtc
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698