mpv/filters/f_decoder_wrapper.h

126 lines
4.5 KiB
C
Raw Normal View History

/*
* 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 <stddef.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);
// 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);
// 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);
// 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);
struct mp_decoder_list *video_decoder_list(void);
struct mp_decoder_list *audio_decoder_list(void);
// 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,
VDCTRL_CHECK_FORCED_EOF,
};
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;
extern const struct mp_decoder_fns ad_lavc;
extern const struct mp_decoder_fns ad_spdif;
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 18:40:46 +02: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;
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 18:40:46 +02: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));
// ad_spdif.c
struct mp_decoder_list *select_spdif_codec(const char *codec, const char *pref);