Tue, 06 Jan 2015 21:39:09 +0100
Conditionally force memory storage according to privacy.thirdparty.isolate;
This solves Tor bug #9701, complying with disk avoidance documented in
https://www.torproject.org/projects/torbrowser/design/#disk-avoidance.
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, ¶mSet); |
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 |