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.c62
-rw-r--r--common/common.c59
-rw-r--r--common/common.h34
-rw-r--r--common/encode.h13
-rw-r--r--common/encode_lavc.c186
-rw-r--r--common/encode_lavc.h18
-rw-r--r--common/meson.build11
-rw-r--r--common/msg.c633
-rw-r--r--common/msg_control.h4
-rw-r--r--common/playlist.c118
-rw-r--r--common/playlist.h31
-rw-r--r--common/recorder.c108
-rw-r--r--common/recorder.h5
-rw-r--r--common/stats.c87
-rw-r--r--common/stats.h2
-rw-r--r--common/tags.c7
-rw-r--r--common/tags.h2
-rw-r--r--common/version.c6
-rw-r--r--common/version.h.in7
21 files changed, 965 insertions, 521 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 8122d3a65b..54b78a617d 100644
--- a/common/av_log.c
+++ b/common/av_log.c
@@ -22,22 +22,29 @@
#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>
@@ -45,10 +52,11 @@
// 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)
{
@@ -74,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;
}
@@ -100,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)
{
@@ -107,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;
@@ -119,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, "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();
@@ -157,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,6 +202,7 @@ void check_library_versions(struct mp_log *log, int v)
{"libswresample", LIBSWRESAMPLE_VERSION_INT, swresample_version()},
};
+ mp_msg(log, v, "FFmpeg version: %s\n", av_version_info());
mp_msg(log, v, "FFmpeg library versions:\n");
for (int n = 0; n < MP_ARRAY_SIZE(libs); n++) {
@@ -203,8 +219,6 @@ void check_library_versions(struct mp_log *log, int v)
abort();
}
}
-
- mp_msg(log, v, "FFmpeg version: %s\n", av_version_info());
}
#undef V
diff --git a/common/common.c b/common/common.c
index 6607f95c3c..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,43 @@ 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.
@@ -373,3 +424,9 @@ uint32_t mp_round_next_power_of_2(uint32_t 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 af01e38e10..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,12 +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 94428c6733..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,38 +76,22 @@ struct mux_stream {
#define OPT_BASE_STRUCT struct encode_opts
const struct m_sub_options encode_config = {
.opts = (const m_option_t[]) {
- {"o", OPT_STRING(file), .flags = CONF_NOCFG | CONF_PRE_PARSE | M_OPT_FILE,
- .deprecation_message = "lack of maintainer"},
+ {"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},
- {"ovoffset", OPT_FLOAT(voffset), M_RANGE(-1000000.0, 1000000.0),
- .deprecation_message = "--audio-delay (once unbroken)"},
- {"oaoffset", OPT_FLOAT(aoffset), M_RANGE(-1000000.0, 1000000.0),
- .deprecation_message = "--audio-delay (once unbroken)"},
- {"orawts", OPT_FLAG(rawts)},
- {"ovfirst", OPT_FLAG(video_first),
- .deprecation_message = "no replacement"},
- {"oafirst", OPT_FLAG(audio_first),
- .deprecation_message = "no replacement"},
- {"ocopy-metadata", OPT_FLAG(copy_metadata)},
+ {"orawts", OPT_BOOL(rawts)},
+ {"ocopy-metadata", OPT_BOOL(copy_metadata)},
{"oset-metadata", OPT_KEYVALUELIST(set_metadata)},
{"oremove-metadata", OPT_STRINGLIST(remove_metadata)},
-
- {"ocopyts", OPT_REMOVED("ocopyts is now the default")},
- {"oneverdrop", OPT_REMOVED("no replacement")},
- {"oharddup", OPT_REMOVED("use --vf-add=fps=VALUE")},
- {"ofps", OPT_REMOVED("no replacement (use --vf-add=fps=VALUE for CFR)")},
- {"oautofps", OPT_REMOVED("no replacement")},
- {"omaxfps", OPT_REMOVED("no replacement")},
{0}
},
.size = sizeof(struct encode_opts),
.defaults = &(const struct encode_opts){
- .copy_metadata = 1,
+ .copy_metadata = true,
},
};
@@ -121,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;
@@ -174,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);
@@ -201,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)
@@ -237,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)
{
@@ -340,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);
@@ -364,32 +337,7 @@ 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).
@@ -403,7 +351,7 @@ static void encode_lavc_add_stream(struct encoder_context *enc,
{
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 (!dst) {
@@ -439,7 +387,7 @@ static void encode_lavc_add_stream(struct encoder_context *enc,
maybe_init_muxer(ctx);
done:
- pthread_mutex_unlock(&ctx->lock);
+ mp_mutex_unlock(&ctx->lock);
}
// Write a packet. This will take over ownership of `pkt`
@@ -450,7 +398,7 @@ static void encode_lavc_add_packet(struct mux_stream *dst, AVPacket *pkt)
assert(dst->st);
- pthread_mutex_lock(&ctx->lock);
+ mp_mutex_lock(&ctx->lock);
if (p->failed)
goto done;
@@ -487,7 +435,7 @@ static void encode_lavc_add_packet(struct mux_stream *dst, AVPacket *pkt)
pkt = NULL;
done:
- pthread_mutex_unlock(&ctx->lock);
+ mp_mutex_unlock(&ctx->lock);
if (pkt)
av_packet_unref(pkt);
}
@@ -502,12 +450,9 @@ void encode_lavc_discontinuity(struct encode_lavc_context *ctx)
if (!ctx)
return;
- pthread_mutex_lock(&ctx->lock);
-
- ctx->audio_pts_offset = MP_NOPTS_VALUE;
+ mp_mutex_lock(&ctx->lock);
ctx->discontinuity_pts_offset = MP_NOPTS_VALUE;
-
- pthread_mutex_unlock(&ctx->lock);
+ mp_mutex_unlock(&ctx->lock);
}
static void encode_lavc_printoptions(struct mp_log *log, const void *obj,
@@ -728,7 +673,7 @@ int encode_lavc_getstatus(struct encode_lavc_context *ctx,
float minutes, megabytes, fps, x;
float f = MPMAX(0.0001, relative_position);
- pthread_mutex_lock(&ctx->lock);
+ mp_mutex_lock(&ctx->lock);
if (p->failed) {
snprintf(buf, bufsize, "(failed)\n");
@@ -752,7 +697,7 @@ int encode_lavc_getstatus(struct encode_lavc_context *ctx,
buf[bufsize - 1] = 0;
done:
- pthread_mutex_unlock(&ctx->lock);
+ mp_mutex_unlock(&ctx->lock);
return 0;
}
@@ -760,9 +705,9 @@ bool encode_lavc_didfail(struct encode_lavc_context *ctx)
{
if (!ctx)
return false;
- pthread_mutex_lock(&ctx->lock);
+ mp_mutex_lock(&ctx->lock);
bool fail = ctx->priv->failed;
- pthread_mutex_unlock(&ctx->lock);
+ mp_mutex_unlock(&ctx->lock);
return fail;
}
@@ -770,10 +715,53 @@ static void encoder_destroy(void *ptr)
{
struct encoder_context *p = ptr;
+ av_packet_free(&p->pkt);
+ avcodec_parameters_free(&p->info.codecpar);
avcodec_free_context(&p->encoder);
free_stream(p->twopass_bytebuffer);
}
+static const AVCodec *find_codec_for(struct encode_lavc_context *ctx,
+ enum stream_type type, bool *used_auto)
+{
+ char *codec_name = type == STREAM_VIDEO
+ ? ctx->options->vcodec
+ : ctx->options->acodec;
+ enum AVMediaType codec_type = mp_to_av_stream_type(type);
+ const char *tname = stream_type_name(type);
+
+ *used_auto = !(codec_name && codec_name[0]);
+
+ const AVCodec *codec;
+ if (*used_auto) {
+ codec = avcodec_find_encoder(av_guess_codec(ctx->oformat, NULL,
+ ctx->options->file, NULL,
+ codec_type));
+ } else {
+ codec = avcodec_find_encoder_by_name(codec_name);
+ if (!codec)
+ MP_FATAL(ctx, "codec '%s' not found.\n", codec_name);
+ }
+
+ if (codec && codec->type != codec_type) {
+ MP_FATAL(ctx, "codec for %s has wrong media type\n", tname);
+ codec = NULL;
+ }
+
+ return codec;
+}
+
+// Return whether the stream type is "supposed" to work.
+bool encode_lavc_stream_type_ok(struct encode_lavc_context *ctx,
+ enum stream_type type)
+{
+ // If a codec was forced, let it proceed to actual encoding, and then error
+ // if it doesn't work. (Worried that av_guess_codec() may return NULL for
+ // some formats where a specific codec works anyway.)
+ bool auto_codec;
+ return !!find_codec_for(ctx, type, &auto_codec) || !auto_codec;
+}
+
struct encoder_context *encoder_context_alloc(struct encode_lavc_context *ctx,
enum stream_type type,
struct mp_log *log)
@@ -794,27 +782,13 @@ struct encoder_context *encoder_context_alloc(struct encode_lavc_context *ctx,
.encode_lavc_ctx = ctx,
};
- char *codec_name = type == STREAM_VIDEO
- ? p->options->vcodec
- : p->options->acodec;
- enum AVMediaType codec_type = mp_to_av_stream_type(type);
+ bool auto_codec;
+ const AVCodec *codec = find_codec_for(ctx, type, &auto_codec);
const char *tname = stream_type_name(type);
- AVCodec *codec;
- if (codec_name&& codec_name[0]) {
- codec = avcodec_find_encoder_by_name(codec_name);
- } else {
- codec = avcodec_find_encoder(av_g