Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(366)

Unified Diff: media/cast/sender/h264_vt_encoder.cc

Issue 1100643002: [cast] Handle frame size changes directly in the VideoToolbox encoder (v2). (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Set the video frame factory's pool to null before destroying the compression session. Created 5 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « media/cast/sender/h264_vt_encoder.h ('k') | media/cast/sender/h264_vt_encoder_unittest.cc » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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 c8ae82bb37a3f5433b757c9cc7bedb7ff6d88d6f..e109bcfca57f930c57ef0edaf07b61a25b58de0a 100644
--- a/media/cast/sender/h264_vt_encoder.cc
+++ b/media/cast/sender/h264_vt_encoder.cc
@@ -37,16 +37,10 @@ struct InProgressFrameEncode {
frame_encoded_callback(callback) {}
};
-base::ScopedCFTypeRef<CFDictionaryRef> DictionaryWithKeysAndValues(
- CFTypeRef* keys,
- CFTypeRef* values,
- size_t size) {
+base::ScopedCFTypeRef<CFDictionaryRef>
+DictionaryWithKeysAndValues(CFTypeRef* keys, CFTypeRef* values, size_t size) {
return base::ScopedCFTypeRef<CFDictionaryRef>(CFDictionaryCreate(
- kCFAllocatorDefault,
- keys,
- values,
- size,
- &kCFTypeDictionaryKeyCallBacks,
+ kCFAllocatorDefault, keys, values, size, &kCFTypeDictionaryKeyCallBacks,
&kCFTypeDictionaryValueCallBacks));
}
@@ -209,40 +203,107 @@ void CopySampleBufferToAnnexBBuffer(CoreMediaGlue::CMSampleBufferRef sbuf,
}
}
-// Implementation of the VideoFrameFactory interface using |CVPixelBufferPool|.
-class VideoFrameFactoryCVPixelBufferPoolImpl : public VideoFrameFactory {
+} // namespace
+
+class H264VideoToolboxEncoder::VideoFrameFactoryImpl
+ : public base::RefCountedThreadSafe<VideoFrameFactoryImpl>,
+ public VideoFrameFactory {
public:
- VideoFrameFactoryCVPixelBufferPoolImpl(
- const base::ScopedCFTypeRef<CVPixelBufferPoolRef>& pool,
- const gfx::Size& frame_size)
- : pool_(pool),
- frame_size_(frame_size) {}
+ // Type that proxies the VideoFrameFactory interface to this class.
+ class Proxy;
- ~VideoFrameFactoryCVPixelBufferPoolImpl() override {}
+ VideoFrameFactoryImpl(const base::WeakPtr<H264VideoToolboxEncoder>& encoder,
+ const scoped_refptr<CastEnvironment>& cast_environment)
+ : encoder_(encoder), cast_environment_(cast_environment) {}
scoped_refptr<VideoFrame> MaybeCreateFrame(
- const gfx::Size& frame_size, base::TimeDelta timestamp) override {
- if (frame_size != frame_size_)
- return nullptr; // Buffer pool is not a match for requested frame size.
+ const gfx::Size& frame_size,
+ base::TimeDelta timestamp) override {
+ if (frame_size.IsEmpty()) {
+ DVLOG(1) << "Rejecting empty video frame.";
+ return nullptr;
+ }
+
+ base::AutoLock auto_lock(lock_);
+
+ // If the pool size does not match, speculatively reset the encoder to use
+ // the new size and return null. Cache the new frame size right away and
+ // toss away the pixel buffer pool to avoid spurious tasks until the encoder
+ // is done resetting.
+ if (frame_size != pool_frame_size_) {
+ DVLOG(1) << "MaybeCreateFrame: Detected frame size change.";
+ cast_environment_->PostTask(
+ CastEnvironment::MAIN, FROM_HERE,
+ base::Bind(&H264VideoToolboxEncoder::UpdateFrameSize, encoder_,
+ frame_size));
+ pool_frame_size_ = frame_size;
+ pool_.reset();
+ return nullptr;
+ }
+
+ if (!pool_) {
+ DVLOG(1) << "MaybeCreateFrame: No pixel buffer pool.";
+ return nullptr;
+ }
+ // Allocate a pixel buffer from the pool and return a wrapper VideoFrame.
base::ScopedCFTypeRef<CVPixelBufferRef> buffer;
- if (CVPixelBufferPoolCreatePixelBuffer(kCFAllocatorDefault, pool_,
- buffer.InitializeInto()) !=
- kCVReturnSuccess)
- return nullptr; // Buffer pool has run out of pixel buffers.
- DCHECK(buffer);
+ auto status = CVPixelBufferPoolCreatePixelBuffer(kCFAllocatorDefault, pool_,
+ buffer.InitializeInto());
+ if (status != kCVReturnSuccess) {
+ DLOG(ERROR) << "CVPixelBufferPoolCreatePixelBuffer failed: " << status;
+ return nullptr;
+ }
+ DCHECK(buffer);
return VideoFrame::WrapCVPixelBuffer(buffer, timestamp);
}
+ void Update(const base::ScopedCFTypeRef<CVPixelBufferPoolRef>& pool,
+ const gfx::Size& frame_size) {
+ base::AutoLock auto_lock(lock_);
+ pool_ = pool;
+ pool_frame_size_ = frame_size;
+ }
+
private:
- const base::ScopedCFTypeRef<CVPixelBufferPoolRef> pool_;
- const gfx::Size frame_size_;
+ friend class base::RefCountedThreadSafe<VideoFrameFactoryImpl>;
+ ~VideoFrameFactoryImpl() override {}
+
+ base::Lock lock_;
+ base::ScopedCFTypeRef<CVPixelBufferPoolRef> pool_;
+ gfx::Size pool_frame_size_;
+
+ // Weak back reference to the encoder and the cast envrionment so we can
+ // message the encoder when the frame size changes.
+ const base::WeakPtr<H264VideoToolboxEncoder> encoder_;
+ const scoped_refptr<CastEnvironment> cast_environment_;
- DISALLOW_COPY_AND_ASSIGN(VideoFrameFactoryCVPixelBufferPoolImpl);
+ DISALLOW_COPY_AND_ASSIGN(VideoFrameFactoryImpl);
};
-} // namespace
+class H264VideoToolboxEncoder::VideoFrameFactoryImpl::Proxy
+ : public VideoFrameFactory {
+ public:
+ explicit Proxy(
+ const scoped_refptr<VideoFrameFactoryImpl>& video_frame_factory)
+ : video_frame_factory_(video_frame_factory) {
+ DCHECK(video_frame_factory_);
+ }
+
+ scoped_refptr<VideoFrame> MaybeCreateFrame(
+ const gfx::Size& frame_size,
+ base::TimeDelta timestamp) override {
+ return video_frame_factory_->MaybeCreateFrame(frame_size, timestamp);
+ }
+
+ private:
+ ~Proxy() override {}
+
+ const scoped_refptr<VideoFrameFactoryImpl> video_frame_factory_;
+
+ DISALLOW_COPY_AND_ASSIGN(Proxy);
+};
// static
bool H264VideoToolboxEncoder::IsSupported(
@@ -253,48 +314,46 @@ bool H264VideoToolboxEncoder::IsSupported(
H264VideoToolboxEncoder::H264VideoToolboxEncoder(
const scoped_refptr<CastEnvironment>& cast_environment,
const VideoSenderConfig& video_config,
- const gfx::Size& frame_size,
- uint32 first_frame_id,
const StatusChangeCallback& status_change_cb)
: cast_environment_(cast_environment),
videotoolbox_glue_(VideoToolboxGlue::Get()),
- frame_size_(frame_size),
+ video_config_(video_config),
status_change_cb_(status_change_cb),
- next_frame_id_(first_frame_id),
- encode_next_frame_as_keyframe_(false) {
- DCHECK(!frame_size_.IsEmpty());
+ last_frame_id_(kStartFrameId),
+ encode_next_frame_as_keyframe_(false),
+ weak_factory_(this) {
+ DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN));
DCHECK(!status_change_cb_.is_null());
- OperationalStatus operational_status;
- if (video_config.codec == CODEC_VIDEO_H264 && videotoolbox_glue_) {
- operational_status = Initialize(video_config) ?
- STATUS_INITIALIZED : STATUS_INVALID_CONFIGURATION;
- } else {
- operational_status = STATUS_UNSUPPORTED_CODEC;
- }
+ OperationalStatus operational_status =
+ H264VideoToolboxEncoder::IsSupported(video_config)
+ ? STATUS_INITIALIZED
+ : STATUS_UNSUPPORTED_CODEC;
cast_environment_->PostTask(
- CastEnvironment::MAIN,
- FROM_HERE,
+ CastEnvironment::MAIN, FROM_HERE,
base::Bind(status_change_cb_, operational_status));
+
+ if (operational_status == STATUS_INITIALIZED) {
+ video_frame_factory_ =
+ scoped_refptr<VideoFrameFactoryImpl>(new VideoFrameFactoryImpl(
+ weak_factory_.GetWeakPtr(), cast_environment_));
+ }
}
H264VideoToolboxEncoder::~H264VideoToolboxEncoder() {
- Teardown();
+ DestroyCompressionSession();
}
-bool H264VideoToolboxEncoder::Initialize(
- const VideoSenderConfig& video_config) {
+void H264VideoToolboxEncoder::ResetCompressionSession() {
DCHECK(thread_checker_.CalledOnValidThread());
- DCHECK(!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.
+ // Notify that we're resetting the encoder.
+ cast_environment_->PostTask(
+ CastEnvironment::MAIN, FROM_HERE,
+ base::Bind(status_change_cb_, STATUS_CODEC_REINIT_PENDING));
+
+ // Destroy the current session, if any.
+ DestroyCompressionSession();
// On OS X, allow the hardware encoder. Don't require it, it does not support
// all configurations (some of which are used for testing).
@@ -309,30 +368,21 @@ bool H264VideoToolboxEncoder::Initialize(
// 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
- };
+ kCVPixelFormatType_420YpCbCr8Planar,
+ CoreVideoGlue::kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange};
// Keep these attachment settings in-sync with those in ConfigureSession().
- CFTypeRef attachments_keys[] = {
- kCVImageBufferColorPrimariesKey,
- kCVImageBufferTransferFunctionKey,
- kCVImageBufferYCbCrMatrixKey
- };
- CFTypeRef attachments_values[] = {
- kCVImageBufferColorPrimaries_ITU_R_709_2,
- kCVImageBufferTransferFunction_ITU_R_709_2,
- kCVImageBufferYCbCrMatrix_ITU_R_709_2
- };
- CFTypeRef buffer_attributes_keys[] = {
- kCVPixelBufferPixelFormatTypeKey,
- kCVBufferPropagatedAttachmentsKey
- };
+ CFTypeRef attachments_keys[] = {kCVImageBufferColorPrimariesKey,
+ kCVImageBufferTransferFunctionKey,
+ kCVImageBufferYCbCrMatrixKey};
+ CFTypeRef attachments_values[] = {kCVImageBufferColorPrimaries_ITU_R_709_2,
+ kCVImageBufferTransferFunction_ITU_R_709_2,
+ kCVImageBufferYCbCrMatrix_ITU_R_709_2};
+ CFTypeRef buffer_attributes_keys[] = {kCVPixelBufferPixelFormatTypeKey,
+ kCVBufferPropagatedAttachmentsKey};
CFTypeRef buffer_attributes_values[] = {
- ArrayWithIntegers(formats, arraysize(formats)).release(),
- DictionaryWithKeysAndValues(attachments_keys,
- attachments_values,
- arraysize(attachments_keys)).release()
- };
+ ArrayWithIntegers(formats, arraysize(formats)).release(),
+ DictionaryWithKeysAndValues(attachments_keys, attachments_values,
+ arraysize(attachments_keys)).release()};
const base::ScopedCFTypeRef<CFDictionaryRef> buffer_attributes =
DictionaryWithKeysAndValues(buffer_attributes_keys,
buffer_attributes_values,
@@ -340,26 +390,49 @@ bool H264VideoToolboxEncoder::Initialize(
for (auto& v : buffer_attributes_values)
CFRelease(v);
- VTCompressionSessionRef session;
+ // 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, frame_size_.width(), frame_size_.height(),
CoreMediaGlue::kCMVideoCodecType_H264, encoder_spec, buffer_attributes,
nullptr /* compressedDataAllocator */,
&H264VideoToolboxEncoder::CompressionCallback,
- reinterpret_cast<void*>(this), &session);
+ reinterpret_cast<void*>(this), compression_session_.InitializeInto());
if (status != noErr) {
DLOG(ERROR) << " VTCompressionSessionCreate failed: " << status;
- return false;
+ // Notify that reinitialization has failed.
+ cast_environment_->PostTask(
+ CastEnvironment::MAIN, FROM_HERE,
+ base::Bind(status_change_cb_, STATUS_CODEC_INIT_FAILED));
+ return;
}
- compression_session_.reset(session);
- ConfigureSession(video_config);
+ // Configure the session (apply session properties based on the current state
+ // of the encoder, experimental tuning and requirements).
+ ConfigureCompressionSession();
- return true;
+ // Update the video frame factory.
+ base::ScopedCFTypeRef<CVPixelBufferPoolRef> pool(
+ videotoolbox_glue_->VTCompressionSessionGetPixelBufferPool(
+ compression_session_),
+ base::scoped_policy::RETAIN);
+ video_frame_factory_->Update(pool, frame_size_);
+
+ // Notify that reinitialization is done.
+ cast_environment_->PostTask(
+ CastEnvironment::MAIN, FROM_HERE,
+ base::Bind(status_change_cb_, STATUS_INITIALIZED));
}
-void H264VideoToolboxEncoder::ConfigureSession(
- const VideoSenderConfig& video_config) {
+void H264VideoToolboxEncoder::ConfigureCompressionSession() {
SetSessionProperty(
videotoolbox_glue_->kVTCompressionPropertyKey_ProfileLevel(),
videotoolbox_glue_->kVTProfileLevel_H264_Main_AutoLevel());
@@ -378,10 +451,10 @@ void H264VideoToolboxEncoder::ConfigureSession(
// https://crbug.com/425352
SetSessionProperty(
videotoolbox_glue_->kVTCompressionPropertyKey_AverageBitRate(),
- (video_config.min_bitrate + video_config.max_bitrate) / 2);
+ (video_config_.min_bitrate + video_config_.max_bitrate) / 2);
SetSessionProperty(
videotoolbox_glue_->kVTCompressionPropertyKey_ExpectedFrameRate(),
- video_config.max_frame_rate);
+ video_config_.max_frame_rate);
// Keep these attachment settings in-sync with those in Initialize().
SetSessionProperty(
videotoolbox_glue_->kVTCompressionPropertyKey_ColorPrimaries(),
@@ -392,20 +465,31 @@ void H264VideoToolboxEncoder::ConfigureSession(
SetSessionProperty(
videotoolbox_glue_->kVTCompressionPropertyKey_YCbCrMatrix(),
kCVImageBufferYCbCrMatrix_ITU_R_709_2);
- if (video_config.max_number_of_video_buffers_used > 0) {
+ if (video_config_.max_number_of_video_buffers_used > 0) {
SetSessionProperty(
videotoolbox_glue_->kVTCompressionPropertyKey_MaxFrameDelayCount(),
- video_config.max_number_of_video_buffers_used);
+ video_config_.max_number_of_video_buffers_used);
}
}
-void H264VideoToolboxEncoder::Teardown() {
+void H264VideoToolboxEncoder::DestroyCompressionSession() {
DCHECK(thread_checker_.CalledOnValidThread());
// If the compression session exists, invalidate it. This blocks until all
// pending output callbacks have returned and any internal threads have
// joined, ensuring no output callback ever sees a dangling encoder pointer.
+ //
+ // Before destroying the compression session, the video frame factory's pool
+ // is updated to null so that no thread will produce new video frames via the
+ // factory until a new compression session is created. The current frame size
+ // is passed to prevent the video frame factory from posting |UpdateFrameSize|
+ // tasks. Indeed, |DestroyCompressionSession| is either called from
+ // |ResetCompressionSession|, in which case a new pool and frame size will be
+ // set, or from callsites that require that there be no compression session
+ // (ex: the dtor).
if (compression_session_) {
+ video_frame_factory_->Update(
+ base::ScopedCFTypeRef<CVPixelBufferPoolRef>(nullptr), frame_size_);
videotoolbox_glue_->VTCompressionSessionInvalidate(compression_session_);
compression_session_.reset();
}
@@ -418,13 +502,24 @@ bool H264VideoToolboxEncoder::EncodeVideoFrame(
DCHECK(thread_checker_.CalledOnValidThread());
DCHECK(!frame_encoded_callback.is_null());
- if (!compression_session_) {
- DLOG(ERROR) << " compression session is null";
+ // Reject empty video frames.
+ const gfx::Size frame_size = video_frame->visible_rect().size();
+ if (frame_size.IsEmpty()) {
+ DVLOG(1) << "Rejecting empty video frame.";
return false;
}
- if (video_frame->visible_rect().size() != frame_size_)
+ // Handle frame size changes. This will reset the compression session.
+ if (frame_size != frame_size_) {
+ DVLOG(1) << "EncodeVideoFrame: Detected frame size change.";
+ UpdateFrameSize(frame_size);
+ }
+
+ // Need a compression session to continue.
+ if (!compression_session_) {
+ DLOG(ERROR) << "No compression session.";
return false;
+ }
// Wrap the VideoFrame in a CVPixelBuffer. In all cases, no data will be
// copied. If the VideoFrame was created by this encoder's video frame
@@ -434,16 +529,21 @@ bool H264VideoToolboxEncoder::EncodeVideoFrame(
// lifetime is extended for the lifetime of the returned CVPixelBuffer.
auto pixel_buffer = media::WrapVideoFrameInCVPixelBuffer(*video_frame);
if (!pixel_buffer) {
+ DLOG(ERROR) << "WrapVideoFrameInCVPixelBuffer failed.";
return false;
}
+ // Convert the frame timestamp to CMTime.
auto timestamp_cm = CoreMediaGlue::CMTimeMake(
(reference_time - base::TimeTicks()).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(
TimeDeltaToRtpDelta(video_frame->timestamp(), kVideoFrequency),
reference_time, frame_encoded_callback));
+ // Build a suitable frame properties dictionary for keyframes.
base::ScopedCFTypeRef<CFDictionaryRef> frame_props;
if (encode_next_frame_as_keyframe_) {
frame_props = DictionaryWithKeyValue(
@@ -452,32 +552,53 @@ bool H264VideoToolboxEncoder::EncodeVideoFrame(
encode_next_frame_as_keyframe_ = false;
}
- VTEncodeInfoFlags info;
+ // Submit the frame to the compression session. The function returns as soon
+ // as the frame has been enqueued.
OSStatus status = videotoolbox_glue_->VTCompressionSessionEncodeFrame(
compression_session_, pixel_buffer, timestamp_cm,
CoreMediaGlue::CMTime{0, 0, 0, 0}, frame_props,
- reinterpret_cast<void*>(request.release()), &info);
+ reinterpret_cast<void*>(request.release()), nullptr);
if (status != noErr) {
DLOG(ERROR) << " VTCompressionSessionEncodeFrame failed: " << status;
return false;
}
- if ((info & VideoToolboxGlue::kVTEncodeInfo_FrameDropped)) {
- DLOG(ERROR) << " frame dropped";
- return false;
- }
return true;
}
-void H264VideoToolboxEncoder::SetBitRate(int new_bit_rate) {
+void H264VideoToolboxEncoder::UpdateFrameSize(const gfx::Size& size_needed) {
+ DCHECK(thread_checker_.CalledOnValidThread());
+
+ // Our video frame factory posts a task to update the frame size when its
+ // cache of the frame size differs from what the client requested. To avoid
+ // spurious encoder resets, check again here.
+ if (size_needed == frame_size_) {
+ DCHECK(compression_session_);
+ return;
+ }
+
+ VLOG(1) << "Resetting compression session (for frame size change from "
+ << frame_size_.ToString() << " to " << size_needed.ToString() << ").";
+
+ // If there is an existing session, finish every pending frame.
+ if (compression_session_) {
+ EmitFrames();
+ }
+
+ // Store the new frame size.
+ frame_size_ = size_needed;
+
+ // Reset the compression session.
+ ResetCompressionSession();
+}
+
+void H264VideoToolboxEncoder::SetBitRate(int /*new_bit_rate*/) {
DCHECK(thread_checker_.CalledOnValidThread());
// VideoToolbox does not seem to support bitrate reconfiguration.
}
void H264VideoToolboxEncoder::GenerateKeyFrame() {
DCHECK(thread_checker_.CalledOnValidThread());
- DCHECK(compression_session_);
-
encode_next_frame_as_keyframe_ = true;
}
@@ -487,23 +608,15 @@ void H264VideoToolboxEncoder::LatestFrameIdToReference(uint32 /*frame_id*/) {
scoped_ptr<VideoFrameFactory>
H264VideoToolboxEncoder::CreateVideoFrameFactory() {
- if (!videotoolbox_glue_ || !compression_session_)
- return nullptr;
- base::ScopedCFTypeRef<CVPixelBufferPoolRef> pool(
- videotoolbox_glue_->VTCompressionSessionGetPixelBufferPool(
- compression_session_),
- base::scoped_policy::RETAIN);
+ DCHECK(thread_checker_.CalledOnValidThread());
return scoped_ptr<VideoFrameFactory>(
- new VideoFrameFactoryCVPixelBufferPoolImpl(pool, frame_size_));
+ new VideoFrameFactoryImpl::Proxy(video_frame_factory_));
}
void H264VideoToolboxEncoder::EmitFrames() {
DCHECK(thread_checker_.CalledOnValidThread());
-
- if (!compression_session_) {
- DLOG(ERROR) << " compression session is null";
+ if (!compression_session_)
return;
- }
OSStatus status = videotoolbox_glue_->VTCompressionSessionCompleteFrames(
compression_session_, CoreMediaGlue::CMTime{0, 0, 0, 0});
@@ -546,14 +659,13 @@ void H264VideoToolboxEncoder::CompressionCallback(void* encoder_opaque,
if (status != noErr) {
DLOG(ERROR) << " encoding failed: " << status;
encoder->cast_environment_->PostTask(
- CastEnvironment::MAIN,
- FROM_HERE,
+ CastEnvironment::MAIN, FROM_HERE,
base::Bind(encoder->status_change_cb_, STATUS_CODEC_RUNTIME_ERROR));
} else if ((info & VideoToolboxGlue::kVTEncodeInfo_FrameDropped)) {
DVLOG(2) << " frame dropped";
} else {
- auto sample_attachments = static_cast<CFDictionaryRef>(
- CFArrayGetValueAtIndex(
+ auto sample_attachments =
+ static_cast<CFDictionaryRef>(CFArrayGetValueAtIndex(
CoreMediaGlue::CMSampleBufferGetSampleAttachmentsArray(sbuf, true),
0));
@@ -561,14 +673,14 @@ void H264VideoToolboxEncoder::CompressionCallback(void* encoder_opaque,
// keyframe (at least I think, VT documentation is, erm, sparse). Could
// alternatively use kCMSampleAttachmentKey_DependsOnOthers == false.
keyframe = !CFDictionaryContainsKey(
- sample_attachments,
- CoreMediaGlue::kCMSampleAttachmentKey_NotSync());
+ sample_attachments,
+ CoreMediaGlue::kCMSampleAttachmentKey_NotSync());
has_frame_data = true;
}
// Increment the encoder-scoped frame id and assign the new value to this
// frame. VideoToolbox calls the output callback serially, so this is safe.
- const uint32 frame_id = encoder->next_frame_id_++;
+ const uint32 frame_id = ++encoder->last_frame_id_;
scoped_ptr<EncodedFrame> encoded_frame(new EncodedFrame());
encoded_frame->frame_id = frame_id;
@@ -600,89 +712,5 @@ void H264VideoToolboxEncoder::CompressionCallback(void* encoder_opaque,
base::Passed(&encoded_frame)));
}
-// A ref-counted structure that is shared to provide concurrent access to the
-// VideoFrameFactory instance for the current encoder. OnEncoderReplaced() can
-// change |factory| whenever an encoder instance has been replaced, while users
-// of CreateVideoFrameFactory() may attempt to read/use |factory| by any thread
-// at any time.
-struct SizeAdaptableH264VideoToolboxVideoEncoder::FactoryHolder
- : public base::RefCountedThreadSafe<FactoryHolder> {
- base::Lock lock;
- scoped_ptr<VideoFrameFactory> factory;
-
- private:
- friend class base::RefCountedThreadSafe<FactoryHolder>;
- ~FactoryHolder() {}
-};
-
-SizeAdaptableH264VideoToolboxVideoEncoder::
- SizeAdaptableH264VideoToolboxVideoEncoder(
- const scoped_refptr<CastEnvironment>& cast_environment,
- const VideoSenderConfig& video_config,
- const StatusChangeCallback& status_change_cb)
- : SizeAdaptableVideoEncoderBase(cast_environment,
- video_config,
- status_change_cb),
- holder_(new FactoryHolder()) {}
-
-SizeAdaptableH264VideoToolboxVideoEncoder::
- ~SizeAdaptableH264VideoToolboxVideoEncoder() {}
-
-// A proxy allowing SizeAdaptableH264VideoToolboxVideoEncoder to swap out the
-// VideoFrameFactory instance to match one appropriate for the current encoder
-// instance.
-class SizeAdaptableH264VideoToolboxVideoEncoder::VideoFrameFactoryProxy
- : public VideoFrameFactory {
- public:
- explicit VideoFrameFactoryProxy(const scoped_refptr<FactoryHolder>& holder)
- : holder_(holder) {}
-
- ~VideoFrameFactoryProxy() override {}
-
- scoped_refptr<VideoFrame> MaybeCreateFrame(
- const gfx::Size& frame_size, base::TimeDelta timestamp) override {
- base::AutoLock auto_lock(holder_->lock);
- return holder_->factory ?
- holder_->factory->MaybeCreateFrame(frame_size, timestamp) : nullptr;
- }
-
- private:
- const scoped_refptr<FactoryHolder> holder_;
-
- DISALLOW_COPY_AND_ASSIGN(VideoFrameFactoryProxy);
-};
-
-scoped_ptr<VideoFrameFactory>
- SizeAdaptableH264VideoToolboxVideoEncoder::CreateVideoFrameFactory() {
- return scoped_ptr<VideoFrameFactory>(new VideoFrameFactoryProxy(holder_));
-}
-
-scoped_ptr<VideoEncoder>
- SizeAdaptableH264VideoToolboxVideoEncoder::CreateEncoder() {
- return scoped_ptr<VideoEncoder>(new H264VideoToolboxEncoder(
- cast_environment(),
- video_config(),
- frame_size(),
- last_frame_id() + 1,
- CreateEncoderStatusChangeCallback()));
-}
-
-void SizeAdaptableH264VideoToolboxVideoEncoder::OnEncoderReplaced(
- VideoEncoder* replacement_encoder) {
- scoped_ptr<VideoFrameFactory> current_factory(
- replacement_encoder->CreateVideoFrameFactory());
- base::AutoLock auto_lock(holder_->lock);
- holder_->factory = current_factory.Pass();
- SizeAdaptableVideoEncoderBase::OnEncoderReplaced(replacement_encoder);
-}
-
-void SizeAdaptableH264VideoToolboxVideoEncoder::DestroyEncoder() {
- {
- base::AutoLock auto_lock(holder_->lock);
- holder_->factory.reset();
- }
- SizeAdaptableVideoEncoderBase::DestroyEncoder();
-}
-
} // namespace cast
} // namespace media
« no previous file with comments | « media/cast/sender/h264_vt_encoder.h ('k') | media/cast/sender/h264_vt_encoder_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698