From c2cb01d418dd18e1cf997c038d37378d773121be Mon Sep 17 00:00:00 2001 From: Luca Barbato Date: Wed, 3 Apr 2013 14:11:10 +0200 Subject: lavf: introduce AVFMT_TS_NEGATIVE Most formats do not support negative timestamps, shift them to avoid unexpected behaviour and a number of bad crashes. CC:libav-stable@libav.org Signed-off-by: Anton Khirnov Signed-off-by: Luca Barbato --- libavformat/avformat.h | 17 +++++++++++++++++ libavformat/ffmenc.c | 1 + libavformat/framecrcenc.c | 3 ++- libavformat/md5enc.c | 3 ++- libavformat/mux.c | 34 +++++++++++++++++++++++++++++++--- libavformat/oggenc.c | 1 + 6 files changed, 54 insertions(+), 5 deletions(-) (limited to 'libavformat') diff --git a/libavformat/avformat.h b/libavformat/avformat.h index 067a7874b9..2512e36020 100644 --- a/libavformat/avformat.h +++ b/libavformat/avformat.h @@ -360,6 +360,11 @@ typedef struct AVProbeData { #define AVFMT_TS_NONSTRICT 0x20000 /**< Format does not require strictly increasing timestamps, but they must still be monotonic */ +#define AVFMT_TS_NEGATIVE 0x40000 /**< Format allows muxing negative + timestamps. If not set the timestamp + will be shifted in av_write_frame and + av_interleaved_write_frame so they + start from 0. */ /** * @addtogroup lavf_encoding @@ -1021,6 +1026,18 @@ typedef struct AVFormatContext { */ #define RAW_PACKET_BUFFER_SIZE 2500000 int raw_packet_buffer_remaining_size; + + /** + * Offset to remap timestamps to be non-negative. + * Expressed in timebase units. + */ + int64_t offset; + + /** + * Timebase for the timestamp offset. + */ + AVRational offset_timebase; + } AVFormatContext; typedef struct AVPacketList { diff --git a/libavformat/ffmenc.c b/libavformat/ffmenc.c index 386487f1f9..91658e12dd 100644 --- a/libavformat/ffmenc.c +++ b/libavformat/ffmenc.c @@ -245,4 +245,5 @@ AVOutputFormat ff_ffm_muxer = { .write_header = ffm_write_header, .write_packet = ffm_write_packet, .write_trailer = ffm_write_trailer, + .flags = AVFMT_TS_NEGATIVE, }; diff --git a/libavformat/framecrcenc.c b/libavformat/framecrcenc.c index de6fa2b960..fed0cca430 100644 --- a/libavformat/framecrcenc.c +++ b/libavformat/framecrcenc.c @@ -43,5 +43,6 @@ AVOutputFormat ff_framecrc_muxer = { .video_codec = AV_CODEC_ID_RAWVIDEO, .write_header = ff_framehash_write_header, .write_packet = framecrc_write_packet, - .flags = AVFMT_VARIABLE_FPS | AVFMT_TS_NONSTRICT, + .flags = AVFMT_VARIABLE_FPS | AVFMT_TS_NONSTRICT | + AVFMT_TS_NEGATIVE, }; diff --git a/libavformat/md5enc.c b/libavformat/md5enc.c index 16412c9a34..92497045eb 100644 --- a/libavformat/md5enc.c +++ b/libavformat/md5enc.c @@ -127,6 +127,7 @@ AVOutputFormat ff_framemd5_muxer = { .write_header = framemd5_write_header, .write_packet = framemd5_write_packet, .write_trailer = framemd5_write_trailer, - .flags = AVFMT_VARIABLE_FPS | AVFMT_TS_NONSTRICT, + .flags = AVFMT_VARIABLE_FPS | AVFMT_TS_NONSTRICT | + AVFMT_TS_NEGATIVE, }; #endif diff --git a/libavformat/mux.c b/libavformat/mux.c index 76b0fb4dc6..0b537b8c1f 100644 --- a/libavformat/mux.c +++ b/libavformat/mux.c @@ -391,6 +391,34 @@ static int compute_pkt_fields2(AVFormatContext *s, AVStream *st, AVPacket *pkt) return 0; } +/* + * FIXME: this function should NEVER get undefined pts/dts beside when the + * AVFMT_NOTIMESTAMPS is set. + * Those additional safety checks should be dropped once the correct checks + * are set in the callers. + */ + +static int write_packet(AVFormatContext *s, AVPacket *pkt) +{ + if (!(s->oformat->flags & (AVFMT_TS_NEGATIVE | AVFMT_NOTIMESTAMPS))) { + AVRational time_base = s->streams[pkt->stream_index]->time_base; + int64_t offset = 0; + + if (!s->offset && pkt->dts != AV_NOPTS_VALUE && pkt->dts < 0) { + s->offset = -pkt->dts; + s->offset_timebase = time_base; + } + if (s->offset) + offset = av_rescale_q(s->offset, s->offset_timebase, time_base); + + if (pkt->dts != AV_NOPTS_VALUE) + pkt->dts += offset; + if (pkt->pts != AV_NOPTS_VALUE) + pkt->pts += offset; + } + return s->oformat->write_packet(s, pkt); +} + int av_write_frame(AVFormatContext *s, AVPacket *pkt) { int ret; @@ -406,7 +434,7 @@ int av_write_frame(AVFormatContext *s, AVPacket *pkt) if (ret < 0 && !(s->oformat->flags & AVFMT_NOTIMESTAMPS)) return ret; - ret = s->oformat->write_packet(s, pkt); + ret = write_packet(s, pkt); if (ret >= 0) s->streams[pkt->stream_index]->nb_frames++; @@ -544,7 +572,7 @@ int av_interleaved_write_frame(AVFormatContext *s, AVPacket *pkt) if (ret <= 0) //FIXME cleanup needed for ret<0 ? return ret; - ret = s->oformat->write_packet(s, &opkt); + ret = write_packet(s, &opkt); if (ret >= 0) s->streams[opkt.stream_index]->nb_frames++; @@ -568,7 +596,7 @@ int av_write_trailer(AVFormatContext *s) if (!ret) break; - ret = s->oformat->write_packet(s, &pkt); + ret = write_packet(s, &pkt); if (ret >= 0) s->streams[pkt.stream_index]->nb_frames++; diff --git a/libavformat/oggenc.c b/libavformat/oggenc.c index 6212d16373..e01c365125 100644 --- a/libavformat/oggenc.c +++ b/libavformat/oggenc.c @@ -619,5 +619,6 @@ AVOutputFormat ff_ogg_muxer = { .write_header = ogg_write_header, .write_packet = ogg_write_packet, .write_trailer = ogg_write_trailer, + .flags = AVFMT_TS_NEGATIVE, .priv_class = &ogg_muxer_class, }; -- cgit v1.2.1