diff options
Diffstat (limited to 'common')
-rw-r--r-- | common/av_common.c | 84 | ||||
-rw-r--r-- | common/av_common.h | 9 | ||||
-rw-r--r-- | common/av_log.c | 100 | ||||
-rw-r--r-- | common/av_log.h | 2 | ||||
-rw-r--r-- | common/common.c | 92 | ||||
-rw-r--r-- | common/common.h | 36 | ||||
-rw-r--r-- | common/encode.h | 13 | ||||
-rw-r--r-- | common/encode_lavc.c | 223 | ||||
-rw-r--r-- | common/encode_lavc.h | 20 | ||||
-rw-r--r-- | common/global.h | 1 | ||||
-rw-r--r-- | common/meson.build | 11 | ||||
-rw-r--r-- | common/msg.c | 800 | ||||
-rw-r--r-- | common/msg.h | 2 | ||||
-rw-r--r-- | common/msg_control.h | 7 | ||||
-rw-r--r-- | common/playlist.c | 138 | ||||
-rw-r--r-- | common/playlist.h | 39 | ||||
-rw-r--r-- | common/recorder.c | 110 | ||||
-rw-r--r-- | common/recorder.h | 5 | ||||
-rw-r--r-- | common/stats.c | 325 | ||||
-rw-r--r-- | common/stats.h | 34 | ||||
-rw-r--r-- | common/tags.c | 7 | ||||
-rw-r--r-- | common/tags.h | 2 | ||||
-rw-r--r-- | common/version.c | 4 | ||||
-rw-r--r-- | common/version.h.in | 7 |
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 |