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

Side by Side Diff: content/common/gpu/media/vt_video_encode_accelerator_mac.cc

Issue 1939683002: Test X11 header pollution (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 4 years, 7 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 unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright 2016 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "content/common/gpu/media/vt_video_encode_accelerator_mac.h"
6
7 #include <memory>
8
9 #include "base/thread_task_runner_handle.h"
10 #include "media/base/mac/coremedia_glue.h"
11 #include "media/base/mac/corevideo_glue.h"
12 #include "media/base/mac/video_frame_mac.h"
13
14 namespace content {
15
16 namespace {
17
18 // TODO(emircan): Check if we can find the actual system capabilities via
19 // creating VTCompressionSessions with varying requirements.
20 // See crbug.com/584784.
21 const size_t kBitsPerByte = 8;
22 const size_t kDefaultResolutionWidth = 640;
23 const size_t kDefaultResolutionHeight = 480;
24 const size_t kMaxFrameRateNumerator = 30;
25 const size_t kMaxFrameRateDenominator = 1;
26 const size_t kMaxResolutionWidth = 4096;
27 const size_t kMaxResolutionHeight = 2160;
28 const size_t kNumInputBuffers = 3;
29
30 } // namespace
31
32 struct VTVideoEncodeAccelerator::InProgressFrameEncode {
33 InProgressFrameEncode(base::TimeDelta rtp_timestamp,
34 base::TimeTicks ref_time)
35 : timestamp(rtp_timestamp), reference_time(ref_time) {}
36 const base::TimeDelta timestamp;
37 const base::TimeTicks reference_time;
38
39 private:
40 DISALLOW_IMPLICIT_CONSTRUCTORS(InProgressFrameEncode);
41 };
42
43 struct VTVideoEncodeAccelerator::EncodeOutput {
44 EncodeOutput(VTEncodeInfoFlags info_flags, CMSampleBufferRef sbuf)
45 : info(info_flags), sample_buffer(sbuf, base::scoped_policy::RETAIN) {}
46 const VTEncodeInfoFlags info;
47 const base::ScopedCFTypeRef<CMSampleBufferRef> sample_buffer;
48
49 private:
50 DISALLOW_IMPLICIT_CONSTRUCTORS(EncodeOutput);
51 };
52
53 struct VTVideoEncodeAccelerator::BitstreamBufferRef {
54 BitstreamBufferRef(int32_t id,
55 std::unique_ptr<base::SharedMemory> shm,
56 size_t size)
57 : id(id), shm(std::move(shm)), size(size) {}
58 const int32_t id;
59 const std::unique_ptr<base::SharedMemory> shm;
60 const size_t size;
61
62 private:
63 DISALLOW_IMPLICIT_CONSTRUCTORS(BitstreamBufferRef);
64 };
65
66 VTVideoEncodeAccelerator::VTVideoEncodeAccelerator()
67 : client_task_runner_(base::ThreadTaskRunnerHandle::Get()),
68 encoder_thread_("VTEncoderThread"),
69 encoder_task_weak_factory_(this) {
70 encoder_weak_ptr_ = encoder_task_weak_factory_.GetWeakPtr();
71 }
72
73 VTVideoEncodeAccelerator::~VTVideoEncodeAccelerator() {
74 DVLOG(3) << __FUNCTION__;
75 DCHECK(thread_checker_.CalledOnValidThread());
76
77 Destroy();
78 DCHECK(!encoder_thread_.IsRunning());
79 DCHECK(!encoder_task_weak_factory_.HasWeakPtrs());
80 }
81
82 media::VideoEncodeAccelerator::SupportedProfiles
83 VTVideoEncodeAccelerator::GetSupportedProfiles() {
84 DVLOG(3) << __FUNCTION__;
85 DCHECK(thread_checker_.CalledOnValidThread());
86
87 SupportedProfiles profiles;
88 // Check if HW encoder is supported initially.
89 videotoolbox_glue_ = VideoToolboxGlue::Get();
90 if (!videotoolbox_glue_) {
91 DLOG(ERROR) << "Failed creating VideoToolbox glue.";
92 return profiles;
93 }
94 const bool rv = CreateCompressionSession(
95 media::video_toolbox::DictionaryWithKeysAndValues(nullptr, nullptr, 0),
96 gfx::Size(kDefaultResolutionWidth, kDefaultResolutionHeight), true);
97 DestroyCompressionSession();
98 if (!rv) {
99 VLOG(1)
100 << "Hardware encode acceleration is not available on this platform.";
101 return profiles;
102 }
103
104 SupportedProfile profile;
105 profile.profile = media::H264PROFILE_BASELINE;
106 profile.max_framerate_numerator = kMaxFrameRateNumerator;
107 profile.max_framerate_denominator = kMaxFrameRateDenominator;
108 profile.max_resolution = gfx::Size(kMaxResolutionWidth, kMaxResolutionHeight);
109 profiles.push_back(profile);
110 return profiles;
111 }
112
113 bool VTVideoEncodeAccelerator::Initialize(
114 media::VideoPixelFormat format,
115 const gfx::Size& input_visible_size,
116 media::VideoCodecProfile output_profile,
117 uint32_t initial_bitrate,
118 Client* client) {
119 DVLOG(3) << __FUNCTION__
120 << ": input_format=" << media::VideoPixelFormatToString(format)
121 << ", input_visible_size=" << input_visible_size.ToString()
122 << ", output_profile=" << output_profile
123 << ", initial_bitrate=" << initial_bitrate;
124 DCHECK(thread_checker_.CalledOnValidThread());
125 DCHECK(client);
126
127 if (media::PIXEL_FORMAT_I420 != format) {
128 DLOG(ERROR) << "Input format not supported= "
129 << media::VideoPixelFormatToString(format);
130 return false;
131 }
132 if (media::H264PROFILE_BASELINE != output_profile) {
133 DLOG(ERROR) << "Output profile not supported= "
134 << output_profile;
135 return false;
136 }
137
138 videotoolbox_glue_ = VideoToolboxGlue::Get();
139 if (!videotoolbox_glue_) {
140 DLOG(ERROR) << "Failed creating VideoToolbox glue.";
141 return false;
142 }
143
144 client_ptr_factory_.reset(new base::WeakPtrFactory<Client>(client));
145 client_ = client_ptr_factory_->GetWeakPtr();
146 input_visible_size_ = input_visible_size;
147 frame_rate_ = kMaxFrameRateNumerator / kMaxFrameRateDenominator;
148 target_bitrate_ = initial_bitrate;
149 bitstream_buffer_size_ = input_visible_size.GetArea();
150
151 if (!encoder_thread_.Start()) {
152 DLOG(ERROR) << "Failed spawning encoder thread.";
153 return false;
154 }
155 encoder_thread_task_runner_ = encoder_thread_.task_runner();
156
157 if (!ResetCompressionSession()) {
158 DLOG(ERROR) << "Failed creating compression session.";
159 return false;
160 }
161
162 client_task_runner_->PostTask(
163 FROM_HERE,
164 base::Bind(&Client::RequireBitstreamBuffers, client_, kNumInputBuffers,
165 input_visible_size_, bitstream_buffer_size_));
166 return true;
167 }
168
169 void VTVideoEncodeAccelerator::Encode(
170 const scoped_refptr<media::VideoFrame>& frame,
171 bool force_keyframe) {
172 DVLOG(3) << __FUNCTION__;
173 DCHECK(thread_checker_.CalledOnValidThread());
174
175 encoder_thread_task_runner_->PostTask(
176 FROM_HERE, base::Bind(&VTVideoEncodeAccelerator::EncodeTask,
177 base::Unretained(this), frame, force_keyframe));
178 }
179
180 void VTVideoEncodeAccelerator::UseOutputBitstreamBuffer(
181 const media::BitstreamBuffer& buffer) {
182 DVLOG(3) << __FUNCTION__ << ": buffer size=" << buffer.size();
183 DCHECK(thread_checker_.CalledOnValidThread());
184
185 if (buffer.size() < bitstream_buffer_size_) {
186 DLOG(ERROR) << "Output BitstreamBuffer isn't big enough: " << buffer.size()
187 << " vs. " << bitstream_buffer_size_;
188 client_->NotifyError(kInvalidArgumentError);
189 return;
190 }
191
192 std::unique_ptr<base::SharedMemory> shm(
193 new base::SharedMemory(buffer.handle(), false));
194 if (!shm->Map(buffer.size())) {
195 DLOG(ERROR) << "Failed mapping shared memory.";
196 client_->NotifyError(kPlatformFailureError);
197 return;
198 }
199
200 std::unique_ptr<BitstreamBufferRef> buffer_ref(
201 new BitstreamBufferRef(buffer.id(), std::move(shm), buffer.size()));
202
203 encoder_thread_task_runner_->PostTask(
204 FROM_HERE,
205 base::Bind(&VTVideoEncodeAccelerator::UseOutputBitstreamBufferTask,
206 base::Unretained(this), base::Passed(&buffer_ref)));
207 }
208
209 void VTVideoEncodeAccelerator::RequestEncodingParametersChange(
210 uint32_t bitrate,
211 uint32_t framerate) {
212 DVLOG(3) << __FUNCTION__ << ": bitrate=" << bitrate
213 << ": framerate=" << framerate;
214 DCHECK(thread_checker_.CalledOnValidThread());
215
216 encoder_thread_task_runner_->PostTask(
217 FROM_HERE,
218 base::Bind(&VTVideoEncodeAccelerator::RequestEncodingParametersChangeTask,
219 base::Unretained(this), bitrate, framerate));
220 }
221
222 void VTVideoEncodeAccelerator::Destroy() {
223 DVLOG(3) << __FUNCTION__;
224 DCHECK(thread_checker_.CalledOnValidThread());
225
226 // Cancel all callbacks.
227 client_ptr_factory_.reset();
228
229 if (encoder_thread_.IsRunning()) {
230 encoder_thread_task_runner_->PostTask(
231 FROM_HERE,
232 base::Bind(&VTVideoEncodeAccelerator::DestroyTask,
233 base::Unretained(this)));
234 encoder_thread_.Stop();
235 } else {
236 DestroyTask();
237 }
238 }
239
240 void VTVideoEncodeAccelerator::EncodeTask(
241 const scoped_refptr<media::VideoFrame>& frame,
242 bool force_keyframe) {
243 DCHECK(encoder_thread_task_runner_->BelongsToCurrentThread());
244 DCHECK(compression_session_);
245 DCHECK(frame);
246
247 // TODO(emircan): See if we can eliminate a copy here by using
248 // CVPixelBufferPool for the allocation of incoming VideoFrames.
249 base::ScopedCFTypeRef<CVPixelBufferRef> pixel_buffer =
250 media::WrapVideoFrameInCVPixelBuffer(*frame);
251 base::ScopedCFTypeRef<CFDictionaryRef> frame_props =
252 media::video_toolbox::DictionaryWithKeyValue(
253 videotoolbox_glue_->kVTEncodeFrameOptionKey_ForceKeyFrame(),
254 force_keyframe ? kCFBooleanTrue : kCFBooleanFalse);
255
256 base::TimeTicks ref_time;
257 if (!frame->metadata()->GetTimeTicks(
258 media::VideoFrameMetadata::REFERENCE_TIME, &ref_time)) {
259 ref_time = base::TimeTicks::Now();
260 }
261 auto timestamp_cm = CoreMediaGlue::CMTimeMake(
262 frame->timestamp().InMicroseconds(), USEC_PER_SEC);
263 // Wrap information we'll need after the frame is encoded in a heap object.
264 // We'll get the pointer back from the VideoToolbox completion callback.
265 std::unique_ptr<InProgressFrameEncode> request(
266 new InProgressFrameEncode(frame->timestamp(), ref_time));
267
268 // We can pass the ownership of |request| to the encode callback if
269 // successful. Otherwise let it fall out of scope.
270 OSStatus status = videotoolbox_glue_->VTCompressionSessionEncodeFrame(
271 compression_session_, pixel_buffer, timestamp_cm,
272 CoreMediaGlue::CMTime{0, 0, 0, 0}, frame_props,
273 reinterpret_cast<void*>(request.get()), nullptr);
274 if (status != noErr) {
275 DLOG(ERROR) << " VTCompressionSessionEncodeFrame failed: " << status;
276 NotifyError(kPlatformFailureError);
277 } else {
278 CHECK(request.release());
279 }
280 }
281
282 void VTVideoEncodeAccelerator::UseOutputBitstreamBufferTask(
283 std::unique_ptr<BitstreamBufferRef> buffer_ref) {
284 DCHECK(encoder_thread_task_runner_->BelongsToCurrentThread());
285
286 // If there is already EncodeOutput waiting, copy its output first.
287 if (!encoder_output_queue_.empty()) {
288 std::unique_ptr<VTVideoEncodeAccelerator::EncodeOutput> encode_output =
289 std::move(encoder_output_queue_.front());
290 encoder_output_queue_.pop_front();
291 ReturnBitstreamBuffer(std::move(encode_output), std::move(buffer_ref));
292 return;
293 }
294
295 bitstream_buffer_queue_.push_back(std::move(buffer_ref));
296 }
297
298 void VTVideoEncodeAccelerator::RequestEncodingParametersChangeTask(
299 uint32_t bitrate,
300 uint32_t framerate) {
301 DCHECK(encoder_thread_task_runner_->BelongsToCurrentThread());
302
303 frame_rate_ = framerate > 1 ? framerate : 1;
304 target_bitrate_ = bitrate > 1 ? bitrate : 1;
305
306 if (!compression_session_) {
307 NotifyError(kPlatformFailureError);
308 return;
309 }
310
311 media::video_toolbox::SessionPropertySetter session_property_setter(
312 compression_session_, videotoolbox_glue_);
313 // TODO(emircan): See crbug.com/425352.
314 bool rv = session_property_setter.Set(
315 videotoolbox_glue_->kVTCompressionPropertyKey_AverageBitRate(),
316 target_bitrate_);
317 rv &= session_property_setter.Set(
318 videotoolbox_glue_->kVTCompressionPropertyKey_ExpectedFrameRate(),
319 frame_rate_);
320 rv &= session_property_setter.Set(
321 videotoolbox_glue_->kVTCompressionPropertyKey_DataRateLimits(),
322 media::video_toolbox::ArrayWithIntegerAndFloat(
323 target_bitrate_ / kBitsPerByte, 1.0f));
324 DLOG_IF(ERROR, !rv) << "Couldn't change session encoding parameters.";
325 }
326
327 void VTVideoEncodeAccelerator::DestroyTask() {
328 DCHECK(thread_checker_.CalledOnValidThread() ||
329 (encoder_thread_.IsRunning() &&
330 encoder_thread_task_runner_->BelongsToCurrentThread()));
331
332 // Cancel all encoder thread callbacks.
333 encoder_task_weak_factory_.InvalidateWeakPtrs();
334
335 // This call blocks until all pending frames are flushed out.
336 DestroyCompressionSession();
337 }
338
339 void VTVideoEncodeAccelerator::NotifyError(
340 media::VideoEncodeAccelerator::Error error) {
341 DCHECK(encoder_thread_task_runner_->BelongsToCurrentThread());
342 client_task_runner_->PostTask(
343 FROM_HERE, base::Bind(&Client::NotifyError, client_, error));
344 }
345
346 // static
347 void VTVideoEncodeAccelerator::CompressionCallback(void* encoder_opaque,
348 void* request_opaque,
349 OSStatus status,
350 VTEncodeInfoFlags info,
351 CMSampleBufferRef sbuf) {
352 // This function may be called asynchronously, on a different thread from the
353 // one that calls VTCompressionSessionEncodeFrame.
354 DVLOG(3) << __FUNCTION__;
355
356 auto encoder = reinterpret_cast<VTVideoEncodeAccelerator*>(encoder_opaque);
357 DCHECK(encoder);
358
359 // Release InProgressFrameEncode, since we don't have support to return
360 // timestamps at this point.
361 std::unique_ptr<InProgressFrameEncode> request(
362 reinterpret_cast<InProgressFrameEncode*>(request_opaque));
363 request.reset();
364
365 // EncodeOutput holds onto CMSampleBufferRef when posting task between
366 // threads.
367 std::unique_ptr<EncodeOutput> encode_output(new EncodeOutput(info, sbuf));
368
369 // This method is NOT called on |encoder_thread_|, so we still need to
370 // post a task back to it to do work.
371 encoder->encoder_thread_task_runner_->PostTask(
372 FROM_HERE, base::Bind(&VTVideoEncodeAccelerator::CompressionCallbackTask,
373 encoder->encoder_weak_ptr_, status,
374 base::Passed(&encode_output)));
375 }
376
377 void VTVideoEncodeAccelerator::CompressionCallbackTask(
378 OSStatus status,
379 std::unique_ptr<EncodeOutput> encode_output) {
380 DCHECK(encoder_thread_task_runner_->BelongsToCurrentThread());
381
382 if (status != noErr) {
383 DLOG(ERROR) << " encode failed: " << status;
384 NotifyError(kPlatformFailureError);
385 return;
386 }
387
388 // If there isn't any BitstreamBuffer to copy into, add it to a queue for
389 // later use.
390 if (bitstream_buffer_queue_.empty()) {
391 encoder_output_queue_.push_back(std::move(encode_output));
392 return;
393 }
394
395 std::unique_ptr<VTVideoEncodeAccelerator::BitstreamBufferRef> buffer_ref =
396 std::move(bitstream_buffer_queue_.front());
397 bitstream_buffer_queue_.pop_front();
398 ReturnBitstreamBuffer(std::move(encode_output), std::move(buffer_ref));
399 }
400
401 void VTVideoEncodeAccelerator::ReturnBitstreamBuffer(
402 std::unique_ptr<EncodeOutput> encode_output,
403 std::unique_ptr<VTVideoEncodeAccelerator::BitstreamBufferRef> buffer_ref) {
404 DVLOG(3) << __FUNCTION__;
405 DCHECK(encoder_thread_task_runner_->BelongsToCurrentThread());
406
407 if (encode_output->info & VideoToolboxGlue::kVTEncodeInfo_FrameDropped) {
408 DVLOG(2) << " frame dropped";
409 client_task_runner_->PostTask(
410 FROM_HERE, base::Bind(&Client::BitstreamBufferReady, client_,
411 buffer_ref->id, 0, false));
412 return;
413 }
414
415 auto sample_attachments = static_cast<CFDictionaryRef>(CFArrayGetValueAtIndex(
416 CoreMediaGlue::CMSampleBufferGetSampleAttachmentsArray(
417 encode_output->sample_buffer.get(), true),
418 0));
419 const bool keyframe =
420 !CFDictionaryContainsKey(sample_attachments,
421 CoreMediaGlue::kCMSampleAttachmentKey_NotSync());
422
423 size_t used_buffer_size = 0;
424 const bool copy_rv = media::video_toolbox::CopySampleBufferToAnnexBBuffer(
425 encode_output->sample_buffer.get(), keyframe, buffer_ref->size,
426 reinterpret_cast<char*>(buffer_ref->shm->memory()), &used_buffer_size);
427 if (!copy_rv) {
428 DLOG(ERROR) << "Cannot copy output from SampleBuffer to AnnexBBuffer.";
429 used_buffer_size = 0;
430 }
431
432 client_task_runner_->PostTask(
433 FROM_HERE, base::Bind(&Client::BitstreamBufferReady, client_,
434 buffer_ref->id, used_buffer_size, keyframe));
435 }
436
437 bool VTVideoEncodeAccelerator::ResetCompressionSession() {
438 DCHECK(thread_checker_.CalledOnValidThread());
439
440 DestroyCompressionSession();
441
442 CFTypeRef attributes_keys[] = {
443 kCVPixelBufferOpenGLCompatibilityKey,
444 kCVPixelBufferIOSurfacePropertiesKey,
445 kCVPixelBufferPixelFormatTypeKey
446 };
447 const int format[] = {
448 CoreVideoGlue::kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange};
449 CFTypeRef attributes_values[] = {
450 kCFBooleanTrue,
451 media::video_toolbox::DictionaryWithKeysAndValues(nullptr, nullptr, 0)
452 .release(),
453 media::video_toolbox::ArrayWithIntegers(format, arraysize(format))
454 .release()};
455 const base::ScopedCFTypeRef<CFDictionaryRef> attributes =
456 media::video_toolbox::DictionaryWithKeysAndValues(
457 attributes_keys, attributes_values, arraysize(attributes_keys));
458 for (auto& v : attributes_values)
459 CFRelease(v);
460
461 bool session_rv =
462 CreateCompressionSession(attributes, input_visible_size_, false);
463 if (!session_rv) {
464 DestroyCompressionSession();
465 return false;
466 }
467
468 const bool configure_rv = ConfigureCompressionSession();
469 if (configure_rv)
470 RequestEncodingParametersChange(target_bitrate_, frame_rate_);
471 return configure_rv;
472 }
473
474 bool VTVideoEncodeAccelerator::CreateCompressionSession(
475 base::ScopedCFTypeRef<CFDictionaryRef> attributes,
476 const gfx::Size& input_size,
477 bool require_hw_encoding) {
478 DCHECK(thread_checker_.CalledOnValidThread());
479
480 std::vector<CFTypeRef> encoder_keys;
481 std::vector<CFTypeRef> encoder_values;
482 if (require_hw_encoding) {
483 encoder_keys.push_back(videotoolbox_glue_
484 ->kVTVideoEncoderSpecification_RequireHardwareAcceleratedVideoEncoder());
485 encoder_values.push_back(kCFBooleanTrue);
486 } else {
487 encoder_keys.push_back(videotoolbox_glue_
488 ->kVTVideoEncoderSpecification_EnableHardwareAcceleratedVideoEncoder());
489 encoder_values.push_back(kCFBooleanTrue);
490 }
491 base::ScopedCFTypeRef<CFDictionaryRef> encoder_spec =
492 media::video_toolbox::DictionaryWithKeysAndValues(
493 encoder_keys.data(), encoder_values.data(), encoder_keys.size());
494
495 // Create the compression session.
496 // Note that the encoder object is given to the compression session as the
497 // callback context using a raw pointer. The C API does not allow us to use a
498 // smart pointer, nor is this encoder ref counted. However, this is still
499 // safe, because we 1) we own the compression session and 2) we tear it down
500 // safely. When destructing the encoder, the compression session is flushed
501 // and invalidated. Internally, VideoToolbox will join all of its threads
502 // before returning to the client. Therefore, when control returns to us, we
503 // are guaranteed that the output callback will not execute again.
504 OSStatus status = videotoolbox_glue_->VTCompressionSessionCreate(
505 kCFAllocatorDefault,
506 input_size.width(),
507 input_size.height(),
508 CoreMediaGlue::kCMVideoCodecType_H264,
509 encoder_spec,
510 attributes,
511 nullptr /* compressedDataAllocator */,
512 &VTVideoEncodeAccelerator::CompressionCallback,
513 reinterpret_cast<void*>(this),
514 compression_session_.InitializeInto());
515 if (status != noErr) {
516 DLOG(ERROR) << " VTCompressionSessionCreate failed: " << status;
517 return false;
518 }
519 DVLOG(3) << " VTCompressionSession created with HW encode: "
520 << require_hw_encoding << ", input size=" << input_size.ToString();
521 return true;
522 }
523
524 bool VTVideoEncodeAccelerator::ConfigureCompressionSession() {
525 DCHECK(thread_checker_.CalledOnValidThread());
526 DCHECK(compression_session_);
527
528 media::video_toolbox::SessionPropertySetter session_property_setter(
529 compression_session_, videotoolbox_glue_);
530 bool rv = true;
531 rv &= session_property_setter.Set(
532 videotoolbox_glue_->kVTCompressionPropertyKey_ProfileLevel(),
533 videotoolbox_glue_->kVTProfileLevel_H264_Baseline_AutoLevel());
534 rv &= session_property_setter.Set(
535 videotoolbox_glue_->kVTCompressionPropertyKey_RealTime(), true);
536 rv &= session_property_setter.Set(
537 videotoolbox_glue_->kVTCompressionPropertyKey_AllowFrameReordering(),
538 false);
539 DLOG_IF(ERROR, !rv) << " Setting session property failed.";
540 return rv;
541 }
542
543 void VTVideoEncodeAccelerator::DestroyCompressionSession() {
544 DCHECK(thread_checker_.CalledOnValidThread() ||
545 (encoder_thread_.IsRunning() &&
546 encoder_thread_task_runner_->BelongsToCurrentThread()));
547
548 if (compression_session_) {
549 videotoolbox_glue_->VTCompressionSessionInvalidate(compression_session_);
550 compression_session_.reset();
551 }
552 }
553
554 } // namespace content
OLDNEW
« no previous file with comments | « content/common/gpu/media/vt_video_encode_accelerator_mac.h ('k') | content/common/sandbox_mac.mm » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698