Bug 1540581 - P3. Add methods to extract color space and color depth from SPS NAL. r=bryce
authorJean-Yves Avenard <jyavenard@mozilla.com>
Thu, 11 Apr 2019 12:36:10 +0000
changeset 469131 961e937daf7bc23193924e4d16404cc2c11120c9
parent 469130 61c265181c16b1e0208bbafb6c6aa7acb6a33216
child 469132 9a4305ff9a2dd501279f98c01ea0609952c4b72c
push id35856
push usercsabou@mozilla.com
push dateFri, 12 Apr 2019 03:19:48 +0000
treeherdermozilla-central@940684cd1065 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbryce
bugs1540581
milestone68.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1540581 - P3. Add methods to extract color space and color depth from SPS NAL. r=bryce Differential Revision: https://phabricator.services.mozilla.com/D26056
dom/media/platforms/agnostic/bytestreams/H264.cpp
dom/media/platforms/agnostic/bytestreams/H264.h
--- a/dom/media/platforms/agnostic/bytestreams/H264.cpp
+++ b/dom/media/platforms/agnostic/bytestreams/H264.cpp
@@ -1,23 +1,23 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
-#include "mozilla/ArrayUtils.h"
-#include "mozilla/PodOperations.h"
-#include "mozilla/ResultExtensions.h"
+#include "H264.h"
+#include <cmath>
+#include <limits>
+#include "AnnexB.h"
 #include "BitReader.h"
 #include "BitWriter.h"
 #include "BufferReader.h"
 #include "ByteWriter.h"
-#include "AnnexB.h"
-#include "H264.h"
-#include <limits>
-#include <cmath>
+#include "mozilla/ArrayUtils.h"
+#include "mozilla/PodOperations.h"
+#include "mozilla/ResultExtensions.h"
 
 #define READSE(var, min, max)     \
   {                               \
     int32_t val = br.ReadSE();    \
     if (val < min || val > max) { \
       return false;               \
     }                             \
     aDest.var = val;              \
@@ -115,16 +115,215 @@ SPSData::SPSData() {
 bool SPSData::operator==(const SPSData& aOther) const {
   return this->valid && aOther.valid && !memcmp(this, &aOther, sizeof(SPSData));
 }
 
 bool SPSData::operator!=(const SPSData& aOther) const {
   return !(operator==(aOther));
 }
 
+// Described in ISO 23001-8:2016
+// Table 2
+enum class PrimaryID : uint8_t {
+  INVALID = 0,
+  BT709 = 1,
+  UNSPECIFIED = 2,
+  BT470M = 4,
+  BT470BG = 5,
+  SMPTE170M = 6,
+  SMPTE240M = 7,
+  FILM = 8,
+  BT2020 = 9,
+  SMPTEST428_1 = 10,
+  SMPTEST431_2 = 11,
+  SMPTEST432_1 = 12,
+  EBU_3213_E = 22
+};
+
+// Table 3
+enum class TransferID : uint8_t {
+  INVALID = 0,
+  BT709 = 1,
+  UNSPECIFIED = 2,
+  GAMMA22 = 4,
+  GAMMA28 = 5,
+  SMPTE170M = 6,
+  SMPTE240M = 7,
+  LINEAR = 8,
+  LOG = 9,
+  LOG_SQRT = 10,
+  IEC61966_2_4 = 11,
+  BT1361_ECG = 12,
+  IEC61966_2_1 = 13,
+  BT2020_10 = 14,
+  BT2020_12 = 15,
+  SMPTEST2084 = 16,
+  SMPTEST428_1 = 17,
+
+  // Not yet standardized
+  ARIB_STD_B67 = 18,  // AKA hybrid-log gamma, HLG.
+};
+
+// Table 4
+enum class MatrixID : uint8_t {
+  RGB = 0,
+  BT709 = 1,
+  UNSPECIFIED = 2,
+  FCC = 4,
+  BT470BG = 5,
+  SMPTE170M = 6,
+  SMPTE240M = 7,
+  YCOCG = 8,
+  BT2020_NCL = 9,
+  BT2020_CL = 10,
+  YDZDX = 11,
+  INVALID = 255,
+};
+
+static PrimaryID GetPrimaryID(int aPrimary) {
+  if (aPrimary < 1 || aPrimary > 22 || aPrimary == 3) {
+    return PrimaryID::INVALID;
+  }
+  if (aPrimary > 12 && aPrimary < 22) {
+    return PrimaryID::INVALID;
+  }
+  return static_cast<PrimaryID>(aPrimary);
+}
+
+static TransferID GetTransferID(int aTransfer) {
+  if (aTransfer < 1 || aTransfer > 18 || aTransfer == 3) {
+    return TransferID::INVALID;
+  }
+  return static_cast<TransferID>(aTransfer);
+}
+
+static MatrixID GetMatrixID(int aMatrix) {
+  if (aMatrix < 0 || aMatrix > 11 || aMatrix == 3) {
+    return MatrixID::INVALID;
+  }
+  return static_cast<MatrixID>(aMatrix);
+}
+
+gfx::YUVColorSpace SPSData::ColorSpace() const {
+  // Bitfield, note that guesses with higher values take precedence over
+  // guesses with lower values.
+  enum Guess {
+    GUESS_BT601 = 1 << 0,
+    GUESS_BT709 = 1 << 1,
+    GUESS_BT2020 = 1 << 2,
+  };
+
+  uint32_t guess = 0;
+
+  switch (GetPrimaryID(colour_primaries)) {
+    case PrimaryID::BT709:
+      guess |= GUESS_BT709;
+      break;
+    case PrimaryID::BT470M:
+    case PrimaryID::BT470BG:
+    case PrimaryID::SMPTE170M:
+    case PrimaryID::SMPTE240M:
+      guess |= GUESS_BT601;
+      break;
+    case PrimaryID::BT2020:
+      guess |= GUESS_BT2020;
+      break;
+    case PrimaryID::FILM:
+    case PrimaryID::SMPTEST428_1:
+    case PrimaryID::SMPTEST431_2:
+    case PrimaryID::SMPTEST432_1:
+    case PrimaryID::EBU_3213_E:
+    case PrimaryID::INVALID:
+    case PrimaryID::UNSPECIFIED:
+      break;
+  }
+
+  switch (GetTransferID(transfer_characteristics)) {
+    case TransferID::BT709:
+      guess |= GUESS_BT709;
+      break;
+    case TransferID::GAMMA22:
+    case TransferID::GAMMA28:
+    case TransferID::SMPTE170M:
+    case TransferID::SMPTE240M:
+      guess |= GUESS_BT601;
+      break;
+    case TransferID::BT2020_10:
+    case TransferID::BT2020_12:
+      guess |= GUESS_BT2020;
+      break;
+    case TransferID::LINEAR:
+    case TransferID::LOG:
+    case TransferID::LOG_SQRT:
+    case TransferID::IEC61966_2_4:
+    case TransferID::BT1361_ECG:
+    case TransferID::IEC61966_2_1:
+    case TransferID::SMPTEST2084:
+    case TransferID::SMPTEST428_1:
+    case TransferID::ARIB_STD_B67:
+    case TransferID::INVALID:
+    case TransferID::UNSPECIFIED:
+      break;
+  }
+
+  switch (GetMatrixID(matrix_coefficients)) {
+    case MatrixID::BT709:
+      guess |= GUESS_BT709;
+      break;
+    case MatrixID::BT470BG:
+    case MatrixID::SMPTE170M:
+    case MatrixID::SMPTE240M:
+      guess |= GUESS_BT601;
+      break;
+    case MatrixID::BT2020_NCL:
+    case MatrixID::BT2020_CL:
+      guess |= GUESS_BT2020;
+      break;
+    case MatrixID::RGB:
+    case MatrixID::FCC:
+    case MatrixID::YCOCG:
+    case MatrixID::YDZDX:
+    case MatrixID::INVALID:
+    case MatrixID::UNSPECIFIED:
+      break;
+  }
+
+  // Removes lowest bit until only a single bit remains.
+  while (guess & (guess - 1)) {
+    guess &= guess - 1;
+  }
+  if (!guess) {
+    // A better default to BT601 which should die a slow death.
+    guess = GUESS_BT709;
+  }
+
+  switch (guess) {
+    case GUESS_BT601:
+      return gfx::YUVColorSpace::BT601;
+    case GUESS_BT709:
+      return gfx::YUVColorSpace::BT709;
+    case GUESS_BT2020:
+      return gfx::YUVColorSpace::BT2020;
+    default:
+      MOZ_ASSERT_UNREACHABLE(
+          "not possible to get here but makes compiler happy");
+      return gfx::YUVColorSpace::UNKNOWN;
+  }
+}
+
+gfx::ColorDepth SPSData::ColorDepth() const {
+  if (bit_depth_luma_minus8 != 0 && bit_depth_luma_minus8 != 2 &&
+      bit_depth_luma_minus8 != 4) {
+    // We don't know what that is, just assume 8 bits to prevent decoding
+    // regressions if we ever encounter those.
+    return gfx::ColorDepth::COLOR_8;
+  }
+  return gfx::ColorDepthForBitDepth(bit_depth_luma_minus8 + 8);
+}
+
 // SPSNAL and SPSNALIterator do not own their data.
 class SPSNAL {
  public:
   SPSNAL(const uint8_t* aPtr, size_t aLength) {
     MOZ_ASSERT(aPtr);
 
     if (aLength == 0 || (*aPtr & 0x1f) != H264_NAL_SPS) {
       return;
--- a/dom/media/platforms/agnostic/bytestreams/H264.h
+++ b/dom/media/platforms/agnostic/bytestreams/H264.h
@@ -1,16 +1,17 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef MP4_DEMUXER_H264_H_
 #define MP4_DEMUXER_H264_H_
 
 #include "DecoderData.h"
+#include "mozilla/gfx/Types.h"
 
 namespace mozilla {
 class BitReader;
 
 // Spec 7.4.2.1
 #define MAX_SPS_COUNT 32
 #define MAX_PPS_COUNT 256
 
@@ -34,16 +35,19 @@ enum NAL_TYPES {
   H264_NAL_SLICE_EXT = 20,
   H264_NAL_SLICE_EXT_DVC = 21,
 };
 
 struct SPSData {
   bool operator==(const SPSData& aOther) const;
   bool operator!=(const SPSData& aOther) const;
 
+  gfx::YUVColorSpace ColorSpace() const;
+  gfx::ColorDepth ColorDepth() const;
+
   bool valid;
 
   /* Decoded Members */
   /*
     pic_width is the decoded width according to:
     pic_width = ((pic_width_in_mbs_minus1 + 1) * 16)
                 - (frame_crop_left_offset + frame_crop_right_offset) * 2
    */