00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00029 #include <stdio.h>
00030 #include "timecode.h"
00031 #include "log.h"
00032 #include "error.h"
00033
00034 #ifdef FF_API_OLD_TC_ADJUST_FRAMENUM
00035 int av_timecode_adjust_ntsc_framenum(int framenum)
00036 {
00037
00038 int d = framenum / 17982;
00039 int m = framenum % 17982;
00040
00041 return framenum + 18 * d + 2 * ((m - 2) / 1798);
00042 }
00043 #endif
00044
00045 int av_timecode_adjust_ntsc_framenum2(int framenum, int fps)
00046 {
00047
00048 int drop_frames = 0;
00049 int d = framenum / 17982;
00050 int m = framenum % 17982;
00051
00052 if (fps == 30)
00053 drop_frames = 2;
00054 else if (fps == 60)
00055 drop_frames = 4;
00056 else
00057 return framenum;
00058
00059
00060 return framenum + 9 * drop_frames * d + drop_frames * ((m - 2) / 1798);
00061 }
00062
00063 uint32_t av_timecode_get_smpte_from_framenum(const AVTimecode *tc, int framenum)
00064 {
00065 unsigned fps = tc->fps;
00066 int drop = !!(tc->flags & AV_TIMECODE_FLAG_DROPFRAME);
00067 int hh, mm, ss, ff;
00068
00069 framenum += tc->start;
00070 if (drop)
00071 framenum = av_timecode_adjust_ntsc_framenum2(framenum, tc->fps);
00072 ff = framenum % fps;
00073 ss = framenum / fps % 60;
00074 mm = framenum / (fps*60) % 60;
00075 hh = framenum / (fps*3600) % 24;
00076 return 0 << 31 |
00077 drop << 30 |
00078 (ff / 10) << 28 |
00079 (ff % 10) << 24 |
00080 0 << 23 |
00081 (ss / 10) << 20 |
00082 (ss % 10) << 16 |
00083 0 << 15 |
00084 (mm / 10) << 12 |
00085 (mm % 10) << 8 |
00086 0 << 7 |
00087 0 << 6 |
00088 (hh / 10) << 4 |
00089 (hh % 10);
00090 }
00091
00092 char *av_timecode_make_string(const AVTimecode *tc, char *buf, int framenum)
00093 {
00094 int fps = tc->fps;
00095 int drop = tc->flags & AV_TIMECODE_FLAG_DROPFRAME;
00096 int hh, mm, ss, ff, neg = 0;
00097
00098 framenum += tc->start;
00099 if (drop)
00100 framenum = av_timecode_adjust_ntsc_framenum2(framenum, fps);
00101 if (framenum < 0) {
00102 framenum = -framenum;
00103 neg = tc->flags & AV_TIMECODE_FLAG_ALLOWNEGATIVE;
00104 }
00105 ff = framenum % fps;
00106 ss = framenum / fps % 60;
00107 mm = framenum / (fps*60) % 60;
00108 hh = framenum / (fps*3600);
00109 if (tc->flags & AV_TIMECODE_FLAG_24HOURSMAX)
00110 hh = hh % 24;
00111 snprintf(buf, AV_TIMECODE_STR_SIZE, "%s%02d:%02d:%02d%c%02d",
00112 neg ? "-" : "",
00113 hh, mm, ss, drop ? ';' : ':', ff);
00114 return buf;
00115 }
00116
00117 static unsigned bcd2uint(uint8_t bcd)
00118 {
00119 unsigned low = bcd & 0xf;
00120 unsigned high = bcd >> 4;
00121 if (low > 9 || high > 9)
00122 return 0;
00123 return low + 10*high;
00124 }
00125
00126 char *av_timecode_make_smpte_tc_string(char *buf, uint32_t tcsmpte, int prevent_df)
00127 {
00128 unsigned hh = bcd2uint(tcsmpte & 0x3f);
00129 unsigned mm = bcd2uint(tcsmpte>>8 & 0x7f);
00130 unsigned ss = bcd2uint(tcsmpte>>16 & 0x7f);
00131 unsigned ff = bcd2uint(tcsmpte>>24 & 0x3f);
00132 unsigned drop = tcsmpte & 1<<30 && !prevent_df;
00133 snprintf(buf, AV_TIMECODE_STR_SIZE, "%02u:%02u:%02u%c%02u",
00134 hh, mm, ss, drop ? ';' : ':', ff);
00135 return buf;
00136 }
00137
00138 char *av_timecode_make_mpeg_tc_string(char *buf, uint32_t tc25bit)
00139 {
00140 snprintf(buf, AV_TIMECODE_STR_SIZE, "%02u:%02u:%02u%c%02u",
00141 tc25bit>>19 & 0x1f,
00142 tc25bit>>13 & 0x3f,
00143 tc25bit>>6 & 0x3f,
00144 tc25bit & 1<<24 ? ';' : ':',
00145 tc25bit & 0x3f);
00146 return buf;
00147 }
00148
00149 static int check_fps(int fps)
00150 {
00151 int i;
00152 static const int supported_fps[] = {24, 25, 30, 50, 60};
00153
00154 for (i = 0; i < FF_ARRAY_ELEMS(supported_fps); i++)
00155 if (fps == supported_fps[i])
00156 return 0;
00157 return -1;
00158 }
00159
00160 static int check_timecode(void *log_ctx, AVTimecode *tc)
00161 {
00162 if (tc->fps <= 0) {
00163 av_log(log_ctx, AV_LOG_ERROR, "Timecode frame rate must be specified\n");
00164 return AVERROR(EINVAL);
00165 }
00166 if ((tc->flags & AV_TIMECODE_FLAG_DROPFRAME) && tc->fps != 30) {
00167 av_log(log_ctx, AV_LOG_ERROR, "Drop frame is only allowed with 30000/1001 FPS\n");
00168 return AVERROR(EINVAL);
00169 }
00170 if (check_fps(tc->fps) < 0) {
00171 av_log(log_ctx, AV_LOG_ERROR, "Timecode frame rate %d/%d not supported\n",
00172 tc->rate.num, tc->rate.den);
00173 return AVERROR_PATCHWELCOME;
00174 }
00175 return 0;
00176 }
00177
00178 static int fps_from_frame_rate(AVRational rate)
00179 {
00180 if (!rate.den || !rate.num)
00181 return -1;
00182 return (rate.num + rate.den/2) / rate.den;
00183 }
00184
00185 int av_timecode_check_frame_rate(AVRational rate)
00186 {
00187 return check_fps(fps_from_frame_rate(rate));
00188 }
00189
00190 int av_timecode_init(AVTimecode *tc, AVRational rate, int flags, int frame_start, void *log_ctx)
00191 {
00192 memset(tc, 0, sizeof(*tc));
00193 tc->start = frame_start;
00194 tc->flags = flags;
00195 tc->rate = rate;
00196 tc->fps = fps_from_frame_rate(rate);
00197 return check_timecode(log_ctx, tc);
00198 }
00199
00200 int av_timecode_init_from_string(AVTimecode *tc, AVRational rate, const char *str, void *log_ctx)
00201 {
00202 char c;
00203 int hh, mm, ss, ff, ret;
00204
00205 if (sscanf(str, "%d:%d:%d%c%d", &hh, &mm, &ss, &c, &ff) != 5) {
00206 av_log(log_ctx, AV_LOG_ERROR, "Unable to parse timecode, "
00207 "syntax: hh:mm:ss[:;.]ff\n");
00208 return AVERROR_INVALIDDATA;
00209 }
00210
00211 memset(tc, 0, sizeof(*tc));
00212 tc->flags = c != ':' ? AV_TIMECODE_FLAG_DROPFRAME : 0;
00213 tc->rate = rate;
00214 tc->fps = fps_from_frame_rate(rate);
00215
00216 ret = check_timecode(log_ctx, tc);
00217 if (ret < 0)
00218 return ret;
00219
00220 tc->start = (hh*3600 + mm*60 + ss) * tc->fps + ff;
00221 if (tc->flags & AV_TIMECODE_FLAG_DROPFRAME) {
00222 int tmins = 60*hh + mm;
00223 tc->start -= 2 * (tmins - tmins/10);
00224 }
00225 return 0;
00226 }