| Index: content/common/gpu/media/vt_video_encode_accelerator_mac.cc
|
| diff --git a/content/common/gpu/media/vt_video_encode_accelerator_mac.cc b/content/common/gpu/media/vt_video_encode_accelerator_mac.cc
|
| deleted file mode 100644
|
| index 71c80ef3a9f1bfb58b4dc8b5f97769409af42fcb..0000000000000000000000000000000000000000
|
| --- a/content/common/gpu/media/vt_video_encode_accelerator_mac.cc
|
| +++ /dev/null
|
| @@ -1,552 +0,0 @@
|
| -// Copyright 2016 The Chromium Authors. All rights reserved.
|
| -// Use of this source code is governed by a BSD-style license that can be
|
| -// found in the LICENSE file.
|
| -
|
| -#include "content/common/gpu/media/vt_video_encode_accelerator_mac.h"
|
| -
|
| -#include "base/thread_task_runner_handle.h"
|
| -#include "media/base/mac/coremedia_glue.h"
|
| -#include "media/base/mac/corevideo_glue.h"
|
| -#include "media/base/mac/video_frame_mac.h"
|
| -
|
| -namespace content {
|
| -
|
| -namespace {
|
| -
|
| -// TODO(emircan): Check if we can find the actual system capabilities via
|
| -// creating VTCompressionSessions with varying requirements.
|
| -// See crbug.com/584784.
|
| -const size_t kBitsPerByte = 8;
|
| -const size_t kDefaultResolutionWidth = 640;
|
| -const size_t kDefaultResolutionHeight = 480;
|
| -const size_t kMaxFrameRateNumerator = 30;
|
| -const size_t kMaxFrameRateDenominator = 1;
|
| -const size_t kMaxResolutionWidth = 4096;
|
| -const size_t kMaxResolutionHeight = 2160;
|
| -const size_t kNumInputBuffers = 3;
|
| -
|
| -} // namespace
|
| -
|
| -struct VTVideoEncodeAccelerator::InProgressFrameEncode {
|
| - InProgressFrameEncode(base::TimeDelta rtp_timestamp,
|
| - base::TimeTicks ref_time)
|
| - : timestamp(rtp_timestamp), reference_time(ref_time) {}
|
| - const base::TimeDelta timestamp;
|
| - const base::TimeTicks reference_time;
|
| -
|
| - private:
|
| - DISALLOW_IMPLICIT_CONSTRUCTORS(InProgressFrameEncode);
|
| -};
|
| -
|
| -struct VTVideoEncodeAccelerator::EncodeOutput {
|
| - EncodeOutput(VTEncodeInfoFlags info_flags, CMSampleBufferRef sbuf)
|
| - : info(info_flags), sample_buffer(sbuf, base::scoped_policy::RETAIN) {}
|
| - const VTEncodeInfoFlags info;
|
| - const base::ScopedCFTypeRef<CMSampleBufferRef> sample_buffer;
|
| -
|
| - private:
|
| - DISALLOW_IMPLICIT_CONSTRUCTORS(EncodeOutput);
|
| -};
|
| -
|
| -struct VTVideoEncodeAccelerator::BitstreamBufferRef {
|
| - BitstreamBufferRef(int32_t id,
|
| - scoped_ptr<base::SharedMemory> shm,
|
| - size_t size)
|
| - : id(id), shm(std::move(shm)), size(size) {}
|
| - const int32_t id;
|
| - const scoped_ptr<base::SharedMemory> shm;
|
| - const size_t size;
|
| -
|
| - private:
|
| - DISALLOW_IMPLICIT_CONSTRUCTORS(BitstreamBufferRef);
|
| -};
|
| -
|
| -VTVideoEncodeAccelerator::VTVideoEncodeAccelerator()
|
| - : client_task_runner_(base::ThreadTaskRunnerHandle::Get()),
|
| - encoder_thread_("VTEncoderThread"),
|
| - encoder_task_weak_factory_(this) {
|
| - encoder_weak_ptr_ = encoder_task_weak_factory_.GetWeakPtr();
|
| -}
|
| -
|
| -VTVideoEncodeAccelerator::~VTVideoEncodeAccelerator() {
|
| - DVLOG(3) << __FUNCTION__;
|
| - DCHECK(thread_checker_.CalledOnValidThread());
|
| -
|
| - Destroy();
|
| - DCHECK(!encoder_thread_.IsRunning());
|
| - DCHECK(!encoder_task_weak_factory_.HasWeakPtrs());
|
| -}
|
| -
|
| -media::VideoEncodeAccelerator::SupportedProfiles
|
| -VTVideoEncodeAccelerator::GetSupportedProfiles() {
|
| - DVLOG(3) << __FUNCTION__;
|
| - DCHECK(thread_checker_.CalledOnValidThread());
|
| -
|
| - SupportedProfiles profiles;
|
| - // Check if HW encoder is supported initially.
|
| - videotoolbox_glue_ = VideoToolboxGlue::Get();
|
| - if (!videotoolbox_glue_) {
|
| - DLOG(ERROR) << "Failed creating VideoToolbox glue.";
|
| - return profiles;
|
| - }
|
| - const bool rv = CreateCompressionSession(
|
| - media::video_toolbox::DictionaryWithKeysAndValues(nullptr, nullptr, 0),
|
| - gfx::Size(kDefaultResolutionWidth, kDefaultResolutionHeight), true);
|
| - DestroyCompressionSession();
|
| - if (!rv) {
|
| - VLOG(1)
|
| - << "Hardware encode acceleration is not available on this platform.";
|
| - return profiles;
|
| - }
|
| -
|
| - SupportedProfile profile;
|
| - profile.profile = media::H264PROFILE_BASELINE;
|
| - profile.max_framerate_numerator = kMaxFrameRateNumerator;
|
| - profile.max_framerate_denominator = kMaxFrameRateDenominator;
|
| - profile.max_resolution = gfx::Size(kMaxResolutionWidth, kMaxResolutionHeight);
|
| - profiles.push_back(profile);
|
| - return profiles;
|
| -}
|
| -
|
| -bool VTVideoEncodeAccelerator::Initialize(
|
| - media::VideoPixelFormat format,
|
| - const gfx::Size& input_visible_size,
|
| - media::VideoCodecProfile output_profile,
|
| - uint32_t initial_bitrate,
|
| - Client* client) {
|
| - DVLOG(3) << __FUNCTION__
|
| - << ": input_format=" << media::VideoPixelFormatToString(format)
|
| - << ", input_visible_size=" << input_visible_size.ToString()
|
| - << ", output_profile=" << output_profile
|
| - << ", initial_bitrate=" << initial_bitrate;
|
| - DCHECK(thread_checker_.CalledOnValidThread());
|
| - DCHECK(client);
|
| -
|
| - if (media::PIXEL_FORMAT_I420 != format) {
|
| - DLOG(ERROR) << "Input format not supported= "
|
| - << media::VideoPixelFormatToString(format);
|
| - return false;
|
| - }
|
| - if (media::H264PROFILE_BASELINE != output_profile) {
|
| - DLOG(ERROR) << "Output profile not supported= "
|
| - << output_profile;
|
| - return false;
|
| - }
|
| -
|
| - videotoolbox_glue_ = VideoToolboxGlue::Get();
|
| - if (!videotoolbox_glue_) {
|
| - DLOG(ERROR) << "Failed creating VideoToolbox glue.";
|
| - return false;
|
| - }
|
| -
|
| - client_ptr_factory_.reset(new base::WeakPtrFactory<Client>(client));
|
| - client_ = client_ptr_factory_->GetWeakPtr();
|
| - input_visible_size_ = input_visible_size;
|
| - frame_rate_ = kMaxFrameRateNumerator / kMaxFrameRateDenominator;
|
| - target_bitrate_ = initial_bitrate;
|
| - bitstream_buffer_size_ = input_visible_size.GetArea();
|
| -
|
| - if (!encoder_thread_.Start()) {
|
| - DLOG(ERROR) << "Failed spawning encoder thread.";
|
| - return false;
|
| - }
|
| - encoder_thread_task_runner_ = encoder_thread_.task_runner();
|
| -
|
| - if (!ResetCompressionSession()) {
|
| - DLOG(ERROR) << "Failed creating compression session.";
|
| - return false;
|
| - }
|
| -
|
| - client_task_runner_->PostTask(
|
| - FROM_HERE,
|
| - base::Bind(&Client::RequireBitstreamBuffers, client_, kNumInputBuffers,
|
| - input_visible_size_, bitstream_buffer_size_));
|
| - return true;
|
| -}
|
| -
|
| -void VTVideoEncodeAccelerator::Encode(
|
| - const scoped_refptr<media::VideoFrame>& frame,
|
| - bool force_keyframe) {
|
| - DVLOG(3) << __FUNCTION__;
|
| - DCHECK(thread_checker_.CalledOnValidThread());
|
| -
|
| - encoder_thread_task_runner_->PostTask(
|
| - FROM_HERE, base::Bind(&VTVideoEncodeAccelerator::EncodeTask,
|
| - base::Unretained(this), frame, force_keyframe));
|
| -}
|
| -
|
| -void VTVideoEncodeAccelerator::UseOutputBitstreamBuffer(
|
| - const media::BitstreamBuffer& buffer) {
|
| - DVLOG(3) << __FUNCTION__ << ": buffer size=" << buffer.size();
|
| - DCHECK(thread_checker_.CalledOnValidThread());
|
| -
|
| - if (buffer.size() < bitstream_buffer_size_) {
|
| - DLOG(ERROR) << "Output BitstreamBuffer isn't big enough: " << buffer.size()
|
| - << " vs. " << bitstream_buffer_size_;
|
| - client_->NotifyError(kInvalidArgumentError);
|
| - return;
|
| - }
|
| -
|
| - scoped_ptr<base::SharedMemory> shm(
|
| - new base::SharedMemory(buffer.handle(), false));
|
| - if (!shm->Map(buffer.size())) {
|
| - DLOG(ERROR) << "Failed mapping shared memory.";
|
| - client_->NotifyError(kPlatformFailureError);
|
| - return;
|
| - }
|
| -
|
| - scoped_ptr<BitstreamBufferRef> buffer_ref(
|
| - new BitstreamBufferRef(buffer.id(), std::move(shm), buffer.size()));
|
| -
|
| - encoder_thread_task_runner_->PostTask(
|
| - FROM_HERE,
|
| - base::Bind(&VTVideoEncodeAccelerator::UseOutputBitstreamBufferTask,
|
| - base::Unretained(this), base::Passed(&buffer_ref)));
|
| -}
|
| -
|
| -void VTVideoEncodeAccelerator::RequestEncodingParametersChange(
|
| - uint32_t bitrate,
|
| - uint32_t framerate) {
|
| - DVLOG(3) << __FUNCTION__ << ": bitrate=" << bitrate
|
| - << ": framerate=" << framerate;
|
| - DCHECK(thread_checker_.CalledOnValidThread());
|
| -
|
| - encoder_thread_task_runner_->PostTask(
|
| - FROM_HERE,
|
| - base::Bind(&VTVideoEncodeAccelerator::RequestEncodingParametersChangeTask,
|
| - base::Unretained(this), bitrate, framerate));
|
| -}
|
| -
|
| -void VTVideoEncodeAccelerator::Destroy() {
|
| - DVLOG(3) << __FUNCTION__;
|
| - DCHECK(thread_checker_.CalledOnValidThread());
|
| -
|
| - // Cancel all callbacks.
|
| - client_ptr_factory_.reset();
|
| -
|
| - if (encoder_thread_.IsRunning()) {
|
| - encoder_thread_task_runner_->PostTask(
|
| - FROM_HERE,
|
| - base::Bind(&VTVideoEncodeAccelerator::DestroyTask,
|
| - base::Unretained(this)));
|
| - encoder_thread_.Stop();
|
| - } else {
|
| - DestroyTask();
|
| - }
|
| -}
|
| -
|
| -void VTVideoEncodeAccelerator::EncodeTask(
|
| - const scoped_refptr<media::VideoFrame>& frame,
|
| - bool force_keyframe) {
|
| - DCHECK(encoder_thread_task_runner_->BelongsToCurrentThread());
|
| - DCHECK(compression_session_);
|
| - DCHECK(frame);
|
| -
|
| - // TODO(emircan): See if we can eliminate a copy here by using
|
| - // CVPixelBufferPool for the allocation of incoming VideoFrames.
|
| - base::ScopedCFTypeRef<CVPixelBufferRef> pixel_buffer =
|
| - media::WrapVideoFrameInCVPixelBuffer(*frame);
|
| - base::ScopedCFTypeRef<CFDictionaryRef> frame_props =
|
| - media::video_toolbox::DictionaryWithKeyValue(
|
| - videotoolbox_glue_->kVTEncodeFrameOptionKey_ForceKeyFrame(),
|
| - force_keyframe ? kCFBooleanTrue : kCFBooleanFalse);
|
| -
|
| - base::TimeTicks ref_time;
|
| - if (!frame->metadata()->GetTimeTicks(
|
| - media::VideoFrameMetadata::REFERENCE_TIME, &ref_time)) {
|
| - ref_time = base::TimeTicks::Now();
|
| - }
|
| - auto timestamp_cm = CoreMediaGlue::CMTimeMake(
|
| - frame->timestamp().InMicroseconds(), USEC_PER_SEC);
|
| - // Wrap information we'll need after the frame is encoded in a heap object.
|
| - // We'll get the pointer back from the VideoToolbox completion callback.
|
| - scoped_ptr<InProgressFrameEncode> request(new InProgressFrameEncode(
|
| - frame->timestamp(), ref_time));
|
| -
|
| - // We can pass the ownership of |request| to the encode callback if
|
| - // successful. Otherwise let it fall out of scope.
|
| - OSStatus status = videotoolbox_glue_->VTCompressionSessionEncodeFrame(
|
| - compression_session_, pixel_buffer, timestamp_cm,
|
| - CoreMediaGlue::CMTime{0, 0, 0, 0}, frame_props,
|
| - reinterpret_cast<void*>(request.get()), nullptr);
|
| - if (status != noErr) {
|
| - DLOG(ERROR) << " VTCompressionSessionEncodeFrame failed: " << status;
|
| - NotifyError(kPlatformFailureError);
|
| - } else {
|
| - CHECK(request.release());
|
| - }
|
| -}
|
| -
|
| -void VTVideoEncodeAccelerator::UseOutputBitstreamBufferTask(
|
| - scoped_ptr<BitstreamBufferRef> buffer_ref) {
|
| - DCHECK(encoder_thread_task_runner_->BelongsToCurrentThread());
|
| -
|
| - // If there is already EncodeOutput waiting, copy its output first.
|
| - if (!encoder_output_queue_.empty()) {
|
| - scoped_ptr<VTVideoEncodeAccelerator::EncodeOutput> encode_output =
|
| - std::move(encoder_output_queue_.front());
|
| - encoder_output_queue_.pop_front();
|
| - ReturnBitstreamBuffer(std::move(encode_output), std::move(buffer_ref));
|
| - return;
|
| - }
|
| -
|
| - bitstream_buffer_queue_.push_back(std::move(buffer_ref));
|
| -}
|
| -
|
| -void VTVideoEncodeAccelerator::RequestEncodingParametersChangeTask(
|
| - uint32_t bitrate,
|
| - uint32_t framerate) {
|
| - DCHECK(encoder_thread_task_runner_->BelongsToCurrentThread());
|
| -
|
| - frame_rate_ = framerate > 1 ? framerate : 1;
|
| - target_bitrate_ = bitrate > 1 ? bitrate : 1;
|
| -
|
| - if (!compression_session_) {
|
| - NotifyError(kPlatformFailureError);
|
| - return;
|
| - }
|
| -
|
| - media::video_toolbox::SessionPropertySetter session_property_setter(
|
| - compression_session_, videotoolbox_glue_);
|
| - // TODO(emircan): See crbug.com/425352.
|
| - bool rv = session_property_setter.Set(
|
| - videotoolbox_glue_->kVTCompressionPropertyKey_AverageBitRate(),
|
| - target_bitrate_);
|
| - rv &= session_property_setter.Set(
|
| - videotoolbox_glue_->kVTCompressionPropertyKey_ExpectedFrameRate(),
|
| - frame_rate_);
|
| - rv &= session_property_setter.Set(
|
| - videotoolbox_glue_->kVTCompressionPropertyKey_DataRateLimits(),
|
| - media::video_toolbox::ArrayWithIntegerAndFloat(
|
| - target_bitrate_ / kBitsPerByte, 1.0f));
|
| - DLOG_IF(ERROR, !rv) << "Couldn't change session encoding parameters.";
|
| -}
|
| -
|
| -void VTVideoEncodeAccelerator::DestroyTask() {
|
| - DCHECK(thread_checker_.CalledOnValidThread() ||
|
| - (encoder_thread_.IsRunning() &&
|
| - encoder_thread_task_runner_->BelongsToCurrentThread()));
|
| -
|
| - // Cancel all encoder thread callbacks.
|
| - encoder_task_weak_factory_.InvalidateWeakPtrs();
|
| -
|
| - // This call blocks until all pending frames are flushed out.
|
| - DestroyCompressionSession();
|
| -}
|
| -
|
| -void VTVideoEncodeAccelerator::NotifyError(
|
| - media::VideoEncodeAccelerator::Error error) {
|
| - DCHECK(encoder_thread_task_runner_->BelongsToCurrentThread());
|
| - client_task_runner_->PostTask(
|
| - FROM_HERE, base::Bind(&Client::NotifyError, client_, error));
|
| -}
|
| -
|
| -// static
|
| -void VTVideoEncodeAccelerator::CompressionCallback(void* encoder_opaque,
|
| - void* request_opaque,
|
| - OSStatus status,
|
| - VTEncodeInfoFlags info,
|
| - CMSampleBufferRef sbuf) {
|
| - // This function may be called asynchronously, on a different thread from the
|
| - // one that calls VTCompressionSessionEncodeFrame.
|
| - DVLOG(3) << __FUNCTION__;
|
| -
|
| - auto encoder = reinterpret_cast<VTVideoEncodeAccelerator*>(encoder_opaque);
|
| - DCHECK(encoder);
|
| -
|
| - // Release InProgressFrameEncode, since we don't have support to return
|
| - // timestamps at this point.
|
| - scoped_ptr<InProgressFrameEncode> request(
|
| - reinterpret_cast<InProgressFrameEncode*>(request_opaque));
|
| - request.reset();
|
| -
|
| - // EncodeOutput holds onto CMSampleBufferRef when posting task between
|
| - // threads.
|
| - scoped_ptr<EncodeOutput> encode_output(new EncodeOutput(info, sbuf));
|
| -
|
| - // This method is NOT called on |encoder_thread_|, so we still need to
|
| - // post a task back to it to do work.
|
| - encoder->encoder_thread_task_runner_->PostTask(
|
| - FROM_HERE, base::Bind(&VTVideoEncodeAccelerator::CompressionCallbackTask,
|
| - encoder->encoder_weak_ptr_, status,
|
| - base::Passed(&encode_output)));
|
| -}
|
| -
|
| -void VTVideoEncodeAccelerator::CompressionCallbackTask(
|
| - OSStatus status,
|
| - scoped_ptr<EncodeOutput> encode_output) {
|
| - DCHECK(encoder_thread_task_runner_->BelongsToCurrentThread());
|
| -
|
| - if (status != noErr) {
|
| - DLOG(ERROR) << " encode failed: " << status;
|
| - NotifyError(kPlatformFailureError);
|
| - return;
|
| - }
|
| -
|
| - // If there isn't any BitstreamBuffer to copy into, add it to a queue for
|
| - // later use.
|
| - if (bitstream_buffer_queue_.empty()) {
|
| - encoder_output_queue_.push_back(std::move(encode_output));
|
| - return;
|
| - }
|
| -
|
| - scoped_ptr<VTVideoEncodeAccelerator::BitstreamBufferRef> buffer_ref =
|
| - std::move(bitstream_buffer_queue_.front());
|
| - bitstream_buffer_queue_.pop_front();
|
| - ReturnBitstreamBuffer(std::move(encode_output), std::move(buffer_ref));
|
| -}
|
| -
|
| -void VTVideoEncodeAccelerator::ReturnBitstreamBuffer(
|
| - scoped_ptr<EncodeOutput> encode_output,
|
| - scoped_ptr<VTVideoEncodeAccelerator::BitstreamBufferRef> buffer_ref) {
|
| - DVLOG(3) << __FUNCTION__;
|
| - DCHECK(encoder_thread_task_runner_->BelongsToCurrentThread());
|
| -
|
| - if (encode_output->info & VideoToolboxGlue::kVTEncodeInfo_FrameDropped) {
|
| - DVLOG(2) << " frame dropped";
|
| - client_task_runner_->PostTask(
|
| - FROM_HERE, base::Bind(&Client::BitstreamBufferReady, client_,
|
| - buffer_ref->id, 0, false));
|
| - return;
|
| - }
|
| -
|
| - auto sample_attachments = static_cast<CFDictionaryRef>(CFArrayGetValueAtIndex(
|
| - CoreMediaGlue::CMSampleBufferGetSampleAttachmentsArray(
|
| - encode_output->sample_buffer.get(), true),
|
| - 0));
|
| - const bool keyframe =
|
| - !CFDictionaryContainsKey(sample_attachments,
|
| - CoreMediaGlue::kCMSampleAttachmentKey_NotSync());
|
| -
|
| - size_t used_buffer_size = 0;
|
| - const bool copy_rv = media::video_toolbox::CopySampleBufferToAnnexBBuffer(
|
| - encode_output->sample_buffer.get(), keyframe, buffer_ref->size,
|
| - reinterpret_cast<char*>(buffer_ref->shm->memory()), &used_buffer_size);
|
| - if (!copy_rv) {
|
| - DLOG(ERROR) << "Cannot copy output from SampleBuffer to AnnexBBuffer.";
|
| - used_buffer_size = 0;
|
| - }
|
| -
|
| - client_task_runner_->PostTask(
|
| - FROM_HERE, base::Bind(&Client::BitstreamBufferReady, client_,
|
| - buffer_ref->id, used_buffer_size, keyframe));
|
| -}
|
| -
|
| -bool VTVideoEncodeAccelerator::ResetCompressionSession() {
|
| - DCHECK(thread_checker_.CalledOnValidThread());
|
| -
|
| - DestroyCompressionSession();
|
| -
|
| - CFTypeRef attributes_keys[] = {
|
| - kCVPixelBufferOpenGLCompatibilityKey,
|
| - kCVPixelBufferIOSurfacePropertiesKey,
|
| - kCVPixelBufferPixelFormatTypeKey
|
| - };
|
| - const int format[] = {
|
| - CoreVideoGlue::kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange};
|
| - CFTypeRef attributes_values[] = {
|
| - kCFBooleanTrue,
|
| - media::video_toolbox::DictionaryWithKeysAndValues(nullptr, nullptr, 0)
|
| - .release(),
|
| - media::video_toolbox::ArrayWithIntegers(format, arraysize(format))
|
| - .release()};
|
| - const base::ScopedCFTypeRef<CFDictionaryRef> attributes =
|
| - media::video_toolbox::DictionaryWithKeysAndValues(
|
| - attributes_keys, attributes_values, arraysize(attributes_keys));
|
| - for (auto& v : attributes_values)
|
| - CFRelease(v);
|
| -
|
| - bool session_rv =
|
| - CreateCompressionSession(attributes, input_visible_size_, false);
|
| - if (!session_rv) {
|
| - DestroyCompressionSession();
|
| - return false;
|
| - }
|
| -
|
| - const bool configure_rv = ConfigureCompressionSession();
|
| - if (configure_rv)
|
| - RequestEncodingParametersChange(target_bitrate_, frame_rate_);
|
| - return configure_rv;
|
| -}
|
| -
|
| -bool VTVideoEncodeAccelerator::CreateCompressionSession(
|
| - base::ScopedCFTypeRef<CFDictionaryRef> attributes,
|
| - const gfx::Size& input_size,
|
| - bool require_hw_encoding) {
|
| - DCHECK(thread_checker_.CalledOnValidThread());
|
| -
|
| - std::vector<CFTypeRef> encoder_keys;
|
| - std::vector<CFTypeRef> encoder_values;
|
| - if (require_hw_encoding) {
|
| - encoder_keys.push_back(videotoolbox_glue_
|
| - ->kVTVideoEncoderSpecification_RequireHardwareAcceleratedVideoEncoder());
|
| - encoder_values.push_back(kCFBooleanTrue);
|
| - } else {
|
| - encoder_keys.push_back(videotoolbox_glue_
|
| - ->kVTVideoEncoderSpecification_EnableHardwareAcceleratedVideoEncoder());
|
| - encoder_values.push_back(kCFBooleanTrue);
|
| - }
|
| - base::ScopedCFTypeRef<CFDictionaryRef> encoder_spec =
|
| - media::video_toolbox::DictionaryWithKeysAndValues(
|
| - encoder_keys.data(), encoder_values.data(), encoder_keys.size());
|
| -
|
| - // Create the compression session.
|
| - // Note that the encoder object is given to the compression session as the
|
| - // callback context using a raw pointer. The C API does not allow us to use a
|
| - // smart pointer, nor is this encoder ref counted. However, this is still
|
| - // safe, because we 1) we own the compression session and 2) we tear it down
|
| - // safely. When destructing the encoder, the compression session is flushed
|
| - // and invalidated. Internally, VideoToolbox will join all of its threads
|
| - // before returning to the client. Therefore, when control returns to us, we
|
| - // are guaranteed that the output callback will not execute again.
|
| - OSStatus status = videotoolbox_glue_->VTCompressionSessionCreate(
|
| - kCFAllocatorDefault,
|
| - input_size.width(),
|
| - input_size.height(),
|
| - CoreMediaGlue::kCMVideoCodecType_H264,
|
| - encoder_spec,
|
| - attributes,
|
| - nullptr /* compressedDataAllocator */,
|
| - &VTVideoEncodeAccelerator::CompressionCallback,
|
| - reinterpret_cast<void*>(this),
|
| - compression_session_.InitializeInto());
|
| - if (status != noErr) {
|
| - DLOG(ERROR) << " VTCompressionSessionCreate failed: " << status;
|
| - return false;
|
| - }
|
| - DVLOG(3) << " VTCompressionSession created with HW encode: "
|
| - << require_hw_encoding << ", input size=" << input_size.ToString();
|
| - return true;
|
| -}
|
| -
|
| -bool VTVideoEncodeAccelerator::ConfigureCompressionSession() {
|
| - DCHECK(thread_checker_.CalledOnValidThread());
|
| - DCHECK(compression_session_);
|
| -
|
| - media::video_toolbox::SessionPropertySetter session_property_setter(
|
| - compression_session_, videotoolbox_glue_);
|
| - bool rv = true;
|
| - rv &= session_property_setter.Set(
|
| - videotoolbox_glue_->kVTCompressionPropertyKey_ProfileLevel(),
|
| - videotoolbox_glue_->kVTProfileLevel_H264_Baseline_AutoLevel());
|
| - rv &= session_property_setter.Set(
|
| - videotoolbox_glue_->kVTCompressionPropertyKey_RealTime(), true);
|
| - rv &= session_property_setter.Set(
|
| - videotoolbox_glue_->kVTCompressionPropertyKey_AllowFrameReordering(),
|
| - false);
|
| - DLOG_IF(ERROR, !rv) << " Setting session property failed.";
|
| - return rv;
|
| -}
|
| -
|
| -void VTVideoEncodeAccelerator::DestroyCompressionSession() {
|
| - DCHECK(thread_checker_.CalledOnValidThread() ||
|
| - (encoder_thread_.IsRunning() &&
|
| - encoder_thread_task_runner_->BelongsToCurrentThread()));
|
| -
|
| - if (compression_session_) {
|
| - videotoolbox_glue_->VTCompressionSessionInvalidate(compression_session_);
|
| - compression_session_.reset();
|
| - }
|
| -}
|
| -
|
| -} // namespace content
|
|
|