diff --git a/libavcodec/avcodec.h b/libavcodec/avcodec.h index d4bbe29b82..5a81a379e3 100644 --- a/libavcodec/avcodec.h +++ b/libavcodec/avcodec.h @@ -30,7 +30,7 @@ #include "libavutil/avutil.h" #define LIBAVCODEC_VERSION_MAJOR 52 -#define LIBAVCODEC_VERSION_MINOR 18 +#define LIBAVCODEC_VERSION_MINOR 19 #define LIBAVCODEC_VERSION_MICRO 0 #define LIBAVCODEC_VERSION_INT AV_VERSION_INT(LIBAVCODEC_VERSION_MAJOR, \ @@ -3147,6 +3147,47 @@ typedef struct AVCodecParserContext { * subtitles are correctly displayed after seeking. */ int64_t convergence_duration; + + // Timestamp generation support: + /** + * Synchronization point for start of timestamp generation. + * + * Set to >0 for sync point, 0 for no sync point and <0 for undefined + * (default). + * + * For example, this corresponds to presence of H.264 buffering period + * SEI message. + */ + int dts_sync_point; + + /** + * Offset of the current timestamp against last timestamp sync point in + * units of AVCodecContext.time_base. + * + * Set to INT_MIN when dts_sync_point unused. Otherwise, it must + * contain a valid timestamp offset. + * + * Note that the timestamp of sync point has usually a nonzero + * dts_ref_dts_delta, which refers to the previous sync point. Offset of + * the next frame after timestamp sync point will be usually 1. + * + * For example, this corresponds to H.264 cpb_removal_delay. + */ + int dts_ref_dts_delta; + + /** + * Presentation delay of current frame in units of AVCodecContext.time_base. + * + * Set to INT_MIN when dts_sync_point unused. Otherwise, it must + * contain valid non-negative timestamp delta (presentation time of a frame + * must not lie in the past). + * + * This delay represents the difference between decoding and presentation + * time of the frame. + * + * For example, this corresponds to H.264 dpb_output_delay. + */ + int pts_dts_delta; } AVCodecParserContext; typedef struct AVCodecParser { diff --git a/libavcodec/parser.c b/libavcodec/parser.c index a0d604dabe..d738a62b83 100644 --- a/libavcodec/parser.c +++ b/libavcodec/parser.c @@ -75,6 +75,9 @@ AVCodecParserContext *av_parser_init(int codec_id) s->pict_type = FF_I_TYPE; s->key_frame = -1; s->convergence_duration = AV_NOPTS_VALUE; + s->dts_sync_point = INT_MIN; + s->dts_ref_dts_delta = INT_MIN; + s->pts_dts_delta = INT_MIN; return s; } diff --git a/libavformat/avformat.h b/libavformat/avformat.h index 6308940ce5..cf455da9e5 100644 --- a/libavformat/avformat.h +++ b/libavformat/avformat.h @@ -22,8 +22,8 @@ #define AVFORMAT_AVFORMAT_H #define LIBAVFORMAT_VERSION_MAJOR 52 -#define LIBAVFORMAT_VERSION_MINOR 29 -#define LIBAVFORMAT_VERSION_MICRO 2 +#define LIBAVFORMAT_VERSION_MINOR 30 +#define LIBAVFORMAT_VERSION_MICRO 0 #define LIBAVFORMAT_VERSION_INT AV_VERSION_INT(LIBAVFORMAT_VERSION_MAJOR, \ LIBAVFORMAT_VERSION_MINOR, \ @@ -494,6 +494,16 @@ typedef struct AVStream { const uint8_t *cur_ptr; int cur_len; AVPacket cur_pkt; + + // Timestamp generation support: + /** + * Timestamp corresponding to the last dts sync point. + * + * Initialized when AVCodecParserContext.dts_sync_point >= 0 and + * a DTS is received from the underlying container. Otherwise set to + * AV_NOPTS_VALUE by default. + */ + int64_t reference_dts; } AVStream; #define AV_PROGRAM_RUNNING 1 diff --git a/libavformat/utils.c b/libavformat/utils.c index 61f74c3c18..073e6dacdc 100644 --- a/libavformat/utils.c +++ b/libavformat/utils.c @@ -834,6 +834,25 @@ static void compute_pkt_fields(AVFormatContext *s, AVStream *st, pkt->dts += offset; } + if (pc && pc->dts_sync_point >= 0) { + // we have synchronization info from the parser + int64_t den = st->codec->time_base.den * (int64_t) st->time_base.num; + if (den > 0) { + int64_t num = st->codec->time_base.num * (int64_t) st->time_base.den; + if (pkt->dts != AV_NOPTS_VALUE) { + // got DTS from the stream, update reference timestamp + st->reference_dts = pkt->dts - pc->dts_ref_dts_delta * num / den; + pkt->pts = pkt->dts + pc->pts_dts_delta * num / den; + } else if (st->reference_dts != AV_NOPTS_VALUE) { + // compute DTS based on reference timestamp + pkt->dts = st->reference_dts + pc->dts_ref_dts_delta * num / den; + pkt->pts = pkt->dts + pc->pts_dts_delta * num / den; + } + if (pc->dts_sync_point > 0) + st->reference_dts = pkt->dts; // new reference + } + } + /* This may be redundant, but it should not hurt. */ if(pkt->dts != AV_NOPTS_VALUE && pkt->pts != AV_NOPTS_VALUE && pkt->pts > pkt->dts) presentation_delayed = 1; @@ -1157,6 +1176,7 @@ static void av_read_frame_flush(AVFormatContext *s) } st->last_IP_pts = AV_NOPTS_VALUE; st->cur_dts = AV_NOPTS_VALUE; /* we set the current DTS to an unspecified origin */ + st->reference_dts = AV_NOPTS_VALUE; /* fail safe */ st->cur_ptr = NULL; st->cur_len = 0; @@ -2332,6 +2352,7 @@ AVStream *av_new_stream(AVFormatContext *s, int id) st->last_IP_pts = AV_NOPTS_VALUE; for(i=0; ipts_buffer[i]= AV_NOPTS_VALUE; + st->reference_dts = AV_NOPTS_VALUE; st->sample_aspect_ratio = (AVRational){0,1};