diff options
-rw-r--r-- | DOCS/man/en/options.rst | 2 | ||||
-rw-r--r-- | DOCS/man/en/vo.rst | 5 | ||||
-rw-r--r-- | Makefile | 1 | ||||
-rwxr-xr-x | TOOLS/mpv_identify.sh | 2 | ||||
-rwxr-xr-x | configure | 12 | ||||
-rw-r--r-- | demux/demux.c | 13 | ||||
-rw-r--r-- | demux/demux.h | 2 | ||||
-rw-r--r-- | demux/demux_lavf.c | 23 | ||||
-rw-r--r-- | demux/demux_libass.c | 2 | ||||
-rw-r--r-- | demux/demux_mf.c | 5 | ||||
-rw-r--r-- | demux/demux_mkv.c | 14 | ||||
-rw-r--r-- | demux/demux_raw.c | 8 | ||||
-rw-r--r-- | demux/demux_subreader.c | 2 | ||||
-rw-r--r-- | mpvcore/player/loadfile.c | 5 | ||||
-rw-r--r-- | mpvcore/player/playloop.c | 32 | ||||
-rw-r--r-- | stream/stream.c | 16 | ||||
-rw-r--r-- | video/decode/dec_video.h | 5 | ||||
-rw-r--r-- | video/decode/lavc.h | 2 | ||||
-rw-r--r-- | video/decode/vaapi.c | 1 | ||||
-rw-r--r-- | video/decode/vd_lavc.c | 7 | ||||
-rw-r--r-- | video/mp_image.c | 22 | ||||
-rw-r--r-- | video/mp_image.h | 3 | ||||
-rw-r--r-- | video/out/gl_common.c | 9 | ||||
-rw-r--r-- | video/out/gl_common.h | 39 | ||||
-rw-r--r-- | video/out/gl_hwdec_vaglx.c | 140 | ||||
-rw-r--r-- | video/out/gl_video.c | 123 | ||||
-rw-r--r-- | video/out/gl_video.h | 4 | ||||
-rw-r--r-- | video/out/vo_opengl.c | 73 |
28 files changed, 478 insertions, 94 deletions
diff --git a/DOCS/man/en/options.rst b/DOCS/man/en/options.rst index 18542b2e37..f28280f73f 100644 --- a/DOCS/man/en/options.rst +++ b/DOCS/man/en/options.rst @@ -1118,7 +1118,7 @@ OPTIONS :no: always use software decoding (default) :auto: see below :vdpau: requires ``--vo=vdpau`` (Linux only) - :vaapi: requires ``--vo=vaapi`` (Linux with Intel GPUs only) + :vaapi: requires ``--vo=opengl`` or ``--vo=vaapi`` (Linux with Intel GPUs only) :vaapi-copy: copies video back into system RAM (Linux with Intel GPUs only) :vda: requires ``--vo=corevideo`` (OSX only) :crystalhd: Broadcom Crystal HD diff --git a/DOCS/man/en/vo.rst b/DOCS/man/en/vo.rst index 4590ec33f2..fd14c6a128 100644 --- a/DOCS/man/en/vo.rst +++ b/DOCS/man/en/vo.rst @@ -241,6 +241,11 @@ Available video output drivers are: Some features are available with OpenGL 3 capable graphics drivers only (or if the necessary extensions are available). + Hardware decoding over OpenGL-interop is supported to some degree. Note + that in this mode, some corner case might not be gracefully handled, and + colorspace conversion and chroma upsampling is generally in the hand of + the hardware decoder APIs. + ``lscale=<filter>`` ``bilinear`` @@ -121,6 +121,7 @@ SOURCES-$(VAAPI) += video/out/vo_vaapi.c \ video/decode/vaapi.c \ video/vaapi.c SOURCES-$(VAAPI_VPP) += video/filter/vf_vavpp.c +SOURCES-$(VAAPI_GLX) += video/out/gl_hwdec_vaglx.c SOURCES-$(X11) += video/out/vo_x11.c video/out/x11_common.c SOURCES-$(XV) += video/out/vo_xv.c diff --git a/TOOLS/mpv_identify.sh b/TOOLS/mpv_identify.sh index 0c4dfc5b02..b1c17f75c2 100755 --- a/TOOLS/mpv_identify.sh +++ b/TOOLS/mpv_identify.sh @@ -104,7 +104,7 @@ for __midentify__key in $__midentify__allprops; do eval unset $__midentify__nextprefix$__midentify__key done -__midentify__output=`$MPV --playing-msg="$__midentify__propstr" --vo=null --ao=null --frames=1 --quiet "$@"` +__midentify__output=`$MPV --playing-msg="$__midentify__propstr" --vo=null --ao=null --frames=1 --quiet --no-cache --no-config "$@"` __midentify__fileindex=0 __midentify__prefix= while :; do @@ -1863,6 +1863,8 @@ echores "$_vdpau" echocheck "VAAPI" _vaapi_vpp=no def_vaapi_vpp='#define HAVE_VAAPI_VPP 0' +_vaapi_glx=no +def_vaapi_glx='#define HAVE_VAAPI_GLX 0' if test "$_vaapi" = auto && test "$_x11" = yes ; then _vaapi=no if test "$_dl" = yes ; then @@ -1886,7 +1888,13 @@ if test "$_vaapi" = yes ; then _vaapi_vpp=yes def_vaapi_vpp='#define HAVE_VAAPI_VPP 1' fi - echores "$_vaapi_vpp" + echores "$_vaapi_glx" + echocheck "VAAPI GLX" + if pkg_config_add 'libva-glx >= 0.32.0' ; then + _vaapi_glx=yes + def_vaapi_glx='#define HAVE_VAAPI_GLX 1' + fi + echores "$_vaapi_glx" fi @@ -3321,6 +3329,7 @@ VDA = $_vda VDA_REFCOUNTING = $_vda_refcounting VAAPI = $_vaapi VAAPI_VPP = $_vaapi_vpp +VAAPI_GLX = $_vaapi_glx WIN32 = $_win32 X11 = $_x11 WAYLAND = $_wayland @@ -3501,6 +3510,7 @@ $def_vda $def_vda_refcounting $def_vaapi $def_vaapi_vpp +$def_vaapi_glx $def_vaapi_hwaccel $def_vm $def_x11 diff --git a/demux/demux.c b/demux/demux.c index eeb979be9d..a0164d529a 100644 --- a/demux/demux.c +++ b/demux/demux.c @@ -533,9 +533,8 @@ static struct demuxer *open_given_type(struct MPOpts *opts, .type = desc->type, .stream = stream, .stream_pts = MP_NOPTS_VALUE, - .movi_start = stream->start_pos, - .movi_end = stream->end_pos, - .seekable = 1, + .seekable = (stream->flags & MP_STREAM_SEEK) == MP_STREAM_SEEK && + stream->end_pos > 0, .accurate_seek = true, .filepos = -1, .opts = opts, @@ -566,6 +565,12 @@ static struct demuxer *open_given_type(struct MPOpts *opts, add_stream_chapters(demuxer); demuxer_sort_chapters(demuxer); demux_info_update(demuxer); + // Pretend we can seek if we can't seek, but there's a cache. + if (!demuxer->seekable && stream->uncached_stream) { + mp_msg(MSGT_DEMUXER, MSGL_WARN, + "File is not seekable, but there's a cache: enabling seeking.\n"); + demuxer->seekable = true; + } return demuxer; } @@ -634,7 +639,7 @@ void demux_flush(demuxer_t *demuxer) int demux_seek(demuxer_t *demuxer, float rel_seek_secs, int flags) { if (!demuxer->seekable) { - mp_tmsg(MSGT_SEEK, MSGL_WARN, "Cannot seek in this file.\n"); + mp_tmsg(MSGT_DEMUXER, MSGL_WARN, "Cannot seek in this file.\n"); return 0; } diff --git a/demux/demux.h b/demux/demux.h index 0c8f9cb3f8..1c8562eb63 100644 --- a/demux/demux.h +++ b/demux/demux.h @@ -166,8 +166,6 @@ typedef struct demuxer { const demuxer_desc_t *desc; ///< Demuxer description structure const char *filetype; // format name when not identified by demuxer (libavformat) int64_t filepos; // input stream current pos. - int64_t movi_start; - int64_t movi_end; struct stream *stream; double stream_pts; // current stream pts, if applicable (e.g. dvd) char *filename; // same as stream->url diff --git a/demux/demux_lavf.c b/demux/demux_lavf.c index e80db5aed4..b2dfcb2193 100644 --- a/demux/demux_lavf.c +++ b/demux/demux_lavf.c @@ -584,9 +584,12 @@ static int demux_open_lavf(demuxer_t *demuxer, enum demux_check check) } } - if (!(priv->avif->flags & AVFMT_NOFILE) && - demuxer->stream->type != STREAMTYPE_AVDEVICE) + if ((priv->avif->flags & AVFMT_NOFILE) || + demuxer->stream->type == STREAMTYPE_AVDEVICE) { + // This might be incorrect. + demuxer->seekable = true; + } else { void *buffer = av_malloc(lavfdopts->buffersize); if (!buffer) return -1; @@ -597,9 +600,7 @@ static int demux_open_lavf(demuxer_t *demuxer, enum demux_check check) return -1; } priv->pb->read_seek = mp_read_seek; - priv->pb->seekable = demuxer->stream->end_pos - && (demuxer->stream->flags & MP_STREAM_SEEK) == MP_STREAM_SEEK - ? AVIO_SEEKABLE_NORMAL : 0; + priv->pb->seekable = demuxer->seekable ? AVIO_SEEKABLE_NORMAL : 0; avfc->pb = priv->pb; } @@ -857,12 +858,12 @@ static void demux_seek_lavf(demuxer_t *demuxer, float rel_seek_secs, int flags) avsflags = AVSEEK_FLAG_BACKWARD; if (flags & SEEK_FACTOR) { - if (demuxer->movi_end > 0 && demuxer->ts_resets_possible && + struct stream *s = demuxer->stream; + if (s->end_pos > 0 && demuxer->ts_resets_possible && !(priv->avif->flags & AVFMT_NO_BYTE_SEEK)) { avsflags |= AVSEEK_FLAG_BYTE; - priv->last_pts = (demuxer->movi_end - demuxer->movi_start) * - rel_seek_secs; + priv->last_pts = (s->end_pos - s->start_pos) * rel_seek_secs; } else if (priv->avfc->duration != 0 && priv->avfc->duration != AV_NOPTS_VALUE) { @@ -923,12 +924,12 @@ static int demux_lavf_control(demuxer_t *demuxer, int cmd, void *arg) switch (cmd) { case DEMUXER_CTRL_GET_TIME_LENGTH: if (priv->seek_by_bytes) { + struct stream *s = demuxer->stream; /* Our bitrate estimate may be better than would be used in * otherwise similar fallback code at higher level */ - if (demuxer->movi_end <= 0) + if (s->end_pos <= 0) return DEMUXER_CTRL_DONTKNOW; - *(double *)arg = (demuxer->movi_end - demuxer->movi_start) * 8 / - priv->bitrate; + *(double *)arg = (s->end_pos - s->start_pos) * 8 / priv->bitrate; return DEMUXER_CTRL_GUESS; } if (priv->avfc->duration == 0 || priv->avfc->duration == AV_NOPTS_VALUE) diff --git a/demux/demux_libass.c b/demux/demux_libass.c index d98cdbb5a4..73c8b3a5c8 100644 --- a/demux/demux_libass.c +++ b/demux/demux_libass.c @@ -100,6 +100,8 @@ static int d_check_file(struct demuxer *demuxer, enum demux_check check) sh->sub->track = track; sh->codec = "ass"; + demuxer->seekable = true; + return 0; } diff --git a/demux/demux_mf.c b/demux/demux_mf.c index 0d7b2ece8a..50888f59ad 100644 --- a/demux/demux_mf.c +++ b/demux/demux_mf.c @@ -85,7 +85,6 @@ static int demux_mf_fill_buffer(demuxer_t *demuxer) demux_packet_t *dp = new_demux_packet(data.len); memcpy(dp->buffer, data.start, data.len); dp->pts = mf->curr_frame / mf->sh->fps; - dp->pos = mf->curr_frame; dp->keyframe = true; demuxer_add_packet(demuxer, demuxer->streams[0], dp); } @@ -200,9 +199,6 @@ static int demux_open_mf(demuxer_t* demuxer, enum demux_check check) mf->curr_frame = 0; - demuxer->movi_start = 0; - demuxer->movi_end = mf->nr_of_files - 1; - // create a new video stream header struct sh_stream *sh = new_sh_stream(demuxer, STREAM_VIDEO); sh_video = sh->video; @@ -214,6 +210,7 @@ static int demux_open_mf(demuxer_t* demuxer, enum demux_check check) mf->sh = sh_video; demuxer->priv=(void*)mf; + demuxer->seekable = true; return 0; diff --git a/demux/demux_mkv.c b/demux/demux_mkv.c index eb352e0f64..6110d25930 100644 --- a/demux/demux_mkv.c +++ b/demux/demux_mkv.c @@ -1029,7 +1029,7 @@ static int demux_mkv_read_seekhead(demuxer_t *demuxer) continue; } uint64_t pos = seek->seek_position + mkv_d->segment_start; - if (pos >= demuxer->movi_end) { + if (pos >= s->end_pos) { mp_msg(MSGT_DEMUX, MSGL_WARN, "[mkv] SeekHead position beyond " "end of file - incomplete file?\n"); continue; @@ -1844,14 +1844,6 @@ static int demux_mkv_open(demuxer_t *demuxer, enum demux_check check) display_create_tracks(demuxer); - if (s->end_pos == 0) { - demuxer->seekable = 0; - } else { - demuxer->movi_start = s->start_pos; - demuxer->movi_end = s->end_pos; - demuxer->seekable = 1; - } - return 0; } @@ -2713,7 +2705,7 @@ static void demux_mkv_seek(demuxer_t *demuxer, float rel_seek_secs, int flags) } demux_mkv_fill_buffer(demuxer); - } else if ((demuxer->movi_end <= 0) || !(flags & SEEK_ABSOLUTE)) + } else if (!(flags & SEEK_ABSOLUTE)) mp_msg(MSGT_DEMUX, MSGL_V, "[mkv] seek unsupported flags\n"); else { stream_t *s = demuxer->stream; @@ -2729,7 +2721,7 @@ static void demux_mkv_seek(demuxer_t *demuxer, float rel_seek_secs, int flags) return; } - target_filepos = (uint64_t) (demuxer->movi_end * rel_seek_secs); + target_filepos = (uint64_t) (s->end_pos * rel_seek_secs); for (i = 0; i < mkv_d->num_indexes; i++) if (mkv_d->indexes[i].tnum == v_tnum) if ((index == NULL) diff --git a/demux/demux_raw.c b/demux/demux_raw.c index 4d6e171ad4..01cf3574a0 100644 --- a/demux/demux_raw.c +++ b/demux/demux_raw.c @@ -100,9 +100,6 @@ static int demux_rawaudio_open(demuxer_t *demuxer, enum demux_check check) w->wBitsPerSample = 8 * samplesize; w->cbSize = 0; - demuxer->movi_start = demuxer->stream->start_pos; - demuxer->movi_end = demuxer->stream->end_pos; - struct priv *p = talloc_ptrtype(demuxer, p); demuxer->priv = p; *p = (struct priv) { @@ -185,9 +182,6 @@ static int demux_rawvideo_open(demuxer_t *demuxer, enum demux_check check) sh_video->disp_h = height; sh_video->i_bps = fps * imgsize; - demuxer->movi_start = demuxer->stream->start_pos; - demuxer->movi_end = demuxer->stream->end_pos; - struct priv *p = talloc_ptrtype(demuxer, p); demuxer->priv = p; *p = (struct priv) { @@ -207,7 +201,7 @@ static int raw_fill_buffer(demuxer_t *demuxer) return 0; struct demux_packet *dp = new_demux_packet(p->frame_size * p->read_frames); - dp->pos = stream_tell(demuxer->stream) - demuxer->movi_start; + dp->pos = stream_tell(demuxer->stream) - demuxer->stream->start_pos; dp->pts = (dp->pos / p->frame_size) / p->frame_rate; int len = stream_read(demuxer->stream, dp->buffer, dp->len); diff --git a/demux/demux_subreader.c b/demux/demux_subreader.c index cc02e61595..21bcf21614 100644 --- a/demux/demux_subreader.c +++ b/demux/demux_subreader.c @@ -1358,6 +1358,8 @@ static int d_open_file(struct demuxer *demuxer, enum demux_check check) add_sub_data(demuxer, sd); subdata_free(sd); + demuxer->seekable = true; + return 0; } diff --git a/mpvcore/player/loadfile.c b/mpvcore/player/loadfile.c index 24b81934ad..baa49f0db5 100644 --- a/mpvcore/player/loadfile.c +++ b/mpvcore/player/loadfile.c @@ -894,8 +894,9 @@ static void print_resolve_contents(struct mp_log *log, // from the given playlist pl, so the entries don't actually need to be copied. static void transfer_playlist(struct MPContext *mpctx, struct playlist *pl) { - if (mpctx->demuxer->playlist->first) { - playlist_transfer_entries(mpctx->playlist, mpctx->demuxer->playlist); + if (pl->first) { + playlist_transfer_entries(mpctx->playlist, pl); + // current entry is replaced if (mpctx->playlist->current) playlist_remove(mpctx->playlist, mpctx->playlist->current); } else { diff --git a/mpvcore/player/playloop.c b/mpvcore/player/playloop.c index 1162572946..d4db03c446 100644 --- a/mpvcore/player/playloop.c +++ b/mpvcore/player/playloop.c @@ -206,8 +206,8 @@ static void seek_reset(struct MPContext *mpctx, bool reset_ao, bool reset_ac) } // return -1 if seek failed (non-seekable stream?), 0 otherwise -static int seek(MPContext *mpctx, struct seek_params seek, - bool timeline_fallthrough) +static int mp_seek(MPContext *mpctx, struct seek_params seek, + bool timeline_fallthrough) { struct MPOpts *opts = mpctx->opts; uint64_t prev_seek_ts = mpctx->vo_pts_history_seek_ts; @@ -215,6 +215,11 @@ static int seek(MPContext *mpctx, struct seek_params seek, if (!mpctx->demuxer) return -1; + if (!mpctx->demuxer->seekable) { + MP_ERR(mpctx, "Can't seek in this file.\n"); + return -1; + } + if (mpctx->stop_play == AT_END_OF_FILE) mpctx->stop_play = KEEP_PLAYING; bool hr_seek = mpctx->demuxer->accurate_seek && opts->correct_pts; @@ -387,7 +392,7 @@ void queue_seek(struct MPContext *mpctx, enum seek_type type, double amount, void execute_queued_seek(struct MPContext *mpctx) { if (mpctx->seek.type) { - seek(mpctx, mpctx->seek, false); + mp_seek(mpctx, mpctx->seek, false); mpctx->seek = (struct seek_params){0}; } } @@ -452,11 +457,12 @@ double get_current_pos_ratio(struct MPContext *mpctx, bool use_range) if (len > 0 && !demuxer->ts_resets_possible) { ans = MPCLAMP((pos - start) / len, 0, 1); } else { - int64_t size = (demuxer->movi_end - demuxer->movi_start); + struct stream *s = demuxer->stream; + int64_t size = s->end_pos - s->start_pos; int64_t fpos = demuxer->filepos > 0 ? demuxer->filepos : stream_tell(demuxer->stream); if (size > 0) - ans = MPCLAMP((double)(fpos - demuxer->movi_start) / size, 0, 1); + ans = MPCLAMP((double)(fpos - s->start_pos) / size, 0, 1); } if (use_range) { if (mpctx->opts->play_frames > 0) @@ -812,10 +818,10 @@ static void handle_backstep(struct MPContext *mpctx) // The whole point is getting frames _before_ that PTS, // so apply an arbitrary offset. (In theory the offset // has to be large enough to reach the previous frame.) - seek(mpctx, (struct seek_params){ - .type = MPSEEK_ABSOLUTE, - .amount = current_pts - 1.0, - }, false); + mp_seek(mpctx, (struct seek_params){ + .type = MPSEEK_ABSOLUTE, + .amount = current_pts - 1.0, + }, false); // Don't leave hr-seek mode. If all goes right, hr-seek // mode is cancelled as soon as the frame before // current_pts is found during hr-seeking. @@ -1184,10 +1190,10 @@ void run_playloop(struct MPContext *mpctx) && (opts->gapless_audio || buffered_audio < 0.05) && (!mpctx->paused || was_restart)) { if (end_is_chapter) { - seek(mpctx, (struct seek_params){ - .type = MPSEEK_ABSOLUTE, - .amount = mpctx->timeline[mpctx->timeline_part+1].start - }, true); + mp_seek(mpctx, (struct seek_params){ + .type = MPSEEK_ABSOLUTE, + .amount = mpctx->timeline[mpctx->timeline_part+1].start + }, true); } else mpctx->stop_play = AT_END_OF_FILE; sleeptime = 0; diff --git a/stream/stream.c b/stream/stream.c index fbc324563a..3844721346 100644 --- a/stream/stream.c +++ b/stream/stream.c @@ -318,8 +318,8 @@ static int open_internal(const stream_info_t *sinfo, struct stream *underlying, if (s->seek && !(s->flags & MP_STREAM_SEEK)) s->flags |= MP_STREAM_SEEK; - if (s->flags & MP_STREAM_FAST_SKIPPING) - s->flags |= MP_STREAM_SEEK_FW; + if (!(s->flags & MP_STREAM_SEEK)) + s->end_pos = 0; s->uncached_type = s->type; @@ -387,6 +387,8 @@ static int stream_reconnect(stream_t *s) #define RECONNECT_SLEEP_MS 1000 if (!s->streaming) return 0; + if (!(s->flags & MP_STREAM_SEEK_FW)) + return 0; int64_t pos = s->pos; for (int retry = 0; retry < MAX_RECONNECT_RETRIES; retry++) { mp_msg(MSGT_STREAM, MSGL_WARN, @@ -601,7 +603,7 @@ static int stream_skip_read(struct stream *s, int64_t len) static int stream_seek_unbuffered(stream_t *s, int64_t newpos) { if (newpos != s->pos) { - if (!s->seek || !(s->flags & MP_STREAM_SEEK)) { + if (newpos > s->pos && !(s->flags & MP_STREAM_SEEK_FW)) { mp_tmsg(MSGT_STREAM, MSGL_ERR, "Can not seek in this stream\n"); return 0; } @@ -628,7 +630,7 @@ static int stream_seek_long(stream_t *s, int64_t pos) s->eof = 0; if (s->mode == STREAM_WRITE) { - if (!s->seek || !s->seek(s, pos)) + if (!(s->flags & MP_STREAM_SEEK) || !s->seek(s, pos)) return 0; return 1; } @@ -640,7 +642,9 @@ static int stream_seek_long(stream_t *s, int64_t pos) mp_msg(MSGT_STREAM, MSGL_DBG3, "Seek from %" PRId64 " to %" PRId64 " (with offset %d)\n", s->pos, pos, (int)(pos - newpos)); - if (!s->seek && (s->flags & MP_STREAM_FAST_SKIPPING) && pos >= s->pos) { + if (pos >= s->pos && !(s->flags & MP_STREAM_SEEK) && + (s->flags & MP_STREAM_FAST_SKIPPING)) + { // skipping is handled by generic code below } else if (stream_seek_unbuffered(s, newpos) >= 0) { return 0; @@ -709,6 +713,8 @@ int stream_control(stream_t *s, int cmd, void *arg) void stream_update_size(stream_t *s) { + if (!(s->flags & MP_STREAM_SEEK)) + return; uint64_t size; if (stream_control(s, STREAM_CTRL_GET_SIZE, &size) == STREAM_OK) { if (size > s->end_pos) diff --git a/video/decode/dec_video.h b/video/decode/dec_video.h index 549d208f81..03b72907ef 100644 --- a/video/decode/dec_video.h +++ b/video/decode/dec_video.h @@ -47,6 +47,11 @@ int vd_control(struct sh_video *sh_video, int cmd, void *arg); struct mp_hwdec_info { struct mp_vdpau_ctx *vdpau_ctx; struct mp_vaapi_ctx *vaapi_ctx; + // Can be used to lazily load a requested API. + // api_name is e.g. "vdpau" (like the fields above, without "_ctx") + // Can be NULL, is idempotent, caller checks _ctx fields for success/access. + void (*load_api)(struct mp_hwdec_info *info, const char *api_name); + void *load_api_ctx; }; #endif /* MPLAYER_DEC_VIDEO_H */ diff --git a/video/decode/lavc.h b/video/decode/lavc.h index 9e2533cbd5..af206bc82a 100644 --- a/video/decode/lavc.h +++ b/video/decode/lavc.h @@ -86,6 +86,8 @@ bool hwdec_check_codec_support(const char *decoder, const struct hwdec_profile_entry *table); int hwdec_get_max_refs(struct lavc_ctx *ctx); +void hwdec_request_api(struct mp_hwdec_info *info, const char *api_name); + // lavc_dr1.c int mp_codec_get_buffer(AVCodecContext *s, AVFrame *frame); void mp_codec_release_buffer(AVCodecContext *s, AVFrame *frame); diff --git a/video/decode/vaapi.c b/video/decode/vaapi.c index bb2a6c1049..4603a3c5e1 100644 --- a/video/decode/vaapi.c +++ b/video/decode/vaapi.c @@ -421,6 +421,7 @@ static int init(struct lavc_ctx *ctx) static int probe(struct vd_lavc_hwdec *hwdec, struct mp_hwdec_info *info, const char *decoder) { + hwdec_request_api(info, "vaapi"); if (!info || !info->vaapi_ctx) return HWDEC_ERR_NO_CTX; if (!hwdec_check_codec_support(decoder, profiles)) diff --git a/video/decode/vd_lavc.c b/video/decode/vd_lavc.c index 64542be69d..c6a939ec51 100644 --- a/video/decode/vd_lavc.c +++ b/video/decode/vd_lavc.c @@ -46,6 +46,7 @@ #include "video/img_format.h" #include "video/mp_image_pool.h" #include "video/filter/vf.h" +#include "video/decode/dec_video.h" #include "demux/stheader.h" #include "demux/demux_packet.h" #include "osdep/numcores.h" @@ -195,6 +196,12 @@ int hwdec_get_max_refs(struct lavc_ctx *ctx) return ctx->avctx->codec_id == AV_CODEC_ID_H264 ? 16 : 2; } +void hwdec_request_api(struct mp_hwdec_info *info, const char *api_name) +{ + if (info && info->load_api) + info->load_api(info, api_name); +} + static int hwdec_probe(struct vd_lavc_hwdec *hwdec, struct mp_hwdec_info *info, const char *decoder, const char **hw_decoder) { diff --git a/video/mp_image.c b/video/mp_image.c index 3bc76b669e..9b96bab67d 100644 --- a/video/mp_image.c +++ b/video/mp_image.c @@ -36,6 +36,8 @@ #include "memcpy_pic.h" #include "fmt-conversion.h" +#include "video/filter/vf.h" + #if HAVE_PTHREADS #include <pthread.h> static pthread_mutex_t refcount_mutex = PTHREAD_MUTEX_INITIALIZER; @@ -468,6 +470,26 @@ void mp_image_set_params(struct mp_image *image, image->chroma_location = params->chroma_location; } +// Set most image parameters, but not image format or size. +// Display size is used to set the PAR. +void mp_image_set_attributes(struct mp_image *image, + const struct mp_image_params *params) +{ + struct mp_image_params nparams = *params; + nparams.imgfmt = image->imgfmt; + nparams.w = image->w; + nparams.h = image->h; + if (nparams.imgfmt != params->imgfmt) + mp_image_params_guess_csp(&nparams); + if (nparams.w != params->w || nparams.h != params->h) { + if (nparams.d_w && nparams.d_h) { + vf_rescale_dsize(&nparams.d_w, &nparams.d_h, + params->w, params->h, nparams.w, nparams.h); + } + } + mp_image_set_params(image, &nparams); +} + void mp_image_set_colorspace_details(struct mp_image *image, struct mp_csp_details *csp) { diff --git a/video/mp_image.h b/video/mp_image.h index e198c4e547..f7e7353475 100644 --- a/video/mp_image.h +++ b/video/mp_image.h @@ -153,6 +153,9 @@ void mp_image_params_from_image(struct mp_image_params *params, void mp_image_set_params(struct mp_image *image, const struct mp_image_params *params); +void mp_image_set_attributes(struct mp_image *image, + const struct mp_image_params *params); + struct AVFrame; void mp_image_copy_fields_from_av_frame(struct mp_image *dst, struct AVFrame *src); diff --git a/video/out/gl_common.c b/video/out/gl_common.c index d39a09df16..f3e38a2171 100644 --- a/video/out/gl_common.c +++ b/video/out/gl_common.c @@ -1008,3 +1008,12 @@ void mp_log_source(struct mp_log *log, int lev, const char *src) src = next; } } + +extern const struct gl_hwdec_driver gl_hwdec_vaglx; + +const struct gl_hwdec_driver *mpgl_hwdec_drivers[] = { +#if HAVE_VAAPI_GLX + &gl_hwdec_vaglx, +#endif + NULL +}; diff --git a/video/out/gl_common.h b/video/out/gl_common.h index 41d30bb001..4722f3d52e 100644 --- a/video/out/gl_common.h +++ b/video/out/gl_common.h @@ -164,6 +164,45 @@ void mpgl_set_backend_w32(MPGLContext *ctx); void mpgl_set_backend_x11(MPGLContext *ctx); void mpgl_set_backend_wayland(MPGLContext *ctx); +struct mp_hwdec_info; + +struct gl_hwdec { + const struct gl_hwdec_driver *driver; + struct mp_log *log; + struct MPGLContext *mpgl; + struct mp_hwdec_info *info; + // For free use by hwdec driver + void *priv; + // hwdec backends must set this to an IMGFMT_ that has an equivalent + // internal representation in gl_video.c as the hardware texture. + // It's used to build the rendering chain, and also as screenshot format. + int converted_imgfmt; +}; + +struct gl_hwdec_driver { + // Same name as used by mp_hwdec_info->load_api() + const char *api_name; + // Test whether the given IMGFMT_ is supported. + bool (*query_format)(int imgfmt); + // Create the hwdec device. It must fill in hw->info, if applicable. + // This also must set hw->converted_imgfmt. + int (*create)(struct gl_hwdec *hw); + // Prepare for rendering video. (E.g. create textures.) + // Called on initialization, and every time the video size changes. + int (*reinit)(struct gl_hwdec *hw, int w, int h); + // Return textures that contain the given hw_image. + // Note that the caller keeps a reference to hw_image until unbind_image + // is called, so the callee doesn't need to do that. + int (*load_image)(struct gl_hwdec *hw, struct mp_image *hw_image, + GLuint *out_textures); + // Undo load_image(). The user of load_image() calls this when the textures + // are not needed anymore. + void (*unload_image)(struct gl_hwdec *hw); + void (*destroy)(struct gl_hwdec *hw); +}; + +extern const struct gl_hwdec_driver *mpgl_hwdec_drivers[]; + void *mp_getdladdr(const char *s); void mpgl_load_functions(GL *gl, void *(*getProcAddress)(const GLubyte *), diff --git a/video/out/gl_hwdec_vaglx.c b/video/out/gl_hwdec_vaglx.c new file mode 100644 index 0000000000..9e1030fe49 --- /dev/null +++ b/video/out/gl_hwdec_vaglx.c @@ -0,0 +1,140 @@ +/* + * This file is part of mpv. + * + * Parts based on the MPlayer VA-API patch (see vo_vaapi.c). + * + * mpv is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 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 < |