mirror of https://github.com/mpv-player/mpv
video: different way to enable hardware decoding, add software fallback
Deprecate the hardware specific video codec entries (like ffh264vdpau). Replace them with the --hwdec switch, which requests that a specific hardware decoding API should be used. The codecs.conf entries will be removed at a later time, but for now they are useful for testing and compatibility. Instead of --vc=ffh264vdpau, --hwdec=vdpau should be used. Add a fallback if hardware decoding fails. Most hardware decoders (including vdpau) support only a subset of h264, and having such a fallback is supposed to enable a better user experience.
This commit is contained in:
parent
dab286a159
commit
58d196c07e
|
@ -117,6 +117,7 @@ Command line switches
|
|||
-spugauss --sub-gauss
|
||||
-vobsub --sub (pass the .idx file)
|
||||
-ass-bottom-margin --vf=sub=bottom:top
|
||||
-vc ffh264vdpau (etc.) --hwdec=vdpau
|
||||
=================================== ===================================
|
||||
|
||||
input.conf and slave commands
|
||||
|
|
|
@ -779,6 +779,18 @@
|
|||
negative of the image with this option. Not supported by all video output
|
||||
drivers.
|
||||
|
||||
--hwdec=<api>
|
||||
Specify the hardware video decoding API that should be used if possible.
|
||||
Whether hardware decoding is actually done depends on the video codec. If
|
||||
hardware decoding is not possible, mpv will fall back to software decoding.
|
||||
|
||||
<api> can be one of the following:
|
||||
|
||||
:no: always use software decoding (default)
|
||||
:vdpau: works with nvidia drivers only, requires ``--vo=vdpau``
|
||||
:vda: OSX
|
||||
:crystalhd: Broadcom Crystal HD
|
||||
|
||||
--identify
|
||||
Deprecated. Use ``TOOLS/mpv_identify.sh``.
|
||||
|
||||
|
|
|
@ -467,6 +467,12 @@ const m_option_t common_opts[] = {
|
|||
{"ac", &audio_codec_list, CONF_TYPE_STRING_LIST, 0, 0, 0, NULL},
|
||||
{"vc", &video_codec_list, CONF_TYPE_STRING_LIST, 0, 0, 0, NULL},
|
||||
|
||||
OPT_CHOICE("hwdec", hwdec_api, 0,
|
||||
({"no", 0},
|
||||
{"vdpau", 1},
|
||||
{"vda", 2},
|
||||
{"crystalhd", 3})),
|
||||
|
||||
// postprocessing:
|
||||
{"pp", &divx_quality, CONF_TYPE_INT, 0, 0, 0, NULL},
|
||||
#ifdef CONFIG_LIBPOSTPROC
|
||||
|
|
|
@ -126,6 +126,9 @@ typedef struct MPOpts {
|
|||
char *ass_styles_file;
|
||||
int ass_style_override;
|
||||
int ass_hinting;
|
||||
|
||||
int hwdec_api;
|
||||
|
||||
struct lavc_param {
|
||||
int workaround_bugs;
|
||||
int error_resilience;
|
||||
|
|
|
@ -180,6 +180,7 @@ videocodec ffmpeg12
|
|||
driver ffmpeg
|
||||
dll "mpegvideo"
|
||||
|
||||
; deprecated in favor of --hwdec=vdpau
|
||||
videocodec ffmpeg12vdpau
|
||||
info "FFmpeg MPEG-1/2 (VDPAU)"
|
||||
status working
|
||||
|
@ -210,6 +211,7 @@ videocodec ffmpeg12vdpau
|
|||
driver ffmpeg
|
||||
dll "mpegvideo_vdpau"
|
||||
|
||||
; deprecated in favor of --hwdec=crystalhd
|
||||
videocodec ffmpeg2crystalhd
|
||||
info "FFmpeg MPEG-2 (CrystalHD)"
|
||||
status working
|
||||
|
@ -576,6 +578,7 @@ videocodec ffdivx
|
|||
driver ffmpeg
|
||||
dll msmpeg4
|
||||
|
||||
; deprecated in favor of --hwdec=crystalhd
|
||||
videocodec ffdivxcrystalhd
|
||||
info "FFmpeg DivX ;-) (MSMPEG-4 v3) (CrystalHD)"
|
||||
status buggy
|
||||
|
@ -638,6 +641,7 @@ videocodec ffwmvp
|
|||
driver ffmpeg
|
||||
dll wmv3
|
||||
|
||||
; deprecated in favor of --hwdec=vdpau
|
||||
videocodec ffwmv3vdpau
|
||||
info "FFmpeg WMV3/WMV9 (VDPAU)"
|
||||
status buggy
|
||||
|
@ -645,6 +649,7 @@ videocodec ffwmv3vdpau
|
|||
driver ffmpeg
|
||||
dll wmv3_vdpau
|
||||
|
||||
; deprecated in favor of --hwdec=crystalhd
|
||||
videocodec ffwmv3crystalhd
|
||||
info "FFmpeg WMV3/WMV9 (CrystalHD)"
|
||||
status buggy
|
||||
|
@ -660,6 +665,7 @@ videocodec ffvc1
|
|||
driver ffmpeg
|
||||
dll vc1
|
||||
|
||||
; deprecated in favor of --hwdec=vdpau
|
||||
videocodec ffvc1vdpau
|
||||
info "FFmpeg WVC1 (VDPAU)"
|
||||
status buggy
|
||||
|
@ -668,6 +674,7 @@ videocodec ffvc1vdpau
|
|||
driver ffmpeg
|
||||
dll vc1_vdpau
|
||||
|
||||
; deprecated in favor of --hwdec=crystalhd
|
||||
videocodec ffvc1crystalhd
|
||||
info "FFmpeg WVC1 (CrystalHD)"
|
||||
status buggy
|
||||
|
@ -691,6 +698,7 @@ videocodec ffh264
|
|||
driver ffmpeg
|
||||
dll h264
|
||||
|
||||
; deprecated in favor of --hwdec=vdpau
|
||||
videocodec ffh264vdpau
|
||||
info "FFmpeg H.264 (VDPAU)"
|
||||
status working
|
||||
|
@ -704,6 +712,7 @@ videocodec ffh264vdpau
|
|||
driver ffmpeg
|
||||
dll h264_vdpau
|
||||
|
||||
; deprecated in favor of --hwdec=crystalhd
|
||||
videocodec ffh264crystalhd
|
||||
info "FFmpeg H.264 (CrystalHD)"
|
||||
status working
|
||||
|
@ -718,6 +727,7 @@ videocodec ffh264crystalhd
|
|||
driver ffmpeg
|
||||
dll h264_crystalhd
|
||||
|
||||
; deprecated in favor of --hwdec=vda
|
||||
videocodec ffh264vda
|
||||
info "FFmpeg H.264 (VDA)"
|
||||
status working
|
||||
|
@ -772,6 +782,7 @@ videocodec ffodivx
|
|||
driver ffmpeg
|
||||
dll mpeg4 ;opendivx
|
||||
|
||||
; deprecated in favor of --hwdec=vdpau
|
||||
videocodec ffodivxvdpau
|
||||
info "FFmpeg MPEG-4,DIVX-4/5 (VDPAU)"
|
||||
status working
|
||||
|
@ -804,6 +815,7 @@ videocodec ffodivxvdpau
|
|||
driver ffmpeg
|
||||
dll mpeg4_vdpau
|
||||
|
||||
; deprecated in favor of --hwdec=crystalhd
|
||||
videocodec ffodivxcrystalhd
|
||||
info "FFmpeg MPEG-4,DIVX-4/5 (CrystalHD)"
|
||||
status working
|
||||
|
|
|
@ -87,8 +87,8 @@
|
|||
# but only take effect when the profile is active.
|
||||
|
||||
#[vo.vdpau]
|
||||
# Use hardware decoding (this will break playback of some h264 files)
|
||||
#vc=ffmpeg12vdpau,ffwmv3vdpau,ffvc1vdpau,ffh264vdpau,ffodivxvdpau,
|
||||
# Use hardware decoding (this might break playback of some h264 files)
|
||||
#hwdec=vdpau
|
||||
# Most video filters do not work with vdpau.
|
||||
#vf-clr=yes
|
||||
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
#include <libavutil/common.h>
|
||||
#include <libavutil/opt.h>
|
||||
#include <libavutil/intreadwrite.h>
|
||||
#include <libavutil/pixdesc.h>
|
||||
|
||||
#include "compat/libav.h"
|
||||
|
||||
|
@ -69,6 +70,7 @@ typedef struct {
|
|||
AVFrame *pic;
|
||||
struct mp_image export_mpi;
|
||||
struct mp_image hwdec_mpi[MAX_NUM_MPI];
|
||||
struct hwdec *hwdec;
|
||||
enum PixelFormat pix_fmt;
|
||||
int do_dr1;
|
||||
int vo_initialized;
|
||||
|
@ -78,10 +80,14 @@ typedef struct {
|
|||
double inv_qp_sum;
|
||||
AVRational last_sample_aspect_ratio;
|
||||
enum AVDiscard skip_frame;
|
||||
int rawvideo_fmt;
|
||||
AVCodec *software_fallback;
|
||||
} vd_ffmpeg_ctx;
|
||||
|
||||
#include "core/m_option.h"
|
||||
|
||||
static int init_avctx(sh_video_t *sh, AVCodec *lavc_codec, struct hwdec *hwdec);
|
||||
static void uninit_avctx(sh_video_t *sh);
|
||||
static int get_buffer_hwdec(AVCodecContext *avctx, AVFrame *pic);
|
||||
static void release_buffer_hwdec(AVCodecContext *avctx, AVFrame *pic);
|
||||
static void draw_slice_hwdec(struct AVCodecContext *s, const AVFrame *src,
|
||||
|
@ -113,6 +119,50 @@ const m_option_t lavc_decode_opts_conf[] = {
|
|||
{NULL, NULL, 0, 0, 0, 0, NULL}
|
||||
};
|
||||
|
||||
// keep in sync with --hwdec option
|
||||
enum hwdec_type {
|
||||
HWDEC_NONE = 0,
|
||||
HWDEC_VDPAU = 1,
|
||||
HWDEC_VDA = 2,
|
||||
HWDEC_CRYSTALHD = 3,
|
||||
};
|
||||
|
||||
struct hwdec {
|
||||
enum hwdec_type api;
|
||||
char *codec, *hw_codec;
|
||||
};
|
||||
|
||||
static const struct hwdec hwdec[] = {
|
||||
{HWDEC_VDPAU, "h264", "h264_vdpau"},
|
||||
{HWDEC_VDPAU, "wmv3", "wmv3_vdpau"},
|
||||
{HWDEC_VDPAU, "vc1", "vc1_vdpau"},
|
||||
{HWDEC_VDPAU, "mpegvideo", "mpegvideo_vdpau"},
|
||||
{HWDEC_VDPAU, "mpeg1video", "mpeg1video_vdpau"},
|
||||
{HWDEC_VDPAU, "mpeg2video", "mpegvideo_vdpau"},
|
||||
{HWDEC_VDPAU, "mpeg2", "mpeg2_vdpau"},
|
||||
{HWDEC_VDPAU, "mpeg4", "mpeg4_vdpau"},
|
||||
|
||||
{HWDEC_VDA, "h264", "h264_vda"},
|
||||
|
||||
{HWDEC_CRYSTALHD, "mpeg2", "mpeg2_crystalhd"},
|
||||
{HWDEC_CRYSTALHD, "msmpeg4", "msmpeg4_crystalhd"},
|
||||
{HWDEC_CRYSTALHD, "wmv3", "wmv3_crystalhd"},
|
||||
{HWDEC_CRYSTALHD, "vc1", "vc1_crystalhd"},
|
||||
{HWDEC_CRYSTALHD, "h264", "h264_crystalhd"},
|
||||
{HWDEC_CRYSTALHD, "mpeg4", "mpeg4_crystalhd"},
|
||||
|
||||
{0}
|
||||
};
|
||||
|
||||
static struct hwdec *find_hwcodec(enum hwdec_type api, const char *codec)
|
||||
{
|
||||
for (int n = 0; hwdec[n].api; n++) {
|
||||
if (hwdec[n].api == api && strcmp(hwdec[n].codec, codec) == 0)
|
||||
return (struct hwdec *)&hwdec[n];
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// print debugging stats into a file
|
||||
static void print_vstats(sh_video_t *sh, int len)
|
||||
{
|
||||
|
@ -209,13 +259,11 @@ static enum AVDiscard str2AVDiscard(char *str)
|
|||
|
||||
static int init(sh_video_t *sh)
|
||||
{
|
||||
struct lavc_param *lavc_param = &sh->opts->lavc_param;
|
||||
AVCodecContext *avctx;
|
||||
vd_ffmpeg_ctx *ctx;
|
||||
AVCodec *lavc_codec = NULL;
|
||||
enum PixelFormat rawfmt = PIX_FMT_NONE;
|
||||
|
||||
ctx = sh->context = talloc_zero(NULL, vd_ffmpeg_ctx);
|
||||
ctx->rawvideo_fmt = PIX_FMT_NONE;
|
||||
|
||||
if (sh->codec->dll) {
|
||||
lavc_codec = avcodec_find_decoder_by_name(sh->codec->dll);
|
||||
|
@ -235,8 +283,8 @@ static int init(sh_video_t *sh)
|
|||
return 0;
|
||||
}
|
||||
} else if (!IMGFMT_IS_HWACCEL(sh->format)) {
|
||||
rawfmt = imgfmt2pixfmt(sh->format);
|
||||
if (rawfmt != PIX_FMT_NONE)
|
||||
ctx->rawvideo_fmt = imgfmt2pixfmt(sh->format);
|
||||
if (ctx->rawvideo_fmt != PIX_FMT_NONE)
|
||||
lavc_codec = avcodec_find_decoder_by_name("rawvideo");
|
||||
}
|
||||
if (!lavc_codec) {
|
||||
|
@ -244,30 +292,64 @@ static int init(sh_video_t *sh)
|
|||
return 0;
|
||||
}
|
||||
|
||||
struct hwdec *hwdec = find_hwcodec(sh->opts->hwdec_api, lavc_codec->name);
|
||||
if (hwdec) {
|
||||
AVCodec *lavc_hwcodec = avcodec_find_decoder_by_name(hwdec->hw_codec);
|
||||
if (lavc_hwcodec) {
|
||||
ctx->software_fallback = lavc_codec;
|
||||
lavc_codec = lavc_hwcodec;
|
||||
} else {
|
||||
hwdec = NULL;
|
||||
mp_tmsg(MSGT_DECVIDEO, MSGL_WARN, "Using software decoding.\n");
|
||||
}
|
||||
}
|
||||
|
||||
if (!init_avctx(sh, lavc_codec, hwdec)) {
|
||||
mp_tmsg(MSGT_DECVIDEO, MSGL_ERR, "Error initializing hardware "
|
||||
"decoding, falling back to software decoding.\n");
|
||||
lavc_codec = ctx->software_fallback;
|
||||
ctx->software_fallback = NULL;
|
||||
if (!init_avctx(sh, lavc_codec, NULL)) {
|
||||
uninit(sh);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int init_avctx(sh_video_t *sh, AVCodec *lavc_codec, struct hwdec *hwdec)
|
||||
{
|
||||
vd_ffmpeg_ctx *ctx = sh->context;
|
||||
struct lavc_param *lavc_param = &sh->opts->lavc_param;
|
||||
|
||||
sh->codecname = lavc_codec->long_name;
|
||||
if (!sh->codecname)
|
||||
sh->codecname = lavc_codec->name;
|
||||
|
||||
ctx->do_dr1 = 0;
|
||||
ctx->pix_fmt = PIX_FMT_NONE;
|
||||
ctx->vo_initialized = 0;
|
||||
ctx->hwdec = hwdec;
|
||||
ctx->pic = avcodec_alloc_frame();
|
||||
ctx->avctx = avcodec_alloc_context3(lavc_codec);
|
||||
avctx = ctx->avctx;
|
||||
AVCodecContext *avctx = ctx->avctx;
|
||||
avctx->opaque = sh;
|
||||
avctx->codec_type = AVMEDIA_TYPE_VIDEO;
|
||||
avctx->codec_id = lavc_codec->id;
|
||||
|
||||
avctx->thread_count = lavc_param->threads;
|
||||
|
||||
if (lavc_codec->capabilities & CODEC_CAP_HWACCEL_VDPAU) {
|
||||
if (ctx->hwdec && ctx->hwdec->api == HWDEC_VDPAU) {
|
||||
ctx->do_dr1 = true;
|
||||
avctx->thread_count = 1;
|
||||
avctx->get_format = get_format_hwdec;
|
||||
avctx->get_buffer = get_buffer_hwdec;
|
||||
avctx->release_buffer = release_buffer_hwdec;
|
||||
if (ctx->hwdec->api == HWDEC_VDPAU) {
|
||||
avctx->draw_horiz_band = draw_slice_hwdec;
|
||||
if (lavc_codec->capabilities & CODEC_CAP_HWACCEL_VDPAU)
|
||||
mp_msg(MSGT_DECVIDEO, MSGL_V, "[VD_FFMPEG] VDPAU hardware "
|
||||
"decoding.\n");
|
||||
avctx->slice_flags = SLICE_FLAG_CODED_ORDER | SLICE_FLAG_ALLOW_FIELD;
|
||||
avctx->slice_flags =
|
||||
SLICE_FLAG_CODED_ORDER | SLICE_FLAG_ALLOW_FIELD;
|
||||
}
|
||||
}
|
||||
|
||||
if (avctx->thread_count == 0) {
|
||||
|
@ -289,10 +371,10 @@ static int init(sh_video_t *sh)
|
|||
if (lavc_param->gray)
|
||||
avctx->flags |= CODEC_FLAG_GRAY;
|
||||
avctx->flags2 |= lavc_param->fast;
|
||||
if (rawfmt == PIX_FMT_NONE) {
|
||||
if (ctx->rawvideo_fmt == PIX_FMT_NONE) {
|
||||
avctx->codec_tag = sh->format;
|
||||
} else {
|
||||
avctx->pix_fmt = rawfmt;
|
||||
avctx->pix_fmt = ctx->rawvideo_fmt;
|
||||
}
|
||||
if (sh->gsh->lavf_codec_tag)
|
||||
avctx->codec_tag = sh->gsh->lavf_codec_tag;
|
||||
|
@ -387,27 +469,18 @@ static int init(sh_video_t *sh)
|
|||
/* open it */
|
||||
if (avcodec_open2(avctx, lavc_codec, NULL) < 0) {
|
||||
mp_tmsg(MSGT_DECVIDEO, MSGL_ERR, "Could not open codec.\n");
|
||||
uninit(sh);
|
||||
uninit_avctx(sh);
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void uninit(sh_video_t *sh)
|
||||
static void uninit_avctx(sh_video_t *sh)
|
||||
{
|
||||
vd_ffmpeg_ctx *ctx = sh->context;
|
||||
AVCodecContext *avctx = ctx->avctx;
|
||||
|
||||
sh->codecname = NULL;
|
||||
if (sh->opts->lavc_param.vstats && avctx->coded_frame) {
|
||||
for (int i = 1; i < 32; i++)
|
||||
mp_msg(MSGT_DECVIDEO, MSGL_INFO,
|
||||
"QP: %d, count: %d\n", i, ctx->qp_stat[i]);
|
||||
mp_tmsg(MSGT_DECVIDEO, MSGL_INFO, "[VD_FFMPEG] Arithmetic mean of QP: "
|
||||
"%2.4f, Harmonic mean of QP: %2.4f\n",
|
||||
ctx->qp_sum / avctx->coded_frame->coded_picture_number,
|
||||
1.0 / (ctx->inv_qp_sum / avctx->coded_frame->coded_picture_number));
|
||||
}
|
||||
|
||||
if (avctx) {
|
||||
if (avctx->codec && avcodec_close(avctx) < 0)
|
||||
|
@ -419,19 +492,34 @@ static void uninit(sh_video_t *sh)
|
|||
|
||||
av_freep(&avctx);
|
||||
avcodec_free_frame(&ctx->pic);
|
||||
talloc_free(ctx);
|
||||
}
|
||||
|
||||
static int init_vo(sh_video_t *sh, enum PixelFormat pix_fmt)
|
||||
static void uninit(sh_video_t *sh)
|
||||
{
|
||||
vd_ffmpeg_ctx *ctx = sh->context;
|
||||
AVCodecContext *avctx = ctx->avctx;
|
||||
float aspect = av_q2d(avctx->sample_aspect_ratio) *
|
||||
avctx->width / avctx->height;
|
||||
int width, height;
|
||||
|
||||
width = avctx->width;
|
||||
height = avctx->height;
|
||||
if (avctx && sh->opts->lavc_param.vstats && avctx->coded_frame) {
|
||||
for (int i = 1; i < 32; i++)
|
||||
mp_msg(MSGT_DECVIDEO, MSGL_INFO,
|
||||
"QP: %d, count: %d\n", i, ctx->qp_stat[i]);
|
||||
mp_tmsg(MSGT_DECVIDEO, MSGL_INFO, "[VD_FFMPEG] Arithmetic mean of QP: "
|
||||
"%2.4f, Harmonic mean of QP: %2.4f\n",
|
||||
ctx->qp_sum / avctx->coded_frame->coded_picture_number,
|
||||
1.0 / (ctx->inv_qp_sum / avctx->coded_frame->coded_picture_number));
|
||||
}
|
||||
|
||||
uninit_avctx(sh);
|
||||
talloc_free(ctx);
|
||||
}
|
||||
|
||||
static int init_vo(sh_video_t *sh)
|
||||
{
|
||||
vd_ffmpeg_ctx *ctx = sh->context;
|
||||
AVCodecContext *avctx = ctx->avctx;
|
||||
int width = avctx->width;
|
||||
int height = avctx->height;
|
||||
float aspect = av_q2d(avctx->sample_aspect_ratio) * width / height;
|
||||
|
||||
/* Reconfiguring filter/VO chain may invalidate direct rendering buffers
|
||||
* we have allocated for libavcodec (including the VDPAU HW decoding
|
||||
|
@ -440,7 +528,8 @@ static int init_vo(sh_video_t *sh, enum PixelFormat pix_fmt)
|
|||
*/
|
||||
if (av_cmp_q(avctx->sample_aspect_ratio, ctx->last_sample_aspect_ratio) ||
|
||||
width != sh->disp_w || height != sh->disp_h ||
|
||||
pix_fmt != ctx->pix_fmt || !ctx->vo_initialized) {
|
||||
avctx->pix_fmt != ctx->pix_fmt || !ctx->vo_initialized)
|
||||
{
|
||||
ctx->vo_initialized = 0;
|
||||
mp_msg(MSGT_DECVIDEO, MSGL_V, "[ffmpeg] aspect_ratio: %f\n", aspect);
|
||||
|
||||
|
@ -454,14 +543,16 @@ static int init_vo(sh_video_t *sh, enum PixelFormat pix_fmt)
|
|||
ctx->last_sample_aspect_ratio = avctx->sample_aspect_ratio;
|
||||
sh->disp_w = width;
|
||||
sh->disp_h = height;
|
||||
ctx->pix_fmt = pix_fmt;
|
||||
ctx->best_csp = pixfmt2imgfmt(pix_fmt);
|
||||
|
||||
ctx->pix_fmt = avctx->pix_fmt;
|
||||
ctx->best_csp = pixfmt2imgfmt(avctx->pix_fmt);
|
||||
|
||||
sh->colorspace = avcol_spc_to_mp_csp(avctx->colorspace);
|
||||
sh->color_range = avcol_range_to_mp_csp_levels(avctx->color_range);
|
||||
|
||||
if (!mpcodecs_config_vo(sh, sh->disp_w, sh->disp_h, ctx->best_csp))
|
||||
return -1;
|
||||
|
||||
ctx->vo_initialized = 1;
|
||||
}
|
||||
return 0;
|
||||
|
@ -471,19 +562,24 @@ static enum PixelFormat get_format_hwdec(struct AVCodecContext *avctx,
|
|||
const enum PixelFormat *fmt)
|
||||
{
|
||||
sh_video_t *sh = avctx->opaque;
|
||||
int i;
|
||||
vd_ffmpeg_ctx *ctx = sh->context;
|
||||
|
||||
for (i = 0; fmt[i] != PIX_FMT_NONE; i++) {
|
||||
mp_msg(MSGT_DECVIDEO, MSGL_V, "Pixel formats supported by decoder:");
|
||||
for (int i = 0; fmt[i] != PIX_FMT_NONE; i++)
|
||||
mp_msg(MSGT_DECVIDEO, MSGL_V, " %s", av_get_pix_fmt_name(fmt[i]));
|
||||
mp_msg(MSGT_DECVIDEO, MSGL_V, "\n");
|
||||
|
||||
assert(ctx->hwdec);
|
||||
|
||||
for (int i = 0; fmt[i] != PIX_FMT_NONE; i++) {
|
||||
int imgfmt = pixfmt2imgfmt(fmt[i]);
|
||||
if (!IMGFMT_IS_HWACCEL(imgfmt))
|
||||
continue;
|
||||
mp_msg(MSGT_DECVIDEO, MSGL_V, "[VD_FFMPEG] Trying pixfmt=%d.\n", i);
|
||||
if (init_vo(sh, fmt[i]) >= 0)
|
||||
break;
|
||||
}
|
||||
if (ctx->hwdec->api == HWDEC_VDPAU && IMGFMT_IS_VDPAU(imgfmt))
|
||||
return fmt[i];
|
||||
}
|
||||
|
||||
return PIX_FMT_NONE;
|
||||
}
|
||||
|
||||
static void draw_slice_hwdec(struct AVCodecContext *s,
|
||||
const AVFrame *src, int offset[4],
|
||||
int y, int type, int height)
|
||||
|
@ -515,15 +611,25 @@ static int get_buffer_hwdec(AVCodecContext *avctx, AVFrame *pic)
|
|||
sh_video_t *sh = avctx->opaque;
|
||||
vd_ffmpeg_ctx *ctx = sh->context;
|
||||
|
||||
assert(IMGFMT_IS_HWACCEL(ctx->best_csp));
|
||||
/* Decoders using ffmpeg's hwaccel architecture (everything except vdpau)
|
||||
* can fall back to software decoding automatically. However, we don't
|
||||
* want that: multithreading was already disabled. ffmpeg's fallback
|
||||
* isn't really useful, and causes more trouble than it helps.
|
||||
*
|
||||
* Instead of trying to "adjust" the thread_count fields in avctx, let
|
||||
* decoding fail hard. Then decode_with_fallback() will do our own software
|
||||
* fallback. Fully reinitializing the decoder is saner, and will probably
|
||||
* save us from other weird corner cases, like having to "reroute" the
|
||||
* get_buffer callback.
|
||||
*/
|
||||
int imgfmt = pixfmt2imgfmt(avctx->pix_fmt);
|
||||
if (!IMGFMT_IS_HWACCEL(imgfmt))
|
||||
return -1;
|
||||
|
||||
// Uncertain whether this is needed; at least deals with VO/filter failures
|
||||
if (init_vo(sh, avctx->pix_fmt) < 0) {
|
||||
avctx->release_buffer = avcodec_default_release_buffer;
|
||||
avctx->get_buffer = avcodec_default_get_buffer;
|
||||
avctx->reget_buffer = avcodec_default_reget_buffer;
|
||||
return avctx->get_buffer(avctx, pic);
|
||||
}
|
||||
if (init_vo(sh) < 0)
|
||||
return -1;
|
||||
|
||||
assert(IMGFMT_IS_HWACCEL(ctx->best_csp));
|
||||
|
||||
struct mp_image *mpi = get_image_hwdec(ctx);
|
||||
if (!mpi)
|
||||
|
@ -568,9 +674,9 @@ static av_unused void swap_palette(void *pal)
|
|||
p[i] = le2me_32(p[i]);
|
||||
}
|
||||
|
||||
static struct mp_image *decode(struct sh_video *sh, struct demux_packet *packet,
|
||||
void *data, int len, int flags,
|
||||
double *reordered_pts)
|
||||
static int decode(struct sh_video *sh, struct demux_packet *packet, void *data,
|
||||
int len, int flags, double *reordered_pts,
|
||||
struct mp_image **out_image)
|
||||
{
|
||||
int got_picture = 0;
|
||||
int ret;
|
||||
|
@ -601,22 +707,22 @@ static struct mp_image *decode(struct sh_video *sh, struct demux_packet *packet,
|
|||
union pts { int64_t i; double d; };
|
||||
avctx->reordered_opaque = (union pts){.d = *reordered_pts}.i;
|
||||
ret = avcodec_decode_video2(avctx, pic, &got_picture, &pkt);
|
||||
*reordered_pts = (union pts){.i = pic->reordered_opaque}.d;
|
||||
|
||||
int dr1 = ctx->do_dr1;
|
||||
if (ret < 0)
|
||||
if (ret < 0) {
|
||||
mp_msg(MSGT_DECVIDEO, MSGL_WARN, "Error while decoding frame!\n");
|
||||
return -1;
|
||||
}
|
||||
*reordered_pts = (union pts){.i = pic->reordered_opaque}.d;
|
||||
|
||||
print_vstats(sh, len);
|
||||
|
||||
if (!got_picture)
|
||||
return NULL; // skipped image
|
||||
return 0; // skipped image
|
||||
|
||||
if (init_vo(sh, avctx->pix_fmt) < 0)
|
||||
return NULL;
|
||||
if (init_vo(sh) < 0)
|
||||
return -1;
|
||||
|
||||
struct mp_image *mpi = NULL;
|
||||
if (dr1 && pic->opaque)
|
||||
if (ctx->do_dr1 && pic->opaque)
|
||||
mpi = (mp_image_t *)pic->opaque;
|
||||
|
||||
if (!mpi) {
|
||||
|
@ -634,7 +740,7 @@ static struct mp_image *decode(struct sh_video *sh, struct demux_packet *packet,
|
|||
}
|
||||
|
||||
if (!mpi->planes[0])
|
||||
return NULL;
|
||||
return 0; // ?
|
||||
|
||||
assert(mpi->imgfmt == pixfmt2imgfmt(avctx->pix_fmt));
|
||||
|
||||
|
@ -658,7 +764,39 @@ static struct mp_image *decode(struct sh_video *sh, struct demux_packet *packet,
|
|||
if (pic->repeat_pict == 1)
|
||||
mpi->fields |= MP_IMGFIELD_REPEAT_FIRST;
|
||||
|
||||
*out_image = mpi;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static struct mp_image *decode_with_fallback(struct sh_video *sh,
|
||||
struct demux_packet *packet, void *data,
|
||||
int len, int flags, double *reordered_pts)
|
||||
{
|
||||
vd_ffmpeg_ctx *ctx = sh->context;
|
||||
if (!ctx->avctx)
|
||||
return NULL;
|
||||
|
||||
struct mp_image *mpi = NULL;
|
||||
int res = decode(sh, packet, data, len, flags, reordered_pts, &mpi);
|
||||
if (res >= 0)
|
||||
return mpi;
|
||||
|
||||
// Failed hardware decoding? Try again in software.
|
||||
if (ctx->software_fallback) {
|
||||
uninit_avctx(sh);
|
||||
sh->vf_initialized = 0;
|
||||
mp_tmsg(MSGT_DECVIDEO, MSGL_ERR, "Error using hardware "
|
||||
"decoding, falling back to software decoding.\n");
|
||||
AVCodec *codec = ctx->software_fallback;
|
||||
ctx->software_fallback = NULL;
|
||||
if (init_avctx(sh, codec, NULL)) {
|
||||
mpi = NULL;
|
||||
decode(sh, packet, data, len, flags, reordered_pts, &mpi);
|
||||
return mpi;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int control(sh_video_t *sh, int cmd, void *arg)
|
||||
|
@ -677,7 +815,7 @@ static int control(sh_video_t *sh, int cmd, void *arg)
|
|||
case VDCTRL_RESET_ASPECT:
|
||||
if (ctx->vo_initialized)
|
||||
ctx->vo_initialized = false;
|
||||
init_vo(sh, avctx->pix_fmt);
|
||||
init_vo(sh);
|
||||
return true;
|
||||
}
|
||||
return CONTROL_UNKNOWN;
|
||||
|
@ -688,5 +826,5 @@ const struct vd_functions mpcodecs_vd_ffmpeg = {
|
|||
.init = init,
|
||||
.uninit = uninit,
|
||||
.control = control,
|
||||
.decode = decode,
|
||||
.decode = decode_with_fallback,
|
||||
};
|
||||
|
|
Loading…
Reference in New Issue