summaryrefslogtreecommitdiffstats
path: root/video
diff options
context:
space:
mode:
Diffstat (limited to 'video')
-rw-r--r--video/decode/dec_video.c526
-rw-r--r--video/decode/dec_video.h101
-rw-r--r--video/decode/vd.h56
-rw-r--r--video/decode/vd_lavc.c218
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)