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
|
-spugauss --sub-gauss
|
||||||
-vobsub --sub (pass the .idx file)
|
-vobsub --sub (pass the .idx file)
|
||||||
-ass-bottom-margin --vf=sub=bottom:top
|
-ass-bottom-margin --vf=sub=bottom:top
|
||||||
|
-vc ffh264vdpau (etc.) --hwdec=vdpau
|
||||||
=================================== ===================================
|
=================================== ===================================
|
||||||
|
|
||||||
input.conf and slave commands
|
input.conf and slave commands
|
||||||
|
|
|
@ -779,6 +779,18 @@
|
||||||
negative of the image with this option. Not supported by all video output
|
negative of the image with this option. Not supported by all video output
|
||||||
drivers.
|
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
|
--identify
|
||||||
Deprecated. Use ``TOOLS/mpv_identify.sh``.
|
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},
|
{"ac", &audio_codec_list, CONF_TYPE_STRING_LIST, 0, 0, 0, NULL},
|
||||||
{"vc", &video_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:
|
// postprocessing:
|
||||||
{"pp", &divx_quality, CONF_TYPE_INT, 0, 0, 0, NULL},
|
{"pp", &divx_quality, CONF_TYPE_INT, 0, 0, 0, NULL},
|
||||||
#ifdef CONFIG_LIBPOSTPROC
|
#ifdef CONFIG_LIBPOSTPROC
|
||||||
|
|
|
@ -126,6 +126,9 @@ typedef struct MPOpts {
|
||||||
char *ass_styles_file;
|
char *ass_styles_file;
|
||||||
int ass_style_override;
|
int ass_style_override;
|
||||||
int ass_hinting;
|
int ass_hinting;
|
||||||
|
|
||||||
|
int hwdec_api;
|
||||||
|
|
||||||
struct lavc_param {
|
struct lavc_param {
|
||||||
int workaround_bugs;
|
int workaround_bugs;
|
||||||
int error_resilience;
|
int error_resilience;
|
||||||
|
|
|
@ -180,6 +180,7 @@ videocodec ffmpeg12
|
||||||
driver ffmpeg
|
driver ffmpeg
|
||||||
dll "mpegvideo"
|
dll "mpegvideo"
|
||||||
|
|
||||||
|
; deprecated in favor of --hwdec=vdpau
|
||||||
videocodec ffmpeg12vdpau
|
videocodec ffmpeg12vdpau
|
||||||
info "FFmpeg MPEG-1/2 (VDPAU)"
|
info "FFmpeg MPEG-1/2 (VDPAU)"
|
||||||
status working
|
status working
|
||||||
|
@ -210,6 +211,7 @@ videocodec ffmpeg12vdpau
|
||||||
driver ffmpeg
|
driver ffmpeg
|
||||||
dll "mpegvideo_vdpau"
|
dll "mpegvideo_vdpau"
|
||||||
|
|
||||||
|
; deprecated in favor of --hwdec=crystalhd
|
||||||
videocodec ffmpeg2crystalhd
|
videocodec ffmpeg2crystalhd
|
||||||
info "FFmpeg MPEG-2 (CrystalHD)"
|
info "FFmpeg MPEG-2 (CrystalHD)"
|
||||||
status working
|
status working
|
||||||
|
@ -576,6 +578,7 @@ videocodec ffdivx
|
||||||
driver ffmpeg
|
driver ffmpeg
|
||||||
dll msmpeg4
|
dll msmpeg4
|
||||||
|
|
||||||
|
; deprecated in favor of --hwdec=crystalhd
|
||||||
videocodec ffdivxcrystalhd
|
videocodec ffdivxcrystalhd
|
||||||
info "FFmpeg DivX ;-) (MSMPEG-4 v3) (CrystalHD)"
|
info "FFmpeg DivX ;-) (MSMPEG-4 v3) (CrystalHD)"
|
||||||
status buggy
|
status buggy
|
||||||
|
@ -638,6 +641,7 @@ videocodec ffwmvp
|
||||||
driver ffmpeg
|
driver ffmpeg
|
||||||
dll wmv3
|
dll wmv3
|
||||||
|
|
||||||
|
; deprecated in favor of --hwdec=vdpau
|
||||||
videocodec ffwmv3vdpau
|
videocodec ffwmv3vdpau
|
||||||
info "FFmpeg WMV3/WMV9 (VDPAU)"
|
info "FFmpeg WMV3/WMV9 (VDPAU)"
|
||||||
status buggy
|
status buggy
|
||||||
|
@ -645,6 +649,7 @@ videocodec ffwmv3vdpau
|
||||||
driver ffmpeg
|
driver ffmpeg
|
||||||
dll wmv3_vdpau
|
dll wmv3_vdpau
|
||||||
|
|
||||||
|
; deprecated in favor of --hwdec=crystalhd
|
||||||
videocodec ffwmv3crystalhd
|
videocodec ffwmv3crystalhd
|
||||||
info "FFmpeg WMV3/WMV9 (CrystalHD)"
|
info "FFmpeg WMV3/WMV9 (CrystalHD)"
|
||||||
status buggy
|
status buggy
|
||||||
|
@ -660,6 +665,7 @@ videocodec ffvc1
|
||||||
driver ffmpeg
|
driver ffmpeg
|
||||||
dll vc1
|
dll vc1
|
||||||
|
|
||||||
|
; deprecated in favor of --hwdec=vdpau
|
||||||
videocodec ffvc1vdpau
|
videocodec ffvc1vdpau
|
||||||
info "FFmpeg WVC1 (VDPAU)"
|
info "FFmpeg WVC1 (VDPAU)"
|
||||||
status buggy
|
status buggy
|
||||||
|
@ -668,6 +674,7 @@ videocodec ffvc1vdpau
|
||||||
driver ffmpeg
|
driver ffmpeg
|
||||||
dll vc1_vdpau
|
dll vc1_vdpau
|
||||||
|
|
||||||
|
; deprecated in favor of --hwdec=crystalhd
|
||||||
videocodec ffvc1crystalhd
|
videocodec ffvc1crystalhd
|
||||||
info "FFmpeg WVC1 (CrystalHD)"
|
info "FFmpeg WVC1 (CrystalHD)"
|
||||||
status buggy
|
status buggy
|
||||||
|
@ -691,6 +698,7 @@ videocodec ffh264
|
||||||
driver ffmpeg
|
driver ffmpeg
|
||||||
dll h264
|
dll h264
|
||||||
|
|
||||||
|
; deprecated in favor of --hwdec=vdpau
|
||||||
videocodec ffh264vdpau
|
videocodec ffh264vdpau
|
||||||
info "FFmpeg H.264 (VDPAU)"
|
info "FFmpeg H.264 (VDPAU)"
|
||||||
status working
|
status working
|
||||||
|
@ -704,6 +712,7 @@ videocodec ffh264vdpau
|
||||||
driver ffmpeg
|
driver ffmpeg
|
||||||
dll h264_vdpau
|
dll h264_vdpau
|
||||||
|
|
||||||
|
; deprecated in favor of --hwdec=crystalhd
|
||||||
videocodec ffh264crystalhd
|
videocodec ffh264crystalhd
|
||||||
info "FFmpeg H.264 (CrystalHD)"
|
info "FFmpeg H.264 (CrystalHD)"
|
||||||
status working
|
status working
|
||||||
|
@ -718,6 +727,7 @@ videocodec ffh264crystalhd
|
||||||
driver ffmpeg
|
driver ffmpeg
|
||||||
dll h264_crystalhd
|
dll h264_crystalhd
|
||||||
|
|
||||||
|
; deprecated in favor of --hwdec=vda
|
||||||
videocodec ffh264vda
|
videocodec ffh264vda
|
||||||
info "FFmpeg H.264 (VDA)"
|
info "FFmpeg H.264 (VDA)"
|
||||||
status working
|
status working
|
||||||
|
@ -772,6 +782,7 @@ videocodec ffodivx
|
||||||
driver ffmpeg
|
driver ffmpeg
|
||||||
dll mpeg4 ;opendivx
|
dll mpeg4 ;opendivx
|
||||||
|
|
||||||
|
; deprecated in favor of --hwdec=vdpau
|
||||||
videocodec ffodivxvdpau
|
videocodec ffodivxvdpau
|
||||||
info "FFmpeg MPEG-4,DIVX-4/5 (VDPAU)"
|
info "FFmpeg MPEG-4,DIVX-4/5 (VDPAU)"
|
||||||
status working
|
status working
|
||||||
|
@ -804,6 +815,7 @@ videocodec ffodivxvdpau
|
||||||
driver ffmpeg
|
driver ffmpeg
|
||||||
dll mpeg4_vdpau
|
dll mpeg4_vdpau
|
||||||
|
|
||||||
|
; deprecated in favor of --hwdec=crystalhd
|
||||||
videocodec ffodivxcrystalhd
|
videocodec ffodivxcrystalhd
|
||||||
info "FFmpeg MPEG-4,DIVX-4/5 (CrystalHD)"
|
info "FFmpeg MPEG-4,DIVX-4/5 (CrystalHD)"
|
||||||
status working
|
status working
|
||||||
|
|
|
@ -87,8 +87,8 @@
|
||||||
# but only take effect when the profile is active.
|
# but only take effect when the profile is active.
|
||||||
|
|
||||||
#[vo.vdpau]
|
#[vo.vdpau]
|
||||||
# Use hardware decoding (this will break playback of some h264 files)
|
# Use hardware decoding (this might break playback of some h264 files)
|
||||||
#vc=ffmpeg12vdpau,ffwmv3vdpau,ffvc1vdpau,ffh264vdpau,ffodivxvdpau,
|
#hwdec=vdpau
|
||||||
# Most video filters do not work with vdpau.
|
# Most video filters do not work with vdpau.
|
||||||
#vf-clr=yes
|
#vf-clr=yes
|
||||||
|
|
||||||
|
|
|
@ -26,6 +26,7 @@
|
||||||
#include <libavutil/common.h>
|
#include <libavutil/common.h>
|
||||||
#include <libavutil/opt.h>
|
#include <libavutil/opt.h>
|
||||||
#include <libavutil/intreadwrite.h>
|
#include <libavutil/intreadwrite.h>
|
||||||
|
#include <libavutil/pixdesc.h>
|
||||||
|
|
||||||
#include "compat/libav.h"
|
#include "compat/libav.h"
|
||||||
|
|
||||||
|
@ -69,6 +70,7 @@ typedef struct {
|
||||||
AVFrame *pic;
|
AVFrame *pic;
|
||||||
struct mp_image export_mpi;
|
struct mp_image export_mpi;
|
||||||
struct mp_image hwdec_mpi[MAX_NUM_MPI];
|
struct mp_image hwdec_mpi[MAX_NUM_MPI];
|
||||||
|
struct hwdec *hwdec;
|
||||||
enum PixelFormat pix_fmt;
|
enum PixelFormat pix_fmt;
|
||||||
int do_dr1;
|
int do_dr1;
|
||||||
int vo_initialized;
|
int vo_initialized;
|
||||||
|
@ -78,10 +80,14 @@ typedef struct {
|
||||||
double inv_qp_sum;
|
double inv_qp_sum;
|
||||||
AVRational last_sample_aspect_ratio;
|
AVRational last_sample_aspect_ratio;
|
||||||
enum AVDiscard skip_frame;
|
enum AVDiscard skip_frame;
|
||||||
|
int rawvideo_fmt;
|
||||||
|
AVCodec *software_fallback;
|
||||||
} vd_ffmpeg_ctx;
|
} vd_ffmpeg_ctx;
|
||||||
|
|
||||||
#include "core/m_option.h"
|
#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 int get_buffer_hwdec(AVCodecContext *avctx, AVFrame *pic);
|
||||||
static void release_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,
|
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}
|
{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
|
// print debugging stats into a file
|
||||||
static void print_vstats(sh_video_t *sh, int len)
|
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)
|
static int init(sh_video_t *sh)
|
||||||
{
|
{
|
||||||
struct lavc_param *lavc_param = &sh->opts->lavc_param;
|
|
||||||
AVCodecContext *avctx;
|
|
||||||
vd_ffmpeg_ctx *ctx;
|
vd_ffmpeg_ctx *ctx;
|
||||||
AVCodec *lavc_codec = NULL;
|
AVCodec *lavc_codec = NULL;
|
||||||
enum PixelFormat rawfmt = PIX_FMT_NONE;
|
|
||||||
|
|
||||||
ctx = sh->context = talloc_zero(NULL, vd_ffmpeg_ctx);
|
ctx = sh->context = talloc_zero(NULL, vd_ffmpeg_ctx);
|
||||||
|
ctx->rawvideo_fmt = PIX_FMT_NONE;
|
||||||
|
|
||||||
if (sh->codec->dll) {
|
if (sh->codec->dll) {
|
||||||
lavc_codec = avcodec_find_decoder_by_name(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;
|
return 0;
|
||||||
}
|
}
|
||||||
} else if (!IMGFMT_IS_HWACCEL(sh->format)) {
|
} else if (!IMGFMT_IS_HWACCEL(sh->format)) {
|
||||||
rawfmt = imgfmt2pixfmt(sh->format);
|
ctx->rawvideo_fmt = imgfmt2pixfmt(sh->format);
|
||||||
if (rawfmt != PIX_FMT_NONE)
|
if (ctx->rawvideo_fmt != PIX_FMT_NONE)
|
||||||
lavc_codec = avcodec_find_decoder_by_name("rawvideo");
|
lavc_codec = avcodec_find_decoder_by_name("rawvideo");
|
||||||
}
|
}
|
||||||
if (!lavc_codec) {
|
if (!lavc_codec) {
|
||||||
|
@ -244,30 +292,64 @@ static int init(sh_video_t *sh)
|
||||||
return 0;
|
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;
|
sh->codecname = lavc_codec->long_name;
|
||||||
if (!sh->codecname)
|
if (!sh->codecname)
|
||||||
sh->codecname = lavc_codec->name;
|
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->pic = avcodec_alloc_frame();
|
||||||
ctx->avctx = avcodec_alloc_context3(lavc_codec);
|
ctx->avctx = avcodec_alloc_context3(lavc_codec);
|
||||||
avctx = ctx->avctx;
|
AVCodecContext *avctx = ctx->avctx;
|
||||||
avctx->opaque = sh;
|
avctx->opaque = sh;
|
||||||
avctx->codec_type = AVMEDIA_TYPE_VIDEO;
|
avctx->codec_type = AVMEDIA_TYPE_VIDEO;
|
||||||
avctx->codec_id = lavc_codec->id;
|
avctx->codec_id = lavc_codec->id;
|
||||||
|
|
||||||
avctx->thread_count = lavc_param->threads;
|
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;
|
ctx->do_dr1 = true;
|
||||||
avctx->thread_count = 1;
|
avctx->thread_count = 1;
|
||||||
avctx->get_format = get_format_hwdec;
|
avctx->get_format = get_format_hwdec;
|
||||||
avctx->get_buffer = get_buffer_hwdec;
|
avctx->get_buffer = get_buffer_hwdec;
|
||||||
avctx->release_buffer = release_buffer_hwdec;
|
avctx->release_buffer = release_buffer_hwdec;
|
||||||
|
if (ctx->hwdec->api == HWDEC_VDPAU) {
|
||||||
avctx->draw_horiz_band = draw_slice_hwdec;
|
avctx->draw_horiz_band = draw_slice_hwdec;
|
||||||
if (lavc_codec->capabilities & CODEC_CAP_HWACCEL_VDPAU)
|
avctx->slice_flags =
|
||||||
mp_msg(MSGT_DECVIDEO, MSGL_V, "[VD_FFMPEG] VDPAU hardware "
|
SLICE_FLAG_CODED_ORDER | SLICE_FLAG_ALLOW_FIELD;
|
||||||
"decoding.\n");
|
}
|
||||||
avctx->slice_flags = SLICE_FLAG_CODED_ORDER | SLICE_FLAG_ALLOW_FIELD;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (avctx->thread_count == 0) {
|
if (avctx->thread_count == 0) {
|
||||||
|
@ -289,10 +371,10 @@ static int init(sh_video_t *sh)
|
||||||
if (lavc_param->gray)
|
if (lavc_param->gray)
|
||||||
avctx->flags |= CODEC_FLAG_GRAY;
|
avctx->flags |= CODEC_FLAG_GRAY;
|
||||||
avctx->flags2 |= lavc_param->fast;
|
avctx->flags2 |= lavc_param->fast;
|
||||||
if (rawfmt == PIX_FMT_NONE) {
|
if (ctx->rawvideo_fmt == PIX_FMT_NONE) {
|
||||||
avctx->codec_tag = sh->format;
|
avctx->codec_tag = sh->format;
|
||||||
} else {
|
} else {
|
||||||
avctx->pix_fmt = rawfmt;
|
avctx->pix_fmt = ctx->rawvideo_fmt;
|
||||||
}
|
}
|
||||||
if (sh->gsh->lavf_codec_tag)
|
if (sh->gsh->lavf_codec_tag)
|
||||||
avctx->codec_tag = 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 */
|
/* open it */
|
||||||
if (avcodec_open2(avctx, lavc_codec, NULL) < 0) {
|
if (avcodec_open2(avctx, lavc_codec, NULL) < 0) {
|
||||||
mp_tmsg(MSGT_DECVIDEO, MSGL_ERR, "Could not open codec.\n");
|
mp_tmsg(MSGT_DECVIDEO, MSGL_ERR, "Could not open codec.\n");
|
||||||
uninit(sh);
|
uninit_avctx(sh);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void uninit(sh_video_t *sh)
|
static void uninit_avctx(sh_video_t *sh)
|
||||||
{
|
{
|
||||||
vd_ffmpeg_ctx *ctx = sh->context;
|
vd_ffmpeg_ctx *ctx = sh->context;
|
||||||
AVCodecContext *avctx = ctx->avctx;
|
AVCodecContext *avctx = ctx->avctx;
|
||||||
|
|
||||||
sh->codecname = NULL;
|
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) {
|
||||||
if (avctx->codec && avcodec_close(avctx) < 0)
|
if (avctx->codec && avcodec_close(avctx) < 0)
|
||||||
|
@ -419,19 +492,34 @@ static void uninit(sh_video_t *sh)
|
||||||
|
|
||||||
av_freep(&avctx);
|
av_freep(&avctx);
|
||||||
avcodec_free_frame(&ctx->pic);
|
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;
|
vd_ffmpeg_ctx *ctx = sh->context;
|
||||||
AVCodecContext *avctx = ctx->avctx;
|
AVCodecContext *avctx = ctx->avctx;
|
||||||
float aspect = av_q2d(avctx->sample_aspect_ratio) *
|
|
||||||
avctx->width / avctx->height;
|
|
||||||
int width, height;
|
|
||||||
|
|
||||||
width = avctx->width;
|
if (avctx && sh->opts->lavc_param.vstats && avctx->coded_frame) {
|
||||||
height = avctx->height;
|
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
|
/* Reconfiguring filter/VO chain may invalidate direct rendering buffers
|
||||||
* we have allocated for libavcodec (including the VDPAU HW decoding
|
* 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) ||
|
if (av_cmp_q(avctx->sample_aspect_ratio, ctx->last_sample_aspect_ratio) ||
|
||||||
width != sh->disp_w || height != sh->disp_h ||
|
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;
|
ctx->vo_initialized = 0;
|
||||||
mp_msg(MSGT_DECVIDEO, MSGL_V, "[ffmpeg] aspect_ratio: %f\n", aspect);
|
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;
|
ctx->last_sample_aspect_ratio = avctx->sample_aspect_ratio;
|
||||||
sh->disp_w = width;
|
sh->disp_w = width;
|
||||||
sh->disp_h = height;
|
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->colorspace = avcol_spc_to_mp_csp(avctx->colorspace);
|
||||||
sh->color_range = avcol_range_to_mp_csp_levels(avctx->color_range);
|
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))
|
if (!mpcodecs_config_vo(sh, sh->disp_w, sh->disp_h, ctx->best_csp))
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
ctx->vo_initialized = 1;
|
ctx->vo_initialized = 1;
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -471,19 +562,24 @@ static enum PixelFormat get_format_hwdec(struct AVCodecContext *avctx,
|
||||||
const enum PixelFormat *fmt)
|
const enum PixelFormat *fmt)
|
||||||
{
|
{
|
||||||
sh_video_t *sh = avctx->opaque;
|
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]);
|
int imgfmt = pixfmt2imgfmt(fmt[i]);
|
||||||
if (!IMGFMT_IS_HWACCEL(imgfmt))
|
if (ctx->hwdec->api == HWDEC_VDPAU && IMGFMT_IS_VDPAU(imgfmt))
|
||||||
continue;
|
|
||||||
mp_msg(MSGT_DECVIDEO, MSGL_V, "[VD_FFMPEG] Trying pixfmt=%d.\n", i);
|
|
||||||
if (init_vo(sh, fmt[i]) >= 0)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return fmt[i];
|
return fmt[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return PIX_FMT_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
static void draw_slice_hwdec(struct AVCodecContext *s,
|
static void draw_slice_hwdec(struct AVCodecContext *s,
|
||||||
const AVFrame *src, int offset[4],
|
const AVFrame *src, int offset[4],
|
||||||
int y, int type, int height)
|
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;
|
sh_video_t *sh = avctx->opaque;
|
||||||
vd_ffmpeg_ctx *ctx = sh->context;
|
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) < 0)
|
||||||
if (init_vo(sh, avctx->pix_fmt) < 0) {
|
return -1;
|
||||||
avctx->release_buffer = avcodec_default_release_buffer;
|
|
||||||
avctx->get_buffer = avcodec_default_get_buffer;
|
assert(IMGFMT_IS_HWACCEL(ctx->best_csp));
|
||||||
avctx->reget_buffer = avcodec_default_reget_buffer;
|
|
||||||
return avctx->get_buffer(avctx, pic);
|
|
||||||
}
|
|
||||||
|
|
||||||
struct mp_image *mpi = get_image_hwdec(ctx);
|
struct mp_image *mpi = get_image_hwdec(ctx);
|
||||||
if (!mpi)
|
if (!mpi)
|
||||||
|
@ -568,9 +674,9 @@ static av_unused void swap_palette(void *pal)
|
||||||
p[i] = le2me_32(p[i]);
|
p[i] = le2me_32(p[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct mp_image *decode(struct sh_video *sh, struct demux_packet *packet,
|
static int decode(struct sh_video *sh, struct demux_packet *packet, void *data,
|
||||||
void *data, int len, int flags,
|
int len, int flags, double *reordered_pts,
|
||||||
double *reordered_pts)
|
struct mp_image **out_image)
|
||||||
{
|
{
|
||||||
int got_picture = 0;
|
int got_picture = 0;
|
||||||
int ret;
|
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; };
|
union pts { int64_t i; double d; };
|
||||||
avctx->reordered_opaque = (union pts){.d = *reordered_pts}.i;
|
avctx->reordered_opaque = (union pts){.d = *reordered_pts}.i;
|
||||||
ret = avcodec_decode_video2(avctx, pic, &got_picture, &pkt);
|
ret = avcodec_decode_video2(avctx, pic, &got_picture, &pkt);
|
||||||
*reordered_pts = (union pts){.i = pic->reordered_opaque}.d;
|
if (ret < 0) {
|
||||||
|
|
||||||
int dr1 = ctx->do_dr1;
|
|
||||||
if (ret < 0)
|
|
||||||
mp_msg(MSGT_DECVIDEO, MSGL_WARN, "Error while decoding frame!\n");
|
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);
|
print_vstats(sh, len);
|
||||||
|
|
||||||
if (!got_picture)
|
if (!got_picture)
|
||||||
return NULL; // skipped image
|
return 0; // skipped image
|
||||||
|
|
||||||
if (init_vo(sh, avctx->pix_fmt) < 0)
|
if (init_vo(sh) < 0)
|
||||||
return NULL;
|
return -1;
|
||||||
|
|
||||||
struct mp_image *mpi = NULL;
|
struct mp_image *mpi = NULL;
|
||||||
if (dr1 && pic->opaque)
|
if (ctx->do_dr1 && pic->opaque)
|
||||||
mpi = (mp_image_t *)pic->opaque;
|
mpi = (mp_image_t *)pic->opaque;
|
||||||
|
|
||||||
if (!mpi) {
|
if (!mpi) {
|
||||||
|
@ -634,7 +740,7 @@ static struct mp_image *decode(struct sh_video *sh, struct demux_packet *packet,
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!mpi->planes[0])
|
if (!mpi->planes[0])
|
||||||
return NULL;
|
return 0; // ?
|
||||||
|
|
||||||
assert(mpi->imgfmt == pixfmt2imgfmt(avctx->pix_fmt));
|
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)
|
if (pic->repeat_pict == 1)
|
||||||
mpi->fields |= MP_IMGFIELD_REPEAT_FIRST;
|
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;
|
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)
|
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:
|
case VDCTRL_RESET_ASPECT:
|
||||||
if (ctx->vo_initialized)
|
if (ctx->vo_initialized)
|
||||||
ctx->vo_initialized = false;
|
ctx->vo_initialized = false;
|
||||||
init_vo(sh, avctx->pix_fmt);
|
init_vo(sh);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return CONTROL_UNKNOWN;
|
return CONTROL_UNKNOWN;
|
||||||
|
@ -688,5 +826,5 @@ const struct vd_functions mpcodecs_vd_ffmpeg = {
|
||||||
.init = init,
|
.init = init,
|
||||||
.uninit = uninit,
|
.uninit = uninit,
|
||||||
.control = control,
|
.control = control,
|
||||||
.decode = decode,
|
.decode = decode_with_fallback,
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in New Issue