summaryrefslogtreecommitdiffstats
path: root/filters/f_decoder_wrapper.c
diff options
context:
space:
mode:
Diffstat (limited to 'filters/f_decoder_wrapper.c')
-rw-r--r--filters/f_decoder_wrapper.c210
1 files changed, 109 insertions, 101 deletions
diff --git a/filters/f_decoder_wrapper.c b/filters/f_decoder_wrapper.c
index 397c3a0a98..7abe95116d 100644
--- a/filters/f_decoder_wrapper.c
+++ b/filters/f_decoder_wrapper.c
@@ -21,13 +21,11 @@
#include <stdbool.h>
#include <math.h>
#include <assert.h>
-#include <pthread.h>
#include <libavutil/buffer.h>
#include <libavutil/common.h>
#include <libavutil/rational.h>
-#include "config.h"
#include "options/options.h"
#include "common/msg.h"
#include "options/m_config.h"
@@ -54,7 +52,7 @@
#include "filter_internal.h"
struct dec_queue_opts {
- int use_queue;
+ bool use_queue;
int64_t max_bytes;
int64_t max_samples;
double max_duration;
@@ -63,7 +61,7 @@ struct dec_queue_opts {
#define OPT_BASE_STRUCT struct dec_queue_opts
static const struct m_option dec_queue_opts_list[] = {
- {"enable", OPT_FLAG(use_queue)},
+ {"enable", OPT_BOOL(use_queue)},
{"max-secs", OPT_DOUBLE(max_duration), M_RANGE(0, DBL_MAX)},
{"max-bytes", OPT_BYTE_SIZE(max_bytes), M_RANGE(0, M_MAX_MEM_BYTES)},
{"max-samples", OPT_INT64(max_samples), M_RANGE(0, DBL_MAX)},
@@ -74,7 +72,6 @@ static const struct m_sub_options vdec_queue_conf = {
.opts = dec_queue_opts_list,
.size = sizeof(struct dec_queue_opts),
.defaults = &(const struct dec_queue_opts){
- .use_queue = 0,
.max_bytes = 512 * 1024 * 1024,
.max_samples = 50,
.max_duration = 2,
@@ -85,7 +82,6 @@ static const struct m_sub_options adec_queue_conf = {
.opts = dec_queue_opts_list,
.size = sizeof(struct dec_queue_opts),
.defaults = &(const struct dec_queue_opts){
- .use_queue = 0,
.max_bytes = 1 * 1024 * 1024,
.max_samples = 48000,
.max_duration = 1,
@@ -96,10 +92,10 @@ static const struct m_sub_options adec_queue_conf = {
#define OPT_BASE_STRUCT struct dec_wrapper_opts
struct dec_wrapper_opts {
- float movie_aspect;
+ double movie_aspect;
int aspect_method;
- double force_fps;
- int correct_pts;
+ double fps_override;
+ bool correct_pts;
int video_rotate;
char *audio_decoders;
char *video_decoders;
@@ -110,16 +106,19 @@ struct dec_wrapper_opts {
int64_t audio_reverse_size;
};
-static int decoder_list_opt(struct mp_log *log, const m_option_t *opt,
- struct bstr name, struct bstr param);
+static int decoder_list_help(struct mp_log *log, const m_option_t *opt,
+ struct bstr name);
const struct m_sub_options dec_wrapper_conf = {
.opts = (const struct m_option[]){
- {"correct-pts", OPT_FLAG(correct_pts)},
- {"fps", OPT_DOUBLE(force_fps), M_RANGE(0, DBL_MAX)},
- {"ad", OPT_STRING_VALIDATE(audio_decoders, decoder_list_opt)},
- {"vd", OPT_STRING_VALIDATE(video_decoders, decoder_list_opt)},
- {"audio-spdif", OPT_STRING_VALIDATE(audio_spdif, decoder_list_opt)},
+ {"correct-pts", OPT_BOOL(correct_pts)},
+ {"container-fps-override", OPT_DOUBLE(fps_override), M_RANGE(0, DBL_MAX)},
+ {"ad", OPT_STRING(audio_decoders),
+ .help = decoder_list_help},
+ {"vd", OPT_STRING(video_decoders),
+ .help = decoder_list_help},
+ {"audio-spdif", OPT_STRING(audio_spdif),
+ .help = decoder_list_help},
{"video-rotate", OPT_CHOICE(video_rotate, {"no", -1}),
.flags = UPDATE_IMGPAR, M_RANGE(0, 359)},
{"video-aspect-override", OPT_ASPECT(movie_aspect),
@@ -132,12 +131,13 @@ const struct m_sub_options dec_wrapper_conf = {
{"video-reversal-buffer", OPT_BYTE_SIZE(video_reverse_size),
M_RANGE(0, M_MAX_MEM_BYTES)},
{"audio-reversal-buffer", OPT_BYTE_SIZE(audio_reverse_size),
- M_RANGE(0, M_MAX_MEM_BYTES)} ,
+ M_RANGE(0, M_MAX_MEM_BYTES)},
+ {"fps", OPT_REPLACED("container-fps-override")},
{0}
},
.size = sizeof(struct dec_wrapper_opts),
.defaults = &(const struct dec_wrapper_opts){
- .correct_pts = 1,
+ .correct_pts = true,
.movie_aspect = -1.,
.aspect_method = 2,
.video_reverse_size = 1 * 1024 * 1024 * 1024,
@@ -218,13 +218,12 @@ struct priv {
struct mp_async_queue *queue; // decoded frame output queue
struct mp_dispatch_queue *dec_dispatch; // non-NULL if decoding thread used
bool dec_thread_lock; // debugging (esp. for no-thread case)
- pthread_t dec_thread;
+ mp_thread dec_thread;
bool dec_thread_valid;
- pthread_mutex_t cache_lock;
+ mp_mutex cache_lock;
// --- Protected by cache_lock.
char *cur_hwdec;
- char *decoder_desc;
bool try_spdif;
bool attached_picture;
bool pts_reset;
@@ -232,11 +231,9 @@ struct priv {
int dropped_frames; // total frames _probably_ dropped
};
-static int decoder_list_opt(struct mp_log *log, const m_option_t *opt,
- struct bstr name, struct bstr param)
+static int decoder_list_help(struct mp_log *log, const m_option_t *opt,
+ struct bstr name)
{
- if (!bstr_equals0(param, "help"))
- return 1;
if (strcmp(opt->name, "ad") == 0) {
struct mp_decoder_list *list = audio_decoder_list();
mp_print_decoders(log, MSGL_INFO, "Audio decoders:", list);
@@ -260,13 +257,13 @@ static int decoder_list_opt(struct mp_log *log, const m_option_t *opt,
// thread state. Must run on/locked with decoder thread.
static void update_cached_values(struct priv *p)
{
- pthread_mutex_lock(&p->cache_lock);
+ mp_mutex_lock(&p->cache_lock);
p->cur_hwdec = NULL;
if (p->decoder && p->decoder->control)
p->decoder->control(p->decoder->f, VDCTRL_GET_HWDEC, &p->cur_hwdec);
- pthread_mutex_unlock(&p->cache_lock);
+ mp_mutex_unlock(&p->cache_lock);
}
// Lock the decoder thread. This may synchronously wait until the decoder thread
@@ -325,11 +322,11 @@ static void decf_reset(struct mp_filter *f)
p->pts = MP_NOPTS_VALUE;
p->last_format = p->fixed_format = (struct mp_image_params){0};
- pthread_mutex_lock(&p->cache_lock);
+ mp_mutex_lock(&p->cache_lock);
p->pts_reset = false;
p->attempt_framedrops = 0;
p->dropped_frames = 0;
- pthread_mutex_unlock(&p->cache_lock);
+ mp_mutex_unlock(&p->cache_lock);
p->coverart_returned = 0;
@@ -348,9 +345,9 @@ int mp_decoder_wrapper_control(struct mp_decoder_wrapper *d,
struct priv *p = d->f->priv;
int res = CONTROL_UNKNOWN;
if (cmd == VDCTRL_GET_HWDEC) {
- pthread_mutex_lock(&p->cache_lock);
+ mp_mutex_lock(&p->cache_lock);
*(char **)arg = p->cur_hwdec;
- pthread_mutex_unlock(&p->cache_lock);
+ mp_mutex_unlock(&p->cache_lock);
} else {
thread_lock(p);
if (p->decoder && p->decoder->control)
@@ -399,9 +396,6 @@ static bool reinit_decoder(struct priv *p)
reset_decoder(p);
p->has_broken_packet_pts = -10; // needs 10 packets to reach decision
- talloc_free(p->decoder_desc);
- p->decoder_desc = NULL;
-
const struct mp_decoder_fns *driver = NULL;
struct mp_decoder_list *list = NULL;
char *user_list = NULL;
@@ -416,9 +410,9 @@ static bool reinit_decoder(struct priv *p)
user_list = p->opts->audio_decoders;
fallback = "aac";
- pthread_mutex_lock(&p->cache_lock);
+ mp_mutex_lock(&p->cache_lock);
bool try_spdif = p->try_spdif;
- pthread_mutex_unlock(&p->cache_lock);
+ mp_mutex_unlock(&p->cache_lock);
if (try_spdif && p->codec->codec) {
struct mp_decoder_list *spdif =
@@ -432,10 +426,12 @@ static bool reinit_decoder(struct priv *p)
}
}
+ if (!driver)
+ return false;
+
if (!list) {
struct mp_decoder_list *full = talloc_zero(NULL, struct mp_decoder_list);
- if (driver)
- driver->add_decoders(full);
+ driver->add_decoders(full);
const char *codec = p->codec->codec;
if (codec && strcmp(codec, "null") == 0)
codec = fallback;
@@ -451,11 +447,12 @@ static bool reinit_decoder(struct priv *p)
p->decoder = driver->create(p->decf, p->codec, sel->decoder);
if (p->decoder) {
- pthread_mutex_lock(&p->cache_lock);
- p->decoder_desc =
- talloc_asprintf(p, "%s (%s)", sel->decoder, sel->desc);
- MP_VERBOSE(p, "Selected codec: %s\n", p->decoder_desc);
- pthread_mutex_unlock(&p->cache_lock);
+ p->codec->decoder = talloc_strdup(p, sel->decoder);
+ p->codec->decoder_desc = talloc_strdup(p, sel->desc && sel->desc[0] ? sel->desc : NULL);
+ MP_VERBOSE(p, "Selected decoder: %s", sel->decoder);
+ if (p->codec->decoder_desc)
+ MP_VERBOSE(p, " - %s", p->codec->decoder_desc);
+ MP_VERBOSE(p, "\n");
break;
}
@@ -482,29 +479,20 @@ bool mp_decoder_wrapper_reinit(struct mp_decoder_wrapper *d)
return res;
}
-void mp_decoder_wrapper_get_desc(struct mp_decoder_wrapper *d,
- char *buf, size_t buf_size)
-{
- struct priv *p = d->f->priv;
- pthread_mutex_lock(&p->cache_lock);
- snprintf(buf, buf_size, "%s", p->decoder_desc ? p->decoder_desc : "");
- pthread_mutex_unlock(&p->cache_lock);
-}
-
void mp_decoder_wrapper_set_frame_drops(struct mp_decoder_wrapper *d, int num)
{
struct priv *p = d->f->priv;
- pthread_mutex_lock(&p->cache_lock);
+ mp_mutex_lock(&p->cache_lock);
p->attempt_framedrops = num;
- pthread_mutex_unlock(&p->cache_lock);
+ mp_mutex_unlock(&p->cache_lock);
}
int mp_decoder_wrapper_get_frames_dropped(struct mp_decoder_wrapper *d)
{
struct priv *p = d->f->priv;
- pthread_mutex_lock(&p->cache_lock);
+ mp_mutex_lock(&p->cache_lock);
int res = p->dropped_frames;
- pthread_mutex_unlock(&p->cache_lock);
+ mp_mutex_unlock(&p->cache_lock);
return res;
}
@@ -520,25 +508,25 @@ double mp_decoder_wrapper_get_container_fps(struct mp_decoder_wrapper *d)
void mp_decoder_wrapper_set_spdif_flag(struct mp_decoder_wrapper *d, bool spdif)
{
struct priv *p = d->f->priv;
- pthread_mutex_lock(&p->cache_lock);
+ mp_mutex_lock(&p->cache_lock);
p->try_spdif = spdif;
- pthread_mutex_unlock(&p->cache_lock);
+ mp_mutex_unlock(&p->cache_lock);
}
void mp_decoder_wrapper_set_coverart_flag(struct mp_decoder_wrapper *d, bool c)
{
struct priv *p = d->f->priv;
- pthread_mutex_lock(&p->cache_lock);
+ mp_mutex_lock(&p->cache_lock);
p->attached_picture = c;
- pthread_mutex_unlock(&p->cache_lock);
+ mp_mutex_unlock(&p->cache_lock);
}
bool mp_decoder_wrapper_get_pts_reset(struct mp_decoder_wrapper *d)
{
struct priv *p = d->f->priv;
- pthread_mutex_lock(&p->cache_lock);
+ mp_mutex_lock(&p->cache_lock);
bool res = p->pts_reset;
- pthread_mutex_unlock(&p->cache_lock);
+ mp_mutex_unlock(&p->cache_lock);
return res;
}
@@ -550,37 +538,37 @@ void mp_decoder_wrapper_set_play_dir(struct mp_decoder_wrapper *d, int dir)
thread_unlock(p);
}
-static bool is_valid_peak(float sig_peak)
-{
- return !sig_peak || (sig_peak >= 1 && sig_peak <= 100);
-}
-
static void fix_image_params(struct priv *p,
- struct mp_image_params *params)
+ struct mp_image_params *params,
+ bool quiet)
{
struct mp_image_params m = *params;
struct mp_codec_params *c = p->codec;
struct dec_wrapper_opts *opts = p->opts;
- MP_VERBOSE(p, "Decoder format: %s\n", mp_image_params_to_str(params));
+ if (!quiet)
+ MP_VERBOSE(p, "Decoder format: %s\n", mp_image_params_to_str(params));
p->dec_format = *params;
// While mp_image_params normally always have to have d_w/d_h set, the
// decoder signals unknown bitstream aspect ratio with both set to 0.
bool use_container = true;
if (opts->aspect_method == 1 && m.p_w > 0 && m.p_h > 0) {
- MP_VERBOSE(p, "Using bitstream aspect ratio.\n");
+ if (!quiet)
+ MP_VERBOSE(p, "Using bitstream aspect ratio.\n");
use_container = false;
}
if (use_container && c->par_w > 0 && c->par_h) {
- MP_VERBOSE(p, "Using container aspect ratio.\n");
+ if (!quiet)
+ MP_VERBOSE(p, "Using container aspect ratio.\n");
m.p_w = c->par_w;
m.p_h = c->par_h;
}
if (opts->movie_aspect >= 0) {
- MP_VERBOSE(p, "Forcing user-set aspect ratio.\n");
+ if (!quiet)
+ MP_VERBOSE(p, "Forcing user-set aspect ratio.\n");
if (opts->movie_aspect == 0) {
m.p_w = m.p_h = 1;
} else {
@@ -593,22 +581,38 @@ static void fix_image_params(struct priv *p,
if (m.p_w <= 0 || m.p_h <= 0)
m.p_w = m.p_h = 1;
- m.rotate = p->codec->rotate;
m.stereo3d = p->codec->stereo_mode;
+ if (!mp_rect_equals(&p->codec->crop, &(struct mp_rect){0})) {
+ struct mp_rect crop = p->codec->crop;
+ // Offset to respect existing decoder crop.
+ crop.x0 += m.crop.x0;
+ crop.x1 += m.crop.x0;
+ crop.y0 += m.crop.y0;
+ crop.y1 += m.crop.y0;
+ // Crop has to be inside existing image bounds.
+ if (mp_image_crop_valid(&(struct mp_image_params) {
+ .w = mp_rect_w(m.crop), .h = mp_rect_h(m.crop), .crop = crop }))
+ {
+ m.crop = crop;
+ } else {
+ MP_WARN(p, "Invalid container crop %dx%d+%d+%d for %dx%d image\n",
+ mp_rect_w(crop), mp_rect_h(crop), crop.x0, crop.y0,
+ mp_rect_w(m.crop), mp_rect_h(m.crop));
+ }
+ }
+
if (opts->video_rotate < 0) {
m.rotate = 0;
} else {
+ // ffmpeg commit 535a835e51 says that frame rotate takes priority
+ if (!m.rotate)
+ m.rotate = p->codec->rotate;
m.rotate = (m.rotate + opts->video_rotate) % 360;
}
- mp_colorspace_merge(&m.color, &c->color);
-
- // Sanitize the HDR peak. Sadly necessary
- if (!is_valid_peak(m.color.sig_peak)) {
- MP_WARN(p, "Invalid HDR peak in stream: %f\n", m.color.sig_peak);
- m.color.sig_peak = 0.0;
- }
+ pl_color_space_merge(&m.color, &c->color);
+ pl_color_repr_merge(&m.repr, &c->repr);
// Guess missing colorspace fields from metadata. This guarantees all
// fields are at least set to legal values afterwards.
@@ -780,9 +784,9 @@ static void correct_audio_pts(struct priv *p, struct mp_aframe *aframe)
if (p->pts != MP_NOPTS_VALUE && diff > 0.1) {
MP_WARN(p, "Invalid audio PTS: %f -> %f\n", p->pts, frame_pts);
if (diff >= 5) {
- pthread_mutex_lock(&p->cache_lock);
+ mp_mutex_lock(&p->cache_lock);
p->pts_reset = true;
- pthread_mutex_unlock(&p->cache_lock);
+ mp_mutex_unlock(&p->cache_lock);
}
}
@@ -808,8 +812,10 @@ static void process_output_frame(struct priv *p, struct mp_frame frame)
correct_video_pts(p, mpi);
- if (!mp_image_params_equal(&p->last_format, &mpi->params))
- fix_image_params(p, &mpi->params);
+ if (!mp_image_params_equal(&p->last_format, &mpi->params)) {
+ fix_image_params(p, &mpi->params,
+ mp_image_params_static_equal(&p->last_format, &mpi->params));
+ }
mpi->params = p->fixed_format;
mpi->nominal_fps = p->fps;
@@ -882,10 +888,10 @@ static void feed_packet(struct priv *p)
int framedrop_type = 0;
- pthread_mutex_lock(&p->cache_lock);
+ mp_mutex_lock(&p->cache_lock);
if (p->attempt_framedrops)
framedrop_type = 1;
- pthread_mutex_unlock(&p->cache_lock);
+ mp_mutex_unlock(&p->cache_lock);
if (start_pts != MP_NOPTS_VALUE && packet && p->play_dir > 0 &&
packet->pts < start_pts - .005 && !p->has_broken_packet_pts)
@@ -983,7 +989,7 @@ static void read_frame(struct priv *p)
if (!frame.type)
return;
- pthread_mutex_lock(&p->cache_lock);
+ mp_mutex_lock(&p->cache_lock);
if (p->attached_picture && frame.type == MP_FRAME_VIDEO)
p->decoded_coverart = frame;
if (p->attempt_framedrops) {
@@ -991,7 +997,7 @@ static void read_frame(struct priv *p)
p->attempt_framedrops = MPMAX(0, p->attempt_framedrops - dropped);
p->dropped_frames += dropped;
}
- pthread_mutex_unlock(&p->cache_lock);
+ mp_mutex_unlock(&p->cache_lock);
if (p->decoded_coverart.type) {
mp_filter_internal_mark_progress(p->decf);
@@ -1078,16 +1084,16 @@ static void decf_process(struct mp_filter *f)
read_frame(p);
}
-static void *dec_thread(void *ptr)
+static MP_THREAD_VOID dec_thread(void *ptr)
{
struct priv *p = ptr;
- char *t_name = "?";
+ char *t_name = "dec/?";
switch (p->header->type) {
- case STREAM_VIDEO: t_name = "vdec"; break;
- case STREAM_AUDIO: t_name = "adec"; break;
+ case STREAM_VIDEO: t_name = "dec/video"; break;
+ case STREAM_AUDIO: t_name = "dec/audio"; break;
}
- mpthread_set_name(t_name);
+ mp_thread_set_name(t_name);
while (!p->request_terminate_dec_thread) {
mp_filter_graph_run(p->dec_root_filter);
@@ -1095,7 +1101,7 @@ static void *dec_thread(void *ptr)
mp_dispatch_queue_process(p->dec_dispatch, INFINITY);
}
- return NULL;
+ MP_THREAD_RETURN();
}
static void public_f_reset(struct mp_filter *f)
@@ -1125,7 +1131,7 @@ static void public_f_destroy(struct mp_filter *f)
p->request_terminate_dec_thread = 1;
mp_dispatch_interrupt(p->dec_dispatch);
thread_unlock(p);
- pthread_join(p->dec_thread, NULL);
+ mp_thread_join(p->dec_thread);
p->dec_thread_valid = false;
}
@@ -1133,7 +1139,7 @@ static void public_f_destroy(struct mp_filter *f)
talloc_free(p->dec_root_filter);
talloc_free(p->queue);
- pthread_mutex_destroy(&p->cache_lock);
+ mp_mutex_destroy(&p->cache_lock);
}
static const struct mp_filter_info decf_filter = {
@@ -1174,7 +1180,7 @@ struct mp_decoder_wrapper *mp_decoder_wrapper_create(struct mp_filter *parent,
struct priv *p = public_f->priv;
p->public.f = public_f;
- pthread_mutex_init(&p->cache_lock, NULL);
+ mp_mutex_init(&p->cache_lock);
p->opt_cache = m_config_cache_alloc(p, public_f->global, &dec_wrapper_conf);
p->opts = p->opt_cache->opts;
p->header = src;
@@ -1189,9 +1195,9 @@ struct mp_decoder_wrapper *mp_decoder_wrapper_create(struct mp_filter *parent,
MP_VERBOSE(p, "Container reported FPS: %f\n", p->fps);
- if (p->opts->force_fps) {
- p->fps = p->opts->force_fps;
- MP_INFO(p, "FPS forced to %5.3f.\n", p->fps);
+ if (p->opts->fps_override) {
+ p->fps = p->opts->fps_override;
+ MP_INFO(p, "Container FPS forced to %5.3f.\n", p->fps);
MP_INFO(p, "Use --no-correct-pts to force FPS based timing.\n");
}
@@ -1224,6 +1230,8 @@ struct mp_decoder_wrapper *mp_decoder_wrapper_create(struct mp_filter *parent,
p->decf = mp_filter_create(p->dec_root_filter ? p->dec_root_filter : public_f,
&decf_filter);
+ if (!p->decf)
+ goto error;
p->decf->priv = p;
p->decf->log = public_f->log = p->log;
mp_filter_add_pin(p->decf, MP_PIN_OUT, "out");
@@ -1244,7 +1252,7 @@ struct mp_decoder_wrapper *mp_decoder_wrapper_create(struct mp_filter *parent,
mp_pin_connect(f_out->pins[0], p->decf->pins[0]);
p->dec_thread_valid = true;
- if (pthread_create(&p->dec_thread, NULL, dec_thread, p)) {
+ if (mp_thread_create(&p->dec_thread, dec_thread, p)) {
p->dec_thread_valid = false;
goto error;
}