Skip to content
This repository was archived by the owner on Apr 3, 2020. It is now read-only.

Commit fa18b3c

Browse files
Use PPS/SPS NALUs to initialize a VTDecompressionSession.
BUG=133828 Review URL: https://codereview.chromium.org/374153003 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@282549 0039d316-1c4b-4281-b951-d872f2087c98
1 parent 24338ec commit fa18b3c

File tree

3 files changed

+216
-11
lines changed

3 files changed

+216
-11
lines changed

content/common/gpu/media/vt_video_decode_accelerator.cc

Lines changed: 180 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,51 @@
22
// Use of this source code is governed by a BSD-style license that can be
33
// found in the LICENSE file.
44

5+
#include <CoreVideo/CoreVideo.h>
6+
#include <OpenGL/CGLIOSurface.h>
7+
8+
#include "base/bind.h"
9+
#include "base/thread_task_runner_handle.h"
510
#include "content/common/gpu/media/vt_video_decode_accelerator.h"
11+
#include "media/filters/h264_parser.h"
12+
13+
using content_common_gpu_media::kModuleVt;
14+
using content_common_gpu_media::InitializeStubs;
15+
using content_common_gpu_media::IsVtInitialized;
16+
using content_common_gpu_media::StubPathMap;
617

718
namespace content {
819

20+
// Size of length headers prepended to NALUs in MPEG-4 framing. (1, 2, or 4.)
21+
static const int kNALUHeaderLength = 4;
22+
23+
// Route decoded frame callbacks back into the VTVideoDecodeAccelerator.
24+
static void OutputThunk(
25+
void* decompression_output_refcon,
26+
void* source_frame_refcon,
27+
OSStatus status,
28+
VTDecodeInfoFlags info_flags,
29+
CVImageBufferRef image_buffer,
30+
CMTime presentation_time_stamp,
31+
CMTime presentation_duration) {
32+
VTVideoDecodeAccelerator* vda =
33+
reinterpret_cast<VTVideoDecodeAccelerator*>(decompression_output_refcon);
34+
int32_t* bitstream_id_ptr = reinterpret_cast<int32_t*>(source_frame_refcon);
35+
int32_t bitstream_id = *bitstream_id_ptr;
36+
delete bitstream_id_ptr;
37+
CFRetain(image_buffer);
38+
vda->Output(bitstream_id, status, info_flags, image_buffer);
39+
}
40+
941
VTVideoDecodeAccelerator::VTVideoDecodeAccelerator(CGLContextObj cgl_context)
10-
: loop_proxy_(base::MessageLoopProxy::current()),
11-
cgl_context_(cgl_context),
42+
: cgl_context_(cgl_context),
1243
client_(NULL),
44+
decoder_thread_("VTDecoderThread"),
45+
format_(NULL),
46+
session_(NULL),
1347
weak_this_factory_(this) {
48+
callback_.decompressionOutputCallback = OutputThunk;
49+
callback_.decompressionOutputRefCon = this;
1450
}
1551

1652
VTVideoDecodeAccelerator::~VTVideoDecodeAccelerator() {
@@ -20,19 +56,154 @@ bool VTVideoDecodeAccelerator::Initialize(
2056
media::VideoCodecProfile profile,
2157
Client* client) {
2258
DCHECK(CalledOnValidThread());
23-
DVLOG(2) << __FUNCTION__;
2459
client_ = client;
2560

2661
// Only H.264 is supported.
2762
if (profile < media::H264PROFILE_MIN || profile > media::H264PROFILE_MAX)
2863
return false;
2964

30-
// Prevent anyone from using VTVideoDecoder for now. http://crbug.com/133828
31-
return false;
65+
// TODO(sandersd): Move VideoToolbox library loading to sandbox startup;
66+
// until then, --no-sandbox is required.
67+
if (!IsVtInitialized()) {
68+
StubPathMap paths;
69+
// CoreVideo is also required, but the loader stops after the first
70+
// path is loaded. Instead we rely on the transitive dependency from
71+
// VideoToolbox to CoreVideo.
72+
// TODO(sandersd): Fallback to PrivateFrameworks for VideoToolbox.
73+
paths[kModuleVt].push_back(FILE_PATH_LITERAL(
74+
"/System/Library/Frameworks/VideoToolbox.framework/VideoToolbox"));
75+
if (!InitializeStubs(paths))
76+
return false;
77+
}
78+
79+
// Spawn a thread to handle parsing and calling VideoToolbox.
80+
if (!decoder_thread_.Start())
81+
return false;
82+
83+
// Note that --ignore-gpu-blacklist is still required to get here.
84+
return true;
85+
}
86+
87+
// TODO(sandersd): Proper error reporting instead of CHECKs.
88+
void VTVideoDecodeAccelerator::ConfigureDecoder(
89+
const std::vector<const uint8_t*>& nalu_data_ptrs,
90+
const std::vector<size_t>& nalu_data_sizes) {
91+
format_.reset();
92+
CHECK(!CMVideoFormatDescriptionCreateFromH264ParameterSets(
93+
kCFAllocatorDefault,
94+
nalu_data_ptrs.size(), // parameter_set_count
95+
&nalu_data_ptrs.front(), // &parameter_set_pointers
96+
&nalu_data_sizes.front(), // &parameter_set_sizes
97+
kNALUHeaderLength, // nal_unit_header_length
98+
format_.InitializeInto()
99+
));
100+
101+
// TODO(sandersd): Check if the size has changed and handle picture requests.
102+
CMVideoDimensions coded_size = CMVideoFormatDescriptionGetDimensions(format_);
103+
coded_size_.SetSize(coded_size.width, coded_size.height);
104+
105+
base::ScopedCFTypeRef<CFMutableDictionaryRef> decoder_config(
106+
CFDictionaryCreateMutable(
107+
kCFAllocatorDefault,
108+
1, // capacity
109+
&kCFTypeDictionaryKeyCallBacks,
110+
&kCFTypeDictionaryValueCallBacks));
111+
112+
CFDictionarySetValue(
113+
decoder_config,
114+
// kVTVideoDecoderSpecification_EnableHardwareAcceleratedVideoDecoder
115+
CFSTR("EnableHardwareAcceleratedVideoDecoder"),
116+
kCFBooleanTrue);
117+
118+
base::ScopedCFTypeRef<CFMutableDictionaryRef> image_config(
119+
CFDictionaryCreateMutable(
120+
kCFAllocatorDefault,
121+
4, // capacity
122+
&kCFTypeDictionaryKeyCallBacks,
123+
&kCFTypeDictionaryValueCallBacks));
124+
125+
// TODO(sandersd): ARGB for video that is not 4:2:0.
126+
int32_t pixel_format = '2vuy';
127+
#define CFINT(i) CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &i)
128+
base::ScopedCFTypeRef<CFNumberRef> cf_pixel_format(CFINT(pixel_format));
129+
base::ScopedCFTypeRef<CFNumberRef> cf_width(CFINT(coded_size.width));
130+
base::ScopedCFTypeRef<CFNumberRef> cf_height(CFINT(coded_size.height));
131+
#undef CFINT
132+
CFDictionarySetValue(
133+
image_config, kCVPixelBufferPixelFormatTypeKey, cf_pixel_format);
134+
CFDictionarySetValue(image_config, kCVPixelBufferWidthKey, cf_width);
135+
CFDictionarySetValue(image_config, kCVPixelBufferHeightKey, cf_height);
136+
CFDictionarySetValue(
137+
image_config, kCVPixelBufferOpenGLCompatibilityKey, kCFBooleanTrue);
138+
139+
// TODO(sandersd): Skip if the session is compatible.
140+
// TODO(sandersd): Flush frames when resetting.
141+
session_.reset();
142+
CHECK(!VTDecompressionSessionCreate(
143+
kCFAllocatorDefault,
144+
format_, // video_format_description
145+
decoder_config, // video_decoder_specification
146+
image_config, // destination_image_buffer_attributes
147+
&callback_, // output_callback
148+
session_.InitializeInto()
149+
));
150+
DVLOG(2) << "Created VTDecompressionSession";
32151
}
33152

34153
void VTVideoDecodeAccelerator::Decode(const media::BitstreamBuffer& bitstream) {
35154
DCHECK(CalledOnValidThread());
155+
decoder_thread_.message_loop_proxy()->PostTask(FROM_HERE, base::Bind(
156+
&VTVideoDecodeAccelerator::DecodeTask, base::Unretained(this),
157+
bitstream));
158+
}
159+
160+
void VTVideoDecodeAccelerator::DecodeTask(
161+
const media::BitstreamBuffer bitstream) {
162+
DCHECK(decoder_thread_.message_loop_proxy()->BelongsToCurrentThread());
163+
164+
// Map the bitstream buffer.
165+
base::SharedMemory memory(bitstream.handle(), true);
166+
size_t size = bitstream.size();
167+
CHECK(memory.Map(size));
168+
const uint8_t* buf = static_cast<uint8_t*>(memory.memory());
169+
170+
// Locate relevant NALUs in the buffer.
171+
size_t data_size = 0;
172+
std::vector<media::H264NALU> nalus;
173+
std::vector<const uint8_t*> config_nalu_data_ptrs;
174+
std::vector<size_t> config_nalu_data_sizes;
175+
parser_.SetStream(buf, size);
176+
media::H264NALU nalu;
177+
while (true) {
178+
media::H264Parser::Result result = parser_.AdvanceToNextNALU(&nalu);
179+
if (result == media::H264Parser::kEOStream)
180+
break;
181+
CHECK_EQ(result, media::H264Parser::kOk);
182+
if (nalu.nal_unit_type == media::H264NALU::kSPS ||
183+
nalu.nal_unit_type == media::H264NALU::kPPS ||
184+
nalu.nal_unit_type == media::H264NALU::kSPSExt) {
185+
config_nalu_data_ptrs.push_back(nalu.data);
186+
config_nalu_data_sizes.push_back(nalu.size);
187+
}
188+
nalus.push_back(nalu);
189+
// Each NALU will have a 4-byte length header prepended.
190+
data_size += kNALUHeaderLength + nalu.size;
191+
}
192+
193+
if (!config_nalu_data_ptrs.empty())
194+
ConfigureDecoder(config_nalu_data_ptrs, config_nalu_data_sizes);
195+
196+
// TODO(sandersd): Rewrite slice NALU headers and send for decoding.
197+
}
198+
199+
// This method may be called on any VideoToolbox thread.
200+
void VTVideoDecodeAccelerator::Output(
201+
int32_t bitstream_id,
202+
OSStatus status,
203+
VTDecodeInfoFlags info_flags,
204+
CVImageBufferRef image_buffer) {
205+
// TODO(sandersd): Store the frame in a queue.
206+
CFRelease(image_buffer);
36207
}
37208

38209
void VTVideoDecodeAccelerator::AssignPictureBuffers(
@@ -46,14 +217,18 @@ void VTVideoDecodeAccelerator::ReusePictureBuffer(int32_t picture_id) {
46217

47218
void VTVideoDecodeAccelerator::Flush() {
48219
DCHECK(CalledOnValidThread());
220+
// TODO(sandersd): Trigger flush, sending frames.
49221
}
50222

51223
void VTVideoDecodeAccelerator::Reset() {
52224
DCHECK(CalledOnValidThread());
225+
// TODO(sandersd): Trigger flush, discarding frames.
53226
}
54227

55228
void VTVideoDecodeAccelerator::Destroy() {
56229
DCHECK(CalledOnValidThread());
230+
// TODO(sandersd): Trigger flush, discarding frames, and wait for them.
231+
delete this;
57232
}
58233

59234
bool VTVideoDecodeAccelerator::CanDecodeOnIOThread() {

content/common/gpu/media/vt_video_decode_accelerator.h

Lines changed: 35 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,19 +5,26 @@
55
#ifndef CONTENT_COMMON_GPU_MEDIA_VT_VIDEO_DECODE_ACCELERATOR_H_
66
#define CONTENT_COMMON_GPU_MEDIA_VT_VIDEO_DECODE_ACCELERATOR_H_
77

8-
#include <stdint.h>
9-
8+
#include "base/basictypes.h"
9+
#include "base/mac/scoped_cftyperef.h"
1010
#include "base/memory/ref_counted.h"
1111
#include "base/memory/weak_ptr.h"
1212
#include "base/message_loop/message_loop.h"
13-
#include "base/message_loop/message_loop_proxy.h"
13+
#include "base/threading/thread.h"
14+
#include "content/common/gpu/media/vt.h"
15+
#include "media/filters/h264_parser.h"
1416
#include "media/video/video_decode_accelerator.h"
17+
#include "ui/gfx/geometry/size.h"
1518
#include "ui/gl/gl_context_cgl.h"
1619

20+
namespace base {
21+
class SingleThreadTaskRunner;
22+
} // namespace base
23+
1724
namespace content {
1825

19-
// (Stub of a) VideoToolbox.framework implementation of the
20-
// VideoDecodeAccelerator interface for Mac OS X.
26+
// VideoToolbox.framework implementation of the VideoDecodeAccelerator
27+
// interface for Mac OS X (currently limited to 10.9+).
2128
class VTVideoDecodeAccelerator
2229
: public media::VideoDecodeAccelerator,
2330
public base::NonThreadSafe {
@@ -38,10 +45,32 @@ class VTVideoDecodeAccelerator
3845
virtual void Destroy() OVERRIDE;
3946
virtual bool CanDecodeOnIOThread() OVERRIDE;
4047

48+
// Called by VideoToolbox when a frame is decoded.
49+
void Output(
50+
int32_t bitstream_id,
51+
OSStatus status,
52+
VTDecodeInfoFlags info_flags,
53+
CVImageBufferRef image_buffer);
54+
4155
private:
42-
scoped_refptr<base::MessageLoopProxy> loop_proxy_;
56+
// Configure a VideoToolbox decompression session from parameter set NALUs.
57+
void ConfigureDecoder(
58+
const std::vector<const uint8_t*>& nalu_data_ptrs,
59+
const std::vector<size_t>& nalu_data_sizes);
60+
61+
// Decode a frame of bitstream.
62+
void DecodeTask(const media::BitstreamBuffer);
63+
4364
CGLContextObj cgl_context_;
4465
media::VideoDecodeAccelerator::Client* client_;
66+
base::Thread decoder_thread_;
67+
68+
// Decoder configuration (used only on decoder thread).
69+
VTDecompressionOutputCallbackRecord callback_;
70+
base::ScopedCFTypeRef<CMFormatDescriptionRef> format_;
71+
base::ScopedCFTypeRef<VTDecompressionSessionRef> session_;
72+
media::H264Parser parser_;
73+
gfx::Size coded_size_;
4574

4675
// Member variables should appear before the WeakPtrFactory, to ensure
4776
// that any WeakPtrs to Controller are invalidated before its members

content/content_common.gypi

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -590,6 +590,7 @@
590590
'sources': [
591591
'common/gpu/client/gpu_memory_buffer_impl_io_surface.cc',
592592
'common/gpu/client/gpu_memory_buffer_impl_io_surface.h',
593+
'common/gpu/media/vt.h',
593594
'common/gpu/media/vt_video_decode_accelerator.cc',
594595
'common/gpu/media/vt_video_decode_accelerator.h',
595596
],

0 commit comments

Comments
 (0)