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

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

Issue 1645543003: H264: Improve FFmpeg decoder performance by using I420BufferPool. (Closed) Base URL: https://chromium.googlesource.com/external/webrtc.git@master
Patch Set: Added comments about why we zero-initialize 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 */
(...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after
70 RTC_NOTREACHED() << "av_lockmgr_register failed."; 70 RTC_NOTREACHED() << "av_lockmgr_register failed.";
71 return; 71 return;
72 } 72 }
73 av_register_all(); 73 av_register_all();
74 ffmpeg_initialized = true; 74 ffmpeg_initialized = true;
75 } 75 }
76 } 76 }
77 77
78 #endif // !defined(WEBRTC_CHROMIUM_BUILD) 78 #endif // !defined(WEBRTC_CHROMIUM_BUILD)
79 79
80 // Called by FFmpeg when it is done with a frame buffer, see AVGetBuffer2. 80 } // namespace
81 void AVFreeBuffer2(void* opaque, uint8_t* data) {
82 VideoFrame* video_frame = static_cast<VideoFrame*>(opaque);
83 delete video_frame;
84 }
85 81
86 // Called by FFmpeg when it needs a frame buffer to store decoded frames in. 82 // Called by FFmpeg when it needs a frame buffer to store decoded frames in.
87 // The VideoFrames returned by FFmpeg at |Decode| originate from here. They are 83 // The VideoFrames returned by FFmpeg at |Decode| originate from here. They are
88 // reference counted and freed by FFmpeg using |AVFreeBuffer2|. 84 // reference counted and freed by FFmpeg using |AVFreeBuffer2|.
89 // TODO(hbos): Use a frame pool for better performance instead of create/free. 85 // TODO(hbos): Use a frame pool for better performance instead of create/free.
90 // Could be owned by decoder, |static_cast<H264DecoderImpl*>(context->opaque)|. 86 // Could be owned by decoder, |static_cast<H264DecoderImpl*>(context->opaque)|.
stefan-webrtc 2016/02/01 14:02:09 Should this comment be removed now?
hbos 2016/02/02 16:13:03 Done.
91 // Consider verifying that the buffer was allocated by us to avoid unsafe type 87 // Consider verifying that the buffer was allocated by us to avoid unsafe type
92 // cast. See https://bugs.chromium.org/p/webrtc/issues/detail?id=5428. 88 // cast. See https://bugs.chromium.org/p/webrtc/issues/detail?id=5428.
93 int AVGetBuffer2(AVCodecContext* context, AVFrame* av_frame, int flags) { 89 int H264DecoderImpl::AVGetBuffer2(
94 RTC_CHECK_EQ(context->pix_fmt, kPixelFormat); // Same as in InitDecode. 90 AVCodecContext* context, AVFrame* av_frame, int flags) {
91 H264DecoderImpl* decoder =
92 reinterpret_cast<H264DecoderImpl*>(context->opaque);
hbos 2016/01/29 10:16:56 To reinterpret_cast or static_cast, that is the qu
hbos 2016/02/02 16:13:03 static_cast, that is the answer.
93
94 // DCHECK values set in |InitDecode|.
95 RTC_DCHECK(decoder);
96 RTC_DCHECK_EQ(context->pix_fmt, kPixelFormat);
95 // Necessary capability to be allowed to provide our own buffers. 97 // Necessary capability to be allowed to provide our own buffers.
96 RTC_CHECK(context->codec->capabilities | AV_CODEC_CAP_DR1); 98 RTC_DCHECK(context->codec->capabilities | AV_CODEC_CAP_DR1);
99
97 // |av_frame->width| and |av_frame->height| are set by FFmpeg. These are the 100 // |av_frame->width| and |av_frame->height| are set by FFmpeg. These are the
98 // actual image's dimensions and may be different from |context->width| and 101 // actual image's dimensions and may be different from |context->width| and
99 // |context->coded_width| due to reordering. 102 // |context->coded_width| due to reordering.
100 int width = av_frame->width; 103 int width = av_frame->width;
101 int height = av_frame->height; 104 int height = av_frame->height;
102 // See |lowres|, if used the decoder scales the image by 1/2^(lowres). This 105 // See |lowres|, if used the decoder scales the image by 1/2^(lowres). This
103 // has implications on which resolutions are valid, but we don't use it. 106 // has implications on which resolutions are valid, but we don't use it.
104 RTC_CHECK_EQ(context->lowres, 0); 107 RTC_CHECK_EQ(context->lowres, 0);
105 // Adjust the |width| and |height| to values acceptable by the decoder. 108 // Adjust the |width| and |height| to values acceptable by the decoder.
106 // Without this, FFmpeg may overflow the buffer. If modified, |width| and/or 109 // Without this, FFmpeg may overflow the buffer. If modified, |width| and/or
107 // |height| are larger than the actual image and the image has to be cropped 110 // |height| are larger than the actual image and the image has to be cropped
108 // (top-left corner) after decoding to avoid visible borders to the right and 111 // (top-left corner) after decoding to avoid visible borders to the right and
109 // bottom of the actual image. 112 // bottom of the actual image.
110 avcodec_align_dimensions(context, &width, &height); 113 avcodec_align_dimensions(context, &width, &height);
111 114
112 RTC_CHECK_GE(width, 0); 115 RTC_CHECK_GE(width, 0);
113 RTC_CHECK_GE(height, 0); 116 RTC_CHECK_GE(height, 0);
114 int ret = av_image_check_size(static_cast<unsigned int>(width), 117 int ret = av_image_check_size(static_cast<unsigned int>(width),
115 static_cast<unsigned int>(height), 0, nullptr); 118 static_cast<unsigned int>(height), 0, nullptr);
116 if (ret < 0) { 119 if (ret < 0) {
117 LOG(LS_ERROR) << "Invalid picture size " << width << "x" << height; 120 LOG(LS_ERROR) << "Invalid picture size " << width << "x" << height;
118 return ret; 121 return ret;
119 } 122 }
120 123
121 // 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
122 // 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.
123 VideoFrame* video_frame = new VideoFrame(); 126 VideoFrame* video_frame = new VideoFrame();
124 int stride_y = width;
125 int stride_uv = (width + 1) / 2;
126 RTC_CHECK_EQ(0, video_frame->CreateEmptyFrame(
127 width, height, stride_y, stride_uv, stride_uv));
128 int total_size = video_frame->allocated_size(kYPlane) +
129 video_frame->allocated_size(kUPlane) +
130 video_frame->allocated_size(kVPlane);
131 RTC_DCHECK_EQ(total_size, stride_y * height +
132 (stride_uv + stride_uv) * ((height + 1) / 2));
133
134 // FFmpeg expects the initial allocation to be zero-initialized according to 127 // FFmpeg expects the initial allocation to be zero-initialized according to
135 // http://crbug.com/390941. 128 // http://crbug.com/390941. Our pool is set up to zero-initialize new buffers.
136 // Using a single |av_frame->buf| - YUV is required to be a continuous blob of 129 video_frame->set_video_frame_buffer(
137 // memory. We can zero-initialize with one memset operation for all planes. 130 decoder->pool_.CreateBuffer(width, height));
131 // DCHECK that we have a continuous buffer as is required.
138 RTC_DCHECK_EQ(video_frame->buffer(kUPlane), 132 RTC_DCHECK_EQ(video_frame->buffer(kUPlane),
139 video_frame->buffer(kYPlane) + video_frame->allocated_size(kYPlane)); 133 video_frame->buffer(kYPlane) + video_frame->allocated_size(kYPlane));
140 RTC_DCHECK_EQ(video_frame->buffer(kVPlane), 134 RTC_DCHECK_EQ(video_frame->buffer(kVPlane),
141 video_frame->buffer(kUPlane) + video_frame->allocated_size(kUPlane)); 135 video_frame->buffer(kUPlane) + video_frame->allocated_size(kUPlane));
142 memset(video_frame->buffer(kYPlane), 0, total_size); 136 int total_size = video_frame->allocated_size(kYPlane) +
stefan-webrtc 2016/02/01 14:02:09 The memset you did in the pool doesn't memset the
hbos 2016/02/02 16:13:03 That memset and this memset are the same. See prev
137 video_frame->allocated_size(kUPlane) +
138 video_frame->allocated_size(kVPlane);
143 139
144 av_frame->format = context->pix_fmt; 140 av_frame->format = context->pix_fmt;
145 av_frame->reordered_opaque = context->reordered_opaque; 141 av_frame->reordered_opaque = context->reordered_opaque;
146 142
147 // Set |av_frame| members as required by FFmpeg. 143 // Set |av_frame| members as required by FFmpeg.
148 av_frame->data[kYPlaneIndex] = video_frame->buffer(kYPlane); 144 av_frame->data[kYPlaneIndex] = video_frame->buffer(kYPlane);
149 av_frame->linesize[kYPlaneIndex] = video_frame->stride(kYPlane); 145 av_frame->linesize[kYPlaneIndex] = video_frame->stride(kYPlane);
150 av_frame->data[kUPlaneIndex] = video_frame->buffer(kUPlane); 146 av_frame->data[kUPlaneIndex] = video_frame->buffer(kUPlane);
151 av_frame->linesize[kUPlaneIndex] = video_frame->stride(kUPlane); 147 av_frame->linesize[kUPlaneIndex] = video_frame->stride(kUPlane);
152 av_frame->data[kVPlaneIndex] = video_frame->buffer(kVPlane); 148 av_frame->data[kVPlaneIndex] = video_frame->buffer(kVPlane);
153 av_frame->linesize[kVPlaneIndex] = video_frame->stride(kVPlane); 149 av_frame->linesize[kVPlaneIndex] = video_frame->stride(kVPlane);
154 RTC_DCHECK_EQ(av_frame->extended_data, av_frame->data); 150 RTC_DCHECK_EQ(av_frame->extended_data, av_frame->data);
155 151
156 av_frame->buf[0] = av_buffer_create(av_frame->data[kYPlaneIndex], 152 av_frame->buf[0] = av_buffer_create(av_frame->data[kYPlaneIndex],
157 total_size, 153 total_size,
158 AVFreeBuffer2, 154 AVFreeBuffer2,
159 static_cast<void*>(video_frame), 155 static_cast<void*>(video_frame),
160 0); 156 0);
161 RTC_CHECK(av_frame->buf[0]); 157 RTC_CHECK(av_frame->buf[0]);
162 return 0; 158 return 0;
163 } 159 }
164 160
165 } // namespace 161 // Called by FFmpeg when it is done with a frame buffer, see AVGetBuffer2.
162 void H264DecoderImpl::AVFreeBuffer2(void* opaque, uint8_t* data) {
163 VideoFrame* video_frame = static_cast<VideoFrame*>(opaque);
164 delete video_frame;
stefan-webrtc 2016/02/01 14:02:09 Seems odd that we delete frames when we are using
hbos 2016/02/02 16:13:03 Added a comment explaining why.
165 }
166 166
167 H264DecoderImpl::H264DecoderImpl() 167 H264DecoderImpl::H264DecoderImpl() : pool_(true),
168 : decoded_image_callback_(nullptr) { 168 decoded_image_callback_(nullptr) {
169 } 169 }
170 170
171 H264DecoderImpl::~H264DecoderImpl() { 171 H264DecoderImpl::~H264DecoderImpl() {
172 Release(); 172 Release();
173 } 173 }
174 174
175 int32_t H264DecoderImpl::InitDecode(const VideoCodec* codec_settings, 175 int32_t H264DecoderImpl::InitDecode(const VideoCodec* codec_settings,
176 int32_t number_of_cores) { 176 int32_t number_of_cores) {
177 if (codec_settings && 177 if (codec_settings &&
178 codec_settings->codecType != kVideoCodecH264) { 178 codec_settings->codecType != kVideoCodecH264) {
(...skipping 22 matching lines...) Expand all
201 av_context_->codec_type = AVMEDIA_TYPE_VIDEO; 201 av_context_->codec_type = AVMEDIA_TYPE_VIDEO;
202 av_context_->codec_id = AV_CODEC_ID_H264; 202 av_context_->codec_id = AV_CODEC_ID_H264;
203 if (codec_settings) { 203 if (codec_settings) {
204 av_context_->coded_width = codec_settings->width; 204 av_context_->coded_width = codec_settings->width;
205 av_context_->coded_height = codec_settings->height; 205 av_context_->coded_height = codec_settings->height;
206 } 206 }
207 av_context_->pix_fmt = kPixelFormat; 207 av_context_->pix_fmt = kPixelFormat;
208 av_context_->extradata = nullptr; 208 av_context_->extradata = nullptr;
209 av_context_->extradata_size = 0; 209 av_context_->extradata_size = 0;
210 210
211 // If this is ever increased, look at |av_context_->thread_safe_callbacks| and
212 // make it possible to disable the thread checker in the frame buffer pool.
211 av_context_->thread_count = 1; 213 av_context_->thread_count = 1;
212 av_context_->thread_type = FF_THREAD_SLICE; 214 av_context_->thread_type = FF_THREAD_SLICE;
213 215
214 // FFmpeg will get video buffers from our AVGetBuffer2, memory managed by us. 216 // Function used by FFmpeg to get buffers to store decoded frames in.
215 av_context_->get_buffer2 = AVGetBuffer2; 217 av_context_->get_buffer2 = AVGetBuffer2;
216 // get_buffer2 is called with the context, there |opaque| can be used to get a 218 // |get_buffer2| is called with the context, there |opaque| can be used to get
217 // pointer |this|. 219 // a pointer |this|.
218 av_context_->opaque = this; 220 av_context_->opaque = this;
219 // Use ref counted frames (av_frame_unref). 221 // Use ref counted frames (av_frame_unref).
220 av_context_->refcounted_frames = 1; // true 222 av_context_->refcounted_frames = 1; // true
221 223
222 AVCodec* codec = avcodec_find_decoder(av_context_->codec_id); 224 AVCodec* codec = avcodec_find_decoder(av_context_->codec_id);
223 if (!codec) { 225 if (!codec) {
224 // This is an indication that FFmpeg has not been initialized or it has not 226 // This is an indication that FFmpeg has not been initialized or it has not
225 // been compiled/initialized with the correct set of codecs. 227 // been compiled/initialized with the correct set of codecs.
226 LOG(LS_ERROR) << "FFmpeg H.264 decoder not found."; 228 LOG(LS_ERROR) << "FFmpeg H.264 decoder not found.";
227 Release(); 229 Release();
(...skipping 125 matching lines...) Expand 10 before | Expand all | Expand 10 after
353 return ret; 355 return ret;
354 } 356 }
355 return WEBRTC_VIDEO_CODEC_OK; 357 return WEBRTC_VIDEO_CODEC_OK;
356 } 358 }
357 359
358 bool H264DecoderImpl::IsInitialized() const { 360 bool H264DecoderImpl::IsInitialized() const {
359 return av_context_ != nullptr; 361 return av_context_ != nullptr;
360 } 362 }
361 363
362 } // namespace webrtc 364 } // namespace webrtc
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698