[x265] [PATCH] Add support for Dolby Vision RPU muxing

Aruna Matheswaran aruna at multicorewareinc.com
Mon Dec 10 10:59:35 CET 2018


# HG changeset patch
# User Aruna Matheswaran <aruna at multicorewareinc.com>
# Date 1538037975 -19800
#      Thu Sep 27 14:16:15 2018 +0530
# Node ID e50f803e26fb3926dc695e0aeea39681fe1eacbd
# Parent  b748ee9f44657a9468b9d62c85d02dfafcbc4039
Add support for Dolby Vision RPU muxing

diff -r b748ee9f4465 -r e50f803e26fb doc/reST/cli.rst
--- a/doc/reST/cli.rst Fri Sep 28 10:45:23 2018 +0530
+++ b/doc/reST/cli.rst Thu Sep 27 14:16:15 2018 +0530
@@ -2208,6 +2208,15 @@

     Currently only profile 5 enabled, Default 0 (disabled)

+.. option:: --dolby-vision-rpu
+
+    File containing Dolby Vision RPU metadata. If given, x265's Dolby
Vision
+    metadata parser will fill the RPU field of input pictures with the
metadata
+    read from the file. The library will interleave access units with RPUs
in the
+    bitstream. Default NULL (disabled).
+
+    **CLI ONLY**
+
 .. option:: --info, --no-info

  Emit an informational SEI with the stream headers which describes
diff -r b748ee9f4465 -r e50f803e26fb source/CMakeLists.txt
--- a/source/CMakeLists.txt Fri Sep 28 10:45:23 2018 +0530
+++ b/source/CMakeLists.txt Thu Sep 27 14:16:15 2018 +0530
@@ -29,7 +29,7 @@
 option(STATIC_LINK_CRT "Statically link C runtime for release builds" OFF)
 mark_as_advanced(FPROFILE_USE FPROFILE_GENERATE NATIVE_BUILD)
 # X265_BUILD must be incremented each time the public API is changed
-set(X265_BUILD 166)
+set(X265_BUILD 167)
 configure_file("${PROJECT_SOURCE_DIR}/x265.def.in"
                "${PROJECT_BINARY_DIR}/x265.def")
 configure_file("${PROJECT_SOURCE_DIR}/x265_config.h.in"
diff -r b748ee9f4465 -r e50f803e26fb source/common/frame.cpp
--- a/source/common/frame.cpp Fri Sep 28 10:45:23 2018 +0530
+++ b/source/common/frame.cpp Thu Sep 27 14:16:15 2018 +0530
@@ -44,6 +44,8 @@
     m_param = NULL;
     m_userSEI.numPayloads = 0;
     m_userSEI.payloads = NULL;
+    m_rpu.payloadSize = 0;
+    m_rpu.payload = NULL;
     memset(&m_lowres, 0, sizeof(m_lowres));
     m_rcData = NULL;
     m_encodeStartTime = 0;
diff -r b748ee9f4465 -r e50f803e26fb source/common/frame.h
--- a/source/common/frame.h Fri Sep 28 10:45:23 2018 +0530
+++ b/source/common/frame.h Thu Sep 27 14:16:15 2018 +0530
@@ -98,6 +98,7 @@

     float*                 m_quantOffsets;       // points to quantOffsets
in x265_picture
     x265_sei               m_userSEI;
+    x265_dolby_vision_rpu            m_rpu;

     /* Frame Parallelism - notification between FrameEncoders of available
motion reference rows */
     ThreadSafeInteger*     m_reconRowFlag;       // flag of CTU rows
completely reconstructed and extended for motion reference
diff -r b748ee9f4465 -r e50f803e26fb source/encoder/api.cpp
--- a/source/encoder/api.cpp Fri Sep 28 10:45:23 2018 +0530
+++ b/source/encoder/api.cpp Thu Sep 27 14:16:15 2018 +0530
@@ -598,6 +598,8 @@
     pic->quantOffsets = NULL;
     pic->userSEI.payloads = NULL;
     pic->userSEI.numPayloads = 0;
+    pic->rpu.payloadSize = 0;
+    pic->rpu.payload = NULL;

     if ((param->analysisSave || param->analysisLoad) || (param->bMVType ==
AVC_INFO))
     {
@@ -612,6 +614,8 @@

 void x265_picture_free(x265_picture *p)
 {
+    if (p->rpu.payload)
+        X265_FREE(p->rpu.payload);
     return x265_free(p);
 }

diff -r b748ee9f4465 -r e50f803e26fb source/encoder/encoder.cpp
--- a/source/encoder/encoder.cpp Fri Sep 28 10:45:23 2018 +0530
+++ b/source/encoder/encoder.cpp Thu Sep 27 14:16:15 2018 +0530
@@ -1075,6 +1075,14 @@

         copyUserSEIMessages(inFrame, pic_in);

+        /*Copy Dolby Vision RPU from pic_in to frame*/
+        if (pic_in->rpu.payloadSize)
+        {
+            inFrame->m_rpu.payloadSize = pic_in->rpu.payloadSize;
+            inFrame->m_rpu.payload = new uint8_t[pic_in->rpu.payloadSize];
+            memcpy(inFrame->m_rpu.payload, pic_in->rpu.payload,
pic_in->rpu.payloadSize);
+        }
+
         if (pic_in->quantOffsets != NULL)
         {
             int cuCount;
@@ -2362,6 +2370,13 @@
 {
     sbacCoder.setBitstream(&bs);

+    if (m_param->dolbyProfile && !m_param->bRepeatHeaders)
+    {
+        bs.resetBits();
+        bs.write(0x10, 8);
+        list.serialize(NAL_UNIT_ACCESS_UNIT_DELIMITER, bs);
+    }
+
     /* headers for start of bitstream */
     bs.resetBits();
     sbacCoder.codeVPS(m_vps);
diff -r b748ee9f4465 -r e50f803e26fb source/encoder/frameencoder.cpp
--- a/source/encoder/frameencoder.cpp Fri Sep 28 10:45:23 2018 +0530
+++ b/source/encoder/frameencoder.cpp Thu Sep 27 14:16:15 2018 +0530
@@ -1063,6 +1063,14 @@
         m_accessUnitBits = bytes << 3;
     }

+    if (m_frame->m_rpu.payloadSize)
+    {
+        m_bs.resetBits();
+        for (int i = 0; i < m_frame->m_rpu.payloadSize; i++)
+            m_bs.write(m_frame->m_rpu.payload[i], 8);
+        m_nalList.serialize(NAL_UNIT_UNSPECIFIED, m_bs);
+    }
+
     m_endCompressTime = x265_mdate();

     /* Decrement referenced frame reference counts, allow them to be
recycled */
diff -r b748ee9f4465 -r e50f803e26fb source/encoder/nal.cpp
--- a/source/encoder/nal.cpp Fri Sep 28 10:45:23 2018 +0530
+++ b/source/encoder/nal.cpp Thu Sep 27 14:16:15 2018 +0530
@@ -97,7 +97,7 @@
         /* Will write size later */
         bytes += 4;
     }
-    else if (!m_numNal || nalUnitType == NAL_UNIT_VPS || nalUnitType ==
NAL_UNIT_SPS || nalUnitType == NAL_UNIT_PPS)
+    else if (!m_numNal || nalUnitType == NAL_UNIT_VPS || nalUnitType ==
NAL_UNIT_SPS || nalUnitType == NAL_UNIT_PPS || nalUnitType ==
NAL_UNIT_UNSPECIFIED)
     {
         memcpy(out, startCodePrefix, 4);
         bytes += 4;
@@ -124,7 +124,7 @@
      *  - 0x000002 */
     for (uint32_t i = 0; i < payloadSize; i++)
     {
-        if (i > 2 && !out[bytes - 2] && !out[bytes - 3] && out[bytes - 1]
<= 0x03)
+        if (i > 2 && !out[bytes - 2] && !out[bytes - 3] && out[bytes - 1]
<= 0x03 && nalUnitType != NAL_UNIT_UNSPECIFIED)
         {
             /* inject 0x03 to prevent emulating a start code */
             out[bytes] = out[bytes - 1];
diff -r b748ee9f4465 -r e50f803e26fb source/encoder/sei.cpp
--- a/source/encoder/sei.cpp Fri Sep 28 10:45:23 2018 +0530
+++ b/source/encoder/sei.cpp Thu Sep 27 14:16:15 2018 +0530
@@ -66,7 +66,8 @@

     if (!isNested)
     {
-        bs.writeByteAlignment();
+        if (nalUnitType != NAL_UNIT_UNSPECIFIED)
+            bs.writeByteAlignment();
         list.serialize(nalUnitType, bs);
     }
 }
diff -r b748ee9f4465 -r e50f803e26fb source/x265.cpp
--- a/source/x265.cpp Fri Sep 28 10:45:23 2018 +0530
+++ b/source/x265.cpp Thu Sep 27 14:16:15 2018 +0530
@@ -65,6 +65,8 @@
 {
     b_ctrl_c = 1;
 }
+#define START_CODE 0x00000001
+#define START_CODE_BYTES 4

 struct CLIOptions
 {
@@ -72,6 +74,7 @@
     ReconFile* recon;
     OutputFile* output;
     FILE*       qpfile;
+    FILE*    dolbyVisionRpu;    /* File containing Dolby Vision BL RPU
metadata */
     const char* reconPlayCmd;
     const x265_api* api;
     x265_param* param;
@@ -94,6 +97,7 @@
         recon = NULL;
         output = NULL;
         qpfile = NULL;
+        dolbyVisionRpu = NULL;
         reconPlayCmd = NULL;
         api = NULL;
         param = NULL;
@@ -124,6 +128,9 @@
     if (qpfile)
         fclose(qpfile);
     qpfile = NULL;
+    if (dolbyVisionRpu)
+        fclose(dolbyVisionRpu);
+    dolbyVisionRpu = NULL;
     if (output)
         output->release();
     output = NULL;
@@ -311,6 +318,15 @@
                 if (!this->qpfile)
                     x265_log_file(param, X265_LOG_ERROR, "%s qpfile not
found or error in opening qp file\n", optarg);
             }
+            OPT("dolby-vision-rpu")
+            {
+                this->dolbyVisionRpu = x265_fopen(optarg, "rb");
+                if (!this->dolbyVisionRpu)
+                {
+                    x265_log_file(param, X265_LOG_ERROR, "Dolby Vision RPU
metadata file %s not found or error in opening file\n", optarg);
+                    return true;
+                }
+            }
             OPT("fullhelp")
             {
                 param->logLevel = X265_LOG_FULL;
@@ -552,6 +568,59 @@
 }
 #endif

+/* Parse the RPU file and extract the RPU corresponding to the current
picture
+ * and fill the rpu field of the input picture */
+static int rpuParser(x265_picture * pic, FILE * ptr)
+{
+    uint8_t byte;
+    uint32_t code = 0;
+    int bytesRead = 0;
+    pic->rpu.payloadSize = 0;
+
+    if (!pic->pts)
+    {
+        while (bytesRead++ < 4 && fread(&byte, sizeof(uint8_t), 1, ptr))
+            code = (code << 8) | byte;
+
+        if (code != START_CODE)
+        {
+            x265_log(NULL, X265_LOG_ERROR, "Invalid Dolby Vision RPU
startcode in POC %d\n", pic->pts);
+            return 1;
+        }
+    }
+
+    bytesRead = 0;
+    while (fread(&byte, sizeof(uint8_t), 1, ptr))
+    {
+        code = (code << 8) | byte;
+        if (bytesRead++ < 3)
+            continue;
+        if (bytesRead >= 1024)
+        {
+            x265_log(NULL, X265_LOG_ERROR, "Invalid Dolby Vision RPU size
in POC %d\n", pic->pts);
+            return 1;
+        }
+
+        if (code != START_CODE)
+            pic->rpu.payload[pic->rpu.payloadSize++] = (code >> (3 * 8)) &
0xFF;
+        else
+            return 0;
+    }
+
+    int ShiftBytes = START_CODE_BYTES - (bytesRead - pic->rpu.payloadSize);
+    int bytesLeft = bytesRead - pic->rpu.payloadSize;
+    code = (code << ShiftBytes * 8);
+    for (int i = 0; i < bytesLeft; i++)
+    {
+        pic->rpu.payload[pic->rpu.payloadSize++] = (code >> (3 * 8)) &
0xFF;
+        code = (code << 8);
+    }
+    if (!pic->rpu.payloadSize)
+        x265_log(NULL, X265_LOG_WARNING, "Dolby Vision RPU not found for
POC %d\n", pic->pts);
+    return 0;
+}
+
+
 /* CLI return codes:
  *
  * 0 - encode successful
@@ -630,8 +699,10 @@
     x265_stats stats;
     uint32_t nal;
     int16_t *errorBuf = NULL;
+    bool bDolbyVisionRPU = false;
     int ret = 0;

+
     if (!param->bRepeatHeaders)
     {
         if (api->encoder_headers(encoder, &p_nal, &nal) < 0)
@@ -646,6 +717,13 @@

     api->picture_init(param, pic_in);

+    if (param->dolbyProfile && cliopt.dolbyVisionRpu)
+    {
+        pic_in->rpu.payload = X265_MALLOC(uint8_t, 1024);
+        if (pic_in->rpu.payload)
+            bDolbyVisionRPU = true;
+    }
+
     if (cliopt.bDither)
     {
         errorBuf = X265_MALLOC(int16_t, param->sourceWidth + 1);
@@ -685,8 +763,13 @@
             }
             /* Overwrite PTS */
             pic_in->pts = pic_in->poc;
+
+            if (bDolbyVisionRPU)
+            {
+                if (rpuParser(pic_in, cliopt.dolbyVisionRpu) > 0)
+                    goto fail;
+            }
         }
-
         int numEncoded = api->encoder_encode(encoder, &p_nal, &nal,
pic_in, pic_recon);
         if (numEncoded < 0)
         {
@@ -749,6 +832,13 @@
             break;
     }

+    if (bDolbyVisionRPU)
+    {
+        if(fgetc(cliopt.dolbyVisionRpu) != EOF)
+            x265_log(NULL, X265_LOG_WARNING, "Dolby Vision RPU count is
greater than frame count\n");
+        x265_log(NULL, X265_LOG_INFO, "VES muxing with Dolby Vision RPU
file successful\n");
+    }
+
     /* clear progress report */
     if (cliopt.bProgress)
         fprintf(stderr, "%*s\r", 80, " ");
diff -r b748ee9f4465 -r e50f803e26fb source/x265.h
--- a/source/x265.h Fri Sep 28 10:45:23 2018 +0530
+++ b/source/x265.h Thu Sep 27 14:16:15 2018 +0530
@@ -81,6 +81,7 @@
     NAL_UNIT_FILLER_DATA,
     NAL_UNIT_PREFIX_SEI,
     NAL_UNIT_SUFFIX_SEI,
+    NAL_UNIT_UNSPECIFIED = 62,
     NAL_UNIT_INVALID = 64,
 } NalUnitType;

@@ -360,6 +361,12 @@
     x265_sei_payload *payloads;
 } x265_sei;

+typedef struct x265_dolby_vision_rpu
+{
+    int payloadSize;
+    uint8_t* payload;
+}x265_dolby_vision_rpu;
+
 /* Used to pass pictures into the encoder, and to get picture data back
out of
  * the encoder.  The input and output semantics are different */
 typedef struct x265_picture
@@ -445,6 +452,9 @@

     // pts is reordered in the order of encoding.
     int64_t reorderedPts;
+
+    //Dolby Vision RPU metadata
+    x265_dolby_vision_rpu rpu;
 } x265_picture;

 typedef enum
diff -r b748ee9f4465 -r e50f803e26fb source/x265cli.h
--- a/source/x265cli.h Fri Sep 28 10:45:23 2018 +0530
+++ b/source/x265cli.h Thu Sep 27 14:16:15 2018 +0530
@@ -306,6 +306,7 @@
     { "atc-sei", required_argument, NULL, 0 },
     { "pic-struct", required_argument, NULL, 0 },
     { "nalu-file", required_argument, NULL, 0 },
+    { "dolby-vision-rpu", required_argument, NULL, 0 },
     { 0, 0, 0, 0 },
     { 0, 0, 0, 0 },
     { 0, 0, 0, 0 },
@@ -357,6 +358,8 @@
     H0("   --[no-]dhdr10-opt             Insert tone mapping SEI only for
IDR frames and when the tone mapping information changes. Default
disabled\n");
 #endif
     H0("  --dolby-vision-profile <float|integer> Specifies Dolby Vision
profile ID. Currently only profile 5 enabled. Specified as '5' or '50'.
Default 0 (disabled).\n");
+    H0("   --dolby-vision-rpu <filename> File containing Dolby Vision RPU
metadata.\n"
+       "                                 If given, x265's Dolby Vision
metadata parser will fill the RPU field of input pictures with the metadata
read from the file. Default NULL(disabled).\n");
     H0("   --nalu-file <filename>        Text file containing SEI messages
in the following format : <POC><space><PREFIX><space><NAL UNIT TYPE>/<SEI
TYPE><space><SEI Payload>\n");
     H0("-f/--frames <integer>            Maximum number of frames to
encode. Default all\n");
     H0("   --seek <integer>              First frame to encode\n");
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mailman.videolan.org/pipermail/x265-devel/attachments/20181210/8ffec319/attachment-0001.html>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: x265_clone_12437.patch
Type: application/octet-stream
Size: 13545 bytes
Desc: not available
URL: <http://mailman.videolan.org/pipermail/x265-devel/attachments/20181210/8ffec319/attachment-0001.obj>


More information about the x265-devel mailing list