summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--audio/decode/ad_lavc.c2
-rw-r--r--audio/decode/ad_spdif.c2
-rw-r--r--mpvcore/av_common.c53
-rw-r--r--mpvcore/av_common.h8
-rw-r--r--sub/sd_lavc_conv.c5
-rw-r--r--video/decode/vd_lavc.c5
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);