From 6b602399c68ce7062d8c2aefee9b3814be3f3b0e Mon Sep 17 00:00:00 2001
From: Praveen Karadugattu <praveenkumar@outlook.com>
Date: Thu, 1 Aug 2019 17:47:36 +0530
Subject: [PATCH] Support for Frame Doubling/ Tripling in FFMPEG's HEVC Decoder
 by parsing the picture_struct SEI value (Support for
 http://ffmpeg.org/pipermail/ffmpeg-devel/2019-June/245521.html)

---
 libavcodec/hevc_parser.c | 29 +++++++++++++++++++++++++++++
 libavcodec/hevc_sei.c    |  6 ++++++
 libavcodec/hevc_sei.h    | 15 +++++++++++++++
 libavcodec/hevcdec.c     |  8 ++++++++
 4 files changed, 58 insertions(+)

diff --git a/libavcodec/hevc_parser.c b/libavcodec/hevc_parser.c
index b444b99..472851c 100644
--- a/libavcodec/hevc_parser.c
+++ b/libavcodec/hevc_parser.c
@@ -30,6 +30,7 @@
 #include "h2645_parse.h"
 #include "internal.h"
 #include "parser.h"
+#include "mpegutils.h"
 
 #define START_CODE 0x000001 ///< start_code_prefix_one_3bytes
 
@@ -232,6 +233,34 @@ static int parse_nal_units(AVCodecParserContext *s, const uint8_t *buf,
         case HEVC_NAL_RADL_R:
         case HEVC_NAL_RASL_N:
         case HEVC_NAL_RASL_R:
+            if (ctx->sei.picture_timing.picture_struct) {
+                switch (ctx->sei.picture_timing.picture_struct) {
+                case HEVC_SEI_PIC_STRUCT_TOP_FIELD:
+                case HEVC_SEI_PIC_STRUCT_BOTTOM_FIELD:
+                    s->repeat_pict = 0;
+                    break;
+                case HEVC_SEI_PIC_STRUCT_FRAME:
+                case HEVC_SEI_PIC_STRUCT_TOP_BOTTOM:
+                case HEVC_SEI_PIC_STRUCT_BOTTOM_TOP:
+                    s->repeat_pict = 1;
+                    break;
+                case HEVC_SEI_PIC_STRUCT_TOP_BOTTOM_TOP:
+                case HEVC_SEI_PIC_STRUCT_BOTTOM_TOP_BOTTOM:
+                    s->repeat_pict = 2;
+                    break;
+                case HEVC_SEI_PIC_STRUCT_FRAME_DOUBLING:
+                    s->repeat_pict = 3;
+                    break;
+                case HEVC_SEI_PIC_STRUCT_FRAME_TRIPLING:
+                    s->repeat_pict = 5;
+                    break;
+                default:
+                    s->repeat_pict = ctx->sei.picture_timing.picture_struct == PICT_FRAME ? 1 : 0;
+                    break;
+                }
+            } else {
+                s->repeat_pict = ctx->sei.picture_timing.picture_struct == PICT_FRAME ? 1 : 0;
+            }
             ret = hevc_parse_slice_header(s, nal, avctx);
             if (ret)
                 return ret;
diff --git a/libavcodec/hevc_sei.c b/libavcodec/hevc_sei.c
index c59bd43..41aa278 100644
--- a/libavcodec/hevc_sei.c
+++ b/libavcodec/hevc_sei.c
@@ -144,6 +144,12 @@ static int decode_nal_sei_pic_timing(HEVCSEI *s, GetBitContext *gb, const HEVCPa
         } else if (pic_struct == 1 || pic_struct == 9 || pic_struct == 11) {
             av_log(logctx, AV_LOG_DEBUG, "TOP Field\n");
             h->picture_struct = AV_PICTURE_STRUCTURE_TOP_FIELD;
+        } else if (pic_struct == 7) {
+            av_log(logctx, AV_LOG_DEBUG, "Frame/ Field Doubling\n");
+            h->picture_struct = HEVC_SEI_PIC_STRUCT_FRAME_DOUBLING;
+        } else if (pic_struct == 8) {
+            av_log(logctx, AV_LOG_DEBUG, "Frame/ Field Tripling\n");
+            h->picture_struct = HEVC_SEI_PIC_STRUCT_FRAME_TRIPLING;
         }
         get_bits(gb, 2);                   // source_scan_type
         get_bits(gb, 1);                   // duplicate_flag
diff --git a/libavcodec/hevc_sei.h b/libavcodec/hevc_sei.h
index f6516ae..ec5f922 100644
--- a/libavcodec/hevc_sei.h
+++ b/libavcodec/hevc_sei.h
@@ -59,6 +59,21 @@ typedef enum {
     HEVC_SEI_TYPE_ALPHA_CHANNEL_INFO                   = 165,
 } HEVC_SEI_Type;
 
+/**
+ * pic_struct in picture timing SEI message
+ */
+typedef enum {
+    HEVC_SEI_PIC_STRUCT_FRAME             = 0, ///<  0: %frame
+    HEVC_SEI_PIC_STRUCT_TOP_FIELD         = 1, ///<  1: top field
+    HEVC_SEI_PIC_STRUCT_BOTTOM_FIELD      = 2, ///<  2: bottom field
+    HEVC_SEI_PIC_STRUCT_TOP_BOTTOM        = 3, ///<  3: top field, bottom field, in that order
+    HEVC_SEI_PIC_STRUCT_BOTTOM_TOP        = 4, ///<  4: bottom field, top field, in that order
+    HEVC_SEI_PIC_STRUCT_TOP_BOTTOM_TOP    = 5, ///<  5: top field, bottom field, top field repeated, in that order
+    HEVC_SEI_PIC_STRUCT_BOTTOM_TOP_BOTTOM = 6, ///<  6: bottom field, top field, bottom field repeated, in that order
+    HEVC_SEI_PIC_STRUCT_FRAME_DOUBLING    = 7, ///<  7: %frame doubling
+    HEVC_SEI_PIC_STRUCT_FRAME_TRIPLING    = 8  ///<  8: %frame tripling
+} HEVC_SEI_PicStructType;
+
 typedef struct HEVCSEIPictureHash {
     uint8_t       md5[3][16];
     uint8_t is_md5;
diff --git a/libavcodec/hevcdec.c b/libavcodec/hevcdec.c
index f193497..d1da3cf 100644
--- a/libavcodec/hevcdec.c
+++ b/libavcodec/hevcdec.c
@@ -3489,6 +3489,14 @@ static av_cold int hevc_decode_init(AVCodecContext *avctx)
     else
         s->threads_number = 1;
 
+   if (avctx->ticks_per_frame == 1) {
+        if(s->avctx->time_base.den < INT_MAX/2) {
+            s->avctx->time_base.den *= 2;
+        } else
+            s->avctx->time_base.num /= 2;
+    }
+    avctx->ticks_per_frame = 2;
+
     if (avctx->extradata_size > 0 && avctx->extradata) {
         ret = hevc_decode_extradata(s, avctx->extradata, avctx->extradata_size, 1);
         if (ret < 0) {
-- 
1.8.3.1

