diff mbox

[FFmpeg-devel,3/3] h264/pic_timing: support multiple timecodes

Message ID 20181009133204.29686-4-joshdk@obe.tv
State Accepted
Headers show

Commit Message

joshdk@ob-encoder.com Oct. 9, 2018, 1:32 p.m. UTC
From: Josh de Kock <joshdk@obe.tv>

---
 libavcodec/h264_sei.c     | 21 ++++++++------
 libavcodec/h264_sei.h     | 28 +++++++++++++------
 libavcodec/h264_slice.c   | 59 ++++++++++++++++++++++-----------------
 libavfilter/vf_showinfo.c | 10 +++++++
 4 files changed, 75 insertions(+), 43 deletions(-)

Comments

joshdk@ob-encoder.com Oct. 11, 2018, 1:04 p.m. UTC | #1
On 9 October 2018 at 21:03, Carl Eugen Hoyos <ceffmpeg@gmail.com> wrote:
> 2018-10-09 15:32 GMT+02:00, joshdk@ob-encoder.com <joshdk@ob-encoder.com>:
>> From: Josh de Kock <joshdk@obe.tv>
>
>> [...]
>
> If the first patch gets committed as-is, please split this one
> in a functional and a cosmetic patch, above is unreviewable.
>
> Thank you, Carl Eugen

I assume you mean split vf_showinfo out, I had intended to do that but
clearly I forgot so
will do that. And why is it unreviewable?

Josh
Carl Eugen Hoyos Oct. 12, 2018, 9:19 a.m. UTC | #2
2018-10-11 15:04 GMT+02:00, Joshua de Kock <joshdk@ob-encoder.com>:
> On 9 October 2018 at 21:03, Carl Eugen Hoyos <ceffmpeg@gmail.com> wrote:
>> 2018-10-09 15:32 GMT+02:00, joshdk@ob-encoder.com <joshdk@ob-encoder.com>:
>>> From: Josh de Kock <joshdk@obe.tv>
>>
>>> [...]
>>
>> If the first patch gets committed as-is, please split this one
>> in a functional and a cosmetic patch, above is unreviewable.
>>
>> Thank you, Carl Eugen
>
> I assume you mean split vf_showinfo out,

No.

> I had intended to do that but clearly I forgot so will do that.

> And why is it unreviewable?

It mixed white-space-only changes with functional changes
so that the original and the new lines get separated and make
the patch much more difficult to read than necessary.

Carl Eugen
diff mbox

Patch

diff --git a/libavcodec/h264_sei.c b/libavcodec/h264_sei.c
index 275224eabe..d4eb9c0dab 100644
--- a/libavcodec/h264_sei.c
+++ b/libavcodec/h264_sei.c
@@ -84,8 +84,10 @@  static int decode_picture_timing(H264SEIPictureTiming *h, GetBitContext *gb,
             return AVERROR_INVALIDDATA;
 
         num_clock_ts = sei_num_clock_ts_table[h->pic_struct];
+        h->timecode_cnt = 0;
         for (i = 0; i < num_clock_ts; i++) {
             if (get_bits(gb, 1)) {                      /* clock_timestamp_flag */
+                H264SEITimeCode *tc = &h->timecode[h->timecode_cnt++];
                 unsigned int full_timestamp_flag;
                 unsigned int counting_type, cnt_dropped_flag;
                 h->ct_type |= 1 << get_bits(gb, 2);
@@ -95,20 +97,21 @@  static int decode_picture_timing(H264SEIPictureTiming *h, GetBitContext *gb,
                 skip_bits(gb, 1);                       /* discontinuity_flag */
                 cnt_dropped_flag = get_bits(gb, 1);      /* cnt_dropped_flag */
                 if (cnt_dropped_flag && counting_type > 1 && counting_type < 7)
-                    h->tc_dropframe = 1;
-                h->tc_frames = get_bits(gb, 8);         /* n_frames */
+                    tc->dropframe = 1;
+                tc->frame = get_bits(gb, 8);         /* n_frames */
                 if (full_timestamp_flag) {
-                    h->fulltc_received = 1;
-                    h->tc_seconds = get_bits(gb, 6); /* seconds_value 0..59 */
-                    h->tc_minutes = get_bits(gb, 6); /* minutes_value 0..59 */
-                    h->tc_hours = get_bits(gb, 5);   /* hours_value 0..23 */
+                    tc->full = 1;
+                    tc->seconds = get_bits(gb, 6); /* seconds_value 0..59 */
+                    tc->minutes = get_bits(gb, 6); /* minutes_value 0..59 */
+                    tc->hours = get_bits(gb, 5);   /* hours_value 0..23 */
                 } else {
+                    tc->seconds = tc->minutes = tc->hours = tc->full = 0;
                     if (get_bits(gb, 1)) {             /* seconds_flag */
-                        h->tc_seconds = get_bits(gb, 6);
+                        tc->seconds = get_bits(gb, 6);
                         if (get_bits(gb, 1)) {         /* minutes_flag */
-                            h->tc_minutes = get_bits(gb, 6);
+                            tc->minutes = get_bits(gb, 6);
                             if (get_bits(gb, 1))       /* hours_flag */
-                                h->tc_minutes = get_bits(gb, 5);
+                                tc->hours = get_bits(gb, 5);
                         }
                     }
                 }
diff --git a/libavcodec/h264_sei.h b/libavcodec/h264_sei.h
index 3b8806be0a..a75c3aa175 100644
--- a/libavcodec/h264_sei.h
+++ b/libavcodec/h264_sei.h
@@ -67,6 +67,17 @@  typedef enum {
     H264_SEI_FPA_TYPE_2D                  = 6,
 } H264_SEI_FpaType;
 
+typedef struct H264SEITimeCode {
+    /* When not continuously receiving full timecodes, we have to reference
+       the previous timecode received */
+    int full;
+    int frame;
+    int seconds;
+    int minutes;
+    int hours;
+    int dropframe;
+} H264SEITimeCode;
+
 typedef struct H264SEIPictureTiming {
     int present;
     H264_SEI_PicStructType pic_struct;
@@ -88,14 +99,15 @@  typedef struct H264SEIPictureTiming {
      */
     int cpb_removal_delay;
 
-    /* When not continuously receiving full timecodes, we have to reference
-       the previous timecode received */
-    int fulltc_received;
-    int tc_frames;
-    int tc_seconds;
-    int tc_minutes;
-    int tc_hours;
-    int tc_dropframe;
+    /**
+     * Maximum three timecodes in a pic_timing SEI.
+     */
+    H264SEITimeCode timecode[3];
+
+    /**
+     * Number of timecode in use
+     */
+    int timecode_cnt;
 } H264SEIPictureTiming;
 
 typedef struct H264SEIAFD {
diff --git a/libavcodec/h264_slice.c b/libavcodec/h264_slice.c
index 973f5761ef..aaf0006a32 100644
--- a/libavcodec/h264_slice.c
+++ b/libavcodec/h264_slice.c
@@ -1287,42 +1287,49 @@  static int h264_export_frame_props(H264Context *h)
         h->avctx->properties |= FF_CODEC_PROPERTY_CLOSED_CAPTIONS;
     }
 
-    if (h->sei.picture_timing.fulltc_received) {
+    if (h->sei.picture_timing.timecode_cnt > 0) {
         uint32_t tc = 0;
-        uint32_t frames;
+        uint32_t *tc_sd;
 
         AVFrameSideData *tcside = av_frame_new_side_data(cur->f,
                                                          AV_FRAME_DATA_S12M_TIMECODE,
-                                                         sizeof(uint32_t));
+                                                         sizeof(uint32_t)*4);
         if (!tcside)
             return AVERROR(ENOMEM);
 
-        /* For SMPTE 12-M timecodes, frame count is a special case if > 30 FPS.
-           See SMPTE ST 12-1:2014 Sec 12.1 for more info. */
-        if (av_cmp_q(h->avctx->framerate, (AVRational) {30, 1}) == 1) {
-            frames = h->sei.picture_timing.tc_frames / 2;
-            if (h->sei.picture_timing.tc_frames % 2 == 1) {
-                if (av_cmp_q(h->avctx->framerate, (AVRational) {50, 1}) == 0)
-                    tc |= (1 << 7);
-                else
-                    tc |= (1 << 23);
+        tc_sd = (uint32_t*)tcside->data;
+        tc_sd[0] = h->sei.picture_timing.timecode_cnt;
+
+        for (int i = 0; i < tc_sd[0]; i++) {
+            uint32_t frames;
+
+            /* For SMPTE 12-M timecodes, frame count is a special case if > 30 FPS.
+               See SMPTE ST 12-1:2014 Sec 12.1 for more info. */
+            if (av_cmp_q(h->avctx->framerate, (AVRational) {30, 1}) == 1) {
+                frames = h->sei.picture_timing.timecode[i].frame / 2;
+                if (h->sei.picture_timing.timecode[i].frame % 2 == 1) {
+                    if (av_cmp_q(h->avctx->framerate, (AVRational) {50, 1}) == 0)
+                        tc |= (1 << 7);
+                    else
+                        tc |= (1 << 23);
+                }
+            } else {
+                frames = h->sei.picture_timing.timecode[i].frame;
             }
-        } else {
-            frames = h->sei.picture_timing.tc_frames;
-        }
 
-        tc |= h->sei.picture_timing.tc_dropframe << 30;
-        tc |= (frames / 10) << 28;
-        tc |= (frames % 10) << 24;
-        tc |= (h->sei.picture_timing.tc_seconds / 10) << 20;
-        tc |= (h->sei.picture_timing.tc_seconds % 10) << 16;
-        tc |= (h->sei.picture_timing.tc_minutes / 10) << 12;
-        tc |= (h->sei.picture_timing.tc_minutes % 10) << 8;
-        tc |= (h->sei.picture_timing.tc_hours / 10) << 4;
-        tc |= (h->sei.picture_timing.tc_hours % 10);
+            tc |= h->sei.picture_timing.timecode[i].dropframe << 30;
+            tc |= (frames / 10) << 28;
+            tc |= (frames % 10) << 24;
+            tc |= (h->sei.picture_timing.timecode[i].seconds / 10) << 20;
+            tc |= (h->sei.picture_timing.timecode[i].seconds % 10) << 16;
+            tc |= (h->sei.picture_timing.timecode[i].minutes / 10) << 12;
+            tc |= (h->sei.picture_timing.timecode[i].minutes % 10) << 8;
+            tc |= (h->sei.picture_timing.timecode[i].hours / 10) << 4;
+            tc |= (h->sei.picture_timing.timecode[i].hours % 10);
 
-        memcpy(tcside->data, &tc, sizeof(uint32_t));
-        h->sei.picture_timing.fulltc_received = 0;
+            tc_sd[i + 1] = tc;
+        }
+        h->sei.picture_timing.timecode_cnt = 0;
     }
 
     if (h->sei.alternative_transfer.present &&
diff --git a/libavfilter/vf_showinfo.c b/libavfilter/vf_showinfo.c
index d1d1415c0b..689b5399db 100644
--- a/libavfilter/vf_showinfo.c
+++ b/libavfilter/vf_showinfo.c
@@ -32,6 +32,7 @@ 
 #include "libavutil/spherical.h"
 #include "libavutil/stereo3d.h"
 #include "libavutil/timestamp.h"
+#include "libavutil/timecode.h"
 
 #include "avfilter.h"
 #include "internal.h"
@@ -174,6 +175,15 @@  static int filter_frame(AVFilterLink *inlink, AVFrame *frame)
         case AV_FRAME_DATA_STEREO3D:
             dump_stereo3d(ctx, sd);
             break;
+        case AV_FRAME_DATA_S12M_TIMECODE: {
+            uint32_t *tc = (uint32_t*)sd->data;
+            for (int j = 1; j < tc[0]; j++) {
+                char tcbuf[AV_TIMECODE_STR_SIZE];
+                av_timecode_make_smpte_tc_string(tcbuf, tc[j], 0);
+                av_log(ctx, AV_LOG_INFO, "timecode - %s%s", tcbuf, j != tc[0] - 1 ? ", " : "");
+            }
+            break;
+        }
         case AV_FRAME_DATA_DISPLAYMATRIX:
             av_log(ctx, AV_LOG_INFO, "displaymatrix: rotation of %.2f degrees",
                    av_display_rotation_get((int32_t *)sd->data));