summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLimin Wang <lance.lmwang@gmail.com>2020-06-18 11:58:50 +0800
committerLimin Wang <lance.lmwang@gmail.com>2020-06-28 21:00:52 +0800
commit9294f5b497e6253c4a3c510b86eb63984ce9dfe7 (patch)
tree7eed382a4823740c329a4b0cb6f0633710b0d254
parent5151f6d2953d75bd26898b2bd51fe095796c07ad (diff)
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.h15
-rw-r--r--libavcodec/utils.c63
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;