diff options
author | wm4 <wm4@nowhere> | 2012-11-05 17:02:04 +0100 |
---|---|---|
committer | wm4 <wm4@nowhere> | 2012-11-12 20:06:14 +0100 |
commit | d4bdd0473d6f43132257c9fb3848d829755167a3 (patch) | |
tree | 8021c2f7da1841393c8c832105e20cd527826d6c /video/decode | |
parent | bd48deba77bd5582c5829d6fe73a7d2571088aba (diff) | |
download | mpv-d4bdd0473d6f43132257c9fb3848d829755167a3.tar.bz2 mpv-d4bdd0473d6f43132257c9fb3848d829755167a3.tar.xz |
Rename directories, move files (step 1 of 2) (does not compile)
Tis drops the silly lib prefixes, and attempts to organize the tree in
a more logical way. Make the top-level directory less cluttered as
well.
Renames the following directories:
libaf -> audio/filter
libao2 -> audio/out
libvo -> video/out
libmpdemux -> demux
Split libmpcodecs:
vf* -> video/filter
vd*, dec_video.* -> video/decode
mp_image*, img_format*, ... -> video/
ad*, dec_audio.* -> audio/decode
libaf/format.* is moved to audio/ - this is similar to how mp_image.*
is located in video/.
Move most top-level .c/.h files to core. (talloc.c/.h is left on top-
level, because it's external.) Park some of the more annoying files
in compat/. Some of these are relicts from the time mplayer used
ffmpeg internals.
sub/ is not split, because it's too much of a mess (subtitle code is
mixed with OSD display and rendering).
Maybe the organization of core is not ideal: it mixes playback core
(like mplayer.c) and utility helpers (like bstr.c/h). Should the need
arise, the playback core will be moved somewhere else, while core
contains all helper and common code.
Diffstat (limited to 'video/decode')
-rw-r--r-- | video/decode/dec_video.c | 448 | ||||
-rw-r--r-- | video/decode/dec_video.h | 51 | ||||
-rw-r--r-- | video/decode/vd.c | 273 | ||||
-rw-r--r-- | video/decode/vd.h | 60 | ||||
-rw-r--r-- | video/decode/vd_lavc.c | 857 |
5 files changed, 1689 insertions, 0 deletions
diff --git a/video/decode/dec_video.c b/video/decode/dec_video.c new file mode 100644 index 0000000000..5c6d3113da --- /dev/null +++ b/video/decode/dec_video.c @@ -0,0 +1,448 @@ +/* + * This file is part of MPlayer. + * + * MPlayer 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. + * + * MPlayer 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with MPlayer; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include "config.h" +#include "options.h" + +#include <stdio.h> +#include <stdlib.h> +#include <stdbool.h> +#include <unistd.h> + +#include "mp_msg.h" + +#include "osdep/timer.h" +#include "osdep/shmem.h" + +#include "stream/stream.h" +#include "libmpdemux/demuxer.h" + +#include "codec-cfg.h" + +#include "libvo/video_out.h" +#include "libvo/csputils.h" + +#include "libmpdemux/stheader.h" +#include "vd.h" +#include "vf.h" + +#include "dec_video.h" + +// =================================================================== + +#include "cpudetect.h" + +int field_dominance = -1; + +int divx_quality = 0; + +int get_video_quality_max(sh_video_t *sh_video) +{ + vf_instance_t *vf = sh_video->vfilter; + if (vf) { + int ret = vf->control(vf, VFCTRL_QUERY_MAX_PP_LEVEL, NULL); + if (ret > 0) { + mp_tmsg(MSGT_DECVIDEO, MSGL_INFO, "[PP] Using external postprocessing filter, max q = %d.\n", ret); + return ret; + } + } + return 0; +} + +int set_video_colors(sh_video_t *sh_video, const char *item, int value) +{ + vf_instance_t *vf = sh_video->vfilter; + vf_equalizer_t data; + + data.item = item; + data.value = value; + + mp_dbg(MSGT_DECVIDEO, MSGL_V, "set video colors %s=%d \n", item, value); + if (vf) { + int ret = vf->control(vf, VFCTRL_SET_EQUALIZER, &data); + if (ret == CONTROL_TRUE) + return 1; + } + mp_tmsg(MSGT_DECVIDEO, MSGL_V, "Video attribute '%s' is not supported by selected vo.\n", + item); + return 0; +} + +int get_video_colors(sh_video_t *sh_video, const char *item, int *value) +{ + vf_instance_t *vf = sh_video->vfilter; + vf_equalizer_t data; + + data.item = item; + + mp_dbg(MSGT_DECVIDEO, MSGL_V, "get video colors %s \n", item); + if (vf) { + int ret = vf->control(vf, VFCTRL_GET_EQUALIZER, &data); + if (ret == CONTROL_TRUE) { + *value = data.value; + return 1; + } + } + return 0; +} + +void get_detected_video_colorspace(struct sh_video *sh, struct mp_csp_details *csp) +{ + struct MPOpts *opts = sh->opts; + struct vf_instance *vf = sh->vfilter; + + csp->format = opts->requested_colorspace; + csp->levels_in = opts->requested_input_range; + csp->levels_out = opts->requested_output_range; + + if (csp->format == MP_CSP_AUTO) + csp->format = sh->colorspace; + if (csp->format == MP_CSP_AUTO) + csp->format = mp_csp_guess_colorspace(vf->w, vf->h); + + if (csp->levels_in == MP_CSP_LEVELS_AUTO) + csp->levels_in = sh->color_range; + if (csp->levels_in == MP_CSP_LEVELS_AUTO) + csp->levels_in = MP_CSP_LEVELS_TV; + + if (csp->levels_out == MP_CSP_LEVELS_AUTO) + csp->levels_out = MP_CSP_LEVELS_PC; +} + +void set_video_colorspace(struct sh_video *sh) +{ + struct vf_instance *vf = sh->vfilter; + + struct mp_csp_details requested; + get_detected_video_colorspace(sh, &requested); + vf->control(vf, VFCTRL_SET_YUV_COLORSPACE, &requested); + + struct mp_csp_details actual = MP_CSP_DETAILS_DEFAULTS; + vf->control(vf, VFCTRL_GET_YUV_COLORSPACE, &actual); + + int success = actual.format == requested.format + && actual.levels_in == requested.levels_in + && actual.levels_out == requested.levels_out; + + if (!success) + mp_tmsg(MSGT_DECVIDEO, MSGL_WARN, + "Colorspace details not fully supported by selected vo.\n"); + + if (actual.format != requested.format + && requested.format == MP_CSP_SMPTE_240M) { + // BT.709 is pretty close, much better than BT.601 + requested.format = MP_CSP_BT_709; + vf->control(vf, VFCTRL_SET_YUV_COLORSPACE, &requested); + } + +} + +void resync_video_stream(sh_video_t *sh_video) +{ + const struct vd_functions *vd = sh_video->vd_driver; + if (vd) + vd->control(sh_video, VDCTRL_RESYNC_STREAM, NULL); + sh_video->prev_codec_reordered_pts = MP_NOPTS_VALUE; + sh_video->prev_sorted_pts = MP_NOPTS_VALUE; +} + +void video_reset_aspect(struct sh_video *sh_video) +{ + sh_video->vd_driver->control(sh_video, VDCTRL_RESET_ASPECT, NULL); +} + +int get_current_video_decoder_lag(sh_video_t *sh_video) +{ + const struct vd_functions *vd = sh_video->vd_driver; + if (!vd) + return -1; + int ret = vd->control(sh_video, VDCTRL_QUERY_UNSEEN_FRAMES, NULL); + if (ret >= 10) + return ret - 10; + return -1; +} + +void uninit_video(sh_video_t *sh_video) +{ + if (!sh_video->initialized) + return; + mp_tmsg(MSGT_DECVIDEO, MSGL_V, "Uninit video: %s\n", sh_video->codec->drv); + sh_video->vd_driver->uninit(sh_video); + vf_uninit_filter_chain(sh_video->vfilter); + sh_video->initialized = 0; +} + +void vfm_help(void) +{ + int i; + mp_tmsg(MSGT_DECVIDEO, MSGL_INFO, "Available (compiled-in) video codec families/drivers:\n"); + mp_msg(MSGT_IDENTIFY, MSGL_INFO, "ID_VIDEO_DRIVERS\n"); + mp_msg(MSGT_DECVIDEO, MSGL_INFO, " vfm: info: (comment)\n"); + for (i = 0; mpcodecs_vd_drivers[i] != NULL; i++) + mp_msg(MSGT_DECVIDEO, MSGL_INFO, "%8s %s (%s)\n", + mpcodecs_vd_drivers[i]->info->short_name, + mpcodecs_vd_drivers[i]->info->name, + mpcodecs_vd_drivers[i]->info->comment); +} + +static int init_video(sh_video_t *sh_video, char *codecname, char *vfm, + int status, stringset_t *selected) +{ + int force = 0; + unsigned int orig_fourcc = + sh_video->bih ? sh_video->bih->biCompression : 0; + sh_video->codec = NULL; + sh_video->vf_initialized = 0; + if (codecname && codecname[0] == '+') { + codecname = &codecname[1]; + force = 1; + } + + while (1) { + int i; + int orig_w, orig_h; + // restore original fourcc: + if (sh_video->bih) + sh_video->bih->biCompression = orig_fourcc; + if (! + (sh_video->codec = + find_video_codec(sh_video->format, + sh_video->bih ? ((unsigned int *) &sh_video-> + bih->biCompression) : NULL, + sh_video->codec, force))) + break; + // ok we found one codec + if (stringset_test(selected, sh_video->codec->name)) + continue; // already tried & failed + if (codecname && strcmp(sh_video->codec->name, codecname)) + continue; // -vc + if (vfm && strcmp(sh_video->codec->drv, vfm)) + continue; // vfm doesn't match + if (!force && sh_video->codec->status < status) + continue; // too unstable + stringset_add(selected, sh_video->codec->name); // tagging it + // ok, it matches all rules, let's find the driver! + for (i = 0; mpcodecs_vd_drivers[i] != NULL; i++) + if (!strcmp(mpcodecs_vd_drivers[i]->info->short_name, + sh_video->codec->drv)) + break; + sh_video->vd_driver = mpcodecs_vd_drivers[i]; + if (!sh_video->vd_driver) { // driver not available (==compiled in) + mp_tmsg(MSGT_DECVIDEO, MSGL_WARN, + _("Requested video codec family [%s] (vfm=%s) not available.\nEnable it at compilation.\n"), + sh_video->codec->name, sh_video->codec->drv); + continue; + } + orig_w = sh_video->bih ? sh_video->bih->biWidth : sh_video->disp_w; + orig_h = sh_video->bih ? sh_video->bih->biHeight : sh_video->disp_h; + sh_video->disp_w = orig_w; + sh_video->disp_h = orig_h; + // it's available, let's try to init! + if (sh_video->codec->flags & CODECS_FLAG_ALIGN16) { + // align width/height to n*16 + sh_video->disp_w = (sh_video->disp_w + 15) & (~15); + sh_video->disp_h = (sh_video->disp_h + 15) & (~15); + } + if (sh_video->bih) { + sh_video->bih->biWidth = sh_video->disp_w; + sh_video->bih->biHeight = sh_video->disp_h; + } + + // init() + const struct vd_functions *vd = sh_video->vd_driver; + mp_tmsg(MSGT_DECVIDEO, MSGL_V, "Opening video decoder: [%s] %s\n", + vd->info->short_name, vd->info->name); + // clear vf init error, it is no longer relevant + if (sh_video->vf_initialized < 0) + sh_video->vf_initialized = 0; + if (!vd->init(sh_video)) { + mp_tmsg(MSGT_DECVIDEO, MSGL_INFO, "Video decoder init failed for " + "codecs.conf entry \"%s\".\n", sh_video->codec->name); + sh_video->disp_w = orig_w; + sh_video->disp_h = orig_h; + if (sh_video->bih) { + sh_video->bih->biWidth = sh_video->disp_w; + sh_video->bih->biHeight = sh_video->disp_h; + } + continue; // try next... + } + // Yeah! We got it! + sh_video->initialized = 1; + sh_video->prev_codec_reordered_pts = MP_NOPTS_VALUE; + sh_video->prev_sorted_pts = MP_NOPTS_VALUE; + return 1; + } + return 0; +} + +int init_best_video_codec(sh_video_t *sh_video, char **video_codec_list, + char **video_fm_list) +{ + char *vc_l_default[2] = { "", (char *) NULL }; + stringset_t selected; + // hack: + if (!video_codec_list) + video_codec_list = vc_l_default; + // Go through the codec.conf and find the best codec... + sh_video->initialized = 0; + stringset_init(&selected); + while (!sh_video->initialized && *video_codec_list) { + char *video_codec = *(video_codec_list++); + if (video_codec[0]) { + if (video_codec[0] == '-') { + // disable this codec: + stringset_add(&selected, video_codec + 1); + } else { + // forced codec by name: + mp_tmsg(MSGT_DECVIDEO, MSGL_INFO, "Forced video codec: %s\n", + video_codec); + init_video(sh_video, video_codec, NULL, -1, &selected); + } + } else { + int status; + // try in stability order: UNTESTED, WORKING, BUGGY. never try CRASHING. + if (video_fm_list) { + char **fmlist = video_fm_list; + // try first the preferred codec families: + while (!sh_video->initialized && *fmlist) { + char *video_fm = *(fmlist++); + mp_tmsg(MSGT_DECVIDEO, MSGL_INFO, "Trying to force video codec driver family %s...\n", + video_fm); + for (status = CODECS_STATUS__MAX; + status >= CODECS_STATUS__MIN; --status) + if (init_video + (sh_video, NULL, video_fm, status, &selected)) + break; + } + } + if (!sh_video->initialized) + for (status = CODECS_STATUS__MAX; status >= CODECS_STATUS__MIN; + --status) + if (init_video(sh_video, NULL, NULL, status, &selected)) + break; + } + } + stringset_free(&selected); + + if (!sh_video->initialized) { + mp_tmsg(MSGT_DECVIDEO, MSGL_ERR, "Cannot find codec matching selected -vo and video format 0x%X.\n", + sh_video->format); + return 0; // failed + } + + mp_tmsg(MSGT_DECVIDEO, MSGL_INFO, "Selected video codec: %s [%s]\n", + sh_video->codecname ? sh_video->codecname : sh_video->codec->info, + sh_video->vd_driver->info->print_name ? + sh_video->vd_driver->info->print_name : + sh_video->vd_driver->info->short_name); + mp_tmsg(MSGT_DECVIDEO, MSGL_V, + "Video codecs.conf entry: %s (%s) vfm: %s\n", + sh_video->codec->name, sh_video->codec->info, sh_video->codec->drv); + return 1; // success +} + +void *decode_video(sh_video_t *sh_video, struct demux_packet *packet, + unsigned char *start, int in_size, + int drop_frame, double pts) +{ + mp_image_t *mpi = NULL; + struct MPOpts *opts = sh_video->opts; + + if (opts->correct_pts && pts != MP_NOPTS_VALUE) { + int delay = get_current_video_decoder_lag(sh_video); + if (delay >= 0) { + if (delay > sh_video->num_buffered_pts) +#if 0 + // this is disabled because vd_ffmpeg reports the same lag + // after seek even when there are no buffered frames, + // leading to incorrect error messages + mp_msg(MSGT_DECVIDEO, MSGL_ERR, "Not enough buffered pts\n"); +#else + ; +#endif + else + sh_video->num_buffered_pts = delay; + } + if (sh_video->num_buffered_pts == + sizeof(sh_video->buffered_pts) / sizeof(double)) + mp_msg(MSGT_DECVIDEO, MSGL_ERR, "Too many buffered pts\n"); + else { + int i, j; + for (i = 0; i < sh_video->num_buffered_pts; i++) + if (sh_video->buffered_pts[i] < pts) + break; + for (j = sh_video->num_buffered_pts; j > i; j--) + sh_video->buffered_pts[j] = sh_video->buffered_pts[j - 1]; + sh_video->buffered_pts[i] = pts; + sh_video->num_buffered_pts++; + } + } + + mpi = sh_video->vd_driver->decode(sh_video, packet, start, in_size, + drop_frame, &pts); + + //------------------------ frame decoded. -------------------- + +#if HAVE_MMX + // some codecs are broken, and doesn't restore MMX state :( + // it happens usually with broken/damaged files. + if (gCpuCaps.hasMMX) { + __asm__ volatile("emms\n\t":::"memory"); + } +#endif + + if (!mpi || drop_frame) + return NULL; // error / skipped frame + + if (field_dominance == 0) + mpi->fields |= MP_IMGFIELD_TOP_FIRST; + else if (field_dominance == 1) + mpi->fields &= ~MP_IMGFIELD_TOP_FIRST; + + double prevpts = sh_video->codec_reordered_pts; + sh_video->prev_codec_reordered_pts = prevpts; + sh_video->codec_reordered_pts = pts; + if (prevpts != MP_NOPTS_VALUE && pts <= prevpts + || pts == MP_NOPTS_VALUE) + sh_video->num_reordered_pts_problems++; + prevpts = sh_video->sorted_pts; + if (opts->correct_pts) { + if (sh_video->num_buffered_pts) { + sh_video->num_buffered_pts--; + sh_video->sorted_pts = + sh_video->buffered_pts[sh_video->num_buffered_pts]; + } else { + mp_msg(MSGT_CPLAYER, MSGL_ERR, + "No pts value from demuxer to use for frame!\n"); + sh_video->sorted_pts = MP_NOPTS_VALUE; + } + } + pts = sh_video->sorted_pts; + if (prevpts != MP_NOPTS_VALUE && pts <= prevpts + || pts == MP_NOPTS_VALUE) + sh_video->num_sorted_pts_problems++; + return mpi; +} + +int filter_video(sh_video_t *sh_video, void *frame, double pts) +{ + mp_image_t *mpi = frame; + vf_instance_t *vf = sh_video->vfilter; + // apply video filters and call the leaf vo/ve + return vf->put_image(vf, mpi, pts); +} diff --git a/video/decode/dec_video.h b/video/decode/dec_video.h new file mode 100644 index 0000000000..f871198988 --- /dev/null +++ b/video/decode/dec_video.h @@ -0,0 +1,51 @@ +/* + * This file is part of MPlayer. + * + * MPlayer 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. + * + * MPlayer 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with MPlayer; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifndef MPLAYER_DEC_VIDEO_H +#define MPLAYER_DEC_VIDEO_H + +#include "libmpdemux/stheader.h" + +struct osd_state; + +// dec_video.c: +void vfm_help(void); + +int init_best_video_codec(sh_video_t *sh_video, char** video_codec_list, char** video_fm_list); +void uninit_video(sh_video_t *sh_video); + +struct demux_packet; +void *decode_video(sh_video_t *sh_video, struct demux_packet *packet, + unsigned char *start, int in_size, int drop_frame, + double pts); +int filter_video(sh_video_t *sh_video, void *frame, double pts); + +int get_video_quality_max(sh_video_t *sh_video); + +int get_video_colors(sh_video_t *sh_video, const char *item, int *value); +int set_video_colors(sh_video_t *sh_video, const char *item, int value); +struct mp_csp_details; +void get_detected_video_colorspace(struct sh_video *sh, struct mp_csp_details *csp); +void set_video_colorspace(struct sh_video *sh); +void resync_video_stream(sh_video_t *sh_video); +void video_reset_aspect(struct sh_video *sh_video); +int get_current_video_decoder_lag(sh_video_t *sh_video); + +extern int divx_quality; + +#endif /* MPLAYER_DEC_VIDEO_H */ diff --git a/video/decode/vd.c b/video/decode/vd.c new file mode 100644 index 0000000000..3bfc17c895 --- /dev/null +++ b/video/decode/vd.c @@ -0,0 +1,273 @@ +/* + * This file is part of MPlayer. + * + * MPlayer 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. + * + * MPlayer 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with MPlayer; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "config.h" +#include "mp_msg.h" +#include "options.h" + +#include "codec-cfg.h" + +#include "img_format.h" + +#include "stream/stream.h" +#include "libmpdemux/demuxer.h" +#include "libmpdemux/stheader.h" +#include "dec_video.h" + +#include "vd.h" +#include "vf.h" +#include "libvo/video_out.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 +}; + +int mpcodecs_config_vo(sh_video_t *sh, int w, int h, + const unsigned int *outfmts, + unsigned int preferred_outfmt) +{ + struct MPOpts *opts = sh->opts; + int j; + unsigned int out_fmt = 0; + int screen_size_x = 0; + int screen_size_y = 0; + vf_instance_t *vf = sh->vfilter; + int vocfg_flags = 0; + + if (w) + sh->disp_w = w; + if (h) + sh->disp_h = h; + + mp_msg(MSGT_DECVIDEO, MSGL_V, + "VIDEO: %dx%d %5.3f fps %5.1f kbps (%4.1f kB/s)\n", + sh->disp_w, sh->disp_h, sh->fps, sh->i_bps * 0.008, + sh->i_bps / 1000.0); + + if (!sh->disp_w || !sh->disp_h) + return 0; + + mp_msg(MSGT_DECVIDEO, MSGL_V, + "VDec: vo config request - %d x %d (preferred colorspace: %s)\n", + w, h, vo_format_name(preferred_outfmt)); + + if (get_video_quality_max(sh) <= 0 && divx_quality) { + // user wants postprocess but no pp filter yet: + sh->vfilter = vf = vf_open_filter(opts, vf, "pp", NULL); + } + + if (!outfmts || sh->codec->outfmt[0] != 0xffffffff) + outfmts = sh->codec->outfmt; + + // check if libvo and codec has common outfmt (no conversion): + csp_again: + + if (mp_msg_test(MSGT_DECVIDEO, MSGL_V)) { + mp_msg(MSGT_DECVIDEO, MSGL_V, "Trying filter chain:"); + for (vf_instance_t *f = vf; f; f = f->next) + mp_msg(MSGT_DECVIDEO, MSGL_V, " %s", f->info->name); + mp_msg(MSGT_DECVIDEO, MSGL_V, "\n"); + } + + j = -1; + for (int i = 0; i < CODECS_MAX_OUTFMT; i++) { + int flags; + out_fmt = outfmts[i]; + if (out_fmt == (unsigned int) 0xFFFFFFFF) + break; + flags = vf->query_format(vf, out_fmt); + mp_msg(MSGT_CPLAYER, MSGL_DBG2, + "vo_debug: query(%s) returned 0x%X (i=%d) \n", + vo_format_name(out_fmt), flags, i); + if ((flags & VFCAP_CSP_SUPPORTED_BY_HW) + || (flags & VFCAP_CSP_SUPPORTED && j < 0)) { + // check (query) if codec really support this outfmt... + sh->outfmtidx = j; // pass index to the control() function this way + if (sh->vd_driver->control(sh, VDCTRL_QUERY_FORMAT, &out_fmt) == + CONTROL_FALSE) { + mp_msg(MSGT_CPLAYER, MSGL_DBG2, + "vo_debug: codec query_format(%s) returned FALSE\n", + vo_format_name(out_fmt)); + continue; + } + j = i; + sh->output_flags = flags; + if (flags & VFCAP_CSP_SUPPORTED_BY_HW) + break; + } + } + if (j < 0) { + // TODO: no match - we should use conversion... + if (strcmp(vf->info->name, "scale")) { + mp_tmsg(MSGT_DECVIDEO, MSGL_INFO, "Could not find matching colorspace - retrying with -vf scale...\n"); + vf = vf_open_filter(opts, vf, "scale", NULL); + goto csp_again; + } + mp_tmsg(MSGT_CPLAYER, MSGL_WARN, + "The selected video_out device is incompatible with this codec.\n"\ + "Try appending the scale filter to your filter list,\n"\ + "e.g. -vf spp,scale instead of -vf spp.\n"); + sh->vf_initialized = -1; + return 0; // failed + } + out_fmt = outfmts[j]; + sh->outfmt = out_fmt; + mp_msg(MSGT_CPLAYER, MSGL_V, "VDec: using %s as output csp (no %d)\n", + vo_format_name(out_fmt), j); + sh->outfmtidx = j; + sh->vfilter = vf; + + // autodetect flipping + if (opts->flip == -1) { + opts->flip = 0; + if (sh->codec->outflags[j] & CODECS_FLAG_FLIP) + if (!(sh->codec->outflags[j] & CODECS_FLAG_NOFLIP)) + opts->flip = 1; + } + if (opts->flip && !(sh->output_flags & VFCAP_FLIP)) { + // we need to flip, but no flipping filter avail. + vf_add_before_vo(&vf, "flip", NULL); + sh->vfilter = vf; + } + // time to do aspect ratio corrections... + + if (opts->movie_aspect > -1.0) + sh->aspect = opts->movie_aspect; // cmdline overrides autodetect + else if (sh->stream_aspect != 0.0) + sh->aspect = sh->stream_aspect; + + if (opts->screen_size_x || opts->screen_size_y) { + screen_size_x = opts->screen_size_x; + screen_size_y = opts->screen_size_y; + if (!opts->vidmode) { + if (!screen_size_x) + screen_size_x = 1; + if (!screen_size_y) + screen_size_y = 1; + if (screen_size_x <= 8) + screen_size_x *= sh->disp_w; + if (screen_size_y <= 8) + screen_size_y *= sh->disp_h; + } + } else { + // check source format aspect, calculate prescale ::atmos + screen_size_x = sh->disp_w; + screen_size_y = sh->disp_h; + if (opts->screen_size_xy >= 0.001) { + if (opts->screen_size_xy <= 8) { + // -xy means x+y scale + screen_size_x *= opts->screen_size_xy; + screen_size_y *= opts->screen_size_xy; + } else { + // -xy means forced width while keeping correct aspect + screen_size_x = opts->screen_size_xy; + screen_size_y = opts->screen_size_xy * sh->disp_h / sh->disp_w; + } + } + if (sh->aspect > 0.01) { + mp_msg(MSGT_IDENTIFY, MSGL_INFO, "ID_VIDEO_ASPECT=%1.4f\n", + sh->aspect); + int w = screen_size_y * sh->aspect; + int h = screen_size_y; + // we don't like horizontal downscale || user forced width: + if (w < screen_size_x || opts->screen_size_xy > 8) { + w = screen_size_x; + h = screen_size_x / sh->aspect; + } + if (abs(screen_size_x - w) >= 4 || abs(screen_size_y - h) >= 4) { + screen_size_x = w; + screen_size_y = h; + mp_tmsg(MSGT_CPLAYER, MSGL_V, "Aspect ratio is %.2f:1 - " + "scaling to correct movie aspect.\n", sh->aspect); + } + } else { + mp_tmsg(MSGT_CPLAYER, MSGL_V, "Movie-Aspect is undefined - no prescaling applied.\n"); + } + } + + vocfg_flags = (opts->fullscreen ? VOFLAG_FULLSCREEN : 0) + | (opts->vidmode ? VOFLAG_MODESWITCHING : 0) + | (opts->softzoom ? VOFLAG_SWSCALE : 0) + | (opts->flip ? VOFLAG_FLIPPING : 0); + + // Time to config libvo! + mp_msg(MSGT_CPLAYER, MSGL_V, + "VO Config (%dx%d->%dx%d,flags=%d,0x%X)\n", sh->disp_w, + sh->disp_h, screen_size_x, screen_size_y, vocfg_flags, out_fmt); + + vf->w = sh->disp_w; + vf->h = sh->disp_h; + + if (vf_config_wrapper + (vf, sh->disp_w, sh->disp_h, screen_size_x, screen_size_y, vocfg_flags, + out_fmt) == 0) { + mp_tmsg(MSGT_CPLAYER, MSGL_WARN, "FATAL: Cannot initialize video driver.\n"); + sh->vf_initialized = -1; + return 0; + } + + sh->vf_initialized = 1; + + set_video_colorspace(sh); + + if (opts->vo_gamma_gamma != 1000) + set_video_colors(sh, "gamma", opts->vo_gamma_gamma); + if (opts->vo_gamma_brightness != 1000) + set_video_colors(sh, "brightness", opts->vo_gamma_brightness); + if (opts->vo_gamma_contrast != 1000) + set_video_colors(sh, "contrast", opts->vo_gamma_contrast); + if (opts->vo_gamma_saturation != 1000) + set_video_colors(sh, "saturation", opts->vo_gamma_saturation); + if (opts->vo_gamma_hue != 1000) + set_video_colors(sh, "hue", opts->vo_gamma_hue); + + return 1; +} + +// mp_imgtype: buffering type, see mp_image.h +// mp_imgflag: buffer requirements (read/write, preserve, stride limits), see mp_image.h +// returns NULL or allocated mp_image_t* +// Note: buffer allocation may be moved to mpcodecs_config_vo() later... +mp_image_t *mpcodecs_get_image(sh_video_t *sh, int mp_imgtype, int mp_imgflag, + int w, int h) +{ + return vf_get_image(sh->vfilter, sh->outfmt, mp_imgtype, mp_imgflag, w, h); +} + +void mpcodecs_draw_slice(sh_video_t *sh, unsigned char **src, int *stride, + int w, int h, int x, int y) +{ + struct vf_instance *vf = sh->vfilter; + + if (vf->draw_slice) + vf->draw_slice(vf, src, stride, w, h, x, y); +} diff --git a/video/decode/vd.h b/video/decode/vd.h new file mode 100644 index 0000000000..6b9803a611 --- /dev/null +++ b/video/decode/vd.h @@ -0,0 +1,60 @@ +/* + * This file is part of MPlayer. + * + * MPlayer 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. + * + * MPlayer 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with MPlayer; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifndef MPLAYER_VD_H +#define MPLAYER_VD_H + +#include "mp_image.h" +#include "mpc_info.h" +#include "libmpdemux/stheader.h" + +typedef struct mp_codec_info vd_info_t; + +struct demux_packet; + +/* interface of video decoder drivers */ +typedef struct vd_functions +{ + const vd_info_t *info; + int (*init)(sh_video_t *sh); + void (*uninit)(sh_video_t *sh); + int (*control)(sh_video_t *sh, int cmd, void *arg); + struct mp_image *(*decode)(struct sh_video *sh, struct demux_packet *pkt, + void *data, int len, int flags, + double *reordered_pts); +} vd_functions_t; + +// NULL terminated array of all drivers +extern const vd_functions_t *const mpcodecs_vd_drivers[]; + +#define VDCTRL_QUERY_FORMAT 3 // test for availabilty of a format +#define VDCTRL_RESYNC_STREAM 8 // reset decode state after seeking +#define VDCTRL_QUERY_UNSEEN_FRAMES 9 // current decoder lag +#define VDCTRL_RESET_ASPECT 10 // reinit filter/VO chain for new aspect ratio + +// callbacks: +int mpcodecs_config_vo(sh_video_t *sh, int w, int h, + const unsigned int *outfmts, + unsigned int preferred_outfmt); + +mp_image_t *mpcodecs_get_image(sh_video_t *sh, int mp_imgtype, int mp_imgflag, + int w, int h); +void mpcodecs_draw_slice(sh_video_t *sh, unsigned char **src, int *stride, + int w, int h, int x, int y); + +#endif /* MPLAYER_VD_H */ diff --git a/video/decode/vd_lavc.c b/video/decode/vd_lavc.c new file mode 100644 index 0000000000..e078de4419 --- /dev/null +++ b/video/decode/vd_lavc.c @@ -0,0 +1,857 @@ +/* + * This file is part of MPlayer. + * + * MPlayer 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. + * + * MPlayer 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with MPlayer; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include <stdio.h> +#include <stdlib.h> +#include <assert.h> +#include <time.h> +#include <stdbool.h> +#include <sys/types.h> + +#include <libavutil/common.h> +#include <libavutil/opt.h> +#include <libavutil/intreadwrite.h> + +#include "talloc.h" +#include "config.h" +#include "mp_msg.h" +#include "options.h" +#include "av_opts.h" + +#include "mpbswap.h" +#include "fmt-conversion.h" + +#include "vd.h" +#include "img_format.h" +#include "libmpdemux/stheader.h" +#include "libmpdemux/demux_packet.h" +#include "codec-cfg.h" |