Index: media/cast/sender/h264_vt_encoder.cc |
diff --git a/media/cast/sender/h264_vt_encoder.cc b/media/cast/sender/h264_vt_encoder.cc |
index 33923488c51daa96b99847893ea713204588837c..d740b8026d1f463bd36346b801f00e16bbb83a68 100644 |
--- a/media/cast/sender/h264_vt_encoder.cc |
+++ b/media/cast/sender/h264_vt_encoder.cc |
@@ -11,6 +11,7 @@ |
#include "base/bind_helpers.h" |
#include "base/location.h" |
#include "base/logging.h" |
+#include "base/macros.h" |
#include "media/base/mac/corevideo_glue.h" |
#include "media/base/mac/video_frame_mac.h" |
#include "media/cast/sender/video_frame_factory.h" |
@@ -43,6 +44,21 @@ base::ScopedCFTypeRef<CFDictionaryRef> DictionaryWithKeyValue(CFTypeRef key, |
&kCFTypeDictionaryValueCallBacks)); |
} |
+base::ScopedCFTypeRef<CFArrayRef> ArrayWithIntegers(const std::vector<int>& v) { |
+ std::vector<CFNumberRef> numbers; |
+ numbers.reserve(v.size()); |
+ for (const int i : v) { |
+ numbers.push_back(CFNumberCreate(nullptr, kCFNumberSInt32Type, &i)); |
+ } |
+ base::ScopedCFTypeRef<CFArrayRef> array(CFArrayCreate( |
+ kCFAllocatorDefault, reinterpret_cast<const void**>(&numbers[0]), |
+ numbers.size(), &kCFTypeArrayCallBacks)); |
+ for (CFNumberRef number : numbers) { |
+ CFRelease(number); |
+ } |
+ return array; |
+} |
+ |
template <typename NalSizeType> |
void CopyNalsToAnnexB(char* avcc_buffer, |
const size_t avcc_size, |
@@ -257,11 +273,20 @@ bool H264VideoToolboxEncoder::Initialize( |
kCFBooleanTrue); |
#endif |
+ // Certain encoders prefer kCVPixelFormatType_422YpCbCr8, which is not |
+ // supported through VideoFrame. We can force 420 formats to be used instead. |
+ const int formats[] = { |
+ kCVPixelFormatType_420YpCbCr8Planar, |
+ CoreVideoGlue::kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange}; |
+ base::ScopedCFTypeRef<CFArrayRef> formats_array = ArrayWithIntegers( |
+ std::vector<int>(formats, formats + arraysize(formats))); |
+ base::ScopedCFTypeRef<CFDictionaryRef> buffer_attributes = |
+ DictionaryWithKeyValue(kCVPixelBufferPixelFormatTypeKey, formats_array); |
+ |
VTCompressionSessionRef session; |
OSStatus status = videotoolbox_glue_->VTCompressionSessionCreate( |
kCFAllocatorDefault, video_config.width, video_config.height, |
- CoreMediaGlue::kCMVideoCodecType_H264, encoder_spec, |
- nullptr /* sourceImageBufferAttributes */, |
+ CoreMediaGlue::kCMVideoCodecType_H264, encoder_spec, buffer_attributes, |
nullptr /* compressedDataAllocator */, |
&H264VideoToolboxEncoder::CompressionCallback, |
reinterpret_cast<void*>(this), &session); |
@@ -309,6 +334,11 @@ void H264VideoToolboxEncoder::ConfigureSession( |
SetSessionProperty( |
videotoolbox_glue_->kVTCompressionPropertyKey_YCbCrMatrix(), |
kCVImageBufferYCbCrMatrix_ITU_R_709_2); |
+ if (video_config.max_number_of_video_buffers_used > 0) { |
+ SetSessionProperty( |
+ videotoolbox_glue_->kVTCompressionPropertyKey_MaxFrameDelayCount(), |
+ video_config.max_number_of_video_buffers_used); |
miu
2015/01/21 23:24:27
VideoSenderConfig::max_number_of_video_buffers_use
|
+ } |
} |
void H264VideoToolboxEncoder::Teardown() { |
@@ -404,6 +434,21 @@ H264VideoToolboxEncoder::CreateVideoFrameFactory() { |
new VideoFrameFactoryCVPixelBufferPoolImpl(pool)); |
} |
+void H264VideoToolboxEncoder::EmitFrames() { |
+ DCHECK(thread_checker_.CalledOnValidThread()); |
+ |
+ if (!compression_session_) { |
+ DLOG(ERROR) << " compression session is null"; |
+ return; |
+ } |
+ |
+ OSStatus status = videotoolbox_glue_->VTCompressionSessionCompleteFrames( |
+ compression_session_, CoreMediaGlue::CMTime{0, 0, 0, 0}); |
+ if (status != noErr) { |
+ DLOG(ERROR) << " VTCompressionSessionCompleteFrames failed: " << status; |
+ } |
+} |
+ |
bool H264VideoToolboxEncoder::SetSessionProperty(CFStringRef key, |
int32_t value) { |
base::ScopedCFTypeRef<CFNumberRef> cfvalue( |