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 232 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
243 // kVTCompressionPropertyKey_MaxH264SliceBytes. | 243 // kVTCompressionPropertyKey_MaxH264SliceBytes. |
244 | 244 |
245 return ResetCompressionSession(); | 245 return ResetCompressionSession(); |
246 } | 246 } |
247 | 247 |
248 rtc::scoped_refptr<VideoFrameBuffer> | 248 rtc::scoped_refptr<VideoFrameBuffer> |
249 H264VideoToolboxEncoder::GetScaledBufferOnEncode( | 249 H264VideoToolboxEncoder::GetScaledBufferOnEncode( |
250 const rtc::scoped_refptr<VideoFrameBuffer>& frame) { | 250 const rtc::scoped_refptr<VideoFrameBuffer>& frame) { |
251 rtc::CritScope lock(&quality_scaler_crit_); | 251 rtc::CritScope lock(&quality_scaler_crit_); |
252 quality_scaler_.OnEncodeFrame(frame->width(), frame->height()); | 252 quality_scaler_.OnEncodeFrame(frame->width(), frame->height()); |
253 return quality_scaler_.GetScaledBuffer(frame); | 253 if (!frame->native_handle()) |
| 254 return quality_scaler_.GetScaledBuffer(frame); |
| 255 |
| 256 // Handle native (CVImageRef) scaling. |
| 257 const QualityScaler::Resolution res = quality_scaler_.GetScaledResolution(); |
| 258 if (res.width == frame->width() && res.height == frame->height()) |
| 259 return frame; |
| 260 // TODO(magjed): Implement efficient CVImageRef -> CVImageRef scaling instead |
| 261 // of doing it via I420. |
| 262 return quality_scaler_.GetScaledBuffer(frame->NativeToI420Buffer()); |
254 } | 263 } |
255 | 264 |
256 int H264VideoToolboxEncoder::Encode( | 265 int H264VideoToolboxEncoder::Encode( |
257 const VideoFrame& frame, | 266 const VideoFrame& frame, |
258 const CodecSpecificInfo* codec_specific_info, | 267 const CodecSpecificInfo* codec_specific_info, |
259 const std::vector<FrameType>* frame_types) { | 268 const std::vector<FrameType>* frame_types) { |
260 RTC_DCHECK(!frame.IsZeroSize()); | 269 RTC_DCHECK(!frame.IsZeroSize()); |
261 if (!callback_ || !compression_session_) { | 270 if (!callback_ || !compression_session_) { |
262 return WEBRTC_VIDEO_CODEC_UNINITIALIZED; | 271 return WEBRTC_VIDEO_CODEC_UNINITIALIZED; |
263 } | 272 } |
264 #if defined(WEBRTC_IOS) | 273 #if defined(WEBRTC_IOS) |
265 if (!RTCIsUIApplicationActive()) { | 274 if (!RTCIsUIApplicationActive()) { |
266 // Ignore all encode requests when app isn't active. In this state, the | 275 // Ignore all encode requests when app isn't active. In this state, the |
267 // hardware encoder has been invalidated by the OS. | 276 // hardware encoder has been invalidated by the OS. |
268 return WEBRTC_VIDEO_CODEC_OK; | 277 return WEBRTC_VIDEO_CODEC_OK; |
269 } | 278 } |
270 #endif | 279 #endif |
271 bool is_keyframe_required = false; | 280 bool is_keyframe_required = false; |
272 rtc::scoped_refptr<VideoFrameBuffer> input_image( | 281 rtc::scoped_refptr<VideoFrameBuffer> input_image( |
273 GetScaledBufferOnEncode(frame.video_frame_buffer())); | 282 GetScaledBufferOnEncode(frame.video_frame_buffer())); |
274 | 283 |
275 if (input_image->width() != width_ || input_image->height() != height_) { | 284 if (input_image->width() != width_ || input_image->height() != height_) { |
276 width_ = input_image->width(); | 285 width_ = input_image->width(); |
277 height_ = input_image->height(); | 286 height_ = input_image->height(); |
278 int ret = ResetCompressionSession(); | 287 int ret = ResetCompressionSession(); |
279 if (ret < 0) | 288 if (ret < 0) |
280 return ret; | 289 return ret; |
281 } | 290 } |
282 | 291 |
283 // Get a pixel buffer from the pool and copy frame data over. | 292 CVPixelBufferRef pixel_buffer = |
284 CVPixelBufferPoolRef pixel_buffer_pool = | 293 static_cast<CVPixelBufferRef>(input_image->native_handle()); |
285 VTCompressionSessionGetPixelBufferPool(compression_session_); | 294 if (pixel_buffer) { |
| 295 CVBufferRetain(pixel_buffer); |
| 296 } else { |
| 297 // Get a pixel buffer from the pool and copy frame data over. |
| 298 CVPixelBufferPoolRef pixel_buffer_pool = |
| 299 VTCompressionSessionGetPixelBufferPool(compression_session_); |
286 #if defined(WEBRTC_IOS) | 300 #if defined(WEBRTC_IOS) |
287 if (!pixel_buffer_pool) { | 301 if (!pixel_buffer_pool) { |
288 // Kind of a hack. On backgrounding, the compression session seems to get | 302 // Kind of a hack. On backgrounding, the compression session seems to get |
289 // invalidated, which causes this pool call to fail when the application | 303 // invalidated, which causes this pool call to fail when the application |
290 // is foregrounded and frames are being sent for encoding again. | 304 // is foregrounded and frames are being sent for encoding again. |
291 // Resetting the session when this happens fixes the issue. | 305 // Resetting the session when this happens fixes the issue. |
292 // In addition we request a keyframe so video can recover quickly. | 306 // In addition we request a keyframe so video can recover quickly. |
293 ResetCompressionSession(); | 307 ResetCompressionSession(); |
294 pixel_buffer_pool = | 308 pixel_buffer_pool = |
295 VTCompressionSessionGetPixelBufferPool(compression_session_); | 309 VTCompressionSessionGetPixelBufferPool(compression_session_); |
296 is_keyframe_required = true; | 310 is_keyframe_required = true; |
297 } | 311 } |
298 #endif | 312 #endif |
299 if (!pixel_buffer_pool) { | 313 if (!pixel_buffer_pool) { |
300 LOG(LS_ERROR) << "Failed to get pixel buffer pool."; | 314 LOG(LS_ERROR) << "Failed to get pixel buffer pool."; |
301 return WEBRTC_VIDEO_CODEC_ERROR; | 315 return WEBRTC_VIDEO_CODEC_ERROR; |
302 } | 316 } |
303 CVPixelBufferRef pixel_buffer = nullptr; | 317 CVReturn ret = CVPixelBufferPoolCreatePixelBuffer( |
304 CVReturn ret = CVPixelBufferPoolCreatePixelBuffer(nullptr, pixel_buffer_pool, | 318 nullptr, pixel_buffer_pool, &pixel_buffer); |
305 &pixel_buffer); | 319 if (ret != kCVReturnSuccess) { |
306 if (ret != kCVReturnSuccess) { | 320 LOG(LS_ERROR) << "Failed to create pixel buffer: " << ret; |
307 LOG(LS_ERROR) << "Failed to create pixel buffer: " << ret; | 321 // We probably want to drop frames here, since failure probably means |
308 // We probably want to drop frames here, since failure probably means | 322 // that the pool is empty. |
309 // that the pool is empty. | 323 return WEBRTC_VIDEO_CODEC_ERROR; |
310 return WEBRTC_VIDEO_CODEC_ERROR; | 324 } |
311 } | 325 RTC_DCHECK(pixel_buffer); |
312 RTC_DCHECK(pixel_buffer); | 326 if (!internal::CopyVideoFrameToPixelBuffer(input_image, pixel_buffer)) { |
313 if (!internal::CopyVideoFrameToPixelBuffer(input_image, pixel_buffer)) { | 327 LOG(LS_ERROR) << "Failed to copy frame data."; |
314 LOG(LS_ERROR) << "Failed to copy frame data."; | 328 CVBufferRelease(pixel_buffer); |
315 CVBufferRelease(pixel_buffer); | 329 return WEBRTC_VIDEO_CODEC_ERROR; |
316 return WEBRTC_VIDEO_CODEC_ERROR; | 330 } |
317 } | 331 } |
318 | 332 |
319 // Check if we need a keyframe. | 333 // Check if we need a keyframe. |
320 if (!is_keyframe_required && frame_types) { | 334 if (!is_keyframe_required && frame_types) { |
321 for (auto frame_type : *frame_types) { | 335 for (auto frame_type : *frame_types) { |
322 if (frame_type == kVideoFrameKey) { | 336 if (frame_type == kVideoFrameKey) { |
323 is_keyframe_required = true; | 337 is_keyframe_required = true; |
324 break; | 338 break; |
325 } | 339 } |
326 } | 340 } |
(...skipping 154 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
481 VTCompressionSessionInvalidate(compression_session_); | 495 VTCompressionSessionInvalidate(compression_session_); |
482 CFRelease(compression_session_); | 496 CFRelease(compression_session_); |
483 compression_session_ = nullptr; | 497 compression_session_ = nullptr; |
484 } | 498 } |
485 } | 499 } |
486 | 500 |
487 const char* H264VideoToolboxEncoder::ImplementationName() const { | 501 const char* H264VideoToolboxEncoder::ImplementationName() const { |
488 return "VideoToolbox"; | 502 return "VideoToolbox"; |
489 } | 503 } |
490 | 504 |
| 505 bool H264VideoToolboxEncoder::SupportsNativeHandle() const { |
| 506 return true; |
| 507 } |
| 508 |
491 void H264VideoToolboxEncoder::SetBitrateBps(uint32_t bitrate_bps) { | 509 void H264VideoToolboxEncoder::SetBitrateBps(uint32_t bitrate_bps) { |
492 if (encoder_bitrate_bps_ != bitrate_bps) { | 510 if (encoder_bitrate_bps_ != bitrate_bps) { |
493 SetEncoderBitrateBps(bitrate_bps); | 511 SetEncoderBitrateBps(bitrate_bps); |
494 } | 512 } |
495 } | 513 } |
496 | 514 |
497 void H264VideoToolboxEncoder::SetEncoderBitrateBps(uint32_t bitrate_bps) { | 515 void H264VideoToolboxEncoder::SetEncoderBitrateBps(uint32_t bitrate_bps) { |
498 if (compression_session_) { | 516 if (compression_session_) { |
499 internal::SetVTSessionProperty(compression_session_, | 517 internal::SetVTSessionProperty(compression_session_, |
500 kVTCompressionPropertyKey_AverageBitRate, | 518 kVTCompressionPropertyKey_AverageBitRate, |
(...skipping 103 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
604 if (result != 0) { | 622 if (result != 0) { |
605 LOG(LS_ERROR) << "Encode callback failed: " << result; | 623 LOG(LS_ERROR) << "Encode callback failed: " << result; |
606 return; | 624 return; |
607 } | 625 } |
608 bitrate_adjuster_.Update(frame._size); | 626 bitrate_adjuster_.Update(frame._size); |
609 } | 627 } |
610 | 628 |
611 } // namespace webrtc | 629 } // namespace webrtc |
612 | 630 |
613 #endif // defined(WEBRTC_VIDEO_TOOLBOX_SUPPORTED) | 631 #endif // defined(WEBRTC_VIDEO_TOOLBOX_SUPPORTED) |
OLD | NEW |