FFmpeg
timecode.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2006 Smartjog S.A.S, Baptiste Coudurier <baptiste.coudurier@gmail.com>
3  * Copyright (c) 2011-2012 Smartjog S.A.S, Clément Bœsch <clement.boesch@smartjog.com>
4  *
5  * This file is part of FFmpeg.
6  *
7  * FFmpeg is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * FFmpeg is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with FFmpeg; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20  */
21 
22 /**
23  * @file
24  * Timecode helpers
25  * @see https://en.wikipedia.org/wiki/SMPTE_time_code
26  * @see http://www.dropframetimecode.org
27  */
28 
29 #include <stdio.h>
30 #include "timecode.h"
31 #include "log.h"
32 #include "error.h"
33 
34 int av_timecode_adjust_ntsc_framenum2(int framenum, int fps)
35 {
36  /* only works for NTSC 29.97 and 59.94 */
37  int drop_frames = 0;
38  int d, m, frames_per_10mins;
39 
40  if (fps == 30) {
41  drop_frames = 2;
42  frames_per_10mins = 17982;
43  } else if (fps == 60) {
44  drop_frames = 4;
45  frames_per_10mins = 35964;
46  } else
47  return framenum;
48 
49  d = framenum / frames_per_10mins;
50  m = framenum % frames_per_10mins;
51 
52  return framenum + 9 * drop_frames * d + drop_frames * ((m - drop_frames) / (frames_per_10mins / 10));
53 }
54 
55 uint32_t av_timecode_get_smpte_from_framenum(const AVTimecode *tc, int framenum)
56 {
57  unsigned fps = tc->fps;
58  int drop = !!(tc->flags & AV_TIMECODE_FLAG_DROPFRAME);
59  int hh, mm, ss, ff;
60 
61  framenum += tc->start;
62  if (drop)
63  framenum = av_timecode_adjust_ntsc_framenum2(framenum, tc->fps);
64  ff = framenum % fps;
65  ss = framenum / fps % 60;
66  mm = framenum / (fps*60) % 60;
67  hh = framenum / (fps*3600) % 24;
68  return av_timecode_get_smpte(tc->rate, drop, hh, mm, ss, ff);
69 }
70 
71 uint32_t av_timecode_get_smpte(AVRational rate, int drop, int hh, int mm, int ss, int ff)
72 {
73  uint32_t tc = 0;
74 
75  /* For SMPTE 12-M timecodes, frame count is a special case if > 30 FPS.
76  See SMPTE ST 12-1:2014 Sec 12.1 for more info. */
77  if (av_cmp_q(rate, (AVRational) {30, 1}) == 1) {
78  if (ff % 2 == 1) {
79  if (av_cmp_q(rate, (AVRational) {50, 1}) == 0)
80  tc |= (1 << 7);
81  else
82  tc |= (1 << 23);
83  }
84  ff /= 2;
85  }
86 
87  hh = hh % 24;
88  mm = av_clip(mm, 0, 59);
89  ss = av_clip(ss, 0, 59);
90  ff = ff % 40;
91 
92  tc |= drop << 30;
93  tc |= (ff / 10) << 28;
94  tc |= (ff % 10) << 24;
95  tc |= (ss / 10) << 20;
96  tc |= (ss % 10) << 16;
97  tc |= (mm / 10) << 12;
98  tc |= (mm % 10) << 8;
99  tc |= (hh / 10) << 4;
100  tc |= (hh % 10);
101 
102  return tc;
103 }
104 
105 char *av_timecode_make_string(const AVTimecode *tc, char *buf, int framenum)
106 {
107  int fps = tc->fps;
108  int drop = tc->flags & AV_TIMECODE_FLAG_DROPFRAME;
109  int hh, mm, ss, ff, neg = 0;
110 
111  framenum += tc->start;
112  if (drop)
113  framenum = av_timecode_adjust_ntsc_framenum2(framenum, fps);
114  if (framenum < 0) {
115  framenum = -framenum;
117  }
118  ff = framenum % fps;
119  ss = framenum / fps % 60;
120  mm = framenum / (fps*60) % 60;
121  hh = framenum / (fps*3600);
123  hh = hh % 24;
124  snprintf(buf, AV_TIMECODE_STR_SIZE, "%s%02d:%02d:%02d%c%02d",
125  neg ? "-" : "",
126  hh, mm, ss, drop ? ';' : ':', ff);
127  return buf;
128 }
129 
130 static unsigned bcd2uint(uint8_t bcd)
131 {
132  unsigned low = bcd & 0xf;
133  unsigned high = bcd >> 4;
134  if (low > 9 || high > 9)
135  return 0;
136  return low + 10*high;
137 }
138 
139 char *av_timecode_make_smpte_tc_string2(char *buf, AVRational rate, uint32_t tcsmpte, int prevent_df, int skip_field)
140 {
141  unsigned hh = bcd2uint(tcsmpte & 0x3f); // 6-bit hours
142  unsigned mm = bcd2uint(tcsmpte>>8 & 0x7f); // 7-bit minutes
143  unsigned ss = bcd2uint(tcsmpte>>16 & 0x7f); // 7-bit seconds
144  unsigned ff = bcd2uint(tcsmpte>>24 & 0x3f); // 6-bit frames
145  unsigned drop = tcsmpte & 1<<30 && !prevent_df; // 1-bit drop if not arbitrary bit
146 
147  if (av_cmp_q(rate, (AVRational) {30, 1}) == 1) {
148  ff <<= 1;
149  if (!skip_field) {
150  if (av_cmp_q(rate, (AVRational) {50, 1}) == 0)
151  ff += !!(tcsmpte & 1 << 7);
152  else
153  ff += !!(tcsmpte & 1 << 23);
154  }
155  }
156 
157  snprintf(buf, AV_TIMECODE_STR_SIZE, "%02u:%02u:%02u%c%02u",
158  hh, mm, ss, drop ? ';' : ':', ff);
159  return buf;
160 
161 }
162 
163 char *av_timecode_make_smpte_tc_string(char *buf, uint32_t tcsmpte, int prevent_df)
164 {
165  return av_timecode_make_smpte_tc_string2(buf, (AVRational){30, 1}, tcsmpte, prevent_df, 1);
166 }
167 
168 char *av_timecode_make_mpeg_tc_string(char *buf, uint32_t tc25bit)
169 {
171  "%02"PRIu32":%02"PRIu32":%02"PRIu32"%c%02"PRIu32,
172  tc25bit>>19 & 0x1f, // 5-bit hours
173  tc25bit>>13 & 0x3f, // 6-bit minutes
174  tc25bit>>6 & 0x3f, // 6-bit seconds
175  tc25bit & 1<<24 ? ';' : ':', // 1-bit drop flag
176  tc25bit & 0x3f); // 6-bit frames
177  return buf;
178 }
179 
180 static int check_fps(int fps)
181 {
182  int i;
183  static const int supported_fps[] = {
184  24, 25, 30, 48, 50, 60, 100, 120, 150,
185  };
186 
187  for (i = 0; i < FF_ARRAY_ELEMS(supported_fps); i++)
188  if (fps == supported_fps[i])
189  return 0;
190  return -1;
191 }
192 
193 static int check_timecode(void *log_ctx, AVTimecode *tc)
194 {
195  if ((int)tc->fps <= 0) {
196  av_log(log_ctx, AV_LOG_ERROR, "Valid timecode frame rate must be specified. Minimum value is 1\n");
197  return AVERROR(EINVAL);
198  }
199  if ((tc->flags & AV_TIMECODE_FLAG_DROPFRAME) && tc->fps != 30 && tc->fps != 60) {
200  av_log(log_ctx, AV_LOG_ERROR, "Drop frame is only allowed with 30000/1001 or 60000/1001 FPS\n");
201  return AVERROR(EINVAL);
202  }
203  if (check_fps(tc->fps) < 0) {
204  av_log(log_ctx, AV_LOG_WARNING, "Using non-standard frame rate %d/%d\n",
205  tc->rate.num, tc->rate.den);
206  }
207  return 0;
208 }
209 
211 {
212  if (!rate.den || !rate.num)
213  return -1;
214  return (rate.num + rate.den/2) / rate.den;
215 }
216 
218 {
219  return check_fps(fps_from_frame_rate(rate));
220 }
221 
222 int av_timecode_init(AVTimecode *tc, AVRational rate, int flags, int frame_start, void *log_ctx)
223 {
224  memset(tc, 0, sizeof(*tc));
225  tc->start = frame_start;
226  tc->flags = flags;
227  tc->rate = rate;
228  tc->fps = fps_from_frame_rate(rate);
229  return check_timecode(log_ctx, tc);
230 }
231 
232 int av_timecode_init_from_string(AVTimecode *tc, AVRational rate, const char *str, void *log_ctx)
233 {
234  char c;
235  int hh, mm, ss, ff, ret;
236 
237  if (sscanf(str, "%d:%d:%d%c%d", &hh, &mm, &ss, &c, &ff) != 5) {
238  av_log(log_ctx, AV_LOG_ERROR, "Unable to parse timecode, "
239  "syntax: hh:mm:ss[:;.]ff\n");
240  return AVERROR_INVALIDDATA;
241  }
242 
243  memset(tc, 0, sizeof(*tc));
244  tc->flags = c != ':' ? AV_TIMECODE_FLAG_DROPFRAME : 0; // drop if ';', '.', ...
245  tc->rate = rate;
246  tc->fps = fps_from_frame_rate(rate);
247 
248  ret = check_timecode(log_ctx, tc);
249  if (ret < 0)
250  return ret;
251 
252  tc->start = (hh*3600 + mm*60 + ss) * tc->fps + ff;
253  if (tc->flags & AV_TIMECODE_FLAG_DROPFRAME) { /* adjust frame number */
254  int tmins = 60*hh + mm;
255  tc->start -= (tc->fps == 30 ? 2 : 4) * (tmins - tmins/10);
256  }
257  return 0;
258 }
#define AVERROR_INVALIDDATA
Invalid data found when processing input.
Definition: error.h:59
#define AV_LOG_WARNING
Something somehow does not look correct.
Definition: log.h:200
int num
Numerator.
Definition: rational.h:59
char * av_timecode_make_mpeg_tc_string(char *buf, uint32_t tc25bit)
Get the timecode string from the 25-bit timecode format (MPEG GOP format).
Definition: timecode.c:168
#define tc
Definition: regdef.h:69
static int check_timecode(void *log_ctx, AVTimecode *tc)
Definition: timecode.c:193
int av_timecode_init_from_string(AVTimecode *tc, AVRational rate, const char *str, void *log_ctx)
Parse timecode representation (hh:mm:ss[:;.
Definition: timecode.c:232
static unsigned bcd2uint(uint8_t bcd)
Definition: timecode.c:130
uint8_t
timecode is drop frame
Definition: timecode.h:36
Undefined Behavior In the C some operations are like signed integer dereferencing freed accessing outside allocated Undefined Behavior must not occur in a C it is not safe even if the output of undefined operations is unused The unsafety may seem nit picking but Optimizing compilers have in fact optimized code on the assumption that no undefined Behavior occurs Optimizing code based on wrong assumptions can and has in some cases lead to effects beyond the output of computations The signed integer overflow problem in speed critical code Code which is highly optimized and works with signed integers sometimes has the problem that often the output of the computation does not c
Definition: undefined.txt:32
int start
timecode frame start (first base frame number)
Definition: timecode.h:42
#define av_log(a,...)
int av_timecode_init(AVTimecode *tc, AVRational rate, int flags, int frame_start, void *log_ctx)
Init a timecode struct with the passed parameters.
Definition: timecode.c:222
static int check_fps(int fps)
Definition: timecode.c:180
#define AV_LOG_ERROR
Something went wrong and cannot losslessly be recovered.
Definition: log.h:194
error code definitions
unsigned fps
frame per second; must be consistent with the rate field
Definition: timecode.h:45
#define ss(width, name, subs,...)
Definition: cbs_vp9.c:261
char * av_timecode_make_smpte_tc_string2(char *buf, AVRational rate, uint32_t tcsmpte, int prevent_df, int skip_field)
Get the timecode string from the SMPTE timecode format.
Definition: timecode.c:139
#define FF_ARRAY_ELEMS(a)
if(ret)
int av_timecode_adjust_ntsc_framenum2(int framenum, int fps)
Adjust frame number for NTSC drop frame time code.
Definition: timecode.c:34
Timecode helpers header.
timecode wraps after 24 hours
Definition: timecode.h:37
AVRational rate
frame rate in rational form
Definition: timecode.h:44
static int frame_start(MpegEncContext *s)
Rational number (pair of numerator and denominator).
Definition: rational.h:58
#define snprintf
Definition: snprintf.h:34
char * av_timecode_make_smpte_tc_string(char *buf, uint32_t tcsmpte, int prevent_df)
Get the timecode string from the SMPTE timecode format.
Definition: timecode.c:163
#define flags(name, subs,...)
Definition: cbs_av1.c:560
static int fps_from_frame_rate(AVRational rate)
Definition: timecode.c:210
char * av_timecode_make_string(const AVTimecode *tc, char *buf, int framenum)
Load timecode string in buf.
Definition: timecode.c:105
static int av_cmp_q(AVRational a, AVRational b)
Compare two rationals.
Definition: rational.h:89
negative time values are allowed
Definition: timecode.h:38
int den
Denominator.
Definition: rational.h:60
int av_timecode_check_frame_rate(AVRational rate)
Check if the timecode feature is available for the given frame rate.
Definition: timecode.c:217
uint32_t av_timecode_get_smpte(AVRational rate, int drop, int hh, int mm, int ss, int ff)
Convert sei info to SMPTE 12M binary representation.
Definition: timecode.c:71
Filter the word “frame” indicates either a video frame or a group of audio as stored in an AVFrame structure Format for each input and each output the list of supported formats For video that means pixel format For audio that means channel sample they are references to shared objects When the negotiation mechanism computes the intersection of the formats supported at each end of a all references to both lists are replaced with a reference to the intersection And when a single format is eventually chosen for a link amongst the remaining all references to the list are updated That means that if a filter requires that its input and output have the same format amongst a supported all it has to do is use a reference to the same list of formats query_formats can leave some formats unset and return AVERROR(EAGAIN) to cause the negotiation mechanism toagain later.That can be used by filters with complex requirements to use the format negotiated on one link to set the formats supported on another.Frame references ownership and permissions
uint32_t flags
flags such as drop frame, +24 hours support, ...
Definition: timecode.h:43
int i
Definition: input.c:407
#define AV_TIMECODE_STR_SIZE
Definition: timecode.h:33
uint32_t av_timecode_get_smpte_from_framenum(const AVTimecode *tc, int framenum)
Convert frame number to SMPTE 12M binary representation.
Definition: timecode.c:55