diff options
Diffstat (limited to 'video/decode')
-rw-r--r-- | video/decode/dec_video.c | 526 | ||||
-rw-r--r-- | video/decode/dec_video.h | 101 | ||||
-rw-r--r-- | video/decode/vd.h | 56 | ||||
-rw-r--r-- | video/decode/vd_lavc.c | 218 |
4 files changed, 125 insertions, 776 deletions
diff --git a/video/decode/dec_video.c b/video/decode/dec_video.c deleted file mode 100644 index aefafbc00c..0000000000 --- a/video/decode/dec_video.c +++ /dev/null @@ -1,526 +0,0 @@ -/* - * 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/>. - */ - -#include <stdio.h> -#include <stdlib.h> -#include <stdbool.h> -#include <assert.h> - -#include <libavutil/rational.h> - -#include "config.h" -#include "options/options.h" -#include "common/msg.h" - -#include "osdep/timer.h" - -#include "stream/stream.h" -#include "demux/demux.h" -#include "demux/packet.h" - -#include "common/codecs.h" -#include "common/recorder.h" - -#include "video/out/vo.h" -#include "video/csputils.h" - -#include "demux/stheader.h" -#include "video/decode/vd.h" - -#include "video/decode/dec_video.h" - -extern const vd_functions_t mpcodecs_vd_ffmpeg; - -/* Please do not add any new decoders here. If you want to implement a new - * decoder, add it to libavcodec, except for wrappers around external - * libraries and decoders requiring binary support. */ - -const vd_functions_t * const mpcodecs_vd_drivers[] = { - &mpcodecs_vd_ffmpeg, - /* Please do not add any new decoders here. If you want to implement a new - * decoder, add it to libavcodec, except for wrappers around external - * libraries and decoders requiring binary support. */ - NULL -}; - -void video_reset(struct dec_video *d_video) -{ - video_vd_control(d_video, VDCTRL_RESET, NULL); - d_video->first_packet_pdts = MP_NOPTS_VALUE; - d_video->start_pts = MP_NOPTS_VALUE; - d_video->decoded_pts = MP_NOPTS_VALUE; - d_video->codec_pts = MP_NOPTS_VALUE; - d_video->codec_dts = MP_NOPTS_VALUE; - d_video->has_broken_decoded_pts = 0; - d_video->last_format = d_video->fixed_format = (struct mp_image_params){0}; - d_video->dropped_frames = 0; - d_video->may_decoder_framedrop = false; - d_video->current_state = DATA_AGAIN; - mp_image_unrefp(&d_video->current_mpi); - talloc_free(d_video->packet); - d_video->packet = NULL; - talloc_free(d_video->new_segment); - d_video->new_segment = NULL; - d_video->start = d_video->end = MP_NOPTS_VALUE; -} - -int video_vd_control(struct dec_video *d_video, int cmd, void *arg) -{ - const struct vd_functions *vd = d_video->vd_driver; - if (vd) - return vd->control(d_video, cmd, arg); - return CONTROL_UNKNOWN; -} - -void video_uninit(struct dec_video *d_video) -{ - if (!d_video) - return; - mp_image_unrefp(&d_video->current_mpi); - if (d_video->vd_driver) { - MP_VERBOSE(d_video, "Uninit video.\n"); - d_video->vd_driver->uninit(d_video); - } - talloc_free(d_video->packet); - talloc_free(d_video->new_segment); - talloc_free(d_video); -} - -static int init_video_codec(struct dec_video *d_video, const char *decoder) -{ - if (!d_video->vd_driver->init(d_video, decoder)) { - MP_VERBOSE(d_video, "Video decoder init failed.\n"); - return 0; - } - return 1; -} - -struct mp_decoder_list *video_decoder_list(void) -{ - struct mp_decoder_list *list = talloc_zero(NULL, struct mp_decoder_list); - for (int i = 0; mpcodecs_vd_drivers[i] != NULL; i++) - mpcodecs_vd_drivers[i]->add_decoders(list); - return list; -} - -static struct mp_decoder_list *mp_select_video_decoders(struct mp_log *log, - const char *codec, - char *selection) -{ - struct mp_decoder_list *list = video_decoder_list(); - struct mp_decoder_list *new = mp_select_decoders(log, list, codec, selection); - talloc_free(list); - return new; -} - -static const struct vd_functions *find_driver(const char *name) -{ - for (int i = 0; mpcodecs_vd_drivers[i] != NULL; i++) { - if (strcmp(mpcodecs_vd_drivers[i]->name, name) == 0) - return mpcodecs_vd_drivers[i]; - } - return NULL; -} - -bool video_init_best_codec(struct dec_video *d_video) -{ - struct MPOpts *opts = d_video->opts; - - assert(!d_video->vd_driver); - video_reset(d_video); - d_video->has_broken_packet_pts = -10; // needs 10 packets to reach decision - - struct mp_decoder_entry *decoder = NULL; - struct mp_decoder_list *list = mp_select_video_decoders(d_video->log, - d_video->codec->codec, - opts->video_decoders); - - mp_print_decoders(d_video->log, MSGL_V, "Codec list:", list); - - for (int n = 0; n < list->num_entries; n++) { - struct mp_decoder_entry *sel = &list->entries[n]; - const struct vd_functions *driver = find_driver(sel->family); - if (!driver) - continue; - MP_VERBOSE(d_video, "Opening video decoder %s\n", sel->decoder); - d_video->vd_driver = driver; - if (init_video_codec(d_video, sel->decoder)) { - decoder = sel; - break; - } - d_video->vd_driver = NULL; - MP_WARN(d_video, "Video decoder init failed for %s\n", sel->decoder); - } - - if (d_video->vd_driver) { - d_video->decoder_desc = - talloc_asprintf(d_video, "%s (%s)", decoder->decoder, decoder->desc); - MP_VERBOSE(d_video, "Selected video codec: %s\n", d_video->decoder_desc); - } else { - MP_ERR(d_video, "Failed to initialize a video decoder for codec '%s'.\n", - d_video->codec->codec); - } - - talloc_free(list); - return !!d_video->vd_driver; -} - -static bool is_valid_peak(float sig_peak) -{ - return !sig_peak || (sig_peak >= 1 && sig_peak <= 100); -} - -static void fix_image_params(struct dec_video *d_video, - struct mp_image_params *params) -{ - struct MPOpts *opts = d_video->opts; - struct mp_image_params p = *params; - struct mp_codec_params *c = d_video->codec; - - MP_VERBOSE(d_video, "Decoder format: %s\n", mp_image_params_to_str(params)); - d_video->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 && p.p_w > 0 && p.p_h > 0) { - MP_VERBOSE(d_video, "Using bitstream aspect ratio.\n"); - use_container = false; - } - - if (use_container && c->par_w > 0 && c->par_h) { - MP_VERBOSE(d_video, "Using container aspect ratio.\n"); - p.p_w = c->par_w; - p.p_h = c->par_h; - } - - if (opts->movie_aspect >= 0) { - MP_VERBOSE(d_video, "Forcing user-set aspect ratio.\n"); - if (opts->movie_aspect == 0) { - p.p_w = p.p_h = 1; - } else { - AVRational a = av_d2q(opts->movie_aspect, INT_MAX); - mp_image_params_set_dsize(&p, a.num, a.den); - } - } - - // Assume square pixels if no aspect ratio is set at all. - if (p.p_w <= 0 || p.p_h <= 0) - p.p_w = p.p_h = 1; - - p.rotate = d_video->codec->rotate; - p.stereo_in = d_video->codec->stereo_mode; - - if (opts->video_rotate < 0) { - p.rotate = 0; - } else { - p.rotate = (p.rotate + opts->video_rotate) % 360; - } - p.stereo_out = opts->video_stereo_mode; - - mp_colorspace_merge(&p.color, &c->color); - - // Sanitize the HDR peak. Sadly necessary - if (!is_valid_peak(p.color.sig_peak)) { - MP_WARN(d_video, "Invalid HDR peak in stream: %f\n", p.color.sig_peak); - p.color.sig_peak = 0.0; - } - - p.spherical = c->spherical; - if (p.spherical.type == MP_SPHERICAL_AUTO) - p.spherical.type = MP_SPHERICAL_NONE; - - // Guess missing colorspace fields from metadata. This guarantees all - // fields are at least set to legal values afterwards. - mp_image_params_guess_csp(&p); - - d_video->last_format = *params; - d_video->fixed_format = p; -} - -static bool send_packet(struct dec_video *d_video, struct demux_packet *packet) -{ - double pkt_pts = packet ? packet->pts : MP_NOPTS_VALUE; - double pkt_dts = packet ? packet->dts : MP_NOPTS_VALUE; - - if (pkt_pts == MP_NOPTS_VALUE) - d_video->has_broken_packet_pts = 1; - - bool dts_replaced = false; - if (packet && packet->dts == MP_NOPTS_VALUE && !d_video->codec->avi_dts) { - packet->dts = packet->pts; - dts_replaced = true; - } - - double pkt_pdts = pkt_pts == MP_NOPTS_VALUE ? pkt_dts : pkt_pts; - if (d_video->first_packet_pdts == MP_NOPTS_VALUE) - d_video->first_packet_pdts = pkt_pdts; - - MP_STATS(d_video, "start decode video"); - - bool res = d_video->vd_driver->send_packet(d_video, packet); - - MP_STATS(d_video, "end decode video"); - - // Stream recording can't deal with almost surely wrong fake DTS. - if (dts_replaced) - packet->dts = MP_NOPTS_VALUE; - - return res; -} - -static bool receive_frame(struct dec_video *d_video, struct mp_image **out_image) -{ - struct MPOpts *opts = d_video->opts; - struct mp_image *mpi = NULL; - - assert(!*out_image); - - MP_STATS(d_video, "start decode video"); - - bool progress = d_video->vd_driver->receive_frame(d_video, &mpi); - - MP_STATS(d_video, "end decode video"); - - // Error, EOF, discarded frame, dropped frame, or initial codec delay. - if (!mpi) - return progress; - - // Note: the PTS is reordered, but the DTS is not. Both should be monotonic. - double pts = mpi->pts; - double dts = mpi->dts; - - if (pts != MP_NOPTS_VALUE) { - if (pts < d_video->codec_pts) - d_video->num_codec_pts_problems++; - d_video->codec_pts = mpi->pts; - } - - if (dts != MP_NOPTS_VALUE) { - if (dts <= d_video->codec_dts) - d_video->num_codec_dts_problems++; - d_video->codec_dts = mpi->dts; - } - - if (d_video->has_broken_packet_pts < 0) - d_video->has_broken_packet_pts++; - if (d_video->num_codec_pts_problems) - d_video->has_broken_packet_pts = 1; - - // If PTS is unset, or non-monotonic, fall back to DTS. - if ((d_video->num_codec_pts_problems > d_video->num_codec_dts_problems || - pts == MP_NOPTS_VALUE) && dts != MP_NOPTS_VALUE) - pts = dts; - - if (!opts->correct_pts || pts == MP_NOPTS_VALUE) { - double fps = d_video->fps > 0 ? d_video->fps : 25; - - if (opts->correct_pts) { - if (d_video->has_broken_decoded_pts <= 1) { - MP_WARN(d_video, "No video PTS! Making something up. using " - "%f FPS.\n", fps); - if (d_video->has_broken_decoded_pts == 1) - MP_WARN(d_video, "Ignoring further missing PTS warnings.\n"); - d_video->has_broken_decoded_pts++; - } - } - - double frame_time = 1.0f / fps; - double base = d_video->first_packet_pdts; - pts = d_video->decoded_pts; - if (pts == MP_NOPTS_VALUE) { - pts = base == MP_NOPTS_VALUE ? 0 : base; - } else { - pts += frame_time; - } - } - - if (!mp_image_params_equal(&d_video->last_format, &mpi->params)) - fix_image_params(d_video, &mpi->params); - - mpi->params = d_video->fixed_format; - - mpi->pts = pts; - d_video->decoded_pts = pts; - - // Compensate for incorrectly using mpeg-style DTS for avi timestamps. - if (d_video->codec->avi_dts && opts->correct_pts && - mpi->pts != MP_NOPTS_VALUE && d_video->fps > 0) - { - int delay = -1; - video_vd_control(d_video, VDCTRL_GET_BFRAMES, &delay); - mpi->pts -= MPMAX(delay, 0) / d_video->fps; - } - - *out_image = mpi; - return true; -} - -void video_reset_params(struct dec_video *d_video) -{ - d_video->last_format = (struct mp_image_params){0}; -} - -void video_get_dec_params(struct dec_video *d_video, struct mp_image_params *p) -{ - *p = d_video->dec_format; -} - -void video_set_framedrop(struct dec_video *d_video, bool enabled) -{ - d_video->framedrop_enabled = enabled; -} - -// Frames before the start timestamp can be dropped. (Used for hr-seek.) -void video_set_start(struct dec_video *d_video, double start_pts) -{ - d_video->start_pts = start_pts; -} - -static bool is_new_segment(struct dec_video *d_video, struct demux_packet *p) -{ - return p->segmented && - (p->start != d_video->start || p->end != d_video->end || - p->codec != d_video->codec); -} - -static void feed_packet(struct dec_video *d_video) -{ - if (d_video->current_mpi || !d_video->vd_driver) - return; - - if (!d_video->packet && !d_video->new_segment && - demux_read_packet_async(d_video->header, &d_video->packet) == 0) - { - d_video->current_state = DATA_WAIT; - return; - } - - if (d_video->packet && is_new_segment(d_video, d_video->packet)) { - assert(!d_video->new_segment); - d_video->new_segment = d_video->packet; - d_video->packet = NULL; - } - - double start_pts = d_video->start_pts; - if (d_video->start != MP_NOPTS_VALUE && (start_pts == MP_NOPTS_VALUE || - d_video->start > start_pts)) - start_pts = d_video->start; - - int framedrop_type = d_video->framedrop_enabled ? 1 : 0; - if (start_pts != MP_NOPTS_VALUE && d_video->packet && - d_video->packet->pts < start_pts - .005 && - !d_video->has_broken_packet_pts) - { - framedrop_type = 2; - } - - d_video->vd_driver->control(d_video, VDCTRL_SET_FRAMEDROP, &framedrop_type); - - if (send_packet(d_video, d_video->packet)) { - if (d_video->recorder_sink) - mp_recorder_feed_packet(d_video->recorder_sink, d_video->packet); - - talloc_free(d_video->packet); - d_video->packet = NULL; - - d_video->may_decoder_framedrop = framedrop_type == 1; - } - - d_video->current_state = DATA_AGAIN; -} - -static void read_frame(struct dec_video *d_video) -{ - if (d_video->current_mpi || !d_video->vd_driver) - return; - - bool progress = receive_frame(d_video, &d_video->current_mpi); - - d_video->current_state = DATA_OK; - if (!progress) { - d_video->current_state = DATA_EOF; - } else if (!d_video->current_mpi) { - if (d_video->may_decoder_framedrop) - d_video->dropped_frames += 1; - d_video->current_state = DATA_AGAIN; - } - d_video->may_decoder_framedrop = false; - - bool segment_ended = d_video->current_state == DATA_EOF; - - if (d_video->current_mpi && d_video->current_mpi->pts != MP_NOPTS_VALUE) { - double vpts = d_video->current_mpi->pts; - segment_ended = d_video->end != MP_NOPTS_VALUE && vpts >= d_video->end; - if ((d_video->start != MP_NOPTS_VALUE && vpts < d_video->start) - || segment_ended) - { - talloc_free(d_video->current_mpi); - d_video->current_mpi = NULL; - } - } - - // If there's a new segment, start it as soon as we're drained/finished. - if (segment_ended && d_video->new_segment) { - struct demux_packet *new_segment = d_video->new_segment; - d_video->new_segment = NULL; - - if (d_video->codec == new_segment->codec) { - video_reset(d_video); - } else { - d_video->codec = new_segment->codec; - d_video->vd_driver->uninit(d_video); - d_video->vd_driver = NULL; - video_init_best_codec(d_video); - } - - d_video->start = new_segment->start; - d_video->end = new_segment->end; - - d_video->packet = new_segment; - d_video->current_state = DATA_AGAIN; - } -} - -void video_work(struct dec_video *d_video) -{ - read_frame(d_video); - if (!d_video->current_mpi) { - feed_packet(d_video); - if (d_video->current_state == DATA_WAIT) - return; - read_frame(d_video); // retry, to avoid redundant iterations - } -} - -// Fetch an image decoded with video_work(). Returns one of: -// DATA_OK: *out_mpi is set to a new image -// DATA_WAIT: waiting for demuxer; will receive a wakeup signal -// DATA_EOF: end of file, no more frames to be expected -// DATA_AGAIN: dropped frame or something similar -int video_get_frame(struct dec_video *d_video, struct mp_image **out_mpi) -{ - *out_mpi = NULL; - if (d_video->current_mpi) { - *out_mpi = d_video->current_mpi; - d_video->current_mpi = NULL; - return DATA_OK; - } - if (d_video->current_state == DATA_OK) - return DATA_AGAIN; - return d_video->current_state; -} diff --git a/video/decode/dec_video.h b/video/decode/dec_video.h deleted file mode 100644 index 426dd967db..0000000000 --- a/video/decode/dec_video.h +++ /dev/null @@ -1,101 +0,0 @@ -/* - * 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/>. - */ - -#ifndef MPLAYER_DEC_VIDEO_H -#define MPLAYER_DEC_VIDEO_H - -#include <stdbool.h> - -#include "demux/stheader.h" -#include "video/hwdec.h" -#include "video/mp_image.h" - -struct mp_decoder_list; -struct vo; - -struct dec_video { - struct mp_log *log; - struct mpv_global *global; - struct MPOpts *opts; - const struct vd_functions *vd_driver; - struct mp_hwdec_devices *hwdec_devs; // video output hwdec handles - struct sh_stream *header; - struct mp_codec_params *codec; - struct vo *vo; // required for direct rendering into video memory - - char *decoder_desc; - - float fps; // FPS from demuxer or from user override - - int dropped_frames; - - struct mp_recorder_sink *recorder_sink; - - // Internal (shared with vd_lavc.c). - - void *priv; // for free use by vd_driver - - // Strictly internal (dec_video.c). - - // Last PTS from decoder (set with each vd_driver->decode() call) - double codec_pts; - int num_codec_pts_problems; - - // Last packet DTS from decoder (passed through from source packets) - double codec_dts; - int num_codec_dts_problems; - - // PTS or DTS of packet first read - double first_packet_pdts; - - // There was at least one packet with non-sense timestamps. - int has_broken_packet_pts; // <0: uninitialized, 0: no problems, 1: broken - - int has_broken_decoded_pts; - - // Final PTS of previously decoded image - double decoded_pts; - - struct mp_image_params dec_format, last_format, fixed_format; - - double start_pts; - double start, end; - struct demux_packet *new_segment; - struct demux_packet *packet; - bool framedrop_enabled; - bool may_decoder_framedrop; - struct mp_image *current_mpi; - int current_state; -}; - -struct mp_decoder_list *video_decoder_list(void); - -bool video_init_best_codec(struct dec_video *d_video); -void video_uninit(struct dec_video *d_video); - -void video_work(struct dec_video *d_video); -int video_get_frame(struct dec_video *d_video, struct mp_image **out_mpi); - -void video_set_framedrop(struct dec_video *d_video, bool enabled); -void video_set_start(struct dec_video *d_video, double start_pts); - -int video_vd_control(struct dec_video *d_video, int cmd, void *arg); -void video_reset(struct dec_video *d_video); -void video_reset_params(struct dec_video *d_video); -void video_get_dec_params(struct dec_video *d_video, struct mp_image_params *p); - -#endif /* MPLAYER_DEC_VIDEO_H */ diff --git a/video/decode/vd.h b/video/decode/vd.h deleted file mode 100644 index 980de44bdc..0000000000 --- a/video/decode/vd.h +++ /dev/null @@ -1,56 +0,0 @@ -/* - * 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/>. - */ - -#ifndef MPLAYER_VD_H -#define MPLAYER_VD_H - -#include "video/mp_image.h" -#include "demux/stheader.h" -#include "dec_video.h" - -struct demux_packet; -struct mp_decoder_list; - -/* interface of video decoder drivers */ -typedef struct vd_functions -{ - const char *name; - void (*add_decoders)(struct mp_decoder_list *list); - int (*init)(struct dec_video *vd, const char *decoder); - void (*uninit)(struct dec_video *vd); - int (*control)(struct dec_video *vd, int cmd, void *arg); - // Return whether or not the packet has been consumed. - bool (*send_packet)(struct dec_video *vd, struct demux_packet *pkt); - // Return whether decoding is still going on (false if EOF was reached). - // Never returns false & *out_image set, but can return true with no image. - bool (*receive_frame)(struct dec_video *vd, struct mp_image **out_image); -} vd_functions_t; - -// NULL terminated array of all drivers -extern const vd_functions_t *const mpcodecs_vd_drivers[]; - -enum vd_ctrl { - VDCTRL_RESET = 1, // reset decode state after seeking - 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, -}; - -#endif /* MPLAYER_VD_H */ diff --git a/video/decode/vd_lavc.c b/video/decode/vd_lavc.c index 4660d813b5..1aaca6b335 100644 --- a/video/decode/vd_lavc.c +++ b/video/decode/vd_lavc.c @@ -29,7 +29,7 @@ #include <libavutil/pixdesc.h> #include "mpv_talloc.h" -#include "config.h" +#include "common/global.h" #include "common/msg.h" #include "options/options.h" #include "misc/bstr.h" @@ -38,12 +38,12 @@ #include "video/fmt-conversion.h" -#include "vd.h" +#include "filters/f_decoder_wrapper.h" +#include "filters/filter_internal.h" #include "video/hwdec.h" #include "video/img_format.h" #include "video/mp_image.h" #include "video/mp_image_pool.h" -#include "video/decode/dec_video.h" #include "demux/demux.h" #include "demux/stheader.h" #include "demux/packet.h" @@ -53,8 +53,8 @@ #include "options/m_option.h" -static void init_avctx(struct dec_video *vd); -static void uninit_avctx(struct dec_video *vd); +static void init_avctx(struct mp_filter *vd); +static void uninit_avctx(struct mp_filter *vd); static int get_buffer2_direct(AVCodecContext *avctx, AVFrame *pic, int flags); static enum AVPixelFormat get_format_hwdec(struct AVCodecContext *avctx, @@ -147,6 +147,7 @@ struct hwdec_info { typedef struct lavc_ctx { struct mp_log *log; struct MPOpts *opts; + struct mp_codec_params *codec; AVCodecContext *avctx; AVFrame *pic; bool use_hwdec; @@ -154,6 +155,7 @@ typedef struct lavc_ctx { AVRational codec_timebase; enum AVDiscard skip_frame; bool flushing; + bool eof_returned; const char *decoder; bool hwdec_requested; bool hwdec_failed; @@ -174,6 +176,7 @@ typedef struct lavc_ctx { int max_delay_queue; // From VO + struct vo *vo; struct mp_hwdec_devices *hwdec_devs; // Wrapped AVHWDeviceContext* used for decoding. @@ -191,6 +194,8 @@ typedef struct lavc_ctx { bool dr_failed; struct mp_image_pool *dr_pool; int dr_imgfmt, dr_w, dr_h, dr_stride_align; + + struct mp_decoder public; } vd_ffmpeg_ctx; // Things not included in this list will be tried last, in random order. @@ -355,9 +360,10 @@ static void add_all_hwdec_methods(struct hwdec_info **infos, int *num_infos) qsort(*infos, *num_infos, sizeof(struct hwdec_info), hwdec_compare); } -static bool hwdec_codec_allowed(struct dec_video *vd, const char *codec) +static bool hwdec_codec_allowed(struct mp_filter *vd, const char *codec) { - bstr s = bstr0(vd->opts->hwdec_codecs); + vd_ffmpeg_ctx *ctx = vd->priv; + bstr s = bstr0(ctx->opts->hwdec_codecs); while (s.len) { bstr item; bstr_split_tok(s, ",", &item, &s); @@ -367,10 +373,11 @@ static bool hwdec_codec_allowed(struct dec_video *vd, const char *codec) return false; } -static AVBufferRef *hwdec_create_dev(struct dec_video *vd, +static AVBufferRef *hwdec_create_dev(struct mp_filter *vd, struct hwdec_info *hwdec, bool autoprobe) { + vd_ffmpeg_ctx *ctx = vd->priv; assert(hwdec->lavc_device); if (hwdec->copying) { @@ -386,21 +393,21 @@ static AVBufferRef *hwdec_create_dev(struct dec_video *vd, av_hwdevice_ctx_create(&ref, hwdec->lavc_device, NULL, NULL, 0); return ref; } - } else if (vd->hwdec_devs) { - hwdec_devices_request_all(vd->hwdec_devs); - return hwdec_devices_get_lavc(vd->hwdec_devs, hwdec->lavc_device); + } else if (ctx->hwdec_devs) { + hwdec_devices_request_all(ctx->hwdec_devs); + return hwdec_devices_get_lavc(ctx->hwdec_devs, hwdec->lavc_device); } return NULL; } // Select if and which hwdec to use. Also makes sure to get the decode device. -static void select_and_set_hwdec(struct dec_video *vd) +static void select_and_set_hwdec(struct mp_filter *vd) { vd_ffmpeg_ctx *ctx = vd->priv; - const char *codec = vd->codec->codec; + const char *codec = ctx->codec->codec; - bstr opt = bstr0(vd->opts->hwdec_api); + bstr opt = bstr0(ctx->opts->hwdec_api); bool hwdec_requested = !bstr_equals0(opt, "no"); bool hwdec_auto_all = bstr_equals0(opt, "auto") || @@ -454,8 +461,8 @@ static void select_and_set_hwdec(struct dec_video *vd) } else if (!hwdec->copying) { // Most likely METHOD_INTERNAL, which often use delay-loaded // VO support as well. - if (vd->hwdec_devs) - hwdec_devices_request_all(vd->hwdec_devs); + if (ctx->hwdec_devs) + hwdec_devices_request_all(ctx->hwdec_devs); } ctx->use_hwdec = true; @@ -503,17 +510,7 @@ int hwdec_validate_opt(struct mp_log *log, const m_option_t *opt, return 0; } -static void uninit(struct dec_video *vd) -{ - vd_ffmpeg_ctx *ctx = vd->priv; - - uninit_avctx(vd); - - pthread_mutex_destroy(&ctx->dr_lock); - talloc_free(vd->priv); -} - -static void force_fallback(struct dec_video *vd) +static void force_fallback(struct mp_filter *vd) { vd_ffmpeg_ctx *ctx = vd->priv; @@ -523,7 +520,7 @@ static void force_fallback(struct dec_video *vd) init_avctx(vd); } -static void reinit(struct dec_video *vd) +static void reinit(struct mp_filter *vd) { vd_ffmpeg_ctx *ctx = vd->priv; @@ -537,33 +534,11 @@ static void reinit(struct dec_video *vd) force_fallback(vd); } -static int init(struct dec_video *vd, const char *decoder) -{ - vd_ffmpeg_ctx *ctx; - ctx = vd->priv = talloc_zero(NULL, vd_ffmpeg_ctx); - ctx->log = vd->log; - ctx->opts = vd->opts; - ctx->decoder = talloc_strdup(ctx, decoder); - ctx->hwdec_devs = vd->hwdec_devs; - ctx->hwdec_swpool = mp_image_pool_new(ctx); - ctx->dr_pool = mp_image_pool_new(ctx); - - pthread_mutex_init(&ctx->dr_lock, NULL); - - reinit(vd); - - if (!ctx->avctx) { - uninit(vd); - return 0; - } - return 1; -} - -static void init_avctx(struct dec_video *vd) +static void init_avctx(struct mp_filter *vd) { vd_ffmpeg_ctx *ctx = vd->priv; - struct vd_lavc_params *lavc_param = vd->opts->vd_lavc_params; - struct mp_codec_params *c = vd->codec; + struct vd_lavc_params *lavc_param = ctx->opts->vd_lavc_params; + struct mp_codec_params *c = ctx->codec; assert(!ctx->avctx); @@ -580,7 +555,7 @@ static void init_avctx(struct dec_video *vd) const AVCodecDescriptor *desc = avcodec_descriptor_get(lavc_codec->id); ctx->intra_only = desc && (desc->props & AV_CODEC_PROP_INTRA_ONLY); - ctx->codec_timebase = mp_get_codec_timebase(vd->codec); + ctx->codec_timebase = mp_get_codec_timebase(ctx->codec); // This decoder does not read pkt_timebase correctly yet. if (strstr(lavc_codec->name, "_mmal")) @@ -632,7 +607,7 @@ static void init_avctx(struct dec_video *vd) mp_set_avcodec_threads(vd->log, avctx, lavc_param->threads); } - if (!ctx->use_hwdec && vd->vo && lavc_param->dr) { + if (!ctx->use_hwdec && ctx->vo && lavc_param->dr) { avctx->opaque = vd; avctx->get_buffer2 = get_buffer2_direct; avctx->thread_safe_callbacks = 1; @@ -685,7 +660,7 @@ error: uninit_avctx(vd); } -static void reset_avctx(struct dec_video *vd) +static void reset_avctx(struct mp_filter *vd) { vd_ffmpeg_ctx *ctx = vd->priv; @@ -695,7 +670,7 @@ static void reset_avctx(struct dec_video *vd) ctx->hwdec_request_reinit = false; } -static void flush_all(struct dec_video *vd) +static void flush_all(struct mp_filter *vd) { vd_ffmpeg_ctx *ctx = vd->priv; @@ -714,7 +689,7 @@ static void flush_all(struct dec_video *vd) reset_avctx(vd); } -static void uninit_avctx(struct dec_video *vd) +static void uninit_avctx(struct mp_filter *vd) { vd_ffmpeg_ctx *ctx = vd->priv; @@ -734,7 +709,7 @@ static void uninit_avctx(struct dec_video *vd) ctx->use_hwdec = false; } -static int init_generic_hwaccel(struct dec_video *vd, enum AVPixelFormat hw_fmt) +static int init_generic_hwaccel(struct mp_filter *vd, enum AVPixelFormat hw_fmt) { struct lavc_ctx *ctx = vd->priv; AVBufferRef *new_frames_ctx = NULL; @@ -756,8 +731,8 @@ static int init_generic_hwaccel(struct dec_video *vd, enum AVPixelFormat hw_fmt) AVHWFramesContext *new_fctx = (void *)new_frames_ctx->data; - if (vd->opts->hwdec_image_format) - new_fctx->sw_format = imgfmt2pixfmt(vd->opts->hwdec_image_format); + if (ctx->opts->hwdec_image_format) + new_fctx->sw_format = imgfmt2pixfmt(ctx->opts->hwdec_image_format); // 1 surface is already included by libavcodec. The field is 0 if the // hwaccel supports dynamic surface allocation. @@ -808,7 +783,7 @@ error: static enum AVPixelFormat get_format_hwdec(struct AVCodecContext *avctx, const enum AVPixelFormat *fmt) { - struct dec_video *vd = avctx->opaque; + struct mp_filter *vd = avctx->opaque; vd_ffmpeg_ctx *ctx = vd->priv; MP_VERBOSE(vd, "Pixel formats supported by decoder:"); @@ -853,7 +828,7 @@ static enum AVPixelFormat get_format_hwdec(struct AVCodecContext *avctx, static int get_buffer2_direct(AVCodecContext *avctx, AVFrame *pic, int flags) { - struct dec_video *vd = avctx->opaque; + struct mp_filter *vd = avctx->opaque; vd_ffmpeg_ctx *p = vd->priv; pthread_mutex_lock(&p->dr_lock); @@ -893,7 +868,7 @@ static int get_buffer2_direct(AVCodecContext *avctx, AVFrame *pic, int flags) struct mp_image *img = mp_image_pool_get_no_alloc(p->dr_pool, imgfmt, w, h); if (!img) { MP_DBG(p, "Allocating new DR image...\n"); - img = vo_get_image(vd->vo, imgfmt, w, h, stride_align); + img = vo_get_image(p->vo, imgfmt, w, h, stride_align); if (!img) { MP_DBG(p, "...failed..\n"); goto fallback; @@ -932,7 +907,7 @@ fallback: return avcodec_default_get_buffer2(avctx, pic, flags); } -static bool prepare_decoding(struct dec_video *vd) +static bool prepare_decoding(struct mp_filter *vd) { vd_ffmpeg_ctx *ctx = vd->priv; AVCodecContext *avctx = ctx->avctx; @@ -959,7 +934,7 @@ static bool prepare_decoding(struct dec_video *vd) return true; } -static void handle_err(struct dec_video *vd) +static void handle_err(struct mp_filter *vd) { vd_ffmpeg_ctx *ctx = vd->priv; struct vd_lavc_params *opts = ctx->opts->vd_lavc_params; @@ -973,7 +948,7 @@ static void handle_err(struct dec_video *vd) } |