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 |
Context | Check | Description |
---|---|---|
andriy/default | pending | |
andriy/make | success | Make finished |
andriy/make_fate | success | Make fate finished |
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.
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 --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 }