diff mbox series

[FFmpeg-devel,v2,4/4] avcodec/nvenc: support for HEVC timecode passthrough

Message ID 1592410030-6553-4-git-send-email-lance.lmwang@gmail.com
State Accepted
Headers show
Series [FFmpeg-devel,v2,1/4] avcodec/hevc_sei: support HEVC timecode decode | expand

Checks

Context Check Description
andriy/default pending
andriy/make success Make finished
andriy/make_fate success Make fate finished

Commit Message

Lance Wang June 17, 2020, 4:07 p.m. UTC
From: Limin Wang <lance.lmwang@gmail.com>

Signed-off-by: Limin Wang <lance.lmwang@gmail.com>
--- 
I failed to find any document about nvenc so that I can update for new option.

 libavcodec/nvenc.c      | 53 +++++++++++++++++++++++++++++++++++++++++++++++++
 libavcodec/nvenc.h      |  1 +
 libavcodec/nvenc_hevc.c |  1 +
 3 files changed, 55 insertions(+)

Comments

Timo Rothenpieler June 17, 2020, 4:41 p.m. UTC | #1
On 17.06.2020 18:07, lance.lmwang@gmail.com wrote:
> From: Limin Wang <lance.lmwang@gmail.com>
> 
> Signed-off-by: Limin Wang <lance.lmwang@gmail.com>
> ---
> I failed to find any document about nvenc so that I can update for new option.
> 
>   libavcodec/nvenc.c      | 53 +++++++++++++++++++++++++++++++++++++++++++++++++
>   libavcodec/nvenc.h      |  1 +
>   libavcodec/nvenc_hevc.c |  1 +
>   3 files changed, 55 insertions(+)
> 
> diff --git a/libavcodec/nvenc.c b/libavcodec/nvenc.c
> index e4356ce..68b212a 100644
> --- a/libavcodec/nvenc.c
> +++ b/libavcodec/nvenc.c
> @@ -22,6 +22,8 @@
>   #include "config.h"
>   
>   #include "nvenc.h"
> +#include "hevc_sei.h"
> +#include "put_bits.h"
>   
>   #include "libavutil/hwcontext_cuda.h"
>   #include "libavutil/hwcontext.h"
> @@ -2068,6 +2070,15 @@ static void reconfig_encoder(AVCodecContext *avctx, const AVFrame *frame)
>       }
>   }
>   
> +static unsigned bcd2uint(uint8_t bcd)
> +{
> +    unsigned low  = bcd & 0xf;
> +    unsigned high = bcd >> 4;
> +    if (low > 9 || high > 9)
> +        return 0;
> +    return low + 10*high;
> +}
> +
>   int ff_nvenc_send_frame(AVCodecContext *avctx, const AVFrame *frame)
>   {
>       NVENCSTATUS nv_status;
> @@ -2156,6 +2167,48 @@ int ff_nvenc_send_frame(AVCodecContext *avctx, const AVFrame *frame)
>               }
>           }
>   
> +        if (ctx->tc && av_frame_get_side_data(frame, AV_FRAME_DATA_S12M_TIMECODE)) {
> +            AVFrameSideData *sd = av_frame_get_side_data(frame, AV_FRAME_DATA_S12M_TIMECODE);
> +            if (sd) {
> +                uint32_t *tc =  (uint32_t*)sd->data;
> +                int m = tc[0] & 3;
> +                if (tc) {
> +                    sei_data[sei_count].payloadSize = sizeof(uint32_t) * 4;
> +                    sei_data[sei_count].payloadType = HEVC_SEI_TYPE_TIME_CODE;
> +                    sei_data[sei_count].payload     = av_mallocz(sei_data[sei_count].payloadSize);
> +                    if (sei_data[sei_count].payload) {
> +                        PutBitContext pb;
> +
> +                        init_put_bits(&pb, sei_data[sei_count].payload, sei_data[sei_count].payloadSize);
> +                        put_bits(&pb, 2, m); // num_clock_ts
> +
> +                        for (int j = 1; j <= m; j++) {
> +                            uint32_t tcsmpte = tc[j];
> +                            unsigned hh   = bcd2uint(tcsmpte     & 0x3f);    // 6-bit hours
> +                            unsigned mm   = bcd2uint(tcsmpte>>8  & 0x7f);    // 7-bit minutes
> +                            unsigned ss   = bcd2uint(tcsmpte>>16 & 0x7f);    // 7-bit seconds
> +                            unsigned ff   = bcd2uint(tcsmpte>>24 & 0x3f);    // 6-bit frames
> +                            unsigned drop = tcsmpte & 1<<30 && !0;  // 1-bit drop if not arbitrary bit
> +
> +                            put_bits(&pb, 1, 1); // clock_timestamp_flag
> +                            put_bits(&pb, 1, 1); // units_field_based_flag
> +                            put_bits(&pb, 5, 0); // counting_type
> +                            put_bits(&pb, 1, 1); // full_timestamp_flag
> +                            put_bits(&pb, 1, 0); // discontinuity_flag
> +                            put_bits(&pb, 1, drop);
> +                            put_bits(&pb, 9, ff);
> +                            put_bits(&pb, 6, ss);
> +                            put_bits(&pb, 6, mm);
> +                            put_bits(&pb, 5, hh);
> +                            put_bits(&pb, 5, 0);
> +                        }
> +                        flush_put_bits(&pb);
> +                        sei_count++;
> +                    }
> +                }
> +            }
> +        }
> +

Does all this really have to be in nvenc? It looks very generic to me, 
and better put in some central location to be re-used by multiple codecs.
Lance Wang June 18, 2020, 1:38 a.m. UTC | #2
On Wed, Jun 17, 2020 at 06:41:45PM +0200, Timo Rothenpieler wrote:
> On 17.06.2020 18:07, lance.lmwang@gmail.com wrote:
> > From: Limin Wang <lance.lmwang@gmail.com>
> > 
> > Signed-off-by: Limin Wang <lance.lmwang@gmail.com>
> > ---
> > I failed to find any document about nvenc so that I can update for new option.
> > 
> >   libavcodec/nvenc.c      | 53 +++++++++++++++++++++++++++++++++++++++++++++++++
> >   libavcodec/nvenc.h      |  1 +
> >   libavcodec/nvenc_hevc.c |  1 +
> >   3 files changed, 55 insertions(+)
> > 
> > diff --git a/libavcodec/nvenc.c b/libavcodec/nvenc.c
> > index e4356ce..68b212a 100644
> > --- a/libavcodec/nvenc.c
> > +++ b/libavcodec/nvenc.c
> > @@ -22,6 +22,8 @@
> >   #include "config.h"
> >   #include "nvenc.h"
> > +#include "hevc_sei.h"
> > +#include "put_bits.h"
> >   #include "libavutil/hwcontext_cuda.h"
> >   #include "libavutil/hwcontext.h"
> > @@ -2068,6 +2070,15 @@ static void reconfig_encoder(AVCodecContext *avctx, const AVFrame *frame)
> >       }
> >   }
> > +static unsigned bcd2uint(uint8_t bcd)
> > +{
> > +    unsigned low  = bcd & 0xf;
> > +    unsigned high = bcd >> 4;
> > +    if (low > 9 || high > 9)
> > +        return 0;
> > +    return low + 10*high;
> > +}
> > +
> >   int ff_nvenc_send_frame(AVCodecContext *avctx, const AVFrame *frame)
> >   {
> >       NVENCSTATUS nv_status;
> > @@ -2156,6 +2167,48 @@ int ff_nvenc_send_frame(AVCodecContext *avctx, const AVFrame *frame)
> >               }
> >           }
> > +        if (ctx->tc && av_frame_get_side_data(frame, AV_FRAME_DATA_S12M_TIMECODE)) {
> > +            AVFrameSideData *sd = av_frame_get_side_data(frame, AV_FRAME_DATA_S12M_TIMECODE);
> > +            if (sd) {
> > +                uint32_t *tc =  (uint32_t*)sd->data;
> > +                int m = tc[0] & 3;
> > +                if (tc) {
> > +                    sei_data[sei_count].payloadSize = sizeof(uint32_t) * 4;
> > +                    sei_data[sei_count].payloadType = HEVC_SEI_TYPE_TIME_CODE;
> > +                    sei_data[sei_count].payload     = av_mallocz(sei_data[sei_count].payloadSize);
> > +                    if (sei_data[sei_count].payload) {
> > +                        PutBitContext pb;
> > +
> > +                        init_put_bits(&pb, sei_data[sei_count].payload, sei_data[sei_count].payloadSize);
> > +                        put_bits(&pb, 2, m); // num_clock_ts
> > +
> > +                        for (int j = 1; j <= m; j++) {
> > +                            uint32_t tcsmpte = tc[j];
> > +                            unsigned hh   = bcd2uint(tcsmpte     & 0x3f);    // 6-bit hours
> > +                            unsigned mm   = bcd2uint(tcsmpte>>8  & 0x7f);    // 7-bit minutes
> > +                            unsigned ss   = bcd2uint(tcsmpte>>16 & 0x7f);    // 7-bit seconds
> > +                            unsigned ff   = bcd2uint(tcsmpte>>24 & 0x3f);    // 6-bit frames
> > +                            unsigned drop = tcsmpte & 1<<30 && !0;  // 1-bit drop if not arbitrary bit
> > +
> > +                            put_bits(&pb, 1, 1); // clock_timestamp_flag
> > +                            put_bits(&pb, 1, 1); // units_field_based_flag
> > +                            put_bits(&pb, 5, 0); // counting_type
> > +                            put_bits(&pb, 1, 1); // full_timestamp_flag
> > +                            put_bits(&pb, 1, 0); // discontinuity_flag
> > +                            put_bits(&pb, 1, drop);
> > +                            put_bits(&pb, 9, ff);
> > +                            put_bits(&pb, 6, ss);
> > +                            put_bits(&pb, 6, mm);
> > +                            put_bits(&pb, 5, hh);
> > +                            put_bits(&pb, 5, 0);
> > +                        }
> > +                        flush_put_bits(&pb);
> > +                        sei_count++;
> > +                    }
> > +                }
> > +            }
> > +        }
> > +
> 
> Does all this really have to be in nvenc? It looks very generic to me, and
> better put in some central location to be re-used by multiple codecs.

Yes, I'll add a general function for reuse next version.

> _______________________________________________
> ffmpeg-devel mailing list
> ffmpeg-devel@ffmpeg.org
> https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
> 
> To unsubscribe, visit link above, or email
> ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".
diff mbox series

Patch

diff --git a/libavcodec/nvenc.c b/libavcodec/nvenc.c
index e4356ce..68b212a 100644
--- a/libavcodec/nvenc.c
+++ b/libavcodec/nvenc.c
@@ -22,6 +22,8 @@ 
 #include "config.h"
 
 #include "nvenc.h"
+#include "hevc_sei.h"
+#include "put_bits.h"
 
 #include "libavutil/hwcontext_cuda.h"
 #include "libavutil/hwcontext.h"
@@ -2068,6 +2070,15 @@  static void reconfig_encoder(AVCodecContext *avctx, const AVFrame *frame)
     }
 }
 
+static unsigned bcd2uint(uint8_t bcd)
+{
+    unsigned low  = bcd & 0xf;
+    unsigned high = bcd >> 4;
+    if (low > 9 || high > 9)
+        return 0;
+    return low + 10*high;
+}
+
 int ff_nvenc_send_frame(AVCodecContext *avctx, const AVFrame *frame)
 {
     NVENCSTATUS nv_status;
@@ -2156,6 +2167,48 @@  int ff_nvenc_send_frame(AVCodecContext *avctx, const AVFrame *frame)
             }
         }
 
+        if (ctx->tc && av_frame_get_side_data(frame, AV_FRAME_DATA_S12M_TIMECODE)) {
+            AVFrameSideData *sd = av_frame_get_side_data(frame, AV_FRAME_DATA_S12M_TIMECODE);
+            if (sd) {
+                uint32_t *tc =  (uint32_t*)sd->data;
+                int m = tc[0] & 3;
+                if (tc) {
+                    sei_data[sei_count].payloadSize = sizeof(uint32_t) * 4;
+                    sei_data[sei_count].payloadType = HEVC_SEI_TYPE_TIME_CODE;
+                    sei_data[sei_count].payload     = av_mallocz(sei_data[sei_count].payloadSize);
+                    if (sei_data[sei_count].payload) {
+                        PutBitContext pb;
+
+                        init_put_bits(&pb, sei_data[sei_count].payload, sei_data[sei_count].payloadSize);
+                        put_bits(&pb, 2, m); // num_clock_ts
+
+                        for (int j = 1; j <= m; j++) {
+                            uint32_t tcsmpte = tc[j];
+                            unsigned hh   = bcd2uint(tcsmpte     & 0x3f);    // 6-bit hours
+                            unsigned mm   = bcd2uint(tcsmpte>>8  & 0x7f);    // 7-bit minutes
+                            unsigned ss   = bcd2uint(tcsmpte>>16 & 0x7f);    // 7-bit seconds
+                            unsigned ff   = bcd2uint(tcsmpte>>24 & 0x3f);    // 6-bit frames
+                            unsigned drop = tcsmpte & 1<<30 && !0;  // 1-bit drop if not arbitrary bit
+
+                            put_bits(&pb, 1, 1); // clock_timestamp_flag
+                            put_bits(&pb, 1, 1); // units_field_based_flag
+                            put_bits(&pb, 5, 0); // counting_type
+                            put_bits(&pb, 1, 1); // full_timestamp_flag
+                            put_bits(&pb, 1, 0); // discontinuity_flag
+                            put_bits(&pb, 1, drop);
+                            put_bits(&pb, 9, ff);
+                            put_bits(&pb, 6, ss);
+                            put_bits(&pb, 6, mm);
+                            put_bits(&pb, 5, hh);
+                            put_bits(&pb, 5, 0);
+                        }
+                        flush_put_bits(&pb);
+                        sei_count++;
+                    }
+                }
+            }
+        }
+
         nvenc_codec_specific_pic_params(avctx, &pic_params, sei_data, sei_count);
     } else {
         pic_params.encodePicFlags = NV_ENC_PIC_FLAG_EOS;
diff --git a/libavcodec/nvenc.h b/libavcodec/nvenc.h
index 7a415a4..f1adaeb 100644
--- a/libavcodec/nvenc.h
+++ b/libavcodec/nvenc.h
@@ -196,6 +196,7 @@  typedef struct NvencContext
     int coder;
     int b_ref_mode;
     int a53_cc;
+    int tc;
     int dpb_size;
 } NvencContext;
 
diff --git a/libavcodec/nvenc_hevc.c b/libavcodec/nvenc_hevc.c
index 7f12b56..6eef613 100644
--- a/libavcodec/nvenc_hevc.c
+++ b/libavcodec/nvenc_hevc.c
@@ -129,6 +129,7 @@  static const AVOption options[] = {
     { "each",         "",                                   0,                    AV_OPT_TYPE_CONST, { .i64 = 1 }, 0, 0,       VE, "b_ref_mode" },
     { "middle",       "",                                   0,                    AV_OPT_TYPE_CONST, { .i64 = 2 }, 0, 0,       VE, "b_ref_mode" },
 #endif
+    { "tc",        "Use timecode (if available)",           OFFSET(tc),           AV_OPT_TYPE_BOOL,  { .i64 = 1 }, 0, 1, VE },
     { "dpb_size",     "Specifies the DPB size used for encoding (0 means automatic)",
                                                             OFFSET(dpb_size),     AV_OPT_TYPE_INT,   { .i64 = 0 }, 0, INT_MAX, VE },
     { NULL }