1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/content/media/omx/OMXCodecDescriptorUtil.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,205 @@ 1.4 +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-*/ 1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this file, 1.7 + * You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.8 + 1.9 +#include "OMXCodecDescriptorUtil.h" 1.10 + 1.11 +namespace android { 1.12 + 1.13 +// The utility functions in this file concatenate two AVC/H.264 parameter sets, 1.14 +// sequence parameter set(SPS) and picture parameter set(PPS), into byte stream 1.15 +// format or construct AVC decoder config descriptor blob from them. 1.16 +// 1.17 +// * NAL unit defined in ISO/IEC 14496-10 7.3.1 1.18 +// * SPS defined ISO/IEC 14496-10 7.3.2.1.1 1.19 +// * PPS defined in ISO/IEC 14496-10 7.3.2.2 1.20 +// 1.21 +// Byte stream format: 1.22 +// Start code <0x00 0x00 0x00 0x01> (4 bytes) 1.23 +// --- (SPS) NAL unit --- 1.24 +// ... (3 bits) 1.25 +// NAL unit type <0x07> (5 bits) 1.26 +// SPS (3+ bytes) 1.27 +// Profile (1 byte) 1.28 +// Compatible profiles (1 byte) 1.29 +// Level (1 byte) 1.30 +// ... 1.31 +// --- End --- 1.32 +// Start code <0x00 0x00 0x00 0x01> (4 bytes) 1.33 +// --- (PPS) NAL unit --- 1.34 +// ... (3 bits) 1.35 +// NAL unit type <0x08> (5 bits) 1.36 +// PPS (1+ bytes) 1.37 +// ... 1.38 +// --- End --- 1.39 +// 1.40 +// Descriptor format: (defined in ISO/IEC 14496-15 5.2.4.1.1) 1.41 +// --- Header (5 bytes) --- 1.42 +// Version <0x01> (1 byte) 1.43 +// Profile (1 byte) 1.44 +// Compatible profiles (1 byte) 1.45 +// Level (1 byte) 1.46 +// Reserved <111111> (6 bits) 1.47 +// NAL length type (2 bits) 1.48 +// --- Parameter sets --- 1.49 +// Reserved <111> (3 bits) 1.50 +// Number of SPS (5 bits) 1.51 +// SPS (3+ bytes) 1.52 +// Length (2 bytes) 1.53 +// SPS NAL unit (1+ bytes) 1.54 +// ... 1.55 +// Number of PPS (1 byte) 1.56 +// PPS (3+ bytes) 1.57 +// Length (2 bytes) 1.58 +// PPS NAL unit (1+ bytes) 1.59 +// ... 1.60 +// --- End --- 1.61 + 1.62 +// NAL unit start code. 1.63 +static const uint8_t kNALUnitStartCode[] = { 0x00, 0x00, 0x00, 0x01 }; 1.64 + 1.65 +// NAL unit types. 1.66 +enum { 1.67 + kNALUnitTypeSPS = 0x07, // Value for sequence parameter set. 1.68 + kNALUnitTypePPS = 0x08, // Value for picture parameter set. 1.69 + kNALUnitTypeBad = -1, // Malformed data. 1.70 +}; 1.71 + 1.72 +// Sequence parameter set or picture parameter set. 1.73 +struct AVCParamSet { 1.74 + AVCParamSet(const uint8_t* aPtr, const size_t aSize) 1.75 + : mPtr(aPtr) 1.76 + , mSize(aSize) 1.77 + { 1.78 + MOZ_ASSERT(mPtr && mSize > 0); 1.79 + } 1.80 + 1.81 + size_t Size() { 1.82 + return mSize + 2; // 2 more bytes for length value. 1.83 + } 1.84 + 1.85 + // Append 2 bytes length value and NAL unit bitstream to aOutputBuf. 1.86 + void AppendTo(nsTArray<uint8_t>* aOutputBuf) 1.87 + { 1.88 + // 2 bytes length value. 1.89 + uint8_t size[] = { 1.90 + (mSize & 0xFF00) >> 8, // MSB. 1.91 + mSize & 0x00FF, // LSB. 1.92 + }; 1.93 + aOutputBuf->AppendElements(size, sizeof(size)); 1.94 + 1.95 + aOutputBuf->AppendElements(mPtr, mSize); 1.96 + } 1.97 + 1.98 + const uint8_t* mPtr; // Pointer to NAL unit. 1.99 + const size_t mSize; // NAL unit length in bytes. 1.100 +}; 1.101 + 1.102 +// Convert SPS and PPS data into decoder config descriptor blob. The generated 1.103 +// blob will be appended to aOutputBuf. 1.104 +static status_t 1.105 +ConvertParamSetsToDescriptorBlob(sp<ABuffer>& aSPS, sp<ABuffer>& aPPS, 1.106 + nsTArray<uint8_t>* aOutputBuf) 1.107 +{ 1.108 + // Strip start code in the input. 1.109 + AVCParamSet sps(aSPS->data() + sizeof(kNALUnitStartCode), 1.110 + aSPS->size() - sizeof(kNALUnitStartCode)); 1.111 + AVCParamSet pps(aPPS->data() + sizeof(kNALUnitStartCode), 1.112 + aPPS->size() - sizeof(kNALUnitStartCode)); 1.113 + size_t paramSetsSize = sps.Size() + pps.Size(); 1.114 + 1.115 + // Profile/level info in SPS. 1.116 + uint8_t* info = aSPS->data() + 5; 1.117 + 1.118 + uint8_t header[] = { 1.119 + 0x01, // Version. 1.120 + info[0], // Profile. 1.121 + info[1], // Compatible profiles. 1.122 + info[2], // Level. 1.123 + 0xFF, // 6 bits reserved value <111111> + 2 bits NAL length type <11> 1.124 + }; 1.125 + 1.126 + // Reserve 1 byte for number of SPS & another 1 for number of PPS. 1.127 + aOutputBuf->SetCapacity(sizeof(header) + paramSetsSize + 2); 1.128 + // Build the blob. 1.129 + aOutputBuf->AppendElements(header, sizeof(header)); // 5 bytes Header. 1.130 + aOutputBuf->AppendElement(0xE0 | 1); // 3 bits <111> + 5 bits number of SPS. 1.131 + sps.AppendTo(aOutputBuf); // SPS NALU data. 1.132 + aOutputBuf->AppendElement(1); // 1 byte number of PPS. 1.133 + pps.AppendTo(aOutputBuf); // PPS NALU data. 1.134 + 1.135 + return OK; 1.136 +} 1.137 + 1.138 +static int 1.139 +NALType(sp<ABuffer>& aBuffer) 1.140 +{ 1.141 + if (aBuffer == nullptr) { 1.142 + return kNALUnitTypeBad; 1.143 + } 1.144 + // Start code? 1.145 + uint8_t* data = aBuffer->data(); 1.146 + if (aBuffer->size() <= 4 || 1.147 + memcmp(data, kNALUnitStartCode, sizeof(kNALUnitStartCode))) { 1.148 + return kNALUnitTypeBad; 1.149 + } 1.150 + 1.151 + return data[4] & 0x1F; 1.152 +} 1.153 + 1.154 +// Generate AVC/H.264 decoder config blob. 1.155 +// See MPEG4Writer::Track::makeAVCCodecSpecificData() and 1.156 +// MPEG4Writer::Track::writeAvccBox() implementation in libstagefright. 1.157 +status_t 1.158 +GenerateAVCDescriptorBlob(sp<AMessage>& aConfigData, 1.159 + nsTArray<uint8_t>* aOutputBuf, 1.160 + OMXVideoEncoder::BlobFormat aFormat) 1.161 +{ 1.162 + // Search for parameter sets using key "csd-0" and "csd-1". 1.163 + char key[6] = "csd-"; 1.164 + sp<ABuffer> sps; 1.165 + sp<ABuffer> pps; 1.166 + for (int i = 0; i < 2; i++) { 1.167 + snprintf(key + 4, 2, "%d", i); 1.168 + sp<ABuffer> paramSet; 1.169 + bool found = aConfigData->findBuffer(key, ¶mSet); 1.170 + int type = NALType(paramSet); 1.171 + bool valid = ((type == kNALUnitTypeSPS) || (type == kNALUnitTypePPS)); 1.172 + 1.173 + MOZ_ASSERT(found && valid); 1.174 + if (!found || !valid) { 1.175 + return ERROR_MALFORMED; 1.176 + } 1.177 + 1.178 + switch (type) { 1.179 + case kNALUnitTypeSPS: 1.180 + sps = paramSet; 1.181 + break; 1.182 + case kNALUnitTypePPS: 1.183 + pps = paramSet; 1.184 + break; 1.185 + default: 1.186 + NS_NOTREACHED("Should not get here!"); 1.187 + } 1.188 + } 1.189 + 1.190 + MOZ_ASSERT(sps != nullptr && pps != nullptr); 1.191 + if (sps == nullptr || pps == nullptr) { 1.192 + return ERROR_MALFORMED; 1.193 + } 1.194 + 1.195 + status_t result = OK; 1.196 + if (aFormat == OMXVideoEncoder::BlobFormat::AVC_NAL) { 1.197 + // SPS + PPS. 1.198 + aOutputBuf->AppendElements(sps->data(), sps->size()); 1.199 + aOutputBuf->AppendElements(pps->data(), pps->size()); 1.200 + return OK; 1.201 + } else { 1.202 + status_t result = ConvertParamSetsToDescriptorBlob(sps, pps, aOutputBuf); 1.203 + MOZ_ASSERT(result == OK); 1.204 + return result; 1.205 + } 1.206 +} 1.207 + 1.208 +} // namespace android