Chromium Code Reviews| OLD | NEW |
|---|---|
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 |
| OLD | NEW |