diff options
author | Limin Wang <lance.lmwang@gmail.com> | 2020-06-18 11:58:50 +0800 |
---|---|---|
committer | Limin Wang <lance.lmwang@gmail.com> | 2020-06-28 21:00:52 +0800 |
commit | 9294f5b497e6253c4a3c510b86eb63984ce9dfe7 (patch) | |
tree | 7eed382a4823740c329a4b0cb6f0633710b0d254 | |
parent | 5151f6d2953d75bd26898b2bd51fe095796c07ad (diff) | |
download | ffmpeg-9294f5b497e6253c4a3c510b86eb63984ce9dfe7.tar.gz |
avcodec/utils: add ff_alloc_timecode_sei() for hevc timecode sei
Signed-off-by: Limin Wang <lance.lmwang@gmail.com>
-rw-r--r-- | libavcodec/internal.h | 15 | ||||
-rw-r--r-- | libavcodec/utils.c | 63 |
2 files changed, 78 insertions, 0 deletions
diff --git a/libavcodec/internal.h b/libavcodec/internal.h index 21708df12e..87710780af 100644 --- a/libavcodec/internal.h +++ b/libavcodec/internal.h @@ -380,6 +380,21 @@ int ff_alloc_a53_sei(const AVFrame *frame, size_t prefix_len, void **data, size_t *sei_size); /** + * Check AVFrame for S12M timecode side data and allocate and fill TC SEI message with timecode info + * + * @param frame Raw frame to get S12M timecode side data from + * @param prefix_len Number of bytes to allocate before SEI message + * @param data Pointer to a variable to store allocated memory + * Upon return the variable will hold NULL on error or if frame has no S12M timecode info. + * Otherwise it will point to prefix_len uninitialized bytes followed by + * *sei_size SEI message + * @param sei_size Pointer to a variable to store generated SEI message length + * @return Zero on success, negative error code on failure + */ +int ff_alloc_timecode_sei(const AVFrame *frame, size_t prefix_len, + void **data, size_t *sei_size); + +/** * Get an estimated video bitrate based on frame size, frame rate and coded * bits per pixel. */ diff --git a/libavcodec/utils.c b/libavcodec/utils.c index b61f274ab3..2ece34f921 100644 --- a/libavcodec/utils.c +++ b/libavcodec/utils.c @@ -50,6 +50,7 @@ #include "thread.h" #include "frame_thread_encoder.h" #include "internal.h" +#include "put_bits.h" #include "raw.h" #include "bytestream.h" #include "version.h" @@ -2244,6 +2245,68 @@ int ff_alloc_a53_sei(const AVFrame *frame, size_t prefix_len, return 0; } +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_alloc_timecode_sei(const AVFrame *frame, size_t prefix_len, + void **data, size_t *sei_size) +{ + AVFrameSideData *sd = NULL; + uint8_t *sei_data; + PutBitContext pb; + uint32_t *tc; + int m; + + if (frame) + sd = av_frame_get_side_data(frame, AV_FRAME_DATA_S12M_TIMECODE); + + if (!sd) { + *data = NULL; + return 0; + } + tc = (uint32_t*)sd->data; + m = tc[0] & 3; + + *sei_size = sizeof(uint32_t) * 4; + *data = av_mallocz(*sei_size + prefix_len); + if (!*data) + return AVERROR(ENOMEM); + sei_data = (uint8_t*)*data + prefix_len; + + init_put_bits(&pb, sei_data, *sei_size); + 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); + + return 0; +} + int64_t ff_guess_coded_bitrate(AVCodecContext *avctx) { AVRational framerate = avctx->framerate; |