The new av_parse_time() is created in libavutil/parseutils.h, all the internal functions used by parse_date are moved to libavutil/parseutils.c and made static. Signed-off-by: Mans Rullgard <mans@mansr.com>tags/n0.8
| @@ -35,6 +35,7 @@ | |||
| #include "libswscale/swscale.h" | |||
| #include "libpostproc/postprocess.h" | |||
| #include "libavutil/avstring.h" | |||
| #include "libavutil/parseutils.h" | |||
| #include "libavutil/pixdesc.h" | |||
| #include "libavutil/eval.h" | |||
| #include "libavcodec/opt.h" | |||
| @@ -113,8 +114,8 @@ double parse_number_or_die(const char *context, const char *numstr, int type, do | |||
| int64_t parse_time_or_die(const char *context, const char *timestr, int is_duration) | |||
| { | |||
| int64_t us = parse_date(timestr, is_duration); | |||
| if (us == INT64_MIN) { | |||
| int64_t us; | |||
| if (av_parse_time(&us, timestr, is_duration) < 0) { | |||
| fprintf(stderr, "Invalid %s specification for %s: %s\n", | |||
| is_duration ? "duration" : "date", context, timestr); | |||
| exit(1); | |||
| @@ -1478,34 +1478,17 @@ attribute_deprecated int parse_frame_rate(int *frame_rate, int *frame_rate_base, | |||
| const char *arg); | |||
| #endif | |||
| #if FF_API_PARSE_DATE | |||
| /** | |||
| * Parse datestr and return a corresponding number of microseconds. | |||
| * | |||
| * @param datestr String representing a date or a duration. | |||
| * - If a date the syntax is: | |||
| * @code | |||
| * now|{[{YYYY-MM-DD|YYYYMMDD}[T|t| ]]{{HH[:MM[:SS[.m...]]]}|{HH[MM[SS[.m...]]]}}[Z|z]} | |||
| * @endcode | |||
| * If the value is "now" it takes the current time. | |||
| * Time is local time unless Z is appended, in which case it is | |||
| * interpreted as UTC. | |||
| * If the year-month-day part is not specified it takes the current | |||
| * year-month-day. | |||
| * @return the number of microseconds since 1st of January, 1970 up to | |||
| * the time of the parsed date or INT64_MIN if datestr cannot be | |||
| * successfully parsed. | |||
| * - If a duration the syntax is: | |||
| * @code | |||
| * [-]HH[:MM[:SS[.m...]]] | |||
| * [-]S+[.m...] | |||
| * @endcode | |||
| * @return the number of microseconds contained in a time interval | |||
| * with the specified duration or INT64_MIN if datestr cannot be | |||
| * successfully parsed. | |||
| * @param duration Flag which tells how to interpret datestr, if | |||
| * not zero datestr is interpreted as a duration, otherwise as a | |||
| * date. | |||
| * See av_parse_time() for the syntax of the provided string. | |||
| * @deprecated in favor of av_parse_time() | |||
| */ | |||
| attribute_deprecated | |||
| int64_t parse_date(const char *datestr, int duration); | |||
| #endif | |||
| /** | |||
| * Get the current time in microseconds. | |||
| @@ -42,25 +42,6 @@ void ff_dynarray_add(intptr_t **tab_ptr, int *nb_ptr, intptr_t elem) | |||
| *nb_ptr = nb; | |||
| } | |||
| time_t mktimegm(struct tm *tm) | |||
| { | |||
| time_t t; | |||
| int y = tm->tm_year + 1900, m = tm->tm_mon + 1, d = tm->tm_mday; | |||
| if (m < 3) { | |||
| m += 12; | |||
| y--; | |||
| } | |||
| t = 86400 * | |||
| (d + (153 * m - 457) / 5 + 365 * y + y / 4 - y / 100 + y / 400 - 719469); | |||
| t += 3600 * tm->tm_hour + 60 * tm->tm_min + tm->tm_sec; | |||
| return t; | |||
| } | |||
| #define ISLEAP(y) (((y) % 4 == 0) && (((y) % 100) != 0 || ((y) % 400) == 0)) | |||
| #define LEAPS_COUNT(y) ((y)/4 - (y)/100 + (y)/400) | |||
| @@ -95,94 +76,3 @@ struct tm *brktimegm(time_t secs, struct tm *tm) | |||
| return tm; | |||
| } | |||
| /* get a positive number between n_min and n_max, for a maximum length | |||
| of len_max. Return -1 if error. */ | |||
| static int date_get_num(const char **pp, | |||
| int n_min, int n_max, int len_max) | |||
| { | |||
| int i, val, c; | |||
| const char *p; | |||
| p = *pp; | |||
| val = 0; | |||
| for(i = 0; i < len_max; i++) { | |||
| c = *p; | |||
| if (!isdigit(c)) | |||
| break; | |||
| val = (val * 10) + c - '0'; | |||
| p++; | |||
| } | |||
| /* no number read ? */ | |||
| if (p == *pp) | |||
| return -1; | |||
| if (val < n_min || val > n_max) | |||
| return -1; | |||
| *pp = p; | |||
| return val; | |||
| } | |||
| /* small strptime for ffmpeg */ | |||
| const char *small_strptime(const char *p, const char *fmt, | |||
| struct tm *dt) | |||
| { | |||
| int c, val; | |||
| for(;;) { | |||
| c = *fmt++; | |||
| if (c == '\0') { | |||
| return p; | |||
| } else if (c == '%') { | |||
| c = *fmt++; | |||
| switch(c) { | |||
| case 'H': | |||
| val = date_get_num(&p, 0, 23, 2); | |||
| if (val == -1) | |||
| return NULL; | |||
| dt->tm_hour = val; | |||
| break; | |||
| case 'M': | |||
| val = date_get_num(&p, 0, 59, 2); | |||
| if (val == -1) | |||
| return NULL; | |||
| dt->tm_min = val; | |||
| break; | |||
| case 'S': | |||
| val = date_get_num(&p, 0, 59, 2); | |||
| if (val == -1) | |||
| return NULL; | |||
| dt->tm_sec = val; | |||
| break; | |||
| case 'Y': | |||
| val = date_get_num(&p, 0, 9999, 4); | |||
| if (val == -1) | |||
| return NULL; | |||
| dt->tm_year = val - 1900; | |||
| break; | |||
| case 'm': | |||
| val = date_get_num(&p, 1, 12, 2); | |||
| if (val == -1) | |||
| return NULL; | |||
| dt->tm_mon = val - 1; | |||
| break; | |||
| case 'd': | |||
| val = date_get_num(&p, 1, 31, 2); | |||
| if (val == -1) | |||
| return NULL; | |||
| dt->tm_mday = val; | |||
| break; | |||
| case '%': | |||
| goto match; | |||
| default: | |||
| return NULL; | |||
| } | |||
| } else { | |||
| match: | |||
| if (c != *p) | |||
| return NULL; | |||
| p++; | |||
| } | |||
| } | |||
| return p; | |||
| } | |||
| @@ -48,10 +48,7 @@ do {\ | |||
| } while(0) | |||
| #endif | |||
| time_t mktimegm(struct tm *tm); | |||
| struct tm *brktimegm(time_t secs, struct tm *tm); | |||
| const char *small_strptime(const char *p, const char *fmt, | |||
| struct tm *dt); | |||
| char *ff_data_to_hex(char *buf, const uint8_t *src, int size, int lowercase); | |||
| @@ -3380,124 +3380,16 @@ uint64_t ff_ntp_time(void) | |||
| return (av_gettime() / 1000) * 1000 + NTP_OFFSET_US; | |||
| } | |||
| int64_t parse_date(const char *datestr, int duration) | |||
| { | |||
| const char *p; | |||
| int64_t t; | |||
| struct tm dt; | |||
| int i; | |||
| static const char * const date_fmt[] = { | |||
| "%Y-%m-%d", | |||
| "%Y%m%d", | |||
| }; | |||
| static const char * const time_fmt[] = { | |||
| "%H:%M:%S", | |||
| "%H%M%S", | |||
| }; | |||
| const char *q; | |||
| int is_utc, len; | |||
| char lastch; | |||
| int negative = 0; | |||
| #undef time | |||
| time_t now = time(0); | |||
| len = strlen(datestr); | |||
| if (len > 0) | |||
| lastch = datestr[len - 1]; | |||
| else | |||
| lastch = '\0'; | |||
| is_utc = (lastch == 'z' || lastch == 'Z'); | |||
| memset(&dt, 0, sizeof(dt)); | |||
| p = datestr; | |||
| q = NULL; | |||
| if (!duration) { | |||
| if (!strncasecmp(datestr, "now", len)) | |||
| return (int64_t) now * 1000000; | |||
| /* parse the year-month-day part */ | |||
| for (i = 0; i < FF_ARRAY_ELEMS(date_fmt); i++) { | |||
| q = small_strptime(p, date_fmt[i], &dt); | |||
| if (q) { | |||
| break; | |||
| } | |||
| } | |||
| /* if the year-month-day part is missing, then take the | |||
| * current year-month-day time */ | |||
| if (!q) { | |||
| if (is_utc) { | |||
| dt = *gmtime(&now); | |||
| } else { | |||
| dt = *localtime(&now); | |||
| } | |||
| dt.tm_hour = dt.tm_min = dt.tm_sec = 0; | |||
| } else { | |||
| p = q; | |||
| } | |||
| if (*p == 'T' || *p == 't' || *p == ' ') | |||
| p++; | |||
| /* parse the hour-minute-second part */ | |||
| for (i = 0; i < FF_ARRAY_ELEMS(time_fmt); i++) { | |||
| q = small_strptime(p, time_fmt[i], &dt); | |||
| if (q) { | |||
| break; | |||
| } | |||
| } | |||
| } else { | |||
| /* parse datestr as a duration */ | |||
| if (p[0] == '-') { | |||
| negative = 1; | |||
| ++p; | |||
| } | |||
| /* parse datestr as HH:MM:SS */ | |||
| q = small_strptime(p, time_fmt[0], &dt); | |||
| if (!q) { | |||
| /* parse datestr as S+ */ | |||
| dt.tm_sec = strtol(p, (char **)&q, 10); | |||
| if (q == p) | |||
| /* the parsing didn't succeed */ | |||
| return INT64_MIN; | |||
| dt.tm_min = 0; | |||
| dt.tm_hour = 0; | |||
| } | |||
| } | |||
| /* Now we have all the fields that we can get */ | |||
| if (!q) { | |||
| return INT64_MIN; | |||
| } | |||
| if (duration) { | |||
| t = dt.tm_hour * 3600 + dt.tm_min * 60 + dt.tm_sec; | |||
| } else { | |||
| dt.tm_isdst = -1; /* unknown */ | |||
| if (is_utc) { | |||
| t = mktimegm(&dt); | |||
| } else { | |||
| t = mktime(&dt); | |||
| } | |||
| } | |||
| t *= 1000000; | |||
| #if FF_API_PARSE_DATE | |||
| #include "libavutil/parseutils.h" | |||
| /* parse the .m... part */ | |||
| if (*q == '.') { | |||
| int val, n; | |||
| q++; | |||
| for (val = 0, n = 100000; n >= 1; n /= 10, q++) { | |||
| if (!isdigit(*q)) | |||
| break; | |||
| val += n * (*q - '0'); | |||
| } | |||
| t += val; | |||
| } | |||
| return negative ? -t : t; | |||
| int64_t parse_date(const char *timestr, int duration) | |||
| { | |||
| int64_t timeval; | |||
| av_parse_time(&timeval, timestr, duration); | |||
| return timeval; | |||
| } | |||
| #endif | |||
| int find_info_tag(char *arg, int arg_size, const char *tag1, const char *info) | |||
| { | |||
| @@ -95,5 +95,8 @@ | |||
| #ifndef FF_API_DUMP_FORMAT | |||
| #define FF_API_DUMP_FORMAT (LIBAVFORMAT_VERSION_MAJOR < 54) | |||
| #endif | |||
| #ifndef FF_API_PARSE_DATE | |||
| #define FF_API_PARSE_DATE (LIBAVFORMAT_VERSION_MAJOR < 54) | |||
| #endif | |||
| #endif //AVFORMAT_VERSION_H | |||
| @@ -22,6 +22,8 @@ | |||
| */ | |||
| #include <strings.h> | |||
| #include <sys/time.h> | |||
| #include <time.h> | |||
| #include "parseutils.h" | |||
| #include "libavutil/avutil.h" | |||
| #include "libavutil/eval.h" | |||
| @@ -371,6 +373,241 @@ int av_parse_color(uint8_t *rgba_color, const char *color_string, int slen, | |||
| return 0; | |||
| } | |||
| /* get a positive number between n_min and n_max, for a maximum length | |||
| of len_max. Return -1 if error. */ | |||
| static int date_get_num(const char **pp, | |||
| int n_min, int n_max, int len_max) | |||
| { | |||
| int i, val, c; | |||
| const char *p; | |||
| p = *pp; | |||
| val = 0; | |||
| for(i = 0; i < len_max; i++) { | |||
| c = *p; | |||
| if (!isdigit(c)) | |||
| break; | |||
| val = (val * 10) + c - '0'; | |||
| p++; | |||
| } | |||
| /* no number read ? */ | |||
| if (p == *pp) | |||
| return -1; | |||
| if (val < n_min || val > n_max) | |||
| return -1; | |||
| *pp = p; | |||
| return val; | |||
| } | |||
| /* small strptime for ffmpeg */ | |||
| static | |||
| const char *small_strptime(const char *p, const char *fmt, | |||
| struct tm *dt) | |||
| { | |||
| int c, val; | |||
| for(;;) { | |||
| c = *fmt++; | |||
| if (c == '\0') { | |||
| return p; | |||
| } else if (c == '%') { | |||
| c = *fmt++; | |||
| switch(c) { | |||
| case 'H': | |||
| val = date_get_num(&p, 0, 23, 2); | |||
| if (val == -1) | |||
| return NULL; | |||
| dt->tm_hour = val; | |||
| break; | |||
| case 'M': | |||
| val = date_get_num(&p, 0, 59, 2); | |||
| if (val == -1) | |||
| return NULL; | |||
| dt->tm_min = val; | |||
| break; | |||
| case 'S': | |||
| val = date_get_num(&p, 0, 59, 2); | |||
| if (val == -1) | |||
| return NULL; | |||
| dt->tm_sec = val; | |||
| break; | |||
| case 'Y': | |||
| val = date_get_num(&p, 0, 9999, 4); | |||
| if (val == -1) | |||
| return NULL; | |||
| dt->tm_year = val - 1900; | |||
| break; | |||
| case 'm': | |||
| val = date_get_num(&p, 1, 12, 2); | |||
| if (val == -1) | |||
| return NULL; | |||
| dt->tm_mon = val - 1; | |||
| break; | |||
| case 'd': | |||
| val = date_get_num(&p, 1, 31, 2); | |||
| if (val == -1) | |||
| return NULL; | |||
| dt->tm_mday = val; | |||
| break; | |||
| case '%': | |||
| goto match; | |||
| default: | |||
| return NULL; | |||
| } | |||
| } else { | |||
| match: | |||
| if (c != *p) | |||
| return NULL; | |||
| p++; | |||
| } | |||
| } | |||
| return p; | |||
| } | |||
| static time_t mktimegm(struct tm *tm) | |||
| { | |||
| time_t t; | |||
| int y = tm->tm_year + 1900, m = tm->tm_mon + 1, d = tm->tm_mday; | |||
| if (m < 3) { | |||
| m += 12; | |||
| y--; | |||
| } | |||
| t = 86400 * | |||
| (d + (153 * m - 457) / 5 + 365 * y + y / 4 - y / 100 + y / 400 - 719469); | |||
| t += 3600 * tm->tm_hour + 60 * tm->tm_min + tm->tm_sec; | |||
| return t; | |||
| } | |||
| int av_parse_time(int64_t *timeval, const char *datestr, int duration) | |||
| { | |||
| const char *p; | |||
| int64_t t; | |||
| struct tm dt; | |||
| int i; | |||
| static const char * const date_fmt[] = { | |||
| "%Y-%m-%d", | |||
| "%Y%m%d", | |||
| }; | |||
| static const char * const time_fmt[] = { | |||
| "%H:%M:%S", | |||
| "%H%M%S", | |||
| }; | |||
| const char *q; | |||
| int is_utc, len; | |||
| char lastch; | |||
| int negative = 0; | |||
| #undef time | |||
| time_t now = time(0); | |||
| len = strlen(datestr); | |||
| if (len > 0) | |||
| lastch = datestr[len - 1]; | |||
| else | |||
| lastch = '\0'; | |||
| is_utc = (lastch == 'z' || lastch == 'Z'); | |||
| memset(&dt, 0, sizeof(dt)); | |||
| p = datestr; | |||
| q = NULL; | |||
| if (!duration) { | |||
| if (!strncasecmp(datestr, "now", len)) { | |||
| *timeval = (int64_t) now * 1000000; | |||
| return 0; | |||
| } | |||
| /* parse the year-month-day part */ | |||
| for (i = 0; i < FF_ARRAY_ELEMS(date_fmt); i++) { | |||
| q = small_strptime(p, date_fmt[i], &dt); | |||
| if (q) { | |||
| break; | |||
| } | |||
| } | |||
| /* if the year-month-day part is missing, then take the | |||
| * current year-month-day time */ | |||
| if (!q) { | |||
| if (is_utc) { | |||
| dt = *gmtime(&now); | |||
| } else { | |||
| dt = *localtime(&now); | |||
| } | |||
| dt.tm_hour = dt.tm_min = dt.tm_sec = 0; | |||
| } else { | |||
| p = q; | |||
| } | |||
| if (*p == 'T' || *p == 't' || *p == ' ') | |||
| p++; | |||
| /* parse the hour-minute-second part */ | |||
| for (i = 0; i < FF_ARRAY_ELEMS(time_fmt); i++) { | |||
| q = small_strptime(p, time_fmt[i], &dt); | |||
| if (q) { | |||
| break; | |||
| } | |||
| } | |||
| } else { | |||
| /* parse datestr as a duration */ | |||
| if (p[0] == '-') { | |||
| negative = 1; | |||
| ++p; | |||
| } | |||
| /* parse datestr as HH:MM:SS */ | |||
| q = small_strptime(p, time_fmt[0], &dt); | |||
| if (!q) { | |||
| /* parse datestr as S+ */ | |||
| dt.tm_sec = strtol(p, (char **)&q, 10); | |||
| if (q == p) { | |||
| /* the parsing didn't succeed */ | |||
| *timeval = INT64_MIN; | |||
| return AVERROR(EINVAL); | |||
| } | |||
| dt.tm_min = 0; | |||
| dt.tm_hour = 0; | |||
| } | |||
| } | |||
| /* Now we have all the fields that we can get */ | |||
| if (!q) { | |||
| *timeval = INT64_MIN; | |||
| return AVERROR(EINVAL); | |||
| } | |||
| if (duration) { | |||
| t = dt.tm_hour * 3600 + dt.tm_min * 60 + dt.tm_sec; | |||
| } else { | |||
| dt.tm_isdst = -1; /* unknown */ | |||
| if (is_utc) { | |||
| t = mktimegm(&dt); | |||
| } else { | |||
| t = mktime(&dt); | |||
| } | |||
| } | |||
| t *= 1000000; | |||
| /* parse the .m... part */ | |||
| if (*q == '.') { | |||
| int val, n; | |||
| q++; | |||
| for (val = 0, n = 100000; n >= 1; n /= 10, q++) { | |||
| if (!isdigit(*q)) | |||
| break; | |||
| val += n * (*q - '0'); | |||
| } | |||
| t += val; | |||
| } | |||
| *timeval = negative ? -t : t; | |||
| return 0; | |||
| } | |||
| #ifdef TEST | |||
| #undef printf | |||
| @@ -72,4 +72,38 @@ int av_parse_video_rate(AVRational *rate, const char *str); | |||
| int av_parse_color(uint8_t *rgba_color, const char *color_string, int slen, | |||
| void *log_ctx); | |||
| /** | |||
| * Parses timestr and returns in *time a corresponding number of | |||
| * microseconds. | |||
| * | |||
| * @param timeval puts here the number of microseconds corresponding | |||
| * to the string in timestr. If the string represents a duration, it | |||
| * is the number of microseconds contained in the time interval. If | |||
| * the string is a date, is the number of microseconds since 1st of | |||
| * January, 1970 up to the time of the parsed date. If timestr cannot | |||
| * be successfully parsed, set *time to INT64_MIN. | |||
| * @param datestr a string representing a date or a duration. | |||
| * - If a date the syntax is: | |||
| * @code | |||
| * [{YYYY-MM-DD|YYYYMMDD}[T|t| ]]{{HH[:MM[:SS[.m...]]]}|{HH[MM[SS[.m...]]]}}[Z] | |||
| * now | |||
| * @endcode | |||
| * If the value is "now" it takes the current time. | |||
| * Time is local time unless Z is appended, in which case it is | |||
| * interpreted as UTC. | |||
| * If the year-month-day part is not specified it takes the current | |||
| * year-month-day. | |||
| * - If a duration the syntax is: | |||
| * @code | |||
| * [-]HH[:MM[:SS[.m...]]] | |||
| * [-]S+[.m...] | |||
| * @endcode | |||
| * @param duration flag which tells how to interpret timestr, if not | |||
| * zero timestr is interpreted as a duration, otherwise as a date | |||
| * @return 0 in case of success, a negative value corresponding to an | |||
| * AVERROR code otherwise | |||
| */ | |||
| int av_parse_time(int64_t *timeval, const char *timestr, int duration); | |||
| #endif /* AVUTIL_PARSEUTILS_H */ | |||