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 0 << 31 | // color frame flag (0: unsync mode, 1: sync mode)
69  drop << 30 | // drop frame flag (0: non drop, 1: drop)
70  (ff / 10) << 28 | // tens of frames
71  (ff % 10) << 24 | // units of frames
72  0 << 23 | // PC (NTSC) or BGF0 (PAL)
73  (ss / 10) << 20 | // tens of seconds
74  (ss % 10) << 16 | // units of seconds
75  0 << 15 | // BGF0 (NTSC) or BGF2 (PAL)
76  (mm / 10) << 12 | // tens of minutes
77  (mm % 10) << 8 | // units of minutes
78  0 << 7 | // BGF2 (NTSC) or PC (PAL)
79  0 << 6 | // BGF1
80  (hh / 10) << 4 | // tens of hours
81  (hh % 10); // units of hours
82 }
83 
84 uint32_t av_timecode_get_smpte(AVRational rate, int drop, int hh, int mm, int ss, int ff)
85 {
86  uint32_t tc = 0;
87  uint32_t frames;
88 
89  /* For SMPTE 12-M timecodes, frame count is a special case if > 30 FPS.
90  See SMPTE ST 12-1:2014 Sec 12.1 for more info. */
91  if (av_cmp_q(rate, (AVRational) {30, 1}) == 1) {
92  frames = ff / 2;
93  if (ff % 2 == 1) {
94  if (av_cmp_q(rate, (AVRational) {50, 1}) == 0)
95  tc |= (1 << 7);
96  else
97  tc |= (1 << 23);
98  }
99  } else {
100  frames = ff;
101  }
102 
103  tc |= drop << 30;
104  tc |= (frames / 10) << 28;
105  tc |= (frames % 10) << 24;
106  tc |= (ss / 10) << 20;
107  tc |= (ss % 10) << 16;
108  tc |= (mm / 10) << 12;
109  tc |= (mm % 10) << 8;
110  tc |= (hh / 10) << 4;
111  tc |= (hh % 10);
112 
113  return tc;
114 }
115 
116 char *av_timecode_make_string(const AVTimecode *tc, char *buf, int framenum)
117 {
118  int fps = tc->fps;
119  int drop = tc->flags & AV_TIMECODE_FLAG_DROPFRAME;
120  int hh, mm, ss, ff, neg = 0;
121 
122  framenum += tc->start;
123  if (drop)
124  framenum = av_timecode_adjust_ntsc_framenum2(framenum, fps);
125  if (framenum < 0) {
126  framenum = -framenum;
128  }
129  ff = framenum % fps;
130  ss = framenum / fps % 60;
131  mm = framenum / (fps*60) % 60;
132  hh = framenum / (fps*3600);
134  hh = hh % 24;
135  snprintf(buf, AV_TIMECODE_STR_SIZE, "%s%02d:%02d:%02d%c%02d",
136  neg ? "-" : "",
137  hh, mm, ss, drop ? ';' : ':', ff);
138  return buf;
139 }
140 
141 static unsigned bcd2uint(uint8_t bcd)
142 {
143  unsigned low = bcd & 0xf;
144  unsigned high = bcd >> 4;
145  if (low > 9 || high > 9)
146  return 0;
147  return low + 10*high;
148 }
149 
150 char *av_timecode_make_smpte_tc_string(char *buf, uint32_t tcsmpte, int prevent_df)
151 {
152  unsigned hh = bcd2uint(tcsmpte & 0x3f); // 6-bit hours
153  unsigned mm = bcd2uint(tcsmpte>>8 & 0x7f); // 7-bit minutes
154  unsigned ss = bcd2uint(tcsmpte>>16 & 0x7f); // 7-bit seconds
155  unsigned ff = bcd2uint(tcsmpte>>24 & 0x3f); // 6-bit frames
156  unsigned drop = tcsmpte & 1<<30 && !prevent_df; // 1-bit drop if not arbitrary bit
157  snprintf(buf, AV_TIMECODE_STR_SIZE, "%02u:%02u:%02u%c%02u",
158  hh, mm, ss, drop ? ';' : ':', ff);
159  return buf;
160 }
161 
162 char *av_timecode_make_mpeg_tc_string(char *buf, uint32_t tc25bit)
163 {
165  "%02"PRIu32":%02"PRIu32":%02"PRIu32"%c%02"PRIu32,
166  tc25bit>>19 & 0x1f, // 5-bit hours
167  tc25bit>>13 & 0x3f, // 6-bit minutes
168  tc25bit>>6 & 0x3f, // 6-bit seconds
169  tc25bit & 1<<24 ? ';' : ':', // 1-bit drop flag
170  tc25bit & 0x3f); // 6-bit frames
171  return buf;
172 }
173 
174 static int check_fps(int fps)
175 {
176  int i;
177  static const int supported_fps[] = {
178  24, 25, 30, 48, 50, 60, 100, 120, 150,
179  };
180 
181  for (i = 0; i < FF_ARRAY_ELEMS(supported_fps); i++)
182  if (fps == supported_fps[i])
183  return 0;
184  return -1;
185 }
186 
187 static int check_timecode(void *log_ctx, AVTimecode *tc)
188 {
189  if ((int)tc->fps <= 0) {
190  av_log(log_ctx, AV_LOG_ERROR, "Valid timecode frame rate must be specified. Minimum value is 1\n");
191  return AVERROR(EINVAL);
192  }
193  if ((tc->flags & AV_TIMECODE_FLAG_DROPFRAME) && tc->fps != 30 && tc->fps != 60) {
194  av_log(log_ctx, AV_LOG_ERROR, "Drop frame is only allowed with 30000/1001 or 60000/1001 FPS\n");
195  return AVERROR(EINVAL);
196  }
197  if (check_fps(tc->fps) < 0) {
198  av_log(log_ctx, AV_LOG_WARNING, "Using non-standard frame rate %d/%d\n",
199  tc->rate.num, tc->rate.den);
200  }
201  return 0;
202 }
203 
205 {
206  if (!rate.den || !rate.num)
207  return -1;
208  return (rate.num + rate.den/2) / rate.den;
209 }
210 
212 {
213  return check_fps(fps_from_frame_rate(rate));
214 }
215 
216 int av_timecode_init(AVTimecode *tc, AVRational rate, int flags, int frame_start, void *log_ctx)
217 {
218  memset(tc, 0, sizeof(*tc));
219  tc->start = frame_start;
220  tc->flags = flags;
221  tc->rate = rate;
222  tc->fps = fps_from_frame_rate(rate);
223  return check_timecode(log_ctx, tc);
224 }
225 
226 int av_timecode_init_from_string(AVTimecode *tc, AVRational rate, const char *str, void *log_ctx)
227 {
228  char c;
229  int hh, mm, ss, ff, ret;
230 
231  if (sscanf(str, "%d:%d:%d%c%d", &hh, &mm, &ss, &c, &ff) != 5) {
232  av_log(log_ctx, AV_LOG_ERROR, "Unable to parse timecode, "
233  "syntax: hh:mm:ss[:;.]ff\n");
234  return AVERROR_INVALIDDATA;
235  }
236 
237  memset(tc, 0, sizeof(*tc));
238  tc->flags = c != ':' ? AV_TIMECODE_FLAG_DROPFRAME : 0; // drop if ';', '.', ...
239  tc->rate = rate;
240  tc->fps = fps_from_frame_rate(rate);
241 
242  ret = check_timecode(log_ctx, tc);
243  if (ret < 0)
244  return ret;
245 
246  tc->start = (hh*3600 + mm*60 + ss) * tc->fps + ff;
247  if (tc->flags & AV_TIMECODE_FLAG_DROPFRAME) { /* adjust frame number */
248  int tmins = 60*hh + mm;
249  tc->start -= (tc->fps == 30 ? 2 : 4) * (tmins - tmins/10);
250  }
251  return 0;
252 }
#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:162
#define tc
Definition: regdef.h:69
static int check_timecode(void *log_ctx, AVTimecode *tc)
Definition: timecode.c:187
if it could not because there are no more frames
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:226
static unsigned bcd2uint(uint8_t bcd)
Definition: timecode.c:141
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:216
static int check_fps(int fps)
Definition: timecode.c:174
#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
#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:150
#define flags(name, subs,...)
Definition: cbs_av1.c:560
static int fps_from_frame_rate(AVRational rate)
Definition: timecode.c:204
char * av_timecode_make_string(const AVTimecode *tc, char *buf, int framenum)
Load timecode string in buf.
Definition: timecode.c:116
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:211
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:84
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