https://zh.osdn.net/projects/android-x86/scm/git/frameworks-av/commits/9aa87d4ef502c9700a31fe46dc6e1d6f99cf4e5e
frameworks/av
修订版 | 9aa87d4ef502c9700a31fe46dc6e1d6f99cf4e5e (tree) |
---|---|
时间 | 2016-01-22 05:47:05 |
作者 | Wonsik Kim |
Commiter | Wonsik Kim |
stagefright: add HEVC support to MediaRecorder
Bug: 22879917
Change-Id: I6c97b051467de44c506a8ff021321e5953a63fc3
@@ -95,6 +95,7 @@ enum video_encoder { | ||
95 | 95 | VIDEO_ENCODER_H264 = 2, |
96 | 96 | VIDEO_ENCODER_MPEG_4_SP = 3, |
97 | 97 | VIDEO_ENCODER_VP8 = 4, |
98 | + VIDEO_ENCODER_HEVC = 5, | |
98 | 99 | |
99 | 100 | VIDEO_ENCODER_LIST_END // must be the last - used to validate the video encoder type |
100 | 101 | }; |
@@ -37,7 +37,8 @@ MediaProfiles *MediaProfiles::sInstance = NULL; | ||
37 | 37 | const MediaProfiles::NameToTagMap MediaProfiles::sVideoEncoderNameMap[] = { |
38 | 38 | {"h263", VIDEO_ENCODER_H263}, |
39 | 39 | {"h264", VIDEO_ENCODER_H264}, |
40 | - {"m4v", VIDEO_ENCODER_MPEG_4_SP} | |
40 | + {"m4v", VIDEO_ENCODER_MPEG_4_SP}, | |
41 | + {"hevc", VIDEO_ENCODER_HEVC} | |
41 | 42 | }; |
42 | 43 | |
43 | 44 | const MediaProfiles::NameToTagMap MediaProfiles::sAudioEncoderNameMap[] = { |
@@ -1226,6 +1226,7 @@ status_t StagefrightRecorder::checkVideoEncoderCapabilities() { | ||
1226 | 1226 | (mVideoEncoder == VIDEO_ENCODER_H263 ? MEDIA_MIMETYPE_VIDEO_H263 : |
1227 | 1227 | mVideoEncoder == VIDEO_ENCODER_MPEG_4_SP ? MEDIA_MIMETYPE_VIDEO_MPEG4 : |
1228 | 1228 | mVideoEncoder == VIDEO_ENCODER_VP8 ? MEDIA_MIMETYPE_VIDEO_VP8 : |
1229 | + mVideoEncoder == VIDEO_ENCODER_HEVC ? MEDIA_MIMETYPE_VIDEO_HEVC : | |
1229 | 1230 | mVideoEncoder == VIDEO_ENCODER_H264 ? MEDIA_MIMETYPE_VIDEO_AVC : ""), |
1230 | 1231 | false /* decoder */, true /* hwCodec */, &codecs); |
1231 | 1232 |
@@ -1515,6 +1516,10 @@ status_t StagefrightRecorder::setupVideoEncoder( | ||
1515 | 1516 | format->setString("mime", MEDIA_MIMETYPE_VIDEO_VP8); |
1516 | 1517 | break; |
1517 | 1518 | |
1519 | + case VIDEO_ENCODER_HEVC: | |
1520 | + format->setString("mime", MEDIA_MIMETYPE_VIDEO_HEVC); | |
1521 | + break; | |
1522 | + | |
1518 | 1523 | default: |
1519 | 1524 | CHECK(!"Should not be here, unsupported video encoding."); |
1520 | 1525 | break; |
@@ -3530,8 +3530,8 @@ status_t ACodec::setupHEVCEncoderParameters(const sp |
||
3530 | 3530 | hevcType.eProfile = static_cast |
3531 | 3531 | hevcType.eLevel = static_cast |
3532 | 3532 | } |
3533 | - | |
3534 | - // TODO: Need OMX structure definition for setting iFrameInterval | |
3533 | + // TODO: finer control? | |
3534 | + hevcType.nKeyFrameInterval = setPFramesSpacing(iFrameInterval, frameRate); | |
3535 | 3535 | |
3536 | 3536 | err = mOMX->setParameter( |
3537 | 3537 | mNode, (OMX_INDEXTYPE)OMX_IndexParamVideoHevc, &hevcType, sizeof(hevcType)); |
@@ -24,6 +24,7 @@ LOCAL_SRC_FILES:= \ | ||
24 | 24 | FLACExtractor.cpp \ |
25 | 25 | FrameRenderTracker.cpp \ |
26 | 26 | HTTPBase.cpp \ |
27 | + HevcUtils.cpp \ | |
27 | 28 | JPEGSource.cpp \ |
28 | 29 | MP3Extractor.cpp \ |
29 | 30 | MPEG2TSWriter.cpp \ |
@@ -0,0 +1,337 @@ | ||
1 | +/* | |
2 | + * Copyright (C) 2015 The Android Open Source Project | |
3 | + * | |
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | |
5 | + * you may not use this file except in compliance with the License. | |
6 | + * You may obtain a copy of the License at | |
7 | + * | |
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | |
9 | + * | |
10 | + * Unless required by applicable law or agreed to in writing, software | |
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | |
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
13 | + * See the License for the specific language governing permissions and | |
14 | + * limitations under the License. | |
15 | + */ | |
16 | + | |
17 | +//#define LOG_NDEBUG 0 | |
18 | +#define LOG_TAG "HevcUtils" | |
19 | + | |
20 | +#include |
|
21 | + | |
22 | +#include "include/HevcUtils.h" | |
23 | +#include "include/avc_utils.h" | |
24 | + | |
25 | +#include |
|
26 | +#include |
|
27 | +#include |
|
28 | +#include |
|
29 | +#include |
|
30 | +#include |
|
31 | + | |
32 | +namespace android { | |
33 | + | |
34 | +static const uint8_t kHevcNalUnitTypes[5] = { | |
35 | + kHevcNalUnitTypeVps, | |
36 | + kHevcNalUnitTypeSps, | |
37 | + kHevcNalUnitTypePps, | |
38 | + kHevcNalUnitTypePrefixSei, | |
39 | + kHevcNalUnitTypeSuffixSei, | |
40 | +}; | |
41 | + | |
42 | +HevcParameterSets::HevcParameterSets() { | |
43 | +} | |
44 | + | |
45 | +status_t HevcParameterSets::addNalUnit(const uint8_t* data, size_t size) { | |
46 | + uint8_t nalUnitType = (data[0] >> 1) & 0x3f; | |
47 | + status_t err = OK; | |
48 | + switch (nalUnitType) { | |
49 | + case 32: // VPS | |
50 | + err = parseVps(data + 2, size - 2); | |
51 | + break; | |
52 | + case 33: // SPS | |
53 | + err = parseSps(data + 2, size - 2); | |
54 | + break; | |
55 | + case 34: // PPS | |
56 | + err = parsePps(data + 2, size - 2); | |
57 | + break; | |
58 | + case 39: // Prefix SEI | |
59 | + case 40: // Suffix SEI | |
60 | + // Ignore | |
61 | + break; | |
62 | + default: | |
63 | + ALOGE("Unrecognized NAL unit type."); | |
64 | + return ERROR_MALFORMED; | |
65 | + } | |
66 | + | |
67 | + if (err != OK) { | |
68 | + return err; | |
69 | + } | |
70 | + | |
71 | + sp |
|
72 | + buffer->setInt32Data(nalUnitType); | |
73 | + mNalUnits.push(buffer); | |
74 | + return OK; | |
75 | +} | |
76 | + | |
77 | +template |
|
78 | +static bool findParam(uint32_t key, T *param, | |
79 | + KeyedVector |
|
80 | + CHECK(param); | |
81 | + if (params.indexOfKey(key) < 0) { | |
82 | + return false; | |
83 | + } | |
84 | + *param = (T) params[key]; | |
85 | + return true; | |
86 | +} | |
87 | + | |
88 | +bool HevcParameterSets::findParam8(uint32_t key, uint8_t *param) { | |
89 | + return findParam(key, param, mParams); | |
90 | +} | |
91 | + | |
92 | +bool HevcParameterSets::findParam16(uint32_t key, uint16_t *param) { | |
93 | + return findParam(key, param, mParams); | |
94 | +} | |
95 | + | |
96 | +bool HevcParameterSets::findParam32(uint32_t key, uint32_t *param) { | |
97 | + return findParam(key, param, mParams); | |
98 | +} | |
99 | + | |
100 | +bool HevcParameterSets::findParam64(uint32_t key, uint64_t *param) { | |
101 | + return findParam(key, param, mParams); | |
102 | +} | |
103 | + | |
104 | +size_t HevcParameterSets::getNumNalUnitsOfType(uint8_t type) { | |
105 | + size_t num = 0; | |
106 | + for (size_t i = 0; i < mNalUnits.size(); ++i) { | |
107 | + if (getType(i) == type) { | |
108 | + ++num; | |
109 | + } | |
110 | + } | |
111 | + return num; | |
112 | +} | |
113 | + | |
114 | +uint8_t HevcParameterSets::getType(size_t index) { | |
115 | + CHECK_LT(index, mNalUnits.size()); | |
116 | + return mNalUnits[index]->int32Data(); | |
117 | +} | |
118 | + | |
119 | +size_t HevcParameterSets::getSize(size_t index) { | |
120 | + CHECK_LT(index, mNalUnits.size()); | |
121 | + return mNalUnits[index]->size(); | |
122 | +} | |
123 | + | |
124 | +bool HevcParameterSets::write(size_t index, uint8_t* dest, size_t size) { | |
125 | + CHECK_LT(index, mNalUnits.size()); | |
126 | + const sp |
|
127 | + if (size < nalUnit->size()) { | |
128 | + ALOGE("dest buffer size too small: %zu vs. %zu to be written", | |
129 | + size, nalUnit->size()); | |
130 | + return false; | |
131 | + } | |
132 | + memcpy(dest, nalUnit->data(), nalUnit->size()); | |
133 | + return true; | |
134 | +} | |
135 | + | |
136 | +status_t HevcParameterSets::parseVps(const uint8_t* data, size_t size) { | |
137 | + // See Rec. ITU-T H.265 v3 (04/2015) Chapter 7.3.2.1 for reference | |
138 | + NALBitReader reader(data, size); | |
139 | + // Skip vps_video_parameter_set_id | |
140 | + reader.skipBits(4); | |
141 | + // Skip vps_base_layer_internal_flag | |
142 | + reader.skipBits(1); | |
143 | + // Skip vps_base_layer_available_flag | |
144 | + reader.skipBits(1); | |
145 | + // Skip vps_max_layers_minus_1 | |
146 | + reader.skipBits(6); | |
147 | + // Skip vps_temporal_id_nesting_flags | |
148 | + reader.skipBits(1); | |
149 | + // Skip reserved | |
150 | + reader.skipBits(16); | |
151 | + | |
152 | + mParams.add(kGeneralProfileSpace, reader.getBits(2)); | |
153 | + mParams.add(kGeneralTierFlag, reader.getBits(1)); | |
154 | + mParams.add(kGeneralProfileIdc, reader.getBits(5)); | |
155 | + mParams.add(kGeneralProfileCompatibilityFlags, reader.getBits(32)); | |
156 | + mParams.add( | |
157 | + kGeneralConstraintIndicatorFlags, | |
158 | + ((uint64_t)reader.getBits(16) << 32) | reader.getBits(32)); | |
159 | + mParams.add(kGeneralLevelIdc, reader.getBits(8)); | |
160 | + // 96 bits total for general profile. | |
161 | + | |
162 | + return OK; | |
163 | +} | |
164 | + | |
165 | +status_t HevcParameterSets::parseSps(const uint8_t* data, size_t size) { | |
166 | + // See Rec. ITU-T H.265 v3 (04/2015) Chapter 7.3.2.2 for reference | |
167 | + NALBitReader reader(data, size); | |
168 | + // Skip sps_video_parameter_set_id | |
169 | + reader.skipBits(4); | |
170 | + uint8_t maxSubLayersMinus1 = reader.getBits(3); | |
171 | + // Skip sps_temporal_id_nesting_flag; | |
172 | + reader.skipBits(1); | |
173 | + // Skip general profile | |
174 | + reader.skipBits(96); | |
175 | + if (maxSubLayersMinus1 > 0) { | |
176 | + bool subLayerProfilePresentFlag[8]; | |
177 | + bool subLayerLevelPresentFlag[8]; | |
178 | + for (int i = 0; i < maxSubLayersMinus1; ++i) { | |
179 | + subLayerProfilePresentFlag[i] = reader.getBits(1); | |
180 | + subLayerLevelPresentFlag[i] = reader.getBits(1); | |
181 | + } | |
182 | + // Skip reserved | |
183 | + reader.skipBits(2 * (8 - maxSubLayersMinus1)); | |
184 | + for (int i = 0; i < maxSubLayersMinus1; ++i) { | |
185 | + if (subLayerProfilePresentFlag[i]) { | |
186 | + // Skip profile | |
187 | + reader.skipBits(88); | |
188 | + } | |
189 | + if (subLayerLevelPresentFlag[i]) { | |
190 | + // Skip sub_layer_level_idc[i] | |
191 | + reader.skipBits(8); | |
192 | + } | |
193 | + } | |
194 | + } | |
195 | + // Skip sps_seq_parameter_set_id | |
196 | + parseUE(&reader); | |
197 | + uint8_t chromaFormatIdc = parseUE(&reader); | |
198 | + mParams.add(kChromaFormatIdc, chromaFormatIdc); | |
199 | + if (chromaFormatIdc == 3) { | |
200 | + // Skip separate_colour_plane_flag | |
201 | + reader.skipBits(1); | |
202 | + } | |
203 | + // Skip pic_width_in_luma_samples | |
204 | + parseUE(&reader); | |
205 | + // Skip pic_height_in_luma_samples | |
206 | + parseUE(&reader); | |
207 | + if (reader.getBits(1) /* i.e. conformance_window_flag */) { | |
208 | + // Skip conf_win_left_offset | |
209 | + parseUE(&reader); | |
210 | + // Skip conf_win_right_offset | |
211 | + parseUE(&reader); | |
212 | + // Skip conf_win_top_offset | |
213 | + parseUE(&reader); | |
214 | + // Skip conf_win_bottom_offset | |
215 | + parseUE(&reader); | |
216 | + } | |
217 | + mParams.add(kBitDepthLumaMinus8, parseUE(&reader)); | |
218 | + mParams.add(kBitDepthChromaMinus8, parseUE(&reader)); | |
219 | + | |
220 | + return OK; | |
221 | +} | |
222 | + | |
223 | +status_t HevcParameterSets::parsePps( | |
224 | + const uint8_t* data __unused, size_t size __unused) { | |
225 | + return OK; | |
226 | +} | |
227 | + | |
228 | +status_t HevcParameterSets::makeHvcc(uint8_t *hvcc, size_t *hvccSize, | |
229 | + size_t nalSizeLength) { | |
230 | + if (hvcc == NULL || hvccSize == NULL | |
231 | + || (nalSizeLength != 4 && nalSizeLength != 2)) { | |
232 | + return BAD_VALUE; | |
233 | + } | |
234 | + // ISO 14496-15: HEVC file format | |
235 | + size_t size = 23; // 23 bytes in the header | |
236 | + size_t numOfArrays = 0; | |
237 | + const size_t numNalUnits = getNumNalUnits(); | |
238 | + for (size_t i = 0; i < ARRAY_SIZE(kHevcNalUnitTypes); ++i) { | |
239 | + uint8_t type = kHevcNalUnitTypes[i]; | |
240 | + size_t numNalus = getNumNalUnitsOfType(type); | |
241 | + if (numNalus == 0) { | |
242 | + continue; | |
243 | + } | |
244 | + ++numOfArrays; | |
245 | + size += 3; | |
246 | + for (size_t j = 0; j < numNalUnits; ++j) { | |
247 | + if (getType(j) != type) { | |
248 | + continue; | |
249 | + } | |
250 | + size += 2 + getSize(j); | |
251 | + } | |
252 | + } | |
253 | + uint8_t generalProfileSpace, generalTierFlag, generalProfileIdc; | |
254 | + if (!findParam8(kGeneralProfileSpace, &generalProfileSpace) | |
255 | + || !findParam8(kGeneralTierFlag, &generalTierFlag) | |
256 | + || !findParam8(kGeneralProfileIdc, &generalProfileIdc)) { | |
257 | + return ERROR_MALFORMED; | |
258 | + } | |
259 | + uint32_t compatibilityFlags; | |
260 | + uint64_t constraintIdcFlags; | |
261 | + if (!findParam32(kGeneralProfileCompatibilityFlags, &compatibilityFlags) | |
262 | + || !findParam64(kGeneralConstraintIndicatorFlags, &constraintIdcFlags)) { | |
263 | + return ERROR_MALFORMED; | |
264 | + } | |
265 | + uint8_t generalLevelIdc; | |
266 | + if (!findParam8(kGeneralLevelIdc, &generalLevelIdc)) { | |
267 | + return ERROR_MALFORMED; | |
268 | + } | |
269 | + uint8_t chromaFormatIdc, bitDepthLumaMinus8, bitDepthChromaMinus8; | |
270 | + if (!findParam8(kChromaFormatIdc, &chromaFormatIdc) | |
271 | + || !findParam8(kBitDepthLumaMinus8, &bitDepthLumaMinus8) | |
272 | + || !findParam8(kBitDepthChromaMinus8, &bitDepthChromaMinus8)) { | |
273 | + return ERROR_MALFORMED; | |
274 | + } | |
275 | + if (size > *hvccSize) { | |
276 | + return NO_MEMORY; | |
277 | + } | |
278 | + *hvccSize = size; | |
279 | + | |
280 | + uint8_t *header = hvcc; | |
281 | + header[0] = 1; | |
282 | + header[1] = (kGeneralProfileSpace << 6) | (kGeneralTierFlag << 5) | kGeneralProfileIdc; | |
283 | + header[2] = (compatibilityFlags >> 24) & 0xff; | |
284 | + header[3] = (compatibilityFlags >> 16) & 0xff; | |
285 | + header[4] = (compatibilityFlags >> 8) & 0xff; | |
286 | + header[5] = compatibilityFlags & 0xff; | |
287 | + header[6] = (constraintIdcFlags >> 40) & 0xff; | |
288 | + header[7] = (constraintIdcFlags >> 32) & 0xff; | |
289 | + header[8] = (constraintIdcFlags >> 24) & 0xff; | |
290 | + header[9] = (constraintIdcFlags >> 16) & 0xff; | |
291 | + header[10] = (constraintIdcFlags >> 8) & 0xff; | |
292 | + header[11] = constraintIdcFlags & 0xff; | |
293 | + header[12] = generalLevelIdc; | |
294 | + // FIXME: parse min_spatial_segmentation_idc. | |
295 | + header[13] = 0xf0; | |
296 | + header[14] = 0; | |
297 | + // FIXME: derive parallelismType properly. | |
298 | + header[15] = 0xfc; | |
299 | + header[16] = 0xfc | chromaFormatIdc; | |
300 | + header[17] = 0xf8 | bitDepthLumaMinus8; | |
301 | + header[18] = 0xf8 | bitDepthChromaMinus8; | |
302 | + // FIXME: derive avgFrameRate | |
303 | + header[19] = 0; | |
304 | + header[20] = 0; | |
305 | + // constantFrameRate, numTemporalLayers, temporalIdNested all set to 0. | |
306 | + header[21] = nalSizeLength - 1; | |
307 | + header[22] = numOfArrays; | |
308 | + header += 23; | |
309 | + for (size_t i = 0; i < ARRAY_SIZE(kHevcNalUnitTypes); ++i) { | |
310 | + uint8_t type = kHevcNalUnitTypes[i]; | |
311 | + size_t numNalus = getNumNalUnitsOfType(type); | |
312 | + if (numNalus == 0) { | |
313 | + continue; | |
314 | + } | |
315 | + // array_completeness set to 0. | |
316 | + header[0] = type; | |
317 | + header[1] = (numNalus >> 8) & 0xff; | |
318 | + header[2] = numNalus & 0xff; | |
319 | + header += 3; | |
320 | + for (size_t j = 0; j < numNalUnits; ++j) { | |
321 | + if (getType(j) != type) { | |
322 | + continue; | |
323 | + } | |
324 | + header[0] = (getSize(j) >> 8) & 0xff; | |
325 | + header[1] = getSize(j) & 0xff; | |
326 | + if (!write(j, header + 2, size - (header - (uint8_t *)hvcc))) { | |
327 | + return NO_MEMORY; | |
328 | + } | |
329 | + header += (2 + getSize(j)); | |
330 | + } | |
331 | + } | |
332 | + CHECK_EQ(header - size, hvcc); | |
333 | + | |
334 | + return OK; | |
335 | +} | |
336 | + | |
337 | +} // namespace android |
@@ -41,7 +41,7 @@ | ||
41 | 41 | #include |
42 | 42 | |
43 | 43 | #include "include/ESDS.h" |
44 | - | |
44 | +#include "include/HevcUtils.h" | |
45 | 45 | |
46 | 46 | #ifndef __predict_false |
47 | 47 | #define __predict_false(exp) __builtin_expect((exp) != 0, 0) |
@@ -70,6 +70,18 @@ static const char kMetaKey_Build[] = "com.android.build"; | ||
70 | 70 | #endif |
71 | 71 | static const char kMetaKey_CaptureFps[] = "com.android.capture.fps"; |
72 | 72 | |
73 | +static const uint8_t kMandatoryHevcNalUnitTypes[3] = { | |
74 | + kHevcNalUnitTypeVps, | |
75 | + kHevcNalUnitTypeSps, | |
76 | + kHevcNalUnitTypePps, | |
77 | +}; | |
78 | +static const uint8_t kHevcNalUnitTypes[5] = { | |
79 | + kHevcNalUnitTypeVps, | |
80 | + kHevcNalUnitTypeSps, | |
81 | + kHevcNalUnitTypePps, | |
82 | + kHevcNalUnitTypePrefixSei, | |
83 | + kHevcNalUnitTypeSuffixSei, | |
84 | +}; | |
73 | 85 | /* uncomment to include model and build in meta */ |
74 | 86 | //#define SHOW_MODEL_BUILD 1 |
75 | 87 |
@@ -89,6 +101,7 @@ public: | ||
89 | 101 | void writeTrackHeader(bool use32BitOffset = true); |
90 | 102 | void bufferChunk(int64_t timestampUs); |
91 | 103 | bool isAvc() const { return mIsAvc; } |
104 | + bool isHevc() const { return mIsHevc; } | |
92 | 105 | bool isAudio() const { return mIsAudio; } |
93 | 106 | bool isMPEG4() const { return mIsMPEG4; } |
94 | 107 | void addChunkOffset(off64_t offset); |
@@ -234,6 +247,7 @@ private: | ||
234 | 247 | volatile bool mResumed; |
235 | 248 | volatile bool mStarted; |
236 | 249 | bool mIsAvc; |
250 | + bool mIsHevc; | |
237 | 251 | bool mIsAudio; |
238 | 252 | bool mIsMPEG4; |
239 | 253 | int32_t mTrackId; |
@@ -299,10 +313,17 @@ private: | ||
299 | 313 | const uint8_t *parseParamSet( |
300 | 314 | const uint8_t *data, size_t length, int type, size_t *paramSetLen); |
301 | 315 | |
316 | + status_t copyCodecSpecificData(const uint8_t *data, size_t size, size_t minLength = 0); | |
317 | + | |
302 | 318 | status_t makeAVCCodecSpecificData(const uint8_t *data, size_t size); |
303 | 319 | status_t copyAVCCodecSpecificData(const uint8_t *data, size_t size); |
304 | 320 | status_t parseAVCCodecSpecificData(const uint8_t *data, size_t size); |
305 | 321 | |
322 | + status_t makeHEVCCodecSpecificData(const uint8_t *data, size_t size); | |
323 | + status_t copyHEVCCodecSpecificData(const uint8_t *data, size_t size); | |
324 | + status_t parseHEVCCodecSpecificData( | |
325 | + const uint8_t *data, size_t size, HevcParameterSets ¶mSets); | |
326 | + | |
306 | 327 | // Track authoring progress status |
307 | 328 | void trackProgressStatus(int64_t timeUs, status_t err = OK); |
308 | 329 | void initTrackingProgressStatus(MetaData *params); |
@@ -340,6 +361,7 @@ private: | ||
340 | 361 | void writeD263Box(); |
341 | 362 | void writePaspBox(); |
342 | 363 | void writeAvccBox(); |
364 | + void writeHvccBox(); | |
343 | 365 | void writeUrlBox(); |
344 | 366 | void writeDrefBox(); |
345 | 367 | void writeDinfBox(); |
@@ -463,6 +485,8 @@ const char *MPEG4Writer::Track::getFourCCForMime(const char *mime) { | ||
463 | 485 | return "s263"; |
464 | 486 | } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_AVC, mime)) { |
465 | 487 | return "avc1"; |
488 | + } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_HEVC, mime)) { | |
489 | + return "hvc1"; | |
466 | 490 | } |
467 | 491 | } else { |
468 | 492 | ALOGE("Track (%s) other than video or audio is not supported", mime); |
@@ -1465,6 +1489,7 @@ MPEG4Writer::Track::Track( | ||
1465 | 1489 | const char *mime; |
1466 | 1490 | mMeta->findCString(kKeyMIMEType, &mime); |
1467 | 1491 | mIsAvc = !strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_AVC); |
1492 | + mIsHevc = !strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_HEVC); | |
1468 | 1493 | mIsAudio = !strncasecmp(mime, "audio/", 6); |
1469 | 1494 | mIsMPEG4 = !strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_MPEG4) || |
1470 | 1495 | !strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AAC); |
@@ -1560,31 +1585,26 @@ void MPEG4Writer::Track::getCodecSpecificDataFromInputFormatIfPossible() { | ||
1560 | 1585 | const char *mime; |
1561 | 1586 | CHECK(mMeta->findCString(kKeyMIMEType, &mime)); |
1562 | 1587 | |
1588 | + uint32_t type; | |
1589 | + const void *data = NULL; | |
1590 | + size_t size = 0; | |
1563 | 1591 | if (!strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_AVC)) { |
1564 | - uint32_t type; | |
1565 | - const void *data; | |
1566 | - size_t size; | |
1567 | - if (mMeta->findData(kKeyAVCC, &type, &data, &size)) { | |
1568 | - mCodecSpecificData = malloc(size); | |
1569 | - mCodecSpecificDataSize = size; | |
1570 | - memcpy(mCodecSpecificData, data, size); | |
1571 | - mGotAllCodecSpecificData = true; | |
1572 | - } | |
1592 | + mMeta->findData(kKeyAVCC, &type, &data, &size); | |
1593 | + } else if (!strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_HEVC)) { | |
1594 | + mMeta->findData(kKeyHVCC, &type, &data, &size); | |
1573 | 1595 | } else if (!strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_MPEG4) |
1574 | 1596 | || !strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AAC)) { |
1575 | - uint32_t type; | |
1576 | - const void *data; | |
1577 | - size_t size; | |
1578 | 1597 | if (mMeta->findData(kKeyESDS, &type, &data, &size)) { |
1579 | 1598 | ESDS esds(data, size); |
1580 | - if (esds.getCodecSpecificInfo(&data, &size) == OK) { | |
1581 | - mCodecSpecificData = malloc(size); | |
1582 | - mCodecSpecificDataSize = size; | |
1583 | - memcpy(mCodecSpecificData, data, size); | |
1584 | - mGotAllCodecSpecificData = true; | |
1599 | + if (esds.getCodecSpecificInfo(&data, &size) != OK) { | |
1600 | + data = NULL; | |
1601 | + size = 0; | |
1585 | 1602 | } |
1586 | 1603 | } |
1587 | 1604 | } |
1605 | + if (data != NULL && copyCodecSpecificData((uint8_t *)data, size) == OK) { | |
1606 | + mGotAllCodecSpecificData = true; | |
1607 | + } | |
1588 | 1608 | } |
1589 | 1609 | |
1590 | 1610 | MPEG4Writer::Track::~Track() { |
@@ -1661,7 +1681,7 @@ void MPEG4Writer::writeChunkToFile(Chunk* chunk) { | ||
1661 | 1681 | while (!chunk->mSamples.empty()) { |
1662 | 1682 | List |
1663 | 1683 | |
1664 | - off64_t offset = chunk->mTrack->isAvc() | |
1684 | + off64_t offset = (chunk->mTrack->isAvc() || chunk->mTrack->isHevc()) | |
1665 | 1685 | ? addLengthPrefixedSample_l(*it) |
1666 | 1686 | : addSample_l(*it); |
1667 | 1687 |
@@ -1968,13 +1988,30 @@ status_t MPEG4Writer::Track::copyAVCCodecSpecificData( | ||
1968 | 1988 | |
1969 | 1989 | // 2 bytes for each of the parameter set length field |
1970 | 1990 | // plus the 7 bytes for the header |
1971 | - if (size < 4 + 7) { | |
1991 | + return copyCodecSpecificData(data, size, 4 + 7); | |
1992 | +} | |
1993 | + | |
1994 | +status_t MPEG4Writer::Track::copyHEVCCodecSpecificData( | |
1995 | + const uint8_t *data, size_t size) { | |
1996 | + ALOGV("copyHEVCCodecSpecificData"); | |
1997 | + | |
1998 | + // Min length of HEVC CSD is 23. (ISO/IEC 14496-15:2014 Chapter 8.3.3.1.2) | |
1999 | + return copyCodecSpecificData(data, size, 23); | |
2000 | +} | |
2001 | + | |
2002 | +status_t MPEG4Writer::Track::copyCodecSpecificData( | |
2003 | + const uint8_t *data, size_t size, size_t minLength) { | |
2004 | + if (size < minLength) { | |
1972 | 2005 | ALOGE("Codec specific data length too short: %zu", size); |
1973 | 2006 | return ERROR_MALFORMED; |
1974 | 2007 | } |
1975 | 2008 | |
1976 | - mCodecSpecificDataSize = size; | |
1977 | 2009 | mCodecSpecificData = malloc(size); |
2010 | + if (mCodecSpecificData == NULL) { | |
2011 | + ALOGE("Failed allocating codec specific data"); | |
2012 | + return NO_MEMORY; | |
2013 | + } | |
2014 | + mCodecSpecificDataSize = size; | |
1978 | 2015 | memcpy(mCodecSpecificData, data, size); |
1979 | 2016 | return OK; |
1980 | 2017 | } |
@@ -2097,6 +2134,11 @@ status_t MPEG4Writer::Track::makeAVCCodecSpecificData( | ||
2097 | 2134 | // ISO 14496-15: AVC file format |
2098 | 2135 | mCodecSpecificDataSize += 7; // 7 more bytes in the header |
2099 | 2136 | mCodecSpecificData = malloc(mCodecSpecificDataSize); |
2137 | + if (mCodecSpecificData == NULL) { | |
2138 | + mCodecSpecificDataSize = 0; | |
2139 | + ALOGE("Failed allocating codec specific data"); | |
2140 | + return NO_MEMORY; | |
2141 | + } | |
2100 | 2142 | uint8_t *header = (uint8_t *)mCodecSpecificData; |
2101 | 2143 | header[0] = 1; // version |
2102 | 2144 | header[1] = mProfileIdc; // profile indication |
@@ -2145,6 +2187,96 @@ status_t MPEG4Writer::Track::makeAVCCodecSpecificData( | ||
2145 | 2187 | return OK; |
2146 | 2188 | } |
2147 | 2189 | |
2190 | + | |
2191 | +status_t MPEG4Writer::Track::parseHEVCCodecSpecificData( | |
2192 | + const uint8_t *data, size_t size, HevcParameterSets ¶mSets) { | |
2193 | + | |
2194 | + ALOGV("parseHEVCCodecSpecificData"); | |
2195 | + const uint8_t *tmp = data; | |
2196 | + const uint8_t *nextStartCode = data; | |
2197 | + size_t bytesLeft = size; | |
2198 | + while (bytesLeft > 4 && !memcmp("\x00\x00\x00\x01", tmp, 4)) { | |
2199 | + nextStartCode = findNextStartCode(tmp + 4, bytesLeft - 4); | |
2200 | + if (nextStartCode == NULL) { | |
2201 | + return ERROR_MALFORMED; | |
2202 | + } | |
2203 | + status_t err = paramSets.addNalUnit(tmp + 4, (nextStartCode - tmp) - 4); | |
2204 | + if (err != OK) { | |
2205 | + return ERROR_MALFORMED; | |
2206 | + } | |
2207 | + | |
2208 | + // Move on to find the next parameter set | |
2209 | + bytesLeft -= nextStartCode - tmp; | |
2210 | + tmp = nextStartCode; | |
2211 | + } | |
2212 | + | |
2213 | + size_t csdSize = 23; | |
2214 | + const size_t numNalUnits = paramSets.getNumNalUnits(); | |
2215 | + for (size_t i = 0; i < ARRAY_SIZE(kMandatoryHevcNalUnitTypes); ++i) { | |
2216 | + int type = kMandatoryHevcNalUnitTypes[i]; | |
2217 | + size_t numParamSets = paramSets.getNumNalUnitsOfType(type); | |
2218 | + if (numParamSets == 0) { | |
2219 | + ALOGE("Cound not find NAL unit of type %d", type); | |
2220 | + return ERROR_MALFORMED; | |
2221 | + } | |
2222 | + } | |
2223 | + for (size_t i = 0; i < ARRAY_SIZE(kHevcNalUnitTypes); ++i) { | |
2224 | + int type = kHevcNalUnitTypes[i]; | |
2225 | + size_t numParamSets = paramSets.getNumNalUnitsOfType(type); | |
2226 | + if (numParamSets > 0xffff) { | |
2227 | + ALOGE("Too many seq parameter sets (%zu) found", numParamSets); | |
2228 | + return ERROR_MALFORMED; | |
2229 | + } | |
2230 | + csdSize += 3; | |
2231 | + for (size_t j = 0; j < numNalUnits; ++j) { | |
2232 | + if (paramSets.getType(j) != type) { | |
2233 | + continue; | |
2234 | + } | |
2235 | + csdSize += 2 + paramSets.getSize(j); | |
2236 | + } | |
2237 | + } | |
2238 | + mCodecSpecificDataSize = csdSize; | |
2239 | + return OK; | |
2240 | +} | |
2241 | + | |
2242 | +status_t MPEG4Writer::Track::makeHEVCCodecSpecificData( | |
2243 | + const uint8_t *data, size_t size) { | |
2244 | + | |
2245 | + if (mCodecSpecificData != NULL) { | |
2246 | + ALOGE("Already have codec specific data"); | |
2247 | + return ERROR_MALFORMED; | |
2248 | + } | |
2249 | + | |
2250 | + if (size < 4) { | |
2251 | + ALOGE("Codec specific data length too short: %zu", size); | |
2252 | + return ERROR_MALFORMED; | |
2253 | + } | |
2254 | + | |
2255 | + // Data is in the form of HEVCCodecSpecificData | |
2256 | + if (memcmp("\x00\x00\x00\x01", data, 4)) { | |
2257 | + return copyHEVCCodecSpecificData(data, size); | |
2258 | + } | |
2259 | + | |
2260 | + HevcParameterSets paramSets; | |
2261 | + if (parseHEVCCodecSpecificData(data, size, paramSets) != OK) { | |
2262 | + return ERROR_MALFORMED; | |
2263 | + } | |
2264 | + | |
2265 | + mCodecSpecificData = malloc(mCodecSpecificDataSize); | |
2266 | + if (mCodecSpecificData == NULL) { | |
2267 | + mCodecSpecificDataSize = 0; | |
2268 | + ALOGE("Failed allocating codec specific data"); | |
2269 | + return NO_MEMORY; | |
2270 | + } | |
2271 | + status_t err = paramSets.makeHvcc((uint8_t *)mCodecSpecificData, | |
2272 | + &mCodecSpecificDataSize, mOwner->useNalLengthFour() ? 5 : 2); | |
2273 | + if (err != OK) { | |
2274 | + return err; | |
2275 | + } | |
2276 | + | |
2277 | + return OK; | |
2278 | +} | |
2279 | + | |
2148 | 2280 | /* |
2149 | 2281 | * Updates the drift time from the audio track so that |
2150 | 2282 | * the video track can get the updated drift time information |
@@ -2228,13 +2360,15 @@ status_t MPEG4Writer::Track::threadEntry() { | ||
2228 | 2360 | + buffer->range_offset(), |
2229 | 2361 | buffer->range_length()); |
2230 | 2362 | CHECK_EQ((status_t)OK, err); |
2231 | - } else if (mIsMPEG4) { | |
2232 | - mCodecSpecificDataSize = buffer->range_length(); | |
2233 | - mCodecSpecificData = malloc(mCodecSpecificDataSize); | |
2234 | - memcpy(mCodecSpecificData, | |
2363 | + } else if (mIsHevc) { | |
2364 | + status_t err = makeHEVCCodecSpecificData( | |
2235 | 2365 | (const uint8_t *)buffer->data() |
2236 | 2366 | + buffer->range_offset(), |
2237 | - buffer->range_length()); | |
2367 | + buffer->range_length()); | |
2368 | + CHECK_EQ((status_t)OK, err); | |
2369 | + } else if (mIsMPEG4) { | |
2370 | + copyCodecSpecificData((const uint8_t *)buffer->data() + buffer->range_offset(), | |
2371 | + buffer->range_length()); | |
2238 | 2372 | } |
2239 | 2373 | |
2240 | 2374 | buffer->release(); |
@@ -2254,10 +2388,10 @@ status_t MPEG4Writer::Track::threadEntry() { | ||
2254 | 2388 | buffer->release(); |
2255 | 2389 | buffer = NULL; |
2256 | 2390 | |
2257 | - if (mIsAvc) StripStartcode(copy); | |
2391 | + if (mIsAvc || mIsHevc) StripStartcode(copy); | |
2258 | 2392 | |
2259 | 2393 | size_t sampleSize = copy->range_length(); |
2260 | - if (mIsAvc) { | |
2394 | + if (mIsAvc || mIsHevc) { | |
2261 | 2395 | if (mOwner->useNalLengthFour()) { |
2262 | 2396 | sampleSize += 4; |
2263 | 2397 | } else { |
@@ -2457,7 +2591,7 @@ status_t MPEG4Writer::Track::threadEntry() { | ||
2457 | 2591 | trackProgressStatus(timestampUs); |
2458 | 2592 | } |
2459 | 2593 | if (!hasMultipleTracks) { |
2460 | - off64_t offset = mIsAvc? mOwner->addLengthPrefixedSample_l(copy) | |
2594 | + off64_t offset = (mIsAvc || mIsHevc) ? mOwner->addLengthPrefixedSample_l(copy) | |
2461 | 2595 | : mOwner->addSample_l(copy); |
2462 | 2596 | |
2463 | 2597 | uint32_t count = (mOwner->use32BitFileOffset() |
@@ -2709,7 +2843,8 @@ status_t MPEG4Writer::Track::checkCodecSpecificData() const { | ||
2709 | 2843 | CHECK(mMeta->findCString(kKeyMIMEType, &mime)); |
2710 | 2844 | if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_AAC, mime) || |
2711 | 2845 | !strcasecmp(MEDIA_MIMETYPE_VIDEO_MPEG4, mime) || |
2712 | - !strcasecmp(MEDIA_MIMETYPE_VIDEO_AVC, mime)) { | |
2846 | + !strcasecmp(MEDIA_MIMETYPE_VIDEO_AVC, mime) || | |
2847 | + !strcasecmp(MEDIA_MIMETYPE_VIDEO_HEVC, mime)) { | |
2713 | 2848 | if (!mCodecSpecificData || |
2714 | 2849 | mCodecSpecificDataSize <= 0) { |
2715 | 2850 | ALOGE("Missing codec specific data"); |
@@ -2815,6 +2950,8 @@ void MPEG4Writer::Track::writeVideoFourCCBox() { | ||
2815 | 2950 | writeD263Box(); |
2816 | 2951 | } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_AVC, mime)) { |
2817 | 2952 | writeAvccBox(); |
2953 | + } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_HEVC, mime)) { | |
2954 | + writeHvccBox(); | |
2818 | 2955 | } |
2819 | 2956 | |
2820 | 2957 | writePaspBox(); |
@@ -3070,6 +3207,20 @@ void MPEG4Writer::Track::writeAvccBox() { | ||
3070 | 3207 | mOwner->endBox(); // avcC |
3071 | 3208 | } |
3072 | 3209 | |
3210 | + | |
3211 | +void MPEG4Writer::Track::writeHvccBox() { | |
3212 | + CHECK(mCodecSpecificData); | |
3213 | + CHECK_GE(mCodecSpecificDataSize, 5); | |
3214 | + | |
3215 | + // Patch avcc's lengthSize field to match the number | |
3216 | + // of bytes we use to indicate the size of a nal unit. | |
3217 | + uint8_t *ptr = (uint8_t *)mCodecSpecificData; | |
3218 | + ptr[21] = (ptr[21] & 0xfc) | (mOwner->useNalLengthFour() ? 3 : 1); | |
3219 | + mOwner->beginBox("hvcC"); | |
3220 | + mOwner->write(mCodecSpecificData, mCodecSpecificDataSize); | |
3221 | + mOwner->endBox(); // hvcC | |
3222 | +} | |
3223 | + | |
3073 | 3224 | void MPEG4Writer::Track::writeD263Box() { |
3074 | 3225 | mOwner->beginBox("d263"); |
3075 | 3226 | mOwner->writeInt32(0); // vendor |
@@ -22,6 +22,7 @@ | ||
22 | 22 | #include |
23 | 23 | |
24 | 24 | #include "include/ESDS.h" |
25 | +#include "include/HevcUtils.h" | |
25 | 26 | |
26 | 27 | #include |
27 | 28 | #include |
@@ -575,6 +576,41 @@ static void reassembleESDS(const sp |
||
575 | 576 | |
576 | 577 | } |
577 | 578 | |
579 | +static size_t reassembleHVCC(const sp |
|
580 | + HevcParameterSets paramSets; | |
581 | + uint8_t* data = csd0->data(); | |
582 | + if (csd0->size() < 4) { | |
583 | + ALOGE("csd0 too small"); | |
584 | + return 0; | |
585 | + } | |
586 | + if (memcmp(data, "\x00\x00\x00\x01", 4) != 0) { | |
587 | + ALOGE("csd0 doesn't start with a start code"); | |
588 | + return 0; | |
589 | + } | |
590 | + size_t prevNalOffset = 4; | |
591 | + status_t err = OK; | |
592 | + for (size_t i = 1; i < csd0->size() - 4; ++i) { | |
593 | + if (memcmp(&data[i], "\x00\x00\x00\x01", 4) != 0) { | |
594 | + continue; | |
595 | + } | |
596 | + err = paramSets.addNalUnit(&data[prevNalOffset], i - prevNalOffset); | |
597 | + if (err != OK) { | |
598 | + return 0; | |
599 | + } | |
600 | + prevNalOffset = i + 4; | |
601 | + } | |
602 | + err = paramSets.addNalUnit(&data[prevNalOffset], csd0->size() - prevNalOffset); | |
603 | + if (err != OK) { | |
604 | + return 0; | |
605 | + } | |
606 | + size_t size = hvccSize; | |
607 | + err = paramSets.makeHvcc(hvcc, &size, nalSizeLength); | |
608 | + if (err != OK) { | |
609 | + return 0; | |
610 | + } | |
611 | + return size; | |
612 | +} | |
613 | + | |
578 | 614 | void convertMessageToMetaData(const sp |
579 | 615 | AString mime; |
580 | 616 | if (msg->findString("mime", &mime)) { |
@@ -693,6 +729,10 @@ void convertMessageToMetaData(const sp |
||
693 | 729 | // for transporting the CSD to muxers. |
694 | 730 | reassembleESDS(csd0, esds); |
695 | 731 | meta->setData(kKeyESDS, kKeyESDS, esds, sizeof(esds)); |
732 | + } else if (mime == MEDIA_MIMETYPE_VIDEO_HEVC) { | |
733 | + uint8_t hvcc[1024]; // that oughta be enough, right? | |
734 | + size_t outsize = reassembleHVCC(csd0, hvcc, 1024, 4); | |
735 | + meta->setData(kKeyHVCC, kKeyHVCC, hvcc, outsize); | |
696 | 736 | } |
697 | 737 | } |
698 | 738 |
@@ -0,0 +1,93 @@ | ||
1 | +/* | |
2 | + * Copyright (C) 2015 The Android Open Source Project | |
3 | + * | |
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | |
5 | + * you may not use this file except in compliance with the License. | |
6 | + * You may obtain a copy of the License at | |
7 | + * | |
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | |
9 | + * | |
10 | + * Unless required by applicable law or agreed to in writing, software | |
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | |
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
13 | + * See the License for the specific language governing permissions and | |
14 | + * limitations under the License. | |
15 | + */ | |
16 | + | |
17 | +#ifndef HEVC_UTILS_H_ | |
18 | + | |
19 | +#define HEVC_UTILS_H_ | |
20 | + | |
21 | +#include |
|
22 | + | |
23 | +#include |
|
24 | +#include |
|
25 | +#include |
|
26 | +#include |
|
27 | +#include |
|
28 | +#include |
|
29 | + | |
30 | +namespace android { | |
31 | + | |
32 | +enum { | |
33 | + kHevcNalUnitTypeVps = 32, | |
34 | + kHevcNalUnitTypeSps = 33, | |
35 | + kHevcNalUnitTypePps = 34, | |
36 | + kHevcNalUnitTypePrefixSei = 39, | |
37 | + kHevcNalUnitTypeSuffixSei = 40, | |
38 | +}; | |
39 | + | |
40 | +enum { | |
41 | + // uint8_t | |
42 | + kGeneralProfileSpace, | |
43 | + // uint8_t | |
44 | + kGeneralTierFlag, | |
45 | + // uint8_t | |
46 | + kGeneralProfileIdc, | |
47 | + // uint32_t | |
48 | + kGeneralProfileCompatibilityFlags, | |
49 | + // uint64_t | |
50 | + kGeneralConstraintIndicatorFlags, | |
51 | + // uint8_t | |
52 | + kGeneralLevelIdc, | |
53 | + // uint8_t | |
54 | + kChromaFormatIdc, | |
55 | + // uint8_t | |
56 | + kBitDepthLumaMinus8, | |
57 | + // uint8_t | |
58 | + kBitDepthChromaMinus8, | |
59 | +}; | |
60 | + | |
61 | +class HevcParameterSets { | |
62 | +public: | |
63 | + HevcParameterSets(); | |
64 | + | |
65 | + status_t addNalUnit(const uint8_t* data, size_t size); | |
66 | + | |
67 | + bool findParam8(uint32_t key, uint8_t *param); | |
68 | + bool findParam16(uint32_t key, uint16_t *param); | |
69 | + bool findParam32(uint32_t key, uint32_t *param); | |
70 | + bool findParam64(uint32_t key, uint64_t *param); | |
71 | + | |
72 | + inline size_t getNumNalUnits() { return mNalUnits.size(); } | |
73 | + size_t getNumNalUnitsOfType(uint8_t type); | |
74 | + uint8_t getType(size_t index); | |
75 | + size_t getSize(size_t index); | |
76 | + // Note that this method does not write the start code. | |
77 | + bool write(size_t index, uint8_t* dest, size_t size); | |
78 | + status_t makeHvcc(uint8_t *hvcc, size_t *hvccSize, size_t nalSizeLength); | |
79 | + | |
80 | +private: | |
81 | + status_t parseVps(const uint8_t* data, size_t size); | |
82 | + status_t parseSps(const uint8_t* data, size_t size); | |
83 | + status_t parsePps(const uint8_t* data, size_t size); | |
84 | + | |
85 | + KeyedVector |
|
86 | + Vector |
|
87 | + | |
88 | + DISALLOW_EVIL_CONSTRUCTORS(HevcParameterSets); | |
89 | +}; | |
90 | + | |
91 | +} // namespace android | |
92 | + | |
93 | +#endif // HEVC_UTILS_H_ |