From 916c80e94ab242489f06c2e578a792b56678134f Mon Sep 17 00:00:00 2001 From: Fabrice Bellard Date: Mon, 21 Oct 2002 15:54:49 +0000 Subject: [PATCH] AV synchronisation API Originally committed as revision 1054 to svn://svn.ffmpeg.org/ffmpeg/trunk --- libav/avformat.h | 20 ++++++- libav/utils.c | 148 +++++++++++++++++++++++++++++++++-------------- 2 files changed, 123 insertions(+), 45 deletions(-) diff --git a/libav/avformat.h b/libav/avformat.h index 2fb64e4d26..d8679d164d 100644 --- a/libav/avformat.h +++ b/libav/avformat.h @@ -14,7 +14,7 @@ #define AV_NOPTS_VALUE 0 typedef struct AVPacket { - INT64 pts; + INT64 pts; /* presentation time stamp in stream units (set av_set_pts_info) */ UINT8 *data; int size; int stream_index; @@ -27,6 +27,19 @@ typedef struct AVPacket { int av_new_packet(AVPacket *pkt, int size); void av_free_packet(AVPacket *pkt); +/*************************************************/ +/* fractional numbers for exact pts handling */ + +/* the exact value of the fractional number is: 'val + num / den'. num + is assumed to be such as 0 <= num < den */ +typedef struct AVFrac { + INT64 val, num, den; +} AVFrac; + +void av_frac_init(AVFrac *f, INT64 val, INT64 num, INT64 den); +void av_frac_add(AVFrac *f, INT64 incr); +void av_frac_set(AVFrac *f, INT64 val); + /*************************************************/ /* input/output formats */ @@ -151,6 +164,9 @@ typedef struct AVFormatContext { char copyright[512]; char comment[512]; int flags; /* format specific flags */ + /* private data for pts handling (do not modify directly) */ + int pts_wrap_bits; /* number of bits in pts (used for wrapping control) */ + int pts_num, pts_den; /* value to convert to seconds */ /* This buffer is only needed when packets were already buffered but not decoded, for example to get the codec parameters in mpeg streams */ @@ -276,6 +292,8 @@ int av_find_stream_info(AVFormatContext *ic); int av_read_packet(AVFormatContext *s, AVPacket *pkt); void av_close_input_file(AVFormatContext *s); AVStream *av_new_stream(AVFormatContext *s, int id); +void av_set_pts_info(AVFormatContext *s, int pts_wrap_bits, + int pts_num, int pts_den); /* media file output */ int av_write_header(AVFormatContext *s); diff --git a/libav/utils.c b/libav/utils.c index 18e125e609..89c32be03a 100644 --- a/libav/utils.c +++ b/libav/utils.c @@ -153,7 +153,7 @@ int av_new_packet(AVPacket *pkt, int size) return AVERROR_NOMEM; pkt->size = size; /* sane state */ - pkt->pts = 0; + pkt->pts = AV_NOPTS_VALUE; pkt->stream_index = 0; pkt->flags = 0; return 0; @@ -356,6 +356,9 @@ int av_open_input_file(AVFormatContext **ic_ptr, const char *filename, goto fail; } + /* default pts settings is MPEG like */ + av_set_pts_info(ic, 33, 1, 90000); + /* check filename in case of an image number is expected */ if (ic->iformat->flags & AVFMT_NEEDNUMBER) { if (filename_number_test(ic->filename) < 0) { @@ -695,6 +698,8 @@ int av_write_header(AVFormatContext *s) s->priv_data = av_mallocz(s->oformat->priv_data_size); if (!s->priv_data) return AVERROR_NOMEM; + /* default pts settings is MPEG like */ + av_set_pts_info(s, 33, 1, 90000); return s->oformat->write_header(s); } @@ -829,11 +834,15 @@ static time_t mktimegm(struct tm *tm) return t; } -/* syntax: - * [YYYY-MM-DD]{T| }HH[:MM[:SS[.m...]]][Z] . - * [YYYYMMDD]{T| }HH[MM[SS[.m...]]][Z] . +/* Syntax: + * - If not a duration: + * [{YYYY-MM-DD|YYYYMMDD}]{T| }{HH[:MM[:SS[.m...]]][Z]|HH[MM[SS[.m...]]][Z]} * Time is localtime unless Z is suffixed to the end. In this case GMT - * Return the date in micro seconds since 1970 */ + * Return the date in micro seconds since 1970 + * - If duration: + * HH[:MM[:SS[.m...]]] + * S+[.m...] + */ INT64 parse_date(const char *datestr, int duration) { const char *p; @@ -849,19 +858,21 @@ INT64 parse_date(const char *datestr, int duration) "%H%M%S", }; const char *q; - int is_utc; + int is_utc, len; char lastch; time_t now = time(0); - lastch = datestr[strlen(datestr)-1]; - + 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 = 0; - + q = NULL; if (!duration) { for (i = 0; i < sizeof(date_fmt) / sizeof(date_fmt[0]); i++) { q = strptime(p, date_fmt[i], &dt); @@ -883,12 +894,19 @@ INT64 parse_date(const char *datestr, int duration) if (*p == 'T' || *p == 't' || *p == ' ') p++; - } - for (i = 0; i < sizeof(time_fmt) / sizeof(time_fmt[0]); i++) { - q = strptime(p, time_fmt[i], &dt); - if (q) { - break; + for (i = 0; i < sizeof(time_fmt) / sizeof(time_fmt[0]); i++) { + q = strptime(p, time_fmt[i], &dt); + if (q) { + break; + } + } + } else { + q = strptime(p, time_fmt[0], &dt); + if (!q) { + dt.tm_sec = strtol(p, (char **)&q, 10); + dt.tm_min = 0; + dt.tm_hour = 0; } } @@ -1022,35 +1040,6 @@ int get_frame_filename(char *buf, int buf_size, return -1; } -static int gcd(INT64 a, INT64 b) -{ - INT64 c; - - while (1) { - c = a % b; - if (c == 0) - return b; - a = b; - b = c; - } -} - -void ticker_init(Ticker *tick, INT64 inrate, INT64 outrate) -{ - int g; - - g = gcd(inrate, outrate); - inrate /= g; - outrate /= g; - - tick->value = -outrate/2; - - tick->inrate = inrate; - tick->outrate = outrate; - tick->div = tick->outrate / tick->inrate; - tick->mod = tick->outrate % tick->inrate; -} - /** * * Print on stdout a nice hexa dump of a buffer @@ -1134,3 +1123,74 @@ void url_split(char *proto, int proto_size, pstrcpy(path, path_size, p); } +/** + * Set the pts for a given stream + * @param s stream + * @param pts_wrap_bits number of bits effectively used by the pts + * (used for wrap control, 33 is the value for MPEG) + * @param pts_num numerator to convert to seconds (MPEG: 1) + * @param pts_den denominator to convert to seconds (MPEG: 90000) + */ +void av_set_pts_info(AVFormatContext *s, int pts_wrap_bits, + int pts_num, int pts_den) +{ + s->pts_wrap_bits = pts_wrap_bits; + s->pts_num = pts_num; + s->pts_den = pts_den; +} + +/* fraction handling */ + +/** + * f = val + (num / den) + 0.5. 'num' is normalized so that it is such + * as 0 <= num < den. + * + * @param f fractional number + * @param val integer value + * @param num must be >= 0 + * @param den must be >= 1 + */ +void av_frac_init(AVFrac *f, INT64 val, INT64 num, INT64 den) +{ + num += (den >> 1); + if (num >= den) { + val += num / den; + num = num % den; + } + f->val = val; + f->num = num; + f->den = den; +} + +/* set f to (val + 0.5) */ +void av_frac_set(AVFrac *f, INT64 val) +{ + f->val = val; + f->num = f->den >> 1; +} + +/** + * Fractionnal addition to f: f = f + (incr / f->den) + * + * @param f fractional number + * @param incr increment, can be positive or negative + */ +void av_frac_add(AVFrac *f, INT64 incr) +{ + INT64 num, den; + + num = f->num + incr; + den = f->den; + if (num < 0) { + f->val += num / den; + num = num % den; + if (num < 0) { + num += den; + f->val--; + } + } else if (num >= den) { + f->val += num / den; + num = num % den; + } + f->num = num; +}