content/media/omx/OMXCodecDescriptorUtil.cpp

changeset 0
6474c204b198
     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, &paramSet);
   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

mercurial