content/media/omx/OMXCodecDescriptorUtil.cpp

Fri, 16 Jan 2015 04:50:19 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Fri, 16 Jan 2015 04:50:19 +0100
branch
TOR_BUG_9701
changeset 13
44a2da4a2ab2
permissions
-rw-r--r--

Replace accessor implementation with direct member state manipulation, by
request https://trac.torproject.org/projects/tor/ticket/9701#comment:32

michael@0 1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-*/
michael@0 2 /* This Source Code Form is subject to the terms of the Mozilla Public
michael@0 3 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
michael@0 4 * You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 5
michael@0 6 #include "OMXCodecDescriptorUtil.h"
michael@0 7
michael@0 8 namespace android {
michael@0 9
michael@0 10 // The utility functions in this file concatenate two AVC/H.264 parameter sets,
michael@0 11 // sequence parameter set(SPS) and picture parameter set(PPS), into byte stream
michael@0 12 // format or construct AVC decoder config descriptor blob from them.
michael@0 13 //
michael@0 14 // * NAL unit defined in ISO/IEC 14496-10 7.3.1
michael@0 15 // * SPS defined ISO/IEC 14496-10 7.3.2.1.1
michael@0 16 // * PPS defined in ISO/IEC 14496-10 7.3.2.2
michael@0 17 //
michael@0 18 // Byte stream format:
michael@0 19 // Start code <0x00 0x00 0x00 0x01> (4 bytes)
michael@0 20 // --- (SPS) NAL unit ---
michael@0 21 // ... (3 bits)
michael@0 22 // NAL unit type <0x07> (5 bits)
michael@0 23 // SPS (3+ bytes)
michael@0 24 // Profile (1 byte)
michael@0 25 // Compatible profiles (1 byte)
michael@0 26 // Level (1 byte)
michael@0 27 // ...
michael@0 28 // --- End ---
michael@0 29 // Start code <0x00 0x00 0x00 0x01> (4 bytes)
michael@0 30 // --- (PPS) NAL unit ---
michael@0 31 // ... (3 bits)
michael@0 32 // NAL unit type <0x08> (5 bits)
michael@0 33 // PPS (1+ bytes)
michael@0 34 // ...
michael@0 35 // --- End ---
michael@0 36 //
michael@0 37 // Descriptor format: (defined in ISO/IEC 14496-15 5.2.4.1.1)
michael@0 38 // --- Header (5 bytes) ---
michael@0 39 // Version <0x01> (1 byte)
michael@0 40 // Profile (1 byte)
michael@0 41 // Compatible profiles (1 byte)
michael@0 42 // Level (1 byte)
michael@0 43 // Reserved <111111> (6 bits)
michael@0 44 // NAL length type (2 bits)
michael@0 45 // --- Parameter sets ---
michael@0 46 // Reserved <111> (3 bits)
michael@0 47 // Number of SPS (5 bits)
michael@0 48 // SPS (3+ bytes)
michael@0 49 // Length (2 bytes)
michael@0 50 // SPS NAL unit (1+ bytes)
michael@0 51 // ...
michael@0 52 // Number of PPS (1 byte)
michael@0 53 // PPS (3+ bytes)
michael@0 54 // Length (2 bytes)
michael@0 55 // PPS NAL unit (1+ bytes)
michael@0 56 // ...
michael@0 57 // --- End ---
michael@0 58
michael@0 59 // NAL unit start code.
michael@0 60 static const uint8_t kNALUnitStartCode[] = { 0x00, 0x00, 0x00, 0x01 };
michael@0 61
michael@0 62 // NAL unit types.
michael@0 63 enum {
michael@0 64 kNALUnitTypeSPS = 0x07, // Value for sequence parameter set.
michael@0 65 kNALUnitTypePPS = 0x08, // Value for picture parameter set.
michael@0 66 kNALUnitTypeBad = -1, // Malformed data.
michael@0 67 };
michael@0 68
michael@0 69 // Sequence parameter set or picture parameter set.
michael@0 70 struct AVCParamSet {
michael@0 71 AVCParamSet(const uint8_t* aPtr, const size_t aSize)
michael@0 72 : mPtr(aPtr)
michael@0 73 , mSize(aSize)
michael@0 74 {
michael@0 75 MOZ_ASSERT(mPtr && mSize > 0);
michael@0 76 }
michael@0 77
michael@0 78 size_t Size() {
michael@0 79 return mSize + 2; // 2 more bytes for length value.
michael@0 80 }
michael@0 81
michael@0 82 // Append 2 bytes length value and NAL unit bitstream to aOutputBuf.
michael@0 83 void AppendTo(nsTArray<uint8_t>* aOutputBuf)
michael@0 84 {
michael@0 85 // 2 bytes length value.
michael@0 86 uint8_t size[] = {
michael@0 87 (mSize & 0xFF00) >> 8, // MSB.
michael@0 88 mSize & 0x00FF, // LSB.
michael@0 89 };
michael@0 90 aOutputBuf->AppendElements(size, sizeof(size));
michael@0 91
michael@0 92 aOutputBuf->AppendElements(mPtr, mSize);
michael@0 93 }
michael@0 94
michael@0 95 const uint8_t* mPtr; // Pointer to NAL unit.
michael@0 96 const size_t mSize; // NAL unit length in bytes.
michael@0 97 };
michael@0 98
michael@0 99 // Convert SPS and PPS data into decoder config descriptor blob. The generated
michael@0 100 // blob will be appended to aOutputBuf.
michael@0 101 static status_t
michael@0 102 ConvertParamSetsToDescriptorBlob(sp<ABuffer>& aSPS, sp<ABuffer>& aPPS,
michael@0 103 nsTArray<uint8_t>* aOutputBuf)
michael@0 104 {
michael@0 105 // Strip start code in the input.
michael@0 106 AVCParamSet sps(aSPS->data() + sizeof(kNALUnitStartCode),
michael@0 107 aSPS->size() - sizeof(kNALUnitStartCode));
michael@0 108 AVCParamSet pps(aPPS->data() + sizeof(kNALUnitStartCode),
michael@0 109 aPPS->size() - sizeof(kNALUnitStartCode));
michael@0 110 size_t paramSetsSize = sps.Size() + pps.Size();
michael@0 111
michael@0 112 // Profile/level info in SPS.
michael@0 113 uint8_t* info = aSPS->data() + 5;
michael@0 114
michael@0 115 uint8_t header[] = {
michael@0 116 0x01, // Version.
michael@0 117 info[0], // Profile.
michael@0 118 info[1], // Compatible profiles.
michael@0 119 info[2], // Level.
michael@0 120 0xFF, // 6 bits reserved value <111111> + 2 bits NAL length type <11>
michael@0 121 };
michael@0 122
michael@0 123 // Reserve 1 byte for number of SPS & another 1 for number of PPS.
michael@0 124 aOutputBuf->SetCapacity(sizeof(header) + paramSetsSize + 2);
michael@0 125 // Build the blob.
michael@0 126 aOutputBuf->AppendElements(header, sizeof(header)); // 5 bytes Header.
michael@0 127 aOutputBuf->AppendElement(0xE0 | 1); // 3 bits <111> + 5 bits number of SPS.
michael@0 128 sps.AppendTo(aOutputBuf); // SPS NALU data.
michael@0 129 aOutputBuf->AppendElement(1); // 1 byte number of PPS.
michael@0 130 pps.AppendTo(aOutputBuf); // PPS NALU data.
michael@0 131
michael@0 132 return OK;
michael@0 133 }
michael@0 134
michael@0 135 static int
michael@0 136 NALType(sp<ABuffer>& aBuffer)
michael@0 137 {
michael@0 138 if (aBuffer == nullptr) {
michael@0 139 return kNALUnitTypeBad;
michael@0 140 }
michael@0 141 // Start code?
michael@0 142 uint8_t* data = aBuffer->data();
michael@0 143 if (aBuffer->size() <= 4 ||
michael@0 144 memcmp(data, kNALUnitStartCode, sizeof(kNALUnitStartCode))) {
michael@0 145 return kNALUnitTypeBad;
michael@0 146 }
michael@0 147
michael@0 148 return data[4] & 0x1F;
michael@0 149 }
michael@0 150
michael@0 151 // Generate AVC/H.264 decoder config blob.
michael@0 152 // See MPEG4Writer::Track::makeAVCCodecSpecificData() and
michael@0 153 // MPEG4Writer::Track::writeAvccBox() implementation in libstagefright.
michael@0 154 status_t
michael@0 155 GenerateAVCDescriptorBlob(sp<AMessage>& aConfigData,
michael@0 156 nsTArray<uint8_t>* aOutputBuf,
michael@0 157 OMXVideoEncoder::BlobFormat aFormat)
michael@0 158 {
michael@0 159 // Search for parameter sets using key "csd-0" and "csd-1".
michael@0 160 char key[6] = "csd-";
michael@0 161 sp<ABuffer> sps;
michael@0 162 sp<ABuffer> pps;
michael@0 163 for (int i = 0; i < 2; i++) {
michael@0 164 snprintf(key + 4, 2, "%d", i);
michael@0 165 sp<ABuffer> paramSet;
michael@0 166 bool found = aConfigData->findBuffer(key, &paramSet);
michael@0 167 int type = NALType(paramSet);
michael@0 168 bool valid = ((type == kNALUnitTypeSPS) || (type == kNALUnitTypePPS));
michael@0 169
michael@0 170 MOZ_ASSERT(found && valid);
michael@0 171 if (!found || !valid) {
michael@0 172 return ERROR_MALFORMED;
michael@0 173 }
michael@0 174
michael@0 175 switch (type) {
michael@0 176 case kNALUnitTypeSPS:
michael@0 177 sps = paramSet;
michael@0 178 break;
michael@0 179 case kNALUnitTypePPS:
michael@0 180 pps = paramSet;
michael@0 181 break;
michael@0 182 default:
michael@0 183 NS_NOTREACHED("Should not get here!");
michael@0 184 }
michael@0 185 }
michael@0 186
michael@0 187 MOZ_ASSERT(sps != nullptr && pps != nullptr);
michael@0 188 if (sps == nullptr || pps == nullptr) {
michael@0 189 return ERROR_MALFORMED;
michael@0 190 }
michael@0 191
michael@0 192 status_t result = OK;
michael@0 193 if (aFormat == OMXVideoEncoder::BlobFormat::AVC_NAL) {
michael@0 194 // SPS + PPS.
michael@0 195 aOutputBuf->AppendElements(sps->data(), sps->size());
michael@0 196 aOutputBuf->AppendElements(pps->data(), pps->size());
michael@0 197 return OK;
michael@0 198 } else {
michael@0 199 status_t result = ConvertParamSetsToDescriptorBlob(sps, pps, aOutputBuf);
michael@0 200 MOZ_ASSERT(result == OK);
michael@0 201 return result;
michael@0 202 }
michael@0 203 }
michael@0 204
michael@0 205 } // namespace android

mercurial