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

Side by Side Diff: media/base/mac/videotoolbox_helpers.cc

Issue 1801343002: Revert of H264 HW encode using VideoToolbox (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 4 years, 9 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
« no previous file with comments | « media/base/mac/videotoolbox_helpers.h ('k') | media/cast/sender/h264_vt_encoder.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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 "media/base/mac/videotoolbox_helpers.h"
6
7 #include <array>
8 #include <vector>
9
10 #include "base/big_endian.h"
11 #include "base/memory/scoped_ptr.h"
12
13 namespace media {
14
15 namespace video_toolbox {
16
17 base::ScopedCFTypeRef<CFDictionaryRef>
18 DictionaryWithKeysAndValues(CFTypeRef* keys, CFTypeRef* values, size_t size) {
19 return base::ScopedCFTypeRef<CFDictionaryRef>(CFDictionaryCreate(
20 kCFAllocatorDefault, keys, values, size, &kCFTypeDictionaryKeyCallBacks,
21 &kCFTypeDictionaryValueCallBacks));
22 }
23
24 base::ScopedCFTypeRef<CFDictionaryRef> DictionaryWithKeyValue(CFTypeRef key,
25 CFTypeRef value) {
26 CFTypeRef keys[1] = {key};
27 CFTypeRef values[1] = {value};
28 return DictionaryWithKeysAndValues(keys, values, 1);
29 }
30
31 base::ScopedCFTypeRef<CFArrayRef> ArrayWithIntegers(const int* v, size_t size) {
32 std::vector<CFNumberRef> numbers;
33 numbers.reserve(size);
34 for (const int* end = v + size; v < end; ++v)
35 numbers.push_back(CFNumberCreate(nullptr, kCFNumberSInt32Type, v));
36 base::ScopedCFTypeRef<CFArrayRef> array(CFArrayCreate(
37 kCFAllocatorDefault, reinterpret_cast<const void**>(&numbers[0]),
38 numbers.size(), &kCFTypeArrayCallBacks));
39 for (auto& number : numbers) {
40 CFRelease(number);
41 }
42 return array;
43 }
44
45 base::ScopedCFTypeRef<CFArrayRef> ArrayWithIntegerAndFloat(int int_val,
46 float float_val) {
47 std::array<CFNumberRef, 2> numbers = {
48 {CFNumberCreate(nullptr, kCFNumberSInt32Type, &int_val),
49 CFNumberCreate(nullptr, kCFNumberFloat32Type, &float_val)}};
50 base::ScopedCFTypeRef<CFArrayRef> array(CFArrayCreate(
51 kCFAllocatorDefault, reinterpret_cast<const void**>(numbers.data()),
52 numbers.size(), &kCFTypeArrayCallBacks));
53 for (auto& number : numbers)
54 CFRelease(number);
55 return array;
56 }
57
58 // Wrapper class for writing AnnexBBuffer output into.
59 class AnnexBBuffer {
60 public:
61 virtual bool Reserve(size_t size) = 0;
62 virtual void Append(const char* s, size_t n) = 0;
63 virtual size_t GetReservedSize() const = 0;
64 };
65
66 class RawAnnexBBuffer : public AnnexBBuffer {
67 public:
68 RawAnnexBBuffer(char* annexb_buffer, size_t annexb_buffer_size)
69 : annexb_buffer_(annexb_buffer),
70 annexb_buffer_size_(annexb_buffer_size),
71 annexb_buffer_offset_(0) {}
72 bool Reserve(size_t size) override {
73 reserved_size_ = size;
74 return size <= annexb_buffer_size_;
75 }
76 void Append(const char* s, size_t n) override {
77 memcpy(annexb_buffer_ + annexb_buffer_offset_, s, n);
78 annexb_buffer_offset_ += n;
79 DCHECK_GE(reserved_size_, annexb_buffer_offset_);
80 }
81 size_t GetReservedSize() const override { return reserved_size_; }
82
83 private:
84 char* annexb_buffer_;
85 size_t annexb_buffer_size_;
86 size_t annexb_buffer_offset_;
87 size_t reserved_size_;
88
89 DISALLOW_IMPLICIT_CONSTRUCTORS(RawAnnexBBuffer);
90 };
91
92 class StringAnnexBBuffer : public AnnexBBuffer {
93 public:
94 explicit StringAnnexBBuffer(std::string* str_annexb_buffer)
95 : str_annexb_buffer_(str_annexb_buffer) {}
96 bool Reserve(size_t size) override {
97 str_annexb_buffer_->reserve(size);
98 return true;
99 }
100 void Append(const char* s, size_t n) override {
101 str_annexb_buffer_->append(s, n);
102 }
103 size_t GetReservedSize() const override { return str_annexb_buffer_->size(); }
104
105 private:
106 std::string* str_annexb_buffer_;
107 DISALLOW_IMPLICIT_CONSTRUCTORS(StringAnnexBBuffer);
108 };
109
110 template <typename NalSizeType>
111 void CopyNalsToAnnexB(char* avcc_buffer,
112 const size_t avcc_size,
113 AnnexBBuffer* annexb_buffer) {
114 static_assert(sizeof(NalSizeType) == 1 || sizeof(NalSizeType) == 2 ||
115 sizeof(NalSizeType) == 4,
116 "NAL size type has unsupported size");
117 static const char startcode_3[3] = {0, 0, 1};
118 DCHECK(avcc_buffer);
119 DCHECK(annexb_buffer);
120 size_t bytes_left = avcc_size;
121 while (bytes_left > 0) {
122 DCHECK_GT(bytes_left, sizeof(NalSizeType));
123 NalSizeType nal_size;
124 base::ReadBigEndian(avcc_buffer, &nal_size);
125 bytes_left -= sizeof(NalSizeType);
126 avcc_buffer += sizeof(NalSizeType);
127
128 DCHECK_GE(bytes_left, nal_size);
129 annexb_buffer->Append(startcode_3, sizeof(startcode_3));
130 annexb_buffer->Append(avcc_buffer, nal_size);
131 bytes_left -= nal_size;
132 avcc_buffer += nal_size;
133 }
134 }
135
136 bool CopySampleBufferToAnnexBBuffer(CoreMediaGlue::CMSampleBufferRef sbuf,
137 AnnexBBuffer* annexb_buffer,
138 bool keyframe) {
139 // Perform two pass, one to figure out the total output size, and another to
140 // copy the data after having performed a single output allocation. Note that
141 // we'll allocate a bit more because we'll count 4 bytes instead of 3 for
142 // video NALs.
143 OSStatus status;
144
145 // Get the sample buffer's block buffer and format description.
146 auto bb = CoreMediaGlue::CMSampleBufferGetDataBuffer(sbuf);
147 DCHECK(bb);
148 auto fdesc = CoreMediaGlue::CMSampleBufferGetFormatDescription(sbuf);
149 DCHECK(fdesc);
150
151 size_t bb_size = CoreMediaGlue::CMBlockBufferGetDataLength(bb);
152 size_t total_bytes = bb_size;
153
154 size_t pset_count;
155 int nal_size_field_bytes;
156 status = CoreMediaGlue::CMVideoFormatDescriptionGetH264ParameterSetAtIndex(
157 fdesc, 0, nullptr, nullptr, &pset_count, &nal_size_field_bytes);
158 if (status ==
159 CoreMediaGlue::kCMFormatDescriptionBridgeError_InvalidParameter) {
160 DLOG(WARNING) << " assuming 2 parameter sets and 4 bytes NAL length header";
161 pset_count = 2;
162 nal_size_field_bytes = 4;
163 } else if (status != noErr) {
164 DLOG(ERROR)
165 << " CMVideoFormatDescriptionGetH264ParameterSetAtIndex failed: "
166 << status;
167 return false;
168 }
169
170 if (keyframe) {
171 const uint8_t* pset;
172 size_t pset_size;
173 for (size_t pset_i = 0; pset_i < pset_count; ++pset_i) {
174 status =
175 CoreMediaGlue::CMVideoFormatDescriptionGetH264ParameterSetAtIndex(
176 fdesc, pset_i, &pset, &pset_size, nullptr, nullptr);
177 if (status != noErr) {
178 DLOG(ERROR)
179 << " CMVideoFormatDescriptionGetH264ParameterSetAtIndex failed: "
180 << status;
181 return false;
182 }
183 total_bytes += pset_size + nal_size_field_bytes;
184 }
185 }
186
187 if (!annexb_buffer->Reserve(total_bytes)) {
188 DLOG(ERROR) << "Cannot fit encode output into bitstream buffer. Requested:"
189 << total_bytes;
190 return false;
191 }
192
193 // Copy all parameter sets before keyframes.
194 if (keyframe) {
195 const uint8_t* pset;
196 size_t pset_size;
197 for (size_t pset_i = 0; pset_i < pset_count; ++pset_i) {
198 status =
199 CoreMediaGlue::CMVideoFormatDescriptionGetH264ParameterSetAtIndex(
200 fdesc, pset_i, &pset, &pset_size, nullptr, nullptr);
201 if (status != noErr) {
202 DLOG(ERROR)
203 << " CMVideoFormatDescriptionGetH264ParameterSetAtIndex failed: "
204 << status;
205 return false;
206 }
207 static const char startcode_4[4] = {0, 0, 0, 1};
208 annexb_buffer->Append(startcode_4, sizeof(startcode_4));
209 annexb_buffer->Append(reinterpret_cast<const char*>(pset), pset_size);
210 }
211 }
212
213 // Block buffers can be composed of non-contiguous chunks. For the sake of
214 // keeping this code simple, flatten non-contiguous block buffers.
215 base::ScopedCFTypeRef<CoreMediaGlue::CMBlockBufferRef> contiguous_bb(
216 bb, base::scoped_policy::RETAIN);
217 if (!CoreMediaGlue::CMBlockBufferIsRangeContiguous(bb, 0, 0)) {
218 contiguous_bb.reset();
219 status = CoreMediaGlue::CMBlockBufferCreateContiguous(
220 kCFAllocatorDefault, bb, kCFAllocatorDefault, nullptr, 0, 0, 0,
221 contiguous_bb.InitializeInto());
222 if (status != noErr) {
223 DLOG(ERROR) << " CMBlockBufferCreateContiguous failed: " << status;
224 return false;
225 }
226 }
227
228 // Copy all the NAL units. In the process convert them from AVCC format
229 // (length header) to AnnexB format (start code).
230 char* bb_data;
231 status = CoreMediaGlue::CMBlockBufferGetDataPointer(contiguous_bb, 0, nullptr,
232 nullptr, &bb_data);
233 if (status != noErr) {
234 DLOG(ERROR) << " CMBlockBufferGetDataPointer failed: " << status;
235 return false;
236 }
237
238 if (nal_size_field_bytes == 1) {
239 CopyNalsToAnnexB<uint8_t>(bb_data, bb_size, annexb_buffer);
240 } else if (nal_size_field_bytes == 2) {
241 CopyNalsToAnnexB<uint16_t>(bb_data, bb_size, annexb_buffer);
242 } else if (nal_size_field_bytes == 4) {
243 CopyNalsToAnnexB<uint32_t>(bb_data, bb_size, annexb_buffer);
244 } else {
245 NOTREACHED();
246 }
247 return true;
248 }
249
250 bool CopySampleBufferToAnnexBBuffer(CoreMediaGlue::CMSampleBufferRef sbuf,
251 bool keyframe,
252 std::string* annexb_buffer) {
253 StringAnnexBBuffer buffer(annexb_buffer);
254 return CopySampleBufferToAnnexBBuffer(sbuf, &buffer, keyframe);
255 }
256
257 bool CopySampleBufferToAnnexBBuffer(CoreMediaGlue::CMSampleBufferRef sbuf,
258 bool keyframe,
259 size_t annexb_buffer_size,
260 char* annexb_buffer,
261 size_t* used_buffer_size) {
262 RawAnnexBBuffer buffer(annexb_buffer, annexb_buffer_size);
263 const bool copy_rv = CopySampleBufferToAnnexBBuffer(sbuf, &buffer, keyframe);
264 *used_buffer_size = buffer.GetReservedSize();
265 return copy_rv;
266 }
267
268 SessionPropertySetter::SessionPropertySetter(
269 base::ScopedCFTypeRef<VideoToolboxGlue::VTCompressionSessionRef> session,
270 const VideoToolboxGlue* const glue)
271 : session_(session), glue_(glue) {}
272
273 SessionPropertySetter::~SessionPropertySetter() {}
274
275 bool SessionPropertySetter::Set(CFStringRef key, int32_t value) {
276 DCHECK(session_);
277 DCHECK(glue_);
278 base::ScopedCFTypeRef<CFNumberRef> cfvalue(
279 CFNumberCreate(nullptr, kCFNumberSInt32Type, &value));
280 return glue_->VTSessionSetProperty(session_, key, cfvalue) == noErr;
281 }
282
283 bool SessionPropertySetter::Set(CFStringRef key, bool value) {
284 DCHECK(session_);
285 DCHECK(glue_);
286 CFBooleanRef cfvalue = (value) ? kCFBooleanTrue : kCFBooleanFalse;
287 return glue_->VTSessionSetProperty(session_, key, cfvalue) == noErr;
288 }
289
290 bool SessionPropertySetter::Set(CFStringRef key, CFStringRef value) {
291 DCHECK(session_);
292 DCHECK(glue_);
293 return glue_->VTSessionSetProperty(session_, key, value) == noErr;
294 }
295
296 bool SessionPropertySetter::Set(CFStringRef key, CFArrayRef value) {
297 DCHECK(session_);
298 DCHECK(glue_);
299 return glue_->VTSessionSetProperty(session_, key, value) == noErr;
300 }
301
302 } // namespace video_toolbox
303
304 } // namespace media
OLDNEW
« no previous file with comments | « media/base/mac/videotoolbox_helpers.h ('k') | media/cast/sender/h264_vt_encoder.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698