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[] = { | |
miu
2015/01/22 00:01:22
Wow. This is all a bit heavy-weight to pass in an
| |
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 204 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
479 CopySampleBufferToAnnexBBuffer(sbuf, &encoded_frame->data, keyframe); | 504 CopySampleBufferToAnnexBBuffer(sbuf, &encoded_frame->data, keyframe); |
480 | 505 |
481 encoder->cast_environment_->PostTask( | 506 encoder->cast_environment_->PostTask( |
482 CastEnvironment::MAIN, FROM_HERE, | 507 CastEnvironment::MAIN, FROM_HERE, |
483 base::Bind(request->frame_encoded_callback, | 508 base::Bind(request->frame_encoded_callback, |
484 base::Passed(&encoded_frame))); | 509 base::Passed(&encoded_frame))); |
485 } | 510 } |
486 | 511 |
487 } // namespace cast | 512 } // namespace cast |
488 } // namespace media | 513 } // namespace media |
OLD | NEW |