1/* 2 * Copyright (C) 2010 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#include "include/avc_utils.h" 18 19#include <media/stagefright/foundation/ABitReader.h> 20#include <media/stagefright/foundation/ADebug.h> 21#include <media/stagefright/MediaDefs.h> 22#include <media/stagefright/MediaErrors.h> 23#include <media/stagefright/MetaData.h> 24 25namespace android { 26 27unsigned parseUE(ABitReader *br) { 28 unsigned numZeroes = 0; 29 while (br->getBits(1) == 0) { 30 ++numZeroes; 31 } 32 33 unsigned x = br->getBits(numZeroes); 34 35 return x + (1u << numZeroes) - 1; 36} 37 38// Determine video dimensions from the sequence parameterset. 39void FindAVCDimensions( 40 const sp<ABuffer> &seqParamSet, int32_t *width, int32_t *height) { 41 ABitReader br(seqParamSet->data() + 1, seqParamSet->size() - 1); 42 43 unsigned profile_idc = br.getBits(8); 44 br.skipBits(16); 45 parseUE(&br); // seq_parameter_set_id 46 47 unsigned chroma_format_idc = 1; // 4:2:0 chroma format 48 49 if (profile_idc == 100 || profile_idc == 110 50 || profile_idc == 122 || profile_idc == 244 51 || profile_idc == 44 || profile_idc == 83 || profile_idc == 86) { 52 chroma_format_idc = parseUE(&br); 53 if (chroma_format_idc == 3) { 54 br.skipBits(1); // residual_colour_transform_flag 55 } 56 parseUE(&br); // bit_depth_luma_minus8 57 parseUE(&br); // bit_depth_chroma_minus8 58 br.skipBits(1); // qpprime_y_zero_transform_bypass_flag 59 CHECK_EQ(br.getBits(1), 0u); // seq_scaling_matrix_present_flag 60 } 61 62 parseUE(&br); // log2_max_frame_num_minus4 63 unsigned pic_order_cnt_type = parseUE(&br); 64 65 if (pic_order_cnt_type == 0) { 66 parseUE(&br); // log2_max_pic_order_cnt_lsb_minus4 67 } else if (pic_order_cnt_type == 1) { 68 // offset_for_non_ref_pic, offset_for_top_to_bottom_field and 69 // offset_for_ref_frame are technically se(v), but since we are 70 // just skipping over them the midpoint does not matter. 71 72 br.getBits(1); // delta_pic_order_always_zero_flag 73 parseUE(&br); // offset_for_non_ref_pic 74 parseUE(&br); // offset_for_top_to_bottom_field 75 76 unsigned num_ref_frames_in_pic_order_cnt_cycle = parseUE(&br); 77 for (unsigned i = 0; i < num_ref_frames_in_pic_order_cnt_cycle; ++i) { 78 parseUE(&br); // offset_for_ref_frame 79 } 80 } 81 82 parseUE(&br); // num_ref_frames 83 br.getBits(1); // gaps_in_frame_num_value_allowed_flag 84 85 unsigned pic_width_in_mbs_minus1 = parseUE(&br); 86 unsigned pic_height_in_map_units_minus1 = parseUE(&br); 87 unsigned frame_mbs_only_flag = br.getBits(1); 88 89 *width = pic_width_in_mbs_minus1 * 16 + 16; 90 91 *height = (2 - frame_mbs_only_flag) 92 * (pic_height_in_map_units_minus1 * 16 + 16); 93 94 if (!frame_mbs_only_flag) { 95 br.getBits(1); // mb_adaptive_frame_field_flag 96 } 97 98 br.getBits(1); // direct_8x8_inference_flag 99 100 if (br.getBits(1)) { // frame_cropping_flag 101 unsigned frame_crop_left_offset = parseUE(&br); 102 unsigned frame_crop_right_offset = parseUE(&br); 103 unsigned frame_crop_top_offset = parseUE(&br); 104 unsigned frame_crop_bottom_offset = parseUE(&br); 105 106 unsigned cropUnitX, cropUnitY; 107 if (chroma_format_idc == 0 /* monochrome */) { 108 cropUnitX = 1; 109 cropUnitY = 2 - frame_mbs_only_flag; 110 } else { 111 unsigned subWidthC = (chroma_format_idc == 3) ? 1 : 2; 112 unsigned subHeightC = (chroma_format_idc == 1) ? 2 : 1; 113 114 cropUnitX = subWidthC; 115 cropUnitY = subHeightC * (2 - frame_mbs_only_flag); 116 } 117 118 LOGV("frame_crop = (%u, %u, %u, %u), cropUnitX = %u, cropUnitY = %u", 119 frame_crop_left_offset, frame_crop_right_offset, 120 frame_crop_top_offset, frame_crop_bottom_offset, 121 cropUnitX, cropUnitY); 122 123 *width -= 124 (frame_crop_left_offset + frame_crop_right_offset) * cropUnitX; 125 *height -= 126 (frame_crop_top_offset + frame_crop_bottom_offset) * cropUnitY; 127 } 128} 129 130status_t getNextNALUnit( 131 const uint8_t **_data, size_t *_size, 132 const uint8_t **nalStart, size_t *nalSize, 133 bool startCodeFollows) { 134 const uint8_t *data = *_data; 135 size_t size = *_size; 136 137 *nalStart = NULL; 138 *nalSize = 0; 139 140 if (size == 0) { 141 return -EAGAIN; 142 } 143 144 // Skip any number of leading 0x00. 145 146 size_t offset = 0; 147 while (offset < size && data[offset] == 0x00) { 148 ++offset; 149 } 150 151 if (offset == size) { 152 return -EAGAIN; 153 } 154 155 // A valid startcode consists of at least two 0x00 bytes followed by 0x01. 156 157 if (offset < 2 || data[offset] != 0x01) { 158 return ERROR_MALFORMED; 159 } 160 161 ++offset; 162 163 size_t startOffset = offset; 164 165 for (;;) { 166 while (offset < size && data[offset] != 0x01) { 167 ++offset; 168 } 169 170 if (offset == size) { 171 if (startCodeFollows) { 172 offset = size + 2; 173 break; 174 } 175 176 return -EAGAIN; 177 } 178 179 if (data[offset - 1] == 0x00 && data[offset - 2] == 0x00) { 180 break; 181 } 182 183 ++offset; 184 } 185 186 size_t endOffset = offset - 2; 187 while (data[endOffset - 1] == 0x00) { 188 --endOffset; 189 } 190 191 *nalStart = &data[startOffset]; 192 *nalSize = endOffset - startOffset; 193 194 if (offset + 2 < size) { 195 *_data = &data[offset - 2]; 196 *_size = size - offset + 2; 197 } else { 198 *_data = NULL; 199 *_size = 0; 200 } 201 202 return OK; 203} 204 205static sp<ABuffer> FindNAL( 206 const uint8_t *data, size_t size, unsigned nalType, 207 size_t *stopOffset) { 208 const uint8_t *nalStart; 209 size_t nalSize; 210 while (getNextNALUnit(&data, &size, &nalStart, &nalSize, true) == OK) { 211 if ((nalStart[0] & 0x1f) == nalType) { 212 sp<ABuffer> buffer = new ABuffer(nalSize); 213 memcpy(buffer->data(), nalStart, nalSize); 214 return buffer; 215 } 216 } 217 218 return NULL; 219} 220 221sp<MetaData> MakeAVCCodecSpecificData(const sp<ABuffer> &accessUnit) { 222 const uint8_t *data = accessUnit->data(); 223 size_t size = accessUnit->size(); 224 225 sp<ABuffer> seqParamSet = FindNAL(data, size, 7, NULL); 226 if (seqParamSet == NULL) { 227 return NULL; 228 } 229 230 int32_t width, height; 231 FindAVCDimensions(seqParamSet, &width, &height); 232 233 size_t stopOffset; 234 sp<ABuffer> picParamSet = FindNAL(data, size, 8, &stopOffset); 235 CHECK(picParamSet != NULL); 236 237 size_t csdSize = 238 1 + 3 + 1 + 1 239 + 2 * 1 + seqParamSet->size() 240 + 1 + 2 * 1 + picParamSet->size(); 241 242 sp<ABuffer> csd = new ABuffer(csdSize); 243 uint8_t *out = csd->data(); 244 245 *out++ = 0x01; // configurationVersion 246 memcpy(out, seqParamSet->data() + 1, 3); // profile/level... 247 out += 3; 248 *out++ = (0x3f << 2) | 1; // lengthSize == 2 bytes 249 *out++ = 0xe0 | 1; 250 251 *out++ = seqParamSet->size() >> 8; 252 *out++ = seqParamSet->size() & 0xff; 253 memcpy(out, seqParamSet->data(), seqParamSet->size()); 254 out += seqParamSet->size(); 255 256 *out++ = 1; 257 258 *out++ = picParamSet->size() >> 8; 259 *out++ = picParamSet->size() & 0xff; 260 memcpy(out, picParamSet->data(), picParamSet->size()); 261 262#if 0 263 LOGI("AVC seq param set"); 264 hexdump(seqParamSet->data(), seqParamSet->size()); 265#endif 266 267 sp<MetaData> meta = new MetaData; 268 meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_AVC); 269 270 meta->setData(kKeyAVCC, 0, csd->data(), csd->size()); 271 meta->setInt32(kKeyWidth, width); 272 meta->setInt32(kKeyHeight, height); 273 274 LOGI("found AVC codec config (%d x %d)", width, height); 275 276 return meta; 277} 278 279bool IsIDR(const sp<ABuffer> &buffer) { 280 const uint8_t *data = buffer->data(); 281 size_t size = buffer->size(); 282 283 bool foundIDR = false; 284 285 const uint8_t *nalStart; 286 size_t nalSize; 287 while (getNextNALUnit(&data, &size, &nalStart, &nalSize, true) == OK) { 288 CHECK_GT(nalSize, 0u); 289 290 unsigned nalType = nalStart[0] & 0x1f; 291 292 if (nalType == 5) { 293 foundIDR = true; 294 break; 295 } 296 } 297 298 return foundIDR; 299} 300 301} // namespace android 302 303