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>
5 * This file is part of FFmpeg.
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.
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.
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
25 * @see https://en.wikipedia.org/wiki/SMPTE_time_code
26 * @see http://www.dropframetimecode.org
32 #include "timecode_internal.h"
36 int av_timecode_adjust_ntsc_framenum2(int framenum
, int fps
)
38 /* only works for multiples of NTSC 29.97 */
40 int d
, m
, frames_per_10mins
;
42 if (fps
&& fps
% 30 == 0) {
43 drop_frames
= fps
/ 30 * 2;
44 frames_per_10mins
= fps
/ 30 * 17982;
48 d
= framenum
/ frames_per_10mins
;
49 m
= framenum
% frames_per_10mins
;
51 return framenum
+ 9U * drop_frames
* d
+ drop_frames
* ((m
- drop_frames
) / (frames_per_10mins
/ 10));
54 uint32_t av_timecode_get_smpte_from_framenum(const AVTimecode
*tc
, int framenum
)
56 unsigned fps
= tc
->fps
;
57 int drop
= !!(tc
->flags
& AV_TIMECODE_FLAG_DROPFRAME
);
60 framenum
+= tc
->start
;
62 framenum
= av_timecode_adjust_ntsc_framenum2(framenum
, tc
->fps
);
64 ss
= framenum
/ fps
% 60;
65 mm
= framenum
/ (fps
*60LL) % 60;
66 hh
= framenum
/ (fps
*3600LL) % 24;
67 return av_timecode_get_smpte(tc
->rate
, drop
, hh
, mm
, ss
, ff
);
70 uint32_t av_timecode_get_smpte(AVRational rate
, int drop
, int hh
, int mm
, int ss
, int ff
)
74 /* For SMPTE 12-M timecodes, frame count is a special case if > 30 FPS.
75 See SMPTE ST 12-1:2014 Sec 12.1 for more info. */
76 if (av_cmp_q(rate
, (AVRational
) {30, 1}) == 1) {
78 if (av_cmp_q(rate
, (AVRational
) {50, 1}) == 0)
87 mm
= av_clip(mm
, 0, 59);
88 ss
= av_clip(ss
, 0, 59);
92 tc
|= (ff
/ 10) << 28;
93 tc
|= (ff
% 10) << 24;
94 tc
|= (ss
/ 10) << 20;
95 tc
|= (ss
% 10) << 16;
96 tc
|= (mm
/ 10) << 12;
104 char *av_timecode_make_string(const AVTimecode
*tc
, char *buf
, int framenum_arg
)
106 unsigned fps
= tc
->fps
;
107 int drop
= tc
->flags
& AV_TIMECODE_FLAG_DROPFRAME
;
108 int hh
, mm
, ss
, ff
, ff_len
, neg
= 0;
109 int64_t framenum
= framenum_arg
;
111 framenum
+= tc
->start
;
113 framenum
= av_timecode_adjust_ntsc_framenum2(framenum
, fps
);
115 framenum
= -framenum
;
116 neg
= tc
->flags
& AV_TIMECODE_FLAG_ALLOWNEGATIVE
;
119 ss
= framenum
/ fps
% 60;
120 mm
= framenum
/ (fps
*60LL) % 60;
121 hh
= framenum
/ (fps
*3600LL);
122 if (tc
->flags
& AV_TIMECODE_FLAG_24HOURSMAX
)
124 ff_len
= fps
> 10000 ? 5 : fps
> 1000 ? 4 : fps
> 100 ? 3 : fps
> 10 ? 2 : 1;
125 snprintf(buf
, AV_TIMECODE_STR_SIZE
, "%s%02d:%02d:%02d%c%0*d",
127 hh
, mm
, ss
, drop
? ';' : ':', ff_len
, ff
);
131 char *av_timecode_make_smpte_tc_string2(char *buf
, AVRational rate
, uint32_t tcsmpte
, int prevent_df
, int skip_field
)
133 unsigned hh
, mm
, ss
, ff
, drop
;
134 ff_timecode_set_smpte(&drop
, &hh
, &mm
, &ss
, &ff
, rate
, tcsmpte
, prevent_df
, skip_field
);
136 snprintf(buf
, AV_TIMECODE_STR_SIZE
, "%02u:%02u:%02u%c%02u",
137 hh
, mm
, ss
, drop
? ';' : ':', ff
);
142 char *av_timecode_make_smpte_tc_string(char *buf
, uint32_t tcsmpte
, int prevent_df
)
144 return av_timecode_make_smpte_tc_string2(buf
, (AVRational
){30, 1}, tcsmpte
, prevent_df
, 1);
147 char *av_timecode_make_mpeg_tc_string(char *buf
, uint32_t tc25bit
)
149 snprintf(buf
, AV_TIMECODE_STR_SIZE
,
150 "%02"PRIu32
":%02"PRIu32
":%02"PRIu32
"%c%02"PRIu32
,
151 tc25bit
>>19 & 0x1f, // 5-bit hours
152 tc25bit
>>13 & 0x3f, // 6-bit minutes
153 tc25bit
>>6 & 0x3f, // 6-bit seconds
154 tc25bit
& 1<<24 ? ';' : ':', // 1-bit drop flag
155 tc25bit
& 0x3f); // 6-bit frames
159 static int check_fps(int fps
)
162 static const int supported_fps
[] = {
163 24, 25, 30, 48, 50, 60, 100, 120, 150,
166 for (i
= 0; i
< FF_ARRAY_ELEMS(supported_fps
); i
++)
167 if (fps
== supported_fps
[i
])
172 static int check_timecode(void *log_ctx
, AVTimecode
*tc
)
174 if ((int)tc
->fps
<= 0) {
175 av_log(log_ctx
, AV_LOG_ERROR
, "Valid timecode frame rate must be specified. Minimum value is 1\n");
176 return AVERROR(EINVAL
);
178 if ((tc
->flags
& AV_TIMECODE_FLAG_DROPFRAME
) && tc
->fps
% 30 != 0) {
179 av_log(log_ctx
, AV_LOG_ERROR
, "Drop frame is only allowed with multiples of 30000/1001 FPS\n");
180 return AVERROR(EINVAL
);
182 if (check_fps(tc
->fps
) < 0) {
183 av_log(log_ctx
, AV_LOG_WARNING
, "Using non-standard frame rate %d/%d\n",
184 tc
->rate
.num
, tc
->rate
.den
);
189 static int fps_from_frame_rate(AVRational rate
)
191 if (!rate
.den
|| !rate
.num
)
193 return (rate
.num
+ rate
.den
/2LL) / rate
.den
;
196 int av_timecode_check_frame_rate(AVRational rate
)
198 return check_fps(fps_from_frame_rate(rate
));
201 int av_timecode_init(AVTimecode
*tc
, AVRational rate
, int flags
, int frame_start
, void *log_ctx
)
203 memset(tc
, 0, sizeof(*tc
));
204 tc
->start
= frame_start
;
207 tc
->fps
= fps_from_frame_rate(rate
);
208 return check_timecode(log_ctx
, tc
);
211 int av_timecode_init_from_components(AVTimecode
*tc
, AVRational rate
, int flags
, int hh
, int mm
, int ss
, int ff
, void *log_ctx
)
215 memset(tc
, 0, sizeof(*tc
));
218 tc
->fps
= fps_from_frame_rate(rate
);
220 ret
= check_timecode(log_ctx
, tc
);
224 tc
->start
= (hh
*3600 + mm
*60 + ss
) * tc
->fps
+ ff
;
225 if (tc
->flags
& AV_TIMECODE_FLAG_DROPFRAME
) { /* adjust frame number */
226 int tmins
= 60*hh
+ mm
;
227 tc
->start
-= (tc
->fps
/ 30 * 2) * (tmins
- tmins
/10);
232 int av_timecode_init_from_string(AVTimecode
*tc
, AVRational rate
, const char *str
, void *log_ctx
)
235 int hh
, mm
, ss
, ff
, flags
;
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
;
242 flags
= c
!= ':' ? AV_TIMECODE_FLAG_DROPFRAME
: 0; // drop if ';', '.', ...
244 return av_timecode_init_from_components(tc
, rate
, flags
, hh
, mm
, ss
, ff
, log_ctx
);