summaryrefslogtreecommitdiffstats
path: root/common
diff options
context:
space:
mode:
Diffstat (limited to 'common')
-rw-r--r--common/av_common.c84
-rw-r--r--common/av_common.h9
-rw-r--r--common/av_log.c100
-rw-r--r--common/av_log.h2
-rw-r--r--common/common.c92
-rw-r--r--common/common.h36
-rw-r--r--common/encode.h13
-rw-r--r--common/encode_lavc.c223
-rw-r--r--common/encode_lavc.h20
-rw-r--r--common/global.h1
-rw-r--r--common/meson.build11
-rw-r--r--common/msg.c800
-rw-r--r--common/msg.h2
-rw-r--r--common/msg_control.h7
-rw-r--r--common/playlist.c138
-rw-r--r--common/playlist.h39
-rw-r--r--common/recorder.c110
-rw-r--r--common/recorder.h5
-rw-r--r--common/stats.c325
-rw-r--r--common/stats.h34
-rw-r--r--common/tags.c7
-rw-r--r--common/tags.h2
-rw-r--r--common/version.c4
-rw-r--r--common/version.h.in7
24 files changed, 1534 insertions, 537 deletions
diff --git a/common/av_common.c b/common/av_common.c
index 01428ff2f4..277601d2fc 100644
--- a/common/av_common.c
+++ b/common/av_common.c
@@ -30,6 +30,7 @@
#include "config.h"
+#include "audio/chmap_avchannel.h"
#include "common/common.h"
#include "common/msg.h"
#include "demux/packet.h"
@@ -39,20 +40,6 @@
#include "av_common.h"
#include "codecs.h"
-int mp_lavc_set_extradata(AVCodecContext *avctx, void *ptr, int size)
-{
- if (size) {
- av_free(avctx->extradata);
- avctx->extradata_size = 0;
- avctx->extradata = av_mallocz(size + AV_INPUT_BUFFER_PADDING_SIZE);
- if (!avctx->extradata)
- return -1;
- avctx->extradata_size = size;
- memcpy(avctx->extradata, ptr, size);
- }
- return 0;
-}
-
enum AVMediaType mp_to_av_stream_type(int type)
{
switch (type) {
@@ -63,7 +50,7 @@ enum AVMediaType mp_to_av_stream_type(int type)
}
}
-AVCodecParameters *mp_codec_params_to_av(struct mp_codec_params *c)
+AVCodecParameters *mp_codec_params_to_av(const struct mp_codec_params *c)
{
AVCodecParameters *avp = avcodec_parameters_alloc();
if (!avp)
@@ -80,12 +67,23 @@ AVCodecParameters *mp_codec_params_to_av(struct mp_codec_params *c)
avp->codec_id = mp_codec_to_av_codec_id(c->codec);
avp->codec_tag = c->codec_tag;
if (c->extradata_size) {
- avp->extradata =
- av_mallocz(c->extradata_size + AV_INPUT_BUFFER_PADDING_SIZE);
+ uint8_t *extradata = c->extradata;
+ int size = c->extradata_size;
+
+ if (avp->codec_id == AV_CODEC_ID_FLAC) {
+ // ffmpeg expects FLAC extradata to be just the STREAMINFO,
+ // so grab only that (and assume it'll be the first block)
+ if (size >= 8 && !memcmp(c->extradata, "fLaC", 4)) {
+ extradata += 8;
+ size = MPMIN(34, size - 8); // FLAC_STREAMINFO_SIZE
+ }
+ }
+
+ avp->extradata = av_mallocz(size + AV_INPUT_BUFFER_PADDING_SIZE);
if (!avp->extradata)
goto error;
- avp->extradata_size = c->extradata_size;
- memcpy(avp->extradata, c->extradata, avp->extradata_size);
+ avp->extradata_size = size;
+ memcpy(avp->extradata, extradata, size);
}
avp->bits_per_coded_sample = c->bits_per_coded_sample;
@@ -97,9 +95,14 @@ AVCodecParameters *mp_codec_params_to_av(struct mp_codec_params *c)
avp->sample_rate = c->samplerate;
avp->bit_rate = c->bitrate;
avp->block_align = c->block_align;
+
+#if !HAVE_AV_CHANNEL_LAYOUT
avp->channels = c->channels.num;
if (!mp_chmap_is_unknown(&c->channels))
avp->channel_layout = mp_chmap_to_lavc(&c->channels);
+#else
+ mp_chmap_to_av_layout(&avp->ch_layout, &c->channels);
+#endif
return avp;
error:
@@ -108,7 +111,7 @@ error:
}
// Set avctx codec headers for decoding. Returns <0 on failure.
-int mp_set_avctx_codec_headers(AVCodecContext *avctx, struct mp_codec_params *c)
+int mp_set_avctx_codec_headers(AVCodecContext *avctx, const struct mp_codec_params *c)
{
enum AVMediaType codec_type = avctx->codec_type;
enum AVCodecID codec_id = avctx->codec_id;
@@ -128,7 +131,7 @@ int mp_set_avctx_codec_headers(AVCodecContext *avctx, struct mp_codec_params *c)
// Pick a "good" timebase, which will be used to convert double timestamps
// back to fractions for passing them through libavcodec.
-AVRational mp_get_codec_timebase(struct mp_codec_params *c)
+AVRational mp_get_codec_timebase(const struct mp_codec_params *c)
{
AVRational tb = {c->native_tb_num, c->native_tb_den};
if (tb.num < 1 || tb.den < 1) {
@@ -179,7 +182,11 @@ double mp_pts_from_av(int64_t av_pts, AVRational *tb)
// 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->side_data = NULL;
+ dst->side_data_elems = 0;
+ dst->buf = NULL;
+ av_packet_unref(dst);
+
dst->data = mpkt ? mpkt->buffer : NULL;
dst->size = mpkt ? mpkt->len : 0;
/* Some codecs (ZeroCodec, some cases of PNG) may want keyframe info
@@ -270,7 +277,7 @@ int mp_codec_to_av_codec_id(const char *codec)
if (desc)
id = desc->id;
if (id == AV_CODEC_ID_NONE) {
- AVCodec *avcodec = avcodec_find_decoder_by_name(codec);
+ const AVCodec *avcodec = avcodec_find_decoder_by_name(codec);
if (avcodec)
id = avcodec->id;
}
@@ -285,7 +292,7 @@ const char *mp_codec_from_av_codec_id(int codec_id)
if (desc)
name = desc->name;
if (!name) {
- AVCodec *avcodec = avcodec_find_decoder(codec_id);
+ const AVCodec *avcodec = avcodec_find_decoder(codec_id);
if (avcodec)
name = avcodec->name;
}
@@ -377,3 +384,32 @@ int mp_set_avopts_pos(struct mp_log *log, void *avobj, void *posargs, char **kv)
}
return success;
}
+
+/**
+ * Must be used to free an AVPacket that was used with mp_set_av_packet().
+ *
+ * We have a particular pattern where we "borrow" buffers and set them
+ * into an AVPacket to pass data to ffmpeg without extra copies.
+ * This applies to buf and side_data, so this function clears them before
+ * freeing.
+ */
+void mp_free_av_packet(AVPacket **pkt)
+{
+ if (*pkt) {
+ (*pkt)->side_data = NULL;
+ (*pkt)->side_data_elems = 0;
+ (*pkt)->buf = NULL;
+ }
+ av_packet_free(pkt);
+}
+
+void mp_codec_info_from_av(const AVCodecContext *avctx, struct mp_codec_params *c)
+{
+ c->codec_profile = av_get_profile_name(avctx->codec, avctx->profile);
+ if (!c->codec_profile)
+ c->codec_profile = avcodec_profile_name(avctx->codec_id, avctx->profile);
+ c->codec = avctx->codec_descriptor->name;
+ c->codec_desc = avctx->codec_descriptor->long_name;
+ c->decoder = avctx->codec->name;
+ c->decoder_desc = avctx->codec->long_name;
+}
diff --git a/common/av_common.h b/common/av_common.h
index 1b3e468884..c584085890 100644
--- a/common/av_common.h
+++ b/common/av_common.h
@@ -31,11 +31,10 @@ struct mp_codec_params;
struct AVDictionary;
struct mp_log;
-int mp_lavc_set_extradata(AVCodecContext *avctx, void *ptr, int size);
enum AVMediaType mp_to_av_stream_type(int type);
-AVCodecParameters *mp_codec_params_to_av(struct mp_codec_params *c);
-int mp_set_avctx_codec_headers(AVCodecContext *avctx, struct mp_codec_params *c);
-AVRational mp_get_codec_timebase(struct mp_codec_params *c);
+AVCodecParameters *mp_codec_params_to_av(const struct mp_codec_params *c);
+int mp_set_avctx_codec_headers(AVCodecContext *avctx, const struct mp_codec_params *c);
+AVRational mp_get_codec_timebase(const struct mp_codec_params *c);
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);
@@ -50,5 +49,7 @@ void mp_set_avdict(struct AVDictionary **dict, char **kv);
void mp_avdict_print_unset(struct mp_log *log, int msgl, struct AVDictionary *d);
int mp_set_avopts(struct mp_log *log, void *avobj, char **kv);
int mp_set_avopts_pos(struct mp_log *log, void *avobj, void *posargs, char **kv);
+void mp_free_av_packet(AVPacket **pkt);
+void mp_codec_info_from_av(const AVCodecContext *avctx, struct mp_codec_params *c);
#endif
diff --git a/common/av_log.c b/common/av_log.c
index 8b0cb09efa..54b78a617d 100644
--- a/common/av_log.c
+++ b/common/av_log.c
@@ -22,44 +22,41 @@
#include <stdlib.h>
#include <stdio.h>
#include <stdbool.h>
-#include <pthread.h>
#include "av_log.h"
-#include "config.h"
#include "common/common.h"
#include "common/global.h"
#include "common/msg.h"
+#include "config.h"
+#include "misc/bstr.h"
+#include "osdep/threads.h"
#include <libavutil/avutil.h>
#include <libavutil/log.h>
+#include <libavutil/version.h>
#include <libavcodec/avcodec.h>
+#include <libavcodec/version.h>
#include <libavformat/avformat.h>
+#include <libavformat/version.h>
+#include <libswresample/swresample.h>
+#include <libswresample/version.h>
#include <libswscale/swscale.h>
+#include <libswscale/version.h>
#include <libavfilter/avfilter.h>
+#include <libavfilter/version.h>
#if HAVE_LIBAVDEVICE
#include <libavdevice/avdevice.h>
#endif
-#if HAVE_LIBAV
-#include <libavresample/avresample.h>
-#else
-#include <libswresample/swresample.h>
-#endif
-
-#if LIBAVCODEC_VERSION_MICRO >= 100
-#define LIB_PREFIX "ffmpeg"
-#else
-#define LIB_PREFIX "libav"
-#endif
-
// Needed because the av_log callback does not provide a library-safe message
// callback.
-static pthread_mutex_t log_lock = PTHREAD_MUTEX_INITIALIZER;
+static mp_static_mutex log_lock = MP_STATIC_MUTEX_INITIALIZER;
static struct mpv_global *log_mpv_instance;
static struct mp_log *log_root, *log_decaudio, *log_decvideo, *log_demuxer;
static bool log_print_prefix = true;
+static bstr log_buffer;
static int av_log_level_to_mp_level(int av_level)
{
@@ -85,7 +82,7 @@ static struct mp_log *get_av_log(void *ptr)
if (!avc) {
mp_warn(log_root,
"av_log callback called with bad parameters (NULL AVClass).\n"
- "This is a bug in one of Libav/FFmpeg libraries used.\n");
+ "This is a bug in one of FFmpeg libraries used.\n");
return log_root;
}
@@ -111,6 +108,11 @@ static struct mp_log *get_av_log(void *ptr)
return log_root;
}
+static const char *avclass_item_name(void *obj, const AVClass *avc)
+{
+ return (avc->item_name ? avc->item_name : av_default_item_name)(obj);
+}
+
static void mp_msg_av_log_callback(void *ptr, int level, const char *fmt,
va_list vl)
{
@@ -118,10 +120,10 @@ static void mp_msg_av_log_callback(void *ptr, int level, const char *fmt,
int mp_level = av_log_level_to_mp_level(level);
// Note: mp_log is thread-safe, but destruction of the log instances is not.
- pthread_mutex_lock(&log_lock);
+ mp_mutex_lock(&log_lock);
if (!log_mpv_instance) {
- pthread_mutex_unlock(&log_lock);
+ mp_mutex_unlock(&log_lock);
// Fallback to stderr
vfprintf(stderr, fmt, vl);
return;
@@ -130,34 +132,36 @@ static void mp_msg_av_log_callback(void *ptr, int level, const char *fmt,
struct mp_log *log = get_av_log(ptr);
if (mp_msg_test(log, mp_level)) {
- char buffer[4096] = "";
- int pos = 0;
- const char *prefix = avc ? avc->item_name(ptr) : NULL;
- if (log_print_prefix && prefix)
- pos = snprintf(buffer, sizeof(buffer), "%s: ", prefix);
- log_print_prefix = fmt[strlen(fmt) - 1] == '\n';
-
- pos = MPMIN(MPMAX(pos, 0), sizeof(buffer));
- vsnprintf(buffer + pos, sizeof(buffer) - pos, fmt, vl);
-
- mp_msg(log, mp_level, "%s", buffer);
+ log_buffer.len = 0;
+ bstr_xappend_vasprintf(log_root, &log_buffer, fmt, vl);
+ if (!log_buffer.len)
+ goto done;
+ const char *prefix = avc ? avclass_item_name(ptr, avc) : NULL;
+ if (log_print_prefix && prefix) {
+ mp_msg(log, mp_level, "%s: %.*s", prefix, BSTR_P(log_buffer));
+ } else {
+ mp_msg(log, mp_level, "%.*s", BSTR_P(log_buffer));
+ }
+ log_print_prefix = log_buffer.start[log_buffer.len - 1] == '\n';
}
- pthread_mutex_unlock(&log_lock);
+done:
+ mp_mutex_unlock(&log_lock);
}
void init_libav(struct mpv_global *global)
{
- pthread_mutex_lock(&log_lock);
+ mp_mutex_lock(&log_lock);
if (!log_mpv_instance) {
log_mpv_instance = global;
- log_root = mp_log_new(NULL, global->log, LIB_PREFIX);
+ log_root = mp_log_new(NULL, global->log, "ffmpeg");
log_decaudio = mp_log_new(log_root, log_root, "audio");
log_decvideo = mp_log_new(log_root, log_root, "video");
log_demuxer = mp_log_new(log_root, log_root, "demuxer");
+ log_buffer = (bstr){0};
av_log_set_callback(mp_msg_av_log_callback);
}
- pthread_mutex_unlock(&log_lock);
+ mp_mutex_unlock(&log_lock);
avformat_network_init();
@@ -168,13 +172,13 @@ void init_libav(struct mpv_global *global)
void uninit_libav(struct mpv_global *global)
{
- pthread_mutex_lock(&log_lock);
+ mp_mutex_lock(&log_lock);
if (log_mpv_instance == global) {
av_log_set_callback(av_log_default_callback);
log_mpv_instance = NULL;
talloc_free(log_root);
}
- pthread_mutex_unlock(&log_lock);
+ mp_mutex_unlock(&log_lock);
}
#define V(x) AV_VERSION_MAJOR(x), \
@@ -187,7 +191,7 @@ struct lib {
unsigned runv;
};
-bool print_libav_versions(struct mp_log *log, int v)
+void check_library_versions(struct mp_log *log, int v)
{
const struct lib libs[] = {
{"libavutil", LIBAVUTIL_VERSION_INT, avutil_version()},
@@ -195,30 +199,26 @@ bool print_libav_versions(struct mp_log *log, int v)
{"libavformat", LIBAVFORMAT_VERSION_INT, avformat_version()},
{"libswscale", LIBSWSCALE_VERSION_INT, swscale_version()},
{"libavfilter", LIBAVFILTER_VERSION_INT, avfilter_version()},
-#if HAVE_LIBAV
- {"libavresample", LIBAVRESAMPLE_VERSION_INT, avresample_version()},
-#else
{"libswresample", LIBSWRESAMPLE_VERSION_INT, swresample_version()},
-#endif
};
- mp_msg(log, v, "%s library versions:\n", LIB_PREFIX);
+ mp_msg(log, v, "FFmpeg version: %s\n", av_version_info());
+ mp_msg(log, v, "FFmpeg library versions:\n");
- bool mismatch = false;
for (int n = 0; n < MP_ARRAY_SIZE(libs); n++) {
const struct lib *l = &libs[n];
mp_msg(log, v, " %-15s %d.%d.%d", l->name, V(l->buildv));
- if (l->buildv != l->runv) {
+ if (l->buildv != l->runv)
mp_msg(log, v, " (runtime %d.%d.%d)", V(l->runv));
- mismatch = l->buildv > l->runv ||
- AV_VERSION_MAJOR(l->buildv) != AV_VERSION_MAJOR(l->runv);
- }
mp_msg(log, v, "\n");
+ if (l->buildv > l->runv ||
+ AV_VERSION_MAJOR(l->buildv) != AV_VERSION_MAJOR(l->runv))
+ {
+ fprintf(stderr, "%s: %d.%d.%d -> %d.%d.%d\n",
+ l->name, V(l->buildv), V(l->runv));
+ abort();
+ }
}
-
- mp_msg(log, v, "%s version: %s\n", LIB_PREFIX, av_version_info());
-
- return !mismatch;
}
#undef V
diff --git a/common/av_log.h b/common/av_log.h
index 18f7fc9d82..ae12838c35 100644
--- a/common/av_log.h
+++ b/common/av_log.h
@@ -7,5 +7,5 @@ struct mpv_global;
struct mp_log;
void init_libav(struct mpv_global *global);
void uninit_libav(struct mpv_global *global);
-bool print_libav_versions(struct mp_log *log, int v);
+void check_library_versions(struct mp_log *log, int v);
#endif
diff --git a/common/common.c b/common/common.c
index 5068995ded..7089a6674b 100644
--- a/common/common.c
+++ b/common/common.c
@@ -21,6 +21,7 @@
#include <libavutil/common.h>
#include <libavutil/error.h>
+#include <libavutil/mathematics.h>
#include "mpv_talloc.h"
#include "misc/bstr.h"
@@ -93,6 +94,25 @@ char *mp_format_time(double time, bool fractions)
return mp_format_time_fmt(fractions ? "%H:%M:%S.%T" : "%H:%M:%S", time);
}
+char *mp_format_double(void *talloc_ctx, double val, int precision,
+ bool plus_sign, bool percent_sign, bool trim)
+{
+ bstr str = {0};
+ const char *fmt = plus_sign ? "%+.*f" : "%.*f";
+ bstr_xappend_asprintf(talloc_ctx, &str, fmt, precision, val);
+ size_t pos = str.len;
+ if (trim) {
+ while (--pos && str.start[pos] == '0')
+ str.len--;
+ if (str.start[pos] == '.')
+ str.len--;
+ }
+ if (percent_sign)
+ bstr_xappend(talloc_ctx, &str, bstr0("%"));
+ str.start[str.len] = '\0';
+ return str.start;
+}
+
// Set rc to the union of rc and rc2
void mp_rect_union(struct mp_rect *rc, const struct mp_rect *rc2)
{
@@ -120,12 +140,65 @@ bool mp_rect_intersection(struct mp_rect *rc, const struct mp_rect *rc2)
return rc->x1 > rc->x0 && rc->y1 > rc->y0;
}
-bool mp_rect_equals(struct mp_rect *rc1, struct mp_rect *rc2)
+bool mp_rect_equals(const struct mp_rect *rc1, const struct mp_rect *rc2)
{
return rc1->x0 == rc2->x0 && rc1->y0 == rc2->y0 &&
rc1->x1 == rc2->x1 && rc1->y1 == rc2->y1;
}
+// Rotate mp_rect by 90 degrees increments
+void mp_rect_rotate(struct mp_rect *rc, int w, int h, int rotation)
+{
+ rotation %= 360;
+
+ if (rotation >= 180) {
+ rotation -= 180;
+ MPSWAP(int, rc->x0, rc->x1);
+ MPSWAP(int, rc->y0, rc->y1);
+ }
+
+ if (rotation == 90) {
+ *rc = (struct mp_rect) {
+ .x0 = rc->y1,
+ .y0 = rc->x0,
+ .x1 = rc->y0,
+ .y1 = rc->x1,
+ };
+ }
+
+ if (rc->x1 < rc->x0) {
+ rc->x0 = w - rc->x0;
+ rc->x1 = w - rc->x1;
+ }
+
+ if (rc->y1 < rc->y0) {
+ rc->y0 = h - rc->y0;
+ rc->y1 = h - rc->y1;
+ }
+}
+
+// Compute rc1-rc2, put result in res_array, return number of rectangles in
+// res_array. In the worst case, there are 4 rectangles, so res_array must
+// provide that much storage space.
+int mp_rect_subtract(const struct mp_rect *rc1, const struct mp_rect *rc2,
+ struct mp_rect res[4])
+{
+ struct mp_rect rc = *rc1;
+ if (!mp_rect_intersection(&rc, rc2))
+ return 0;
+
+ int cnt = 0;
+ if (rc1->y0 < rc.y0)
+ res[cnt++] = (struct mp_rect){rc1->x0, rc1->y0, rc1->x1, rc.y0};
+ if (rc1->x0 < rc.x0)
+ res[cnt++] = (struct mp_rect){rc1->x0, rc.y0, rc.x0, rc.y1};
+ if (rc1->x1 > rc.x1)
+ res[cnt++] = (struct mp_rect){rc.x1, rc.y0, rc1->x1, rc.y1};
+ if (rc1->y1 > rc.y1)
+ res[cnt++] = (struct mp_rect){rc1->x0, rc.y1, rc1->x1, rc1->y1};
+ return cnt;
+}
+
// This works like snprintf(), except that it starts writing the first output
// character to str[strlen(str)]. This returns the number of characters the
// string would have *appended* assuming a large enough buffer, will make sure
@@ -344,9 +417,16 @@ unsigned int mp_log2(uint32_t v)
// mp_round_next_power_of_2(UINT32_MAX) == 0
uint32_t mp_round_next_power_of_2(uint32_t v)
{
- for (int n = 0; n < 30; n++) {
- if ((1 << n) >= v)
- return 1 << n;
- }
- return 0;
+ if (!v)
+ return 1;
+ if (!(v & (v - 1)))
+ return v;
+ int l = mp_log2(v) + 1;
+ return l == 32 ? 0 : (uint32_t)1 << l;
+}
+
+int mp_lcm(int x, int y)
+{
+ assert(x && y);
+ return x * (y / av_gcd(x, y));
}
diff --git a/common/common.h b/common/common.h
index 8dbb304625..cd9bea93c2 100644
--- a/common/common.h
+++ b/common/common.h
@@ -39,6 +39,7 @@
#define MPSWAP(type, a, b) \
do { type SWAP_tmp = b; b = a; a = SWAP_tmp; } while (0)
#define MP_ARRAY_SIZE(s) (sizeof(s) / sizeof((s)[0]))
+#define MP_DIV_UP(x, y) (((x) + (y) - 1) / (y))
// align must be a power of two (align >= 1), x >= 0
#define MP_ALIGN_UP(x, align) (((x) + (align) - 1) & ~((align) - 1))
@@ -46,6 +47,9 @@
#define MP_IS_ALIGNED(x, align) (!((x) & ((align) - 1)))
#define MP_IS_POWER_OF_2(x) ((x) > 0 && !((x) & ((x) - 1)))
+// align to non power of two
+#define MP_ALIGN_NPOT(x, align) ((align) ? MP_DIV_UP(x, align) * (align) : (x))
+
// Return "a", or if that is NOPTS, return "def".
#define MP_PTS_OR_DEF(a, def) ((a) == MP_NOPTS_VALUE ? (def) : (a))
// If one of the values is NOPTS, always pick the other one.
@@ -68,6 +72,26 @@ enum stream_type {
STREAM_TYPE_COUNT,
};
+enum video_sync {
+ VS_DEFAULT = 0,
+ VS_DISP_RESAMPLE,
+ VS_DISP_RESAMPLE_VDROP,
+ VS_DISP_RESAMPLE_NONE,
+ VS_DISP_TEMPO,
+ VS_DISP_ADROP,
+ VS_DISP_VDROP,
+ VS_DISP_NONE,
+ VS_NONE,
+};
+
+#define VS_IS_DISP(x) ((x) == VS_DISP_RESAMPLE || \
+ (x) == VS_DISP_RESAMPLE_VDROP || \
+ (x) == VS_DISP_RESAMPLE_NONE || \
+ (x) == VS_DISP_TEMPO || \
+ (x) == VS_DISP_ADROP || \
+ (x) == VS_DISP_VDROP || \
+ (x) == VS_DISP_NONE)
+
extern const char mpv_version[];
extern const char mpv_builddate[];
extern const char mpv_copyright[];
@@ -75,6 +99,12 @@ extern const char mpv_copyright[];
char *mp_format_time(double time, bool fractions);
char *mp_format_time_fmt(const char *fmt, double time);
+// Formats a double value to a string with the specified precision.
+// Trailing zeros (and the dot) can be trimmed.
+// Optionally, a plus sign and a percent sign can be added.
+char *mp_format_double(void *talloc_ctx, double val, int precision,
+ bool plus_sign, bool percent_sign, bool trim);
+
struct mp_rect {
int x0, y0;
int x1, y1;
@@ -86,10 +116,14 @@ struct mp_rect {
void mp_rect_union(struct mp_rect *rc, const struct mp_rect *src);
bool mp_rect_intersection(struct mp_rect *rc, const struct mp_rect *rc2);
bool mp_rect_contains(struct mp_rect *rc, int x, int y);
-bool mp_rect_equals(struct mp_rect *rc1, struct mp_rect *rc2);
+bool mp_rect_equals(const struct mp_rect *rc1, const struct mp_rect *rc2);
+int mp_rect_subtract(const struct mp_rect *rc1, const struct mp_rect *rc2,
+ struct mp_rect res_array[4]);
+void mp_rect_rotate(struct mp_rect *rc, int w, int h, int rotation);
unsigned int mp_log2(uint32_t v);
uint32_t mp_round_next_power_of_2(uint32_t v);
+int mp_lcm(int x, int y);
int mp_snprintf_cat(char *str, size_t size, const char *format, ...)
PRINTF_ATTRIBUTE(3, 4);
diff --git a/common/encode.h b/common/encode.h
index 62a8b094e9..33d778cd67 100644
--- a/common/encode.h
+++ b/common/encode.h
@@ -38,12 +38,8 @@ struct encode_opts {
char **vopts;
char *acodec;
char **aopts;
- float voffset;
- float aoffset;
- int rawts;
- int video_first;
- int audio_first;
- int copy_metadata;
+ bool rawts;
+ bool copy_metadata;
char **set_metadata;
char **remove_metadata;
};
@@ -54,13 +50,12 @@ bool encode_lavc_free(struct encode_lavc_context *ctx);
void encode_lavc_discontinuity(struct encode_lavc_context *ctx);
bool encode_lavc_showhelp(struct mp_log *log, struct encode_opts *options);
int encode_lavc_getstatus(struct encode_lavc_context *ctx, char *buf, int bufsize, float relative_position);
+bool encode_lavc_stream_type_ok(struct encode_lavc_context *ctx,
+ enum stream_type type);
void encode_lavc_expect_stream(struct encode_lavc_context *ctx,
enum stream_type type);
-void encode_lavc_stream_eof(struct encode_lavc_context *ctx,
- enum stream_type type);
void encode_lavc_set_metadata(struct encode_lavc_context *ctx,
struct mp_tags *metadata);
-void encode_lavc_set_audio_pts(struct encode_lavc_context *ctx, double pts);
bool encode_lavc_didfail(struct encode_lavc_context *ctx); // check if encoding failed
#endif
diff --git a/common/encode_lavc.c b/common/encode_lavc.c
index b64232fb87..a250f9c994 100644
--- a/common/encode_lavc.c
+++ b/common/encode_lavc.c
@@ -23,7 +23,6 @@
#include <libavutil/avutil.h>
#include <libavutil/timestamp.h>
-#include "config.h"
#include "encode_lavc.h"
#include "common/av_common.h"
#include "common/global.h"
@@ -77,37 +76,22 @@ struct mux_stream {
#define OPT_BASE_STRUCT struct encode_opts
const struct m_sub_options encode_config = {
.opts = (const m_option_t[]) {
- OPT_STRING("o", file, CONF_NOCFG | CONF_PRE_PARSE | M_OPT_FILE),
- OPT_STRING("of", format, 0),
- OPT_KEYVALUELIST("ofopts", fopts, M_OPT_HAVE_HELP),
- OPT_STRING("ovc", vcodec, 0),
- OPT_KEYVALUELIST("ovcopts", vopts, M_OPT_HAVE_HELP),
- OPT_STRING("oac", acodec, 0),
- OPT_KEYVALUELIST("oacopts", aopts, M_OPT_HAVE_HELP),
- OPT_FLOATRANGE("ovoffset", voffset, 0, -1000000.0, 1000000.0,
- .deprecation_message = "--audio-delay (once unbroken)"),
- OPT_FLOATRANGE("oaoffset", aoffset, 0, -1000000.0, 1000000.0,
- .deprecation_message = "--audio-delay (once unbroken)"),
- OPT_FLAG("orawts", rawts, 0),
- OPT_FLAG("ovfirst", video_first, 0,
- .deprecation_message = "no replacement"),
- OPT_FLAG("oafirst", audio_first, 0,
- .deprecation_message = "no replacement"),
- OPT_FLAG("ocopy-metadata", copy_metadata, 0),
- OPT_KEYVALUELIST("oset-metadata", set_metadata, 0),
- OPT_STRINGLIST("oremove-metadata", remove_metadata, 0),
-
- OPT_REMOVED("ocopyts", "ocopyts is now the default"),
- OPT_REMOVED("oneverdrop", "no replacement"),
- OPT_REMOVED("oharddup", "use --vf-add=fps=VALUE"),
- OPT_REMOVED("ofps", "no replacement (use --vf-add=fps=VALUE for CFR)"),
- OPT_REMOVED("oautofps", "no replacement"),
- OPT_REMOVED("omaxfps", "no replacement"),
+ {"o", OPT_STRING(file), .flags = CONF_NOCFG | CONF_PRE_PARSE | M_OPT_FILE},
+ {"of", OPT_STRING(format)},
+ {"ofopts", OPT_KEYVALUELIST(fopts), .flags = M_OPT_HAVE_HELP},
+ {"ovc", OPT_STRING(vcodec)},
+ {"ovcopts", OPT_KEYVALUELIST(vopts), .flags = M_OPT_HAVE_HELP},
+ {"oac", OPT_STRING(acodec)},
+ {"oacopts", OPT_KEYVALUELIST(aopts), .flags = M_OPT_HAVE_HELP},
+ {"orawts", OPT_BOOL(rawts)},
+ {"ocopy-metadata", OPT_BOOL(copy_metadata)},
+ {"oset-metadata", OPT_KEYVALUELIST(set_metadata)},
+ {"oremove-metadata", OPT_STRINGLIST(remove_metadata)},
{0}
},
.size = sizeof(struct encode_opts),
.defaults = &(const struct encode_opts){
- .copy_metadata = 1,
+ .copy_metadata = true,
},
};
@@ -120,7 +104,7 @@ struct encode_lavc_context *encode_lavc_init(struct mpv_global *global)
.priv = talloc_zero(ctx, struct encode_priv),
.log = mp_log_new(ctx, global->log, "encode"),
};
- pthread_mutex_init(&ctx->lock, NULL);
+ mp_mutex_init(&ctx->lock);
struct encode_priv *p = ctx->priv;
p->log = ctx->log;
@@ -173,7 +157,7 @@ void encode_lavc_set_metadata(struct encode_lavc_context *ctx,
{
struct encode_priv *p = ctx->priv;
- pthread_mutex_lock(&ctx->lock);
+ mp_mutex_lock(&ctx->lock);
if (ctx->options->copy_metadata) {
p->metadata = mp_tags_dup(ctx, metadata);
@@ -200,7 +184,7 @@ void encode_lavc_set_metadata(struct encode_lavc_context *ctx,
}
}
- pthread_mutex_unlock(&ctx->lock);
+ mp_mutex_unlock(&ctx->lock);
}
bool encode_lavc_free(struct encode_lavc_context *ctx)
@@ -236,22 +220,12 @@ bool encode_lavc_free(struct encode_lavc_context *ctx)
res = !p->failed;
- pthread_mutex_destroy(&ctx->lock);
+ mp_mutex_destroy(&ctx->lock);
talloc_free(ctx);
return res;
}
-void encode_lavc_set_audio_pts(struct encode_lavc_context *ctx, double pts)
-{
- if (ctx) {
- pthread_mutex_lock(&ctx->lock);
- ctx->last_audio_in_pts = pts;
- ctx->samples_since_last_pts = 0;
- pthread_mutex_unlock(&ctx->lock);
- }
-}
-
// called locked
static void maybe_init_muxer(struct encode_lavc_context *ctx)
{
@@ -339,7 +313,7 @@ void encode_lavc_expect_stream(struct encode_lavc_context *ctx,
{
struct encode_priv *p = ctx->priv;
- pthread_mutex_lock(&ctx->lock);
+ mp_mutex_lock(&ctx->lock);
enum AVMediaType codec_type = mp_to_av_stream_type(type);
@@ -363,45 +337,21 @@ void encode_lavc_expect_stream(struct encode_lavc_context *ctx,
MP_TARRAY_APPEND(p, p->streams, p->num_streams, dst);
done:
- pthread_mutex_unlock(&ctx->lock);
-}
-
-void encode_lavc_stream_eof(struct encode_lavc_context *ctx,
- enum stream_type type)
-{
- if (!ctx)
- return;
-
- struct encode_priv *p = ctx->priv;
-
- pthread_mutex_lock(&ctx->lock);
-
- enum AVMediaType codec_type = mp_to_av_stream_type(type);
- struct mux_stream *dst = find_mux_stream(ctx, codec_type);
-
- // If we've reached EOF, even though the stream was selected, and we didn't
- // ever initialize it, we have a problem. We could mux some sort of dummy
- // stream (and could fail if actual data arrives later), or we bail out
- // early.
- if (dst && !dst->st) {
- MP_ERR(p, "No data on stream %s.\n", dst->name);
- p->failed = true;
- }
-
- pthread_mutex_unlock(&ctx->lock);
+ mp_mutex_unlock(&ctx->lock);
}
// Signal that you are ready to encode (you provide the codec params etc. too).
// This returns a muxing handle which you can use to add encodec packets.
// Can be called only once per stream. info is copied by callee as needed.
-static struct mux_stream *encode_lavc_add_stream(struct encode_lavc_context *ctx,
- struct encoder_stream_info *info,
- void (*on_ready)(void *ctx),
- void *on_ready_ctx)
+static void encode_lavc_add_stream(struct encoder_context *enc,
+ struct encode_lavc_context *ctx,
+ struct encoder_stream_info *info,
+ void (*on_ready)(void *ctx),
+ void *on_ready_ctx)
{
struct encode_priv *p = ctx->priv;
- pthread_mutex_lock(&ctx->lock);
+ mp_mutex_lock(&ctx->lock);
struct mux_stream *dst = find_mux_stream(ctx, info->codecpar->codec_type);
if