]> git.sesse.net Git - ffmpeg/blobdiff - libavutil/timecode.c
avutil/timecode: do not trash bits on invalid av_timecode_get_smpte arguments
[ffmpeg] / libavutil / timecode.c
index 60077ba0c04407459cf91e19911844b2eded6509..806638ddfcefaf39ba6828f82c743c405851430b 100644 (file)
@@ -65,20 +65,41 @@ uint32_t av_timecode_get_smpte_from_framenum(const AVTimecode *tc, int framenum)
     ss = framenum / fps      % 60;
     mm = framenum / (fps*60) % 60;
     hh = framenum / (fps*3600) % 24;
-    return 0         << 31 | // color frame flag (0: unsync mode, 1: sync mode)
-           drop      << 30 | // drop  frame flag (0: non drop,    1: drop)
-           (ff / 10) << 28 | // tens  of frames
-           (ff % 10) << 24 | // units of frames
-           0         << 23 | // PC (NTSC) or BGF0 (PAL)
-           (ss / 10) << 20 | // tens  of seconds
-           (ss % 10) << 16 | // units of seconds
-           0         << 15 | // BGF0 (NTSC) or BGF2 (PAL)
-           (mm / 10) << 12 | // tens  of minutes
-           (mm % 10) <<  8 | // units of minutes
-           0         <<  7 | // BGF2 (NTSC) or PC (PAL)
-           0         <<  6 | // BGF1
-           (hh / 10) <<  4 | // tens  of hours
-           (hh % 10);        // units of hours
+    return av_timecode_get_smpte(tc->rate, drop, hh, mm, ss, ff);
+}
+
+uint32_t av_timecode_get_smpte(AVRational rate, int drop, int hh, int mm, int ss, int ff)
+{
+    uint32_t tc = 0;
+
+    /* 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(rate, (AVRational) {30, 1}) == 1) {
+        if (ff % 2 == 1) {
+            if (av_cmp_q(rate, (AVRational) {50, 1}) == 0)
+                tc |= (1 << 7);
+            else
+                tc |= (1 << 23);
+        }
+        ff /= 2;
+    }
+
+    hh = hh % 24;
+    mm = av_clip(mm, 0, 59);
+    ss = av_clip(ss, 0, 59);
+    ff = ff % 40;
+
+    tc |= drop << 30;
+    tc |= (ff / 10) << 28;
+    tc |= (ff % 10) << 24;
+    tc |= (ss / 10) << 20;
+    tc |= (ss % 10) << 16;
+    tc |= (mm / 10) << 12;
+    tc |= (mm % 10) << 8;
+    tc |= (hh / 10) << 4;
+    tc |= (hh % 10);
+
+    return tc;
 }
 
 char *av_timecode_make_string(const AVTimecode *tc, char *buf, int framenum)