video: make decoder wrapper a filter
Move dec_video.c to filters/f_decoder_wrapper.c. It essentially becomes
a source filter. vd.h mostly disappears, because mp_filter takes care of
the dataflow, but its remains are in struct mp_decoder_fns.
One goal is to simplify dataflow by letting the filter framework handle
it (or more accurately, using its conventions). One result is that the
decode calls disappear from video.c, because we simply connect the
decoder wrapper and the filter chain with mp_pin_connect().
Another goal is to eventually remove the code duplication between the
audio and video paths for this. This commit prepares for this by trying
to make f_decoder_wrapper.c extensible, so it can be used for audio as
well later.
Decoder framedropping changes a bit. It doesn't seem to be worse than
before, and it's an obscure feature, so I'm content with its new state.
Some special code that was apparently meant to avoid dropping too many
frames in a row is removed, though.
I'm not sure how the source code tree should be organized. For one,
video/decode/vd_lavc.c is the only file in its directory, which is a bit
annoying.
2018-01-28 09:08:45 +00:00
|
|
|
/*
|
|
|
|
* This file is part of mpv.
|
|
|
|
*
|
|
|
|
* mpv is free software; you can redistribute it and/or
|
|
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
|
|
* License as published by the Free Software Foundation; either
|
|
|
|
* version 2.1 of the License, or (at your option) any later version.
|
|
|
|
*
|
|
|
|
* mpv is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU Lesser General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
|
|
* License along with mpv. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#pragma once
|
|
|
|
|
|
|
|
#include <stdbool.h>
|
|
|
|
|
|
|
|
#include "filter.h"
|
|
|
|
|
|
|
|
struct sh_stream;
|
|
|
|
struct mp_codec_params;
|
|
|
|
struct mp_image_params;
|
|
|
|
struct mp_decoder_list;
|
|
|
|
struct demux_packet;
|
|
|
|
|
|
|
|
// (free with talloc_free(mp_decoder_wrapper.f)
|
|
|
|
struct mp_decoder_wrapper {
|
|
|
|
// Filter with no input and 1 output, which returns the decoded data.
|
|
|
|
struct mp_filter *f;
|
|
|
|
|
|
|
|
// Can be set by user.
|
|
|
|
struct mp_recorder_sink *recorder_sink;
|
|
|
|
};
|
|
|
|
|
|
|
|
// Create the decoder wrapper for the given stream, plus underlying decoder.
|
|
|
|
// The src stream must be selected, and remain valid and selected until the
|
|
|
|
// wrapper is destroyed.
|
|
|
|
struct mp_decoder_wrapper *mp_decoder_wrapper_create(struct mp_filter *parent,
|
|
|
|
struct sh_stream *src);
|
|
|
|
|
f_decoder_wrapper: replace most public fields with setters/getters
I may (optionally) move decoding to a separate thread in a future
change. It's a bit attractive to move the entire decoder wrapper to
there, so if the demuxer has a new packet, it doesn't have to wake up
the main thread, and can directly wake up the decoder. (Although that's
bullshit, since there's a queue in between, and libavcodec's
multi-threaded decoding plays cross-threads ping pong with packets
anyway. On the other hand, the main thread would still have to shuffle
the packets around, so whatever, just seems like better design.)
As preparation, there shouldn't be any mutable state exposed by the
wrapper. But there's still a large number of corner-caseish crap, so
just use setters/getters for them. This recorder thing will inherently
not work, so it'll have to be disabled if threads are used.
This is a bit painful, but probably still the right thing. Like
speculatively pulling teeth.
2020-02-28 20:17:55 +00:00
|
|
|
// For informational purposes.
|
|
|
|
void mp_decoder_wrapper_get_desc(struct mp_decoder_wrapper *d,
|
|
|
|
char *buf, size_t buf_size);
|
|
|
|
|
|
|
|
// Legacy decoder framedrop control.
|
|
|
|
void mp_decoder_wrapper_set_frame_drops(struct mp_decoder_wrapper *d, int num);
|
|
|
|
int mp_decoder_wrapper_get_frames_dropped(struct mp_decoder_wrapper *d);
|
|
|
|
|
|
|
|
double mp_decoder_wrapper_get_container_fps(struct mp_decoder_wrapper *d);
|
|
|
|
|
|
|
|
// Whether to prefer spdif wrapper over real decoders on next reinit.
|
|
|
|
void mp_decoder_wrapper_set_spdif_flag(struct mp_decoder_wrapper *d, bool spdif);
|
|
|
|
|
2020-09-27 22:04:21 +00:00
|
|
|
// Whether to decode only 1 frame and then stop, and cache the frame across resets.
|
|
|
|
void mp_decoder_wrapper_set_coverart_flag(struct mp_decoder_wrapper *d, bool c);
|
|
|
|
|
f_decoder_wrapper: replace most public fields with setters/getters
I may (optionally) move decoding to a separate thread in a future
change. It's a bit attractive to move the entire decoder wrapper to
there, so if the demuxer has a new packet, it doesn't have to wake up
the main thread, and can directly wake up the decoder. (Although that's
bullshit, since there's a queue in between, and libavcodec's
multi-threaded decoding plays cross-threads ping pong with packets
anyway. On the other hand, the main thread would still have to shuffle
the packets around, so whatever, just seems like better design.)
As preparation, there shouldn't be any mutable state exposed by the
wrapper. But there's still a large number of corner-caseish crap, so
just use setters/getters for them. This recorder thing will inherently
not work, so it'll have to be disabled if threads are used.
This is a bit painful, but probably still the right thing. Like
speculatively pulling teeth.
2020-02-28 20:17:55 +00:00
|
|
|
// True if a pts reset was observed (audio only, heuristic).
|
|
|
|
bool mp_decoder_wrapper_get_pts_reset(struct mp_decoder_wrapper *d);
|
|
|
|
|
|
|
|
void mp_decoder_wrapper_set_play_dir(struct mp_decoder_wrapper *d, int dir);
|
|
|
|
|
video: make decoder wrapper a filter
Move dec_video.c to filters/f_decoder_wrapper.c. It essentially becomes
a source filter. vd.h mostly disappears, because mp_filter takes care of
the dataflow, but its remains are in struct mp_decoder_fns.
One goal is to simplify dataflow by letting the filter framework handle
it (or more accurately, using its conventions). One result is that the
decode calls disappear from video.c, because we simply connect the
decoder wrapper and the filter chain with mp_pin_connect().
Another goal is to eventually remove the code duplication between the
audio and video paths for this. This commit prepares for this by trying
to make f_decoder_wrapper.c extensible, so it can be used for audio as
well later.
Decoder framedropping changes a bit. It doesn't seem to be worse than
before, and it's an obscure feature, so I'm content with its new state.
Some special code that was apparently meant to avoid dropping too many
frames in a row is removed, though.
I'm not sure how the source code tree should be organized. For one,
video/decode/vd_lavc.c is the only file in its directory, which is a bit
annoying.
2018-01-28 09:08:45 +00:00
|
|
|
struct mp_decoder_list *video_decoder_list(void);
|
2018-01-29 05:18:33 +00:00
|
|
|
struct mp_decoder_list *audio_decoder_list(void);
|
video: make decoder wrapper a filter
Move dec_video.c to filters/f_decoder_wrapper.c. It essentially becomes
a source filter. vd.h mostly disappears, because mp_filter takes care of
the dataflow, but its remains are in struct mp_decoder_fns.
One goal is to simplify dataflow by letting the filter framework handle
it (or more accurately, using its conventions). One result is that the
decode calls disappear from video.c, because we simply connect the
decoder wrapper and the filter chain with mp_pin_connect().
Another goal is to eventually remove the code duplication between the
audio and video paths for this. This commit prepares for this by trying
to make f_decoder_wrapper.c extensible, so it can be used for audio as
well later.
Decoder framedropping changes a bit. It doesn't seem to be worse than
before, and it's an obscure feature, so I'm content with its new state.
Some special code that was apparently meant to avoid dropping too many
frames in a row is removed, though.
I'm not sure how the source code tree should be organized. For one,
video/decode/vd_lavc.c is the only file in its directory, which is a bit
annoying.
2018-01-28 09:08:45 +00:00
|
|
|
|
|
|
|
// For precise seeking: if possible, try to drop frames up until the given PTS.
|
|
|
|
// This is automatically unset if the target is reached, or on reset.
|
|
|
|
void mp_decoder_wrapper_set_start_pts(struct mp_decoder_wrapper *d, double pts);
|
|
|
|
|
|
|
|
enum dec_ctrl {
|
|
|
|
VDCTRL_FORCE_HWDEC_FALLBACK, // force software decoding fallback
|
|
|
|
VDCTRL_GET_HWDEC,
|
|
|
|
VDCTRL_REINIT,
|
|
|
|
VDCTRL_GET_BFRAMES,
|
|
|
|
// framedrop mode: 0=none, 1=standard, 2=hrseek
|
|
|
|
VDCTRL_SET_FRAMEDROP,
|
|
|
|
};
|
|
|
|
|
|
|
|
int mp_decoder_wrapper_control(struct mp_decoder_wrapper *d,
|
|
|
|
enum dec_ctrl cmd, void *arg);
|
|
|
|
|
|
|
|
// Force it to reevaluate output parameters (for overrides like aspect).
|
|
|
|
void mp_decoder_wrapper_reset_params(struct mp_decoder_wrapper *d);
|
|
|
|
|
|
|
|
void mp_decoder_wrapper_get_video_dec_params(struct mp_decoder_wrapper *d,
|
|
|
|
struct mp_image_params *p);
|
|
|
|
|
|
|
|
bool mp_decoder_wrapper_reinit(struct mp_decoder_wrapper *d);
|
|
|
|
|
|
|
|
struct mp_decoder {
|
|
|
|
// Bidirectional filter; takes MP_FRAME_PACKET for input.
|
|
|
|
struct mp_filter *f;
|
|
|
|
|
|
|
|
// Can be set by decoder impl. on init for "special" functionality.
|
|
|
|
int (*control)(struct mp_filter *f, enum dec_ctrl cmd, void *arg);
|
|
|
|
};
|
|
|
|
|
|
|
|
struct mp_decoder_fns {
|
|
|
|
struct mp_decoder *(*create)(struct mp_filter *parent,
|
|
|
|
struct mp_codec_params *codec,
|
|
|
|
const char *decoder);
|
|
|
|
void (*add_decoders)(struct mp_decoder_list *list);
|
|
|
|
};
|
|
|
|
|
|
|
|
extern const struct mp_decoder_fns vd_lavc;
|
2018-01-29 05:18:33 +00:00
|
|
|
extern const struct mp_decoder_fns ad_lavc;
|
|
|
|
extern const struct mp_decoder_fns ad_spdif;
|
video: make decoder wrapper a filter
Move dec_video.c to filters/f_decoder_wrapper.c. It essentially becomes
a source filter. vd.h mostly disappears, because mp_filter takes care of
the dataflow, but its remains are in struct mp_decoder_fns.
One goal is to simplify dataflow by letting the filter framework handle
it (or more accurately, using its conventions). One result is that the
decode calls disappear from video.c, because we simply connect the
decoder wrapper and the filter chain with mp_pin_connect().
Another goal is to eventually remove the code duplication between the
audio and video paths for this. This commit prepares for this by trying
to make f_decoder_wrapper.c extensible, so it can be used for audio as
well later.
Decoder framedropping changes a bit. It doesn't seem to be worse than
before, and it's an obscure feature, so I'm content with its new state.
Some special code that was apparently meant to avoid dropping too many
frames in a row is removed, though.
I'm not sure how the source code tree should be organized. For one,
video/decode/vd_lavc.c is the only file in its directory, which is a bit
annoying.
2018-01-28 09:08:45 +00:00
|
|
|
|
ad_lavc, vd_lavc: return full error codes to shared decoder loop
ad_lavc and vd_lavc use the lavc_process() helper to translate the
FFmpeg push/pull API to the internal filter API (which completely
mismatch, even though I'm responsible for both, just fucking kill me).
This interface was "slightly" too tight. It returned only a bool
indicating "progress", which was not enough to handle some cases (see
following commit).
While we're at it, move all state into a struct. This is only a single
bool, but we get the chance to add more if needed.
This fixes mpv falling asleep if decoding returns an error during
draining. If decoding fails when we already sent EOF, the state machine
stopped making progress. This left mpv just sitting around and doing
nothing.
A test case can be created with: echo $RANDOM >> image.png
This makes libavformat read a proper packet plus a packet of garbage.
libavcodec will decode a frame, and then return an error code. The
lavc_process() wrapper could not deal with this, because there was no
way to differentiate between "retry" and "send new packet". Normally, it
would send a new packet, so decoding would make progress anyway. If
there was "progress", we couldn't just retry, because it'd retry
forever.
This is made worse by the fact that it tries to decode at least two
frames before starting display, meaning it will "sit around and do
nothing" before the picture is displayed.
Change it so that on error return, "receiving" a frame is retried. This
will make it return the EOF, so everything works properly.
This is a high-risk change, because all these funny bullshit exceptions
for hardware decoding are in the way, and I didn't retest them. For
example, if hardware decoding is enabled, it keeps a list of packets,
that are fed into the decoder again if hardware decoding fails, and a
software fallback is performed. Another case of horrifying accidental
complexity.
Fixes: #6618
2019-10-24 16:40:46 +00:00
|
|
|
// Convenience wrapper for lavc based decoders. Treat lavc_state as private;
|
|
|
|
// init to all-0 on init and resets.
|
|
|
|
struct lavc_state {
|
|
|
|
bool eof_returned;
|
2020-08-27 16:40:12 +00:00
|
|
|
bool packets_sent;
|
ad_lavc, vd_lavc: return full error codes to shared decoder loop
ad_lavc and vd_lavc use the lavc_process() helper to translate the
FFmpeg push/pull API to the internal filter API (which completely
mismatch, even though I'm responsible for both, just fucking kill me).
This interface was "slightly" too tight. It returned only a bool
indicating "progress", which was not enough to handle some cases (see
following commit).
While we're at it, move all state into a struct. This is only a single
bool, but we get the chance to add more if needed.
This fixes mpv falling asleep if decoding returns an error during
draining. If decoding fails when we already sent EOF, the state machine
stopped making progress. This left mpv just sitting around and doing
nothing.
A test case can be created with: echo $RANDOM >> image.png
This makes libavformat read a proper packet plus a packet of garbage.
libavcodec will decode a frame, and then return an error code. The
lavc_process() wrapper could not deal with this, because there was no
way to differentiate between "retry" and "send new packet". Normally, it
would send a new packet, so decoding would make progress anyway. If
there was "progress", we couldn't just retry, because it'd retry
forever.
This is made worse by the fact that it tries to decode at least two
frames before starting display, meaning it will "sit around and do
nothing" before the picture is displayed.
Change it so that on error return, "receiving" a frame is retried. This
will make it return the EOF, so everything works properly.
This is a high-risk change, because all these funny bullshit exceptions
for hardware decoding are in the way, and I didn't retest them. For
example, if hardware decoding is enabled, it keeps a list of packets,
that are fed into the decoder again if hardware decoding fails, and a
software fallback is performed. Another case of horrifying accidental
complexity.
Fixes: #6618
2019-10-24 16:40:46 +00:00
|
|
|
};
|
|
|
|
void lavc_process(struct mp_filter *f, struct lavc_state *state,
|
|
|
|
int (*send)(struct mp_filter *f, struct demux_packet *pkt),
|
|
|
|
int (*receive)(struct mp_filter *f, struct mp_frame *res));
|
2018-01-29 05:18:33 +00:00
|
|
|
|
|
|
|
// ad_spdif.c
|
|
|
|
struct mp_decoder_list *select_spdif_codec(const char *codec, const char *pref);
|