Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "media/cast/sender/h264_vt_encoder.h" | 5 #include "media/cast/sender/h264_vt_encoder.h" |
| 6 | 6 |
| 7 #include <string> | 7 #include <string> |
| 8 | 8 |
| 9 #include "base/big_endian.h" | 9 #include "base/big_endian.h" |
| 10 #include "base/bind.h" | 10 #include "base/bind.h" |
| 11 #include "base/bind_helpers.h" | 11 #include "base/bind_helpers.h" |
| 12 #include "base/location.h" | 12 #include "base/location.h" |
| 13 #include "base/logging.h" | 13 #include "base/logging.h" |
| 14 #include "base/macros.h" | |
| 14 #include "media/base/mac/corevideo_glue.h" | 15 #include "media/base/mac/corevideo_glue.h" |
| 15 #include "media/base/mac/video_frame_mac.h" | 16 #include "media/base/mac/video_frame_mac.h" |
| 16 #include "media/cast/sender/video_frame_factory.h" | 17 #include "media/cast/sender/video_frame_factory.h" |
| 17 | 18 |
| 18 namespace media { | 19 namespace media { |
| 19 namespace cast { | 20 namespace cast { |
| 20 | 21 |
| 21 namespace { | 22 namespace { |
| 22 | 23 |
| 23 // Container for the associated data of a video frame being processed. | 24 // Container for the associated data of a video frame being processed. |
| (...skipping 12 matching lines...) Expand all Loading... | |
| 36 | 37 |
| 37 base::ScopedCFTypeRef<CFDictionaryRef> DictionaryWithKeyValue(CFTypeRef key, | 38 base::ScopedCFTypeRef<CFDictionaryRef> DictionaryWithKeyValue(CFTypeRef key, |
| 38 CFTypeRef value) { | 39 CFTypeRef value) { |
| 39 CFTypeRef keys[1] = {key}; | 40 CFTypeRef keys[1] = {key}; |
| 40 CFTypeRef values[1] = {value}; | 41 CFTypeRef values[1] = {value}; |
| 41 return base::ScopedCFTypeRef<CFDictionaryRef>(CFDictionaryCreate( | 42 return base::ScopedCFTypeRef<CFDictionaryRef>(CFDictionaryCreate( |
| 42 kCFAllocatorDefault, keys, values, 1, &kCFTypeDictionaryKeyCallBacks, | 43 kCFAllocatorDefault, keys, values, 1, &kCFTypeDictionaryKeyCallBacks, |
| 43 &kCFTypeDictionaryValueCallBacks)); | 44 &kCFTypeDictionaryValueCallBacks)); |
| 44 } | 45 } |
| 45 | 46 |
| 47 base::ScopedCFTypeRef<CFArrayRef> ArrayWithIntegers(const std::vector<int>& v) { | |
| 48 std::vector<CFNumberRef> numbers; | |
| 49 numbers.reserve(v.size()); | |
| 50 for (const int i : v) { | |
| 51 numbers.push_back(CFNumberCreate(nullptr, kCFNumberSInt32Type, &i)); | |
| 52 } | |
| 53 base::ScopedCFTypeRef<CFArrayRef> array(CFArrayCreate( | |
| 54 kCFAllocatorDefault, reinterpret_cast<const void**>(&numbers[0]), | |
| 55 numbers.size(), &kCFTypeArrayCallBacks)); | |
| 56 for (CFNumberRef number : numbers) { | |
| 57 CFRelease(number); | |
| 58 } | |
| 59 return array; | |
| 60 } | |
| 61 | |
| 46 template <typename NalSizeType> | 62 template <typename NalSizeType> |
| 47 void CopyNalsToAnnexB(char* avcc_buffer, | 63 void CopyNalsToAnnexB(char* avcc_buffer, |
| 48 const size_t avcc_size, | 64 const size_t avcc_size, |
| 49 std::string* annexb_buffer) { | 65 std::string* annexb_buffer) { |
| 50 static_assert(sizeof(NalSizeType) == 1 || sizeof(NalSizeType) == 2 || | 66 static_assert(sizeof(NalSizeType) == 1 || sizeof(NalSizeType) == 2 || |
| 51 sizeof(NalSizeType) == 4, | 67 sizeof(NalSizeType) == 4, |
| 52 "NAL size type has unsupported size"); | 68 "NAL size type has unsupported size"); |
| 53 static const char startcode_3[3] = {0, 0, 1}; | 69 static const char startcode_3[3] = {0, 0, 1}; |
| 54 DCHECK(avcc_buffer); | 70 DCHECK(avcc_buffer); |
| 55 DCHECK(annexb_buffer); | 71 DCHECK(annexb_buffer); |
| (...skipping 194 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 250 // On OS X, allow the hardware encoder. Don't require it, it does not support | 266 // On OS X, allow the hardware encoder. Don't require it, it does not support |
| 251 // all configurations (some of which are used for testing). | 267 // all configurations (some of which are used for testing). |
| 252 base::ScopedCFTypeRef<CFDictionaryRef> encoder_spec; | 268 base::ScopedCFTypeRef<CFDictionaryRef> encoder_spec; |
| 253 #if !defined(OS_IOS) | 269 #if !defined(OS_IOS) |
| 254 encoder_spec = DictionaryWithKeyValue( | 270 encoder_spec = DictionaryWithKeyValue( |
| 255 videotoolbox_glue_ | 271 videotoolbox_glue_ |
| 256 ->kVTVideoEncoderSpecification_EnableHardwareAcceleratedVideoEncoder() , | 272 ->kVTVideoEncoderSpecification_EnableHardwareAcceleratedVideoEncoder() , |
| 257 kCFBooleanTrue); | 273 kCFBooleanTrue); |
| 258 #endif | 274 #endif |
| 259 | 275 |
| 276 // Certain encoders prefer kCVPixelFormatType_422YpCbCr8, which is not | |
| 277 // supported through VideoFrame. We can force 420 formats to be used instead. | |
| 278 const int formats[] = { | |
| 279 kCVPixelFormatType_420YpCbCr8Planar, | |
| 280 CoreVideoGlue::kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange}; | |
| 281 base::ScopedCFTypeRef<CFArrayRef> formats_array = ArrayWithIntegers( | |
| 282 std::vector<int>(formats, formats + arraysize(formats))); | |
| 283 base::ScopedCFTypeRef<CFDictionaryRef> buffer_attributes = | |
| 284 DictionaryWithKeyValue(kCVPixelBufferPixelFormatTypeKey, formats_array); | |
| 285 | |
| 260 VTCompressionSessionRef session; | 286 VTCompressionSessionRef session; |
| 261 OSStatus status = videotoolbox_glue_->VTCompressionSessionCreate( | 287 OSStatus status = videotoolbox_glue_->VTCompressionSessionCreate( |
| 262 kCFAllocatorDefault, video_config.width, video_config.height, | 288 kCFAllocatorDefault, video_config.width, video_config.height, |
| 263 CoreMediaGlue::kCMVideoCodecType_H264, encoder_spec, | 289 CoreMediaGlue::kCMVideoCodecType_H264, encoder_spec, buffer_attributes, |
| 264 nullptr /* sourceImageBufferAttributes */, | |
| 265 nullptr /* compressedDataAllocator */, | 290 nullptr /* compressedDataAllocator */, |
| 266 &H264VideoToolboxEncoder::CompressionCallback, | 291 &H264VideoToolboxEncoder::CompressionCallback, |
| 267 reinterpret_cast<void*>(this), &session); | 292 reinterpret_cast<void*>(this), &session); |
| 268 if (status != noErr) { | 293 if (status != noErr) { |
| 269 DLOG(ERROR) << " VTCompressionSessionCreate failed: " << status; | 294 DLOG(ERROR) << " VTCompressionSessionCreate failed: " << status; |
| 270 return false; | 295 return false; |
| 271 } | 296 } |
| 272 compression_session_.reset(session); | 297 compression_session_.reset(session); |
| 273 | 298 |
| 274 ConfigureSession(video_config); | 299 ConfigureSession(video_config); |
| (...skipping 27 matching lines...) Expand all Loading... | |
| 302 video_config.max_frame_rate); | 327 video_config.max_frame_rate); |
| 303 SetSessionProperty( | 328 SetSessionProperty( |
| 304 videotoolbox_glue_->kVTCompressionPropertyKey_ColorPrimaries(), | 329 videotoolbox_glue_->kVTCompressionPropertyKey_ColorPrimaries(), |
| 305 kCVImageBufferColorPrimaries_ITU_R_709_2); | 330 kCVImageBufferColorPrimaries_ITU_R_709_2); |
| 306 SetSessionProperty( | 331 SetSessionProperty( |
| 307 videotoolbox_glue_->kVTCompressionPropertyKey_TransferFunction(), | 332 videotoolbox_glue_->kVTCompressionPropertyKey_TransferFunction(), |
| 308 kCVImageBufferTransferFunction_ITU_R_709_2); | 333 kCVImageBufferTransferFunction_ITU_R_709_2); |
| 309 SetSessionProperty( | 334 SetSessionProperty( |
| 310 videotoolbox_glue_->kVTCompressionPropertyKey_YCbCrMatrix(), | 335 videotoolbox_glue_->kVTCompressionPropertyKey_YCbCrMatrix(), |
| 311 kCVImageBufferYCbCrMatrix_ITU_R_709_2); | 336 kCVImageBufferYCbCrMatrix_ITU_R_709_2); |
| 337 if (video_config.max_number_of_video_buffers_used > 0) { | |
| 338 SetSessionProperty( | |
| 339 videotoolbox_glue_->kVTCompressionPropertyKey_MaxFrameDelayCount(), | |
| 340 video_config.max_number_of_video_buffers_used); | |
|
miu
2015/01/21 23:24:27
VideoSenderConfig::max_number_of_video_buffers_use
| |
| 341 } | |
| 312 } | 342 } |
| 313 | 343 |
| 314 void H264VideoToolboxEncoder::Teardown() { | 344 void H264VideoToolboxEncoder::Teardown() { |
| 315 DCHECK(thread_checker_.CalledOnValidThread()); | 345 DCHECK(thread_checker_.CalledOnValidThread()); |
| 316 | 346 |
| 317 // If the compression session exists, invalidate it. This blocks until all | 347 // If the compression session exists, invalidate it. This blocks until all |
| 318 // pending output callbacks have returned and any internal threads have | 348 // pending output callbacks have returned and any internal threads have |
| 319 // joined, ensuring no output callback ever sees a dangling encoder pointer. | 349 // joined, ensuring no output callback ever sees a dangling encoder pointer. |
| 320 if (compression_session_) { | 350 if (compression_session_) { |
| 321 videotoolbox_glue_->VTCompressionSessionInvalidate(compression_session_); | 351 videotoolbox_glue_->VTCompressionSessionInvalidate(compression_session_); |
| (...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 397 scoped_ptr<VideoFrameFactory> | 427 scoped_ptr<VideoFrameFactory> |
| 398 H264VideoToolboxEncoder::CreateVideoFrameFactory() { | 428 H264VideoToolboxEncoder::CreateVideoFrameFactory() { |
| 399 base::ScopedCFTypeRef<CVPixelBufferPoolRef> pool( | 429 base::ScopedCFTypeRef<CVPixelBufferPoolRef> pool( |
| 400 videotoolbox_glue_->VTCompressionSessionGetPixelBufferPool( | 430 videotoolbox_glue_->VTCompressionSessionGetPixelBufferPool( |
| 401 compression_session_), | 431 compression_session_), |
| 402 base::scoped_policy::RETAIN); | 432 base::scoped_policy::RETAIN); |
| 403 return scoped_ptr<VideoFrameFactory>( | 433 return scoped_ptr<VideoFrameFactory>( |
| 404 new VideoFrameFactoryCVPixelBufferPoolImpl(pool)); | 434 new VideoFrameFactoryCVPixelBufferPoolImpl(pool)); |
| 405 } | 435 } |
| 406 | 436 |
| 437 void H264VideoToolboxEncoder::EmitFrames() { | |
| 438 DCHECK(thread_checker_.CalledOnValidThread()); | |
| 439 | |
| 440 if (!compression_session_) { | |
| 441 DLOG(ERROR) << " compression session is null"; | |
| 442 return; | |
| 443 } | |
| 444 | |
| 445 OSStatus status = videotoolbox_glue_->VTCompressionSessionCompleteFrames( | |
| 446 compression_session_, CoreMediaGlue::CMTime{0, 0, 0, 0}); | |
| 447 if (status != noErr) { | |
| 448 DLOG(ERROR) << " VTCompressionSessionCompleteFrames failed: " << status; | |
| 449 } | |
| 450 } | |
| 451 | |
| 407 bool H264VideoToolboxEncoder::SetSessionProperty(CFStringRef key, | 452 bool H264VideoToolboxEncoder::SetSessionProperty(CFStringRef key, |
| 408 int32_t value) { | 453 int32_t value) { |
| 409 base::ScopedCFTypeRef<CFNumberRef> cfvalue( | 454 base::ScopedCFTypeRef<CFNumberRef> cfvalue( |
| 410 CFNumberCreate(nullptr, kCFNumberSInt32Type, &value)); | 455 CFNumberCreate(nullptr, kCFNumberSInt32Type, &value)); |
| 411 return videotoolbox_glue_->VTSessionSetProperty(compression_session_, key, | 456 return videotoolbox_glue_->VTSessionSetProperty(compression_session_, key, |
| 412 cfvalue) == noErr; | 457 cfvalue) == noErr; |
| 413 } | 458 } |
| 414 | 459 |
| 415 bool H264VideoToolboxEncoder::SetSessionProperty(CFStringRef key, bool value) { | 460 bool H264VideoToolboxEncoder::SetSessionProperty(CFStringRef key, bool value) { |
| 416 CFBooleanRef cfvalue = (value) ? kCFBooleanTrue : kCFBooleanFalse; | 461 CFBooleanRef cfvalue = (value) ? kCFBooleanTrue : kCFBooleanFalse; |
| (...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 479 CopySampleBufferToAnnexBBuffer(sbuf, &encoded_frame->data, keyframe); | 524 CopySampleBufferToAnnexBBuffer(sbuf, &encoded_frame->data, keyframe); |
| 480 | 525 |
| 481 encoder->cast_environment_->PostTask( | 526 encoder->cast_environment_->PostTask( |
| 482 CastEnvironment::MAIN, FROM_HERE, | 527 CastEnvironment::MAIN, FROM_HERE, |
| 483 base::Bind(request->frame_encoded_callback, | 528 base::Bind(request->frame_encoded_callback, |
| 484 base::Passed(&encoded_frame))); | 529 base::Passed(&encoded_frame))); |
| 485 } | 530 } |
| 486 | 531 |
| 487 } // namespace cast | 532 } // namespace cast |
| 488 } // namespace media | 533 } // namespace media |
| OLD | NEW |