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 216 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
227 | 227 |
228 H264VideoToolboxEncoder::~H264VideoToolboxEncoder() { | 228 H264VideoToolboxEncoder::~H264VideoToolboxEncoder() { |
229 DestroyCompressionSession(); | 229 DestroyCompressionSession(); |
230 } | 230 } |
231 | 231 |
232 int H264VideoToolboxEncoder::InitEncode(const VideoCodec* codec_settings, | 232 int H264VideoToolboxEncoder::InitEncode(const VideoCodec* codec_settings, |
233 int number_of_cores, | 233 int number_of_cores, |
234 size_t max_payload_size) { | 234 size_t max_payload_size) { |
235 RTC_DCHECK(codec_settings); | 235 RTC_DCHECK(codec_settings); |
236 RTC_DCHECK_EQ(codec_settings->codecType, kVideoCodecH264); | 236 RTC_DCHECK_EQ(codec_settings->codecType, kVideoCodecH264); |
237 { | 237 |
238 rtc::CritScope lock(&quality_scaler_crit_); | 238 width_ = codec_settings->width; |
239 quality_scaler_.Init(internal::kLowH264QpThreshold, | 239 height_ = codec_settings->height; |
240 internal::kHighH264QpThreshold, | |
241 codec_settings->startBitrate, codec_settings->width, | |
242 codec_settings->height, codec_settings->maxFramerate); | |
243 QualityScaler::Resolution res = quality_scaler_.GetScaledResolution(); | |
244 // TODO(tkchin): We may need to enforce width/height dimension restrictions | |
245 // to match what the encoder supports. | |
246 width_ = res.width; | |
247 height_ = res.height; | |
248 } | |
249 // We can only set average bitrate on the HW encoder. | 240 // We can only set average bitrate on the HW encoder. |
250 target_bitrate_bps_ = codec_settings->startBitrate; | 241 target_bitrate_bps_ = codec_settings->startBitrate; |
251 bitrate_adjuster_.SetTargetBitrateBps(target_bitrate_bps_); | 242 bitrate_adjuster_.SetTargetBitrateBps(target_bitrate_bps_); |
252 | 243 |
253 // TODO(tkchin): Try setting payload size via | 244 // TODO(tkchin): Try setting payload size via |
254 // kVTCompressionPropertyKey_MaxH264SliceBytes. | 245 // kVTCompressionPropertyKey_MaxH264SliceBytes. |
255 | 246 |
256 return ResetCompressionSession(); | 247 return ResetCompressionSession(); |
257 } | 248 } |
258 | 249 |
259 int H264VideoToolboxEncoder::Encode( | 250 int H264VideoToolboxEncoder::Encode( |
260 const VideoFrame& frame, | 251 const VideoFrame& frame, |
261 const CodecSpecificInfo* codec_specific_info, | 252 const CodecSpecificInfo* codec_specific_info, |
262 const std::vector<FrameType>* frame_types) { | 253 const std::vector<FrameType>* frame_types) { |
254 // input_frame size should always match codec settings | |
sprang_webrtc
2016/10/27 13:43:48
nit: // Input_frame size should always match codec
kthelgason
2016/10/28 13:20:14
I feel weird capitalizing a variable name that is
sprang_webrtc
2016/10/31 10:24:31
Right, I missed the '_' so didn't notice it was th
| |
255 RTC_DCHECK_EQ(frame.width(), width_); | |
256 RTC_DCHECK_EQ(frame.height(), height_); | |
263 RTC_DCHECK(!frame.IsZeroSize()); | 257 RTC_DCHECK(!frame.IsZeroSize()); |
264 if (!callback_ || !compression_session_) { | 258 if (!callback_ || !compression_session_) { |
265 return WEBRTC_VIDEO_CODEC_UNINITIALIZED; | 259 return WEBRTC_VIDEO_CODEC_UNINITIALIZED; |
266 } | 260 } |
267 #if defined(WEBRTC_IOS) | 261 #if defined(WEBRTC_IOS) |
268 if (!RTCIsUIApplicationActive()) { | 262 if (!RTCIsUIApplicationActive()) { |
269 // Ignore all encode requests when app isn't active. In this state, the | 263 // Ignore all encode requests when app isn't active. In this state, the |
270 // hardware encoder has been invalidated by the OS. | 264 // hardware encoder has been invalidated by the OS. |
271 return WEBRTC_VIDEO_CODEC_OK; | 265 return WEBRTC_VIDEO_CODEC_OK; |
272 } | 266 } |
273 #endif | 267 #endif |
274 bool is_keyframe_required = false; | 268 bool is_keyframe_required = false; |
275 | 269 |
276 quality_scaler_.OnEncodeFrame(frame.width(), frame.height()); | |
277 const QualityScaler::Resolution scaled_res = | |
278 quality_scaler_.GetScaledResolution(); | |
279 | |
280 if (scaled_res.width != width_ || scaled_res.height != height_) { | |
281 width_ = scaled_res.width; | |
282 height_ = scaled_res.height; | |
283 int ret = ResetCompressionSession(); | |
284 if (ret < 0) | |
285 return ret; | |
286 } | |
287 | |
288 // Get a pixel buffer from the pool and copy frame data over. | 270 // Get a pixel buffer from the pool and copy frame data over. |
289 CVPixelBufferPoolRef pixel_buffer_pool = | 271 CVPixelBufferPoolRef pixel_buffer_pool = |
290 VTCompressionSessionGetPixelBufferPool(compression_session_); | 272 VTCompressionSessionGetPixelBufferPool(compression_session_); |
291 #if defined(WEBRTC_IOS) | 273 #if defined(WEBRTC_IOS) |
292 if (!pixel_buffer_pool) { | 274 if (!pixel_buffer_pool) { |
293 // Kind of a hack. On backgrounding, the compression session seems to get | 275 // Kind of a hack. On backgrounding, the compression session seems to get |
294 // invalidated, which causes this pool call to fail when the application | 276 // invalidated, which causes this pool call to fail when the application |
295 // is foregrounded and frames are being sent for encoding again. | 277 // is foregrounded and frames are being sent for encoding again. |
296 // Resetting the session when this happens fixes the issue. | 278 // Resetting the session when this happens fixes the issue. |
297 // In addition we request a keyframe so video can recover quickly. | 279 // In addition we request a keyframe so video can recover quickly. |
(...skipping 21 matching lines...) Expand all Loading... | |
319 } | 301 } |
320 CVReturn ret = CVPixelBufferPoolCreatePixelBuffer( | 302 CVReturn ret = CVPixelBufferPoolCreatePixelBuffer( |
321 nullptr, pixel_buffer_pool, &pixel_buffer); | 303 nullptr, pixel_buffer_pool, &pixel_buffer); |
322 if (ret != kCVReturnSuccess) { | 304 if (ret != kCVReturnSuccess) { |
323 LOG(LS_ERROR) << "Failed to create pixel buffer: " << ret; | 305 LOG(LS_ERROR) << "Failed to create pixel buffer: " << ret; |
324 // We probably want to drop frames here, since failure probably means | 306 // We probably want to drop frames here, since failure probably means |
325 // that the pool is empty. | 307 // that the pool is empty. |
326 return WEBRTC_VIDEO_CODEC_ERROR; | 308 return WEBRTC_VIDEO_CODEC_ERROR; |
327 } | 309 } |
328 RTC_DCHECK(pixel_buffer); | 310 RTC_DCHECK(pixel_buffer); |
329 // TODO(magjed): Optimize by merging scaling and NV12 pixel buffer | 311 if (!internal::CopyVideoFrameToPixelBuffer(frame.video_frame_buffer(), |
330 // conversion once libyuv::MergeUVPlanes is available. | |
331 rtc::scoped_refptr<VideoFrameBuffer> scaled_i420_buffer = | |
332 quality_scaler_.GetScaledBuffer(frame.video_frame_buffer()); | |
333 if (!internal::CopyVideoFrameToPixelBuffer(scaled_i420_buffer, | |
334 pixel_buffer)) { | 312 pixel_buffer)) { |
335 LOG(LS_ERROR) << "Failed to copy frame data."; | 313 LOG(LS_ERROR) << "Failed to copy frame data."; |
336 CVBufferRelease(pixel_buffer); | 314 CVBufferRelease(pixel_buffer); |
337 return WEBRTC_VIDEO_CODEC_ERROR; | 315 return WEBRTC_VIDEO_CODEC_ERROR; |
338 } | 316 } |
339 } | 317 } |
340 | 318 |
341 // Check if we need a keyframe. | 319 // Check if we need a keyframe. |
342 if (!is_keyframe_required && frame_types) { | 320 if (!is_keyframe_required && frame_types) { |
343 for (auto frame_type : *frame_types) { | 321 for (auto frame_type : *frame_types) { |
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
379 } | 357 } |
380 return WEBRTC_VIDEO_CODEC_OK; | 358 return WEBRTC_VIDEO_CODEC_OK; |
381 } | 359 } |
382 | 360 |
383 int H264VideoToolboxEncoder::RegisterEncodeCompleteCallback( | 361 int H264VideoToolboxEncoder::RegisterEncodeCompleteCallback( |
384 EncodedImageCallback* callback) { | 362 EncodedImageCallback* callback) { |
385 callback_ = callback; | 363 callback_ = callback; |
386 return WEBRTC_VIDEO_CODEC_OK; | 364 return WEBRTC_VIDEO_CODEC_OK; |
387 } | 365 } |
388 | 366 |
389 void H264VideoToolboxEncoder::OnDroppedFrame() { | |
390 rtc::CritScope lock(&quality_scaler_crit_); | |
391 quality_scaler_.ReportDroppedFrame(); | |
392 } | |
393 | |
394 int H264VideoToolboxEncoder::SetChannelParameters(uint32_t packet_loss, | 367 int H264VideoToolboxEncoder::SetChannelParameters(uint32_t packet_loss, |
395 int64_t rtt) { | 368 int64_t rtt) { |
396 // Encoder doesn't know anything about packet loss or rtt so just return. | 369 // Encoder doesn't know anything about packet loss or rtt so just return. |
397 return WEBRTC_VIDEO_CODEC_OK; | 370 return WEBRTC_VIDEO_CODEC_OK; |
398 } | 371 } |
399 | 372 |
400 int H264VideoToolboxEncoder::SetRates(uint32_t new_bitrate_kbit, | 373 int H264VideoToolboxEncoder::SetRates(uint32_t new_bitrate_kbit, |
401 uint32_t frame_rate) { | 374 uint32_t frame_rate) { |
402 target_bitrate_bps_ = 1000 * new_bitrate_kbit; | 375 target_bitrate_bps_ = 1000 * new_bitrate_kbit; |
403 bitrate_adjuster_.SetTargetBitrateBps(target_bitrate_bps_); | 376 bitrate_adjuster_.SetTargetBitrateBps(target_bitrate_bps_); |
404 SetBitrateBps(bitrate_adjuster_.GetAdjustedBitrateBps()); | 377 SetBitrateBps(bitrate_adjuster_.GetAdjustedBitrateBps()); |
405 | |
406 rtc::CritScope lock(&quality_scaler_crit_); | |
407 quality_scaler_.ReportFramerate(frame_rate); | |
408 | |
409 return WEBRTC_VIDEO_CODEC_OK; | 378 return WEBRTC_VIDEO_CODEC_OK; |
410 } | 379 } |
411 | 380 |
412 int H264VideoToolboxEncoder::Release() { | 381 int H264VideoToolboxEncoder::Release() { |
413 // Need to reset so that the session is invalidated and won't use the | 382 // Need to reset so that the session is invalidated and won't use the |
414 // callback anymore. Do not remove callback until the session is invalidated | 383 // callback anymore. Do not remove callback until the session is invalidated |
415 // since async encoder callbacks can occur until invalidation. | 384 // since async encoder callbacks can occur until invalidation. |
416 int ret = ResetCompressionSession(); | 385 int ret = ResetCompressionSession(); |
417 callback_ = nullptr; | 386 callback_ = nullptr; |
418 return ret; | 387 return ret; |
(...skipping 152 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
571 int32_t height, | 540 int32_t height, |
572 int64_t render_time_ms, | 541 int64_t render_time_ms, |
573 uint32_t timestamp, | 542 uint32_t timestamp, |
574 VideoRotation rotation) { | 543 VideoRotation rotation) { |
575 if (status != noErr) { | 544 if (status != noErr) { |
576 LOG(LS_ERROR) << "H264 encode failed."; | 545 LOG(LS_ERROR) << "H264 encode failed."; |
577 return; | 546 return; |
578 } | 547 } |
579 if (info_flags & kVTEncodeInfo_FrameDropped) { | 548 if (info_flags & kVTEncodeInfo_FrameDropped) { |
580 LOG(LS_INFO) << "H264 encode dropped frame."; | 549 LOG(LS_INFO) << "H264 encode dropped frame."; |
581 rtc::CritScope lock(&quality_scaler_crit_); | |
582 quality_scaler_.ReportDroppedFrame(); | |
583 return; | 550 return; |
584 } | 551 } |
585 | 552 |
586 bool is_keyframe = false; | 553 bool is_keyframe = false; |
587 CFArrayRef attachments = | 554 CFArrayRef attachments = |
588 CMSampleBufferGetSampleAttachmentsArray(sample_buffer, 0); | 555 CMSampleBufferGetSampleAttachmentsArray(sample_buffer, 0); |
589 if (attachments != nullptr && CFArrayGetCount(attachments)) { | 556 if (attachments != nullptr && CFArrayGetCount(attachments)) { |
590 CFDictionaryRef attachment = | 557 CFDictionaryRef attachment = |
591 static_cast<CFDictionaryRef>(CFArrayGetValueAtIndex(attachments, 0)); | 558 static_cast<CFDictionaryRef>(CFArrayGetValueAtIndex(attachments, 0)); |
592 is_keyframe = | 559 is_keyframe = |
(...skipping 21 matching lines...) Expand all Loading... | |
614 frame._encodedWidth = width; | 581 frame._encodedWidth = width; |
615 frame._encodedHeight = height; | 582 frame._encodedHeight = height; |
616 frame._completeFrame = true; | 583 frame._completeFrame = true; |
617 frame._frameType = | 584 frame._frameType = |
618 is_keyframe ? webrtc::kVideoFrameKey : webrtc::kVideoFrameDelta; | 585 is_keyframe ? webrtc::kVideoFrameKey : webrtc::kVideoFrameDelta; |
619 frame.capture_time_ms_ = render_time_ms; | 586 frame.capture_time_ms_ = render_time_ms; |
620 frame._timeStamp = timestamp; | 587 frame._timeStamp = timestamp; |
621 frame.rotation_ = rotation; | 588 frame.rotation_ = rotation; |
622 | 589 |
623 h264_bitstream_parser_.ParseBitstream(buffer->data(), buffer->size()); | 590 h264_bitstream_parser_.ParseBitstream(buffer->data(), buffer->size()); |
624 int qp; | 591 h264_bitstream_parser_.GetLastSliceQp(&frame.qp_); |
625 if (h264_bitstream_parser_.GetLastSliceQp(&qp)) { | |
626 rtc::CritScope lock(&quality_scaler_crit_); | |
627 quality_scaler_.ReportQP(qp); | |
628 } | |
629 | 592 |
630 int result = callback_->Encoded(frame, &codec_specific_info, header.get()); | 593 int result = callback_->Encoded(frame, &codec_specific_info, header.get()); |
631 if (result != 0) { | 594 if (result != 0) { |
632 LOG(LS_ERROR) << "Encode callback failed: " << result; | 595 LOG(LS_ERROR) << "Encode callback failed: " << result; |
633 return; | 596 return; |
634 } | 597 } |
635 bitrate_adjuster_.Update(frame._size); | 598 bitrate_adjuster_.Update(frame._size); |
636 } | 599 } |
637 | 600 |
601 QualityScaler::Settings H264VideoToolboxEncoder::GetQPThresholds() const { | |
602 return QualityScaler::Settings(true, internal::kLowH264QpThreshold, | |
603 internal::kHighH264QpThreshold); | |
604 } | |
638 } // namespace webrtc | 605 } // namespace webrtc |
639 | 606 |
640 #endif // defined(WEBRTC_VIDEO_TOOLBOX_SUPPORTED) | 607 #endif // defined(WEBRTC_VIDEO_TOOLBOX_SUPPORTED) |
OLD | NEW |