diff options
-rw-r--r-- | audio/decode/ad_lavc.c | 2 | ||||
-rw-r--r-- | audio/decode/ad_spdif.c | 2 | ||||
-rw-r--r-- | mpvcore/av_common.c | 53 | ||||
-rw-r--r-- | mpvcore/av_common.h | 8 | ||||
-rw-r--r-- | sub/sd_lavc_conv.c | 5 | ||||
-rw-r--r-- | video/decode/vd_lavc.c | 5 |
6 files changed, 47 insertions, 28 deletions
diff --git a/audio/decode/ad_lavc.c b/audio/decode/ad_lavc.c index 4093fa77bd..3b9a48e419 100644 --- a/audio/decode/ad_lavc.c +++ b/audio/decode/ad_lavc.c @@ -329,7 +329,7 @@ static int decode_new_packet(struct dec_audio *da) int in_len = mpkt->len; AVPacket pkt; - mp_set_av_packet(&pkt, mpkt); + mp_set_av_packet(&pkt, mpkt, NULL); if (mpkt->pts != MP_NOPTS_VALUE) { da->pts = mpkt->pts; diff --git a/audio/decode/ad_spdif.c b/audio/decode/ad_spdif.c index 059022e5e3..8c3c7c3ea7 100644 --- a/audio/decode/ad_spdif.c +++ b/audio/decode/ad_spdif.c @@ -202,7 +202,7 @@ static int decode_audio(struct dec_audio *da, struct mp_audio *buffer, int maxle return -1; AVPacket pkt; - mp_set_av_packet(&pkt, mpkt); + mp_set_av_packet(&pkt, mpkt, NULL); pkt.pts = pkt.dts = 0; mp_msg(MSGT_DECAUDIO, MSGL_V, "spdif packet, size=%d\n", pkt.size); if (mpkt->pts != MP_NOPTS_VALUE) { diff --git a/mpvcore/av_common.c b/mpvcore/av_common.c index d233071c23..59f6d636c7 100644 --- a/mpvcore/av_common.c +++ b/mpvcore/av_common.c @@ -63,16 +63,40 @@ void mp_copy_lav_codec_headers(AVCodecContext *avctx, AVCodecContext *st) // We merely pass-through our PTS/DTS as an int64_t; libavcodec won't use it. union pts { int64_t i; double d; }; -// Set dst from mpkt. Note that dst is not refcountable. -// mpkt can be NULL to generate empty packets (used to flush delayed data). -// Sets pts/dts to reinterpret-casted mpv values - these are useful for -// reading back via mp_get_av_frame_pkt_pdts(), but they will be non-sense for -// libavcodec itself. (And normally, libavcodec won't interpret them.) -// Does not set duration field. -void mp_set_av_packet(AVPacket *dst, struct demux_packet *mpkt) +// Convert the mpv style timestamp (seconds as double) to a libavcodec style +// timestamp (integer units in a given timebase). +// +// If the given timebase is NULL or invalid, pass through the mpv timestamp by +// reinterpret casting them to int64_t. In this case, the timestamps will be +// non-sense for libavcodec, but we expect that it doesn't interpret them, +// and treats them as opaque. +int64_t mp_pts_to_av(double mp_pts, AVRational *tb) { assert(sizeof(int64_t) >= sizeof(double)); + if (tb && tb->num > 0 && tb->den > 0) + return mp_pts == MP_NOPTS_VALUE ? AV_NOPTS_VALUE : mp_pts / av_q2d(*tb); + // The + 0.0 is to squash possible negative zero mp_pts, which would + // happen to end up as AV_NOPTS_VALUE. + return (union pts){.d = mp_pts + 0.0}.i; +} + +// Inverse of mp_pts_to_av(). (The timebases must be exactly the same.) +double mp_pts_from_av(int64_t av_pts, AVRational *tb) +{ + assert(sizeof(int64_t) >= sizeof(double)); + if (tb && tb->num > 0 && tb->den > 0) + return av_pts == AV_NOPTS_VALUE ? MP_NOPTS_VALUE : av_pts * av_q2d(*tb); + // Should libavcodec set the PTS to AV_NOPTS_VALUE, it would end up as + // non-sense (usually negative zero) when unwrapped to double. + return av_pts == AV_NOPTS_VALUE ? MP_NOPTS_VALUE : (union pts){.i = av_pts}.d; +} +// Set dst from mpkt. Note that dst is not refcountable. +// mpkt can be NULL to generate empty packets (used to flush delayed data). +// Sets pts/dts using mp_pts_to_av(ts, tb). (Be aware of the implications.) +// Set duration field only if tb is set. +void mp_set_av_packet(AVPacket *dst, struct demux_packet *mpkt, AVRational *tb) +{ av_init_packet(dst); dst->data = mpkt ? mpkt->buffer : NULL; dst->size = mpkt ? mpkt->len : 0; @@ -84,17 +108,10 @@ void mp_set_av_packet(AVPacket *dst, struct demux_packet *mpkt) dst->side_data = mpkt->avpacket->side_data; dst->side_data_elems = mpkt->avpacket->side_data_elems; } - dst->pts = (union pts){.d = mpkt ? mpkt->pts : MP_NOPTS_VALUE}.i; - dst->dts = (union pts){.d = mpkt ? mpkt->dts : MP_NOPTS_VALUE}.i; -} - -// Return the pts/dts from a frame returned by libavcodec. Note that this -// assumes libavcodec was fed a packet setup with mp_set_av_packet()! If not, -// the timestamps might contain garbage. -void mp_get_av_frame_pkt_ts(AVFrame *frame, double *out_pts, double *out_dts) -{ - *out_pts = (union pts){.i = frame->pkt_pts}.d; - *out_dts = (union pts){.i = frame->pkt_dts}.d; + if (mpkt && tb && tb->num > 0 && tb->den > 0) + dst->duration = mpkt->duration / av_q2d(*tb); + dst->pts = mp_pts_to_av(mpkt ? mpkt->pts : MP_NOPTS_VALUE, tb); + dst->dts = mp_pts_to_av(mpkt ? mpkt->dts : MP_NOPTS_VALUE, tb); } void mp_add_lavc_decoders(struct mp_decoder_list *list, enum AVMediaType type) diff --git a/mpvcore/av_common.h b/mpvcore/av_common.h index 103185329c..e457628979 100644 --- a/mpvcore/av_common.h +++ b/mpvcore/av_common.h @@ -18,15 +18,19 @@ #ifndef MP_AVCOMMON_H #define MP_AVCOMMON_H +#include <inttypes.h> + #include <libavutil/avutil.h> +#include <libavutil/rational.h> #include <libavcodec/avcodec.h> struct mp_decoder_list; struct demux_packet; void mp_copy_lav_codec_headers(AVCodecContext *avctx, AVCodecContext *st); -void mp_set_av_packet(AVPacket *dst, struct demux_packet *mpkt); -void mp_get_av_frame_pkt_ts(AVFrame *frame, double *out_pts, double *out_dts); +void mp_set_av_packet(AVPacket *dst, struct demux_packet *mpkt, AVRational *tb); +int64_t mp_pts_to_av(double mp_pts, AVRational *tb); +double mp_pts_from_av(int64_t av_pts, AVRational *tb); void mp_add_lavc_decoders(struct mp_decoder_list *list, enum AVMediaType type); int mp_codec_to_av_codec_id(const char *codec); const char *mp_codec_from_av_codec_id(int codec_id); diff --git a/sub/sd_lavc_conv.c b/sub/sd_lavc_conv.c index 6f72671650..24ea2c10c6 100644 --- a/sub/sd_lavc_conv.c +++ b/sub/sd_lavc_conv.c @@ -234,15 +234,12 @@ static void decode(struct sd *sd, struct demux_packet *packet) { struct sd_lavc_priv *priv = sd->priv; AVCodecContext *avctx = priv->avctx; - double ts = av_q2d(av_inv_q(avctx->time_base)); AVSubtitle sub = {0}; AVPacket pkt; AVPacket parsed_pkt = {0}; int ret, got_sub; - mp_set_av_packet(&pkt, packet); - pkt.pts = packet->pts == MP_NOPTS_VALUE ? AV_NOPTS_VALUE : packet->pts * ts; - pkt.duration = packet->duration * ts; + mp_set_av_packet(&pkt, packet, &avctx->time_base); if (sd->codec && strcmp(sd->codec, "webvtt-webm") == 0) { if (parse_webvtt(&pkt, &parsed_pkt) < 0) { diff --git a/video/decode/vd_lavc.c b/video/decode/vd_lavc.c index 868f148d8b..fadd76de0e 100644 --- a/video/decode/vd_lavc.c +++ b/video/decode/vd_lavc.c @@ -744,7 +744,7 @@ static int decode(struct dec_video *vd, struct demux_packet *packet, else avctx->skip_frame = ctx->skip_frame; - mp_set_av_packet(&pkt, packet); + mp_set_av_packet(&pkt, packet, NULL); ret = avcodec_decode_video2(avctx, ctx->pic, &got_picture, &pkt); if (ret < 0) { @@ -757,7 +757,8 @@ static int decode(struct dec_video *vd, struct demux_packet *packet, return 0; update_image_params(vd, ctx->pic); - mp_get_av_frame_pkt_ts(ctx->pic, &vd->codec_pts, &vd->codec_dts); + vd->codec_pts = mp_pts_from_av(ctx->pic->pkt_pts, NULL); + vd->codec_dts = mp_pts_from_av(ctx->pic->pkt_dts, NULL); // Note: potentially resets ctx->pic as it is transferred to mpi struct mp_image *mpi = image_from_decoder(vd); |