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

Unified Diff: content/common/gpu/media/vt_video_decode_accelerator.cc

Issue 374153003: Use PPS/SPS NALUs to initialize a VTDecompressionSession. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Move parsing to decoder thread. Created 6 years, 5 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
Index: content/common/gpu/media/vt_video_decode_accelerator.cc
diff --git a/content/common/gpu/media/vt_video_decode_accelerator.cc b/content/common/gpu/media/vt_video_decode_accelerator.cc
index 59251d20465c7249396029833cf575007046efbd..dd00fde689bb85afa87a3a2a2ee694d4425ee566 100644
--- a/content/common/gpu/media/vt_video_decode_accelerator.cc
+++ b/content/common/gpu/media/vt_video_decode_accelerator.cc
@@ -2,37 +2,224 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#include <CoreVideo/CoreVideo.h>
+#include <OpenGL/CGLIOSurface.h>
+
+#include "base/bind.h"
+#include "base/thread_task_runner_handle.h"
#include "content/common/gpu/media/vt_video_decode_accelerator.h"
+#include "media/filters/h264_parser.h"
+
+using content_common_gpu_media::kModuleVt;
+using content_common_gpu_media::InitializeStubs;
+using content_common_gpu_media::IsVtInitialized;
+using content_common_gpu_media::StubPathMap;
namespace content {
+// Route decoded frame callbacks back into the VTVideoDecodeAccelerator.
+static void OutputThunk(
+ void* decompression_output_refcon,
+ void* source_frame_refcon,
+ OSStatus status,
+ VTDecodeInfoFlags info_flags,
+ CVImageBufferRef image_buffer,
+ CMTime presentation_time_stamp,
+ CMTime presentation_duration) {
+ VTVideoDecodeAccelerator* vda =
+ reinterpret_cast<VTVideoDecodeAccelerator*>(decompression_output_refcon);
+ int32_t* bitstream_id_ptr = reinterpret_cast<int32_t*>(source_frame_refcon);
+ int32_t bitstream_id = *bitstream_id_ptr;
+ delete bitstream_id_ptr;
+ CFRetain(image_buffer);
+ vda->Output(bitstream_id, status, info_flags, image_buffer);
+}
+
VTVideoDecodeAccelerator::VTVideoDecodeAccelerator(CGLContextObj cgl_context)
- : loop_proxy_(base::MessageLoopProxy::current()),
+ : gpu_task_runner_(base::ThreadTaskRunnerHandle::Get()),
cgl_context_(cgl_context),
client_(NULL),
- weak_this_factory_(this) {
+ decoder_thread_("VTDecoderThread"),
+ format_(NULL),
+ session_(NULL),
+ coded_width_(0),
+ coded_height_(0),
+ weak_factory_(this) {
+ callback_.decompressionOutputCallback = OutputThunk;
+ callback_.decompressionOutputRefCon = this;
}
VTVideoDecodeAccelerator::~VTVideoDecodeAccelerator() {
+ // TODO(sandersd): Move these into scoped pointers.
scherkus (not reviewing) 2014/07/09 18:32:48 can we use base/mac/scoped_cftyperef.h now? if so
sandersd (OOO until July 31) 2014/07/09 20:07:11 Done.
+ if (format_)
+ CFRelease(format_);
+ if (session_)
+ CFRelease(session_);
}
bool VTVideoDecodeAccelerator::Initialize(
media::VideoCodecProfile profile,
Client* client) {
DCHECK(CalledOnValidThread());
- DVLOG(2) << __FUNCTION__;
client_ = client;
// Only H.264 is supported.
if (profile < media::H264PROFILE_MIN || profile > media::H264PROFILE_MAX)
return false;
- // Prevent anyone from using VTVideoDecoder for now. http://crbug.com/133828
- return false;
+ // TODO(sandersd): Move VideoToolbox library loading to sandbox startup;
+ // until then, --no-sandbox is required.
+ if (!IsVtInitialized()) {
+ StubPathMap paths;
+ // CoreVideo is also required, but the loader stops after the first
+ // path is loaded. Instead we rely on the transitive dependency from
+ // VideoToolbox to CoreVideo.
+ // TODO(sandersd): Fallback to PrivateFrameworks for VideoToolbox.
+ paths[kModuleVt].push_back(FILE_PATH_LITERAL(
+ "/System/Library/Frameworks/VideoToolbox.framework/VideoToolbox"));
+ if (!InitializeStubs(paths))
+ return false;
+ }
+
+ // Spawn a thread to handle parsing and calling VideoToolbox.
+ if (!decoder_thread_.Start())
+ return false;
+ decoder_task_runner_ = decoder_thread_.message_loop_proxy();
+
+ // Note that --ignore-gpu-blacklist is still required to get here.
+ return true;
+}
+
+// TODO(sandersd): Proper error reporting instead of CHECKs.
+void VTVideoDecodeAccelerator::ConfigureDecoder(
+ const std::vector<const uint8_t*>& nalu_data_ptrs,
+ const std::vector<size_t>& nalu_data_sizes) {
+ if (format_ != NULL) {
scherkus (not reviewing) 2014/07/09 18:32:48 nit: (!format_)
sandersd (OOO until July 31) 2014/07/09 20:07:11 Done.
+ CFRelease(format_);
+ format_ = NULL;
+ }
+
+ CHECK(!CMVideoFormatDescriptionCreateFromH264ParameterSets(
+ kCFAllocatorDefault,
+ nalu_data_ptrs.size(), // parameter_set_count
+ &nalu_data_ptrs.front(), // &parameter_set_pointers
+ &nalu_data_sizes.front(), // &parameter_set_sizes
+ 4, // nal_unit_header_length
+ &format_
+ ));
+
+ // TODO(sandersd): Check if the size has changed and handle picture requests.
+ CMVideoDimensions coded_size = CMVideoFormatDescriptionGetDimensions(format_);
+ coded_width_ = coded_size.width;
+ coded_height_ = coded_size.height;
+
+ // TODO(sandersd): Scoped pointers.
scherkus (not reviewing) 2014/07/09 18:32:49 I'd go for scoped pointers right away
sandersd (OOO until July 31) 2014/07/09 20:07:11 Done.
+ CFMutableDictionaryRef decoder_config = CFDictionaryCreateMutable(
+ kCFAllocatorDefault,
+ 1, // capacity
+ &kCFTypeDictionaryKeyCallBacks,
+ &kCFTypeDictionaryValueCallBacks);
+
+ CFDictionarySetValue(
+ decoder_config,
+ // kVTVideoDecoderSpecification_EnableHardwareAcceleratedVideoDecoder
+ CFSTR("EnableHardwareAcceleratedVideoDecoder"),
+ kCFBooleanTrue);
+
+ CFMutableDictionaryRef image_config = CFDictionaryCreateMutable(
+ kCFAllocatorDefault,
+ 4, // capacity
+ &kCFTypeDictionaryKeyCallBacks,
+ &kCFTypeDictionaryValueCallBacks);
+
+ // TODO(sandersd): ARGB for video that is not 4:2:0.
+ int32_t pixel_format = '2vuy';
+#define CFINT(i) CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &i)
+ CFNumberRef cf_pixel_format = CFINT(pixel_format);
+ CFNumberRef cf_width = CFINT(coded_width_);
+ CFNumberRef cf_height = CFINT(coded_height_);
+ CFDictionarySetValue(
+ image_config, kCVPixelBufferPixelFormatTypeKey, cf_pixel_format);
scherkus (not reviewing) 2014/07/09 18:32:48 AFAIK (and you may want to verify this) you can di
sandersd (OOO until July 31) 2014/07/09 20:07:12 Sadly that would leak memory, but I've gone ahead
scherkus (not reviewing) 2014/07/09 20:37:44 Yeah I've seen both instances in the Chromium code
+ CFDictionarySetValue(image_config, kCVPixelBufferWidthKey, cf_width);
+ CFDictionarySetValue(image_config, kCVPixelBufferHeightKey, cf_height);
+ CFDictionarySetValue(
+ image_config, kCVPixelBufferOpenGLCompatibilityKey, kCFBooleanTrue);
+ CFRelease(cf_pixel_format);
+ CFRelease(cf_width);
+ CFRelease(cf_height);
+
+ if (session_ != NULL) {
scherkus (not reviewing) 2014/07/09 18:32:49 !session_
sandersd (OOO until July 31) 2014/07/09 20:07:12 Done.
+ // TODO(sandersd): Check if the session is compatable first.
+ // TODO(sandersd): Flush frames.
+ CFRelease(session_);
+ session_ = NULL;
+ }
+
+ CHECK(!VTDecompressionSessionCreate(
+ kCFAllocatorDefault,
+ format_, // video_format_description
+ decoder_config, // video_decoder_specification
+ image_config, // destination_image_buffer_attributes
+ &callback_, // output_callback
+ &session_
+ ));
+ DVLOG(2) << "Created VTDecompressionSession";
+
+ CFRelease(decoder_config);
+ CFRelease(image_config);
}
void VTVideoDecodeAccelerator::Decode(const media::BitstreamBuffer& bitstream) {
DCHECK(CalledOnValidThread());
+ decoder_task_runner_->PostTask(FROM_HERE, base::Bind(
+ &VTVideoDecodeAccelerator::DecodeTask, weak_factory_.GetWeakPtr(),
+ bitstream));
+}
+
+void VTVideoDecodeAccelerator::DecodeTask(
+ const media::BitstreamBuffer bitstream) {
+ // Map the bitstream buffer.
scherkus (not reviewing) 2014/07/09 18:32:48 DCHECK(decode_thread_.message_loop_proxy()->Belong
sandersd (OOO until July 31) 2014/07/09 20:07:11 Done.
+ base::SharedMemory memory(bitstream.handle(), true);
+ size_t size = bitstream.size();
+ CHECK(memory.Map(size));
+ const uint8_t* buf = static_cast<uint8_t*>(memory.memory());
+
+ // Locate relevant NALUs in the buffer.
+ size_t data_size = 0;
+ std::vector<media::H264NALU> nalus;
+ std::vector<const uint8_t*> config_nalu_data_ptrs;
+ std::vector<size_t> config_nalu_data_sizes;
+ parser_.SetStream(buf, size);
+ media::H264NALU nalu;
+ while (true) {
+ media::H264Parser::Result result = parser_.AdvanceToNextNALU(&nalu);
+ if (result == media::H264Parser::kEOStream)
+ break;
+ CHECK(result == media::H264Parser::kOk);
scherkus (not reviewing) 2014/07/09 18:32:48 CHECK_EQ
sandersd (OOO until July 31) 2014/07/09 20:07:12 Done.
+ if (nalu.nal_unit_type == media::H264NALU::kSPS ||
+ nalu.nal_unit_type == media::H264NALU::kPPS ||
+ nalu.nal_unit_type == media::H264NALU::kSPSExt) {
+ config_nalu_data_ptrs.push_back(nalu.data);
+ config_nalu_data_sizes.push_back(nalu.size);
+ }
+ nalus.push_back(nalu);
+ data_size += 4 + nalu.size;
+ }
+
+ if (!config_nalu_data_ptrs.empty())
+ ConfigureDecoder(config_nalu_data_ptrs, config_nalu_data_sizes);
+
+ // TODO(sandersd): Rewrite slice NALU headers and send for decoding.
+}
+
+// This method may be called on any VideoToolbox thread.
+void VTVideoDecodeAccelerator::Output(
+ int32_t bitstream_id,
+ OSStatus status,
+ VTDecodeInfoFlags info_flags,
+ CVImageBufferRef image_buffer) {
+ // TODO(sandersd): Store the frame in a queue.
+ CFRelease(image_buffer);
}
void VTVideoDecodeAccelerator::AssignPictureBuffers(
@@ -46,14 +233,18 @@ void VTVideoDecodeAccelerator::ReusePictureBuffer(int32_t picture_id) {
void VTVideoDecodeAccelerator::Flush() {
DCHECK(CalledOnValidThread());
+ // TODO(sandersd): Trigger flush, sending frames.
}
void VTVideoDecodeAccelerator::Reset() {
DCHECK(CalledOnValidThread());
+ // TODO(sandersd): Trigger flush, discarding frames.
}
void VTVideoDecodeAccelerator::Destroy() {
DCHECK(CalledOnValidThread());
+ // TODO(sandersd): Trigger flush, discarding frames, and wait for them.
+ delete this;
}
bool VTVideoDecodeAccelerator::CanDecodeOnIOThread() {

Powered by Google App Engine
This is Rietveld 408576698