diff options
Diffstat (limited to 'libvo')
42 files changed, 0 insertions, 21808 deletions
diff --git a/libvo/aspect.c b/libvo/aspect.c deleted file mode 100644 index f3cd00a5e5..0000000000 --- a/libvo/aspect.c +++ /dev/null @@ -1,148 +0,0 @@ -/* - * 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. - */ - -/* Stuff for correct aspect scaling. */ -#include "aspect.h" -#include "geometry.h" -#include "video_out.h" -#include "mp_msg.h" -#include "options.h" - -#include "video_out.h" - -void aspect_save_videores(struct vo *vo, int w, int h, int d_w, int d_h) -{ - vo->aspdat.orgw = w; - vo->aspdat.orgh = h; - vo->aspdat.prew = d_w; - vo->aspdat.preh = d_h; - vo->aspdat.par = (double)d_w / d_h * h / w; -} - -void aspect_save_screenres(struct vo *vo, int scrw, int scrh) -{ - mp_msg(MSGT_VO, MSGL_DBG2, "aspect_save_screenres %dx%d\n", scrw, scrh); - struct MPOpts *opts = vo->opts; - if (scrw <= 0 && scrh <= 0) - scrw = 1024; - if (scrh <= 0) - scrh = (scrw * 3 + 3) / 4; - if (scrw <= 0) - scrw = (scrh * 4 + 2) / 3; - vo->aspdat.scrw = scrw; - vo->aspdat.scrh = scrh; - if (opts->force_monitor_aspect) - vo->monitor_par = opts->force_monitor_aspect * scrh / scrw; - else - vo->monitor_par = 1.0 / opts->monitor_pixel_aspect; -} - -/* aspect is called with the source resolution and the - * resolution, that the scaled image should fit into - */ - -void aspect_fit(struct vo *vo, int *srcw, int *srch, int fitw, int fith) -{ - struct aspect_data *aspdat = &vo->aspdat; - float pixelaspect = vo->monitor_par; - - mp_msg(MSGT_VO, MSGL_DBG2, "aspect(0) fitin: %dx%d monitor_par: %.2f\n", - fitw, fith, vo->monitor_par); - *srcw = fitw; - *srch = (float)fitw / aspdat->prew * aspdat->preh / pixelaspect; - *srch += *srch % 2; // round - mp_msg(MSGT_VO, MSGL_DBG2, "aspect(1) wh: %dx%d (org: %dx%d)\n", - *srcw, *srch, aspdat->prew, aspdat->preh); - if (*srch > fith || *srch < aspdat->orgh) { - int tmpw = (float)fith / aspdat->preh * aspdat->prew * pixelaspect; - tmpw += tmpw % 2; // round - if (tmpw <= fitw) { - *srch = fith; - *srcw = tmpw; - } else if (*srch > fith) { - mp_tmsg(MSGT_VO, MSGL_WARN, - "[ASPECT] Warning: No suitable new res found!\n"); - } - } - aspdat->asp = *srcw / (float)*srch; - mp_msg(MSGT_VO, MSGL_DBG2, "aspect(2) wh: %dx%d (org: %dx%d)\n", - *srcw, *srch, aspdat->prew, aspdat->preh); -} - -static void get_max_dims(struct vo *vo, int *w, int *h, int zoom) -{ - struct aspect_data *aspdat = &vo->aspdat; - *w = zoom ? aspdat->scrw : aspdat->prew; - *h = zoom ? aspdat->scrh : aspdat->preh; - if (zoom && WinID >= 0) - zoom = A_WINZOOM; - if (zoom == A_WINZOOM) { - *w = vo->dwidth; - *h = vo->dheight; - } -} - -void aspect(struct vo *vo, int *srcw, int *srch, int zoom) -{ - int fitw; - int fith; - get_max_dims(vo, &fitw, &fith, zoom); - if (!zoom && geometry_wh_changed) { - mp_msg(MSGT_VO, MSGL_DBG2, "aspect(0) no aspect forced!\n"); - return; // the user doesn't want to fix aspect - } - aspect_fit(vo, srcw, srch, fitw, fith); -} - -void panscan_init(struct vo *vo) -{ - vo->panscan_x = 0; - vo->panscan_y = 0; - vo->panscan_amount = 0.0f; -} - -static void panscan_calc_internal(struct vo *vo, int zoom) -{ - int fwidth, fheight; - int vo_panscan_area; - int max_w, max_h; - get_max_dims(vo, &max_w, &max_h, zoom); - struct MPOpts *opts = vo->opts; - - if (opts->vo_panscanrange > 0) { - aspect(vo, &fwidth, &fheight, zoom); - vo_panscan_area = max_h - fheight; - if (!vo_panscan_area) - vo_panscan_area = max_w - fwidth; - vo_panscan_area *= opts->vo_panscanrange; - } else - vo_panscan_area = -opts->vo_panscanrange * max_h; - - vo->panscan_amount = vo_fs || zoom == A_WINZOOM ? vo_panscan : 0; - vo->panscan_x = vo_panscan_area * vo->panscan_amount * vo->aspdat.asp; - vo->panscan_y = vo_panscan_area * vo->panscan_amount; -} - -/** - * vos that set vo_dwidth and v_dheight correctly should call this to update - * vo_panscan_x and vo_panscan_y - */ -void panscan_calc_windowed(struct vo *vo) -{ - panscan_calc_internal(vo, A_WINZOOM); -} diff --git a/libvo/aspect.h b/libvo/aspect.h deleted file mode 100644 index c5247421d2..0000000000 --- a/libvo/aspect.h +++ /dev/null @@ -1,37 +0,0 @@ -/* - * 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_ASPECT_H -#define MPLAYER_ASPECT_H -/* Stuff for correct aspect scaling. */ - -struct vo; -void panscan_init(struct vo *vo); -void panscan_calc_windowed(struct vo *vo); - -void aspect_save_videores(struct vo *vo, int w, int h, int d_w, int d_h); -void aspect_save_screenres(struct vo *vo, int scrw, int scrh); - -#define A_WINZOOM 2 ///< zoom to fill window size -#define A_ZOOM 1 -#define A_NOZOOM 0 - -void aspect(struct vo *vo, int *srcw, int *srch, int zoom); -void aspect_fit(struct vo *vo, int *srcw, int *srch, int fitw, int fith); - -#endif /* MPLAYER_ASPECT_H */ diff --git a/libvo/bitmap_packer.c b/libvo/bitmap_packer.c deleted file mode 100644 index 603a6ce410..0000000000 --- a/libvo/bitmap_packer.c +++ /dev/null @@ -1,227 +0,0 @@ -/* - * Calculate how to pack bitmap rectangles into a larger surface - * - * Copyright 2009, 2012 Uoti Urpala - * - * This file is part of mplayer2. - * - * mplayer2 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. - * - * mplayer2 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 mplayer2. If not, see <http://www.gnu.org/licenses/>. - */ - -#include <stdlib.h> -#include <assert.h> - -#include <libavutil/common.h> - -#include "talloc.h" -#include "bitmap_packer.h" -#include "mp_msg.h" -#include "mpcommon.h" -#include "sub/dec_sub.h" -#include "fastmemcpy.h" - -#define IS_POWER_OF_2(x) (((x) > 0) && !(((x) - 1) & (x))) - -void packer_reset(struct bitmap_packer *packer) -{ - struct bitmap_packer old = *packer; - *packer = (struct bitmap_packer) { - .w_max = old.w_max, - .h_max = old.h_max, - }; - talloc_free_children(packer); -} - -void packer_get_bb(struct bitmap_packer *packer, struct pos out_bb[2]) -{ - out_bb[0] = (struct pos) {0}; - out_bb[1] = (struct pos) { - FFMIN(packer->used_width + packer->padding, packer->w), - FFMIN(packer->used_height + packer->padding, packer->h), - }; -} - -#define HEIGHT_SORT_BITS 4 -static int size_index(int s) -{ - int n = av_log2_16bit(s); - return (n << HEIGHT_SORT_BITS) - + (- 1 - (s << HEIGHT_SORT_BITS >> n) & (1 << HEIGHT_SORT_BITS) - 1); -} - -/* Pack the given rectangles into an area of size w * h. - * The size of each rectangle is read from in[i].x / in[i].y. - * The height of each rectangle must be less than 65536. - * 'scratch' must point to work memory for num_rects+16 ints. - * The packed position for rectangle number i is set in out[i]. - * Return 0 on success, -1 if the rectangles did not fit in w*h. - * - * The rectangles are placed in rows in order approximately sorted by - * height (the approximate sorting is simpler than a full one would be, - * and allows the algorithm to work in linear time). Additionally, to - * reduce wasted space when there are a few tall rectangles, empty - * lower-right parts of rows are filled recursively when the size of - * rectangles in the row drops past a power-of-two threshold. So if a - * row starts with rectangles of size 3x50, 10x40 and 5x20 then the - * free rectangle with corners (13, 20)-(w, 50) is filled recursively. - */ -static int pack_rectangles(struct pos *in, struct pos *out, int num_rects, - int w, int h, int *scratch, int *used_width) -{ - int bins[16 << HEIGHT_SORT_BITS]; - int sizes[16 << HEIGHT_SORT_BITS] = { 0 }; - for (int i = 0; i < num_rects; i++) - sizes[size_index(in[i].y)]++; - int idx = 0; - for (int i = 0; i < 16 << HEIGHT_SORT_BITS; i += 1 << HEIGHT_SORT_BITS) { - for (int j = 0; j < 1 << HEIGHT_SORT_BITS; j++) { - bins[i + j] = idx; - idx += sizes[i + j]; - } - scratch[idx++] = -1; - } - for (int i = 0; i < num_rects; i++) - scratch[bins[size_index(in[i].y)]++] = i; - for (int i = 0; i < 16; i++) - bins[i] = bins[i << HEIGHT_SORT_BITS] - sizes[i << HEIGHT_SORT_BITS]; - struct { - int size, x, bottom; - } stack[16] = {{15, 0, h}}, s = {}; - int stackpos = 1; - int y; - while (stackpos) { - y = s.bottom; - s = stack[--stackpos]; - s.size++; - while (s.size--) { - int maxy = -1; - int obj; - while ((obj = scratch[bins[s.size]]) >= 0) { - int bottom = y + in[obj].y; - if (bottom > s.bottom) - break; - int right = s.x + in[obj].x; - if (right > w) - break; - bins[s.size]++; - out[obj] = (struct pos){s.x, y}; - num_rects--; - if (maxy < 0) - stack[stackpos++] = s; - s.x = right; - maxy = FFMAX(maxy, bottom); - } - *used_width = FFMAX(*used_width, s.x); - if (maxy > 0) - s.bottom = maxy; - } - } - return num_rects ? -1 : y; -} - -int packer_pack(struct bitmap_packer *packer) -{ - if (packer->count == 0) - return 0; - int w_orig = packer->w, h_orig = packer->h; - struct pos *in = packer->in; - int xmax = 0, ymax = 0; - for (int i = 0; i < packer->count; i++) { - if (in[i].x <= packer->padding || in[i].y <= packer->padding) - in[i] = (struct pos){0, 0}; - if (in[i].x < 0 || in [i].x > 65535 || in[i].y < 0 || in[i].y > 65535) { - mp_msg(MSGT_VO, MSGL_FATAL, "Invalid OSD / subtitle bitmap size\n"); - abort(); - } - xmax = FFMAX(xmax, in[i].x); - ymax = FFMAX(ymax, in[i].y); - } - xmax = FFMAX(0, xmax - packer->padding); - ymax = FFMAX(0, ymax - packer->padding); - if (xmax > packer->w) - packer->w = 1 << av_log2(xmax - 1) + 1; - if (ymax > packer->h) - packer->h = 1 << av_log2(ymax - 1) + 1; - while (1) { - int used_width = 0; - int y = pack_rectangles(in, packer->result, packer->count, - packer->w + packer->padding, - packer->h + packer->padding, - packer->scratch, &used_width); - if (y >= 0) { - // No padding at edges - packer->used_width = FFMIN(used_width, packer->w); - packer->used_height = FFMIN(y, packer->h); - assert(packer->w == 0 || IS_POWER_OF_2(packer->w)); - assert(packer->h == 0 || IS_POWER_OF_2(packer->h)); - return packer->w != w_orig || packer->h != h_orig; - } - if (packer->w <= packer->h && packer->w != packer->w_max) - packer->w = FFMIN(packer->w * 2, packer->w_max); - else if (packer->h != packer->h_max) - packer->h = FFMIN(packer->h * 2, packer->h_max); - else { - packer->w = w_orig; - packer->h = h_orig; - return -1; - } - } -} - -void packer_set_size(struct bitmap_packer *packer, int size) -{ - packer->count = size; - if (size <= packer->asize) - return; - packer->asize = FFMAX(packer->asize * 2, size); - talloc_free(packer->result); - talloc_free(packer->scratch); - packer->in = talloc_realloc(packer, packer->in, struct pos, packer->asize); - packer->result = talloc_array_ptrtype(packer, packer->result, - packer->asize); - packer->scratch = talloc_array_ptrtype(packer, packer->scratch, - packer->asize + 16); -} - -int packer_pack_from_subbitmaps(struct bitmap_packer *packer, - struct sub_bitmaps *b) -{ - packer->count = 0; - if (b->format == SUBBITMAP_EMPTY) - return 0; - packer_set_size(packer, b->num_parts); - int a = packer->padding; - for (int i = 0; i < b->num_parts; i++) - packer->in[i] = (struct pos){b->parts[i].w + a, b->parts[i].h + a}; - return packer_pack(packer); -} - -void packer_copy_subbitmaps(struct bitmap_packer *packer, struct sub_bitmaps *b, - void *data, int pixel_stride, int stride) -{ - assert(packer->count == b->num_parts); - if (packer->padding) { - struct pos bb[2]; - packer_get_bb(packer, bb); - memset_pic(data, 0, bb[1].x * pixel_stride, bb[1].y, stride); - } - for (int n = 0; n < packer->count; n++) { - struct sub_bitmap *s = &b->parts[n]; - struct pos p = packer->result[n]; - - void *pdata = (uint8_t *)data + p.y * stride + p.x * pixel_stride; - memcpy_pic(pdata, s->bitmap, s->w * pixel_stride, s->h, - stride, s->stride); - } -} diff --git a/libvo/bitmap_packer.h b/libvo/bitmap_packer.h deleted file mode 100644 index b86c3ec4f9..0000000000 --- a/libvo/bitmap_packer.h +++ /dev/null @@ -1,68 +0,0 @@ -#ifndef MPLAYER_PACK_RECTANGLES_H -#define MPLAYER_PACK_RECTANGLES_H - -struct pos { - int x; - int y; -}; - -struct bitmap_packer { - int w; - int h; - int w_max; - int h_max; - int padding; - int count; - struct pos *in; - struct pos *result; - int used_width; - int used_height; - - // internal - int *scratch; - int asize; -}; - -struct ass_image; -struct sub_bitmaps; - -// Clear all internal state. Leave the following fields: w_max, h_max -void packer_reset(struct bitmap_packer *packer); - -// Get the bounding box used for bitmap data (including padding). -// The bounding box doesn't exceed (0,0)-(packer->w,packer->h). -void packer_get_bb(struct bitmap_packer *packer, struct pos out_bb[2]); - -/* Reallocate packer->in for at least to desired number of items. - * Also sets packer->count to the same value. - */ -void packer_set_size(struct bitmap_packer *packer, int size); - -/* To use this, set packer->count to number of rectangles, w_max and h_max - * to maximum output rectangle size, and w and h to start size (may be 0). - * Write input sizes in packer->in. - * Resulting packing will be written in packer->result. - * w and h will be increased if necessary for successful packing. - * There is a strong guarantee that w and h will be powers of 2 (or set to 0). - * Return value is -1 if packing failed because w and h were set to max - * values but that wasn't enough, 1 if w or h was increased, and 0 otherwise. - */ -int packer_pack(struct bitmap_packer *packer); - -/* Like above, but packer->count will be automatically set and - * packer->in will be reallocated if needed and filled from the - * given image list. - */ -int packer_pack_from_subbitmaps(struct bitmap_packer *packer, - struct sub_bitmaps *b); - -// Copy the (already packed) sub-bitmaps from b to the image in data. -// data must point to an image that is at least (packer->w, packer->h) big. -// The image has the given stride (bytes between (x, y) to (x, y + 1)), and the -// pixel format used by both the sub-bitmaps and the image uses pixel_stride -// bytes per pixel (bytes between (x, y) to (x + 1, y)). -// If packer->padding is set, the padding borders are cleared with 0. -void packer_copy_subbitmaps(struct bitmap_packer *packer, struct sub_bitmaps *b, - void *data, int pixel_stride, int stride); - -#endif diff --git a/libvo/cocoa_common.h b/libvo/cocoa_common.h deleted file mode 100644 index 079e497441..0000000000 --- a/libvo/cocoa_common.h +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Cocoa OpenGL Backend - * - * This file is part of mplayer2. - * - * mplayer2 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. - * - * mplayer2 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 mplayer2. If not, see <http://www.gnu.org/licenses/>. - */ - -#ifndef MPLAYER_COCOA_COMMON_H -#define MPLAYER_COCOA_COMMON_H - -#include "video_out.h" - -struct vo_cocoa_state; - -bool vo_cocoa_gui_running(void); -void *vo_cocoa_glgetaddr(const char *s); - -int vo_cocoa_init(struct vo *vo); -void vo_cocoa_uninit(struct vo *vo); - -void vo_cocoa_update_xinerama_info(struct vo *vo); - -int vo_cocoa_change_attributes(struct vo *vo); -int vo_cocoa_create_window(struct vo *vo, uint32_t d_width, - uint32_t d_height, uint32_t flags, - int gl3profile); - -void vo_cocoa_swap_buffers(struct vo *vo); -int vo_cocoa_check_events(struct vo *vo); -void vo_cocoa_fullscreen(struct vo *vo); -void vo_cocoa_ontop(struct vo *vo); -void vo_cocoa_pause(struct vo *vo); -void vo_cocoa_resume(struct vo *vo); - -// returns an int to conform to the gl extensions from other platforms -int vo_cocoa_swap_interval(int enabled); - -void *vo_cocoa_cgl_context(struct vo *vo); -void *vo_cocoa_cgl_pixel_format(struct vo *vo); - -int vo_cocoa_cgl_color_size(struct vo *vo); - -#endif /* MPLAYER_COCOA_COMMON_H */ diff --git a/libvo/cocoa_common.m b/libvo/cocoa_common.m deleted file mode 100644 index 337e0a32be..0000000000 --- a/libvo/cocoa_common.m +++ /dev/null @@ -1,865 +0,0 @@ -/* - * Cocoa OpenGL Backend - * - * This file is part of mplayer2. - * - * mplayer2 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. - * - * mplayer2 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 mplayer2. If not, see <http://www.gnu.org/licenses/>. - */ - -#import <Cocoa/Cocoa.h> -#import <CoreServices/CoreServices.h> // for CGDisplayHideCursor -#import <IOKit/pwr_mgt/IOPMLib.h> -#include <dlfcn.h> - -#include "cocoa_common.h" - -#include "config.h" - -#include "options.h" -#include "video_out.h" -#include "aspect.h" - -#include "mp_fifo.h" -#include "talloc.h" - -#include "input/input.h" -#include "input/keycodes.h" -#include "osx_common.h" -#include "mp_msg.h" - -#ifndef NSOpenGLPFAOpenGLProfile -#define NSOpenGLPFAOpenGLProfile 99 -#endif - -#ifndef NSOpenGLProfileVersionLegacy -#define NSOpenGLProfileVersionLegacy 0x1000 -#endif - -#ifndef NSOpenGLProfileVersion3_2Core -#define NSOpenGLProfileVersion3_2Core 0x3200 -#endif - -#define NSLeftAlternateKeyMask (0x000020 | NSAlternateKeyMask) -#define NSRightAlternateKeyMask (0x000040 | NSAlternateKeyMask) - -// add methods not available on OSX versions prior to 10.7 -#ifndef MAC_OS_X_VERSION_10_7 -@interface NSView (IntroducedInLion) -- (NSRect)convertRectToBacking:(NSRect)aRect; -- (void)setWantsBestResolutionOpenGLSurface:(BOOL)aBool; -@end -#endif - -// add power management assertion not available on OSX versions prior to 10.7 -#ifndef kIOPMAssertionTypePreventUserIdleDisplaySleep -#define kIOPMAssertionTypePreventUserIdleDisplaySleep \ - CFSTR("PreventUserIdleDisplaySleep") -#endif - -@interface GLMPlayerWindow : NSWindow <NSWindowDelegate> { - struct vo *_vo; -} -- (void)setVideoOutput:(struct vo *)vo; -- (BOOL)canBecomeKeyWindow; -- (BOOL)canBecomeMainWindow; -- (void)fullscreen; -- (void)mouseEvent:(NSEvent *)theEvent; -- (void)mulSize:(float)multiplier; -- (void)setContentSize:(NSSize)newSize keepCentered:(BOOL)keepCentered; -@end - -@interface GLMPlayerOpenGLView : NSView -@end - -struct vo_cocoa_state { - NSAutoreleasePool *pool; - GLMPlayerWindow *window; - NSOpenGLContext *glContext; - NSOpenGLPixelFormat *pixelFormat; - - NSSize current_video_size; - NSSize previous_video_size; - - NSRect screen_frame; - NSScreen *screen_handle; - NSArray *screen_array; - - NSInteger windowed_mask; - NSInteger fullscreen_mask; - - NSRect windowed_frame; - - NSString *window_title; - - NSInteger window_level; - NSInteger fullscreen_window_level; - - int display_cursor; - int cursor_timer; - int cursor_autohide_delay; - - bool did_resize; - bool out_fs_resize; - - IOPMAssertionID power_mgmt_assertion; -}; - -static int _instances = 0; - -static void create_menu(void); - -static struct vo_cocoa_state *vo_cocoa_init_state(struct vo *vo) -{ - struct vo_cocoa_state *s = talloc_ptrtype(vo, s); - *s = (struct vo_cocoa_state){ - .pool = [[NSAutoreleasePool alloc] init], - .did_resize = NO, - .current_video_size = {0,0}, - .previous_video_size = {0,0}, - .windowed_mask = NSTitledWindowMask|NSClosableWindowMask| - NSMiniaturizableWindowMask|NSResizableWindowMask, - .fullscreen_mask = NSBorderlessWindowMask, - .windowed_frame = {{0,0},{0,0}}, - .out_fs_resize = NO, - .display_cursor = 1, - .cursor_autohide_delay = vo->opts->cursor_autohide_delay, - .power_mgmt_assertion = kIOPMNullAssertionID, - }; - return s; -} - -static bool supports_hidpi(NSView *view) -{ - SEL hdpi_selector = @selector(setWantsBestResolutionOpenGLSurface:); - return is_osx_version_at_least(10, 7, 0) && view && - [view respondsToSelector:hdpi_selector]; -} - -bool vo_cocoa_gui_running(void) -{ - return _instances > 0; -} - -void *vo_cocoa_glgetaddr(const char *s) -{ - void *ret = NULL; - void *handle = dlopen( - "/System/Library/Frameworks/OpenGL.framework/OpenGL", - RTLD_LAZY | RTLD_LOCAL); - if (!handle) - return NULL; - ret = dlsym(handle, s); - dlclose(handle); - return ret; -} - -static void enable_power_management(struct vo *vo) -{ - struct vo_cocoa_state *s = vo->cocoa; - if (!s->power_mgmt_assertion) return; - IOPMAssertionRelease(s->power_mgmt_assertion); - s->power_mgmt_assertion = kIOPMNullAssertionID; -} - -static void disable_power_management(struct vo *vo) -{ - struct vo_cocoa_state *s = vo->cocoa; - if (s->power_mgmt_assertion) return; - - CFStringRef assertion_type = kIOPMAssertionTypeNoDisplaySleep; - if (is_osx_version_at_least(10, 7, 0)) - assertion_type = kIOPMAssertionTypePreventUserIdleDisplaySleep; - - IOPMAssertionCreateWithName(assertion_type, kIOPMAssertionLevelOn, - CFSTR("org.mplayer2.power_mgmt"), &s->power_mgmt_assertion); -} - -int vo_cocoa_init(struct vo *vo) -{ - vo->cocoa = vo_cocoa_init_state(vo); - _instances++; - - NSApplicationLoad(); - NSApp = [NSApplication sharedApplication]; - [NSApp setActivationPolicy: NSApplicationActivationPolicyRegular]; - disable_power_management(vo); - - return 1; -} - -void vo_cocoa_uninit(struct vo *vo) -{ - struct vo_cocoa_state *s = vo->cocoa; - CGDisplayShowCursor(kCGDirectMainDisplay); - enable_power_management(vo); - [NSApp setPresentationOptions:NSApplicationPresentationDefault]; - - [s->window release]; - s->window = nil; - [s->glContext release]; - s->glContext = nil; - [s->pool release]; - s->pool = nil; - - _instances--; -} - -void vo_cocoa_pause(struct vo *vo) -{ - enable_power_management(vo); -} - -void vo_cocoa_resume(struct vo *vo) -{ - disable_power_management(vo); -} - -static int current_screen_has_dock_or_menubar(struct vo *vo) -{ - struct vo_cocoa_state *s = vo->cocoa; - NSRect f = s->screen_frame; - NSRect vf = [s->screen_handle visibleFrame]; - return f.size.height > vf.size.height || f.size.width > vf.size.width; -} - -static void update_screen_info(struct vo *vo) -{ - struct vo_cocoa_state *s = vo->cocoa; - s->screen_array = [NSScreen screens]; - if (xinerama_screen >= (int)[s->screen_array count]) { - mp_msg(MSGT_VO, MSGL_INFO, "[cocoa] Device ID %d does not exist, " - "falling back to main device\n", xinerama_screen); - xinerama_screen = -1; - } - - if (xinerama_screen < 0) { // default behaviour - if (! (s->screen_handle = [s->window screen]) ) - s->screen_handle = [s->screen_array objectAtIndex:0]; - } else { - s->screen_handle = [s->screen_array objectAtIndex:(xinerama_screen)]; - } - - s->screen_frame = [s->screen_handle frame]; -} - -void vo_cocoa_update_xinerama_info(struct vo *vo) -{ - struct vo_cocoa_state *s = vo->cocoa; - struct MPOpts *opts = vo->opts; - - update_screen_info(vo); - aspect_save_screenres(vo, s->screen_frame.size.width, - s->screen_frame.size.height); - opts->vo_screenwidth = s->screen_frame.size.width; - opts->vo_screenheight = s->screen_frame.size.height; - xinerama_x = s->screen_frame.origin.x; - xinerama_y = s->screen_frame.origin.y; -} - -int vo_cocoa_change_attributes(struct vo *vo) -{ - return 0; -} - -static void resize_window(struct vo *vo) -{ - struct vo_cocoa_state *s = vo->cocoa; - NSView *view = [s->window contentView]; - NSRect frame; - - if (supports_hidpi(view)) { - frame = [view convertRectToBacking: [view frame]]; - } else { - frame = [view frame]; - } - - vo->dwidth = frame.size.width; - vo->dheight = frame.size.height; - [s->glContext update]; -} - -static void vo_set_level(struct vo *vo, int ontop) -{ - struct vo_cocoa_state *s = vo->cocoa; - if (ontop) { - s->window_level = NSNormalWindowLevel + 1; - } else { - s->window_level = NSNormalWindowLevel; - } - - if (!vo_fs) - [s->window setLevel:s->window_level]; -} - -void vo_cocoa_ontop(struct vo *vo) -{ - struct MPOpts *opts = vo->opts; - opts->vo_ontop = !opts->vo_ontop; - vo_set_level(vo, opts->vo_ontop); -} - -static void update_state_sizes(struct vo_cocoa_state *s, - uint32_t d_width, uint32_t d_height) -{ - if (s->current_video_size.width > 0 || s->current_video_size.height > 0) - s->previous_video_size = s->current_video_size; - s->current_video_size = NSMakeSize(d_width, d_height); -} - -static int create_window(struct vo *vo, uint32_t d_width, uint32_t d_height, - uint32_t flags, int gl3profile) -{ - struct vo_cocoa_state *s = vo->cocoa; - struct MPOpts *opts = vo->opts; - - const NSRect window_rect = NSMakeRect(0, 0, d_width, d_height); - const NSRect glview_rect = NSMakeRect(0, 0, 100, 100); - - s->window = - [[GLMPlayerWindow alloc] initWithContentRect:window_rect - styleMask:s->windowed_mask - backing:NSBackingStoreBuffered - defer:NO]; - - GLMPlayerOpenGLView *glView = - [[GLMPlayerOpenGLView alloc] initWithFrame:glview_rect]; - - // check for HiDPI support and enable it (available on 10.7 +) - if (supports_hidpi(glView)) - [glView setWantsBestResolutionOpenGLSurface:YES]; - - int i = 0; - NSOpenGLPixelFormatAttribute attr[32]; - if (is_osx_version_at_least(10, 7, 0)) { - attr[i++] = NSOpenGLPFAOpenGLProfile; - if (gl3profile) { - attr[i++] = NSOpenGLProfileVersion3_2Core; - } else { - attr[i++] = NSOpenGLProfileVersionLegacy; - } - } else if(gl3profile) { - mp_msg(MSGT_VO, MSGL_ERR, - "[cocoa] Invalid pixel format attribute " - "(GL3 is not supported on OSX versions prior to 10.7)\n"); - return -1; - } - attr[i++] = NSOpenGLPFADoubleBuffer; // double buffered - attr[i] = (NSOpenGLPixelFormatAttribute)0; - - s->pixelFormat = - [[[NSOpenGLPixelFormat alloc] initWithAttributes:attr] autorelease]; - if (!s->pixelFormat) { - mp_msg(MSGT_VO, MSGL_ERR, - "[cocoa] Invalid pixel format attribute " - "(GL3 not supported?)\n"); - return -1; - } - s->glContext = - [[NSOpenGLContext alloc] initWithFormat:s->pixelFormat - shareContext:nil]; - - create_menu(); - - [s->window setContentView:glView]; - [glView release]; - [s->window setAcceptsMouseMovedEvents:YES]; - [s->glContext setView:glView]; - [s->glContext makeCurrentContext]; - [s->window setVideoOutput:vo]; - - [NSApp setDelegate:s->window]; - [s->window setDelegate:s->window]; - [s->window setContentSize:s->current_video_size]; - [s->window setContentAspectRatio:s->current_video_size]; - [s->window setFrameOrigin:NSMakePoint(vo->dx, vo->dy)]; - - if (flags & VOFLAG_HIDDEN) { - [s->window orderOut:nil]; - } else { - [s->window makeKeyAndOrderFront:nil]; - [NSApp activateIgnoringOtherApps:YES]; - } - - if (flags & VOFLAG_FULLSCREEN) - vo_cocoa_fullscreen(vo); - - vo_set_level(vo, opts->vo_ontop); - - return 0; -} - -static void update_window(struct vo *vo) -{ - struct vo_cocoa_state *s = vo->cocoa; - - if (s->current_video_size.width != s->previous_video_size.width || - s->current_video_size.height != s->previous_video_size.height) { - if (vo_fs) { - // we will resize as soon as we get out of fullscreen - s->out_fs_resize = YES; - } else { - // only if we are not in fullscreen and the video size did - // change we resize the window and set a new aspect ratio - [s->window setContentSize:s->current_video_size - keepCentered:YES]; - [s->window setContentAspectRatio:s->current_video_size]; - } - } -} - -int vo_cocoa_create_window(struct vo *vo, uint32_t d_width, - uint32_t d_height, uint32_t flags, - int gl3profile) -{ - struct vo_cocoa_state *s = vo->cocoa; - - update_state_sizes(s, d_width, d_height); - - if (!(s->window || s->glContext)) { - if (create_window(vo, d_width, d_height, flags, gl3profile) < 0) - return -1; - } else { - update_window(vo); - } - - resize_window(vo); - - if (s->window_title) - [s->window_title release]; - - s->window_title = - [[NSString alloc] initWithUTF8String:vo_get_window_title(vo)]; - [s->window setTitle: s->window_title]; - - return 0; -} - -void vo_cocoa_swap_buffers(struct vo *vo) -{ - struct vo_cocoa_state *s = vo->cocoa; - [s->glContext flushBuffer]; -} - -static void vo_cocoa_display_cursor(struct vo *vo, int requested_state) -{ - struct vo_cocoa_state *s = vo->cocoa; - if (requested_state) { - if (!vo_fs || s->cursor_autohide_delay > -2) { - s->display_cursor = requested_state; - CGDisplayShowCursor(kCGDirectMainDisplay); - } - } else { - if (s->cursor_autohide_delay != -1) { - s->display_cursor = requested_state; - CGDisplayHideCursor(kCGDirectMainDisplay); - } - } -} - -int vo_cocoa_check_events(struct vo *vo) -{ - struct vo_cocoa_state *s = vo->cocoa; - NSEvent *event; - int ms_time = (int) ([[NSProcessInfo processInfo] systemUptime] * 1000); - - // automatically hide mouse cursor - if (vo_fs && s->display_cursor && - (ms_time - s->cursor_timer >= s->cursor_autohide_delay)) { - vo_cocoa_display_cursor(vo, 0); - s->cursor_timer = ms_time; - } - - event = [NSApp nextEventMatchingMask:NSAnyEventMask untilDate:nil - inMode:NSEventTrackingRunLoopMode dequeue:YES]; - if (event == nil) - return 0; - [NSApp sendEvent:event]; - - if (s->did_resize) { - s->did_resize = NO; - resize_window(vo); - return VO_EVENT_RESIZE; - } - // Without SDL's bootstrap code (include SDL.h in mplayer.c), - // on Leopard, we have trouble to get the play window automatically focused - // when the app is actived. The Following code fix this problem. - if ([event type] == NSAppKitDefined - && [event subtype] == NSApplicationActivatedEventType) { - [s->window makeMainWindow]; - [s->window makeKeyAndOrderFront:nil]; - } - return 0; -} - -void vo_cocoa_fullscreen(struct vo *vo) -{ - struct vo_cocoa_state *s = vo->cocoa; - [s->window fullscreen]; - resize_window(vo); -} - -int vo_cocoa_swap_interval(int enabled) -{ - [[NSOpenGLContext currentContext] setValues:&enabled - forParameter:NSOpenGLCPSwapInterval]; - return 0; -} - -void *vo_cocoa_cgl_context(struct vo *vo) -{ - struct vo_cocoa_state *s = vo->cocoa; - return [s->glContext CGLContextObj]; -} - -void *vo_cocoa_cgl_pixel_format(struct vo *vo) -{ - return CGLGetPixelFormat(vo_cocoa_cgl_context(vo)); -} - -int vo_cocoa_cgl_color_size(struct vo *vo) -{ - GLint value; - CGLDescribePixelFormat(vo_cocoa_cgl_pixel_format(vo), 0, - kCGLPFAColorSize, &value); - switch (value) { - case 32: - case 24: - return 8; - case 16: - return 5; - } - - return 8; -} - -static NSMenuItem *new_menu_item(NSMenu *parent_menu, NSString *title, - SEL action, NSString *key_equivalent) -{ - NSMenuItem *new_item = - [[NSMenuItem alloc] initWithTitle:title action:action - keyEquivalent:key_equivalent]; - [parent_menu addItem:new_item]; - return [new_item autorelease]; -} - -static NSMenuItem *new_main_menu_item(NSMenu *parent_menu, NSMenu *child_menu, - NSString *title) -{ - NSMenuItem *new_item = - [[NSMenuItem alloc] initWithTitle:title action:nil - keyEquivalent:@""]; - [new_item setSubmenu:child_menu]; - [parent_menu addItem:new_item]; - return [new_item autorelease]; -} - -void create_menu() -{ - NSAutoreleasePool *pool = [NSAutoreleasePool new]; - NSMenu *main_menu, *m_menu, *w_menu; - NSMenuItem *app_menu_item; - - main_menu = [[NSMenu new] autorelease]; - app_menu_item = [[NSMenuItem new] autorelease]; - [main_menu addItem:app_menu_item]; - [NSApp setMainMenu: main_menu]; - - m_menu = [[[NSMenu alloc] initWithTitle:@"Movie"] autorelease]; - new_menu_item(m_menu, @"Half Size", @selector(halfSize), @"0"); - new_menu_item(m_menu, @"Normal Size", @selector(normalSize), @"1"); - new_menu_item(m_menu, @"Double Size", @selector(doubleSize), @"2"); - - new_main_menu_item(main_menu, m_menu, @"Movie"); - - w_menu = [[[NSMenu alloc] initWithTitle:@"Window"] autorelease]; - new_menu_item(w_menu, @"Minimize", @selector(performMiniaturize:), @"m"); - new_menu_item(w_menu, @"Zoom", @selector(performZoom:), @"z"); - - new_main_menu_item(main_menu, w_menu, @"Window"); - [pool release]; -} - -@implementation GLMPlayerWindow -- (void)setVideoOutput:(struct vo *)vo -{ - _vo = vo; -} - -- (void)windowDidResize:(NSNotification *) notification -{ - if (_vo) { - struct vo_cocoa_state *s = _vo->cocoa; - s->did_resize = YES; - } -} - -- (void)fullscreen -{ - struct vo_cocoa_state *s = _vo->cocoa; - if (!vo_fs) { - update_screen_info(_vo); - if (current_screen_has_dock_or_menubar(_vo)) - [NSApp setPresentationOptions:NSApplicationPresentationHideDock| - NSApplicationPresentationHideMenuBar]; - s->windowed_frame = [self frame]; - [self setHasShadow:NO]; - [self setStyleMask:s->fullscreen_mask]; - [self setFrame:s->screen_frame display:YES animate:NO]; - vo_fs = VO_TRUE; - vo_cocoa_display_cursor(_vo, 0); - [self setMovableByWindowBackground: NO]; - } else { - [NSApp setPresentationOptions:NSApplicationPresentationDefault]; - [self setHasShadow:YES]; - [self setStyleMask:s->windowed_mask]; - [self setTitle:s->window_title]; - [self setFrame:s->windowed_frame display:YES animate:NO]; - if (s->out_fs_resize) { - [self setContentSize:s->current_video_size keepCentered:YES]; - s->out_fs_resize = NO; - } - [self setContentAspectRatio:s->current_video_size]; - vo_fs = VO_FALSE; - vo_cocoa_display_cursor(_vo, 1); - [self setMovableByWindowBackground: YES]; - } -} - -- (BOOL)canBecomeMainWindow { return YES; } -- (BOOL)canBecomeKeyWindow { return YES; } -- (BOOL)acceptsFirstResponder { return YES; } -- (BOOL)becomeFirstResponder { return YES; } -- (BOOL)resignFirstResponder { return YES; } -- (BOOL)windowShouldClose:(id)sender -{ - mplayer_put_key(_vo->key_fifo, KEY_CLOSE_WIN); - // We have to wait for MPlayer to handle this, - // otherwise we are in trouble if the - // KEY_CLOSE_WIN handler is disabled - return NO; -} - -- (BOOL)isMovableByWindowBackground -{ - // this is only valid as a starting value. it will be rewritten in the - // -fullscreen method. - return !vo_fs; -} - -- (void)handleQuitEvent:(NSAppleEventDescriptor*)e - withReplyEvent:(NSAppleEventDescriptor*)r -{ - mplayer_put_key(_vo->key_fifo, KEY_CLOSE_WIN); -} - -- (void)keyDown:(NSEvent *)theEvent -{ - unsigned char charcode; - if (([theEvent modifierFlags] & NSRightAlternateKeyMask) == - NSRightAlternateKeyMask) - charcode = *[[theEvent characters] UTF8String]; - else - charcode = [[theEvent charactersIgnoringModifiers] characterAtIndex:0]; - - int key = convert_key([theEvent keyCode], charcode); - - if (key > -1) { - if ([theEvent modifierFlags] & NSShiftKeyMask) - key |= KEY_MODIFIER_SHIFT; - if ([theEvent modifierFlags] & NSControlKeyMask) - key |= KEY_MODIFIER_CTRL; - if (([theEvent modifierFlags] & NSLeftAlternateKeyMask) == - NSLeftAlternateKeyMask) - key |= KEY_MODIFIER_ALT; - if ([theEvent modifierFlags] & NSCommandKeyMask) - key |= KEY_MODIFIER_META; - mplayer_put_key(_vo->key_fifo, key); - } -} - -- (void)mouseMoved: (NSEvent *) theEvent -{ - if (vo_fs) - vo_cocoa_display_cursor(_vo, 1); -} - -- (void)mouseDragged:(NSEvent *)theEvent -{ - [self mouseEvent: theEvent]; -} - -- (void)mouseDown:(NSEvent *)theEvent -{ - [self mouseEvent: theEvent]; -} - -- (void)mouseUp:(NSEvent *)theEvent -{ - [self mouseEvent: theEvent]; -} - -- (void)rightMouseDown:(NSEvent *)theEvent -{ - [self mouseEvent: theEvent]; -} - -- (void)rightMouseUp:(NSEvent *)theEvent -{ - [self mouseEvent: theEvent]; -} - -- (void)otherMouseDown:(NSEvent *)theEvent -{ - [self mouseEvent: theEvent]; -} - -- (void)otherMouseUp:(NSEvent *)theEvent -{ - [self mouseEvent: theEvent]; -} - -- (void)scrollWheel:(NSEvent *)theEvent -{ - if ([theEvent deltaY] > 0) - mplayer_put_key(_vo->key_fifo, MOUSE_BTN3); - else - mplayer_put_key(_vo->key_fifo, MOUSE_BTN4); -} - -- (void)mouseEvent:(NSEvent *)theEvent -{ - if ([theEvent buttonNumber] >= 0 && [theEvent buttonNumber] <= 9) { - int buttonNumber = [theEvent buttonNumber]; - // Fix to mplayer defined button order: left, middle, right - if (buttonNumber == 1) buttonNumber = 2; - else if (buttonNumber == 2) buttonNumber = 1; - switch ([theEvent type]) { - case NSLeftMouseDown: - case NSRightMouseDown: - case NSOtherMouseDown: - mplayer_put_key(_vo->key_fifo, - (MOUSE_BTN0 + buttonNumber) | MP_KEY_DOWN); - // Looks like Cocoa doesn't create MouseUp events when we are - // doing the second click in a double click. Put in the key_fifo - // the key that would be put from the MouseUp handling code. - if([theEvent clickCount] == 2) - mplayer_put_key(_vo->key_fifo, MOUSE_BTN0 + buttonNumber); - break; - case NSLeftMouseUp: - case NSRightMouseUp: - case NSOtherMouseUp: - mplayer_put_key(_vo->key_fifo, MOUSE_BTN0 + buttonNumber); - break; - } - } -} - -- (void)applicationWillBecomeActive:(NSNotification *)aNotification -{ - if (vo_fs && current_screen_has_dock_or_menubar(_vo)) { - [NSApp setPresentationOptions:NSApplicationPresentationHideDock| - NSApplicationPresentationHideMenuBar]; - } -} - -- (void)applicationWillResignActive:(NSNotification *)aNotification -{ - if (vo_fs) { - [NSApp setPresentationOptions:NSApplicationPresentationDefault]; - } -} - -- (void)applicationDidFinishLaunching:(NSNotification*)notification -{ - // Install an event handler so the Quit menu entry works - // The proper way using NSApp setDelegate: and - // applicationShouldTerminate: does not work, - // probably NSApplication never installs its handler. - [[NSAppleEventManager sharedAppleEventManager] - setEventHandler:self - andSelector:@selector(handleQuitEvent:withReplyEvent:) - forEventClass:kCoreEventClass - andEventID:kAEQuitApplication]; -} - -- (void)normalSize -{ - struct vo_cocoa_state *s = _vo->cocoa; - if (!vo_fs) - [self setContentSize:s->current_video_size keepCentered:YES]; -} - -- (void)halfSize { [self mulSize:0.5f];} - -- (void)doubleSize { [self mulSize:2.0f];} - -- (void)mulSize:(float)multiplier -{ - if (!vo_fs) { - struct vo_cocoa_state *s = _vo->cocoa; - NSSize size = [[self contentView] frame].size; - size.width = s->current_video_size.width * (multiplier); - size.height = s->current_video_size.height * (multiplier); - [self setContentSize:size keepCentered:YES]; - } -} - -- (void)setCenteredContentSize:(NSSize)ns -{ - NSRect nf = [self frame]; - NSRect vf = [[self screen] visibleFrame]; - NSRect cb = [[self contentView] bounds]; - int title_height = nf.size.height - cb.size.height; - double ratio = (double)ns.width / (double)ns.height; - - // clip the new size to the visibleFrame's size if needed - if (ns.width > vf.size.width || ns.height + title_height > vf.size.height) { - ns = vf.size; - ns.height -= title_height; // make space for the title bar - - if (ns.width > ns.height) { - ns.height = ((double)ns.width * 1/ratio + 0.5); - } else { - ns.width = ((double)ns.height * ratio + 0.5); - } - } - - int dw = nf.size.width - ns.width; - int dh = nf.size.height - ns.height - title_height; - - nf.origin.x += dw / 2; - nf.origin.y += dh / 2; - - NSRect new_frame = - NSMakeRect(nf.origin.x, nf.origin.y, ns.width, ns.height + title_height); - [self setFrame:new_frame display:YES animate:NO]; -} - -- (void)setContentSize:(NSSize)ns keepCentered:(BOOL)keepCentered -{ - if (keepCentered) { - [self setCenteredContentSize:ns]; - } else { - [self setContentSize:ns]; - } -} -@end - -@implementation GLMPlayerOpenGLView -- (void)drawRect: (NSRect)rect -{ - [[NSColor clearColor] set]; - NSRectFill([self bounds]); -} -@end diff --git a/libvo/csputils.c b/libvo/csputils.c deleted file mode 100644 index 23eb099f69..0000000000 --- a/libvo/csputils.c +++ /dev/null @@ -1,391 +0,0 @@ -/* - * Common code related to colorspaces and conversion - * - * Copyleft (C) 2009 Reimar Döffinger <Reimar.Doeffinger@gmx.de> - * - * mp_invert_yuv2rgb based on DarkPlaces engine, original code (GPL2 or later) - * - * 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. - * - * You can alternatively redistribute this file and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - */ - -#include <stdint.h> -#include <math.h> -#include <assert.h> -#include <libavutil/common.h> - -#include "csputils.h" - -char * const mp_csp_names[MP_CSP_COUNT] = { - "Autoselect", - "BT.601 (SD)", - "BT.709 (HD)", - "SMPTE-240M", - "RGB", -}; - -char * const mp_csp_equalizer_names[MP_CSP_EQ_COUNT] = { - "brightness", - "contrast", - "hue", - "saturation", - "gamma", -}; - -enum mp_csp avcol_spc_to_mp_csp(enum AVColorSpace colorspace) -{ - switch (colorspace) { - case AVCOL_SPC_BT709: return MP_CSP_BT_709; - case AVCOL_SPC_BT470BG: return MP_CSP_BT_601; - case AVCOL_SPC_SMPTE170M: return MP_CSP_BT_601; - case AVCOL_SPC_SMPTE240M: return MP_CSP_SMPTE_240M; - case AVCOL_SPC_RGB: return MP_CSP_RGB; - default: return MP_CSP_AUTO; - } -} - -enum mp_csp_levels avcol_range_to_mp_csp_levels(enum AVColorRange range) -{ - switch (range) { - case AVCOL_RANGE_MPEG: return MP_CSP_LEVELS_TV; - case AVCOL_RANGE_JPEG: return MP_CSP_LEVELS_PC; - default: return MP_CSP_LEVELS_AUTO; - } -} - -enum AVColorSpace mp_csp_to_avcol_spc(enum mp_csp colorspace) -{ - switch (colorspace) { - case MP_CSP_BT_709: return AVCOL_SPC_BT709; - case MP_CSP_BT_601: return AVCOL_SPC_BT470BG; - case MP_CSP_SMPTE_240M: return AVCOL_SPC_SMPTE240M; - case MP_CSP_RGB: return AVCOL_SPC_RGB; - default: return AVCOL_SPC_UNSPECIFIED; - } -} - -enum AVColorRange mp_csp_levels_to_avcol_range(enum mp_csp_levels range) -{ - switch (range) { - case MP_CSP_LEVELS_TV: return AVCOL_RANGE_MPEG; - case MP_CSP_LEVELS_PC: return AVCOL_RANGE_JPEG; - default: return AVCOL_RANGE_UNSPECIFIED; - } -} - -enum mp_csp mp_csp_guess_colorspace(int width, int height) -{ - return width >= 1280 || height > 576 ? MP_CSP_BT_709 : MP_CSP_BT_601; -} - -/** - * \brief little helper function to create a lookup table for gamma - * \param map buffer to create map into - * \param size size of buffer - * \param gamma gamma value - */ -void mp_gen_gamma_map(uint8_t *map, int size, float gamma) -{ - if (gamma == 1.0) { - for (int i = 0; i < size; i++) - map[i] = 255 * i / (size - 1); - return; - } - gamma = 1.0 / gamma; - for (int i = 0; i < size; i++) { - float tmp = (float)i / (size - 1.0); - tmp = pow(tmp, gamma); - if (tmp > 1.0) - tmp = 1.0; - if (tmp < 0.0) - tmp = 0.0; - map[i] = 255 * tmp; - } -} - -/* Fill in the Y, U, V vectors of a yuv2rgb conversion matrix - * based on the given luma weights of the R, G and B components (lr, lg, lb). - * lr+lg+lb is assumed to equal 1. - * This function is meant for colorspaces satisfying the following - * conditions (which are true for common YUV colorspaces): - * - The mapping from input [Y, U, V] to output [R, G, B] is linear. - * - Y is the vector [1, 1, 1]. (meaning input Y component maps to 1R+1G+1B) - * - U maps to a value with zero R and positive B ([0, x, y], y > 0; - * i.e. blue and green only). - * - V maps to a value with zero B and positive R ([x, y, 0], x > 0; - * i.e. red and green only). - * - U and V are orthogonal to the luma vector [lr, lg, lb]. - * - The magnitudes of the vectors U and V are the minimal ones for which - * the image of the set Y=[0...1],U=[-0.5...0.5],V=[-0.5...0.5] under the - * conversion function will cover the set R=[0...1],G=[0...1],B=[0...1] - * (the resulting matrix can be converted for other input/output ranges - * outside this function). - * Under these conditions the given parameters lr, lg, lb uniquely - * determine the mapping of Y, U, V to R, G, B. - */ -static void luma_coeffs(float m[3][4], float lr, float lg, float lb) -{ - assert(fabs(lr+lg+lb - 1) < 1e-6); - m[0][0] = m[1][0] = m[2][0] = 1; - m[0][1] = 0; - m[1][1] = -2 * (1-lb) * lb/lg; - m[2][1] = 2 * (1-lb); - m[0][2] = 2 * (1-lr); - m[1][2] = -2 * (1-lr) * lr/lg; - m[2][2] = 0; - // Constant coefficients (m[x][3]) not set here -} - -/** - * \brief get the coefficients of the yuv -> rgb conversion matrix - * \param params struct specifying the properties of the conversion like - * brightness, ... - * \param m array to store coefficients into - */ -void mp_get_yuv2rgb_coeffs(struct mp_csp_params *params, float m[3][4]) -{ - int format = params->colorspace.format; - if (format <= MP_CSP_AUTO || format >= MP_CSP_COUNT) - format = MP_CSP_BT_601; - switch (format) { - case MP_CSP_BT_601: luma_coeffs(m, 0.299, 0.587, 0.114 ); break; - case MP_CSP_BT_709: luma_coeffs(m, 0.2126, 0.7152, 0.0722); break; - case MP_CSP_SMPTE_240M: luma_coeffs(m, 0.2122, 0.7013, 0.0865); break; - default: - abort(); - }; - - // Hue is equivalent to rotating input [U, V] subvector around the origin. - // Saturation scales [U, V]. - float huecos = params->saturation * cos(params->hue); - float huesin = params->saturation * sin(params->hue); - for (int i = 0; i < 3; i++) { - float u = m[i][COL_U]; - m[i][COL_U] = huecos * u - huesin * m[i][COL_V]; - m[i][COL_V] = huesin * u + huecos * m[i][COL_V]; - } - - int levels_in = params->colorspace.levels_in; - if (levels_in <= MP_CSP_LEVELS_AUTO || levels_in >= MP_CSP_LEVELS_COUNT) - levels_in = MP_CSP_LEVELS_TV; - assert(params->input_bits >= 8); - assert(params->texture_bits >= params->input_bits); - double s = (1 << params->input_bits-8) / ((1<<params->texture_bits)-1.); - // The values below are written in 0-255 scale - struct yuvlevels { double ymin, ymax, cmin, cmid; } - yuvlim = { 16*s, 235*s, 16*s, 128*s }, - yuvfull = { 0*s, 255*s, 1*s, 128*s }, // '1' for symmetry around 128 - yuvlev; - switch (levels_in) { - case MP_CSP_LEVELS_TV: yuvlev = yuvlim; break; - case MP_CSP_LEVELS_PC: yuvlev = yuvfull; break; - default: - abort(); - } - - int levels_out = params->colorspace.levels_out; - if (levels_out <= MP_CSP_LEVELS_AUTO || levels_out >= MP_CSP_LEVELS_COUNT) - levels_out = MP_CSP_LEVELS_PC; - struct rgblevels { double min, max; } - rgblim = { 16/255., 235/255. }, - rgbfull = { 0, 1 }, - rgblev; - switch (levels_out) { - case MP_CSP_LEVELS_TV: rgblev = rgblim; break; - case MP_CSP_LEVELS_PC: rgblev = rgbfull; break; - default: - abort(); - } - - double ymul = (rgblev.max - rgblev.min) / (yuvlev.ymax - yuvlev.ymin); - double cmul = (rgblev.max - rgblev.min) / (yuvlev.cmid - yuvlev.cmin) / 2; - for (int i = 0; i < 3; i++) { - m[i][COL_Y] *= ymul; - m[i][COL_U] *= cmul; - m[i][COL_V] *= cmul; - // Set COL_C so that Y=umin,UV=cmid maps to RGB=min (black to black) - m[i][COL_C] = rgblev.min - m[i][COL_Y] * yuvlev.ymin - -(m[i][COL_U] + m[i][COL_V]) * yuvlev.cmid; - } - - // Brightness adds a constant to output R,G,B. - // Contrast scales Y around 1/2 (not 0 in this implementation). - for (int i = 0; i < 3; i++) { - m[i][COL_C] += params->brightness; - m[i][COL_Y] *= params->contrast; - m[i][COL_C] += (rgblev.max-rgblev.min) * (1 - params->contrast)/2; - } - - int in_bits = FFMAX(params->int_bits_in, 1); - int out_bits = FFMAX(params->int_bits_out, 1); - double in_scale = (1 << in_bits) - 1.0; - double out_scale = (1 << out_bits) - 1.0; - for (int i = 0; i < 3; i++) { - m[i][COL_C] *= out_scale; // constant is 1.0 - for (int x = 0; x < 3; x++) - m[i][x] *= out_scale / in_scale; - } -} - -//! size of gamma map use to avoid slow exp function in gen_yuv2rgb_map -#define GMAP_SIZE (1024) -/** - * \brief generate a 3D YUV -> RGB map - * \param params struct containing parameters like brightness, gamma, ... - * \param map where to store map. Must provide space for (size + 2)^3 elements - * \param size size of the map, excluding border - */ -void mp_gen_yuv2rgb_map(struct mp_csp_params *params, unsigned char *map, int size) -{ - int i, j, k, l; - float step = 1.0 / size; - float y, u, v; - float yuv2rgb[3][4]; - unsigned char gmaps[3][GMAP_SIZE]; - mp_gen_gamma_map(gmaps[0], GMAP_SIZE, params->rgamma); - mp_gen_gamma_map(gmaps[1], GMAP_SIZE, params->ggamma); - mp_gen_gamma_map(gmaps[2], GMAP_SIZE, params->bgamma); - mp_get_yuv2rgb_coeffs(params, yuv2rgb); - for (i = 0; i < 3; i++) - for (j = 0; j < 4; j++) - yuv2rgb[i][j] *= GMAP_SIZE - 1; - v = 0; - for (i = -1; i <= size; i++) { - u = 0; - for (j = -1; j <= size; j++) { - y = 0; - for (k = -1; k <= size; k++) { - for (l = 0; l < 3; l++) { - float rgb = yuv2rgb[l][COL_Y] * y + yuv2rgb[l][COL_U] * u + - yuv2rgb[l][COL_V] * v + yuv2rgb[l][COL_C]; - *map++ = gmaps[l][av_clip(rgb, 0, GMAP_SIZE - 1)]; - } - y += (k == -1 || k == size - 1) ? step / 2 : step; - } - u += (j == -1 || j == size - 1) ? step / 2 : step; - } - v += (i == -1 || i == size - 1) ? step / 2 : step; - } -} - -// Copy settings from eq into params. -void mp_csp_copy_equalizer_values(struct mp_csp_params *params, - const struct mp_csp_equalizer *eq) -{ - params->brightness = eq->values[MP_CSP_EQ_BRIGHTNESS] / 100.0; - params->contrast = (eq->values[MP_CSP_EQ_CONTRAST] + 100) / 100.0; - params->hue = eq->values[MP_CSP_EQ_HUE] / 100.0 * 3.1415927; - params->saturation = (eq->values[MP_CSP_EQ_SATURATION] + 100) / 100.0; - float gamma = exp(log(8.0) * eq->values[MP_CSP_EQ_GAMMA] / 100.0); - params->rgamma = gamma; - params->ggamma = gamma; - params->bgamma = gamma; -} - -static int find_eq(int capabilities, const char *name) -{ - for (int i = 0; i < MP_CSP_EQ_COUNT; i++) { - if (strcmp(name, mp_csp_equalizer_names[i]) == 0) - return ((1 << i) & capabilities) ? i : -1; - } - return -1; -} - -int mp_csp_equalizer_get(struct mp_csp_equalizer *eq, const char *property, - int *out_value) -{ - int index = find_eq(eq->capabilities, property); - if (index < 0) - return -1; - - *out_value = eq->values[index]; - - return 0; -} - -int mp_csp_equalizer_set(struct mp_csp_equalizer *eq, const char *property, - int value) -{ - int index = find_eq(eq->capabilities, property); - if (index < 0) - return 0; - - eq->values[index] = value; - - return 1; -} - -void mp_invert_yuv2rgb(float out[3][4], float in[3][4]) -{ - float m00 = in[0][0], m01 = in[0][1], m02 = in[0][2], m03 = in[0][3], - m10 = in[1][0], m11 = in[1][1], m12 = in[1][2], m13 = in[1][3], - m20 = in[2][0], m21 = in[2][1], m22 = in[2][2], m23 = in[2][3]; - - // calculate the adjoint - out[0][0] = (m11 * m22 - m21 * m12); - out[0][1] = -(m01 * m22 - m21 * m02); - out[0][2] = (m01 * m12 - m11 * m02); - out[1][0] = -(m10 * m22 - m20 * m12); - out[1][1] = (m00 * m22 - m20 * m02); - out[1][2] = -(m00 * m12 - m10 * m02); - out[2][0] = (m10 * m21 - m20 * m11); - out[2][1] = -(m00 * m21 - m20 * m01); - out[2][2] = (m00 * m11 - m10 * m01); - - // calculate the determinant (as inverse == 1/det * adjoint, - // adjoint * m == identity * det, so this calculates the det) - float det = m00 * out[0][0] + m10 * out[0][1] + m20 * out[0][2]; - det = 1.0f / det; - - out[0][0] *= det; - out[0][1] *= det; - out[0][2] *= det; - out[1][0] *= det; - out[1][1] *= det; - out[1][2] *= det; - out[2][0] *= det; - out[2][1] *= det; - out[2][2] *= det; - - // fix the constant coefficient - // rgb = M * yuv + C - // M^-1 * rgb = yuv + M^-1 * C - // yuv = M^-1 * rgb - M^-1 * C - // ^^^^^^^^^^ - out[0][3] = -(out[0][0] * m03 + out[0][1] * m13 + out[0][2] * m23); - out[1][3] = -(out[1][0] * m03 + out[1][1] * m13 + out[1][2] * m23); - out[2][3] = -(out[2][0] * m03 + out[2][1] * m13 + out[2][2] * m23); -} - -// Multiply the color in c with the given matrix. -// c is {R, G, B} or {Y, U, V} (depending on input/output and matrix). -// Output is clipped to the given number of bits. -void mp_map_int_color(float matrix[3][4], int clip_bits, int c[3]) -{ - int in[3] = {c[0], c[1], c[2]}; - for (int i = 0; i < 3; i++) { - double val = matrix[i][3]; - for (int x = 0; x < 3; x++) - val += matrix[i][x] * in[x]; - int ival = lrint(val); - c[i] = av_clip(ival, 0, (1 << clip_bits) - 1); - } -} diff --git a/libvo/csputils.h b/libvo/csputils.h deleted file mode 100644 index d66bb86fa3..0000000000 --- a/libvo/csputils.h +++ /dev/null @@ -1,151 +0,0 @@ -/* - * 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. - * - * You can alternatively redistribute this file and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - */ - -#ifndef MPLAYER_CSPUTILS_H -#define MPLAYER_CSPUTILS_H - -#include <stdbool.h> -#include <stdint.h> - -#include "libavcodec/avcodec.h" - -/* NOTE: the csp and levels AUTO values are converted to specific ones - * above vf/vo level. At least vf_scale relies on all valid settings being - * nonzero at vf/vo level. - */ - -enum mp_csp { - MP_CSP_AUTO, - MP_CSP_BT_601, - MP_CSP_BT_709, - MP_CSP_SMPTE_240M, - MP_CSP_RGB, - MP_CSP_COUNT -}; - -// Any enum mp_csp value is a valid index (except MP_CSP_COUNT) -extern char * const mp_csp_names[MP_CSP_COUNT]; - -enum mp_csp_levels { - MP_CSP_LEVELS_AUTO, - MP_CSP_LEVELS_TV, - MP_CSP_LEVELS_PC, - MP_CSP_LEVELS_COUNT, -}; - -struct mp_csp_details { - enum mp_csp format; - enum mp_csp_levels levels_in; // encoded video - enum mp_csp_levels levels_out; // output device -}; - -// initializer for struct mp_csp_details that contains reasonable defaults -#define MP_CSP_DETAILS_DEFAULTS {MP_CSP_BT_601, MP_CSP_LEVELS_TV, MP_CSP_LEVELS_PC} - -struct mp_csp_params { - struct mp_csp_details colorspace; - float brightness; - float contrast; - float hue; - float saturation; - float rgamma; - float ggamma; - float bgamma; - // texture_bits/input_bits is for rescaling fixed point input to range [0,1] - int texture_bits; - int input_bits; - // for scaling integer input and output (if 0, assume range [0,1]) - int int_bits_in; - int int_bits_out; -}; - -#define MP_CSP_PARAMS_DEFAULTS { \ - .colorspace = MP_CSP_DETAILS_DEFAULTS, \ - .brightness = 0, .contrast = 1, .hue = 0, .saturation = 1, \ - .rgamma = 1, .ggamma = 1, .bgamma = 1, \ - .texture_bits = 8, .input_bits = 8} - -enum mp_csp_equalizer_param { - MP_CSP_EQ_BRIGHTNESS, - MP_CSP_EQ_CONTRAST, - MP_CSP_EQ_HUE, - MP_CSP_EQ_SATURATION, - MP_CSP_EQ_GAMMA, - MP_CSP_EQ_COUNT, -}; - -#define MP_CSP_EQ_CAPS_COLORMATRIX \ - ( (1 << MP_CSP_EQ_BRIGHTNESS) \ - | (1 << MP_CSP_EQ_CONTRAST) \ - | (1 << MP_CSP_EQ_HUE) \ - | (1 << MP_CSP_EQ_SATURATION) ) - -#define MP_CSP_EQ_CAPS_GAMMA (1 << MP_CSP_EQ_GAMMA) - -extern char * const mp_csp_equalizer_names[MP_CSP_EQ_COUNT]; - -// Default initialization with 0 is enough, except for the capabilities field -struct mp_csp_equalizer { - // Bit field of capabilities. For example (1 << MP_CSP_EQ_HUE) means hue - // support is available. - int capabilities; - // Value for each property is in the range [-100, 100]. - // 0 is default, meaning neutral or no change. - int values[MP_CSP_EQ_COUNT]; -}; - - -void mp_csp_copy_equalizer_values(struct mp_csp_params *params, - const struct mp_csp_equalizer *eq); - -int mp_csp_equalizer_set(struct mp_csp_equalizer *eq, const char *property, - int value); - -int mp_csp_equalizer_get(struct mp_csp_equalizer *eq, const char *property, - int *out_value); - -enum mp_csp avcol_spc_to_mp_csp(enum AVColorSpace colorspace); - -enum mp_csp_levels avcol_range_to_mp_csp_levels(enum AVColorRange range); - -enum AVColorSpace mp_csp_to_avcol_spc(enum mp_csp colorspace); - -enum AVColorRange mp_csp_levels_to_avcol_range(enum mp_csp_levels range); - -enum mp_csp mp_csp_guess_colorspace(int width, int height); - -void mp_gen_gamma_map(unsigned char *map, int size, float gamma); -#define ROW_R 0 -#define ROW_G 1 -#define ROW_B 2 -#define COL_Y 0 -#define COL_U 1 -#define COL_V 2 -#define COL_C 3 -void mp_get_yuv2rgb_coeffs(struct mp_csp_params *params, float yuv2rgb[3][4]); -void mp_gen_yuv2rgb_map(struct mp_csp_params *params, uint8_t *map, int size); - -void mp_invert_yuv2rgb(float out[3][4], float in[3][4]); -void mp_map_int_color(float matrix[3][4], int clip_bits, int c[3]); - -#endif /* MPLAYER_CSPUTILS_H */ diff --git a/libvo/d3d_shader_yuv.h b/libvo/d3d_shader_yuv.h deleted file mode 100644 index 49ef753b4c..0000000000 --- a/libvo/d3d_shader_yuv.h +++ /dev/null @@ -1,142 +0,0 @@ -#if 0 -// -// Generated by Microsoft (R) HLSL Shader Compiler 9.27.952.3022 -// -// fxc /Tps_2_0 /Fhz:\tmp\mplayer\libvo\d3d_shader_yuv.h -// z:\tmp\mplayer\libvo\d3d_shader_yuv.hlsl /Vnd3d_shader_yuv -// -// -// Parameters: -// -// float4x4 colormatrix; -// sampler2D tex0; -// sampler2D tex1; -// sampler2D tex2; -// -// -// Registers: -// -// Name Reg Size -// ------------ ----- ---- -// colormatrix c0 4 -// tex0 s0 1 -// tex1 s1 1 -// tex2 s2 1 -// - - ps_2_0 - def c4, 1, 0, 0, 0 - dcl t0.xy - dcl t1.xy - dcl t2.xy - dcl_2d s0 - dcl_2d s1 - dcl_2d s2 - texld r0, t0, s0 - texld r1, t1, s1 - texld r2, t2, s2 - mov r0.y, r1.x - mov r0.z, r2.x - mov r0.w, c4.x - dp4 r1.x, r0, c0 - dp4 r1.y, r0, c1 - dp4 r1.z, r0, c2 - dp4 r1.w, r0, c3 - mov oC0, r1 - -// approximately 11 instruction slots used (3 texture, 8 arithmetic) -#endif - -const BYTE d3d_shader_yuv[] = -{ - 0, 2, 255, 255, 254, 255, - 67, 0, 67, 84, 65, 66, - 28, 0, 0, 0, 215, 0, - 0, 0, 0, 2, 255, 255, - 4, 0, 0, 0, 28, 0, - 0, 0, 0, 1, 0, 0, - 208, 0, 0, 0, 108, 0, - 0, 0, 2, 0, 0, 0, - 4, 0, 2, 0, 120, 0, - 0, 0, 0, 0, 0, 0, - 136, 0, 0, 0, 3, 0, - 0, 0, 1, 0, 2, 0, - 144, 0, 0, 0, 0, 0, - 0, 0, 160, 0, 0, 0, - 3, 0, 1, 0, 1, 0, - 6, 0, 168, 0, 0, 0, - 0, 0, 0, 0, 184, 0, - 0, 0, 3, 0, 2, 0, - 1, 0, 10, 0, 192, 0, - 0, 0, 0, 0, 0, 0, - 99, 111, 108, 111, 114, 109, - 97, 116, 114, 105, 120, 0, - 3, 0, 3, 0, 4, 0, - 4, 0, 1, 0, 0, 0, - 0, 0, 0, 0, 116, 101, - 120, 48, 0, 171, 171, 171, - 4, 0, 12, 0, 1, 0, - 1, 0, 1, 0, 0, 0, - 0, 0, 0, 0, 116, 101, - 120, 49, 0, 171, 171, 171, - 4, 0, 12, 0, 1, 0, - 1, 0, 1, 0, 0, 0, - 0, 0, 0, 0, 116, 101, - 120, 50, 0, 171, 171, 171, - 4, 0, 12, 0, 1, 0, - 1, 0, 1, 0, 0, 0, - 0, 0, 0, 0, 112, 115, - 95, 50, 95, 48, 0, 77, - 105, 99, 114, 111, 115, 111, - 102, 116, 32, 40, 82, 41, - 32, 72, 76, 83, 76, 32, - 83, 104, 97, 100, 101, 114, - 32, 67, 111, 109, 112, 105, - 108, 101, 114, 32, 57, 46, - 50, 55, 46, 57, 53, 50, - 46, 51, 48, 50, 50, 0, - 81, 0, 0, 5, 4, 0, - 15, 160, 0, 0, 128, 63, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 31, 0, 0, 2, 0, 0, - 0, 128, 0, 0, 3, 176, - 31, 0, 0, 2, 0, 0, - 0, 128, 1, 0, 3, 176, - 31, 0, 0, 2, 0, 0, - 0, 128, 2, 0, 3, 176, - 31, 0, 0, 2, 0, 0, - 0, 144, 0, 8, 15, 160, - 31, 0, 0, 2, 0, 0, - 0, 144, 1, 8, 15, 160, - 31, 0, 0, 2, 0, 0, - 0, 144, 2, 8, 15, 160, - 66, 0, 0, 3, 0, 0, - 15, 128, 0, 0, 228, 176, - 0, 8, 228, 160, 66, 0, - 0, 3, 1, 0, 15, 128, - 1, 0, 228, 176, 1, 8, - 228, 160, 66, 0, 0, 3, - 2, 0, 15, 128, 2, 0, - 228, 176, 2, 8, 228, 160, - 1, 0, 0, 2, 0, 0, - 2, 128, 1, 0, 0, 128, - 1, 0, 0, 2, 0, 0, - 4, 128, 2, 0, 0, 128, - 1, 0, 0, 2, 0, 0, - 8, 128, 4, 0, 0, 160, - 9, 0, 0, 3, 1, 0, - 1, 128, 0, 0, 228, 128, - 0, 0, 228, 160, 9, 0, - 0, 3, 1, 0, 2, 128, - 0, 0, 228, 128, 1, 0, - 228, 160, 9, 0, 0, 3, - 1, 0, 4, 128, 0, 0, - 228, 128, 2, 0, 228, 160, - 9, 0, 0, 3, 1, 0, - 8, 128, 0, 0, 228, 128, - 3, 0, 228, 160, 1, 0, - 0, 2, 0, 8, 15, 128, - 1, 0, 228, 128, 255, 255, - 0, 0 -}; diff --git a/libvo/d3d_shader_yuv.hlsl b/libvo/d3d_shader_yuv.hlsl deleted file mode 100644 index b17e257210..0000000000 --- a/libvo/d3d_shader_yuv.hlsl +++ /dev/null @@ -1,44 +0,0 @@ -// Compile with: -// fxc.exe /Tps_2_0 /Fhd3d_shader_yuv.h d3d_shader_yuv.hlsl /Vnd3d_shader_yuv -// fxc.exe /Tps_2_0 /Fhd3d_shader_yuv_2ch.h d3d_shader_yuv.hlsl /Vnd3d_shader_yuv_2ch /DUSE_2CH=1 - -// Be careful with this shader. You can't use constant slots, since we don't -// load the shader with D3DX. All uniform variables are mapped to hardcoded -// constant slots. - -sampler2D tex0 : register(s0); -sampler2D tex1 : register(s1); -sampler2D tex2 : register(s2); - -uniform float4x4 colormatrix : register(c0); -uniform float2 depth : register(c5); - -#ifdef USE_2CH - -float1 sample(sampler2D tex, float2 t) -{ - // Sample from A8L8 format as if we sampled a single value from L16. - // We compute the 2 channel values back into one. - return dot(tex2D(tex, t).xw, depth); -} - -#else - -float1 sample(sampler2D tex, float2 t) -{ - return tex2D(tex, t).x; -} - -#endif - -float4 main(float2 t0 : TEXCOORD0, - float2 t1 : TEXCOORD1, - float2 t2 : TEXCOORD2) - : COLOR -{ - float4 c = float4(sample(tex0, t0), - sample(tex1, t1), - sample(tex2, t2), - 1); - return mul(c, colormatrix); -} diff --git a/libvo/d3d_shader_yuv_2ch.h b/libvo/d3d_shader_yuv_2ch.h deleted file mode 100644 index 45dcc73992..0000000000 --- a/libvo/d3d_shader_yuv_2ch.h +++ /dev/null @@ -1,170 +0,0 @@ -#if 0 -// -// Generated by Microsoft (R) HLSL Shader Compiler 9.27.952.3022 -// -// fxc /Tps_2_0 /Fhz:\tmp\mplayer\libvo\d3d_shader_yuv_2ch.h -// z:\tmp\mplayer\libvo\d3d_shader_yuv.hlsl /Vnd3d_shader_yuv_2ch -// /DUSE_2CH=1 -// -// -// Parameters: -// -// float4x4 colormatrix; -// float2 depth; -// sampler2D tex0; -// sampler2D tex1; -// sampler2D tex2; -// -// -// Registers: -// -// Name Reg Size -// ------------ ----- ---- -// colormatrix c0 4 -// depth c5 1 -// tex0 s0 1 -// tex1 s1 1 -// tex2 s2 1 -// - - ps_2_0 - def c4, 1, 0, 0, 0 - dcl t0.xy - dcl t1.xy - dcl t2.xy - dcl_2d s0 - dcl_2d s1 - dcl_2d s2 - texld r0, t0, s0 - texld r1, t1, s1 - texld r2, t2, s2 - mul r0.x, r0.x, c5.x - mad r0.x, r0.w, c5.y, r0.x - mul r1.x, r1.x, c5.x - mad r0.y, r1.w, c5.y, r1.x - mul r1.x, r2.x, c5.x - mad r0.z, r2.w, c5.y, r1.x - mov r0.w, c4.x - dp4 r1.x, r0, c0 - dp4 r1.y, r0, c1 - dp4 r1.z, r0, c2 - dp4 r1.w, r0, c3 - mov oC0, r1 - -// approximately 15 instruction slots used (3 texture, 12 arithmetic) -#endif - -const BYTE d3d_shader_yuv_2ch[] = -{ - 0, 2, 255, 255, 254, 255, - 78, 0, 67, 84, 65, 66, - 28, 0, 0, 0, 3, 1, - 0, 0, 0, 2, 255, 255, - 5, 0, 0, 0, 28, 0, - 0, 0, 0, 1, 0, 0, - 252, 0, 0, 0, 128, 0, - 0, 0, 2, 0, 0, 0, - 4, 0, 2, 0, 140, 0, - 0, 0, 0, 0, 0, 0, - 156, 0, 0, 0, 2, 0, - 5, 0, 1, 0, 22, 0, - 164, 0, 0, 0, 0, 0, - 0, 0, 180, 0, 0, 0, - 3, 0, 0, 0, 1, 0, - 2, 0, 188, 0, 0, 0, - 0, 0, 0, 0, 204, 0, - 0, 0, 3, 0, 1, 0, - 1, 0, 6, 0, 212, 0, - 0, 0, 0, 0, 0, 0, - 228, 0, 0, 0, 3, 0, - 2, 0, 1, 0, 10, 0, - 236, 0, 0, 0, 0, 0, - 0, 0, 99, 111, 108, 111, - 114, 109, 97, 116, 114, 105, - 120, 0, 3, 0, 3, 0, - 4, 0, 4, 0, 1, 0, - 0, 0, 0, 0, 0, 0, - 100, 101, 112, 116, 104, 0, - 171, 171, 1, 0, 3, 0, - 1, 0, 2, 0, 1, 0, - 0, 0, 0, 0, 0, 0, - 116, 101, 120, 48, 0, 171, - 171, 171, 4, 0, 12, 0, - 1, 0, 1, 0, 1, 0, - 0, 0, 0, 0, 0, 0, - 116, 101, 120, 49, 0, 171, - 171, 171, 4, 0, 12, 0, - 1, 0, 1, 0, 1, 0, - 0, 0, 0, 0, 0, 0, - 116, 101, 120, 50, 0, 171, - 171, 171, 4, 0, 12, 0, - 1, 0, 1, 0, 1, 0, - 0, 0, 0, 0, 0, 0, - 112, 115, 95, 50, 95, 48, - 0, 77, 105, 99, 114, 111, - 115, 111, 102, 116, 32, 40, - 82, 41, 32, 72, 76, 83, - 76, 32, 83, 104, 97, 100, - 101, 114, 32, 67, 111, 109, - 112, 105, 108, 101, 114, 32, - 57, 46, 50, 55, 46, 57, - 53, 50, 46, 51, 48, 50, - 50, 0, 81, 0, 0, 5, - 4, 0, 15, 160, 0, 0, - 128, 63, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 31, 0, 0, 2, - 0, 0, 0, 128, 0, 0, - 3, 176, 31, 0, 0, 2, - 0, 0, 0, 128, 1, 0, - 3, 176, 31, 0, 0, 2, - 0, 0, 0, 128, 2, 0, - 3, 176, 31, 0, 0, 2, - 0, 0, 0, 144, 0, 8, - 15, 160, 31, 0, 0, 2, - 0, 0, 0, 144, 1, 8, - 15, 160, 31, 0, 0, 2, - 0, 0, 0, 144, 2, 8, - 15, 160, 66, 0, 0, 3, - 0, 0, 15, 128, 0, 0, - 228, 176, 0, 8, 228, 160, - 66, 0, 0, 3, 1, 0, - 15, 128, 1, 0, 228, 176, - 1, 8, 228, 160, 66, 0, - 0, 3, 2, 0, 15, 128, - 2, 0, 228, 176, 2, 8, - 228, 160, 5, 0, 0, 3, - 0, 0, 1, 128, 0, 0, - 0, 128, 5, 0, 0, 160, - 4, 0, 0, 4, 0, 0, - 1, 128, 0, 0, 255, 128, - 5, 0, 85, 160, 0, 0, - 0, 128, 5, 0, 0, 3, - 1, 0, 1, 128, 1, 0, - 0, 128, 5, 0, 0, 160, - 4, 0, 0, 4, 0, 0, - 2, 128, 1, 0, 255, 128, - 5, 0, 85, 160, 1, 0, - 0, 128, 5, 0, 0, 3, - 1, 0, 1, 128, 2, 0, - 0, 128, 5, 0, 0, 160, - 4, 0, 0, 4, 0, 0, - 4, 128, 2, 0, 255, 128, - 5, 0, 85, 160, 1, 0, - 0, 128, 1, 0, 0, 2, - 0, 0, 8, 128, 4, 0, - 0, 160, 9, 0, 0, 3, - 1, 0, 1, 128, 0, 0, - 228, 128, 0, 0, 228, 160, - 9, 0, 0, 3, 1, 0, - 2, 128, 0, 0, 228, 128, - 1, 0, 228, 160, 9, 0, - 0, 3, 1, 0, 4, 128, - 0, 0, 228, 128, 2, 0, - 228, 160, 9, 0, 0, 3, - 1, 0, 8, 128, 0, 0, - 228, 128, 3, 0, 228, 160, - 1, 0, 0, 2, 0, 8, - 15, 128, 1, 0, 228, 128, - 255, 255, 0, 0 -}; diff --git a/libvo/fastmemcpy.h b/libvo/fastmemcpy.h deleted file mode 100644 index c2cd79314f..0000000000 --- a/libvo/fastmemcpy.h +++ /dev/null @@ -1,77 +0,0 @@ -/* - * This file is part of MPlayer. - * - * MPlayer is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser 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_FASTMEMCPY_H -#define MPLAYER_FASTMEMCPY_H - -#include "config.h" -#include <inttypes.h> -#include <string.h> -#include <stddef.h> - -#define memcpy_pic(d, s, b, h, ds, ss) memcpy_pic2(d, s, b, h, ds, ss, 0) -#define my_memcpy_pic(d, s, b, h, ds, ss) memcpy_pic2(d, s, b, h, ds, ss, 1) - -/** - * \param limit2width always skip data between end of line and start of next - * instead of copying the full block when strides are the same - */ -static inline void * memcpy_pic2(void * dst, const void * src, - int bytesPerLine, int height, - int dstStride, int srcStride, int limit2width) -{ - int i; - void *retval=dst; - - if(!limit2width && dstStride == srcStride) - { - if (srcStride < 0) { - src = (uint8_t*)src + (height-1)*srcStride; - dst = (uint8_t*)dst + (height-1)*dstStride; - srcStride = -srcStride; - } - - memcpy(dst, src, srcStride*height); - } - else - { - for(i=0; i<height; i++) - { - memcpy(dst, src, bytesPerLine); - src = (uint8_t*)src + srcStride; - dst = (uint8_t*)dst + dstStride; - } - } - - return retval; -} - -static inline void memset_pic(void *dst, int fill, int bytesPerLine, int height, - int stride) -{ - if (bytesPerLine == stride) { - memset(dst, fill, stride * height); - } else { - for (int i = 0; i < height; i++) { - memset(dst, fill, bytesPerLine); - dst = (uint8_t *)dst + stride; - } - } -} - -#endif /* MPLAYER_FASTMEMCPY_H */ diff --git a/libvo/filter_kernels.c b/libvo/filter_kernels.c deleted file mode 100644 index 2c2f56ee51..0000000000 --- a/libvo/filter_kernels.c +++ /dev/null @@ -1,279 +0,0 @@ -/* - * This file is part of mplayer2. - * - * Most code for computing the weights is taken from Anti-Grain Geometry (AGG) - * (licensed under GPL 2 or later), with modifications. - * Copyright (C) 2002-2006 Maxim Shemanarev - * http://vector-agg.cvs.sourceforge.net/viewvc/vector-agg/agg-2.5/include/agg_image_filters.h?view=markup - * - * Also see glumpy (BSD licensed), contains the same code in Python: - * http://code.google.com/p/glumpy/source/browse/glumpy/image/filter.py - * - * Also see: Paul Heckbert's "zoom" - * - * Also see XBMC: ConvolutionKernels.cpp etc. - * - * mplayer2 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. - * - * mplayer2 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 mplayer2; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -#include <stddef.h> -#include <string.h> -#include <math.h> -#include <assert.h> - -#include "filter_kernels.h" - -// NOTE: all filters are separable, symmetric, and are intended for use with -// a lookup table/texture. - -const struct filter_kernel *mp_find_filter_kernel(const char *name) -{ - for (const struct filter_kernel *k = mp_filter_kernels; k->name; k++) { - if (strcmp(k->name, name) == 0) - return k; - } - return NULL; -} - -// sizes = sorted list of available filter sizes, terminated with size 0 -// inv_scale = source_size / dest_size -bool mp_init_filter(struct filter_kernel *filter, const int *sizes, - double inv_scale) -{ - // only downscaling requires widening the filter - filter->inv_scale = inv_scale >= 1.0 ? inv_scale : 1.0; - double support = filter->radius * filter->inv_scale; - int size = ceil(2.0 * support); - // round up to smallest available size that's still large enough - if (size < sizes[0]) - size = sizes[0]; - const int *cursize = sizes; - while (size > *cursize && *cursize) - cursize++; - if (*cursize) { - filter->size = *cursize; - return true; - } else { - // The filter doesn't fit - instead of failing completely, use the - // largest filter available. This is incorrect, but better than refusing - // to do anything. - filter->size = cursize[-1]; - filter->inv_scale = filter->size / 2.0 / filter->radius; - return false; - } -} - -// Calculate the 1D filtering kernel for N sample points. -// N = number of samples, which is filter->size -// The weights will be stored in out_w[0] to out_w[N - 1] -// f = x0 - abs(x0), subpixel position in the range [0,1) or [0,1]. -void mp_compute_weights(struct filter_kernel *filter, double f, float *out_w) -{ - assert(filter->size > 0); - double sum = 0; - for (int n = 0; n < filter->size; n++) { - double x = f - (n - filter->size / 2 + 1); - double w = filter->weight(filter, fabs(x) / filter->inv_scale); - out_w[n] = w; - sum += w; - } - //normalize - for (int n = 0; n < filter->size; n++) - out_w[n] /= sum; -} - -// Fill the given array with weights for the range [0.0, 1.0]. The array is -// interpreted as rectangular array of count * filter->size items. -void mp_compute_lut(struct filter_kernel *filter, int count, float *out_array) -{ - for (int n = 0; n < count; n++) { - mp_compute_weights(filter, n / (double)(count - 1), - out_array + filter->size * n); - } -} - -typedef struct filter_kernel kernel; - -static double bilinear(kernel *k, double x) -{ - return 1.0 - x; -} - -static double hanning(kernel *k, double x) -{ - return 0.5 + 0.5 * cos(M_PI * x); -} - -static double hamming(kernel *k, double x) -{ - return 0.54 + 0.46 * cos(M_PI * x); -} - -static double hermite(kernel *k, double x) -{ - return (2.0 * x - 3.0) * x * x + 1.0; -} - -static double quadric(kernel *k, double x) -{ - // NOTE: glumpy uses 0.75, AGG uses 0.5 - if (x < 0.5) - return 0.75 - x * x; - if (x < 1.5) - return 0.5 * (x - 1.5) * (x - 1.5); - return 0; -} - -static double bc_pow3(double x) -{ - return (x <= 0) ? 0 : x * x * x; -} - -static double bicubic(kernel *k, double x) -{ - return (1.0/6.0) * ( bc_pow3(x + 2) - - 4 * bc_pow3(x + 1) - + 6 * bc_pow3(x) - - 4 * bc_pow3(x - 1)); -} - -static double bessel_i0(double epsilon, double x) -{ - double sum = 1; - double y = x * x / 4; - double t = y; - for (int i = 2; t > epsilon; i++) { - sum += t; - t *= y / (i * i); - } - return sum; -} - -static double kaiser(kernel *k, double x) -{ - double a = k->params[0]; - double b = k->params[1]; - double epsilon = 1e-12; - double i0a = 1 / bessel_i0(epsilon, b); - return bessel_i0(epsilon, a * sqrt(1 - x * x)) * i0a; -} - -static double catmull_rom(kernel *k, double x) -{ - if (x < 1.0) - return 0.5 * (2.0 + x * x * (-5.0 + x * 3.0)); - if (x < 2.0) - return 0.5 * (4.0 + x * (-8.0 + x * (5.0 - x))); - return 0; -} - -// Mitchell-Netravali -static double mitchell(kernel *k, double x) -{ - double b = k->params[0]; - double c = k->params[1]; - double - p0 = (6.0 - 2.0 * b) / 6.0, - p2 = (-18.0 + 12.0 * b + 6.0 * c) / 6.0, - p3 = (12.0 - 9.0 * b - 6.0 * c) / 6.0, - q0 = (8.0 * b + 24.0 * c) / 6.0, - q1 = (-12.0 * b - 48.0 * c) / 6.0, - q2 = (6.0 * b + 30.0 * c) / 6.0, - q3 = (-b - 6.0 * c) / 6.0; - if (x < 1.0) - return p0 + x * x * (p2 + x * p3); - if (x < 2.0) - return q0 + x * (q1 + x * (q2 + x * q3)); - return 0; -} - -static double spline16(kernel *k, double x) -{ - if (x < 1.0) - return ((x - 9.0/5.0 ) * x - 1.0/5.0 ) * x + 1.0; - return ((-1.0/3.0 * (x-1) + 4.0/5.0) * (x-1) - 7.0/15.0 ) * (x-1); -} - -static double spline36(kernel *k, double x) -{ - if(x < 1.0) - return ((13.0/11.0 * x - 453.0/209.0) * x - 3.0/209.0) * x + 1.0; - if(x < 2.0) - return ((-6.0/11.0 * (x - 1) + 270.0/209.0) * (x - 1) - 156.0/209.0) - * (x - 1); - return ((1.0/11.0 * (x - 2) - 45.0/209.0) * (x - 2) + 26.0/209.0) - * (x - 2); -} - -static double gaussian(kernel *k, double x) -{ - return exp(-2.0 * x * x) * sqrt(2.0 / M_PI); -} - -static double sinc(kernel *k, double x) -{ - if (x == 0.0) - return 1.0; - double pix = M_PI * x; - return sin(pix) / pix; -} - -static double lanczos(kernel *k, double x) -{ - double radius = k->size / 2; - if (x < -radius || x > radius) - return 0; - if (x == 0) - return 1; - double pix = M_PI * x; - return radius * sin(pix) * sin(pix / radius) / (pix * pix); -} - -static double blackman(kernel *k, double x) -{ - double radius = k->size / 2; - if (x == 0.0) - return 1.0; - if (x > radius) - return 0.0; - x *= M_PI; - double xr = x / radius; - return (sin(x) / x) * (0.42 + 0.5 * cos(xr) + 0.08 * cos(2 * xr)); -} - -const struct filter_kernel mp_filter_kernels[] = { - {"bilinear_slow", 1, bilinear}, - {"hanning", 1, hanning}, - {"hamming", 1, hamming}, - {"hermite", 1, hermite}, - {"quadric", 1.5, quadric}, - {"bicubic", 2, bicubic}, - {"kaiser", 1, kaiser, .params = {6.33, 6.33} }, - {"catmull_rom", 2, catmull_rom}, - {"mitchell", 2, mitchell, .params = {1.0/3.0, 1.0/3.0} }, - {"spline16", 2, spline16}, - {"spline36", 3, spline36}, - {"gaussian", 2, gaussian}, - {"sinc2", 2, sinc}, - {"sinc3", 3, sinc}, - {"sinc4", 4, sinc}, - {"lanczos2", 2, lanczos}, - {"lanczos3", 3, lanczos}, - {"lanczos4", 4, lanczos}, - {"blackman2", 2, blackman}, - {"blackman3", 3, blackman}, - {"blackman4", 4, blackman}, - {0} -}; diff --git a/libvo/filter_kernels.h b/libvo/filter_kernels.h deleted file mode 100644 index 46a392c40a..0000000000 --- a/libvo/filter_kernels.h +++ /dev/null @@ -1,45 +0,0 @@ -/* - * This file is part of mplayer2. - * - * mplayer2 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. - * - * mplayer2 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 mplayer2; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -#ifndef MPLAYER_FILTER_KERNELS_H -#define MPLAYER_FILTER_KERNELS_H - -#include <stdbool.h> - -struct filter_kernel { - const char *name; - double radius; - double (*weight)(struct filter_kernel *kernel, double x); - - // The filter params can be changed at runtime. Only used by some filters. - float params[2]; - // The following values are set by mp_init_filter() at runtime. - // Number of coefficients; equals the rounded up radius multiplied with 2. - int size; - double inv_scale; -}; - -extern const struct filter_kernel mp_filter_kernels[]; - -const struct filter_kernel *mp_find_filter_kernel(const char *name); -bool mp_init_filter(struct filter_kernel *filter, const int *sizes, - double scale); -void mp_compute_weights(struct filter_kernel *filter, double f, float *out_w); -void mp_compute_lut(struct filter_kernel *filter, int count, float *out_array); - -#endif /* MPLAYER_FILTER_KERNELS_H */ diff --git a/libvo/geometry.c b/libvo/geometry.c deleted file mode 100644 index 941528aea9..0000000000 --- a/libvo/geometry.c +++ /dev/null @@ -1,112 +0,0 @@ -/* - * copyright (C) 2002 Mark Zealey <mark@zealos.org> - * - * 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 <string.h> -#include <limits.h> -#include "geometry.h" -#include "mp_msg.h" - -/* A string of the form [WxH][+X+Y] or xpos[%]:ypos[%] */ -char *vo_geometry; -// set when either width or height is changed -int geometry_wh_changed; -int geometry_xy_changed; - -// xpos,ypos: position of the left upper corner -// widw,widh: width and height of the window -// scrw,scrh: width and height of the current screen -int geometry(int *xpos, int *ypos, int *widw, int *widh, int scrw, int scrh) -{ - if(vo_geometry != NULL) { - char xsign[2], ysign[2], dummy[2]; - int width, height, xoff, yoff, xper, yper; - int i; - int ok = 0; - for (i = 0; !ok && i < 9; i++) { - width = height = xoff = yoff = xper = yper = INT_MIN; - strcpy(xsign, "+"); - strcpy(ysign, "+"); - switch (i) { - case 0: - ok = sscanf(vo_geometry, "%ix%i%1[+-]%i%1[+-]%i%c", - &width, &height, xsign, &xoff, ysign, - &yoff, dummy) == 6; - break; - case 1: - ok = sscanf(vo_geometry, "%ix%i%c", &width, &height, dummy) == 2; - break; - case 2: - ok = sscanf(vo_geometry, "%1[+-]%i%1[+-]%i%c", - xsign, &xoff, ysign, &yoff, dummy) == 4; - break; - case 3: - ok = sscanf(vo_geometry, "%i%%:%i%1[%]%c", &xper, &yper, dummy, dummy) == 3; - break; - case 4: - ok = sscanf(vo_geometry, "%i:%i%1[%]%c", &xoff, &yper, dummy, dummy) == 3; - break; - case 5: - ok = sscanf(vo_geometry, "%i%%:%i%c", &xper, &yoff, dummy) == 2; - break; - case 6: - ok = sscanf(vo_geometry, "%i:%i%c", &xoff, &yoff, dummy) == 2; - break; - case 7: - ok = sscanf(vo_geometry, "%i%1[%]%c", &xper, dummy, dummy) == 2; - break; - case 8: - ok = sscanf(vo_geometry, "%i%c", &xoff, dummy) == 1; - break; - } - } - if (!ok) { - mp_msg(MSGT_VO, MSGL_ERR, - "-geometry must be in [WxH][[+-]X[+-]Y] | [X[%%]:[Y[%%]]] format, incorrect (%s)\n", vo_geometry); - return 0; - } - - mp_msg(MSGT_VO, MSGL_V,"geometry window parameter: widw: %i," - " widh: %i, scrw: %i, scrh: %i\n",*widw, *widh, scrw, scrh); - - mp_msg(MSGT_VO, MSGL_V,"geometry set to width: %i," - "height: %i, xoff: %s%i, yoff: %s%i, xper: %i, yper: %i\n", - width, height, xsign, xoff, ysign, yoff, xper, yper); - - if (width > 0) *widw = width; - if (height > 0) *widh = height; - - if(xoff != INT_MIN && xsign[0] == '-') xoff = scrw - *widw - xoff; - if(yoff != INT_MIN && ysign[0] == '-') yoff = scrh - *widh - yoff; - if(xper >= 0 && xper <= 100) xoff = (scrw - *widw) * ((float)xper / 100.0); - if(yper >= 0 && yper <= 100) yoff = (scrh - *widh) * ((float)yper / 100.0); - - mp_msg(MSGT_VO, MSGL_V,"geometry set to width: %i," - "height: %i, xoff: %i, yoff: %i, xper: %i, yper: %i\n", - width, height, xoff, yoff, xper, yper); - - if (xoff != INT_MIN && xpos) *xpos = xoff; - if (yoff != INT_MIN && ypos) *ypos = yoff; - - geometry_wh_changed = width > 0 || height > 0; - geometry_xy_changed = xoff != INT_MIN || yoff != INT_MIN; - } - return 1; -} diff --git a/libvo/geometry.h b/libvo/geometry.h deleted file mode 100644 index 77868a5aad..0000000000 --- a/libvo/geometry.h +++ /dev/null @@ -1,29 +0,0 @@ -/* - * copyright (C) 2002 Mark Zealey <mark@zealos.org> - * - * 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_GEOMETRY_H -#define MPLAYER_GEOMETRY_H - -extern char *vo_geometry; -extern int geometry_wh_changed; -extern int geometry_xy_changed; -int geometry(int *xpos, int *ypos, int *widw, int *widh, int scrw, int scrh); - -#endif /* MPLAYER_GEOMETRY_H */ diff --git a/libvo/gl_common.c b/libvo/gl_common.c deleted file mode 100644 index 80db2eacc4..0000000000 --- a/libvo/gl_common.c +++ /dev/null @@ -1,2654 +0,0 @@ -/* - * common OpenGL routines - * - * copyleft (C) 2005-2010 Reimar Döffinger <Reimar.Doeffinger@gmx.de> - * Special thanks go to the xine team and Matthias Hopf, whose video_out_opengl.c - * gave me lots of good ideas. - * - * 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. - * - * You can alternatively redistribute this file and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - */ - -/** - * \file gl_common.c - * \brief OpenGL helper functions used by vo_gl.c and vo_gl2.c - */ - -#include <stddef.h> -#include <stdlib.h> -#include <stdio.h> -#include <string.h> -#include <ctype.h> -#include <stdbool.h> -#include <math.h> -#include <assert.h> -#include "talloc.h" -#include "gl_common.h" -#include "csputils.h" -#include "aspect.h" -#include "pnm_loader.h" -#include "options.h" -#include "sub/sub.h" -#include "bitmap_packer.h" - -//! \defgroup glgeneral OpenGL general helper functions - -// GLU has this as gluErrorString (we don't use GLU, as it is legacy-OpenGL) -static const char *gl_error_to_string(GLenum error) -{ - switch (error) { - case GL_INVALID_ENUM: return "INVALID_ENUM"; - case GL_INVALID_VALUE: return "INVALID_VALUE"; - case GL_INVALID_OPERATION: return "INVALID_OPERATION"; - case GL_INVALID_FRAMEBUFFER_OPERATION: - return "INVALID_FRAMEBUFFER_OPERATION"; - case GL_OUT_OF_MEMORY: return "OUT_OF_MEMORY"; - default: return "unknown"; - } -} - -void glCheckError(GL *gl, const char *info) -{ - for (;;) { - GLenum error = gl->GetError(); - if (error == GL_NO_ERROR) - break; - mp_msg(MSGT_VO, MSGL_ERR, "[gl] %s: OpenGL error %s.\n", info, - gl_error_to_string(error)); - } -} - -//! \defgroup glcontext OpenGL context management helper functions - -//! \defgroup gltexture OpenGL texture handling helper functions - -//! \defgroup glconversion OpenGL conversion helper functions - -/** - * \brief adjusts the GL_UNPACK_ALIGNMENT to fit the stride. - * \param stride number of bytes per line for which alignment should fit. - * \ingroup glgeneral - */ -void glAdjustAlignment(GL *gl, int stride) -{ - GLint gl_alignment; - if (stride % 8 == 0) - gl_alignment = 8; - else if (stride % 4 == 0) - gl_alignment = 4; - else if (stride % 2 == 0) - gl_alignment = 2; - else - gl_alignment = 1; - gl->PixelStorei(GL_UNPACK_ALIGNMENT, gl_alignment); - gl->PixelStorei(GL_PACK_ALIGNMENT, gl_alignment); -} - -//! always return this format as internal texture format in glFindFormat -#define TEXTUREFORMAT_ALWAYS GL_RGB8 -#undef TEXTUREFORMAT_ALWAYS - -/** - * \brief find the OpenGL settings coresponding to format. - * - * All parameters may be NULL. - * \param fmt MPlayer format to analyze. - * \param bpp [OUT] bits per pixel of that format. - * \param gl_texfmt [OUT] internal texture format that fits the - * image format, not necessarily the best for performance. - * \param gl_format [OUT] OpenGL format for this image format. - * \param gl_type [OUT] OpenGL type for this image format. - * \return 1 if format is supported by OpenGL, 0 if not. - * \ingroup gltexture - */ -int glFindFormat(uint32_t fmt, int have_texture_rg, int *bpp, GLint *gl_texfmt, - GLenum *gl_format, GLenum *gl_type) -{ - int supported = 1; - int dummy1; - GLenum dummy2; - GLint dummy3; - if (!bpp) - bpp = &dummy1; - if (!gl_texfmt) - gl_texfmt = &dummy3; - if (!gl_format) - gl_format = &dummy2; - if (!gl_type) - gl_type = &dummy2; - - if (mp_get_chroma_shift(fmt, NULL, NULL, NULL)) { - // reduce the possible cases a bit - if (IMGFMT_IS_YUVP16_LE(fmt)) - fmt = IMGFMT_420P16_LE; - else if (IMGFMT_IS_YUVP16_BE(fmt)) - fmt = IMGFMT_420P16_BE; - else - fmt = IMGFMT_YV12; - } - - *bpp = IMGFMT_IS_BGR(fmt) ? IMGFMT_BGR_DEPTH(fmt) : IMGFMT_RGB_DEPTH(fmt); - *gl_texfmt = 3; - switch (fmt) { - case IMGFMT_RGB48NE: - *gl_format = GL_RGB; - *gl_type = GL_UNSIGNED_SHORT; - break; - case IMGFMT_RGB24: - *gl_format = GL_RGB; - *gl_type = GL_UNSIGNED_BYTE; - break; - case IMGFMT_RGBA: - *gl_texfmt = 4; - *gl_format = GL_RGBA; - *gl_type = GL_UNSIGNED_BYTE; - break; - case IMGFMT_420P16: - supported = 0; // no native YUV support - *gl_texfmt = have_texture_rg ? GL_R16 : GL_LUMINANCE16; - *bpp = 16; - *gl_format = have_texture_rg ? GL_RED : GL_LUMINANCE; - *gl_type = GL_UNSIGNED_SHORT; - break; - case IMGFMT_YV12: - supported = 0; // no native YV12 support - case IMGFMT_Y800: - case IMGFMT_Y8: - *gl_texfmt = 1; - *bpp = 8; - *gl_format = GL_LUMINANCE; - *gl_type = GL_UNSIGNED_BYTE; - break; - case IMGFMT_UYVY: - // IMGFMT_YUY2 would be more logical for the _REV format, - // but gives clearly swapped colors. - case IMGFMT_YVYU: - *gl_texfmt = GL_YCBCR_MESA; - *bpp = 16; - *gl_format = GL_YCBCR_MESA; - *gl_type = fmt == IMGFMT_UYVY ? GL_UNSIGNED_SHORT_8_8 : GL_UNSIGNED_SHORT_8_8_REV; - break; -#if 0 - // we do not support palettized formats, although the format the - // swscale produces works - case IMGFMT_RGB8: - *gl_format = GL_RGB; - *gl_type = GL_UNSIGNED_BYTE_2_3_3_REV; - break; -#endif - case IMGFMT_RGB15: - *gl_format = GL_RGBA; - *gl_type = GL_UNSIGNED_SHORT_1_5_5_5_REV; - break; - case IMGFMT_RGB16: - *gl_format = GL_RGB; - *gl_type = GL_UNSIGNED_SHORT_5_6_5_REV; - break; -#if 0 - case IMGFMT_BGR8: - // special case as red and blue have a different number of bits. - // GL_BGR and GL_UNSIGNED_BYTE_3_3_2 isn't supported at least - // by nVidia drivers, and in addition would give more bits to - // blue than to red, which isn't wanted - *gl_format = GL_RGB; - *gl_type = GL_UNSIGNED_BYTE_3_3_2; - break; -#endif - case IMGFMT_BGR15: - *gl_format = GL_BGRA; - *gl_type = GL_UNSIGNED_SHORT_1_5_5_5_REV; - break; - case IMGFMT_BGR16: - *gl_format = GL_RGB; - *gl_type = GL_UNSIGNED_SHORT_5_6_5; - break; - case IMGFMT_BGR24: - *gl_format = GL_BGR; - *gl_type = GL_UNSIGNED_BYTE; - break; - case IMGFMT_BGRA: - *gl_texfmt = 4; - *gl_format = GL_BGRA; - *gl_type = GL_UNSIGNED_BYTE; - break; - default: - *gl_texfmt = 4; - *gl_format = GL_RGBA; - *gl_type = GL_UNSIGNED_BYTE; - supported = 0; - } -#ifdef TEXTUREFORMAT_ALWAYS - *gl_texfmt = TEXTUREFORMAT_ALWAYS; -#endif - return supported; -} - -struct feature { - int id; - const char *name; -}; - -static const struct feature features[] = { - {MPGL_CAP_GL, "Basic OpenGL"}, - {MPGL_CAP_GL_LEGACY, "Legacy OpenGL"}, - {MPGL_CAP_GL2, "OpenGL 2.0"}, - {MPGL_CAP_GL21, "OpenGL 2.1"}, - {MPGL_CAP_GL3, "OpenGL 3.0"}, - {MPGL_CAP_FB, "Framebuffers"}, - {MPGL_CAP_VAO, "VAOs"}, - {MPGL_CAP_SRGB_TEX, "sRGB textures"}, - {MPGL_CAP_SRGB_FB, "sRGB framebuffers"}, - {MPGL_CAP_FLOAT_TEX, "Float textures"}, - {MPGL_CAP_TEX_RG, "RG textures"}, - {MPGL_CAP_NO_SW, "NO_SW"}, - {0}, -}; - -static void list_features(int set, int msgl, bool invert) -{ - for (const struct feature *f = &features[0]; f->id; f++) { - if (invert == !(f->id & set)) - mp_msg(MSGT_VO, msgl, " [%s]", f->name); - } - mp_msg(MSGT_VO, msgl, "\n"); -} - -// This guesses if the current GL context is a suspected software renderer. -static bool is_software_gl(GL *gl) -{ - const char *renderer = gl->GetString(GL_RENDERER); - const char *vendor = gl->GetString(GL_VENDOR); - return !(renderer && vendor) || - strcmp(renderer, "Software Rasterizer") == 0 || - strstr(renderer, "llvmpipe") || - strcmp(vendor, "Microsoft Corporation") == 0 || - strcmp(renderer, "Mesa X11") == 0; -} - -#ifdef HAVE_LIBDL -#include <dlfcn.h> -#endif -/** - * \brief find address of a linked function - * \param s name of function to find - * \return address of function or NULL if not found - */ -static void *getdladdr(const char *s) -{ - void *ret = NULL; -#ifdef HAVE_LIBDL - void *handle = dlopen(NULL, RTLD_LAZY); - if (!handle) - return NULL; - ret = dlsym(handle, s); - dlclose(handle); -#endif - return ret; -} - -#define FN_OFFS(name) offsetof(GL, name) - -// Define the function with a "hard" reference to the function as fallback. -// (This requires linking with a compatible OpenGL library.) -#define DEF_FN_HARD(name) {FN_OFFS(name), {"gl" # name}, gl ## name} - -#define DEF_FN(name) {FN_OFFS(name), {"gl" # name}} -#define DEF_FN_NAMES(name, ...) {FN_OFFS(name), {__VA_ARGS__}} - -struct gl_function { - ptrdiff_t offset; - char *funcnames[7]; - void *fallback; -}; - -struct gl_functions { - const char *extension; // introduced with this extension in any version - int provides; // bitfield of MPGL_CAP_* constants - int ver_core; // introduced as required function - int ver_removed; // removed as required function (no replacement) - bool partial_ok; // loading only some functions is ok - struct gl_function *functions; -}; - -#define MAX_FN_COUNT 50 // max functions per gl_functions section - -struct gl_functions gl_functions[] = { - // GL functions which are always available anywhere at least since 1.1 - { - .ver_core = MPGL_VER(1, 1), - .provides = MPGL_CAP_GL, - .functions = (struct gl_function[]) { - DEF_FN_HARD(Viewport), - DEF_FN_HARD(Clear), - DEF_FN_HARD(GenTextures), - DEF_FN_HARD(DeleteTextures), - DEF_FN_HARD(TexEnvi), - DEF_FN_HARD(ClearColor), - DEF_FN_HARD(Enable), - DEF_FN_HARD(Disable), - DEF_FN_HARD(DrawBuffer), - DEF_FN_HARD(DepthMask), - DEF_FN_HARD(BlendFunc), - DEF_FN_HARD(Flush), - DEF_FN_HARD(Finish), - DEF_FN_HARD(PixelStorei), - DEF_FN_HARD(TexImage1D), - DEF_FN_HARD(TexImage2D), - DEF_FN_HARD(TexSubImage2D), - DEF_FN_HARD(GetTexImage), - DEF_FN_HARD(TexParameteri), - DEF_FN_HARD(TexParameterf), - DEF_FN_HARD(TexParameterfv), - DEF_FN_HARD(GetIntegerv), - DEF_FN_HARD(GetBooleanv), - DEF_FN_HARD(ColorMask), - DEF_FN_HARD(ReadPixels), - DEF_FN_HARD(ReadBuffer), - DEF_FN_HARD(DrawArrays), - DEF_FN_HARD(GetString), - DEF_FN_HARD(GetError), - {0} - }, - }, - // GL 2.0-3.x functions - { - .ver_core = MPGL_VER(2, 0), - .provides = MPGL_CAP_GL2, - .functions = (struct gl_function[]) { - DEF_FN(GenBuffers), - DEF_FN(DeleteBuffers), - DEF_FN(BindBuffer), - DEF_FN(MapBuffer), - DEF_FN(UnmapBuffer), - DEF_FN(BufferData), - DEF_FN(ActiveTexture), - DEF_FN(BindTexture), - DEF_FN(GetAttribLocation), - DEF_FN(EnableVertexAttribArray), - DEF_FN(DisableVertexAttribArray), - DEF_FN(VertexAttribPointer), - DEF_FN(UseProgram), - DEF_FN(GetUniformLocation), - DEF_FN(CompileShader), - DEF_FN(CreateProgram), - DEF_FN(CreateShader), - DEF_FN(ShaderSource), - DEF_FN(LinkProgram), - DEF_FN(AttachShader), - DEF_FN(DeleteShader), - DEF_FN(DeleteProgram), - DEF_FN(GetShaderInfoLog), - DEF_FN(GetShaderiv), - DEF_FN(GetProgramInfoLog), - DEF_FN(GetProgramiv), - DEF_FN(BindAttribLocation), - DEF_FN(Uniform1f), - DEF_FN(Uniform2f), - DEF_FN(Uniform3f), - DEF_FN(Uniform1i), - DEF_FN(UniformMatrix3fv), - DEF_FN(TexImage3D), - {0}, - }, - }, - // GL 2.1-3.x functions (also: GLSL 120 shaders) - { - .ver_core = MPGL_VER(2, 1), - .provides = MPGL_CAP_GL21, - .functions = (struct gl_function[]) { - DEF_FN(UniformMatrix4x3fv), - {0} - }, - }, - // GL 3.x core only functions. - { - .ver_core = MPGL_VER(3, 0), - .provides = MPGL_CAP_GL3 | MPGL_CAP_SRGB_TEX | MPGL_CAP_SRGB_FB, - .functions = (struct gl_function[]) { - DEF_FN(GetStringi), - {0} - }, - }, - // Framebuffers, extension in GL 2.x, core in GL 3.x core. - { - .ver_core = MPGL_VER(3, 0), - .extension = "GL_ARB_framebuffer_object", - .provides = MPGL_CAP_FB, - .functions = (struct gl_function[]) { - DEF_FN(BindFramebuffer), - DEF_FN(GenFramebuffers), - DEF_FN(DeleteFramebuffers), - DEF_FN(CheckFramebufferStatus), - DEF_FN(FramebufferTexture2D), - {0} - }, - }, - // Framebuffers, alternative extension name. - { - .ver_removed = MPGL_VER(3, 0), // don't touch these fn names in 3.x - .extension = "GL_EXT_framebuffer_object", - .provides = MPGL_CAP_FB, - .functions = (struct gl_function[]) { - DEF_FN_NAMES(BindFramebuffer, "glBindFramebufferEXT"), - DEF_FN_NAMES(GenFramebuffers, "glGenFramebuffersEXT"), - DEF_FN_NAMES(DeleteFramebuffers, "glDeleteFramebuffersEXT"), - DEF_FN_NAMES(CheckFramebufferStatus, "glCheckFramebufferStatusEXT"), - DEF_FN_NAMES(FramebufferTexture2D, "glFramebufferTexture2DEXT"), - {0} - }, - }, - // VAOs, extension in GL 2.x, core in GL 3.x core. - { - .ver_core = MPGL_VER(3, 0), - .extension = "GL_ARB_vertex_array_object", - .provides = MPGL_CAP_VAO, - .functions = (struct gl_function[]) { - DEF_FN(GenVertexArrays), - DEF_FN(BindVertexArray), - DEF_FN(DeleteVertexArrays), - {0} - } - }, - // sRGB textures, extension in GL 2.x, core in GL 3.x core. - { - .ver_core = MPGL_VER(3, 0), - .extension = "GL_EXT_texture_sRGB", - .provides = MPGL_CAP_SRGB_TEX, - .functions = (struct gl_function[]) {{0}}, - }, - // sRGB framebuffers, extension in GL 2.x, core in GL 3.x core. - { - .ver_core = MPGL_VER(3, 0), - .extension = "GL_EXT_framebuffer_sRGB", - .provides = MPGL_CAP_SRGB_FB, - .functions = (struct gl_function[]) {{0}}, - }, - // Float textures, extension in GL 2.x, core in GL 3.x core. - { - .ver_core = MPGL_VER(3, 0), - .extension = "GL_ARB_texture_float", - .provides = MPGL_CAP_FLOAT_TEX, - .functions = (struct gl_function[]) {{0}}, - }, - // GL_RED / GL_RG textures, extension in GL 2.x, core in GL 3.x core. - { - .ver_core = MPGL_VER(3, 0), - .extension = "GL_ARB_texture_rg", - .provides = MPGL_CAP_TEX_RG, - .functions = (struct gl_function[]) {{0}}, - }, - // Swap control, always an OS specific extension - { - .extension = "_swap_control", - .functions = (struct gl_function[]) { - DEF_FN_NAMES(SwapInterval, "glXSwapIntervalSGI", "glXSwapInterval", - "wglSwapIntervalSGI", "wglSwapInterval", - "wglSwapIntervalEXT"), - {0} - }, - }, - // GL legacy functions in GL 1.x - 2.x, removed from GL 3.x - { - .ver_core = MPGL_VER(1, 1), - .ver_removed = MPGL_VER(3, 0), - .provides = MPGL_CAP_GL_LEGACY, - .functions = (struct gl_function[]) { - DEF_FN_HARD(Begin), - DEF_FN_HARD(End), - DEF_FN_HARD(MatrixMode), - DEF_FN_HARD(LoadIdentity), - DEF_FN_HARD(Translated), - DEF_FN_HARD(Scaled), - DEF_FN_HARD(Ortho), - DEF_FN_HARD(PushMatrix), - DEF_FN_HARD(PopMatrix), - DEF_FN_HARD(GenLists), - DEF_FN_HARD(DeleteLists), - DEF_FN_HARD(NewList), - DEF_FN_HARD(EndList), - DEF_FN_HARD(CallList), - DEF_FN_HARD(CallLists), - DEF_FN_HARD(Color4ub), - DEF_FN_HARD(Color4f), - DEF_FN_HARD(TexCoord2f), - DEF_FN_HARD(TexCoord2fv), - DEF_FN_HARD(Vertex2f), - DEF_FN_HARD(VertexPointer), - DEF_FN_HARD(ColorPointer), - DEF_FN_HARD(TexCoordPointer), - DEF_FN_HARD(EnableClientState), - DEF_FN_HARD(DisableClientState), - {0} - }, - }, - // Loading of old extensions, which are later added to GL 2.0. - // NOTE: actually we should be checking the extension strings: the OpenGL - // library could provide an entry point, but not implement it. - // But the previous code didn't do that, and nobody ever complained. - { - .ver_removed = MPGL_VER(2, 1), - .partial_ok = true, - .functions = (struct gl_function[]) { - DEF_FN_NAMES(GenBuffers, "glGenBuffers", "glGenBuffersARB"), - DEF_FN_NAMES(DeleteBuffers, "glDeleteBuffers", "glDeleteBuffersARB"), - DEF_FN_NAMES(BindBuffer, "glBindBuffer", "glBindBufferARB"), - DEF_FN_NAMES(MapBuffer, "glMapBuffer", "glMapBufferARB"), - DEF_FN_NAMES(UnmapBuffer, "glUnmapBuffer", "glUnmapBufferARB"), - DEF_FN_NAMES(BufferData, "glBufferData", "glBufferDataARB"), - DEF_FN_NAMES(ActiveTexture, "glActiveTexture", "glActiveTextureARB"), - DEF_FN_NAMES(BindTexture, "glBindTexture", "glBindTextureARB", "glBindTextureEXT"), - DEF_FN_NAMES(MultiTexCoord2f, "glMultiTexCoord2f", "glMultiTexCoord2fARB"), - DEF_FN_NAMES(TexImage3D, "glTexImage3D"), - {0} - }, - }, - // Ancient ARB shaders. - { - .extension = "_program", - .ver_removed = MPGL_VER(3, 0), - .functions = (struct gl_function[]) { - DEF_FN_NAMES(GenPrograms, "glGenProgramsARB"), - DEF_FN_NAMES(DeletePrograms, "glDeleteProgramsARB"), - DEF_FN_NAMES(BindProgram, "glBindProgramARB"), - DEF_FN_NAMES(ProgramString, "glProgramStringARB"), - DEF_FN_NAMES(GetProgramivARB, "glGetProgramivARB"), - DEF_FN_NAMES(ProgramEnvParameter4f, "glProgramEnvParameter4fARB"), - {0} - }, - }, - // Ancient ATI extensions. - { - .extension = "ATI_fragment_shader", - .ver_removed = MPGL_VER(3, 0), - .functions = (struct gl_function[]) { - DEF_FN_NAMES(BeginFragmentShader, "glBeginFragmentShaderATI"), - DEF_FN_NAMES(EndFragmentShader, "glEndFragmentShaderATI"), - DEF_FN_NAMES(SampleMap, "glSampleMapATI"), - DEF_FN_NAMES(ColorFragmentOp2, "glColorFragmentOp2ATI"), - DEF_FN_NAMES(ColorFragmentOp3, "glColorFragmentOp3ATI"), - DEF_FN_NAMES(SetFragmentShaderConstant, "glSetFragmentShaderConstantATI"), - {0} - }, - }, -}; - -#undef FN_OFFS -#undef DEF_FN_HARD -#undef DEF_FN -#undef DEF_FN_NAMES - - -/** - * \brief find the function pointers of some useful OpenGL extensions - * \param getProcAddress function to resolve function names, may be NULL - * \param ext2 an extra extension string - */ -static void getFunctions(GL *gl, void *(*getProcAddress)(const GLubyte *), - const char *ext2, bool gl3) -{ - talloc_free_children(gl); - *gl = (GL) { - .extensions = talloc_strdup(gl, ext2 ? ext2 : ""), - }; - - if (!getProcAddress) - getProcAddress = (void *)getdladdr; - - GLint major = 0, minor = 0; - if (gl3) { - gl->GetStringi = getProcAddress("glGetStringi"); - gl->GetIntegerv = getProcAddress("glGetIntegerv"); - - if (!(gl->GetStringi && gl->GetIntegerv)) - return; - - gl->GetIntegerv(GL_MAJOR_VERSION, &major); - gl->GetIntegerv(GL_MINOR_VERSION, &minor); - - GLint exts; - gl->GetIntegerv(GL_NUM_EXTENSIONS, &exts); - for (int n = 0; n < exts; n++) { - gl->extensions - = talloc_asprintf_append(gl->extensions, " %s", - gl->GetStringi(GL_EXTENSIONS, n)); - } - } else { - gl->GetString = getProcAddress("glGetString"); - if (!gl->GetString) - gl->GetString = glGetString; - - const char *ext = (char*)gl->GetString(GL_EXTENSIONS); - gl->extensions = talloc_asprintf_append(gl->extensions, " %s", ext); - - const char *version = gl->GetString(GL_VERSION); - sscanf(version, "%d.%d", &major, &minor); - } - gl->version = MPGL_VER(major, minor); - - mp_msg(MSGT_VO, MSGL_V, "[gl] Detected OpenGL %d.%d.\n", major, minor); - mp_msg(MSGT_VO, MSGL_DBG2, "[gl] Combined OpenGL extensions string:\n%s\n", - gl->extensions); - - for (int n = 0; n < sizeof(gl_functions) / sizeof(gl_functions[0]); n++) { - struct gl_functions *section = &gl_functions[n]; - - // With gl3=false, we could have a legacy context, where functionality - // is never removed. (E.g. the context could be at version >= 3.0, but - // legacy functions like glBegin still exist and work.) - if (gl3 && section->ver_removed && gl->version >= section->ver_removed) - continue; - - bool must_exist = section->ver_core && gl->version >= section->ver_core - && !section->partial_ok; - - if (!must_exist && section->extension && - !strstr(gl->extensions, section->extension)) - continue; - - void *loaded[MAX_FN_COUNT] = {0}; - bool all_loaded = true; - - for (int i = 0; section->functions[i].funcnames[0]; i++) { - struct gl_function *fn = §ion->functions[i]; - void *ptr = NULL; - for (int x = 0; fn->funcnames[x]; x++) { - ptr = getProcAddress((const GLubyte *)fn->funcnames[x]); - if (ptr) - break; - } - if (!ptr) - ptr = fn->fallback; - if (!ptr) { - all_loaded = false; - if (must_exist) { - // Either we or the driver are not conforming to OpenGL. - mp_msg(MSGT_VO, MSGL_ERR, "[gl] Required function '%s' not " - "found.\n", fn->funcnames[0]); - talloc_free_children(gl); - *gl = (GL) {0}; - return; - } - } - assert(i < MAX_FN_COUNT); - loaded[i] = ptr; - } - - if (all_loaded || section->partial_ok) { - gl->mpgl_caps |= section->provides; - for (int i = 0; section->functions[i].funcnames[0]; i++) { - struct gl_function *fn = §ion->functions[i]; - void **funcptr = (void**)(((char*)gl) + fn->offset); - if (loaded[i]) - *funcptr = loaded[i]; - } - } - } - - gl->glsl_version = 0; - if (gl->version >= MPGL_VER(2, 0)) - gl->glsl_version = 110; - if (gl->version >= MPGL_VER(2, 1)) - gl->glsl_version = 120; - if (gl->version >= MPGL_VER(3, 0)) - gl->glsl_version = 130; - // Specifically needed for OSX (normally we request 3.0 contexts only, but - // OSX always creates 3.2 contexts when requesting a core context). - if (gl->version >= MPGL_VER(3, 2)) - gl->glsl_version = 150; - - if (!is_software_gl(gl)) - gl->mpgl_caps |= MPGL_CAP_NO_SW; - - mp_msg(MSGT_VO, MSGL_V, "[gl] Detected OpenGL features:"); - list_features(gl->mpgl_caps, MSGL_V, false); -} - -/** - * \brief create a texture and set some defaults - * \param target texture taget, usually GL_TEXTURE_2D - * \param fmt internal texture format - * \param format texture host data format - * \param type texture host data type - * \param filter filter used for scaling, e.g. GL_LINEAR - * \param w texture width - * \param h texture height - * \param val luminance value to fill texture with - * \ingroup gltexture - */ -void glCreateClearTex(GL *gl, GLenum target, GLenum fmt, GLenum format, - GLenum type, GLint filter, int w, int h, - unsigned char val) -{ - GLfloat fval = (GLfloat)val / 255.0; - GLfloat border[4] = { - fval, fval, fval, fval - }; - int stride; - char *init; - if (w == 0) - w = 1; - if (h == 0) - h = 1; - stride = w * glFmt2bpp(format, type); - if (!stride) - return; - init = malloc(stride * h); - memset(init, val, stride * h); - glAdjustAlignment(gl, stride); - gl->PixelStorei(GL_UNPACK_ROW_LENGTH, w); - gl->TexImage2D(target, 0, fmt, w, h, 0, format, type, init); - gl->TexParameterf(target, GL_TEXTURE_PRIORITY, 1.0); - gl->TexParameteri(target, GL_TEXTURE_MIN_FILTER, filter); - gl->TexParameteri(target, GL_TEXTURE_MAG_FILTER, filter); - gl->TexParameteri(target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - gl->TexParameteri(target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - // Border texels should not be used with CLAMP_TO_EDGE - // We set a sane default anyway. - gl->TexParameterfv(target, GL_TEXTURE_BORDER_COLOR, border); - free(init); -} - -static GLint detect_hqtexfmt(GL *gl) -{ - const char *extensions = (const char *)gl->GetString(GL_EXTENSIONS); - if (strstr(extensions, "_texture_float")) - return GL_RGB32F; - else if (strstr(extensions, "NV_float_buffer")) - return GL_FLOAT_RGB32_NV; - return GL_RGB16; -} - -/** - * \brief creates a texture from a PPM file - * \param target texture taget, usually GL_TEXTURE_2D - * \param fmt internal texture format, 0 for default - * \param filter filter used for scaling, e.g. GL_LINEAR - * \param f file to read PPM from - * \param width [out] width of texture - * \param height [out] height of texture - * \param maxval [out] maxval value from PPM file - * \return 0 on error, 1 otherwise - * \ingroup gltexture - */ -int glCreatePPMTex(GL *gl, GLenum target, GLenum fmt, GLint filter, - FILE *f, int *width, int *height, int *maxval) -{ - int w, h, m, bpp; - GLenum type; - uint8_t *data = read_pnm(f, &w, &h, &bpp, &m); - GLint hqtexfmt = detect_hqtexfmt(gl); - if (!data || (bpp != 3 && bpp != 6)) { - free(data); - return 0; - } - if (!fmt) { - fmt = bpp == 6 ? hqtexfmt : 3; - if (fmt == GL_FLOAT_RGB32_NV && target != GL_TEXTURE_RECTANGLE) - fmt = GL_RGB16; - } - type = bpp == 6 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_BYTE; - glCreateClearTex(gl, target, fmt, GL_RGB, type, filter, w, h, 0); - glUploadTex(gl, target, GL_RGB, type, - data, w * bpp, 0, 0, w, h, 0); - free(data); - if (width) - *width = w; - if (height) - *height = h; - if (maxval) - *maxval = m; - return 1; -} - -/** - * \brief return the number of bytes per pixel for the given format - * \param format OpenGL format - * \param type OpenGL type - * \return bytes per pixel - * \ingroup glgeneral - * - * Does not handle all possible variants, just those used by MPlayer - */ -int glFmt2bpp(GLenum format, GLenum type) -{ - int component_size = 0; - switch (type) { - case GL_UNSIGNED_BYTE_3_3_2: - case GL_UNSIGNED_BYTE_2_3_3_REV: - return 1; - case GL_UNSIGNED_SHORT_5_5_5_1: - case GL_UNSIGNED_SHORT_1_5_5_5_REV: - case GL_UNSIGNED_SHORT_5_6_5: - case GL_UNSIGNED_SHORT_5_6_5_REV: - return 2; - case GL_UNSIGNED_BYTE: - component_size = 1; - break; - case GL_UNSIGNED_SHORT: - component_size = 2; - break; - } - switch (format) { - case GL_LUMINANCE: - case GL_ALPHA: - return component_size; - case GL_YCBCR_MESA: - return 2; - case GL_RGB: - case GL_BGR: - return 3 * component_size; - case GL_RGBA: - case GL_BGRA: - return 4 * component_size; - case GL_RED: - return component_size; - case GL_RG: - case GL_LUMINANCE_ALPHA: - return 2 * component_size; - } - abort(); // unknown -} - -/** - * \brief upload a texture, handling things like stride and slices - * \param target texture target, usually GL_TEXTURE_2D - * \param format OpenGL format of data - * \param type OpenGL type of data - * \param dataptr data to upload - * \param stride data stride - * \param x x offset in texture - * \param y y offset in texture - * \param w width of the texture part to upload - * \param h height of the texture part to upload - * \param slice height of an upload slice, 0 for all at once - * \ingroup gltexture - */ -void glUploadTex(GL *gl, GLenum target, GLenum format, GLenum type, - const void *dataptr, int stride, - int x, int y, int w, int h, int slice) -{ - const uint8_t *data = dataptr; - int y_max = y + h; - if (w <= 0 || h <= 0) - return; - if (slice <= 0) - slice = h; - if (stride < 0) { - data += (h - 1) * stride; - stride = -stride; - } - // this is not always correct, but should work for MPlayer - glAdjustAlignment(gl, stride); - gl->PixelStorei(GL_UNPACK_ROW_LENGTH, stride / glFmt2bpp(format, type)); - for (; y + slice <= y_max; y += slice) { - gl->TexSubImage2D(target, 0, x, y, w, slice, format, type, data); - data += stride * slice; - } - if (y < y_max) - gl->TexSubImage2D(target, 0, x, y, w, y_max - y, format, type, data); -} - -// Like glUploadTex, but upload a byte array with all elements set to val. -// If scratch is not NULL, points to a resizeable talloc memory block than can -// be freely used by the function (for avoiding temporary memory allocations). -void glClearTex(GL *gl, GLenum target, GLenum format, GLenum type, - int x, int y, int w, int h, uint8_t val, void **scratch) -{ - int bpp = glFmt2bpp(format, type); - int stride = w * bpp; - int size = h * stride; - if (size < 1) - return; - void *data = scratch ? *scratch : NULL; - if (talloc_get_size(data) < size) - data = talloc_realloc(NULL, data, char *, size); - memset(data, val, size); - glAdjustAlignment(gl, stride); - gl->PixelStorei(GL_UNPACK_ROW_LENGTH, w); - gl->TexSubImage2D(target, 0, x, y, w, h, format, type, data); - if (scratch) { - *scratch = data; - } else { - talloc_free(data); - } -} - -/** - * \brief download a texture, handling things like stride and slices - * \param target texture target, usually GL_TEXTURE_2D - * \param format OpenGL format of data - * \param type OpenGL type of data - * \param dataptr destination memory for download - * \param stride data stride (must be positive) - * \ingroup gltexture - */ -void glDownloadTex(GL *gl, GLenum target, GLenum format, GLenum type, - void *dataptr, int stride) -{ - // this is not always correct, but should work for MPlayer - glAdjustAlignment(gl, stride); - gl->PixelStorei(GL_PACK_ROW_LENGTH, stride / glFmt2bpp(format, type)); - gl->GetTexImage(target, 0, format, type, dataptr); -} - -/** - * \brief Setup ATI version of register combiners for YUV to RGB conversion. - * \param csp_params parameters used for colorspace conversion - * \param text if set use the GL_ATI_text_fragment_shader API as - * used on OS X. - */ -static void glSetupYUVFragmentATI(GL *gl, struct mp_csp_params *csp_params, - int text) -{ - GLint i; - float yuv2rgb[3][4]; - - gl->GetIntegerv(GL_MAX_TEXTURE_UNITS, &i); - if (i < 3) - mp_msg(MSGT_VO, MSGL_ERR, - "[gl] 3 texture units needed for YUV combiner (ATI) support (found %i)\n", i); - - mp_get_yuv2rgb_coeffs(csp_params, yuv2rgb); - for (i = 0; i < 3; i++) { - int j; - yuv2rgb[i][3] -= -0.5 * (yuv2rgb[i][1] + yuv2rgb[i][2]); - for (j = 0; j < 4; j++) { - yuv2rgb[i][j] *= 0.125; - yuv2rgb[i][j] += 0.5; - if (yuv2rgb[i][j] > 1) - yuv2rgb[i][j] = 1; - if (yuv2rgb[i][j] < 0) - yuv2rgb[i][j] = 0; - } - } - if (text == 0) { - GLfloat c0[4] = { yuv2rgb[0][0], yuv2rgb[1][0], yuv2rgb[2][0] }; - GLfloat c1[4] = { yuv2rgb[0][1], yuv2rgb[1][1], yuv2rgb[2][1] }; - GLfloat c2[4] = { yuv2rgb[0][2], yuv2rgb[1][2], yuv2rgb[2][2] }; - GLfloat c3[4] = { yuv2rgb[0][3], yuv2rgb[1][3], yuv2rgb[2][3] }; - if (!gl->BeginFragmentShader || !gl->EndFragmentShader || - !gl->SetFragmentShaderConstant || !gl->SampleMap || - !gl->ColorFragmentOp2 || !gl->ColorFragmentOp3) { - mp_msg(MSGT_VO, MSGL_FATAL, "[gl] Combiner (ATI) functions missing!\n"); - return; - } - gl->GetIntegerv(GL_NUM_FRAGMENT_REGISTERS_ATI, &i); - if (i < 3) - mp_msg(MSGT_VO, MSGL_ERR, - "[gl] 3 registers needed for YUV combiner (ATI) support (found %i)\n", i); - gl->BeginFragmentShader(); - gl->SetFragmentShaderConstant(GL_CON_0_ATI, c0); - gl->SetFragmentShaderConstant(GL_CON_1_ATI, c1); - gl->SetFragmentShaderConstant(GL_CON_2_ATI, c2); - gl->SetFragmentShaderConstant(GL_CON_3_ATI, c3); - gl->SampleMap(GL_REG_0_ATI, GL_TEXTURE0, GL_SWIZZLE_STR_ATI); - gl->SampleMap(GL_REG_1_ATI, GL_TEXTURE1, GL_SWIZZLE_STR_ATI); - gl->SampleMap(GL_REG_2_ATI, GL_TEXTURE2, GL_SWIZZLE_STR_ATI); - gl->ColorFragmentOp2(GL_MUL_ATI, GL_REG_1_ATI, GL_NONE, GL_NONE, - GL_REG_1_ATI, GL_NONE, GL_BIAS_BIT_ATI, - GL_CON_1_ATI, GL_NONE, GL_BIAS_BIT_ATI); - gl->ColorFragmentOp3(GL_MAD_ATI, GL_REG_2_ATI, GL_NONE, GL_NONE, - GL_REG_2_ATI, GL_NONE, GL_BIAS_BIT_ATI, - GL_CON_2_ATI, GL_NONE, GL_BIAS_BIT_ATI, - GL_REG_1_ATI, GL_NONE, GL_NONE); - gl->ColorFragmentOp3(GL_MAD_ATI, GL_REG_0_ATI, GL_NONE, GL_NONE, - GL_REG_0_ATI, GL_NONE, GL_NONE, - GL_CON_0_ATI, GL_NONE, GL_BIAS_BIT_ATI, - GL_REG_2_ATI, GL_NONE, GL_NONE); - gl->ColorFragmentOp2(GL_ADD_ATI, GL_REG_0_ATI, GL_NONE, GL_8X_BIT_ATI, - GL_REG_0_ATI, GL_NONE, GL_NONE, - GL_CON_3_ATI, GL_NONE, GL_BIAS_BIT_ATI); - gl->EndFragmentShader(); - } else { - static const char template[] = - "!!ATIfs1.0\n" - "StartConstants;\n" - " CONSTANT c0 = {%e, %e, %e};\n" - " CONSTANT c1 = {%e, %e, %e};\n" - " CONSTANT c2 = {%e, %e, %e};\n" - " CONSTANT c3 = {%e, %e, %e};\n" - "EndConstants;\n" - "StartOutputPass;\n" - " SampleMap r0, t0.str;\n" - " SampleMap r1, t1.str;\n" - " SampleMap r2, t2.str;\n" - " MUL r1.rgb, r1.bias, c1.bias;\n" - " MAD r2.rgb, r2.bias, c2.bias, r1;\n" - " MAD r0.rgb, r0, c0.bias, r2;\n" - " ADD r0.rgb.8x, r0, c3.bias;\n" - "EndPass;\n"; - char buffer[512]; - snprintf(buffer, sizeof(buffer), template, - yuv2rgb[0][0], yuv2rgb[1][0], yuv2rgb[2][0], - yuv2rgb[0][1], yuv2rgb[1][1], yuv2rgb[2][1], - yuv2rgb[0][2], yuv2rgb[1][2], yuv2rgb[2][2], - yuv2rgb[0][3], yuv2rgb[1][3], yuv2rgb[2][3]); - mp_msg(MSGT_VO, MSGL_DBG2, "[gl] generated fragment program:\n%s\n", - buffer); - loadGPUProgram(gl, GL_TEXT_FRAGMENT_SHADER_ATI, buffer); - } -} - -// Replace all occurances of variables named "$"+name (e.g. $foo) in *text with -// replace, and return the result. *text must have been allocated with talloc. -static void replace_var_str(char **text, const char *name, const char *replace) -{ - size_t namelen = strlen(name); - char *nextvar = *text; - void *parent = talloc_parent(*text); - for (;;) { - nextvar = strchr(nextvar, '$'); - if (!nextvar) - break; - char *until = nextvar; - nextvar++; - if (strncmp(nextvar, name, namelen) != 0) - continue; - nextvar += namelen; - // try not to replace prefixes of other vars (e.g. $foo vs. $foo_bar) - char term = nextvar[0]; - if (isalnum(term) || term == '_') - continue; - int prelength = until - *text; - int postlength = nextvar - *text; - char *n = talloc_asprintf(parent, "%.*s%s%s", prelength, *text, replace, - nextvar); - talloc_free(*text); - *text = n; - nextvar = *text + postlength; - } -} - -static void replace_var_float(char **text, const char *name, float replace) -{ - char *s = talloc_asprintf(NULL, "%e", replace); - replace_var_str(text, name, s); - talloc_free(s); -} - -static void replace_var_char(char **text, const char *name, char replace) -{ - char s[2] = { replace, '\0' }; - replace_var_str(text, name, s); -} - -// Append template to *text. Possibly initialize *text if it's NULL. -static void append_template(char **text, const char* template) -{ - if (!text) - *text = talloc_strdup(NULL, template); - else - *text = talloc_strdup_append(*text, template); -} - -/** - * \brief helper function for gen_spline_lookup_tex - * \param x subpixel-position ((0,1) range) to calculate weights for - * \param dst where to store transformed weights, must provide space for 4 GLfloats - * - * calculates the weights and stores them after appropriate transformation - * for the scaler fragment program. - */ -static void store_weights(float x, GLfloat *dst) -{ - float w0 = (((-1 * x + 3) * x - 3) * x + 1) / 6; - float w1 = (((3 * x - 6) * x + 0) * x + 4) / 6; - float w2 = (((-3 * x + 3) * x + 3) * x + 1) / 6; - float w3 = (((1 * x + 0) * x + 0) * x + 0) / 6; - *dst++ = 1 + x - w1 / (w0 + w1); - *dst++ = 1 - x + w3 / (w2 + w3); - *dst++ = w0 + w1; - *dst++ = 0; -} - -//! to avoid artefacts this should be rather large -#define LOOKUP_BSPLINE_RES (2 * 1024) -/** - * \brief creates the 1D lookup texture needed for fast higher-order filtering - * \param unit texture unit to attach texture to - */ -static void gen_spline_lookup_tex(GL *gl, GLenum unit) -{ - GLfloat *tex = calloc(4 * LOOKUP_BSPLINE_RES, sizeof(*tex)); - GLfloat *tp = tex; - int i; - for (i = 0; i < LOOKUP_BSPLINE_RES; i++) { - float x = (float)(i + 0.5) / LOOKUP_BSPLINE_RES; - store_weights(x, tp); - tp += 4; - } - store_weights(0, tex); - store_weights(1, &tex[4 * (LOOKUP_BSPLINE_RES - 1)]); - gl->ActiveTexture(unit); - gl->TexImage1D(GL_TEXTURE_1D, 0, GL_RGBA16, LOOKUP_BSPLINE_RES, 0, GL_RGBA, - GL_FLOAT, tex); - gl->TexParameterf(GL_TEXTURE_1D, GL_TEXTURE_PRIORITY, 1.0); - gl->TexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - gl->TexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - gl->TexParameteri(GL_TEXTURE_1D, GL_TEXTURE_WRAP_S, GL_REPEAT); - gl->ActiveTexture(GL_TEXTURE0); - free(tex); -} - -#define NOISE_RES 2048 - -/** - * \brief creates the 1D lookup texture needed to generate pseudo-random numbers. - * \param unit texture unit to attach texture to - */ -static void gen_noise_lookup_tex(GL *gl, GLenum unit) { - GLfloat *tex = calloc(NOISE_RES, sizeof(*tex)); - uint32_t lcg = 0x79381c11; - int i; - for (i = 0; i < NOISE_RES; i++) - tex[i] = (double)i / (NOISE_RES - 1); - for (i = 0; i < NOISE_RES - 1; i++) { - int remain = NOISE_RES - i; - int idx = i + (lcg >> 16) % remain; - GLfloat tmp = tex[i]; - tex[i] = tex[idx]; - tex[idx] = tmp; - lcg = lcg * 1664525 + 1013904223; - } - gl->ActiveTexture(unit); - gl->TexImage1D(GL_TEXTURE_1D, 0, 1, NOISE_RES, 0, GL_RED, GL_FLOAT, tex); - gl->TexParameterf(GL_TEXTURE_1D, GL_TEXTURE_PRIORITY, 1.0); - gl->TexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - gl->TexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - gl->TexParameteri(GL_TEXTURE_1D, GL_TEXTURE_WRAP_S, GL_REPEAT); - gl->ActiveTexture(GL_TEXTURE0); - free(tex); -} - -#define SAMPLE(dest, coord, texture) \ - "TEX textemp, " coord ", " texture ", $tex_type;\n" \ - "MOV " dest ", textemp.r;\n" - -static const char bilin_filt_template[] = - SAMPLE("yuv.$out_comp","fragment.texcoord[$in_tex]","texture[$in_tex]"); - -#define BICUB_FILT_MAIN \ - /* first y-interpolation */ \ - "ADD coord, fragment.texcoord[$in_tex].xyxy, cdelta.xyxw;\n" \ - "ADD coord2, fragment.texcoord[$in_tex].xyxy, cdelta.zyzw;\n" \ - SAMPLE("a.r","coord.xyxy","texture[$in_tex]") \ - SAMPLE("a.g","coord.zwzw","texture[$in_tex]") \ - /* second y-interpolation */ \ - SAMPLE("b.r","coord2.xyxy","texture[$in_tex]") \ - SAMPLE("b.g","coord2.zwzw","texture[$in_tex]") \ - "LRP a.b, parmy.b, a.rrrr, a.gggg;\n" \ - "LRP a.a, parmy.b, b.rrrr, b.gggg;\n" \ - /* x-interpolation */ \ - "LRP yuv.$out_comp, parmx.b, a.bbbb, a.aaaa;\n" - -static const char bicub_filt_template_2D[] = - "MAD coord.xy, fragment.texcoord[$in_tex], {$texw, $texh}, {0.5, 0.5};\n" - "TEX parmx, coord.x, texture[$texs], 1D;\n" - "MUL cdelta.xz, parmx.rrgg, {-$ptw, 0, $ptw, 0};\n" - "TEX parmy, coord.y, texture[$texs], 1D;\n" - "MUL cdelta.yw, parmy.rrgg, {0, -$pth, 0, $pth};\n" - BICUB_FILT_MAIN; - -static const char bicub_filt_template_RECT[] = - "ADD coord, fragment.texcoord[$in_tex], {0.5, 0.5};\n" - "TEX parmx, coord.x, texture[$texs], 1D;\n" - "MUL cdelta.xz, parmx.rrgg, {-1, 0, 1, 0};\n" - "TEX parmy, coord.y, texture[$texs], 1D;\n" - "MUL cdelta.yw, parmy.rrgg, {0, -1, 0, 1};\n" - BICUB_FILT_MAIN; - -#define CALCWEIGHTS(t, s) \ - "MAD "t ", {-0.5, 0.1666, 0.3333, -0.3333}, "s ", {1, 0, -0.5, 0.5};\n" \ - "MAD "t ", "t ", "s ", {0, 0, -0.5, 0.5};\n" \ - "MAD "t ", "t ", "s ", {-0.6666, 0, 0.8333, 0.1666};\n" \ - "RCP a.x, "t ".z;\n" \ - "RCP a.y, "t ".w;\n" \ - "MAD "t ".xy, "t ".xyxy, a.xyxy, {1, 1, 0, 0};\n" \ - "ADD "t ".x, "t ".xxxx, "s ";\n" \ - "SUB "t ".y, "t ".yyyy, "s ";\n" - -static const char bicub_notex_filt_template_2D[] = - "MAD coord.xy, fragment.texcoord[$in_tex], {$texw, $texh}, {0.5, 0.5};\n" - "FRC coord.xy, coord.xyxy;\n" - CALCWEIGHTS("parmx", "coord.xxxx") - "MUL cdelta.xz, parmx.rrgg, {-$ptw, 0, $ptw, 0};\n" - CALCWEIGHTS("parmy", "coord.yyyy") - "MUL cdelta.yw, parmy.rrgg, {0, -$pth, 0, $pth};\n" - BICUB_FILT_MAIN; - -static const char bicub_notex_filt_template_RECT[] = - "ADD coord, fragment.texcoord[$in_tex], {0.5, 0.5};\n" - "FRC coord.xy, coord.xyxy;\n" - CALCWEIGHTS("parmx", "coord.xxxx") - "MUL cdelta.xz, parmx.rrgg, {-1, 0, 1, 0};\n" - CALCWEIGHTS("parmy", "coord.yyyy") - "MUL cdelta.yw, parmy.rrgg, {0, -1, 0, 1};\n" - BICUB_FILT_MAIN; - -#define BICUB_X_FILT_MAIN \ - "ADD coord.xy, fragment.texcoord[$in_tex].xyxy, cdelta.xyxy;\n" \ - "ADD coord2.xy, fragment.texcoord[$in_tex].xyxy, cdelta.zyzy;\n" \ - SAMPLE("a.r","coord","texture[$in_tex]") \ - SAMPLE("b.r","coord2","texture[$in_tex]") \ - /* x-interpolation */ \ - "LRP yuv.$out_comp, parmx.b, a.rrrr, b.rrrr;\n" - -static const char bicub_x_filt_template_2D[] = - "MAD coord.x, fragment.texcoord[$in_tex], {$texw}, {0.5};\n" - "TEX parmx, coord, texture[$texs], 1D;\n" - "MUL cdelta.xyz, parmx.rrgg, {-$ptw, 0, $ptw};\n" - BICUB_X_FILT_MAIN; - -static const char bicub_x_filt_template_RECT[] = - "ADD coord.x, fragment.texcoord[$in_tex], {0.5};\n" - "TEX parmx, coord, texture[$texs], 1D;\n" - "MUL cdelta.xyz, parmx.rrgg, {-1, 0, 1};\n" - BICUB_X_FILT_MAIN; - -static const char unsharp_filt_template[] = - "PARAM dcoord$out_comp = {$ptw_05, $pth_05, $ptw_05, -$pth_05};\n" - "ADD coord, fragment.texcoord[$in_tex].xyxy, dcoord$out_comp;\n" - "SUB coord2, fragment.texcoord[$in_tex].xyxy, dcoord$out_comp;\n" - SAMPLE("a.r","fragment.texcoord[$in_tex]","texture[$in_tex]") - SAMPLE("b.r","coord.xyxy","texture[$in_tex]") - SAMPLE("b.g","coord.zwzw","texture[$in_tex]") - "ADD b.r, b.r, b.g;\n" - SAMPLE("b.b","coord2.xyxy","texture[$in_tex]") - SAMPLE("b.g","coord2.zwzw","texture[$in_tex]") - "DP3 b, b, {0.25, 0.25, 0.25};\n" - "SUB b.r, a.r, b.r;\n" - "MAD textemp.r, b.r, {$strength}, a.r;\n" - "MOV yuv.$out_comp, textemp.r;\n"; - -static const char unsharp_filt_template2[] = - "PARAM dcoord$out_comp = {$ptw_12, $pth_12, $ptw_12, -$pth_12};\n" - "PARAM dcoord2$out_comp = {$ptw_15, 0, 0, $pth_15};\n" - "ADD coord, fragment.texcoord[$in_tex].xyxy, dcoord$out_comp;\n" - "SUB coord2, fragment.texcoord[$in_tex].xyxy, dcoord$out_comp;\n" - SAMPLE("a.r","fragment.texcoord[$in_tex]","texture[$in_tex]") - SAMPLE("b.r","coord.xyxy","texture[$in_tex]") - SAMPLE("b.g","coord.zwzw","texture[$in_tex]") - "ADD b.r, b.r, b.g;\n" - SAMPLE("b.b","coord2.xyxy","texture[$in_tex]") - SAMPLE("b.g","coord2.zwzw","texture[$in_tex]") - "ADD b.r, b.r, b.b;\n" - "ADD b.a, b.r, b.g;\n" - "ADD coord, fragment.texcoord[$in_tex].xyxy, dcoord2$out_comp;\n" - "SUB coord2, fragment.texcoord[$in_tex].xyxy, dcoord2$out_comp;\n" - SAMPLE("b.r","coord.xyxy","texture[$in_tex]") - SAMPLE("b.g","coord.zwzw","texture[$in_tex]") - "ADD b.r, b.r, b.g;\n" - SAMPLE("b.b","coord2.xyxy","texture[$in_tex]") - SAMPLE("b.g","coord2.zwzw","texture[$in_tex]") - "DP4 b.r, b, {-0.1171875, -0.1171875, -0.1171875, -0.09765625};\n" - "MAD b.r, a.r, {0.859375}, b.r;\n" - "MAD textemp.r, b.r, {$strength}, a.r;\n" - "MOV yuv.$out_comp, textemp.r;\n"; - -static const char yuv_prog_template[] = - "PARAM ycoef = {$cm11, $cm21, $cm31};\n" - "PARAM ucoef = {$cm12, $cm22, $cm32};\n" - "PARAM vcoef = {$cm13, $cm23, $cm33};\n" - "PARAM offsets = {$cm14, $cm24, $cm34};\n" - "TEMP res;\n" - "MAD res.rgb, yuv.rrrr, ycoef, offsets;\n" - "MAD res.rgb, yuv.gggg, ucoef, res;\n" - "MAD res.rgb, yuv.bbbb, vcoef, res;\n"; - -static const char yuv_pow_prog_template[] = - "PARAM ycoef = {$cm11, $cm21, $cm31};\n" - "PARAM ucoef = {$cm12, $cm22, $cm32};\n" - "PARAM vcoef = {$cm13, $cm23, $cm33};\n" - "PARAM offsets = {$cm14, $cm24, $cm34};\n" - "PARAM gamma = {$gamma_r, $gamma_g, $gamma_b};\n" - "TEMP res;\n" - "MAD res.rgb, yuv.rrrr, ycoef, offsets;\n" - "MAD res.rgb, yuv.gggg, ucoef, res;\n" - "MAD_SAT res.rgb, yuv.bbbb, vcoef, res;\n" - "POW res.r, res.r, gamma.r;\n" - "POW res.g, res.g, gamma.g;\n" - "POW res.b, res.b, gamma.b;\n"; - -static const char yuv_lookup_prog_template[] = - "PARAM ycoef = {$cm11, $cm21, $cm31, 0};\n" - "PARAM ucoef = {$cm12, $cm22, $cm32, 0};\n" - "PARAM vcoef = {$cm13, $cm23, $cm33, 0};\n" - "PARAM offsets = {$cm14, $cm24, $cm34, 0.125};\n" - "TEMP res;\n" - "MAD res, yuv.rrrr, ycoef, offsets;\n" - "MAD res.rgb, yuv.gggg, ucoef, res;\n" - "MAD res.rgb, yuv.bbbb, vcoef, res;\n" - "TEX res.r, res.raaa, texture[$conv_tex0], 2D;\n" - "ADD res.a, res.a, 0.25;\n" - "TEX res.g, res.gaaa, texture[$conv_tex0], 2D;\n" - "ADD res.a, res.a, 0.25;\n" - "TEX res.b, res.baaa, texture[$conv_tex0], 2D;\n"; - -static const char yuv_lookup3d_prog_template[] = - "TEMP res;\n" - "TEX res, yuv, texture[$conv_tex0], 3D;\n"; - -static const char noise_filt_template[] = - "MUL coord.xy, fragment.texcoord[0], {$noise_sx, $noise_sy};\n" - "TEMP rand;\n" - "TEX rand.r, coord.x, texture[$noise_filt_tex], 1D;\n" - "ADD rand.r, rand.r, coord.y;\n" - "TEX rand.r, rand.r, texture[$noise_filt_tex], 1D;\n" - "MAD res.rgb, rand.rrrr, {$noise_str, $noise_str, $noise_str}, res;\n"; - -/** - * \brief creates and initializes helper textures needed for scaling texture read - * \param scaler scaler type to create texture for - * \param texu contains next free texture unit number - * \param texs texture unit ids for the scaler are stored in this array - */ -static void create_scaler_textures(GL *gl, int scaler, int *texu, char *texs) -{ - switch (scaler) { - case YUV_SCALER_BILIN: - case YUV_SCALER_BICUB_NOTEX: - case YUV_SCALER_UNSHARP: - case YUV_SCALER_UNSHARP2: - break; - case YUV_SCALER_BICUB: - case YUV_SCALER_BICUB_X: - texs[0] = (*texu)++; - gen_spline_lookup_tex(gl, GL_TEXTURE0 + texs[0]); - texs[0] += '0'; - break; - default: - mp_msg(MSGT_VO, MSGL_ERR, "[gl] unknown scaler type %i\n", scaler); - } -} - -//! resolution of texture for gamma lookup table -#define LOOKUP_RES 512 -//! resolution for 3D yuv->rgb conversion lookup table -#define LOOKUP_3DRES 32 -/** - * \brief creates and initializes helper textures needed for yuv conversion - * \param params struct containing parameters like brightness, gamma, ... - * \param texu contains next free texture unit number - * \param texs texture unit ids for the conversion are stored in this array - */ -static void create_conv_textures(GL *gl, gl_conversion_params_t *params, - int *texu, char *texs) -{ - unsigned char *lookup_data = NULL; - int conv = YUV_CONVERSION(params->type); - switch (conv) { - case YUV_CONVERSION_FRAGMENT: - case YUV_CONVERSION_FRAGMENT_POW: - break; - case YUV_CONVERSION_FRAGMENT_LOOKUP: - texs[0] = (*texu)++; - gl->ActiveTexture(GL_TEXTURE0 + texs[0]); - lookup_data = malloc(4 * LOOKUP_RES); - mp_gen_gamma_map(lookup_data, LOOKUP_RES, params->csp_params.rgamma); - mp_gen_gamma_map(&lookup_data[LOOKUP_RES], LOOKUP_RES, - params->csp_params.ggamma); - mp_gen_gamma_map(&lookup_data[2 * LOOKUP_RES], LOOKUP_RES, - params->csp_params.bgamma); - glCreateClearTex(gl, GL_TEXTURE_2D, GL_LUMINANCE8, GL_LUMINANCE, - GL_UNSIGNED_BYTE, GL_LINEAR, LOOKUP_RES, 4, 0); - glUploadTex(gl, GL_TEXTURE_2D, GL_LUMINANCE, GL_UNSIGNED_BYTE, - lookup_data, LOOKUP_RES, 0, 0, LOOKUP_RES, 4, 0); - gl->ActiveTexture(GL_TEXTURE0); - texs[0] += '0'; - break; - case YUV_CONVERSION_FRAGMENT_LOOKUP3D: - { - int sz = LOOKUP_3DRES + 2; // texture size including borders - if (!gl->TexImage3D) { - mp_msg(MSGT_VO, MSGL_ERR, "[gl] Missing 3D texture function!\n"); - break; - } - texs[0] = (*texu)++; - gl->ActiveTexture(GL_TEXTURE0 + texs[0]); - lookup_data = malloc(3 * sz * sz * sz); - mp_gen_yuv2rgb_map(¶ms->csp_params, lookup_data, LOOKUP_3DRES); - glAdjustAlignment(gl, sz); - gl->PixelStorei(GL_UNPACK_ROW_LENGTH, 0); - gl->TexImage3D(GL_TEXTURE_3D, 0, 3, sz, sz, sz, 1, - GL_RGB, GL_UNSIGNED_BYTE, lookup_data); - gl->TexParameterf(GL_TEXTURE_3D, GL_TEXTURE_PRIORITY, 1.0); - gl->TexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - gl->TexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - gl->TexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_S, GL_CLAMP); - gl->TexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_T, GL_CLAMP); - gl->TexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_R, GL_CLAMP); - gl->ActiveTexture(GL_TEXTURE0); - texs[0] += '0'; - } - break; - default: - mp_msg(MSGT_VO, MSGL_ERR, "[gl] unknown conversion type %i\n", conv); - } - free(lookup_data); -} - -/** - * \brief adds a scaling texture read at the current fragment program position - * \param scaler type of scaler to insert - * \param prog pointer to fragment program so far - * \param texs array containing the texture unit identifiers for this scaler - * \param in_tex texture unit the scaler should read from - * \param out_comp component of the yuv variable the scaler stores the result in - * \param rect if rectangular (pixel) adressing should be used for in_tex - * \param texw width of the in_tex texture - * \param texh height of the in_tex texture - * \param strength strength of filter effect if the scaler does some kind of filtering - */ -static void add_scaler(int scaler, char **prog, char *texs, - char in_tex, char out_comp, int rect, int texw, int texh, - double strength) -{ - const char *ttype = rect ? "RECT" : "2D"; - const float ptw = rect ? 1.0 : 1.0 / texw; - const float pth = rect ? 1.0 : 1.0 / texh; - switch (scaler) { - case YUV_SCALER_BILIN: - append_template(prog, bilin_filt_template); - break; - case YUV_SCALER_BICUB: - if (rect) - append_template(prog, bicub_filt_template_RECT); - else - append_template(prog, bicub_filt_template_2D); - break; - case YUV_SCALER_BICUB_X: - if (rect) - append_template(prog, bicub_x_filt_template_RECT); - else - append_template(prog, bicub_x_filt_template_2D); - break; - case YUV_SCALER_BICUB_NOTEX: - if (rect) - append_template(prog, bicub_notex_filt_template_RECT); - else - append_template(prog, bicub_notex_filt_template_2D); - break; - case YUV_SCALER_UNSHARP: - append_template(prog, unsharp_filt_template); - break; - case YUV_SCALER_UNSHARP2: - append_template(prog, unsharp_filt_template2); - break; - } - - replace_var_char(prog, "texs", texs[0]); - replace_var_char(prog, "in_tex", in_tex); - replace_var_char(prog, "out_comp", out_comp); - replace_var_str(prog, "tex_type", ttype); - replace_var_float(prog, "texw", texw); - replace_var_float(prog, "texh", texh); - replace_var_float(prog, "ptw", ptw); - replace_var_float(prog, "pth", pth); - - // this is silly, not sure if that couldn't be in the shader source instead - replace_var_float(prog, "ptw_05", ptw * 0.5); - replace_var_float(prog, "pth_05", pth * 0.5); - replace_var_float(prog, "ptw_15", ptw * 1.5); - replace_var_float(prog, "pth_15", pth * 1.5); - replace_var_float(prog, "ptw_12", ptw * 1.2); - replace_var_float(prog, "pth_12", pth * 1.2); - - replace_var_float(prog, "strength", strength); -} - -static const struct { - const char *name; - GLenum cur; - GLenum max; -} progstats[] = { - {"instructions", 0x88A0, 0x88A1}, - {"native instructions", 0x88A2, 0x88A3}, - {"temporaries", 0x88A4, 0x88A5}, - {"native temporaries", 0x88A6, 0x88A7}, - {"parameters", 0x88A8, 0x88A9}, - {"native parameters", 0x88AA, 0x88AB}, - {"attribs", 0x88AC, 0x88AD}, - {"native attribs", 0x88AE, 0x88AF}, - {"ALU instructions", 0x8805, 0x880B}, - {"TEX instructions", 0x8806, 0x880C}, - {"TEX indirections", 0x8807, 0x880D}, - {"native ALU instructions", 0x8808, 0x880E}, - {"native TEX instructions", 0x8809, 0x880F}, - {"native TEX indirections", 0x880A, 0x8810}, - {NULL, 0, 0} -}; - -/** - * \brief load the specified GPU Program - * \param target program target to load into, only GL_FRAGMENT_PROGRAM is tested - * \param prog program string - * \return 1 on success, 0 otherwise - */ -int loadGPUProgram(GL *gl, GLenum target, char *prog) -{ - int i; - GLint cur = 0, max = 0, err = 0; - if (!gl->ProgramString) { - mp_msg(MSGT_VO, MSGL_ERR, "[gl] Missing GPU program function\n"); - return 0; - } - gl->ProgramString(target, GL_PROGRAM_FORMAT_ASCII, strlen(prog), prog); - gl->GetIntegerv(GL_PROGRAM_ERROR_POSITION, &err); - if (err != -1) { - mp_msg(MSGT_VO, MSGL_ERR, - "[gl] Error compiling fragment program, make sure your card supports\n" - "[gl] GL_ARB_fragment_program (use glxinfo to check).\n" - "[gl] Error message:\n %s at %.10s\n", - gl->GetString(GL_PROGRAM_ERROR_STRING), &prog[err]); - return 0; - } - if (!gl->GetProgramivARB || !mp_msg_test(MSGT_VO, MSGL_DBG2)) - return 1; - mp_msg(MSGT_VO, MSGL_V, "[gl] Program statistics:\n"); - for (i = 0; progstats[i].name; i++) { - gl->GetProgramivARB(target, progstats[i].cur, &cur); - gl->GetProgramivARB(target, progstats[i].max, &max); - mp_msg(MSGT_VO, MSGL_V, "[gl] %s: %i/%i\n", progstats[i].name, cur, - max); - } - return 1; -} - -#define MAX_PROGSZ (1024 * 1024) - -/** - * \brief setup a fragment program that will do YUV->RGB conversion - * \param parms struct containing parameters like conversion and scaler type, - * brightness, ... - */ -static void glSetupYUVFragprog(GL *gl, gl_conversion_params_t *params) -{ - int type = params->type; - int texw = params->texw; - int texh = params->texh; - int rect = params->target == GL_TEXTURE_RECTANGLE; - static const char prog_hdr[] = - "!!ARBfp1.0\n" - "OPTION ARB_precision_hint_fastest;\n" - // all scaler variables must go here so they aren't defined - // multiple times when the same scaler is used more than once - "TEMP coord, coord2, cdelta, parmx, parmy, a, b, yuv, textemp;\n"; - char *yuv_prog = NULL; - char **prog = &yuv_prog; - int cur_texu = 3; - char lum_scale_texs[1] = {0}; - char chrom_scale_texs[1] = {0}; - char conv_texs[1]; - char filt_texs[1] = {0}; - GLint i; - // this is the conversion matrix, with y, u, v factors - // for red, green, blue and the constant offsets - float yuv2rgb[3][4]; - int noise = params->noise_strength != 0; - create_conv_textures(gl, params, &cur_texu, conv_texs); - create_scaler_textures(gl, YUV_LUM_SCALER(type), &cur_texu, lum_scale_texs); - if (YUV_CHROM_SCALER(type) == YUV_LUM_SCALER(type)) - memcpy(chrom_scale_texs, lum_scale_texs, sizeof(chrom_scale_texs)); - else - create_scaler_textures(gl, YUV_CHROM_SCALER(type), &cur_texu, - chrom_scale_texs); - - if (noise) { - gen_noise_lookup_tex(gl, cur_texu); - filt_texs[0] = '0' + cur_texu++; - } - - gl->GetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS, &i); - if (i < cur_texu) - mp_msg(MSGT_VO, MSGL_ERR, - "[gl] %i texture units needed for this type of YUV fragment support (found %i)\n", - cur_texu, i); - if (!gl->ProgramString) { - mp_msg(MSGT_VO, MSGL_FATAL, "[gl] ProgramString function missing!\n"); - return; - } - append_template(prog, prog_hdr); - add_scaler(YUV_LUM_SCALER(type), prog, lum_scale_texs, - '0', 'r', rect, texw, texh, params->filter_strength); - add_scaler(YUV_CHROM_SCALER(type), prog, - chrom_scale_texs, '1', 'g', rect, params->chrom_texw, - params->chrom_texh, params->filter_strength); - add_scaler(YUV_CHROM_SCALER(type), prog, - chrom_scale_texs, '2', 'b', rect, params->chrom_texw, - params->chrom_texh, params->filter_strength); - mp_get_yuv2rgb_coeffs(¶ms->csp_params, yuv2rgb); - switch (YUV_CONVERSION(type)) { - case YUV_CONVERSION_FRAGMENT: - append_template(prog, yuv_prog_template); - break; - case YUV_CONVERSION_FRAGMENT_POW: - append_template(prog, yuv_pow_prog_template); - break; - case YUV_CONVERSION_FRAGMENT_LOOKUP: - append_template(prog, yuv_lookup_prog_template); - break; - case YUV_CONVERSION_FRAGMENT_LOOKUP3D: - append_template(prog, yuv_lookup3d_prog_template); - break; - default: - mp_msg(MSGT_VO, MSGL_ERR, "[gl] unknown conversion type %i\n", - YUV_CONVERSION(type)); - break; - } - for (int r = 0; r < 3; r++) { - for (int c = 0; c < 4; c++) { - // "cmRC" - char var[] = { 'c', 'm', '1' + r, '1' + c, '\0' }; - replace_var_float(prog, var, yuv2rgb[r][c]); - } - } - replace_var_float(prog, "gamma_r", (float)1.0 / params->csp_params.rgamma); - replace_var_float(prog, "gamma_g", (float)1.0 / params->csp_params.ggamma); - replace_var_float(prog, "gamma_b", (float)1.0 / params->csp_params.bgamma); - replace_var_char(prog, "conv_tex0", conv_texs[0]); - - if (noise) { - // 1.0 strength is suitable for dithering 8 to 6 bit - double str = params->noise_strength * (1.0 / 64); - double scale_x = (double)NOISE_RES / texw; - double scale_y = (double)NOISE_RES / texh; - if (rect) { - scale_x /= texw; - scale_y /= texh; - } - append_template(prog, noise_filt_template); - replace_var_float(prog, "noise_sx", scale_x); - replace_var_float(prog, "noise_sy", scale_y); - replace_var_char(prog, "noise_filt_tex", filt_texs[0]); - replace_var_float(prog, "noise_str", str); - } - - append_template(prog, "MOV result.color.rgb, res;\nEND"); - - mp_msg(MSGT_VO, MSGL_DBG2, "[gl] generated fragment program:\n%s\n", - yuv_prog); - loadGPUProgram(gl, GL_FRAGMENT_PROGRAM, yuv_prog); - talloc_free(yuv_prog); -} - -/** - * \brief detect the best YUV->RGB conversion method available - */ -int glAutodetectYUVConversion(GL *gl) -{ - const char *extensions = gl->GetString(GL_EXTENSIONS); - if (!extensions || !gl->MultiTexCoord2f) - return YUV_CONVERSION_NONE; - if (strstr(extensions, "GL_ARB_fragment_program")) - return YUV_CONVERSION_FRAGMENT; - if (strstr(extensions, "GL_ATI_text_fragment_shader")) - return YUV_CONVERSION_TEXT_FRAGMENT; - if (strstr(extensions, "GL_ATI_fragment_shader")) - return YUV_CONVERSION_COMBINERS_ATI; - return YUV_CONVERSION_NONE; -} - -/** - * \brief setup YUV->RGB conversion - * \param parms struct containing parameters like conversion and scaler type, - * brightness, ... - * \ingroup glconversion - */ -void glSetupYUVConversion(GL *gl, gl_conversion_params_t *params) -{ - if (params->chrom_texw == 0) - params->chrom_texw = 1; - if (params->chrom_texh == 0) - params->chrom_texh = 1; - switch (YUV_CONVERSION(params->type)) { - case YUV_CONVERSION_COMBINERS_ATI: - glSetupYUVFragmentATI(gl, ¶ms->csp_params, 0); - break; - case YUV_CONVERSION_TEXT_FRAGMENT: - glSetupYUVFragmentATI(gl, ¶ms->csp_params, 1); - break; - case YUV_CONVERSION_FRAGMENT_LOOKUP: - case YUV_CONVERSION_FRAGMENT_LOOKUP3D: - case YUV_CONVERSION_FRAGMENT: - case YUV_CONVERSION_FRAGMENT_POW: - glSetupYUVFragprog(gl, params); - break; - case YUV_CONVERSION_NONE: - break; - default: - mp_msg(MSGT_VO, MSGL_ERR, "[gl] unknown conversion type %i\n", - YUV_CONVERSION(params->type)); - } -} - -/** - * \brief enable the specified YUV conversion - * \param target texture target for Y, U and V textures (e.g. GL_TEXTURE_2D) - * \param type type of YUV conversion - * \ingroup glconversion - */ -void glEnableYUVConversion(GL *gl, GLenum target, int type) -{ - switch (YUV_CONVERSION(type)) { - case YUV_CONVERSION_COMBINERS_ATI: - gl->ActiveTexture(GL_TEXTURE1); - gl->Enable(target); - gl->ActiveTexture(GL_TEXTURE2); - gl->Enable(target); - gl->ActiveTexture(GL_TEXTURE0); - gl->Enable(GL_FRAGMENT_SHADER_ATI); - break; - case YUV_CONVERSION_TEXT_FRAGMENT: - gl->ActiveTexture(GL_TEXTURE1); - gl->Enable(target); - gl->ActiveTexture(GL_TEXTURE2); - gl->Enable(target); - gl->ActiveTexture(GL_TEXTURE0); - gl->Enable(GL_TEXT_FRAGMENT_SHADER_ATI); - break; - case YUV_CONVERSION_FRAGMENT_LOOKUP3D: - case YUV_CONVERSION_FRAGMENT_LOOKUP: - case YUV_CONVERSION_FRAGMENT_POW: - case YUV_CONVERSION_FRAGMENT: - case YUV_CONVERSION_NONE: - gl->Enable(GL_FRAGMENT_PROGRAM); - break; - } -} - -/** - * \brief disable the specified YUV conversion - * \param target texture target for Y, U and V textures (e.g. GL_TEXTURE_2D) - * \param type type of YUV conversion - * \ingroup glconversion - */ -void glDisableYUVConversion(GL *gl, GLenum target, int type) -{ - switch (YUV_CONVERSION(type)) { - case YUV_CONVERSION_COMBINERS_ATI: - gl->ActiveTexture(GL_TEXTURE1); - gl->Disable(target); - gl->ActiveTexture(GL_TEXTURE2); - gl->Disable(target); - gl->ActiveTexture(GL_TEXTURE0); - gl->Disable(GL_FRAGMENT_SHADER_ATI); - break; - case YUV_CONVERSION_TEXT_FRAGMENT: - gl->Disable(GL_TEXT_FRAGMENT_SHADER_ATI); - // HACK: at least the Mac OS X 10.5 PPC Radeon drivers are broken and - // without this disable the texture units while the program is still - // running (10.4 PPC seems to work without this though). - gl->Flush(); - gl->ActiveTexture(GL_TEXTURE1); - gl->Disable(target); - gl->ActiveTexture(GL_TEXTURE2); - gl->Disable(target); - gl->ActiveTexture(GL_TEXTURE0); - break; - case YUV_CONVERSION_FRAGMENT_LOOKUP3D: - case YUV_CONVERSION_FRAGMENT_LOOKUP: - case YUV_CONVERSION_FRAGMENT_POW: - case YUV_CONVERSION_FRAGMENT: - case YUV_CONVERSION_NONE: - gl->Disable(GL_FRAGMENT_PROGRAM); - break; - } -} - -void glEnable3DLeft(GL *gl, int type) -{ - GLint buffer; - switch (type) { - case GL_3D_RED_CYAN: - gl->ColorMask(GL_TRUE, GL_FALSE, GL_FALSE, GL_FALSE); - break; - case GL_3D_GREEN_MAGENTA: - gl->ColorMask(GL_FALSE, GL_TRUE, GL_FALSE, GL_FALSE); - break; - case GL_3D_QUADBUFFER: - gl->GetIntegerv(GL_DRAW_BUFFER, &buffer); - switch (buffer) { - case GL_FRONT: - case GL_FRONT_LEFT: - case GL_FRONT_RIGHT: - buffer = GL_FRONT_LEFT; - break; - case GL_BACK: - case GL_BACK_LEFT: - case GL_BACK_RIGHT: - buffer = GL_BACK_LEFT; - break; - } - gl->DrawBuffer(buffer); - break; - } -} - -void glEnable3DRight(GL *gl, int type) -{ - GLint buffer; - switch (type) { - case GL_3D_RED_CYAN: - gl->ColorMask(GL_FALSE, GL_TRUE, GL_TRUE, GL_FALSE); - break; - case GL_3D_GREEN_MAGENTA: - gl->ColorMask(GL_TRUE, GL_FALSE, GL_TRUE, GL_FALSE); - break; - case GL_3D_QUADBUFFER: - gl->GetIntegerv(GL_DRAW_BUFFER, &buffer); - switch (buffer) { - case GL_FRONT: - case GL_FRONT_LEFT: - case GL_FRONT_RIGHT: - buffer = GL_FRONT_RIGHT; - break; - case GL_BACK: - case GL_BACK_LEFT: - case GL_BACK_RIGHT: - buffer = GL_BACK_RIGHT; - break; - } - gl->DrawBuffer(buffer); - break; - } -} - -void glDisable3D(GL *gl, int type) -{ - GLint buffer; - switch (type) { - case GL_3D_RED_CYAN: - case GL_3D_GREEN_MAGENTA: - gl->ColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); - break; - case GL_3D_QUADBUFFER: - gl->DrawBuffer(GL_BACK); - gl->GetIntegerv(GL_DRAW_BUFFER, &buffer); - switch (buffer) { - case GL_FRONT: - case GL_FRONT_LEFT: - case GL_FRONT_RIGHT: - buffer = GL_FRONT; - break; - case GL_BACK: - case GL_BACK_LEFT: - case GL_BACK_RIGHT: - buffer = GL_BACK; - break; - } - gl->DrawBuffer(buffer); - break; - } -} - -/** - * \brief draw a texture part at given 2D coordinates - * \param x screen top coordinate - * \param y screen left coordinate - * \param w screen width coordinate - * \param h screen height coordinate - * \param tx texture top coordinate in pixels - * \param ty texture left coordinate in pixels - * \param tw texture part width in pixels - * \param th texture part height in pixels - * \param sx width of texture in pixels - * \param sy height of texture in pixels - * \param rect_tex whether this texture uses texture_rectangle extension - * \param is_yv12 if != 0, also draw the textures from units 1 and 2, - * bits 8 - 15 and 16 - 23 specify the x and y scaling of those textures - * \param flip flip the texture upside down - * \ingroup gltexture - */ -void glDrawTex(GL *gl, GLfloat x, GLfloat y, GLfloat w, GLfloat h, - GLfloat tx, GLfloat ty, GLfloat tw, GLfloat th, - int sx, int sy, int rect_tex, int is_yv12, int flip) -{ - int chroma_x_shift = (is_yv12 >> 8) & 31; - int chroma_y_shift = (is_yv12 >> 16) & 31; - GLfloat xscale = 1 << chroma_x_shift; - GLfloat yscale = 1 << chroma_y_shift; - GLfloat tx2 = tx / xscale, ty2 = ty / yscale, tw2 = tw / xscale, th2 = th / yscale; - if (!rect_tex) { - tx /= sx; - ty /= sy; - tw /= sx; - th /= sy; - tx2 = tx, ty2 = ty, tw2 = tw, th2 = th; - } - if (flip) { - y += h; - h = -h; - } - gl->Begin(GL_QUADS); - gl->TexCoord2f(tx, ty); - if (is_yv12) { - gl->MultiTexCoord2f(GL_TEXTURE1, tx2, ty2); - gl->MultiTexCoord2f(GL_TEXTURE2, tx2, ty2); - } - gl->Vertex2f(x, y); - gl->TexCoord2f(tx, ty + th); - if (is_yv12) { - gl->MultiTexCoord2f(GL_TEXTURE1, tx2, ty2 + th2); - gl->MultiTexCoord2f(GL_TEXTURE2, tx2, ty2 + th2); - } - gl->Vertex2f(x, y + h); - gl->TexCoord2f(tx + tw, ty + th); - if (is_yv12) { - gl->MultiTexCoord2f(GL_TEXTURE1, tx2 + tw2, ty2 + th2); - gl->MultiTexCoord2f(GL_TEXTURE2, tx2 + tw2, ty2 + th2); - } - gl->Vertex2f(x + w, y + h); - gl->TexCoord2f(tx + tw, ty); - if (is_yv12) { - gl->MultiTexCoord2f(GL_TEXTURE1, tx2 + tw2, ty2); - gl->MultiTexCoord2f(GL_TEXTURE2, tx2 + tw2, ty2); - } - gl->Vertex2f(x + w, y); - gl->End(); -} - -mp_image_t *glGetWindowScreenshot(GL *gl) -{ - GLint vp[4]; //x, y, w, h - gl->GetIntegerv(GL_VIEWPORT, vp); - mp_image_t *image = alloc_mpi(vp[2], vp[3], IMGFMT_RGB24); - gl->BindBuffer(GL_PIXEL_UNPACK_BUFFER, 0); - gl->PixelStorei(GL_PACK_ALIGNMENT, 0); - gl->PixelStorei(GL_PACK_ROW_LENGTH, 0); - gl->ReadBuffer(GL_FRONT); - //flip image while reading - for (int y = 0; y < vp[3]; y++) { - gl->ReadPixels(vp[0], vp[1] + vp[3] - y - 1, vp[2], 1, - GL_RGB, GL_UNSIGNED_BYTE, - image->planes[0] + y * image->stride[0]); - } - return image; -} - -#ifdef CONFIG_GL_COCOA -#include "cocoa_common.h" - -static bool create_window_cocoa(struct MPGLContext *ctx, uint32_t d_width, - uint32_t d_height, uint32_t flags, bool gl3) -{ - int rv = vo_cocoa_create_window(ctx->vo, d_width, d_height, flags, gl3); - if (rv != 0) - return false; - - getFunctions(ctx->gl, (void *)vo_cocoa_glgetaddr, NULL, gl3); - - if (gl3) { - ctx->depth_r = vo_cocoa_cgl_color_size(ctx->vo); - ctx->depth_g = vo_cocoa_cgl_color_size(ctx->vo); - ctx->depth_b = vo_cocoa_cgl_color_size(ctx->vo); - } - - if (!ctx->gl->SwapInterval) - ctx->gl->SwapInterval = vo_cocoa_swap_interval; - - return true; -} - -static bool create_window_cocoa_old(struct MPGLContext *ctx, uint32_t d_width, - uint32_t d_height, uint32_t flags) -{ - return create_window_cocoa(ctx, d_width, d_height, flags, false); -} - -static bool create_window_cocoa_gl3(struct MPGLContext *ctx, uint32_t d_width, - uint32_t d_height, uint32_t flags) -{ - return create_window_cocoa(ctx, d_width, d_height, flags, true); -} - -static void releaseGlContext_cocoa(MPGLContext *ctx) -{ -} - -static void swapGlBuffers_cocoa(MPGLContext *ctx) -{ - vo_cocoa_swap_buffers(ctx->vo); -} -#endif - -#ifdef CONFIG_GL_WIN32 -#include <windows.h> -#include "w32_common.h" - -struct w32_context { - HGLRC context; -}; - -static void *w32gpa(const GLubyte *procName) -{ - HMODULE oglmod; - void *res = wglGetProcAddress(procName); - if (res) - return res; - oglmod = GetModuleHandle("opengl32.dll"); - return GetProcAddress(oglmod, procName); -} - -static bool create_window_w32_old(struct MPGLContext *ctx, uint32_t d_width, - uint32_t d_height, uint32_t flags) -{ - GL *gl = ctx->gl; - - if (!vo_w32_config(ctx->vo, d_width, d_height, flags)) - return false; - - struct w32_context *w32_ctx = ctx->priv; - HGLRC *context = &w32_ctx->context; - - if (*context) { - gl->Finish(); // supposedly to prevent flickering - return true; - } - - HWND win = ctx->vo->w32->window; - HDC windc = vo_w32_get_dc(ctx->vo, win); - bool res = false; - - HGLRC new_context = wglCreateContext(windc); - if (!new_context) { - mp_msg(MSGT_VO, MSGL_FATAL, "[gl] Could not create GL context!\n"); - goto out; - } - - if (!wglMakeCurrent(windc, new_context)) { - mp_msg(MSGT_VO, MSGL_FATAL, "[gl] Could not set GL context!\n"); - wglDeleteContext(new_context); - goto out; - } - - *context = new_context; - - getFunctions(ctx->gl, w32gpa, NULL, false); - res = true; - -out: - vo_w32_release_dc(ctx->vo, win, windc); - return res; -} - -static bool create_window_w32_gl3(struct MPGLContext *ctx, uint32_t d_width, - uint32_t d_height, uint32_t flags) -{ - if (!vo_w32_config(ctx->vo, d_width, d_height, flags)) - return false; - - struct w32_context *w32_ctx = ctx->priv; - HGLRC *context = &w32_ctx->context; - - if (*context) // reuse existing context - return true; // not reusing it breaks gl3! - - HWND win = ctx->vo->w32->window; - HDC windc = vo_w32_get_dc(ctx->vo, win); - HGLRC new_context = 0; - - new_context = wglCreateContext(windc); - if (!new_context) { - mp_msg(MSGT_VO, MSGL_FATAL, "[gl] Could not create GL context!\n"); - return false; - } - - // set context - if (!wglMakeCurrent(windc, new_context)) { - mp_msg(MSGT_VO, MSGL_FATAL, "[gl] Could not set GL context!\n"); - goto out; - } - - const char *(GLAPIENTRY *wglGetExtensionsStringARB)(HDC hdc) - = w32gpa((const GLubyte*)"wglGetExtensionsStringARB"); - - if (!wglGetExtensionsStringARB) - goto unsupported; - - const char *wgl_exts = wglGetExtensionsStringARB(windc); - if (!strstr(wgl_exts, "WGL_ARB_create_context")) - goto unsupported; - - HGLRC (GLAPIENTRY *wglCreateContextAttribsARB)(HDC hDC, HGLRC hShareContext, - const int *attribList) - = w32gpa((const GLubyte*)"wglCreateContextAttribsARB"); - - if (!wglCreateContextAttribsARB) - goto unsupported; - - int gl_version = ctx->requested_gl_version; - int attribs[] = { - WGL_CONTEXT_MAJOR_VERSION_ARB, MPGL_VER_GET_MAJOR(gl_version), - WGL_CONTEXT_MINOR_VERSION_ARB, MPGL_VER_GET_MINOR(gl_version), - WGL_CONTEXT_FLAGS_ARB, WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB, - WGL_CONTEXT_PROFILE_MASK_ARB, WGL_CONTEXT_CORE_PROFILE_BIT_ARB, - 0 - }; - - *context = wglCreateContextAttribsARB(windc, 0, attribs); - if (! *context) { - // NVidia, instead of ignoring WGL_CONTEXT_FLAGS_ARB, will error out if - // it's present on pre-3.2 contexts. - // Remove it from attribs and retry the context creation. - attribs[6] = attribs[7] = 0; - *context = wglCreateContextAttribsARB(windc, 0, attribs); - } - if (! *context) { - int err = GetLastError(); - mp_msg(MSGT_VO, MSGL_FATAL, "[gl] Could not create an OpenGL 3.x" - " context: error 0x%x\n", err); - goto out; - } - - wglMakeCurrent(NULL, NULL); - wglDeleteContext(new_context); - - if (!wglMakeCurrent(windc, *context)) { - mp_msg(MSGT_VO, MSGL_FATAL, "[gl] Could not set GL3 context!\n"); - wglDeleteContext(*context); - return false; - } - - /* update function pointers */ - getFunctions(ctx->gl, w32gpa, NULL, true); - - int pfmt = GetPixelFormat(windc); - PIXELFORMATDESCRIPTOR pfd; - if (DescribePixelFormat(windc, pfmt, sizeof(PIXELFORMATDESCRIPTOR), &pfd)) { - ctx->depth_r = pfd.cRedBits; - ctx->depth_g = pfd.cGreenBits; - ctx->depth_b = pfd.cBlueBits; - } - - return true; - -unsupported: - mp_msg(MSGT_VO, MSGL_ERR, "[gl] The current OpenGL implementation does" - " not support OpenGL 3.x \n"); -out: - wglDeleteContext(new_context); - return false; -} - -static void releaseGlContext_w32(MPGLContext *ctx) -{ - struct w32_context *w32_ctx = ctx->priv; - HGLRC *context = &w32_ctx->context; - if (*context) { - wglMakeCurrent(0, 0); - wglDeleteContext(*context); - } - *context = 0; -} - -static void swapGlBuffers_w32(MPGLContext *ctx) -{ - HDC vo_hdc = vo_w32_get_dc(ctx->vo, ctx->vo->w32->window); - SwapBuffers(vo_hdc); - vo_w32_release_dc(ctx->vo, ctx->vo->w32->window, vo_hdc); -} -#endif - -#ifdef CONFIG_GL_X11 -#include <X11/Xlib.h> -#include <GL/glx.h> -#include "x11_common.h" - -struct glx_context { - XVisualInfo *vinfo; - GLXContext context; - GLXFBConfig fbc; -}; - -// The GL3/FBC initialization code roughly follows/copies from: -// http://www.opengl.org/wiki/Tutorial:_OpenGL_3.0_Context_Creation_(GLX) -// but also uses some of the old code. - -static GLXFBConfig select_fb_config(struct vo *vo, const int *attribs) -{ - int fbcount; - GLXFBConfig *fbc = glXChooseFBConfig(vo->x11->display, vo->x11->screen, - attribs, &fbcount); - if (!fbc) - return NULL; - - // The list in fbc is sorted (so that the first element is the best). - GLXFBConfig fbconfig = fbc[0]; - - XFree(fbc); - - return fbconfig; -} - -static bool create_glx_window(struct MPGLContext *ctx, uint32_t d_width, - uint32_t d_height, uint32_t flags) -{ - struct vo *vo = ctx->vo; - struct glx_context *glx_ctx = ctx->priv; - - if (glx_ctx->context) { - // GL context and window already exist. - // Only update window geometry etc. - Colormap colormap = XCreateColormap(vo->x11->display, vo->x11->rootwin, - glx_ctx->vinfo->visual, AllocNone); - vo_x11_create_vo_window(vo, glx_ctx->vinfo, vo->dx, vo->dy, d_width, - d_height, flags, colormap, "gl"); - XFreeColormap(vo->x11->display, colormap); - return true; - } - - int glx_major, glx_minor; - - // FBConfigs were added in GLX version 1.3. - if (!glXQueryVersion(vo->x11->display, &glx_major, &glx_minor) || - (MPGL_VER(glx_major, glx_minor) < MPGL_VER(1, 3))) - { - mp_msg(MSGT_VO, MSGL_ERR, "[gl] GLX version older than 1.3.\n"); - return false; - } - - const int glx_attribs_stereo_value_idx = 1; // index of GLX_STEREO + 1 - int glx_attribs[] = { - GLX_STEREO, False, - GLX_X_RENDERABLE, True, - GLX_RED_SIZE, 1, - GLX_GREEN_SIZE, 1, - GLX_BLUE_SIZE, 1, - GLX_DOUBLEBUFFER, True, - None - }; - GLXFBConfig fbc = NULL; - if (flags & VOFLAG_STEREO) { - glx_attribs[glx_attribs_stereo_value_idx] = True; - fbc = select_fb_config(vo, glx_attribs); - if (!fbc) { - mp_msg(MSGT_VO, MSGL_ERR, "[gl] Could not find a stereo visual," - " 3D will probably not work!\n"); - glx_attribs[glx_attribs_stereo_value_idx] = False; - } - } - if (!fbc) - fbc = select_fb_config(vo, glx_attribs); - if (!fbc) { - mp_msg(MSGT_VO, MSGL_ERR, "[gl] no GLX support present\n"); - return false; - } - - glx_ctx->fbc = fbc; - glx_ctx->vinfo = glXGetVisualFromFBConfig(vo->x11->display, fbc); - - mp_msg(MSGT_VO, MSGL_V, "[gl] GLX chose visual with ID 0x%x\n", - (int)glx_ctx->vinfo->visualid); - - glXGetFBConfigAttrib(vo->x11->display, fbc, GLX_RED_SIZE, &ctx->depth_r); - glXGetFBConfigAttrib(vo->x11->display, fbc, GLX_GREEN_SIZE, &ctx->depth_g); - glXGetFBConfigAttrib(vo->x11->display, fbc, GLX_BLUE_SIZE, &ctx->depth_b); - - Colormap colormap = XCreateColormap(vo->x11->display, vo->x11->rootwin, - glx_ctx->vinfo->visual, AllocNone); - vo_x11_create_vo_window(vo, glx_ctx->vinfo, vo->dx, vo->dy, d_width, - d_height, flags, colormap, "gl"); - XFreeColormap(vo->x11->display, colormap); - - return true; -} - -static bool create_window_x11_old(struct MPGLContext *ctx, uint32_t d_width, - uint32_t d_height, uint32_t flags) -{ - struct glx_context *glx_ctx = ctx->priv; - Display *display = ctx->vo->x11->display; - struct vo *vo = ctx->vo; - GL *gl = ctx->gl; - - if (!create_glx_window(ctx, d_width, d_height, flags)) - return false; - - if (glx_ctx->context) - return true; - - GLXContext new_context = glXCreateContext(display, glx_ctx->vinfo, NULL, - True); - if (!new_context) { - mp_msg(MSGT_VO, MSGL_FATAL, "[gl] Could not create GLX context!\n"); - return false; - } - - if (!glXMakeCurrent(display, ctx->vo->x11->window, new_context)) { - mp_msg(MSGT_VO, MSGL_FATAL, "[gl] Could not set GLX context!\n"); - glXDestroyContext(display, new_context); - return false; - } - - void *(*getProcAddress)(const GLubyte *); - getProcAddress = getdladdr("glXGetProcAddress"); - if (!getProcAddress) - getProcAddress = getdladdr("glXGetProcAddressARB"); - - const char *glxstr = ""; - const char *(*glXExtStr)(Display *, int) - = getdladdr("glXQueryExtensionsString"); - if (glXExtStr) - glxstr = glXExtStr(display, ctx->vo->x11->screen); - - getFunctions(gl, getProcAddress, glxstr, false); - if (!gl->GenPrograms && gl->GetString && - gl->version < MPGL_VER(3, 0) && - getProcAddress && - strstr(gl->GetString(GL_EXTENSIONS), "GL_ARB_vertex_program")) - { - mp_msg(MSGT_VO, MSGL_WARN, - "Broken glXGetProcAddress detected, trying workaround\n"); - getFunctions(gl, NULL, glxstr, false); - } - - glx_ctx->context = new_context; - - if (!glXIsDirect(vo->x11->display, new_context)) - ctx->gl->mpgl_caps &= ~MPGL_CAP_NO_SW; - - return true; -} - -typedef GLXContext (*glXCreateContextAttribsARBProc) - (Display*, GLXFBConfig, GLXContext, Bool, const int*); - -static bool create_window_x11_gl3(struct MPGLContext *ctx, uint32_t d_width, - uint32_t d_height, uint32_t flags) -{ - struct glx_context *glx_ctx = ctx->priv; - struct vo *vo = ctx->vo; - - if (!create_glx_window(ctx, d_width, d_height, flags)) - return false; - - if (glx_ctx->context) - return true; - - glXCreateContextAttribsARBProc glXCreateContextAttribsARB = - (glXCreateContextAttribsARBProc) - glXGetProcAddressARB((const GLubyte *)"glXCreateContextAttribsARB"); - - const char *glxstr = ""; - const char *(*glXExtStr)(Display *, int) - = getdladdr("glXQueryExtensionsString"); - if (glXExtStr) - glxstr = glXExtStr(vo->x11->display, vo->x11->screen); - bool have_ctx_ext = glxstr && !!strstr(glxstr, "GLX_ARB_create_context"); - - if (!(have_ctx_ext && glXCreateContextAttribsARB)) { - return false; - } - - int gl_version = ctx->requested_gl_version; - int context_attribs[] = { - GLX_CONTEXT_MAJOR_VERSION_ARB, MPGL_VER_GET_MAJOR(gl_version), - GLX_CONTEXT_MINOR_VERSION_ARB, MPGL_VER_GET_MINOR(gl_version), - GLX_CONTEXT_PROFILE_MASK_ARB, GLX_CONTEXT_CORE_PROFILE_BIT_ARB, - GLX_CONTEXT_FLAGS_ARB, GLX_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB - | (flags & VOFLAG_GL_DEBUG ? GLX_CONTEXT_DEBUG_BIT_ARB : 0), - None - }; - GLXContext context = glXCreateContextAttribsARB(vo->x11->display, - glx_ctx->fbc, 0, True, - context_attribs); - if (!context) { - mp_msg(MSGT_VO, MSGL_FATAL, "[gl] Could not create GLX context!\n"); - return false; - } - - // set context - if (!glXMakeCurrent(vo->x11->display, vo->x11->window, context)) { - mp_msg(MSGT_VO, MSGL_FATAL, "[gl] Could not set GLX context!\n"); - glXDestroyContext(vo->x11->display, context); - return false; - } - - glx_ctx->context = context; - - getFunctions(ctx->gl, (void *)glXGetProcAddress, glxstr, true); - - if (!glXIsDirect(vo->x11->display, context)) - ctx->gl->mpgl_caps &= ~MPGL_CAP_NO_SW; - - return true; -} - -/** - * \brief free the VisualInfo and GLXContext of an OpenGL context. - * \ingroup glcontext - */ -static void releaseGlContext_x11(MPGLContext *ctx) -{ - struct glx_context *glx_ctx = ctx->priv; - XVisualInfo **vinfo = &glx_ctx->vinfo; - GLXContext *context = &glx_ctx->context; - Display *display = ctx->vo->x11->display; - GL *gl = ctx->gl; - if (*vinfo) - XFree(*vinfo); - *vinfo = NULL; - if (*context) { - if (gl->Finish) - gl->Finish(); - glXMakeCurrent(display, None, NULL); - glXDestroyContext(display, *context); - } - *context = 0; -} - -static void swapGlBuffers_x11(MPGLContext *ctx) -{ - glXSwapBuffers(ctx->vo->x11->display, ctx->vo->x11->window); -} -#endif - - -struct backend { - const char *name; - enum MPGLType type; -}; - -static struct backend backends[] = { - {"auto", GLTYPE_AUTO}, - {"cocoa", GLTYPE_COCOA}, - {"win", GLTYPE_W32}, - {"x11", GLTYPE_X11}, - // mplayer-svn aliases (note that mplayer-svn couples these with the numeric - // values of the internal GLTYPE_* constants) - {"-1", GLTYPE_AUTO}, - { "0", GLTYPE_W32}, - { "1", GLTYPE_X11}, - - {0} -}; - -int mpgl_find_backend(const char *name) -{ - for (const struct backend *entry = backends; entry->name; entry++) { - if (strcmp(entry->name, name) == 0) - return entry->type; - } - return -1; -} - -MPGLContext *mpgl_init(enum MPGLType type, struct vo *vo) -{ - MPGLContext *ctx; - if (type == GLTYPE_AUTO) { - ctx = mpgl_init(GLTYPE_COCOA, vo); - if (ctx) - return ctx; - ctx = mpgl_init(GLTYPE_W32, vo); - if (ctx) - return ctx; - return mpgl_init(GLTYPE_X11, vo); - } - ctx = talloc_zero(NULL, MPGLContext); - *ctx = (MPGLContext) { - .gl = talloc_zero(ctx, GL), - .type = type, - .vo = vo, - .requested_gl_version = MPGL_VER(3, 0), - .vo_init_ok = true, - }; - switch (ctx->type) { -#ifdef CONFIG_GL_COCOA - case GLTYPE_COCOA: - ctx->create_window_old = create_window_cocoa_old; - ctx->create_window_gl3 = create_window_cocoa_gl3; - ctx->releaseGlContext = releaseGlContext_cocoa; - ctx->swapGlBuffers = swapGlBuffers_cocoa; - ctx->check_events = vo_cocoa_check_events; - ctx->update_xinerama_info = vo_cocoa_update_xinerama_info; - ctx->fullscreen = vo_cocoa_fullscreen; - ctx->ontop = vo_cocoa_ontop; - ctx->vo_init = vo_cocoa_init; - ctx->pause = vo_cocoa_pause; - ctx->resume = vo_cocoa_resume; - ctx->vo_uninit = vo_cocoa_uninit; - break; -#endif -#ifdef CONFIG_GL_WIN32 - case GLTYPE_W32: - ctx->priv = talloc_zero(ctx, struct w32_context); - ctx->create_window_old = create_window_w32_old; - ctx->create_window_gl3 = create_window_w32_gl3; - ctx->releaseGlContext = releaseGlContext_w32; - ctx->swapGlBuffers = swapGlBuffers_w32; - ctx->update_xinerama_info = w32_update_xinerama_info; - ctx->border = vo_w32_border; - ctx->check_events = vo_w32_check_events; - ctx->fullscreen = vo_w32_fullscreen; - ctx->ontop = vo_w32_ontop; - ctx->vo_init = vo_w32_init; - ctx->vo_uninit = vo_w32_uninit; - break; -#endif -#ifdef CONFIG_GL_X11 - case GLTYPE_X11: - ctx->priv = talloc_zero(ctx, struct glx_context); - ctx->create_window_old = create_window_x11_old; - ctx->create_window_gl3 = create_window_x11_gl3; - ctx->releaseGlContext = releaseGlContext_x11; - ctx->swapGlBuffers = swapGlBuffers_x11; - ctx->update_xinerama_info = update_xinerama_info; - ctx->border = vo_x11_border; - ctx->check_events = vo_x11_check_events; - ctx->fullscreen = vo_x11_fullscreen; - ctx->ontop = vo_x11_ontop; - ctx->vo_init = vo_init; - ctx->vo_uninit = vo_x11_uninit; - break; -#endif - } - if (ctx->vo_init && ctx->vo_init(vo)) - return ctx; - talloc_free(ctx); - return NULL; -} - -bool mpgl_destroy_window(struct MPGLContext *ctx) -{ - ctx->releaseGlContext(ctx); - *ctx->gl = (GL) {0}; - // This is a caveat. At least on X11, this will recreate the X display - // connection. Also, if vo_init() fails, unspecified things will happen. - ctx->vo_uninit(ctx->vo); - ctx->vo_init_ok = ctx->vo_init(ctx->vo); - return ctx->vo_init_ok; -} - -static bool create_window(struct MPGLContext *ctx, int gl_caps, - bool (*create)(struct MPGLContext *, uint32_t, - uint32_t, uint32_t), - uint32_t d_width, uint32_t d_height, uint32_t flags) -{ - if (!create || !ctx->vo_init_ok) - return false; - if (create(ctx, d_width, d_height, flags)) { - int missing = (ctx->gl->mpgl_caps & gl_caps) ^ gl_caps; - if (!missing) { - ctx->selected_create_window = create; - return true; - } - mp_msg(MSGT_VO, MSGL_WARN, "[gl] Missing OpenGL features:"); - list_features(missing, MSGL_WARN, false); - if (missing & MPGL_CAP_NO_SW) { - mp_msg(MSGT_VO, MSGL_WARN, "[gl] Rejecting suspected software " - "OpenGL renderer.\n"); - } - } - // If we tried to create a GL 3 context, and we're going to create a legacy - // context after this, the window should be recreated at least on X11. - mpgl_destroy_window(ctx); - return false; -} - -bool mpgl_create_window(struct MPGLContext *ctx, int gl_caps, uint32_t d_width, - uint32_t d_height, uint32_t flags) -{ - assert(ctx->vo_init_ok); - if (ctx->selected_create_window) - return ctx->selected_create_window(ctx, d_width, d_height, flags); - - bool allow_gl3 = !(gl_caps & MPGL_CAP_GL_LEGACY); - bool allow_legacy = !(gl_caps & MPGL_CAP_GL3); - gl_caps |= MPGL_CAP_GL; - - if (allow_gl3 && create_window(ctx, gl_caps, ctx->create_window_gl3, - d_width, d_height, flags)) - return true; - - if (allow_legacy && create_window(ctx, gl_caps, ctx->create_window_old, - d_width, d_height, flags)) - return true; - - mp_msg(MSGT_VO, MSGL_ERR, "[gl] OpenGL context creation failed!\n"); - return false; -} - -void mpgl_uninit(MPGLContext *ctx) -{ - if (!ctx) - return; - if (ctx->vo_init_ok) { - ctx->releaseGlContext(ctx); - ctx->vo_uninit(ctx->vo); - } - talloc_free(ctx); -} - -void mp_log_source(int mod, int lev, const char *src) -{ - int line = 1; - if (!src) - return; - while (*src) { - const char *end = strchr(src, '\n'); - const char *next = end + 1; - if (!end) - next = end = src + strlen(src); - mp_msg(mod, lev, "[%3d] %.*s\n", line, (int)(end - src), src); - line++; - src = next; - } -} diff --git a/libvo/gl_common.h b/libvo/gl_common.h deleted file mode 100644 index 9816566097..0000000000 --- a/libvo/gl_common.h +++ /dev/null @@ -1,396 +0,0 @@ -/* - * 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. - * - * You can alternatively redistribute this file and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - */ - -#ifndef MPLAYER_GL_COMMON_H -#define MPLAYER_GL_COMMON_H - -#include <stdio.h> -#include <stdint.h> - -#include "config.h" -#include "mp_msg.h" - -#include "video_out.h" -#include "csputils.h" - -#include "libmpcodecs/mp_image.h" - -#if defined(CONFIG_GL_COCOA) && !defined(CONFIG_GL_X11) -#ifdef GL_VERSION_3_0 -#include <OpenGL/gl3.h> -#else -#include <OpenGL/gl.h> -#endif -#include <OpenGL/glext.h> -#else -#include <GL/gl.h> -#include <GL/glext.h> -#endif - -#include "libvo/gl_header_fixes.h" - -struct GL; -typedef struct GL GL; - -void glAdjustAlignment(GL *gl, int stride); - -int glFindFormat(uint32_t format, int have_texture_rg, int *bpp, - GLint *gl_texfmt, GLenum *gl_format, GLenum *gl_type); -int glFmt2bpp(GLenum format, GLenum type); -void glCreateClearTex(GL *gl, GLenum target, GLenum fmt, GLenum format, - GLenum type, GLint filter, int w, int h, - unsigned char val); -int glCreatePPMTex(GL *gl, GLenum target, GLenum fmt, GLint filter, - FILE *f, int *width, int *height, int *maxval); -void glUploadTex(GL *gl, GLenum target, GLenum format, GLenum type, - const void *dataptr, int stride, - int x, int y, int w, int h, int slice); -void glClearTex(GL *gl, GLenum target, GLenum format, GLenum type, - int x, int y, int w, int h, uint8_t val, void **scratch); -void glDownloadTex(GL *gl, GLenum target, GLenum format, GLenum type, - void *dataptr, int stride); -void glDrawTex(GL *gl, GLfloat x, GLfloat y, GLfloat w, GLfloat h, - GLfloat tx, GLfloat ty, GLfloat tw, GLfloat th, - int sx, int sy, int rect_tex, int is_yv12, int flip); -int loadGPUProgram(GL *gl, GLenum target, char *prog); -void glCheckError(GL *gl, const char *info); -mp_image_t *glGetWindowScreenshot(GL *gl); - -/** \addtogroup glconversion - * \{ */ -//! do not use YUV conversion, this should always stay 0 -#define YUV_CONVERSION_NONE 0 -//! use nVidia specific register combiners for YUV conversion -//! implementation has been removed -#define YUV_CONVERSION_COMBINERS 1 -//! use a fragment program for YUV conversion -#define YUV_CONVERSION_FRAGMENT 2 -//! use a fragment program for YUV conversion with gamma using POW -#define YUV_CONVERSION_FRAGMENT_POW 3 -//! use a fragment program with additional table lookup for YUV conversion -#define YUV_CONVERSION_FRAGMENT_LOOKUP 4 -//! use ATI specific register combiners ("fragment program") -#define YUV_CONVERSION_COMBINERS_ATI 5 -//! use a fragment program with 3D table lookup for YUV conversion -#define YUV_CONVERSION_FRAGMENT_LOOKUP3D 6 -//! use ATI specific "text" register combiners ("fragment program") -#define YUV_CONVERSION_TEXT_FRAGMENT 7 -//! use normal bilinear scaling for textures -#define YUV_SCALER_BILIN 0 -//! use higher quality bicubic scaling for textures -#define YUV_SCALER_BICUB 1 -//! use cubic scaling in X and normal linear scaling in Y direction -#define YUV_SCALER_BICUB_X 2 -//! use cubic scaling without additional lookup texture -#define YUV_SCALER_BICUB_NOTEX 3 -#define YUV_SCALER_UNSHARP 4 -#define YUV_SCALER_UNSHARP2 5 -//! mask for conversion type -#define YUV_CONVERSION_MASK 0xF -//! mask for scaler type -#define YUV_SCALER_MASK 0xF -//! shift value for luminance scaler type -#define YUV_LUM_SCALER_SHIFT 8 -//! shift value for chrominance scaler type -#define YUV_CHROM_SCALER_SHIFT 12 -//! extract conversion out of type -#define YUV_CONVERSION(t) ((t) & YUV_CONVERSION_MASK) -//! extract luminance scaler out of type -#define YUV_LUM_SCALER(t) (((t) >> YUV_LUM_SCALER_SHIFT) & YUV_SCALER_MASK) -//! extract chrominance scaler out of type -#define YUV_CHROM_SCALER(t) (((t) >> YUV_CHROM_SCALER_SHIFT) & YUV_SCALER_MASK) -#define SET_YUV_CONVERSION(c) ((c) & YUV_CONVERSION_MASK) -#define SET_YUV_LUM_SCALER(s) (((s) & YUV_SCALER_MASK) << YUV_LUM_SCALER_SHIFT) -#define SET_YUV_CHROM_SCALER(s) (((s) & YUV_SCALER_MASK) << YUV_CHROM_SCALER_SHIFT) -//! returns whether the yuv conversion supports large brightness range etc. -static inline int glYUVLargeRange(int conv) -{ - switch (conv) { - case YUV_CONVERSION_NONE: - case YUV_CONVERSION_COMBINERS_ATI: - case YUV_CONVERSION_FRAGMENT_LOOKUP3D: - case YUV_CONVERSION_TEXT_FRAGMENT: - return 0; - } - return 1; -} -/** \} */ - -typedef struct { - GLenum target; - int type; - struct mp_csp_params csp_params; - int texw; - int texh; - int chrom_texw; - int chrom_texh; - float filter_strength; - float noise_strength; -} gl_conversion_params_t; - -int glAutodetectYUVConversion(GL *gl); -void glSetupYUVConversion(GL *gl, gl_conversion_params_t *params); -void glEnableYUVConversion(GL *gl, GLenum target, int type); -void glDisableYUVConversion(GL *gl, GLenum target, int type); - -#define GL_3D_RED_CYAN 1 -#define GL_3D_GREEN_MAGENTA 2 -#define GL_3D_QUADBUFFER 3 - -void glEnable3DLeft(GL *gl, int type); -void glEnable3DRight(GL *gl, int type); -void glDisable3D(GL *gl, int type); - -enum MPGLType { - GLTYPE_AUTO, - GLTYPE_COCOA, - GLTYPE_W32, - GLTYPE_X11, -}; - -enum { - MPGL_CAP_GL = (1 << 0), // GL was successfully loaded - MPGL_CAP_GL_LEGACY = (1 << 1), // GL 1.1 (but not 3.x) - MPGL_CAP_GL2 = (1 << 2), // GL 2.0 (3.x core subset) - MPGL_CAP_GL21 = (1 << 3), // GL 2.1 (3.x core subset) - MPGL_CAP_GL3 = (1 << 4), // GL 3.x core - MPGL_CAP_FB = (1 << 5), - MPGL_CAP_VAO = (1 << 6), - MPGL_CAP_SRGB_TEX = (1 << 7), - MPGL_CAP_SRGB_FB = (1 << 8), - MPGL_CAP_FLOAT_TEX = (1 << 9), - MPGL_CAP_TEX_RG = (1 << 10), // GL_ARB_texture_rg / GL 3.x - MPGL_CAP_NO_SW = (1 << 30), // used to block sw. renderers -}; - -#define MPGL_VER(major, minor) (((major) << 16) | (minor)) -#define MPGL_VER_GET_MAJOR(ver) ((ver) >> 16) -#define MPGL_VER_GET_MINOR(ver) ((ver) & ((1 << 16) - 1)) - -#define MPGL_VER_P(ver) MPGL_VER_GET_MAJOR(ver), MPGL_VER_GET_MINOR(ver) - -typedef struct MPGLContext { - GL *gl; - enum MPGLType type; - struct vo *vo; - - // Bit size of each component in the created framebuffer. 0 if unknown. - int depth_r, depth_g, depth_b; - - // GL version requested from create_window_gl3 backend. - // (Might be different from the actual version in gl->version.) - int requested_gl_version; - - void (*swapGlBuffers)(struct MPGLContext *); - int (*check_events)(struct vo *vo); - void (*fullscreen)(struct vo *vo); - int (*vo_init)(struct vo *vo); - void (*vo_uninit)(struct vo *vo); - void (*releaseGlContext)(struct MPGLContext *); - - // Creates GL 1.x/2.x legacy context. - bool (*create_window_old)(struct MPGLContext *ctx, uint32_t d_width, - uint32_t d_height, uint32_t flags); - - // Creates GL 3.x core context. - bool (*create_window_gl3)(struct MPGLContext *ctx, uint32_t d_width, - uint32_t d_height, uint32_t flags); - - // optional - void (*pause)(struct vo *vo); - void (*resume)(struct vo *vo); - void (*ontop)(struct vo *vo); - void (*border)(struct vo *vo); - void (*update_xinerama_info)(struct vo *vo); - - // For free use by the backend. - void *priv; - // Internal to gl_common.c. - bool (*selected_create_window)(struct MPGLContext *ctx, uint32_t d_width, - uint32_t d_height, uint32_t flags); - bool vo_init_ok; -} MPGLContext; - -int mpgl_find_backend(const char *name); - -MPGLContext *mpgl_init(enum MPGLType type, struct vo *vo); -void mpgl_uninit(MPGLContext *ctx); - -// Create a VO window and create a GL context on it. -// (Calls create_window_gl3 or create_window+setGlWindow.) -// gl_caps: bitfield of MPGL_CAP_* (required GL version and feature set) -// flags: passed to the backend's create window function -// Returns success. -bool mpgl_create_window(struct MPGLContext *ctx, int gl_caps, uint32_t d_width, - uint32_t d_height, uint32_t flags); - -// Destroy the window, without resetting GL3 vs. GL2 context choice. -// If this fails (false), mpgl_uninit(ctx) must be called. -bool mpgl_destroy_window(struct MPGLContext *ctx); - -// print a multi line string with line numbers (e.g. for shader sources) -// mod, lev: module and log level, as in mp_msg() -void mp_log_source(int mod, int lev, const char *src); - -//function pointers loaded from the OpenGL library -struct GL { - int version; // MPGL_VER() mangled - int glsl_version; // e.g. 130 for GLSL 1.30 - char *extensions; // Equivalent to GL_EXTENSIONS - int mpgl_caps; // Bitfield of MPGL_CAP_* constants - - void (GLAPIENTRY *Begin)(GLenum); - void (GLAPIENTRY *End)(void); - void (GLAPIENTRY *Viewport)(GLint, GLint, GLsizei, GLsizei); - void (GLAPIENTRY *MatrixMode)(GLenum); - void (GLAPIENTRY *LoadIdentity)(void); - void (GLAPIENTRY *Translated)(double, double, double); - void (GLAPIENTRY *Scaled)(double, double, double); - void (GLAPIENTRY *Ortho)(double, double, double, double, double,double); - void (GLAPIENTRY *PushMatrix)(void); - void (GLAPIENTRY *PopMatrix)(void); - void (GLAPIENTRY *Clear)(GLbitfield); - GLuint (GLAPIENTRY *GenLists)(GLsizei); - void (GLAPIENTRY *DeleteLists)(GLuint, GLsizei); - void (GLAPIENTRY *NewList)(GLuint, GLenum); - void (GLAPIENTRY *EndList)(void); - void (GLAPIENTRY *CallList)(GLuint); - void (GLAPIENTRY *CallLists)(GLsizei, GLenum, const GLvoid *); - void (GLAPIENTRY *GenTextures)(GLsizei, GLuint *); - void (GLAPIENTRY *DeleteTextures)(GLsizei, const GLuint *); - void (GLAPIENTRY *TexEnvi)(GLenum, GLenum, GLint); - void (GLAPIENTRY *Color4ub)(GLubyte, GLubyte, GLubyte, GLubyte); - void (GLAPIENTRY *Color4f)(GLfloat, GLfloat, GLfloat, GLfloat); - void (GLAPIENTRY *ClearColor)(GLclampf, GLclampf, GLclampf, GLclampf); - void (GLAPIENTRY *Enable)(GLenum); - void (GLAPIENTRY *Disable)(GLenum); - const GLubyte *(GLAPIENTRY * GetString)(GLenum); - void (GLAPIENTRY *DrawBuffer)(GLenum); - void (GLAPIENTRY *DepthMask)(GLboolean); - void (GLAPIENTRY *BlendFunc)(GLenum, GLenum); - void (GLAPIENTRY *Flush)(void); - void (GLAPIENTRY *Finish)(void); - void (GLAPIENTRY *PixelStorei)(GLenum, GLint); - void (GLAPIENTRY *TexImage1D)(GLenum, GLint, GLint, GLsizei, GLint, - GLenum, GLenum, const GLvoid *); - void (GLAPIENTRY *TexImage2D)(GLenum, GLint, GLint, GLsizei, GLsizei, - GLint, GLenum, GLenum, const GLvoid *); - void (GLAPIENTRY *TexSubImage2D)(GLenum, GLint, GLint, GLint, - GLsizei, GLsizei, GLenum, GLenum, - const GLvoid *); - void (GLAPIENTRY *GetTexImage)(GLenum, GLint, GLenum, GLenum, GLvoid *); - void (GLAPIENTRY *TexParameteri)(GLenum, GLenum, GLint); - void (GLAPIENTRY *TexParameterf)(GLenum, GLenum, GLfloat); - void (GLAPIENTRY *TexParameterfv)(GLenum, GLenum, const GLfloat *); - void (GLAPIENTRY *TexCoord2f)(GLfloat, GLfloat); - void (GLAPIENTRY *TexCoord2fv)(const GLfloat *); - void (GLAPIENTRY *Vertex2f)(GLfloat, GLfloat); - void (GLAPIENTRY *GetIntegerv)(GLenum, GLint *); - void (GLAPIENTRY *GetBooleanv)(GLenum, GLboolean *); - void (GLAPIENTRY *ColorMask)(GLboolean, GLboolean, GLboolean, GLboolean); - void (GLAPIENTRY *ReadPixels)(GLint, GLint, GLsizei, GLsizei, GLenum, - GLenum, GLvoid *); - void (GLAPIENTRY *ReadBuffer)(GLenum); - void (GLAPIENTRY *VertexPointer)(GLint, GLenum, GLsizei, const GLvoid *); - void (GLAPIENTRY *ColorPointer)(GLint, GLenum, GLsizei, const GLvoid *); - void (GLAPIENTRY *TexCoordPointer)(GLint, GLenum, GLsizei, const GLvoid *); - void (GLAPIENTRY *DrawArrays)(GLenum, GLint, GLsizei); - void (GLAPIENTRY *EnableClientState)(GLenum); - void (GLAPIENTRY *DisableClientState)(GLenum); - GLenum (GLAPIENTRY *GetError)(void); - - void (GLAPIENTRY *GenBuffers)(GLsizei, GLuint *); - void (GLAPIENTRY *DeleteBuffers)(GLsizei, const GLuint *); - void (GLAPIENTRY *BindBuffer)(GLenum, GLuint); - GLvoid * (GLAPIENTRY * MapBuffer)(GLenum, GLenum); - GLboolean (GLAPIENTRY *UnmapBuffer)(GLenum); - void (GLAPIENTRY *BufferData)(GLenum, intptr_t, const GLvoid *, GLenum); - void (GLAPIENTRY *ActiveTexture)(GLenum); - void (GLAPIENTRY *BindTexture)(GLenum, GLuint); - void (GLAPIENTRY *MultiTexCoord2f)(GLenum, GLfloat, GLfloat); - void (GLAPIENTRY *GenPrograms)(GLsizei, GLuint *); - void (GLAPIENTRY *DeletePrograms)(GLsizei, const GLuint *); - void (GLAPIENTRY *BindProgram)(GLenum, GLuint); - void (GLAPIENTRY *ProgramString)(GLenum, GLenum, GLsizei, const GLvoid *); - void (GLAPIENTRY *GetProgramivARB)(GLenum, GLenum, GLint *); - void (GLAPIENTRY *ProgramEnvParameter4f)(GLenum, GLuint, GLfloat, GLfloat, - GLfloat, GLfloat); - int (GLAPIENTRY *SwapInterval)(int); - void (GLAPIENTRY *TexImage3D)(GLenum, GLint, GLenum, GLsizei, GLsizei, - GLsizei, GLint, GLenum, GLenum, - const GLvoid *); - - void (GLAPIENTRY *BeginFragmentShader)(void); - void (GLAPIENTRY *EndFragmentShader)(void); - void (GLAPIENTRY *SampleMap)(GLuint, GLuint, GLenum); - void (GLAPIENTRY *ColorFragmentOp2)(GLenum, GLuint, GLuint, GLuint, GLuint, - GLuint, GLuint, GLuint, GLuint, GLuint); - void (GLAPIENTRY *ColorFragmentOp3)(GLenum, GLuint, GLuint, GLuint, GLuint, - GLuint, GLuint, GLuint, GLuint, GLuint, - GLuint, GLuint, GLuint); - void (GLAPIENTRY *SetFragmentShaderConstant)(GLuint, const GLfloat *); - - void (GLAPIENTRY *GenVertexArrays)(GLsizei, GLuint *); - void (GLAPIENTRY *BindVertexArray)(GLuint); - GLint (GLAPIENTRY *GetAttribLocation)(GLuint, const GLchar *); - void (GLAPIENTRY *EnableVertexAttribArray)(GLuint); - void (GLAPIENTRY *DisableVertexAttribArray)(GLuint); - void (GLAPIENTRY *VertexAttribPointer)(GLuint, GLint, GLenum, GLboolean, - GLsizei, const GLvoid *); - void (GLAPIENTRY *DeleteVertexArrays)(GLsizei, const GLuint *); - void (GLAPIENTRY *UseProgram)(GLuint); - GLint (GLAPIENTRY *GetUniformLocation)(GLuint, const GLchar *); - void (GLAPIENTRY *CompileShader)(GLuint); - GLuint (GLAPIENTRY *CreateProgram)(void); - GLuint (GLAPIENTRY *CreateShader)(GLenum); - void (GLAPIENTRY *ShaderSource)(GLuint, GLsizei, const GLchar **, - const GLint *); - void (GLAPIENTRY *LinkProgram)(GLuint); - void (GLAPIENTRY *AttachShader)(GLuint, GLuint); - void (GLAPIENTRY *DeleteShader)(GLuint); - void (GLAPIENTRY *DeleteProgram)(GLuint); - void (GLAPIENTRY *GetShaderInfoLog)(GLuint, GLsizei, GLsizei *, GLchar *); - void (GLAPIENTRY *GetShaderiv)(GLuint, GLenum, GLint *); - void (GLAPIENTRY *GetProgramInfoLog)(GLuint, GLsizei, GLsizei *, GLchar *); - void (GLAPIENTRY *GetProgramiv)(GLenum, GLenum, GLint *); - const GLubyte* (GLAPIENTRY *GetStringi)(GLenum, GLuint); - void (GLAPIENTRY *BindAttribLocation)(GLuint, GLuint, const GLchar *); - void (GLAPIENTRY *BindFramebuffer)(GLenum, GLuint); - void (GLAPIENTRY *GenFramebuffers)(GLsizei, GLuint *); - void (GLAPIENTRY *DeleteFramebuffers)(GLsizei, const GLuint *); - GLenum (GLAPIENTRY *CheckFramebufferStatus)(GLenum); - void (GLAPIENTRY *FramebufferTexture2D)(GLenum, GLenum, GLenum, GLuint, - GLint); - - void (GLAPIENTRY *Uniform1f)(GLint, GLfloat); - void (GLAPIENTRY *Uniform2f)(GLint, GLfloat, GLfloat); - void (GLAPIENTRY *Uniform3f)(GLint, GLfloat, GLfloat, GLfloat); - void (GLAPIENTRY *Uniform4f)(GLint, GLfloat, GLfloat, GLfloat, GLfloat); - void (GLAPIENTRY *Uniform1i)(GLint, GLint); - void (GLAPIENTRY *UniformMatrix3fv)(GLint, GLsizei, GLboolean, - const GLfloat *); - void (GLAPIENTRY *UniformMatrix4x3fv)(GLint, GLsizei, GLboolean, - const GLfloat *); -}; - -#endif /* MPLAYER_GL_COMMON_H */ diff --git a/libvo/gl_header_fixes.h b/libvo/gl_header_fixes.h deleted file mode 100644 index d149a9970a..0000000000 --- a/libvo/gl_header_fixes.h +++ /dev/null @@ -1,257 +0,0 @@ -/* - * 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. - * - * You can alternatively redistribute this file and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - */ - -// workaround for some gl.h headers -#ifndef GLAPIENTRY -#ifdef APIENTRY -#define GLAPIENTRY APIENTRY -#elif defined(CONFIG_GL_WIN32) -#define GLAPIENTRY __stdcall -#else -#define GLAPIENTRY -#endif -#endif - -/** - * \defgroup glextdefines OpenGL extension defines - * - * conditionally define all extension defines used. - * vendor specific extensions should be marked as such - * (e.g. _NV), _ARB is not used to ease readability. - * \{ - */ -#ifndef GL_TEXTURE_3D -#define GL_TEXTURE_3D 0x806F -#endif -#ifndef GL_TEXTURE_WRAP_R -#define GL_TEXTURE_WRAP_R 0x8072 -#endif -#ifndef GL_CLAMP_TO_EDGE -#define GL_CLAMP_TO_EDGE 0x812F -#endif -#ifndef GL_GENERATE_MIPMAP -#define GL_GENERATE_MIPMAP 0x8191 -#endif -#ifndef GL_TEXT_FRAGMENT_SHADER_ATI -#define GL_TEXT_FRAGMENT_SHADER_ATI 0x8200 -#endif -#ifndef GL_FRAGMENT_SHADER_ATI -#define GL_FRAGMENT_SHADER_ATI 0x8920 -#endif -#ifndef GL_NUM_FRAGMENT_REGISTERS_ATI -#define GL_NUM_FRAGMENT_REGISTERS_ATI 0x896E -#endif -#ifndef GL_REG_0_ATI -#define GL_REG_0_ATI 0x8921 -#endif -#ifndef GL_REG_1_ATI -#define GL_REG_1_ATI 0x8922 -#endif -#ifndef GL_REG_2_ATI -#define GL_REG_2_ATI 0x8923 -#endif -#ifndef GL_CON_0_ATI -#define GL_CON_0_ATI 0x8941 -#endif -#ifndef GL_CON_1_ATI -#define GL_CON_1_ATI 0x8942 -#endif -#ifndef GL_CON_2_ATI -#define GL_CON_2_ATI 0x8943 -#endif -#ifndef GL_CON_3_ATI -#define GL_CON_3_ATI 0x8944 -#endif -#ifndef GL_ADD_ATI -#define GL_ADD_ATI 0x8963 -#endif -#ifndef GL_MUL_ATI -#define GL_MUL_ATI 0x8964 -#endif -#ifndef GL_MAD_ATI -#define GL_MAD_ATI 0x8968 -#endif -#ifndef GL_SWIZZLE_STR_ATI -#define GL_SWIZZLE_STR_ATI 0x8976 -#endif -#ifndef GL_4X_BIT_ATI -#define GL_4X_BIT_ATI 2 -#endif -#ifndef GL_8X_BIT_ATI -#define GL_8X_BIT_ATI 4 -#endif -#ifndef GL_BIAS_BIT_ATI -#define GL_BIAS_BIT_ATI 8 -#endif -#ifndef GL_MAX_TEXTURE_UNITS -#define GL_MAX_TEXTURE_UNITS 0x84E2 -#endif -#ifndef GL_TEXTURE0 -#define GL_TEXTURE0 0x84C0 -#endif -#ifndef GL_TEXTURE1 -#define GL_TEXTURE1 0x84C1 -#endif -#ifndef GL_TEXTURE2 -#define GL_TEXTURE2 0x84C2 -#endif -#ifndef GL_TEXTURE3 -#define GL_TEXTURE3 0x84C3 -#endif -#ifndef GL_TEXTURE_RECTANGLE -#define GL_TEXTURE_RECTANGLE 0x84F5 -#endif -#ifndef GL_PIXEL_UNPACK_BUFFER -#define GL_PIXEL_UNPACK_BUFFER 0x88EC -#endif -#ifndef GL_STREAM_DRAW -#define GL_STREAM_DRAW 0x88E0 -#endif -#ifndef GL_DYNAMIC_DRAW -#define GL_DYNAMIC_DRAW 0x88E8 -#endif -#ifndef GL_WRITE_ONLY -#define GL_WRITE_ONLY 0x88B9 -#endif -#ifndef GL_BGR -#define GL_BGR 0x80E0 -#endif -#ifndef GL_BGRA -#define GL_BGRA 0x80E1 -#endif -#ifndef GL_UNSIGNED_BYTE_3_3_2 -#define GL_UNSIGNED_BYTE_3_3_2 0x8032 -#endif -#ifndef GL_UNSIGNED_BYTE_2_3_3_REV -#define GL_UNSIGNED_BYTE_2_3_3_REV 0x8362 -#endif -#ifndef GL_UNSIGNED_SHORT_4_4_4_4 -#define GL_UNSIGNED_SHORT_4_4_4_4 0x8033 -#endif -#ifndef GL_UNSIGNED_SHORT_4_4_4_4_REV -#define GL_UNSIGNED_SHORT_4_4_4_4_REV 0x8365 -#endif -#ifndef GL_UNSIGNED_SHORT_5_6_5 -#define GL_UNSIGNED_SHORT_5_6_5 0x8363 -#endif -#ifndef GL_UNSIGNED_INT_8_8_8_8 -#define GL_UNSIGNED_INT_8_8_8_8 0x8035 -#endif -#ifndef GL_UNSIGNED_INT_8_8_8_8_REV -#define GL_UNSIGNED_INT_8_8_8_8_REV 0x8367 -#endif -#ifndef GL_UNSIGNED_SHORT_5_6_5_REV -#define GL_UNSIGNED_SHORT_5_6_5_REV 0x8364 -#endif -#ifndef GL_UNSIGNED_INT_10_10_10_2 -#define GL_UNSIGNED_INT_10_10_10_2 0x8036 -#endif -#ifndef GL_UNSIGNED_INT_2_10_10_10_REV -#define GL_UNSIGNED_INT_2_10_10_10_REV 0x8368 -#endif -#ifndef GL_UNSIGNED_SHORT_5_5_5_1 -#define GL_UNSIGNED_SHORT_5_5_5_1 0x8034 -#endif -#ifndef GL_UNSIGNED_SHORT_1_5_5_5_REV -#define GL_UNSIGNED_SHORT_1_5_5_5_REV 0x8366 -#endif -#ifndef GL_UNSIGNED_SHORT_8_8 -#define GL_UNSIGNED_SHORT_8_8 0x85BA -#endif -#ifndef GL_UNSIGNED_SHORT_8_8_REV -#define GL_UNSIGNED_SHORT_8_8_REV 0x85BB -#endif -#ifndef GL_YCBCR_MESA -#define GL_YCBCR_MESA 0x8757 -#endif -#ifndef GL_RGB32F -#define GL_RGB32F 0x8815 -#endif -#ifndef GL_FLOAT_RGB32_NV -#define GL_FLOAT_RGB32_NV 0x8889 -#endif -#ifndef GL_LUMINANCE16 -#define GL_LUMINANCE16 0x8042 -#endif -#ifndef GL_R16 -#define GL_R16 0x822A -#endif -#ifndef GL_UNPACK_CLIENT_STORAGE_APPLE -#define GL_UNPACK_CLIENT_STORAGE_APPLE 0x85B2 -#endif -#ifndef GL_FRAGMENT_PROGRAM -#define GL_FRAGMENT_PROGRAM 0x8804 -#endif -#ifndef GL_PROGRAM_FORMAT_ASCII -#define GL_PROGRAM_FORMAT_ASCII 0x8875 -#endif -#ifndef GL_PROGRAM_ERROR_POSITION -#define GL_PROGRAM_ERROR_POSITION 0x864B -#endif -#ifndef GL_MAX_TEXTURE_IMAGE_UNITS -#define GL_MAX_TEXTURE_IMAGE_UNITS 0x8872 -#endif -#ifndef GL_PROGRAM_ERROR_STRING -#define GL_PROGRAM_ERROR_STRING 0x8874 -#endif -/** \} */ // end of glextdefines group - - -#if defined(CONFIG_GL_WIN32) && !defined(WGL_CONTEXT_MAJOR_VERSION_ARB) -/* these are supposed to be defined in wingdi.h but mingw's is too old */ -/* only the bits actually used by mplayer are defined */ -/* reference: http://www.opengl.org/registry/specs/ARB/wgl_create_context.txt */ - -#define WGL_CONTEXT_MAJOR_VERSION_ARB 0x2091 -#define WGL_CONTEXT_MINOR_VERSION_ARB 0x2092 -#define WGL_CONTEXT_FLAGS_ARB 0x2094 -#define WGL_CONTEXT_PROFILE_MASK_ARB 0x9126 -#define WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB 0x0002 -#define WGL_CONTEXT_CORE_PROFILE_BIT_ARB 0x00000001 -#endif - -// Define just enough constants to make the OpenGL 3 code compile against -// older SDKs. Values are taken straight from OpenGL/gl3.h -#if defined __APPLE__ && !(defined GL_VERSION_3_0) -#define GL_RGBA16F 0x881A -#define GL_RGB16F 0x881B -#define GL_MAJOR_VERSION 0x821B -#define GL_MINOR_VERSION 0x821C -#define GL_NUM_EXTENSIONS 0x821D - -#ifndef GL_ARB_framebuffer_sRGB -#define GL_FRAMEBUFFER_SRGB 0x8DB9 -#endif -#endif - -// FreeBSD 10.0-CURRENT lacks the GLX_ARB_create_context extension completely -#ifndef GLX_CONTEXT_MAJOR_VERSION_ARB -#define GLX_CONTEXT_MAJOR_VERSION_ARB 0x2091 -#define GLX_CONTEXT_MINOR_VERSION_ARB 0x2092 -#define GLX_CONTEXT_FLAGS_ARB 0x2094 -#define GLX_CONTEXT_PROFILE_MASK_ARB 0x9126 -#define GLX_CONTEXT_DEBUG_BIT_ARB 0x0001 -#define GLX_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB 0x0002 -#define GLX_CONTEXT_CORE_PROFILE_BIT_ARB 0x00000001 -#define GLX_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB 0x00000002 -#endif diff --git a/libvo/gl_osd.c b/libvo/gl_osd.c deleted file mode 100644 index 81485cabe9..0000000000 --- a/libvo/gl_osd.c +++ /dev/null @@ -1,324 +0,0 @@ -/* - * 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, see <http://www.gnu.org/licenses/>. - */ - -#include <stdlib.h> -#include <assert.h> -#include <libavutil/common.h> - -#include "bitmap_packer.h" - -#include "gl_osd.h" - -struct osd_fmt_entry { - GLint internal_format; - GLint format; - GLenum type; -}; - -// glBlendFunc() arguments -static const int blend_factors[SUBBITMAP_COUNT][2] = { - [SUBBITMAP_LIBASS] = {GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA}, - [SUBBITMAP_RGBA] = {GL_ONE, GL_ONE_MINUS_SRC_ALPHA}, -}; - -static const struct osd_fmt_entry osd_to_gl3_formats[SUBBITMAP_COUNT] = { - [SUBBITMAP_LIBASS] = {GL_RED, GL_RED, GL_UNSIGNED_BYTE}, - [SUBBITMAP_RGBA] = {GL_RGBA, GL_BGRA, GL_UNSIGNED_BYTE}, -}; - -static const struct osd_fmt_entry osd_to_gl_legacy_formats[SUBBITMAP_COUNT] = { - [SUBBITMAP_LIBASS] = {GL_ALPHA, GL_ALPHA, GL_UNSIGNED_BYTE}, - [SUBBITMAP_RGBA] = {GL_RGBA, GL_BGRA, GL_UNSIGNED_BYTE}, -}; - -struct mpgl_osd *mpgl_osd_init(GL *gl, bool legacy) -{ - GLint max_texture_size; - gl->GetIntegerv(GL_MAX_TEXTURE_SIZE, &max_texture_size); - - struct mpgl_osd *ctx = talloc_ptrtype(NULL, ctx); - *ctx = (struct mpgl_osd) { - .gl = gl, - .fmt_table = legacy ? osd_to_gl_legacy_formats : osd_to_gl3_formats, - .scratch = talloc_zero_size(ctx, 1), - }; - - for (int n = 0; n < MAX_OSD_PARTS; n++) { - struct mpgl_osd_part *p = talloc_ptrtype(ctx, p); - *p = (struct mpgl_osd_part) { - .packer = talloc_struct(p, struct bitmap_packer, { - .w_max = max_texture_size, - .h_max = max_texture_size, - }), - }; - ctx->parts[n] = p; - } - - for (int n = 0; n < SUBBITMAP_COUNT; n++) - ctx->formats[n] = ctx->fmt_table[n].type != 0; - - return ctx; -} - -void mpgl_osd_destroy(struct mpgl_osd *ctx) -{ - GL *gl = ctx->gl; - - for (int n = 0; n < MAX_OSD_PARTS; n++) { - struct mpgl_osd_part *p = ctx->parts[n]; - gl->DeleteTextures(1, &p->texture); - if (gl->DeleteBuffers) - gl->DeleteBuffers(1, &p->buffer); - } - talloc_free(ctx); -} - -static bool upload_pbo(struct mpgl_osd *ctx, struct mpgl_osd_part *osd, - struct sub_bitmaps *imgs) -{ - GL *gl = ctx->gl; - bool success = true; - struct osd_fmt_entry fmt = ctx->fmt_table[imgs->format]; - int pix_stride = glFmt2bpp(fmt.format, fmt.type); - - if (!osd->buffer) { - gl->GenBuffers(1, &osd->buffer); - gl->BindBuffer(GL_PIXEL_UNPACK_BUFFER, osd->buffer); - gl->BufferData(GL_PIXEL_UNPACK_BUFFER, osd->w * osd->h * pix_stride, - NULL, GL_DYNAMIC_COPY); - gl->BindBuffer(GL_PIXEL_UNPACK_BUFFER, 0); - } - - gl->BindBuffer(GL_PIXEL_UNPACK_BUFFER, osd->buffer); - char *data = gl->MapBuffer(GL_PIXEL_UNPACK_BUFFER, GL_WRITE_ONLY); - if (!data) { - success = false; - } else { - struct pos bb[2]; - packer_get_bb(osd->packer, bb); - size_t stride = osd->w * pix_stride; - packer_copy_subbitmaps(osd->packer, imgs, data, pix_stride, stride); - if (!gl->UnmapBuffer(GL_PIXEL_UNPACK_BUFFER)) - success = false; - glUploadTex(gl, GL_TEXTURE_2D, fmt.format, fmt.type, NULL, stride, - bb[0].x, bb[0].y, bb[1].x - bb[0].x, bb[1].y - bb[0].y, - 0); - } - gl->BindBuffer(GL_PIXEL_UNPACK_BUFFER, 0); - - if (!success) { - mp_msg(MSGT_VO, MSGL_FATAL, "[gl] Error: can't upload subtitles! " - "Remove the 'pbo' suboption.\n"); - } - - return success; -} - -static void upload_tex(struct mpgl_osd *ctx, struct mpgl_osd_part *osd, - struct sub_bitmaps *imgs) -{ - struct osd_fmt_entry fmt = ctx->fmt_table[imgs->format]; - if (osd->packer->padding) { - struct pos bb[2]; - packer_get_bb(osd->packer, bb); - glClearTex(ctx->gl, GL_TEXTURE_2D, fmt.format, fmt.type, - bb[0].x, bb[0].y, bb[1].x - bb[0].y, bb[1].y - bb[0].y, - 0, &ctx->scratch); - } - for (int n = 0; n < osd->packer->count; n++) { - struct sub_bitmap *s = &imgs->parts[n]; - struct pos p = osd->packer->result[n]; - - glUploadTex(ctx->gl, GL_TEXTURE_2D, fmt.format, fmt.type, - s->bitmap, s->stride, p.x, p.y, s->w, s->h, 0); - } -} - -static bool upload_osd(struct mpgl_osd *ctx, struct mpgl_osd_part *osd, - struct sub_bitmaps *imgs) -{ - GL *gl = ctx->gl; - - // assume 2x2 filter on scaling - osd->packer->padding = ctx->scaled || imgs->scaled; - int r = packer_pack_from_subbitmaps(osd->packer, imgs); - if (r < 0) { - mp_msg(MSGT_VO, MSGL_ERR, "[gl] OSD bitmaps do not fit on " - "a surface with the maximum supported size %dx%d.\n", - osd->packer->w_max, osd->packer->h_max); - return false; - } - - struct osd_fmt_entry fmt = ctx->fmt_table[imgs->format]; - assert(fmt.type != 0); - - if (!osd->texture) - gl->GenTextures(1, &osd->texture); - - gl->BindTexture(GL_TEXTURE_2D, osd->texture); - - if (osd->packer->w > osd->w || osd->packer->h > osd->h - || osd->format != imgs->format) - { - osd->format = imgs->format; - osd->w = FFMAX(32, osd->packer->w); - osd->h = FFMAX(32, osd->packer->h); - - gl->TexImage2D(GL_TEXTURE_2D, 0, fmt.internal_format, osd->w, osd->h, - 0, fmt.format, fmt.type, NULL); - - gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - - if (gl->DeleteBuffers) - gl->DeleteBuffers(1, &osd->buffer); - osd->buffer = 0; - } - - bool uploaded = false; - if (ctx->use_pbo) - uploaded = upload_pbo(ctx, osd, imgs); - if (!uploaded) - upload_tex(ctx, osd, imgs); - - gl->BindTexture(GL_TEXTURE_2D, 0); - - return true; -} - -struct mpgl_osd_part *mpgl_osd_generate(struct mpgl_osd *ctx, - struct sub_bitmaps *imgs) -{ - if (imgs->num_parts == 0 || !ctx->formats[imgs->format]) - return NULL; - - struct mpgl_osd_part *osd = ctx->parts[imgs->render_index]; - - if (imgs->bitmap_pos_id != osd->bitmap_pos_id) { - if (imgs->bitmap_id != osd->bitmap_id) { - if (!upload_osd(ctx, osd, imgs)) - osd->packer->count = 0; - } - - osd->bitmap_id = imgs->bitmap_id; - osd->bitmap_pos_id = imgs->bitmap_pos_id; - osd->num_vertices = 0; - } - - return osd->packer->count ? osd : NULL; -} - -void mpgl_osd_set_gl_state(struct mpgl_osd *ctx, struct mpgl_osd_part *p) -{ - GL *gl = ctx->gl; - - gl->BindTexture(GL_TEXTURE_2D, p->texture); - gl->Enable(GL_BLEND); - gl->BlendFunc(blend_factors[p->format][0], blend_factors[p->format][1]); -} - -void mpgl_osd_unset_gl_state(struct mpgl_osd *ctx, struct mpgl_osd_part *p) -{ - GL *gl = ctx->gl; - - gl->Disable(GL_BLEND); - gl->BindTexture(GL_TEXTURE_2D, 0); -} - -struct vertex { - float position[2]; - uint8_t color[4]; - float texcoord[2]; -}; - -static void draw_legacy_cb(void *pctx, struct sub_bitmaps *imgs) -{ - struct mpgl_osd *ctx = pctx; - struct mpgl_osd_part *osd = mpgl_osd_generate(ctx, imgs); - if (!osd) - return; - - if (!osd->num_vertices) { - // 2 triangles primitives per quad = 6 vertices per quad - // not using GL_QUADS, as it is deprecated in OpenGL 3.x and later - osd->vertices = talloc_realloc(osd, osd->vertices, struct vertex, - osd->packer->count * 6); - - struct vertex *va = osd->vertices; - float tex_w = osd->w; - float tex_h = osd->h; - - for (int n = 0; n < osd->packer->count; n++) { - struct sub_bitmap *b = &imgs->parts[n]; - struct pos p = osd->packer->result[n]; - - uint32_t c = imgs->format == SUBBITMAP_LIBASS - ? b->libass.color : 0xFFFFFF00; - uint8_t color[4] = { c >> 24, (c >> 16) & 0xff, - (c >> 8) & 0xff, 255 - (c & 0xff) }; - - float x0 = b->x; - float y0 = b->y; - float x1 = b->x + b->dw; - float y1 = b->y + b->dh; - float tx0 = p.x / tex_w; - float ty0 = p.y / tex_h; - float tx1 = (p.x + b->w) / tex_w; - float ty1 = (p.y + b->h) / tex_h; - -#define COLOR_INIT {color[0], color[1], color[2], color[3]} - struct vertex *v = &va[osd->num_vertices]; - v[0] = (struct vertex) { {x0, y0}, COLOR_INIT, {tx0, ty0} }; - v[1] = (struct vertex) { {x0, y1}, COLOR_INIT, {tx0, ty1} }; - v[2] = (struct vertex) { {x1, y0}, COLOR_INIT, {tx1, ty0} }; - v[3] = (struct vertex) { {x1, y1}, COLOR_INIT, {tx1, ty1} }; - v[4] = v[2]; - v[5] = v[1]; -#undef COLOR_INIT - osd->num_vertices += 6; - } - } - - GL *gl = ctx->gl; - - struct vertex *va = osd->vertices; - size_t stride = sizeof(va[0]); - - gl->VertexPointer(2, GL_FLOAT, stride, &va[0].position[0]); - gl->ColorPointer(4, GL_UNSIGNED_BYTE, stride, &va[0].color[0]); - gl->TexCoordPointer(2, GL_FLOAT, stride, &va[0].texcoord[0]); - - gl->EnableClientState(GL_VERTEX_ARRAY); - gl->EnableClientState(GL_TEXTURE_COORD_ARRAY); - gl->EnableClientState(GL_COLOR_ARRAY); - - mpgl_osd_set_gl_state(ctx, osd); - gl->DrawArrays(GL_TRIANGLES, 0, osd->num_vertices); - mpgl_osd_unset_gl_state(ctx, osd); - - gl->DisableClientState(GL_VERTEX_ARRAY); - gl->DisableClientState(GL_TEXTURE_COORD_ARRAY); - gl->DisableClientState(GL_COLOR_ARRAY); -} - -void mpgl_osd_draw_legacy(struct mpgl_osd *ctx, struct osd_state *osd, - struct mp_osd_res res) -{ - osd_draw(osd, res, osd->vo_pts, 0, ctx->formats, draw_legacy_cb, ctx); -} diff --git a/libvo/gl_osd.h b/libvo/gl_osd.h deleted file mode 100644 index cf3182ffb2..0000000000 --- a/libvo/gl_osd.h +++ /dev/null @@ -1,43 +0,0 @@ -#ifndef MPLAYER_GL_OSD_H -#define MPLAYER_GL_OSD_H - -#include <stdbool.h> -#include <inttypes.h> - -#include "gl_common.h" -#include "sub/sub.h" - -struct mpgl_osd_part { - enum sub_bitmap_format format; - int bitmap_id, bitmap_pos_id; - GLuint texture; - int w, h; - GLuint buffer; - int num_vertices; - void *vertices; - struct bitmap_packer *packer; -}; - -struct mpgl_osd { - GL *gl; - bool use_pbo; - bool scaled; - struct mpgl_osd_part *parts[MAX_OSD_PARTS]; - const struct osd_fmt_entry *fmt_table; - bool formats[SUBBITMAP_COUNT]; - void *scratch; -}; - -struct mpgl_osd *mpgl_osd_init(GL *gl, bool legacy); -void mpgl_osd_destroy(struct mpgl_osd *ctx); - -struct mpgl_osd_part *mpgl_osd_generate(struct mpgl_osd *ctx, - struct sub_bitmaps *b); - -void mpgl_osd_set_gl_state(struct mpgl_osd *ctx, struct mpgl_osd_part *p); -void mpgl_osd_unset_gl_state(struct mpgl_osd *ctx, struct mpgl_osd_part *p); - -void mpgl_osd_draw_legacy(struct mpgl_osd *ctx, struct osd_state *osd, - struct mp_osd_res res); - -#endif diff --git a/libvo/osx_common.c b/libvo/osx_common.c deleted file mode 100644 index 2aa0a28126..0000000000 --- a/libvo/osx_common.c +++ /dev/null @@ -1,145 +0,0 @@ -/* - * 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" - -// only to get keycode definitions from HIToolbox/Events.h -#include <Carbon/Carbon.h> -#include <CoreServices/CoreServices.h> -#include "config.h" -#include "osx_common.h" -#include "video_out.h" -#include "input/keycodes.h" -#include "input/input.h" -#include "mp_msg.h" - -/* - * Define keycodes only found in OSX >= 10.5 for older versions - */ -#if MAC_OS_X_VERSION_MAX_ALLOWED <= 1040 -#define kVK_ANSI_Keypad0 0x52 -#define kVK_ANSI_Keypad1 0x53 -#define kVK_ANSI_Keypad2 0x54 -#define kVK_ANSI_Keypad3 0x55 -#define kVK_ANSI_Keypad4 0x56 -#define kVK_ANSI_Keypad5 0x57 -#define kVK_ANSI_Keypad6 0x58 -#define kVK_ANSI_Keypad7 0x59 -#define kVK_ANSI_Keypad8 0x5b -#define kVK_ANSI_Keypad9 0x5c -#define kVK_ANSI_KeypadDecimal 0x41 -#define kVK_ANSI_KeypadDivide 0x4b -#define kVK_ANSI_KeypadEnter 0x4c -#define kVK_ANSI_KeypadMinus 0x4e -#define kVK_ANSI_KeypadMultiply 0x43 -#define kVK_ANSI_KeypadPlus 0x45 -#define kVK_Control 0x3b -#define kVK_Delete 0x33 -#define kVK_DownArrow 0x7d -#define kVK_End 0x77 -#define kVK_Escape 0x35 -#define kVK_F1 0x7a -#define kVK_F10 0x6d -#define kVK_F11 0x67 -#define kVK_F12 0x6f -#define kVK_F2 0x78 -#define kVK_F3 0x63 -#define kVK_F4 0x76 -#define kVK_F5 0x60 -#define kVK_F6 0x61 -#define kVK_F7 0x62 -#define kVK_F8 0x64 -#define kVK_F9 0x65 -#define kVK_ForwardDelete 0x75 -#define kVK_Help 0x72 -#define kVK_Home 0x73 -#define kVK_LeftArrow 0x7b -#define kVK_Option 0x3a -#define kVK_PageDown 0x79 -#define kVK_PageUp 0x74 -#define kVK_Return 0x24 -#define kVK_RightArrow 0x7c -#define kVK_Shift 0x38 -#define kVK_Tab 0x30 -#define kVK_UpArrow 0x7e -#endif /* MAC_OS_X_VERSION_MAX_ALLOWED <= 1040 */ - -static const struct mp_keymap keymap[] = { - // special keys - {0x34, KEY_ENTER}, // Enter key on some iBooks? - {kVK_Return, KEY_ENTER}, - {kVK_Escape, KEY_ESC}, - {kVK_Delete, KEY_BACKSPACE}, {kVK_Option, KEY_BACKSPACE}, {kVK_Control, KEY_BACKSPACE}, {kVK_Shift, KEY_BACKSPACE}, - {kVK_Tab, KEY_TAB}, - - // cursor keys - {kVK_UpArrow, KEY_UP}, {kVK_DownArrow, KEY_DOWN}, {kVK_LeftArrow, KEY_LEFT}, {kVK_RightArrow, KEY_RIGHT}, - - // navigation block - {kVK_Help, KEY_INSERT}, {kVK_ForwardDelete, KEY_DELETE}, {kVK_Home, KEY_HOME}, - {kVK_End, KEY_END}, {kVK_PageUp, KEY_PAGE_UP}, {kVK_PageDown, KEY_PAGE_DOWN}, - - // F-keys - {kVK_F1, KEY_F + 1}, {kVK_F2, KEY_F + 2}, {kVK_F3, KEY_F + 3}, {kVK_F4, KEY_F + 4}, - {kVK_F5, KEY_F + 5}, {kVK_F6, KEY_F + 6}, {kVK_F7, KEY_F + 7}, {kVK_F8, KEY_F + 8}, - {kVK_F9, KEY_F + 9}, {kVK_F10, KEY_F + 10}, {kVK_F11, KEY_F + 11}, {kVK_F12, KEY_F + 12}, - - // numpad - {kVK_ANSI_KeypadPlus, '+'}, {kVK_ANSI_KeypadMinus, '-'}, {kVK_ANSI_KeypadMultiply, '*'}, - {kVK_ANSI_KeypadDivide, '/'}, {kVK_ANSI_KeypadEnter, KEY_KPENTER}, {kVK_ANSI_KeypadDecimal, KEY_KPDEC}, - {kVK_ANSI_Keypad0, KEY_KP0}, {kVK_ANSI_Keypad1, KEY_KP1}, {kVK_ANSI_Keypad2, KEY_KP2}, {kVK_ANSI_Keypad3, KEY_KP3}, - {kVK_ANSI_Keypad4, KEY_KP4}, {kVK_ANSI_Keypad5, KEY_KP5}, {kVK_ANSI_Keypad6, KEY_KP6}, {kVK_ANSI_Keypad7, KEY_KP7}, - {kVK_ANSI_Keypad8, KEY_KP8}, {kVK_ANSI_Keypad9, KEY_KP9}, - - {0, 0} -}; - -int convert_key(unsigned key, unsigned charcode) -{ - int mpkey = lookup_keymap_table(keymap, key); - if (mpkey) - return mpkey; - return charcode; -} - -/** - * Checks at runtime that OSX version is the same or newer than the one - * provided as input. - */ -int is_osx_version_at_least(int majorv, int minorv, int bugfixv) -{ - OSErr err; - SInt32 major, minor, bugfix; - if ((err = Gestalt(gestaltSystemVersionMajor, &major)) != noErr) - goto fail; - if ((err = Gestalt(gestaltSystemVersionMinor, &minor)) != noErr) - goto fail; - if ((err = Gestalt(gestaltSystemVersionBugFix, &bugfix)) != noErr) - goto fail; - - if(major > majorv || - (major == majorv && (minor > minorv || - (minor == minorv && bugfix >= bugfixv)))) - return 1; - else - return 0; -fail: - // There's no reason the Gestalt system call should fail on OSX. - mp_msg(MSGT_VO, MSGL_FATAL, "[osx] Failed to get system version number. " - "Please contact the developers. Error code: %ld\n", (long)err); - return 0; -} diff --git a/libvo/osx_common.h b/libvo/osx_common.h deleted file mode 100644 index ae31a6353d..0000000000 --- a/libvo/osx_common.h +++ /dev/null @@ -1,27 +0,0 @@ -/* - * 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_OSX_COMMON_H -#define MPLAYER_OSX_COMMON_H - -struct vo; - -int convert_key(unsigned key, unsigned charcode); -int is_osx_version_at_least(int majorv, int minorv, int bugfixv); - -#endif /* MPLAYER_OSX_COMMON_H */ diff --git a/libvo/video_out.c b/libvo/video_out.c deleted file mode 100644 index 571f00da4d..0000000000 --- a/libvo/video_out.c +++ /dev/null @@ -1,530 +0,0 @@ -/* - * libvo common functions, variables used by many/all drivers. - * - * 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 <assert.h> -#include <stdbool.h> - -#include <unistd.h> -//#include <sys/mman.h> - -#include "config.h" -#include "options.h" -#include "talloc.h" -#include "bstr.h" -#include "video_out.h" -#include "aspect.h" -#include "geometry.h" -#include "input/input.h" -#include "mp_fifo.h" -#include "m_config.h" -#include "mp_msg.h" -#include "libmpcodecs/vfcap.h" -#include "sub/sub.h" - -#include "osdep/shmem.h" -#ifdef CONFIG_X11 -#include "x11_common.h" -#endif - -int xinerama_screen = -1; -int xinerama_x; -int xinerama_y; - -int vo_nomouse_input = 0; -int vo_grabpointer = 1; -int vo_vsync = 1; -int vo_fs = 0; -int vo_fsmode = 0; -float vo_panscan = 0.0f; -int vo_refresh_rate=0; -int vo_keepaspect=1; -int vo_rootwin=0; -int vo_border=1; -int64_t WinID = -1; - -int vo_pts=0; // for hw decoding -float vo_fps=0; - -int vo_colorkey = 0x0000ff00; // default colorkey is green - // (0xff000000 means that colorkey has been disabled) - -// -// Externally visible list of all vo drivers -// -extern struct vo_driver video_out_x11; -extern struct vo_driver video_out_vdpau; -extern struct vo_driver video_out_xv; -extern struct vo_driver video_out_opengl; -extern struct vo_driver video_out_opengl_hq; -extern struct vo_driver video_out_opengl_old; -extern struct vo_driver video_out_null; -extern struct vo_driver video_out_image; -extern struct vo_driver video_out_lavc; -extern struct vo_driver video_out_caca; -extern struct vo_driver video_out_direct3d; -extern struct vo_driver video_out_direct3d_shaders; -extern struct vo_driver video_out_corevideo; - -const struct vo_driver *video_out_drivers[] = -{ -#ifdef CONFIG_DIRECT3D - &video_out_direct3d_shaders, - &video_out_direct3d, -#endif -#ifdef CONFIG_GL_COCOA - &video_out_opengl, - &video_out_opengl_old, -#endif -#ifdef CONFIG_COREVIDEO - &video_out_corevideo, -#endif -#if CONFIG_VDPAU - &video_out_vdpau, -#endif -#ifdef CONFIG_XV - &video_out_xv, -#endif -#ifdef CONFIG_GL -#if !defined CONFIG_GL_COCOA - &video_out_opengl, - &video_out_opengl_old, -#endif -#endif -#ifdef CONFIG_X11 - &video_out_x11, -#endif -#ifdef CONFIG_CACA - &video_out_caca, -#endif - &video_out_null, - // should not be auto-selected - &video_out_image, -#ifdef CONFIG_ENCODING - &video_out_lavc, -#endif -#ifdef CONFIG_GL - &video_out_opengl_hq, -#endif - NULL -}; - - -static int vo_preinit(struct vo *vo, char *arg) -{ - if (vo->driver->priv_size) { - vo->priv = talloc_zero_size(vo, vo->driver->priv_size); - if (vo->driver->priv_defaults) - memcpy(vo->priv, vo->driver->priv_defaults, vo->driver->priv_size); - } - if (vo->driver->options) { - struct m_config *cfg = m_config_simple(vo->priv); - talloc_steal(vo->priv, cfg); - m_config_register_options(cfg, vo->driver->options); - char n[50]; - int l = snprintf(n, sizeof(n), "vo/%s", vo->driver->info->short_name); - assert(l < sizeof(n)); - int r = m_config_parse_suboptions(cfg, n, arg); - if (r < 0) - return r; - } - return vo->driver->preinit(vo, arg); -} - -int vo_control(struct vo *vo, uint32_t request, void *data) -{ - return vo->driver->control(vo, request, data); -} - -// Return -1 if driver appears not to support a draw_image interface, -// 0 otherwise (whether the driver actually drew something or not). -int vo_draw_image(struct vo *vo, struct mp_image *mpi, double pts) -{ - if (!vo->config_ok) - return 0; - if (vo->driver->buffer_frames) { - vo->driver->draw_image(vo, mpi, pts); - return 0; - } - vo->frame_loaded = true; - vo->next_pts = pts; - // Guaranteed to support at least DRAW_IMAGE later - if (vo->driver->is_new) { - vo->waiting_mpi = mpi; - return 0; - } - if (vo_control(vo, VOCTRL_DRAW_IMAGE, mpi) == VO_NOTIMPL) - return -1; - return 0; -} - -int vo_redraw_frame(struct vo *vo) -{ - if (!vo->config_ok || !vo->hasframe) - return -1; - if (vo_control(vo, VOCTRL_REDRAW_FRAME, NULL) == true) { - vo->redrawing = true; - return 0; - } - return -1; -} - -int vo_get_buffered_frame(struct vo *vo, bool eof) -{ - if (!vo->config_ok) - return -1; - if (vo->frame_loaded) - return 0; - if (!vo->driver->buffer_frames) - return -1; - vo->driver->get_buffered_frame(vo, eof); - return vo->frame_loaded ? 0 : -1; -} - -void vo_skip_frame(struct vo *vo) -{ - vo_control(vo, VOCTRL_SKIPFRAME, NULL); - vo->frame_loaded = false; -} - -int vo_draw_slice(struct vo *vo, uint8_t *src[], int stride[], int w, int h, int x, int y) -{ - return vo->driver->draw_slice(vo, src, stride, w, h, x, y); -} - -void vo_new_frame_imminent(struct vo *vo) -{ - if (!vo->driver->is_new) - return; - if (vo->driver->buffer_frames) - vo_control(vo, VOCTRL_NEWFRAME, NULL); - else { - vo_control(vo, VOCTRL_DRAW_IMAGE, vo->waiting_mpi); - vo->waiting_mpi = NULL; - } -} - -void vo_draw_osd(struct vo *vo, struct osd_state *osd) -{ - if (vo->config_ok && (vo->default_caps & VFCAP_OSD)) - vo->driver->draw_osd(vo, osd); -} - -void vo_flip_page(struct vo *vo, unsigned int pts_us, int duration) -{ - if (!vo->config_ok) - return; - if (!vo->redrawing) { - vo->frame_loaded = false; - vo->next_pts = MP_NOPTS_VALUE; - } - vo->want_redraw = false; - vo->redrawing = false; - if (vo->driver->flip_page_timed) - vo->driver->flip_page_timed(vo, pts_us, duration); - else - vo->driver->flip_page(vo); - vo->hasframe = true; -} - -void vo_check_events(struct vo *vo) -{ - if (!vo->config_ok) { - if (vo->registered_fd != -1) - mp_input_rm_key_fd(vo->input_ctx, vo->registered_fd); - vo->registered_fd = -1; - return; - } - vo->driver->check_events(vo); -} - -void vo_seek_reset(struct vo *vo) -{ - vo_control(vo, VOCTRL_RESET, NULL); - vo->frame_loaded = false; - vo->hasframe = false; -} - -void vo_destroy(struct vo *vo) -{ - if (vo->registered_fd != -1) - mp_input_rm_key_fd(vo->input_ctx, vo->registered_fd); - vo->driver->uninit(vo); - talloc_free(vo); -} - -void list_video_out(void) -{ - int i = 0; - mp_tmsg(MSGT_CPLAYER, MSGL_INFO, "Available video output drivers:\n"); - mp_msg(MSGT_IDENTIFY, MSGL_INFO, "ID_VIDEO_OUTPUTS\n"); - while (video_out_drivers[i]) { - const vo_info_t *info = video_out_drivers[i++]->info; - mp_msg(MSGT_GLOBAL, MSGL_INFO,"\t%s\t%s\n", info->short_name, info->name); - } - mp_msg(MSGT_GLOBAL, MSGL_INFO,"\n"); -} - -static void replace_legacy_vo_name(bstr *name) -{ - bstr new = *name; - if (bstr_equals0(*name, "gl")) - new = bstr0("opengl"); - if (bstr_equals0(*name, "gl3")) - new = bstr0("opengl-hq"); - if (!bstr_equals(*name, new)) { - mp_tmsg(MSGT_CPLAYER, MSGL_ERR, "VO driver '%.*s' has been replaced " - "with '%.*s'!\n", BSTR_P(*name), BSTR_P(new)); - } - *name = new; -} - -struct vo *init_best_video_out(struct MPOpts *opts, - struct mp_fifo *key_fifo, - struct input_ctx *input_ctx, - struct encode_lavc_context *encode_lavc_ctx) -{ - char **vo_list = opts->video_driver_list; - int i; - struct vo *vo = talloc_ptrtype(NULL, vo); - struct vo initial_values = { - .opts = opts, - .key_fifo = key_fifo, - .encode_lavc_ctx = encode_lavc_ctx, - .input_ctx = input_ctx, - .event_fd = -1, - .registered_fd = -1, - }; - // first try the preferred drivers, with their optional subdevice param: - if (vo_list && vo_list[0]) - while (vo_list[0][0]) { - char *arg = vo_list[0]; - bstr name = bstr0(arg); - char *params = strchr(arg, ':'); - if (params) { - name = bstr_splice(name, 0, params - arg); - params++; - } - replace_legacy_vo_name(&name); - for (i = 0; video_out_drivers[i]; i++) { - const struct vo_driver *video_driver = video_out_drivers[i]; - const vo_info_t *info = video_driver->info; - if (bstr_equals0(name, info->short_name)) { - // name matches, try it - *vo = initial_values; - vo->driver = video_driver; - if (!vo_preinit(vo, params)) - return vo; // success! - talloc_free_children(vo); - } - } - // continue... - ++vo_list; - if (!(vo_list[0])) { - talloc_free(vo); - return NULL; // do NOT fallback to others - } - } - // now try the rest... - for (i = 0; video_out_drivers[i]; i++) { - const struct vo_driver *video_driver = video_out_drivers[i]; - *vo = initial_values; - vo->driver = video_driver; - if (!vo_preinit(vo, NULL)) - return vo; // success! - talloc_free_children(vo); - } - talloc_free(vo); - return NULL; -} - -static int event_fd_callback(void *ctx, int fd) -{ - struct vo *vo = ctx; - vo_check_events(vo); - return MP_INPUT_NOTHING; -} - -int vo_config(struct vo *vo, uint32_t width, uint32_t height, - uint32_t d_width, uint32_t d_height, uint32_t flags, - uint32_t format) -{ - struct MPOpts *opts = vo->opts; - panscan_init(vo); - aspect_save_videores(vo, width, height, d_width, d_height); - - if (vo_control(vo, VOCTRL_UPDATE_SCREENINFO, NULL) == VO_TRUE) { - aspect(vo, &d_width, &d_height, A_NOZOOM); - vo->dx = (int)(opts->vo_screenwidth - d_width) / 2; - vo->dy = (int)(opts->vo_screenheight - d_height) / 2; - geometry(&vo->dx, &vo->dy, &d_width, &d_height, - opts->vo_screenwidth, opts->vo_screenheight); - geometry_xy_changed |= xinerama_screen >= 0; - vo->dx += xinerama_x; - vo->dy += xinerama_y; - vo->dwidth = d_width; - vo->dheight = d_height; - } - - vo->default_caps = vo_control(vo, VOCTRL_QUERY_FORMAT, &format); - - int ret = vo->driver->config(vo, width, height, d_width, d_height, flags, - format); - vo->config_ok = (ret == 0); - vo->config_count += vo->config_ok; - if (!vo->config_ok) - vo->default_caps = 0; - if (vo->registered_fd == -1 && vo->event_fd != -1 && vo->config_ok) { - mp_input_add_key_fd(vo->input_ctx, vo->event_fd, 1, event_fd_callback, - NULL, vo); - vo->registered_fd = vo->event_fd; - } - vo->frame_loaded = false; - vo->waiting_mpi = NULL; - vo->redrawing = false; - vo->hasframe = false; - return ret; -} - -/** - * \brief lookup an integer in a table, table must have 0 as the last key - * \param key key to search for - * \result translation corresponding to key or "to" value of last mapping - * if not found. - */ -int lookup_keymap_table(const struct mp_keymap *map, int key) { - while (map->from && map->from != key) map++; - return map->to; -} - -static void print_video_rect(struct vo *vo, struct mp_rect src, - struct mp_rect dst, struct mp_osd_res osd) -{ - int lv = MSGL_V; - - int sw = src.x1 - src.x0, sh = src.y1 - src.y0; - int dw = dst.x1 - dst.x0, dh = dst.y1 - dst.y0; - - mp_msg(MSGT_VO, lv, "[vo] Window size: %dx%d\n", - vo->dwidth, vo->dheight); - mp_msg(MSGT_VO, lv, "[vo] Video source: %dx%d (%dx%d)\n", - vo->aspdat.orgw, vo->aspdat.orgh, - vo->aspdat.prew, vo->aspdat.preh); - mp_msg(MSGT_VO, lv, "[vo] Video display: (%d, %d) %dx%d -> (%d, %d) %dx%d\n", - src.x0, src.y0, sw, sh, dst.x0, dst.y0, dw, dh); - mp_msg(MSGT_VO, lv, "[vo] Video scale: %f/%f\n", - (double)dw / sw, (double)dh / sh); - mp_msg(MSGT_VO, lv, "[vo] OSD borders: l=%d t=%d r=%d b=%d\n", - osd.ml, osd.mt, osd.mr, osd.mb); - mp_msg(MSGT_VO, lv, "[vo] Video borders: l=%d t=%d r=%d b=%d\n", - dst.x0, dst.y0, vo->dwidth - dst.x1, vo->dheight - dst.y1); -} - -static void src_dst_split_scaling(int src_size, int dst_size, - int scaled_src_size, int *src_start, - int *src_end, int *dst_start, int *dst_end) -{ - if (scaled_src_size > dst_size) { - int border = src_size * (scaled_src_size - dst_size) / scaled_src_size; - // round to a multiple of 2, this is at least needed for vo_direct3d - // and ATI cards - border = (border / 2 + 1) & ~1; - *src_start = border; - *src_end = src_size - border; - *dst_start = 0; - *dst_end = dst_size; - } else { - *src_start = 0; - *src_end = src_size; - *dst_start = (dst_size - scaled_src_size) / 2; - *dst_end = *dst_start + scaled_src_size; - } -} - -// Calculate the appropriate source and destination rectangle to -// get a correctly scaled picture, including pan-scan. -// out_src: visible part of the video -// out_dst: area of screen covered by the video source rectangle -// out_osd: OSD size, OSD margins, etc. -void vo_get_src_dst_rects(struct vo *vo, struct mp_rect *out_src, - struct mp_rect *out_dst, struct mp_osd_res *out_osd) -{ - int src_w = vo->aspdat.orgw; - int src_h = vo->aspdat.orgh; - struct mp_rect dst = {0, 0, vo->dwidth, vo->dheight}; - struct mp_rect src = {0, 0, src_w, src_h}; - struct mp_osd_res osd = { - .w = vo->dwidth, - .h = vo->dheight, - .display_par = vo->monitor_par, - .video_par = vo->aspdat.par, - }; - if (aspect_scaling()) { - int scaled_width = 0, scaled_height = 0; - aspect(vo, &scaled_width, &scaled_height, A_WINZOOM); - panscan_calc_windowed(vo); - scaled_width += vo->panscan_x; - scaled_height += vo->panscan_y; - int border_w = vo->dwidth - scaled_width; - int border_h = vo->dheight - scaled_height; - osd.ml = border_w / 2; - osd.mt = border_h / 2; - osd.mr = border_w - osd.ml; - osd.mb = border_h - osd.mt; - src_dst_split_scaling(src_w, vo->dwidth, scaled_width, - &src.x0, &src.x1, &dst.x0, &dst.x1); - src_dst_split_scaling(src_h, vo->dheight, scaled_height, - &src.y0, &src.y1, &dst.y0, &dst.y1); - } - - *out_src = src; - *out_dst = dst; - *out_osd = osd; - - print_video_rect(vo, src, dst, osd); -} - -// Return the window title the VO should set. Always returns a null terminated -// string. The string is valid until frontend code is invoked again. Copy it if -// you need to keep the string for an extended period of time. -const char *vo_get_window_title(struct vo *vo) -{ - if (!vo->window_title) - vo->window_title = talloc_strdup(vo, ""); - return vo->window_title; -} - -/** - * Generates a mouse movement message if those are enable and sends it - * to the "main" MPlayer. - * - * \param posx new x position of mouse - * \param posy new y position of mouse - */ -void vo_mouse_movement(struct vo *vo, int posx, int posy) -{ - char cmd_str[40]; - if (!enable_mouse_movements) - return; - snprintf(cmd_str, sizeof(cmd_str), "set_mouse_pos %i %i", posx, posy); - mp_input_queue_cmd(vo->input_ctx, mp_input_parse_cmd(bstr0(cmd_str), "")); -} diff --git a/libvo/video_out.h b/libvo/video_out.h deleted file mode 100644 index ac2ded9b3c..0000000000 --- a/libvo/video_out.h +++ /dev/null @@ -1,352 +0,0 @@ -/* - * Copyright (C) Aaron Holtzman - Aug 1999 - * Strongly modified, most parts rewritten: A'rpi/ESP-team - 2000-2001 - * (C) MPlayer developers - * - * 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_VIDEO_OUT_H -#define MPLAYER_VIDEO_OUT_H - -#include <inttypes.h> -#include <stdbool.h> - -#include "libmpcodecs/img_format.h" -#include "mpcommon.h" - -#define VO_EVENT_EXPOSE 1 -#define VO_EVENT_RESIZE 2 -#define VO_EVENT_KEYPRESS 4 -#define VO_EVENT_REINIT 8 -#define VO_EVENT_MOVE 16 - -enum mp_voctrl { - /* does the device support the required format */ - VOCTRL_QUERY_FORMAT = 1, - /* signal a device reset seek */ - VOCTRL_RESET, - /* used to switch to fullscreen */ - VOCTRL_FULLSCREEN, - /* signal a device pause */ - VOCTRL_PAUSE, - /* start/resume playback */ - VOCTRL_RESUME, - /* libmpcodecs direct rendering */ - VOCTRL_GET_IMAGE, - VOCTRL_DRAW_IMAGE, - VOCTRL_GET_PANSCAN, - VOCTRL_SET_PANSCAN, - VOCTRL_SET_EQUALIZER, // struct voctrl_set_equalizer_args - VOCTRL_GET_EQUALIZER, // struct voctrl_get_equalizer_args - VOCTRL_DUPLICATE_FRAME, - - VOCTRL_START_SLICE, - - VOCTRL_NEWFRAME, - VOCTRL_SKIPFRAME, - VOCTRL_REDRAW_FRAME, - - VOCTRL_ONTOP, - VOCTRL_ROOTWIN, - VOCTRL_BORDER, - - VOCTRL_SET_DEINTERLACE, - VOCTRL_GET_DEINTERLACE, - - VOCTRL_UPDATE_SCREENINFO, - - VOCTRL_SET_YUV_COLORSPACE, // struct mp_csp_details - VOCTRL_GET_YUV_COLORSPACE, // struct mp_csp_details - - VOCTRL_SCREENSHOT, // struct voctrl_screenshot_args - - VOCTRL_SET_COMMAND_LINE, // char* -}; - -// VOCTRL_SET_EQUALIZER -struct voctrl_set_equalizer_args { - const char *name; - int value; -}; - -// VOCTRL_GET_EQUALIZER -struct voctrl_get_equalizer_args { - const char *name; - int *valueptr; -}; - -// VOCTRL_SCREENSHOT -struct voctrl_screenshot_args { - // 0: Save image of the currently displayed video frame, in original - // resolution. - // 1: Save full screenshot of the window. Should contain OSD, EOSD, and the - // scaled video. - // The value of this variable can be ignored if only a single method is - // implemented. - int full_window; - // Will be set to a newly allocated image, that contains the screenshot. - // The caller has to free the pointer with free_mp_image(). - // It is not specified whether the image data is a copy or references the - // image data directly. - // Is never NULL. (Failure has to be indicated by returning VO_FALSE.) - struct mp_image *out_image; - // Whether the VO rendered OSD/subtitles into out_image - bool has_osd; -}; - -typedef struct { - int x,y; - int w,h; -} mp_win_t; - -#define VO_TRUE 1 -#define VO_FALSE 0 -#define VO_ERROR -1 -#define VO_NOTAVAIL -2 -#define VO_NOTIMPL -3 - -#define VOFLAG_FULLSCREEN 0x01 -#define VOFLAG_MODESWITCHING 0x02 -#define VOFLAG_SWSCALE 0x04 -#define VOFLAG_FLIPPING 0x08 -#define VOFLAG_HIDDEN 0x10 //< Use to create a hidden window -#define VOFLAG_STEREO 0x20 //< Use to create a stereo-capable window -#define VOFLAG_GL_DEBUG 0x40 // Hint to request debug OpenGL context - -typedef struct vo_info_s -{ - /* driver name ("Matrox Millennium G200/G400" */ - const char *name; - /* short name (for config strings) ("vdpau") */ - const char *short_name; - /* author ("Aaron Holtzman <aholtzma@ess.engr.uvic.ca>") */ - const char *author; - /* any additional comments */ - const char *comment; -} vo_info_t; - -struct vo; -struct osd_state; -struct mp_image; - -struct vo_driver { - // Driver uses new API - bool is_new; - // Driver buffers or adds (deinterlace) frames and will keep track - // of pts values itself - bool buffer_frames; - - const vo_info_t *info; - /* - * Preinitializes driver (real INITIALIZATION) - * arg - currently it's vo_subdevice - * returns: zero on successful initialization, non-zero on error. - */ - int (*preinit)(struct vo *vo, const char *arg); - /* - * Initialize (means CONFIGURE) the display driver. - * params: - * width,height: image source size - * d_width,d_height: size of the requested window size, just a hint - * fullscreen: flag, 0=windowd 1=fullscreen, just a hint - * title: window title, if available - * format: fourcc of pixel format - * returns : zero on successful initialization, non-zero on error. - */ - int (*config)(struct vo *vo, uint32_t width, uint32_t height, - uint32_t d_width, uint32_t d_height, uint32_t fullscreen, - uint32_t format); - - /* - * Control interface - */ - int (*control)(struct vo *vo, uint32_t request, void *data); - - void (*draw_image)(struct vo *vo, struct mp_image *mpi, double pts); - - /* - * Get extra frames from the VO, such as those added by VDPAU - * deinterlace. Preparing the next such frame if any could be done - * automatically by the VO after a previous flip_page(), but having - * it as a separate step seems to allow making code more robust. - */ - void (*get_buffered_frame)(struct vo *vo, bool eof); - - /* - * Draw a planar YUV slice to the buffer: - * params: - * src[3] = source image planes (Y,U,V) - * stride[3] = source image planes line widths (in bytes) - * w,h = width*height of area to be copied (in Y pixels) - * x,y = position at the destination image (in Y pixels) - */ - int (*draw_slice)(struct vo *vo, uint8_t *src[], int stride[], int w, - int h, int x, int y); - - /* - * Draws OSD to the screen buffer - */ - void (*draw_osd)(struct vo *vo, struct osd_state *osd); - - /* - * Blit/Flip buffer to the screen. Must be called after each frame! - */ - void (*flip_page)(struct vo *vo); - void (*flip_page_timed)(struct vo *vo, unsigned int pts_us, int duration); - - /* - * This func is called after every frames to handle keyboard and - * other events. It's called in PAUSE mode too! - */ - void (*check_events)(struct vo *vo); - - /* - * Closes driver. Should restore the original state of the system. - */ - void (*uninit)(struct vo *vo); - - // Size of private struct for automatic allocation (0 doesn't allocate) - int priv_size; - - // If not NULL, it's copied into the newly allocated private struct. - const void *priv_defaults; - - // List of options to parse into priv struct (requires privsize to be set) - const struct m_option *options; -}; - -struct vo { - int config_ok; // Last config call was successful? - int config_count; // Total number of successful config calls - int default_caps; // query_format() result for configured video format - - bool frame_loaded; // Is there a next frame the VO could flip to? - struct mp_image *waiting_mpi; - double next_pts; // pts value of the next frame if any - double next_pts2; // optional pts of frame after that - bool want_redraw; // visible frame wrong (window resize), needs refresh - bool redrawing; // between redrawing frame and flipping it - bool hasframe; // >= 1 frame has been drawn, so redraw is possible - - double flip_queue_offset; // queue flip events at most this much in advance - - const struct vo_driver *driver; - void *priv; - struct MPOpts *opts; - struct vo_x11_state *x11; - struct vo_w32_state *w32; - struct vo_cocoa_state *cocoa; - struct mp_fifo *key_fifo; - struct encode_lavc_context *encode_lavc_ctx; - struct input_ctx *input_ctx; - int event_fd; // check_events() should be called when this has input - int registered_fd; // set to event_fd when registered in input system - - // requested position/resolution (usually window position/window size) - int dx; - int dy; - int dwidth; - int dheight; - - int panscan_x; - int panscan_y; - float panscan_amount; - float monitor_par; - struct aspect_data { - int orgw; // real width - int orgh; // real height - int prew; // prescaled width - int preh; // prescaled height - float par; // pixel aspect ratio out of orgw/orgh and prew/preh - int scrw; // horizontal resolution - int scrh; // vertical resolution - float asp; - } aspdat; - - char *window_title; -}; - -struct vo *init_best_video_out(struct MPOpts *opts, - struct mp_fifo *key_fifo, - struct input_ctx *input_ctx, - struct encode_lavc_context *encode_lavc_ctx); -int vo_config(struct vo *vo, uint32_t width, uint32_t height, - uint32_t d_width, uint32_t d_height, uint32_t flags, - uint32_t format); -void list_video_out(void); - -int vo_control(struct vo *vo, uint32_t request, void *data); -int vo_draw_image(struct vo *vo, struct mp_image *mpi, double pts); -int vo_redraw_frame(struct vo *vo); -int vo_get_buffered_frame(struct vo *vo, bool eof); -void vo_skip_frame(struct vo *vo); -int vo_draw_slice(struct vo *vo, uint8_t *src[], int stride[], int w, int h, int x, int y); -void vo_new_frame_imminent(struct vo *vo); -void vo_draw_osd(struct vo *vo, struct osd_state *osd); -void vo_flip_page(struct vo *vo, unsigned int pts_us, int duration); -void vo_check_events(struct vo *vo); -void vo_seek_reset(struct vo *vo); -void vo_destroy(struct vo *vo); - -const char *vo_get_window_title(struct vo *vo); - -// NULL terminated array of all drivers -extern const struct vo_driver *video_out_drivers[]; - -extern int xinerama_screen; -extern int xinerama_x; -extern int xinerama_y; - -extern int vo_grabpointer; -extern int vo_vsync; -extern int vo_fs; -extern int vo_fsmode; -extern float vo_panscan; -extern int vo_refresh_rate; -extern int vo_keepaspect; -extern int vo_rootwin; -extern int vo_border; - -extern int vo_nomouse_input; -extern int enable_mouse_movements; - -extern int vo_pts; -extern float vo_fps; - -extern int vo_colorkey; - -extern int64_t WinID; - -struct mp_keymap { - int from; - int to; -}; -int lookup_keymap_table(const struct mp_keymap *map, int key); - -void vo_mouse_movement(struct vo *vo, int posx, int posy); - -struct mp_osd_res; -void vo_get_src_dst_rects(struct vo *vo, struct mp_rect *out_src, - struct mp_rect *out_dst, struct mp_osd_res *out_osd); - -static inline int aspect_scaling(void) -{ - return vo_keepaspect || vo_fs; -} - -#endif /* MPLAYER_VIDEO_OUT_H */ diff --git a/libvo/vo_caca.c b/libvo/vo_caca.c deleted file mode 100644 index 2d998bf91d..0000000000 --- a/libvo/vo_caca.c +++ /dev/null @@ -1,395 +0,0 @@ -/* - * video output driver for libcaca - * - * by Pigeon <pigeon@pigeond.net> - * - * Some functions/codes/ideas are from x11 and aalib vo - * - * TODO: support draw_alpha? - * - * 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 <sys/stat.h> -#include <unistd.h> -#include <string.h> -#include <time.h> -#include <errno.h> -#include <assert.h> -#include <caca.h> - -#include "config.h" -#include "video_out.h" -#include "sub/sub.h" -#include "libmpcodecs/mp_image.h" -#include "libmpcodecs/vfcap.h" - -#include "input/keycodes.h" -#include "input/input.h" -#include "mp_msg.h" -#include "mp_fifo.h" - -/* caca stuff */ -static caca_canvas_t *canvas; -static caca_display_t *display; -static caca_dither_t *dither = NULL; -static const char *dither_antialias = "default"; -static const char *dither_charset = "default"; -static const char *dither_color = "default"; -static const char *dither_algo = "none"; - -/* image infos */ -static int image_format; -static int image_width; -static int image_height; - -static int screen_w, screen_h; - -/* We want 24bpp always for now */ -static unsigned int bpp = 24; -static unsigned int depth = 3; -static unsigned int rmask = 0xff0000; -static unsigned int gmask = 0x00ff00; -static unsigned int bmask = 0x0000ff; -static unsigned int amask = 0; - -#define MESSAGE_SIZE 512 -#define MESSAGE_DURATION 5 - -static time_t stoposd = 0; -static int showosdmessage = 0; -static char osdmessagetext[MESSAGE_SIZE]; -static char posbar[MESSAGE_SIZE]; - -static int osdx = 0, osdy = 0; -static int posbary = 2; - -static void osdmessage(int duration, const char *fmt, ...) -{ - /* for outputting a centered string at the window bottom for a while */ - va_list ar; - char m[MESSAGE_SIZE]; - - va_start(ar, fmt); - vsprintf(m, fmt, ar); - va_end(ar); - strcpy(osdmessagetext, m); - - showosdmessage = 1; - stoposd = time(NULL) + duration; - osdx = (screen_w - strlen(osdmessagetext)) / 2; - posbar[0] = '\0'; -} - -static void osdpercent(int duration, int min, int max, int val, - const char *desc, const char *unit) -{ - /* prints a bar for setting values */ - float step; - int where, i; - - step = (float)screen_w / (float)(max - min); - where = (val - min) * step; - osdmessage(duration, "%s: %i%s", desc, val, unit); - posbar[0] = '|'; - posbar[screen_w - 1] = '|'; - - for (i = 0; i < screen_w; i++) { - if (i == where) - posbar[i] = '#'; - else - posbar[i] = '-'; - } - - if (where != 0) - posbar[0] = '|'; - - if (where != (screen_w - 1)) - posbar[screen_w - 1] = '|'; - - posbar[screen_w] = '\0'; -} - -static int resize(void) -{ - screen_w = caca_get_canvas_width(canvas); - screen_h = caca_get_canvas_height(canvas); - - caca_free_dither(dither); - - dither = caca_create_dither(bpp, image_width, image_height, - depth * image_width, - rmask, gmask, bmask, amask); - if (dither == NULL) { - mp_msg(MSGT_VO, MSGL_FATAL, "vo_caca: caca_create_dither failed!\n"); - return ENOSYS; - } - - /* Default libcaca features */ - caca_set_dither_antialias(dither, dither_antialias); - caca_set_dither_charset(dither, dither_charset); - caca_set_dither_color(dither, dither_color); - caca_set_dither_algorithm(dither, dither_algo); - - return 0; -} - -static int config(struct vo *vo, uint32_t width, uint32_t height, - uint32_t d_width, uint32_t d_height, uint32_t flags, - uint32_t format) -{ - image_height = height; - image_width = width; - image_format = format; - - showosdmessage = 0; - posbar[0] = '\0'; - - return resize(); -} - -static uint32_t draw_image(struct vo *vo, mp_image_t *mpi) -{ - assert(mpi->stride[0] == image_width * 3); - caca_dither_bitmap(canvas, 0, 0, screen_w, screen_h, dither, - mpi->planes[0]); - return true; -} - -static int draw_slice(struct vo *vo, uint8_t *src[], int stride[], int w, int h, - int x, int y) -{ - return 0; -} - -static void flip_page(struct vo *vo) -{ - if (showosdmessage) { - if (time(NULL) >= stoposd) { - showosdmessage = 0; - if (*posbar) - posbar[0] = '\0'; - } else { - caca_put_str(canvas, osdx, osdy, osdmessagetext); - if (*posbar) - caca_put_str(canvas, 0, posbary, posbar); - } - } - - caca_refresh_display(display); -} - -static void set_next_str(const char * const *list, const char **str, - const char **msg) -{ - int ind; - for (ind = 0; list[ind]; ind += 2) { - if (strcmp(list[ind], *str) == 0) { - if (list[ind + 2] == NULL) - ind = -2; - *str = list[ind + 2]; - *msg = list[ind + 3]; - return; - } - } - - *str = list[0]; - *msg = list[1]; -} - -static const struct mp_keymap keysym_map[] = { - {CACA_KEY_RETURN, KEY_ENTER}, {CACA_KEY_ESCAPE, KEY_ESC}, - {CACA_KEY_UP, KEY_DOWN}, {CACA_KEY_DOWN, KEY_DOWN}, - {CACA_KEY_LEFT, KEY_LEFT}, {CACA_KEY_RIGHT, KEY_RIGHT}, - {CACA_KEY_PAGEUP, KEY_PAGE_UP}, {CACA_KEY_PAGEDOWN, KEY_PAGE_DOWN}, - {CACA_KEY_HOME, KEY_HOME}, {CACA_KEY_END, KEY_END}, - {CACA_KEY_INSERT, KEY_INSERT}, {CACA_KEY_DELETE, KEY_DELETE}, - {CACA_KEY_BACKSPACE, KEY_BACKSPACE}, {CACA_KEY_TAB, KEY_TAB}, - {CACA_KEY_PAUSE, KEY_PAUSE}, - {CACA_KEY_F1, KEY_F+1}, {CACA_KEY_F2, KEY_F+2}, - {CACA_KEY_F3, KEY_F+3}, {CACA_KEY_F4, KEY_F+4}, - {CACA_KEY_F5, KEY_F+5}, {CACA_KEY_F6, KEY_F+6}, - {CACA_KEY_F7, KEY_F+7}, {CACA_KEY_F8, KEY_F+8}, - {CACA_KEY_F9, KEY_F+9}, {CACA_KEY_F10, KEY_F+10}, - {CACA_KEY_F11, KEY_F+11}, {CACA_KEY_F12, KEY_F+12}, - {CACA_KEY_F13, KEY_F+13}, {CACA_KEY_F14, KEY_F+14}, - {CACA_KEY_F15, KEY_F+15}, - {0, 0} -}; - -static void check_events(struct vo *vo) -{ - caca_event_t cev; - while (caca_get_event(display, CACA_EVENT_ANY, &cev, 0)) { - - switch (cev.type) { - case CACA_EVENT_RESIZE: - caca_refresh_display(display); - resize(); - break; - case CACA_EVENT_QUIT: - mplayer_put_key(vo->key_fifo, KEY_CLOSE_WIN); - break; - case CACA_EVENT_MOUSE_MOTION: - vo_mouse_movement(vo, cev.data.mouse.x, cev.data.mouse.y); - break; - case CACA_EVENT_MOUSE_PRESS: - if (!vo_nomouse_input) - mplayer_put_key(vo->key_fifo, - (MOUSE_BTN0 + cev.data.mouse.button - 1) | MP_KEY_DOWN); - break; - case CACA_EVENT_MOUSE_RELEASE: - if (!vo_nomouse_input) - mplayer_put_key(vo->key_fifo, - MOUSE_BTN0 + cev.data.mouse.button - 1); - break; - case CACA_EVENT_KEY_PRESS: - { - int key = cev.data.key.ch; - int mpkey = lookup_keymap_table(keysym_map, key); - const char *msg_name; - - if (mpkey) - mplayer_put_key(vo->key_fifo, mpkey); - else - switch (key) { - case 'd': - case 'D': - /* Toggle dithering algorithm */ - set_next_str(caca_get_dither_algorithm_list(dither), - &dither_algo, &msg_name); - caca_set_dither_algorithm(dither, dither_algo); - osdmessage(MESSAGE_DURATION, "Using %s", msg_name); - break; - - case 'a': - case 'A': - /* Toggle antialiasing method */ - set_next_str(caca_get_dither_antialias_list(dither), - &dither_antialias, &msg_name); - caca_set_dither_antialias(dither, dither_antialias); - osdmessage(MESSAGE_DURATION, "Using %s", msg_name); - break; - - case 'h': - case 'H': - /* Toggle charset method */ - set_next_str(caca_get_dither_charset_list(dither), - &dither_charset, &msg_name); - caca_set_dither_charset(dither, dither_charset); - osdmessage(MESSAGE_DURATION, "Using %s", msg_name); - break; - - case 'c': - case 'C': - /* Toggle color method */ - set_next_str(caca_get_dither_color_list(dither), - &dither_color, &msg_name); - caca_set_dither_color(dither, dither_color); - osdmessage(MESSAGE_DURATION, "Using %s", msg_name); - break; - - default: - if (key <= 255) - mplayer_put_key(vo->key_fifo, key); - break; - } - } - } - } -} - -static void uninit(struct vo *vo) -{ - caca_free_dither(dither); - dither = NULL; - caca_free_display(display); - caca_free_canvas(canvas); -} - -static void draw_osd(struct vo *vo, struct osd_state *osd) -{ - if (osd->progbar_type != -1) - osdpercent(MESSAGE_DURATION, 0, 255, osd->progbar_value, - sub_osd_names[osd->progbar_type], ""); -} - -static int preinit(struct vo *vo, const char *arg) -{ - if (arg) { - mp_msg(MSGT_VO, MSGL_ERR, "vo_caca: Unknown subdevice: %s\n", arg); - return ENOSYS; - } - - canvas = caca_create_canvas(0, 0); - if (canvas == NULL) { - mp_msg(MSGT_VO, MSGL_ERR, "vo_caca: failed to create canvas\n"); - return ENOSYS; - } - - display = caca_create_display(canvas); - - if (display == NULL) { - mp_msg(MSGT_VO, MSGL_ERR, "vo_caca: failed to create display\n"); - caca_free_canvas(canvas); - return ENOSYS; - } - - caca_set_display_title(display, "mpv"); - - return 0; -} - -static int query_format(uint32_t format) -{ - if (format == IMGFMT_BGR24) - return VFCAP_OSD | VFCAP_CSP_SUPPORTED; - - return 0; -} - -static int control(struct vo *vo, uint32_t request, void *data) -{ - switch (request) { - case VOCTRL_QUERY_FORMAT: - return query_format(*((uint32_t *)data)); - case VOCTRL_DRAW_IMAGE: - return draw_image(vo, data); - default: - return VO_NOTIMPL; - } -} - -const struct vo_driver video_out_caca = { - .is_new = false, - .info = &(const vo_info_t) { - "libcaca", - "caca", - "Pigeon <pigeon@pigeond.net>", - "" - }, - .preinit = preinit, - .config = config, - .control = control, - .draw_slice = draw_slice, - .draw_osd = draw_osd, - .flip_page = flip_page, - .check_events = check_events, - .uninit = uninit, -}; diff --git a/libvo/vo_corevideo.h b/libvo/vo_corevideo.h deleted file mode 100644 index cfb86621bc..0000000000 --- a/libvo/vo_corevideo.h +++ /dev/null @@ -1,28 +0,0 @@ -/* - * CoreVideo video output driver - * - * Copyright (c) 2005 Nicolas Plourde <nicolasplourde@gmail.com> - * - * 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_VO_COREVIDEO_H -#define MPLAYER_VO_COREVIDEO_H - -#import <QuartzCore/QuartzCore.h> - -#endif /* MPLAYER_VO_COREVIDEO_H */ diff --git a/libvo/vo_corevideo.m b/libvo/vo_corevideo.m deleted file mode 100644 index 5116ab653c..0000000000 --- a/libvo/vo_corevideo.m +++ /dev/null @@ -1,457 +0,0 @@ -/* - * CoreVideo video output driver - * Copyright (c) 2005 Nicolas Plourde <nicolasplourde@gmail.com> - * - * 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 <assert.h> - -#import "vo_corevideo.h" - -// mplayer includes -#import "fastmemcpy.h" -#import "talloc.h" -#import "video_out.h" -#import "aspect.h" -#import "sub/sub.h" -#import "subopt-helper.h" - -#import "csputils.h" -#import "libmpcodecs/vfcap.h" -#import "libmpcodecs/mp_image.h" - -#import "gl_common.h" -#import "gl_osd.h" -#import "cocoa_common.h" - -struct quad { - GLfloat lowerLeft[2]; - GLfloat lowerRight[2]; - GLfloat upperRight[2]; - GLfloat upperLeft[2]; -}; - -struct priv { - MPGLContext *mpglctx; - OSType pixelFormat; - unsigned int image_width; - unsigned int image_height; - struct mp_csp_details colorspace; - int ass_border_x, ass_border_y; - - CVPixelBufferRef pixelBuffer; - CVOpenGLTextureCacheRef textureCache; - CVOpenGLTextureRef texture; - struct quad *quad; - - struct mpgl_osd *osd; -}; - -static void resize(struct vo *vo, int width, int height) -{ - struct priv *p = vo->priv; - GL *gl = p->mpglctx->gl; - - gl->Viewport(0, 0, width, height); - gl->MatrixMode(GL_PROJECTION); - gl->LoadIdentity(); - p->ass_border_x = p->ass_border_y = 0; - if (aspect_scaling()) { - int new_w, new_h; - GLdouble scale_x, scale_y; - - aspect(vo, &new_w, &new_h, A_WINZOOM); - panscan_calc_windowed(vo); - new_w += vo->panscan_x; - new_h += vo->panscan_y; - scale_x = (GLdouble)new_w / (GLdouble)width; - scale_y = (GLdouble)new_h / (GLdouble)height; - gl->Scaled(scale_x, scale_y, 1); - p->ass_border_x = (vo->dwidth - new_w) / 2; - p->ass_border_y = (vo->dheight - new_h) / 2; - } - - gl->Ortho(0, p->image_width, p->image_height, 0, -1.0, 1.0); - gl->MatrixMode(GL_MODELVIEW); - gl->LoadIdentity(); - - gl->Clear(GL_COLOR_BUFFER_BIT); - vo->want_redraw = true; -} - -static int init_gl(struct vo *vo, uint32_t d_width, uint32_t d_height) -{ - struct priv *p = vo->priv; - GL *gl = p->mpglctx->gl; - - const char *vendor = gl->GetString(GL_VENDOR); - const char *version = gl->GetString(GL_VERSION); - const char *renderer = gl->GetString(GL_RENDERER); - - mp_msg(MSGT_VO, MSGL_V, "[vo_corevideo] Running on OpenGL '%s' by '%s'," - " version '%s'\n", renderer, vendor, version); - - gl->Disable(GL_BLEND); - gl->Disable(GL_DEPTH_TEST); - gl->DepthMask(GL_FALSE); - gl->Disable(GL_CULL_FACE); - gl->Enable(GL_TEXTURE_2D); - gl->DrawBuffer(GL_BACK); - gl->TexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); - - if (!p->osd) - p->osd = mpgl_osd_init(gl, true); - - resize(vo, d_width, d_height); - - gl->ClearColor(0.0f, 0.0f, 0.0f, 0.0f); - gl->Clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - if (gl->SwapInterval) - gl->SwapInterval(1); - return 1; -} - -static void release_cv_entities(struct vo *vo) { - struct priv *p = vo->priv; - CVPixelBufferRelease(p->pixelBuffer); - p->pixelBuffer = NULL; - CVOpenGLTextureRelease(p->texture); - p->texture = NULL; - CVOpenGLTextureCacheRelease(p->textureCache); - p->textureCache = NULL; -} - -static int config(struct vo *vo, uint32_t width, uint32_t height, - uint32_t d_width, uint32_t d_height, uint32_t flags, - uint32_t format) -{ - struct priv *p = vo->priv; - release_cv_entities(vo); - p->image_width = width; - p->image_height = height; - - int mpgl_caps = MPGL_CAP_GL_LEGACY; - if (!mpgl_create_window(p->mpglctx, mpgl_caps, d_width, d_height, flags)) - return -1; - - init_gl(vo, vo->dwidth, vo->dheight); - - return 0; -} - -static void check_events(struct vo *vo) -{ - struct priv *p = vo->priv; - int e = p->mpglctx->check_events(vo); - if (e & VO_EVENT_RESIZE) - resize(vo, vo->dwidth, vo->dheight); -} - -static void prepare_texture(struct vo *vo) -{ - struct priv *p = vo->priv; - struct quad *q = p->quad; - CVReturn error; - - CVOpenGLTextureRelease(p->texture); - error = CVOpenGLTextureCacheCreateTextureFromImage(NULL, - p->textureCache, p->pixelBuffer, 0, &p->texture); - if(error != kCVReturnSuccess) - mp_msg(MSGT_VO, MSGL_ERR,"[vo_corevideo] Failed to create OpenGL" - " texture(%d)\n", error); - - CVOpenGLTextureGetCleanTexCoords(p->texture, q->lowerLeft, q->lowerRight, - q->upperRight, q->upperLeft); -} - -static void do_render(struct vo *vo) -{ - struct priv *p = vo->priv; - struct quad *q = p->quad; - GL *gl = p->mpglctx->gl; - prepare_texture(vo); - - float x0 = 0; - float y0 = 0; - float w = p->image_width; - float h = p->image_height; - - // vertically flips the image - y0 += h; - h = -h; - - float xm = x0 + w; - float ym = y0 + h; - - gl->Enable(CVOpenGLTextureGetTarget(p->texture)); - gl->BindTexture( - CVOpenGLTextureGetTarget(p->texture), - CVOpenGLTextureGetName(p->texture)); - - gl->Begin(GL_QUADS); - gl->TexCoord2fv(q->lowerLeft); gl->Vertex2f(x0, y0); - gl->TexCoord2fv(q->upperLeft); gl->Vertex2f(x0, ym); - gl->TexCoord2fv(q->upperRight); gl->Vertex2f(xm, ym); - gl->TexCoord2fv(q->lowerRight); gl->Vertex2f(xm, y0); - gl->End(); - - gl->Disable(CVOpenGLTextureGetTarget(p->texture)); -} - -static void flip_page(struct vo *vo) -{ - struct priv *p = vo->priv; - p->mpglctx->swapGlBuffers(p->mpglctx); - p->mpglctx->gl->Clear(GL_COLOR_BUFFER_BIT); -} - -static uint32_t draw_image(struct vo *vo, mp_image_t *mpi) -{ - struct priv *p = vo->priv; - CVReturn error; - - if (!p->textureCache || !p->pixelBuffer) { - error = CVOpenGLTextureCacheCreate(NULL, 0, vo_cocoa_cgl_context(vo), - vo_cocoa_cgl_pixel_format(vo), 0, &p->textureCache); - if(error != kCVReturnSuccess) - mp_msg(MSGT_VO, MSGL_ERR,"[vo_corevideo] Failed to create OpenGL" - " texture Cache(%d)\n", error); - - error = CVPixelBufferCreateWithBytes(NULL, mpi->width, mpi->height, - p->pixelFormat, mpi->planes[0], mpi->width * mpi->bpp / 8, - NULL, NULL, NULL, &p->pixelBuffer); - if(error != kCVReturnSuccess) - mp_msg(MSGT_VO, MSGL_ERR,"[vo_corevideo] Failed to create Pixel" - "Buffer(%d)\n", error); - } - - do_render(vo); - return VO_TRUE; -} - -static int query_format(struct vo *vo, uint32_t format) -{ - struct priv *p = vo->priv; - const int flags = VFCAP_CSP_SUPPORTED | VFCAP_CSP_SUPPORTED_BY_HW | - VFCAP_OSD | VFCAP_HWSCALE_UP | VFCAP_HWSCALE_DOWN | - VOCAP_NOSLICES; - switch (format) { - case IMGFMT_YUY2: - p->pixelFormat = kYUVSPixelFormat; - return flags; - - case IMGFMT_RGB24: - p->pixelFormat = k24RGBPixelFormat; - return flags; - - case IMGFMT_ARGB: - p->pixelFormat = k32ARGBPixelFormat; - return flags; - - case IMGFMT_BGRA: - p->pixelFormat = k32BGRAPixelFormat; - return flags; - } - return 0; -} - -static void uninit(struct vo *vo) -{ - struct priv *p = vo->priv; - if (p->osd) - mpgl_osd_destroy(p->osd); - release_cv_entities(vo); - mpgl_uninit(p->mpglctx); -} - - -static int preinit(struct vo *vo, const char *arg) -{ - struct priv *p = vo->priv; - - *p = (struct priv) { - .mpglctx = mpgl_init(GLTYPE_COCOA, vo), - .colorspace = MP_CSP_DETAILS_DEFAULTS, - .quad = talloc_ptrtype(p, p->quad), - }; - - return 0; -} - -static void draw_osd(struct vo *vo, struct osd_state *osd) -{ - struct priv *p = vo->priv; - GL *gl = p->mpglctx->gl; - assert(p->osd); - - gl->MatrixMode(GL_PROJECTION); - gl->PushMatrix(); - gl->LoadIdentity(); - gl->Ortho(0, vo->dwidth, vo->dheight, 0, -1, 1); - - struct mp_osd_res res = { - .w = vo->dwidth, - .h = vo->dheight, - .display_par = vo->monitor_par, - .video_par = vo->aspdat.par, - }; - - if (aspect_scaling()) { - res.ml = res.mr = p->ass_border_x; - res.mt = res.mb = p->ass_border_y; - } - - mpgl_osd_draw_legacy(p->osd, osd, res); - - gl->PopMatrix(); -} - -static CFStringRef get_cv_csp_matrix(struct vo *vo) -{ - struct priv *p = vo->priv; - switch (p->colorspace.format) { - case MP_CSP_BT_601: - return kCVImageBufferYCbCrMatrix_ITU_R_601_4; - case MP_CSP_BT_709: - return kCVImageBufferYCbCrMatrix_ITU_R_709_2; - case MP_CSP_SMPTE_240M: - return kCVImageBufferYCbCrMatrix_SMPTE_240M_1995; - } - return kCVImageBufferYCbCrMatrix_ITU_R_601_4; -} - -static void set_yuv_colorspace(struct vo *vo) -{ - struct priv *p = vo->priv; - CVBufferSetAttachment(p->pixelBuffer, - kCVImageBufferYCbCrMatrixKey, get_cv_csp_matrix(vo), - kCVAttachmentMode_ShouldPropagate); - vo->want_redraw = true; -} - -static int get_image_fmt(struct vo *vo) -{ - struct priv *p = vo->priv; - switch (p->pixelFormat) { - case kYUVSPixelFormat: return IMGFMT_YUY2; - case k24RGBPixelFormat: return IMGFMT_RGB24; - case k32ARGBPixelFormat: return IMGFMT_ARGB; - case k32BGRAPixelFormat: return IMGFMT_BGRA; - } - mp_msg(MSGT_VO, MSGL_ERR, "[vo_corevideo] Failed to convert pixel format. " - "Please contact the developers. PixelFormat: %d\n", p->pixelFormat); - return -1; -} - -static mp_image_t *get_screenshot(struct vo *vo) -{ - int img_fmt = get_image_fmt(vo); - if (img_fmt < 0) return NULL; - - struct priv *p = vo->priv; - void *base = CVPixelBufferGetBaseAddress(p->pixelBuffer); - - size_t width = CVPixelBufferGetWidth(p->pixelBuffer); - size_t height = CVPixelBufferGetHeight(p->pixelBuffer); - size_t stride = CVPixelBufferGetBytesPerRow(p->pixelBuffer); - size_t image_size = stride * height; - - mp_image_t *image = alloc_mpi(width, height, img_fmt); - memcpy(image->planes[0], base, image_size); - image->stride[0] = stride; - - image->display_w = vo->aspdat.prew; - image->display_h = vo->aspdat.preh; - - mp_image_set_colorspace_details(image, &p->colorspace); - - return image; -} - -static int control(struct vo *vo, uint32_t request, void *data) -{ - struct priv *p = vo->priv; - switch (request) { - case VOCTRL_DRAW_IMAGE: - return draw_image(vo, data); - case VOCTRL_QUERY_FORMAT: - return query_format(vo, *(uint32_t*)data); - case VOCTRL_ONTOP: - p->mpglctx->ontop(vo); - return VO_TRUE; - case VOCTRL_PAUSE: - if (!p->mpglctx->pause) - break; - p->mpglctx->pause(vo); - return VO_TRUE; - case VOCTRL_RESUME: - if (!p->mpglctx->resume) - break; - p->mpglctx->resume(vo); - return VO_TRUE; - case VOCTRL_FULLSCREEN: - p->mpglctx->fullscreen(vo); - resize(vo, vo->dwidth, vo->dheight); - return VO_TRUE; - case VOCTRL_GET_PANSCAN: - return VO_TRUE; - case VOCTRL_SET_PANSCAN: - resize(vo, vo->dwidth, vo->dheight); - return VO_TRUE; - case VOCTRL_UPDATE_SCREENINFO: - p->mpglctx->update_xinerama_info(vo); - return VO_TRUE; - case VOCTRL_REDRAW_FRAME: - do_render(vo); - return VO_TRUE; - case VOCTRL_SET_YUV_COLORSPACE: - p->colorspace.format = ((struct mp_csp_details *)data)->format; - set_yuv_colorspace(vo); - return VO_TRUE; - case VOCTRL_GET_YUV_COLORSPACE: - *(struct mp_csp_details *)data = p->colorspace; - return VO_TRUE; - case VOCTRL_SCREENSHOT: { - struct voctrl_screenshot_args *args = data; - if (args->full_window) - args->out_image = glGetWindowScreenshot(p->mpglctx->gl); - else - args->out_image = get_screenshot(vo); - return VO_TRUE; - } - } - return VO_NOTIMPL; -} - -const struct vo_driver video_out_corevideo = { - .is_new = true, - .info = &(const vo_info_t) { - "Mac OS X Core Video", - "corevideo", - "Nicolas Plourde <nicolas.plourde@gmail.com> and others", - "" - }, - .preinit = preinit, - .config = config, - .control = control, - .draw_osd = draw_osd, - .flip_page = flip_page, - .check_events = check_events, - .uninit = uninit, - .priv_size = sizeof(struct priv), -}; diff --git a/libvo/vo_direct3d.c b/libvo/vo_direct3d.c deleted file mode 100644 index 294a101ffe..0000000000 --- a/libvo/vo_direct3d.c +++ /dev/null @@ -1,2101 +0,0 @@ -/* - * Copyright (c) 2008 Georgi Petrov (gogothebee) <gogothebee@gmail.com> - * - * 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 <windows.h> -#include <errno.h> -#include <stdio.h> -#include <stdlib.h> -#include <math.h> -#include <stdbool.h> -#include <assert.h> -#include <d3d9.h> -#include "config.h" -#include "options.h" -#include "subopt-helper.h" -#include "talloc.h" -#include "video_out.h" -#include "libmpcodecs/vfcap.h" -#include "csputils.h" -#include "libmpcodecs/mp_image.h" -#include "libmpcodecs/img_format.h" -#include "fastmemcpy.h" -#include "mp_msg.h" -#include "aspect.h" -#include "w32_common.h" -#include "libavutil/common.h" -#include "sub/sub.h" -#include "bitmap_packer.h" - -// shaders generated by fxc.exe from d3d_shader_yuv.hlsl -#include "d3d_shader_yuv.h" -#include "d3d_shader_yuv_2ch.h" - - -// TODO: beg someone to add this (there is already IMGFMT_Y8) -// equals MAKEFOURCC('Y', '1', '6', ' ') -#define IMGFMT_Y16 0x20363159 -#define IMGFMT_A8Y8 MAKEFOURCC('A', '8', 'Y', '8') - -#define IMGFMT_IS_Y(x) ((x) == IMGFMT_Y8 || (x) == IMGFMT_Y16 || (x) == IMGFMT_A8Y8) -#define IMGFMT_Y_DEPTH(x) ((x) == IMGFMT_Y8 ? 8 : 16) - -#define DEVTYPE D3DDEVTYPE_HAL -//#define DEVTYPE D3DDEVTYPE_REF - -#define D3DFVF_OSD_VERTEX (D3DFVF_XYZ | D3DFVF_TEX1 | D3DFVF_DIFFUSE) - -typedef struct { - float x, y, z; - D3DCOLOR color; - float tu, tv; -} vertex_osd; - -#define D3DFVF_VIDEO_VERTEX (D3DFVF_XYZ | D3DFVF_TEX3) - -typedef struct { - float x, y, z; - // pairs of texture coordinates for up to 3 planes - float t[3][2]; -} vertex_video; - - -struct d3dtex { - // user-requested size - int w, h; - // allocated texture size - int tex_w, tex_h; - // D3DPOOL_SYSTEMMEM (or others) texture: - // - can be locked in order to write (and even read) data - // - can _not_ (probably) be used as texture for rendering - // This is always non-NULL if d3dtex_allocate succeeds. - IDirect3DTexture9 *system; - // D3DPOOL_DEFAULT texture: - // - can't be locked (Probably.) - // - must be used for rendering - // This will be NULL on systems with device_texture_sys != 0. - IDirect3DTexture9 *device; -}; - -struct texplane { - int bytes_per_pixel; - int bits_per_pixel; - // chroma shifts - // e.g. get the plane's width in pixels with (priv->src_width >> shift_x) - int shift_x, shift_y; - D3DFORMAT d3d_format; - struct d3dtex texture; - // temporary locking during uploading the frame (e.g. for draw_slice) - D3DLOCKED_RECT locked_rect; - // value used to clear the image with memset (YUV chroma planes do not use - // the value 0 for this) - uint8_t clearval; -}; - -struct osdpart { - enum sub_bitmap_format format; - int bitmap_id, bitmap_pos_id; - struct d3dtex texture; - int num_vertices; - vertex_osd *vertices; - struct bitmap_packer *packer; -}; - -/* Global variables "priv" structure. I try to keep their count low. - */ -typedef struct d3d_priv { - int opt_prefer_stretchrect; - int opt_disable_textures; - int opt_disable_stretchrect; - int opt_disable_shaders; - int opt_only_8bit; - int opt_disable_osd; - int opt_disable_texture_align; - // debugging - int opt_force_power_of_2; - int opt_texture_memory; - int opt_swap_discard; - int opt_exact_backbuffer; - int opt_16bit_textures; - - struct vo *vo; - - int is_clear_needed; /**< 1 = Clear the backbuffer before StretchRect - 0 = (default) Don't clear it */ - D3DLOCKED_RECT locked_rect; /**< The locked offscreen surface */ - RECT fs_movie_rect; /**< Rect (upscaled) of the movie when displayed - in fullscreen */ - RECT fs_panscan_rect; /**< PanScan source surface cropping in - fullscreen */ - int src_width; /**< Source (movie) width */ - int src_height; /**< Source (movie) heigth */ - struct mp_osd_res osd_res; - int image_format; /**< mplayer image format */ - bool use_textures; /**< use 3D texture rendering, instead of - StretchRect */ - bool use_shaders; /**< use shader for YUV color conversion - (or possibly for RGB video equalizers) */ - bool use_2ch_hack; /**< 2 byte YUV formats use 2 channel hack */ - - int plane_count; - struct texplane planes[3]; - - IDirect3DPixelShader9 *pixel_shader; - const BYTE *pixel_shader_data; - - D3DFORMAT movie_src_fmt; /**< Movie colorspace format (depends on - the movie's codec) */ - D3DFORMAT desktop_fmt; /**< Desktop (screen) colorspace format. - Usually XRGB */ - - HANDLE d3d9_dll; /**< d3d9 Library HANDLE */ - IDirect3D9 * (WINAPI *pDirect3DCreate9)(UINT); /**< pointer to Direct3DCreate9 function */ - - LPDIRECT3D9 d3d_handle; /**< Direct3D Handle */ - LPDIRECT3DDEVICE9 d3d_device; /**< The Direct3D Adapter */ - bool d3d_in_scene; /**< BeginScene was called, EndScene not */ - IDirect3DSurface9 *d3d_surface; /**< Offscreen Direct3D Surface. MPlayer - renders inside it. Uses colorspace - priv->movie_src_fmt */ - IDirect3DSurface9 *d3d_backbuf; /**< Video card's back buffer (used to - display next frame) */ - int cur_backbuf_width; /**< Current backbuffer width */ - int cur_backbuf_height; /**< Current backbuffer height */ - int device_caps_power2_only; /**< 1 = texture sizes have to be power 2 - 0 = texture sizes can be anything */ - int device_caps_square_only; /**< 1 = textures have to be square - 0 = textures do not have to be square */ - int device_texture_sys; /**< 1 = device can texture from system memory - 0 = device requires shadow */ - int max_texture_width; /**< from the device capabilities */ - int max_texture_height; /**< from the device capabilities */ - - D3DMATRIX d3d_colormatrix; - float d3d_depth_vector[4]; - struct mp_csp_details colorspace; - struct mp_csp_equalizer video_eq; - - struct osdpart *osd[MAX_OSD_PARTS]; -} d3d_priv; - -struct fmt_entry { - const unsigned int mplayer_fmt; /**< Given by MPlayer */ - const D3DFORMAT fourcc; /**< Required by D3D's test function */ -}; - -/* Map table from reported MPlayer format to the required - fourcc. This is needed to perform the format query. */ - -static const struct fmt_entry fmt_table[] = { - // planar YUV - {IMGFMT_YV12, MAKEFOURCC('Y','V','1','2')}, - {IMGFMT_I420, MAKEFOURCC('I','4','2','0')}, - {IMGFMT_IYUV, MAKEFOURCC('I','Y','U','V')}, - {IMGFMT_YVU9, MAKEFOURCC('Y','V','U','9')}, - // packed YUV - {IMGFMT_YUY2, D3DFMT_YUY2}, - {IMGFMT_UYVY, D3DFMT_UYVY}, - // packed RGB - {IMGFMT_BGR32, D3DFMT_X8R8G8B8}, - {IMGFMT_RGB32, D3DFMT_X8B8G8R8}, - {IMGFMT_BGR24, D3DFMT_R8G8B8}, //untested - {IMGFMT_BGR16, D3DFMT_R5G6B5}, - {IMGFMT_BGR15, D3DFMT_X1R5G5B5}, - {IMGFMT_BGR8 , D3DFMT_R3G3B2}, //untested - // grayscale (can be considered both packed and planar) - {IMGFMT_Y8, D3DFMT_L8}, - {IMGFMT_Y16, D3DFMT_L16}, - {IMGFMT_A8Y8, D3DFMT_A8L8}, - {0}, -}; - -static const D3DFORMAT osd_fmt_table[SUBBITMAP_COUNT] = { - [SUBBITMAP_LIBASS] = D3DFMT_A8, - [SUBBITMAP_RGBA] = D3DFMT_A8R8G8B8, -}; -static const bool osd_fmt_supported[SUBBITMAP_COUNT] = { - [SUBBITMAP_LIBASS] = true, - [SUBBITMAP_RGBA] = true, -}; - - -static void update_colorspace(d3d_priv *priv); -static void d3d_clear_video_textures(d3d_priv *priv); -static bool resize_d3d(d3d_priv *priv); -static uint32_t d3d_draw_frame(d3d_priv *priv); -static int draw_slice(struct vo *vo, uint8_t *src[], int stride[], int w, int h, - int x, int y); -static void uninit(struct vo *vo); -static void flip_page(struct vo *vo); -static mp_image_t *get_screenshot(d3d_priv *priv); -static mp_image_t *get_window_screenshot(d3d_priv *priv); - - -static void d3d_matrix_identity(D3DMATRIX *m) -{ - memset(m, 0, sizeof(D3DMATRIX)); - m->_11 = m->_22 = m->_33 = m->_44 = 1.0f; -} - -static void d3d_matrix_ortho(D3DMATRIX *m, float left, float right, - float bottom, float top) -{ - d3d_matrix_identity(m); - m->_11 = 2.0f / (right - left); - m->_22 = 2.0f / (top - bottom); - m->_33 = 1.0f; - m->_41 = -(right + left) / (right - left); - m->_42 = -(top + bottom) / (top - bottom); - m->_43 = 0; - m->_44 = 1.0f; -} - -/**************************************************************************** - * * - * * - * * - * Direct3D specific implementation functions * - * * - * * - * * - ****************************************************************************/ - -static bool d3d_begin_scene(d3d_priv *priv) -{ - if (!priv->d3d_in_scene) { - if (FAILED(IDirect3DDevice9_BeginScene(priv->d3d_device))) { - mp_msg(MSGT_VO, MSGL_ERR, "<vo_direct3d>BeginScene failed.\n"); - return false; - } - priv->d3d_in_scene = true; - } - return true; -} - -/** @brief Calculate scaled fullscreen movie rectangle with - * preserved aspect ratio. - */ -static void calc_fs_rect(d3d_priv *priv) -{ - struct mp_rect src_rect; - struct mp_rect dst_rect; - vo_get_src_dst_rects(priv->vo, &src_rect, &dst_rect, &priv->osd_res); - - priv->fs_movie_rect.left = dst_rect.x0; - priv->fs_movie_rect.right = dst_rect.x1; - priv->fs_movie_rect.top = dst_rect.y0; - priv->fs_movie_rect.bottom = dst_rect.y1; - priv->fs_panscan_rect.left = src_rect.x0; - priv->fs_panscan_rect.right = src_rect.x1; - priv->fs_panscan_rect.top = src_rect.y0; - priv->fs_panscan_rect.bottom = src_rect.y1; - - mp_msg(MSGT_VO, MSGL_V, - "<vo_direct3d>Video rectangle: t: %ld, l: %ld, r: %ld, b:%ld\n", - priv->fs_movie_rect.top, priv->fs_movie_rect.left, - priv->fs_movie_rect.right, priv->fs_movie_rect.bottom); - - /* The backbuffer should be cleared before next StretchRect. This is - * necessary because our new draw area could be smaller than the - * previous one used by StretchRect and without it, leftovers from the - * previous frame will be left. */ - priv->is_clear_needed = 1; -} - -// Adjust the texture size *width/*height to fit the requirements of the D3D -// device. The texture size is only increased. -static void d3d_fix_texture_size(d3d_priv *priv, int *width, int *height) -{ - int tex_width = *width; - int tex_height = *height; - - // avoid nasty special cases with 0-sized textures and texture sizes - tex_width = FFMAX(tex_width, 1); - tex_height = FFMAX(tex_height, 1); - - if (priv->device_caps_power2_only) { - tex_width = 1; - tex_height = 1; - while (tex_width < *width) tex_width <<= 1; - while (tex_height < *height) tex_height <<= 1; - } - if (priv->device_caps_square_only) - /* device only supports square textures */ - tex_width = tex_height = FFMAX(tex_width, tex_height); - // better round up to a multiple of 16 - if (!priv->opt_disable_texture_align) { - tex_width = (tex_width + 15) & ~15; - tex_height = (tex_height + 15) & ~15; - } - - *width = tex_width; - *height = tex_height; -} - -static void d3dtex_release(d3d_priv *priv, struct d3dtex *tex) -{ - if (tex->system) - IDirect3DTexture9_Release(tex->system); - tex->system = NULL; - - if (tex->device) - IDirect3DTexture9_Release(tex->device); - tex->device = NULL; - - tex->tex_w = tex->tex_h = 0; -} - -static bool d3dtex_allocate(d3d_priv *priv, struct d3dtex *tex, D3DFORMAT fmt, - int w, int h) -{ - d3dtex_release(priv, tex); - - tex->w = w; - tex->h = h; - - int tw = w, th = h; - d3d_fix_texture_size(priv, &tw, &th); - - int memtype = D3DPOOL_SYSTEMMEM; - switch (priv->opt_texture_memory) { - case 1: memtype = D3DPOOL_MANAGED; break; - case 2: memtype = D3DPOOL_DEFAULT; break; - } - - if (FAILED(IDirect3DDevice9_CreateTexture(priv->d3d_device, tw, th, 1, - D3DUSAGE_DYNAMIC, fmt, memtype, &tex->system, NULL))) - { - mp_msg(MSGT_VO, MSGL_ERR, - "<vo_direct3d>Allocating %dx%d texture in system RAM failed.\n", - w, h); - goto error_exit; - } - - if (!priv->device_texture_sys && !priv->opt_texture_memory) { - if (FAILED(IDirect3DDevice9_CreateTexture(priv->d3d_device, tw, th, 1, - D3DUSAGE_DYNAMIC, fmt, D3DPOOL_DEFAULT, &tex->device, NULL))) - { - mp_msg(MSGT_VO, MSGL_ERR, - "<vo_direct3d>Allocating %dx%d texture in video RAM failed.\n", - w, h); - goto error_exit; - } - } - - tex->tex_w = tw; - tex->tex_h = th; - - return true; - -error_exit: - d3dtex_release(priv, tex); - return false; -} - -static IDirect3DBaseTexture9 *d3dtex_get_render_texture(d3d_priv *priv, - struct d3dtex *tex) -{ - return (IDirect3DBaseTexture9 *)(tex->device ? tex->device : tex->system); -} - -// Copy system texture contents to device texture. -static bool d3dtex_update(d3d_priv *priv, struct d3dtex *tex) -{ - if (!tex->device) - return true; - return !FAILED(IDirect3DDevice9_UpdateTexture(priv->d3d_device, - (IDirect3DBaseTexture9 *)tex->system, - (IDirect3DBaseTexture9 *)tex->device)); -} - -static void d3d_unlock_video_objects(d3d_priv *priv) -{ - bool any_failed = false; - - if (priv->locked_rect.pBits) { - if (FAILED(IDirect3DSurface9_UnlockRect(priv->d3d_surface))) - any_failed = true; - } - priv->locked_rect.pBits = NULL; - - for (int n = 0; n < priv->plane_count; n++) { - struct texplane *plane = &priv->planes[n]; - if (plane->locked_rect.pBits) { - if (FAILED(IDirect3DTexture9_UnlockRect(plane->texture.system, 0))) - any_failed = true; - } - plane->locked_rect.pBits = NULL; - } - - if (any_failed) { - mp_msg(MSGT_VO, MSGL_V, - "<vo_direct3d>Unlocking video objects failed.\n"); - } -} - -// Free video surface/textures, shaders, etc. -static void d3d_destroy_video_objects(d3d_priv *priv) -{ - d3d_unlock_video_objects(priv); - - if (priv->d3d_surface) - IDirect3DSurface9_Release(priv->d3d_surface); - priv->d3d_surface = NULL; - - for (int n = 0; n < priv->plane_count; n++) { - d3dtex_release(priv, &priv->planes[n].texture); - } - - if (priv->pixel_shader) - IDirect3DPixelShader9_Release(priv->pixel_shader); - priv->pixel_shader = NULL; -} - -/** @brief Destroy D3D Offscreen and Backbuffer surfaces. - */ -static void destroy_d3d_surfaces(d3d_priv *priv) -{ - mp_msg(MSGT_VO, MSGL_V, "<vo_direct3d>destroy_d3d_surfaces called.\n"); - - d3d_destroy_video_objects(priv); - - for (int n = 0; n < MAX_OSD_PARTS; n++) { - struct osdpart *osd = priv->osd[n]; - d3dtex_release(priv, &osd->texture); - osd->bitmap_id = osd->bitmap_pos_id = -1; - } - - if (priv->d3d_backbuf) - IDirect3DSurface9_Release(priv->d3d_backbuf); - priv->d3d_backbuf = NULL; - - priv->d3d_in_scene = false; -} - -// Allocate video surface or textures, and create shaders if needed. -static bool d3d_configure_video_objects(d3d_priv *priv) -{ - int n; - bool need_clear = false; - - assert(priv->image_format != 0); - - if (priv->use_textures) { - for (n = 0; n < priv->plane_count; n++) { - struct texplane *plane = &priv->planes[n]; - - if (!plane->texture.system) { - if (!d3dtex_allocate(priv, - &plane->texture, - plane->d3d_format, - priv->src_width >> plane->shift_x, - priv->src_height >> plane->shift_y)) - { - mp_msg(MSGT_VO, MSGL_ERR, "<vo_direct3d>Allocating plane %d" - " failed.\n", n); - return false; - } - - mp_msg(MSGT_VO, MSGL_V, "<vo_direct3d>Allocated plane %d:" - " %d bit, shift=%d/%d size=%d/%d (%d/%d).\n", n, - plane->bits_per_pixel, - plane->shift_x, plane->shift_y, - plane->texture.w, plane->texture.h, - plane->texture.tex_w, plane->texture.tex_h); - - need_clear = true; - } - } - - if (need_clear) - d3d_clear_video_textures(priv); - - if (priv->pixel_shader_data) { - if (!priv->pixel_shader && - FAILED(IDirect3DDevice9_CreatePixelShader(priv->d3d_device, - (DWORD *)priv->pixel_shader_data, &priv->pixel_shader))) - { - mp_msg(MSGT_VO, MSGL_ERR, "<vo_direct3d>Failed to create " - "YUV conversion pixel shader.\n"); - return false; - } - } - - } else { - - if (!priv->d3d_surface && - FAILED(IDirect3DDevice9_CreateOffscreenPlainSurface( - priv->d3d_device, priv->src_width, priv->src_height, - priv->movie_src_fmt, D3DPOOL_DEFAULT, &priv->d3d_surface, NULL))) - { - mp_msg(MSGT_VO, MSGL_ERR, - "<vo_direct3d>Allocating offscreen surface failed.\n"); - return false; - } - } - - return true; -} - -static bool d3d_lock_video_textures(d3d_priv *priv) -{ - for (int n = 0; n < priv->plane_count; n++) { - struct texplane *plane = &priv->planes[n]; - - if (!plane->locked_rect.pBits) { - if (FAILED(IDirect3DTexture9_LockRect(plane->texture.system, 0, - &plane->locked_rect, NULL, 0))) - { - mp_msg(MSGT_VO, MSGL_V, "<vo_direct3d>Texture lock failure.\n"); - d3d_unlock_video_objects(priv); - return false; - } - } - } - - return true; -} - -static void d3d_clear_video_textures(d3d_priv *priv) -{ - if (!d3d_lock_video_textures(priv)) - return; - - for (int n = 0; n < priv->plane_count; n++) { - struct texplane *plane = &priv->planes[n]; - memset(plane->locked_rect.pBits, plane->clearval, - plane->locked_rect.Pitch * plane->texture.tex_h); - } - - d3d_unlock_video_objects(priv); -} - -// Recreate and initialize D3D objects if necessary. The amount of work that -// needs to be done can be quite different: it could be that full initialization -// is required, or that some objects need to be created, or that nothing is -// done. -static bool create_d3d_surfaces(d3d_priv *priv) -{ - mp_msg(MSGT_VO, MSGL_V, "<vo_direct3d>create_d3d_surfaces called.\n"); - - if (!priv->d3d_backbuf && - FAILED(IDirect3DDevice9_GetBackBuffer(priv->d3d_device, 0, 0, - D3DBACKBUFFER_TYPE_MONO, - &priv->d3d_backbuf))) { - mp_msg(MSGT_VO, MSGL_ERR, "<vo_direct3d>Allocating backbuffer failed.\n"); - return 0; - } - - if (!d3d_configure_video_objects(priv)) - return 0; - - /* setup default renderstate */ - IDirect3DDevice9_SetRenderState(priv->d3d_device, - D3DRS_SRCBLEND, D3DBLEND_SRCALPHA); - IDirect3DDevice9_SetRenderState(priv->d3d_device, - D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA); - IDirect3DDevice9_SetRenderState(priv->d3d_device, - D3DRS_ALPHAFUNC, D3DCMP_GREATER); - IDirect3DDevice9_SetRenderState(priv->d3d_device, - D3DRS_ALPHAREF, (DWORD)0x0); - IDirect3DDevice9_SetRenderState(priv->d3d_device, - D3DRS_LIGHTING, FALSE); - - // we use up to 3 samplers for up to 3 YUV planes - for (int n = 0; n < 3; n++) { - IDirect3DDevice9_SetSamplerState(priv->d3d_device, n, D3DSAMP_MINFILTER, - D3DTEXF_LINEAR); - IDirect3DDevice9_SetSamplerState(priv->d3d_device, n, D3DSAMP_MAGFILTER, - D3DTEXF_LINEAR); - IDirect3DDevice9_SetSamplerState(priv->d3d_device, n, D3DSAMP_ADDRESSU, - D3DTADDRESS_CLAMP); - IDirect3DDevice9_SetSamplerState(priv->d3d_device, n, D3DSAMP_ADDRESSV, - D3DTADDRESS_CLAMP); - } - - return 1; -} - -static bool init_d3d(d3d_priv *priv) -{ - D3DDISPLAYMODE disp_mode; - D3DCAPS9 disp_caps; - DWORD texture_caps; - DWORD dev_caps; - - priv->d3d_handle = priv->pDirect3DCreate9(D3D_SDK_VERSION); - if (!priv->d3d_handle) { - mp_msg(MSGT_VO, MSGL_ERR, - "<vo_direct3d>Initializing Direct3D failed.\n"); - return false; - } - - if (FAILED(IDirect3D9_GetAdapterDisplayMode(priv->d3d_handle, - D3DADAPTER_DEFAULT, - &disp_mode))) { - mp_msg(MSGT_VO, MSGL_ERR, - "<vo_direct3d>Reading display mode failed.\n"); - return false; - } - - priv->desktop_fmt = disp_mode.Format; - priv->cur_backbuf_width = disp_mode.Width; - priv->cur_backbuf_height = disp_mode.Height; - - mp_msg(MSGT_VO, MSGL_V, - "<vo_direct3d>Setting backbuffer dimensions to (%dx%d).\n", - disp_mode.Width, disp_mode.Height); - - if (FAILED(IDirect3D9_GetDeviceCaps(priv->d3d_handle, - D3DADAPTER_DEFAULT, - DEVTYPE, - &disp_caps))) - { - mp_msg(MSGT_VO, MSGL_ERR, - "<vo_direct3d>Reading display capabilities failed.\n"); - return false; - } - - /* Store relevant information reguarding caps of device */ - texture_caps = disp_caps.TextureCaps; - dev_caps = disp_caps.DevCaps; - priv->device_caps_power2_only = (texture_caps & D3DPTEXTURECAPS_POW2) && - !(texture_caps & D3DPTEXTURECAPS_NONPOW2CONDITIONAL); - priv->device_caps_square_only = texture_caps & D3DPTEXTURECAPS_SQUAREONLY; - priv->device_texture_sys = dev_caps & D3DDEVCAPS_TEXTURESYSTEMMEMORY; - priv->max_texture_width = disp_caps.MaxTextureWidth; - priv->max_texture_height = disp_caps.MaxTextureHeight; - - if (priv->opt_force_power_of_2) - priv->device_caps_power2_only = 1; - - mp_msg(MSGT_VO, MSGL_V, - "<vo_direct3d>device_caps_power2_only %d, device_caps_square_only %d\n" - "<vo_direct3d>device_texture_sys %d\n" - "<vo_direct3d>max_texture_width %d, max_texture_height %d\n", - priv->device_caps_power2_only, priv->device_caps_square_only, - priv->device_texture_sys, priv->max_texture_width, - priv->max_texture_height); - - return true; -} - -/** @brief Fill D3D Presentation parameters - */ -static void fill_d3d_presentparams(d3d_priv *priv, - D3DPRESENT_PARAMETERS *present_params) -{ - /* Prepare Direct3D initialization parameters. */ - memset(present_params, 0, sizeof(D3DPRESENT_PARAMETERS)); - present_params->Windowed = TRUE; - present_params->SwapEffect = - priv->opt_swap_discard ? D3DSWAPEFFECT_DISCARD : D3DSWAPEFFECT_COPY; - present_params->Flags = D3DPRESENTFLAG_VIDEO; - present_params->hDeviceWindow = priv->vo->w32->window; - present_params->BackBufferWidth = priv->cur_backbuf_width; - present_params->BackBufferHeight = priv->cur_backbuf_height; - present_params->MultiSampleType = D3DMULTISAMPLE_NONE; - present_params->PresentationInterval = D3DPRESENT_INTERVAL_ONE; - present_params->BackBufferFormat = priv->desktop_fmt; - present_params->BackBufferCount = 1; - present_params->EnableAutoDepthStencil = FALSE; -} - - -// Create a new backbuffer. Create or Reset the D3D device. -static bool change_d3d_backbuffer(d3d_priv *priv) -{ - D3DPRESENT_PARAMETERS present_params; - - int window_w = priv->vo->dwidth; - int window_h = priv->vo->dheight; - - /* Grow the backbuffer in the required dimension. */ - if (window_w > priv->cur_backbuf_width) - priv->cur_backbuf_width = window_w; - - if (window_h > priv->cur_backbuf_height) - priv->cur_backbuf_height = window_h; - - if (priv->opt_exact_backbuffer) { - priv->cur_backbuf_width = window_w; - priv->cur_backbuf_height = window_h; - } - - /* The grown backbuffer dimensions are ready and fill_d3d_presentparams - * will use them, so we can reset the device. - */ - fill_d3d_presentparams(priv, &present_params); - - if (!priv->d3d_device) { - if (FAILED(IDirect3D9_CreateDevice(priv->d3d_handle, - D3DADAPTER_DEFAULT, - DEVTYPE, priv->vo->w32->window, - D3DCREATE_SOFTWARE_VERTEXPROCESSING - | D3DCREATE_FPU_PRESERVE, - &present_params, &priv->d3d_device))) - { - mp_msg(MSGT_VO, MSGL_V, - "<vo_direct3d>Creating Direct3D device failed.\n"); - return 0; - } - } else { - if (FAILED(IDirect3DDevice9_Reset(priv->d3d_device, &present_params))) { - mp_msg(MSGT_VO, MSGL_ERR, - "<vo_direct3d>Reseting Direct3D device failed.\n"); - return 0; - } - } - - mp_msg(MSGT_VO, MSGL_V, - "<vo_direct3d>New backbuffer (%dx%d), VO (%dx%d)\n", - present_params.BackBufferWidth, present_params.BackBufferHeight, - window_w, window_h); - - return 1; -} - -/** @brief Reconfigure the whole Direct3D. Called only - * when the video adapter becomes uncooperative. ("Lost" devices) - * @return 1 on success, 0 on failure - */ -static int reconfigure_d3d(d3d_priv *priv) -{ - mp_msg(MSGT_VO, MSGL_V, "<vo_direct3d>reconfigure_d3d called.\n"); - - destroy_d3d_surfaces(priv); - - if (priv->d3d_device) - IDirect3DDevice9_Release(priv->d3d_device); - priv->d3d_device = NULL; - - // Force complete destruction of the D3D state. - // Note: this step could be omitted. The resize_d3d call below would detect - // that d3d_device is NULL, and would properly recreate it. I'm not sure why - // the following code to release and recreate the d3d_handle exists. - if (priv->d3d_handle) - IDirect3D9_Release(priv->d3d_handle); - priv->d3d_handle = NULL; - if (!init_d3d(priv)) - return 0; - - // Proper re-initialization. - if (!resize_d3d(priv)) - return 0; - - return 1; -} - -// Resize Direct3D context on window resize. -// This function also is called when major initializations need to be done. -static bool resize_d3d(d3d_priv *priv) -{ - D3DVIEWPORT9 vp = {0, 0, priv->vo->dwidth, priv->vo->dheight, 0, 1}; - - mp_msg(MSGT_VO, MSGL_V, "<vo_direct3d>resize_d3d called.\n"); - - /* Make sure that backbuffer is large enough to accomodate the new - viewport dimensions. Grow it if necessary. */ - - bool backbuf_resize = priv->vo->dwidth > priv->cur_backbuf_width || - priv->vo->dheight > priv->cur_backbuf_height; - - if (priv->opt_exact_backbuffer) { - backbuf_resize = priv->vo->dwidth != priv->cur_backbuf_width || - priv->vo->dheight != priv->cur_backbuf_height; - } - - if (backbuf_resize || !priv->d3d_device) - { - destroy_d3d_surfaces(priv); - if (!change_d3d_backbuffer(priv)) - return 0; - } - - if (!priv->d3d_device) - return 1; - - if (!create_d3d_surfaces(priv)) - return 0; - - if (FAILED(IDirect3DDevice9_SetViewport(priv->d3d_device, &vp))) { - mp_msg(MSGT_VO, MSGL_ERR, "<vo_direct3d>Setting viewport failed.\n"); - return 0; - } - - // so that screen coordinates map to D3D ones - D3DMATRIX view; - d3d_matrix_ortho(&view, 0.5f, vp.Width + 0.5f, vp.Height + 0.5f, 0.5f); - IDirect3DDevice9_SetTransform(priv->d3d_device, D3DTS_VIEW, &view); - - calc_fs_rect(priv); - - priv->vo->want_redraw = true; - - return 1; -} - -/** @brief Uninitialize Direct3D and close the window. - */ -static void uninit_d3d(d3d_priv *priv) -{ - mp_msg(MSGT_VO, MSGL_V, "<vo_direct3d>uninit_d3d called.\n"); - - destroy_d3d_surfaces(priv); - - if (priv->d3d_device) - IDirect3DDevice9_Release(priv->d3d_device); - priv->d3d_device = NULL; - - if (priv->d3d_handle) { - mp_msg(MSGT_VO, MSGL_V, "<vo_direct3d>Stopping Direct3D.\n"); - IDirect3D9_Release(priv->d3d_handle); - } - priv->d3d_handle = NULL; -} - -static uint32_t d3d_upload_and_render_frame_texture(d3d_priv *priv, - mp_image_t *mpi) -{ - if (!(mpi->flags & MP_IMGFLAG_DRAW_CALLBACK)) - draw_slice(priv->vo, mpi->planes, mpi->stride, mpi->w, mpi->h, 0, 0); - - d3d_unlock_video_objects(priv); - - for (int n = 0; n < priv->plane_count; n++) { - d3dtex_update(priv, &priv->planes[n].texture); - } - - return d3d_draw_frame(priv); -} - -/** @brief Render a frame on the screen. - * @param mpi mpi structure with the decoded frame inside - * @return VO_TRUE on success, VO_ERROR on failure - */ -static uint32_t d3d_upload_and_render_frame(d3d_priv *priv, mp_image_t *mpi) -{ - if (!priv->d3d_device) - return VO_TRUE; - - if (priv->use_textures) - return d3d_upload_and_render_frame_texture(priv, mpi); - - if (mpi->flags & MP_IMGFLAG_DRAW_CALLBACK) - goto skip_upload; - - if (mpi->flags & MP_IMGFLAG_PLANAR) { /* Copy a planar frame. */ - draw_slice(priv->vo, mpi->planes, mpi->stride, mpi->w, mpi->h, 0, 0); - goto skip_upload; - } - - /* If we're here, then we should lock the rect and copy a packed frame */ - if (!priv->locked_rect.pBits) { - if (FAILED(IDirect3DSurface9_LockRect(priv->d3d_surface, - &priv->locked_rect, NULL, 0))) { - mp_msg(MSGT_VO, MSGL_ERR, "<vo_direct3d>Surface lock failed.\n"); - return VO_ERROR; - } - } - - memcpy_pic(priv->locked_rect.pBits, mpi->planes[0], mpi->stride[0], - mpi->height, priv->locked_rect.Pitch, mpi->stride[0]); - -skip_upload: - d3d_unlock_video_objects(priv); - - return d3d_draw_frame(priv); -} - -static uint32_t d3d_draw_frame(d3d_priv *priv) -{ - int n; - - if (!priv->d3d_device) - return VO_TRUE; - - if (!d3d_begin_scene(priv)) - return VO_ERROR; - - if (priv->is_clear_needed || priv->opt_swap_discard) { - IDirect3DDevice9_Clear(priv->d3d_device, 0, NULL, - D3DCLEAR_TARGET, 0, 0, 0); - priv->is_clear_needed = 0; - } - - if (priv->use_textures) { - - for (n = 0; n < priv->plane_count; n++) { - IDirect3DDevice9_SetTexture(priv->d3d_device, n, - d3dtex_get_render_texture(priv, &priv->planes[n].texture)); - } - - RECT rm = priv->fs_movie_rect; - RECT rs = priv->fs_panscan_rect; - - vertex_video vb[] = { - { rm.left, rm.top, 0.0f}, - { rm.right, rm.top, 0.0f}, - { rm.left, rm.bottom, 0.0f}, - { rm.right, rm.bottom, 0.0f} - }; - - float texc[4][2] = { - { rs.left, rs.top}, - { rs.right, rs.top}, - { rs.left, rs.bottom}, - { rs.right, rs.bottom} - }; - - for (n = 0; n < priv->plane_count; n++) { - float s_x = (1.0f / (1 << priv->planes[n].shift_x)) - / priv->planes[n].texture.tex_w; - float s_y = (1.0f / (1 << priv->planes[n].shift_y)) - / priv->planes[n].texture.tex_h; - for (int i = 0; i < 4; i++) { - vb[i].t[n][0] = texc[i][0] * s_x; - vb[i].t[n][1] = texc[i][1] * s_y; - } - } - - if (priv->pixel_shader) { - IDirect3DDevice9_SetPixelShader(priv->d3d_device, priv->pixel_shader); - IDirect3DDevice9_SetPixelShaderConstantF(priv->d3d_device, 0, - &priv->d3d_colormatrix._11, - 4); - IDirect3DDevice9_SetPixelShaderConstantF(priv->d3d_device, 5, - priv->d3d_depth_vector, - 1); - } - - IDirect3DDevice9_SetFVF(priv->d3d_device, D3DFVF_VIDEO_VERTEX); - IDirect3DDevice9_DrawPrimitiveUP(priv->d3d_device, D3DPT_TRIANGLESTRIP, - 2, &vb[0], sizeof(vertex_video)); - - IDirect3DDevice9_SetPixelShader(priv->d3d_device, NULL); - - for (n = 0; n < priv->plane_count; n++) { - IDirect3DDevice9_SetTexture(priv->d3d_device, n, NULL); - } - - } else { - if (FAILED(IDirect3DDevice9_StretchRect(priv->d3d_device, - priv->d3d_surface, - &priv->fs_panscan_rect, - priv->d3d_backbuf, - &priv->fs_movie_rect, - D3DTEXF_LINEAR))) { - mp_msg(MSGT_VO, MSGL_ERR, - "<vo_direct3d>Copying frame to the backbuffer failed.\n"); - return VO_ERROR; - } - } - - return VO_TRUE; -} - -// Return the high byte of the value that represents white in chroma (U/V) -static int get_chroma_clear_val(int bit_depth) -{ - return 1 << (bit_depth - 1 & 7); -} - -// this macro is supposed to work on all formats supported by 3D rendering, and -// that produce "reasonable" output (i.e. no mixed up colors) -#define IMGFMT_IS_ANY_RND(x) \ - (IMGFMT_IS_BGR(x) || IMGFMT_IS_RGB(x) || IMGFMT_IS_Y(x)) - -// pixel size in bit for any IMGFMT_IS_ANY_RND(x)==true -// we assume that the actual pixel strides are always aligned on bytes -static int imgfmt_any_rnd_depth(int fmt) -{ - if (IMGFMT_IS_BGR(fmt)) - return IMGFMT_BGR_DEPTH(fmt); - if (IMGFMT_IS_RGB(fmt)) - return IMGFMT_RGB_DEPTH(fmt); - if (IMGFMT_IS_Y(fmt)) - return IMGFMT_Y_DEPTH(fmt); - assert(false); - return 0; -} - -static D3DFORMAT check_format(d3d_priv *priv, uint32_t movie_fmt, - bool as_texture) -{ - const char *type = as_texture ? "texture rendering" : "StretchRect"; - const struct fmt_entry *cur = &fmt_table[0]; - - // Don't try to handle weird packed texture formats (although I don't know - // if D3D9 would even accept any such format for 3D rendering; and we - // certainly don't try any tricks like matching it to RGB formats and - // applying a YUV conversion matrix) - if (as_texture && !IMGFMT_IS_ANY_RND(movie_fmt)) - return 0; - - while (cur->mplayer_fmt) { - if (cur->mplayer_fmt == movie_fmt) { - HRESULT res; - if (as_texture) { - res = IDirect3D9_CheckDeviceFormat(priv->d3d_handle, - D3DADAPTER_DEFAULT, - DEVTYPE, - priv->desktop_fmt, - D3DUSAGE_DYNAMIC | D3DUSAGE_QUERY_FILTER, - D3DRTYPE_TEXTURE, - cur->fourcc); - } else { - /* Test conversion from Movie colorspace to - * display's target colorspace. */ - res = IDirect3D9_CheckDeviceFormatConversion(priv->d3d_handle, - D3DADAPTER_DEFAULT, - DEVTYPE, - cur->fourcc, - priv->desktop_fmt); - } - if (FAILED(res)) { - mp_msg(MSGT_VO, MSGL_V, "<vo_direct3d>Rejected image format " - "(%s): %s\n", type, vo_format_name(cur->mplayer_fmt)); - return 0; - } - - mp_msg(MSGT_VO, MSGL_DBG2, "<vo_direct3d>Accepted image format " - "(%s): %s\n", type, vo_format_name(cur->mplayer_fmt)); - - return cur->fourcc; - } - cur++; - } - - return 0; -} - -// Check whether YUV conversion with shaders can be done. -// Returns the format the individual planes should use (or 0 on failure) -static D3DFORMAT check_shader_conversion(d3d_priv *priv, uint32_t fmt) -{ - if (priv->opt_disable_shaders) - return 0; - int component_bits; - if (!mp_get_chroma_shift(fmt, NULL, NULL, &component_bits)) - return 0; - if (component_bits < 8 || component_bits > 16) - return 0; - bool is_8bit = component_bits == 8; - if (!is_8bit && priv->opt_only_8bit) - return 0; - int texfmt = IMGFMT_Y8; - if (!is_8bit) { - if (priv->opt_16bit_textures) - texfmt = IMGFMT_Y16; - else - texfmt = IMGFMT_A8Y8; - } - return check_format(priv, texfmt, true); -} - -// Return if the image format can be used. If it can, decide which rendering -// and conversion mode to use. -// If initialize is true, actually setup all variables to use the picked -// rendering mode. -static bool init_rendering_mode(d3d_priv *priv, uint32_t fmt, bool initialize) -{ - int n; - int blit_d3dfmt = check_format(priv, fmt, false); - int texture_d3dfmt = check_format(priv, fmt, true); - int shader_d3dfmt = check_shader_conversion(priv, fmt); - - if (priv->opt_disable_textures) - texture_d3dfmt = 0; - if (priv->opt_disable_shaders) - shader_d3dfmt = 0; - if (priv->opt_disable_stretchrect) - blit_d3dfmt = 0; - - if (!(blit_d3dfmt || shader_d3dfmt || texture_d3dfmt)) - return false; - - mp_msg(MSGT_VO, MSGL_V, "<vo_direct3d>Accepted rendering methods for " - "format='%s': StretchRect=%#x, Texture=%#x, Texture+Shader=%#x.\n", - vo_format_name(fmt), blit_d3dfmt, texture_d3dfmt, shader_d3dfmt); - - if (!initialize) - return true; - - // initialization doesn't fail beyond this point - - priv->use_shaders = false; - priv->use_textures = false; - priv->use_2ch_hack = false; - priv->movie_src_fmt = 0; - priv->pixel_shader_data = NULL; - priv->plane_count = 0; - priv->image_format = fmt; - - if (blit_d3dfmt && priv->opt_prefer_stretchrect) - texture_d3dfmt = shader_d3dfmt = 0; - - if (texture_d3dfmt) { - priv->use_textures = true; - } else if (shader_d3dfmt) { - priv->use_textures = true; - priv->use_shaders = true; - } else { - assert(!!blit_d3dfmt); - } - - if (priv->use_textures) { - mp_msg(MSGT_VO, MSGL_V, "<vo_direct3d>Using 3D rendering.\n"); - - struct texplane *planes = &priv->planes[0]; - planes[0].shift_x = planes[0].shift_y = 0; - planes[0].clearval = 0; - - if (!priv->use_shaders) { - assert(IMGFMT_IS_ANY_RND(priv->image_format)); - priv->plane_count = 1; - planes[0].bits_per_pixel = imgfmt_any_rnd_depth(priv->image_format); - planes[0].d3d_format = texture_d3dfmt; - } else { - mp_msg(MSGT_VO, MSGL_V, "<vo_direct3d>Using YUV shaders.\n"); - - int sx, sy, component_bits; - mp_get_chroma_shift(priv->image_format, &sx, &sy, &component_bits); - priv->plane_count = 3; - for (n = 0; n < 3; n++) { - planes[n].d3d_format = shader_d3dfmt; - planes[n].bits_per_pixel = component_bits; - if (n > 0) { - planes[n].shift_x = sx; - planes[n].shift_y = sy; - planes[n].clearval = get_chroma_clear_val(component_bits); - } - } - if (shader_d3dfmt != D3DFMT_A8L8) { - priv->pixel_shader_data = d3d_shader_yuv; - } else { - mp_msg(MSGT_VO, MSGL_WARN, "<vo_direct3d>Using YUV 2ch hack.\n"); - - priv->pixel_shader_data = d3d_shader_yuv_2ch; - priv->use_2ch_hack = true; - } - } - - for (n = 0; n < priv->plane_count; n++) { - planes[n].bytes_per_pixel = (planes[n].bits_per_pixel + 7) / 8; - } - - } else { - mp_msg(MSGT_VO, MSGL_V, "<vo_direct3d>Using StretchRect.\n"); - - priv->movie_src_fmt = blit_d3dfmt; - } - - update_colorspace(priv); - - return true; -} - -/** @brief Query if movie colorspace is supported by the HW. - * @return 0 on failure, device capabilities (not probed - * currently) on success. - */ -static int query_format(d3d_priv *priv, uint32_t movie_fmt) -{ - if (!init_rendering_mode(priv, movie_fmt, false)) - return 0; - - int osd_caps = VFCAP_CSP_SUPPORTED | VFCAP_CSP_SUPPORTED_BY_HW - | VFCAP_HWSCALE_UP | VFCAP_HWSCALE_DOWN; - if (!priv->opt_disable_osd) - osd_caps |= VFCAP_OSD; - return osd_caps; -} - -/**************************************************************************** - * * - * * - * * - * libvo Control / Callback functions * - * * - * * - * * - ****************************************************************************/ - -static void get_2ch_depth_multiplier(int depth, float *out_f1, float *out_f2) { - // How to get these values: - // The suffix i8 and i16 is for values with 8/16 bit fixed point numbers. - // The suffix f is for float, ideally in the range 0.0-1.0. - // c_i8 is a two component vector, sampled from a two channel texture. - // (c_i8.x is the low byte, c_i8.y is the high byte) - // r_f is the resulting color scalar value. - // - // c_i8 = c_f * (2^8-1) - // r_i16 = c_i8.x + c_i8.y * 2^8 - // r_f = r_i16 / (2^16-1) - // = c_f.x * (2^8-1) / (2^16-1) + c_f.y * (2^8-1) * 2^8 / (2^16-1) - // = c_f.x * ((2^8-1) / (2^16-1)) + c_f.y * (2^8 * ((2^8-1) / (2^16-1))) - // out = ((2^8-1) / (2^16-1), 2^8 * ((2^8-1) / (2^16-1))) - // The result color is r_f = dot(c_f, out). - // Same goes for other bit depth, such as 10 bit. Assuming (2^depth-1) is - // the maximum possible value at that depth, you have to scale the value - // r_i16 with it, the factor (2^16-1) in the formula above has to be - // replaced with (2^depth-1). - float factor = (float)((1 << 8) - 1) / (float)((1 << depth) - 1); - *out_f1 = factor; - *out_f2 = 256.0 * factor; -} - -static void update_colorspace(d3d_priv *priv) -{ - float coeff[3][4]; - struct mp_csp_params csp = { .colorspace = priv->colorspace }; - mp_csp_copy_equalizer_values(&csp, &priv->video_eq); - - if (priv->use_shaders) { - if (!priv->use_2ch_hack) { - csp.input_bits = priv->planes[0].bits_per_pixel; - csp.texture_bits = (csp.input_bits + 7) & ~7; - } else { - float f1, f2; - get_2ch_depth_multiplier(priv->planes[0].bits_per_pixel, &f1, &f2); - priv->d3d_depth_vector[0] = f1; - priv->d3d_depth_vector[1] = f2; - priv->d3d_depth_vector[2] = priv->d3d_depth_vector[3] = 0; - // no change - csp.input_bits = 8; - csp.texture_bits = 8; - } - - mp_get_yuv2rgb_coeffs(&csp, coeff); - for (int row = 0; row < 3; row++) { - for (int col = 0; col < 4; col++) { - priv->d3d_colormatrix.m[row][col] = coeff[row][col]; - } - } - } -} - -const char *options_help_text = "-vo direct3d command line help:\n" -"Example: -vo direct3d:disable-osd:disable-textures\n" -"Options:\n" -" prefer-stretchrect\n" -" Use IDirect3DDevice9::StretchRect over other methods if possible.\n" -" disable-stretchrect\n" -" Never render the video using IDirect3DDevice9::StretchRect.\n" -" disable-textures\n" -" Never render the video using D3D texture rendering. (Rendering with\n" -" textures + shader will still be allowed. Add disable-shaders to\n" -" completely disable video rendering with textures.)\n" -" disable-shaders\n" -" Never use shaders when rendering video.\n" -" only-8bit\n" -" Never render YUV video with more than 8 bits per component.\n" -" (Using this flag will force software conversion to 8 bit.)\n" -" disable-osd\n" -" Disable OSD rendering.\n" -" (Using this flag might force the insertion of the 'ass' video filter,\n" -" which will render the subtitles in software.)\n" -" disable-texture-align\n" -" Normally texture sizes are always aligned to 16. With this option\n" -" enabled, the video texture will always have exactly the same size as\n" -" the video itself.\n" -"Debug options. These might be incorrect, might be removed in the future, might\n" -"crash, might cause slow downs, etc. Contact the developers if you actually need\n" -"any of these for performance or proper operation.\n" -" force-power-of-2\n" -" Always force textures to power of 2, even if the device reports\n" -" non-power-of-2 texture sizes as supported.\n" -" texture-memory=N\n" -" Only affects operation with shaders/texturing enabled, and (E)OSD.\n" -" Values for N:\n" -" 0 default, will often use an additional shadow texture + copy\n" -" 1 use D3DPOOL_MANAGED\n" -" 2 use D3DPOOL_DEFAULT\n" -" 3 use D3DPOOL_SYSTEMMEM, but without shadow texture\n" -" swap-discard\n" -" Use D3DSWAPEFFECT_DISCARD, which might be faster.\n" -" Might be slower too, as it must (?) clear every frame.\n" -" exact-backbuffer\n" -" Always resize the backbuffer to window size.\n" -" no16bit-textures\n" -" Don't use textures with a 16 bit color channel for YUV formats that\n" -" use more than 8 bits per component. Instead, use D3DFMT_A8L8 textures\n" -" and compute the values sampled from the 2 channels back into one.\n" -" Might be slower, since the shader becomes slightly more complicated.\n" -" Might work better, if your drivers either don't support D3DFMT_L16,\n" -" or if either the texture unit or the shaders don't operate in at least\n" -" 16 bit precision.\n" -""; - -/** @brief libvo Callback: Preinitialize the video card. - * Preinit the hardware just enough to be queried about - * supported formats. - * - * @return 0 on success, -1 on failure - */ - -static int preinit_internal(struct vo *vo, const char *arg, bool allow_shaders) -{ - d3d_priv *priv = talloc_zero(vo, d3d_priv); - vo->priv = priv; - - *priv = (d3d_priv) { - .vo = vo, - - .opt_16bit_textures = true, - - .colorspace = MP_CSP_DETAILS_DEFAULTS, - .video_eq = { MP_CSP_EQ_CAPS_COLORMATRIX }, - }; - - for (int n = 0; n < MAX_OSD_PARTS; n++) { - struct osdpart *osd = talloc_ptrtype(priv, osd); - *osd = (struct osdpart) { - .packer = talloc_zero(osd, struct bitmap_packer), - }; - priv->osd[n] = osd; - } - - if (!allow_shaders) { - priv->opt_disable_shaders = priv->opt_disable_textures = true; - } - - const opt_t subopts[] = { - {"prefer-stretchrect", OPT_ARG_BOOL, &priv->opt_prefer_stretchrect}, - {"disable-textures", OPT_ARG_BOOL, &priv->opt_disable_textures}, - {"disable-stretchrect", OPT_ARG_BOOL, &priv->opt_disable_stretchrect}, - {"disable-shaders", OPT_ARG_BOOL, &priv->opt_disable_shaders}, - {"only-8bit", OPT_ARG_BOOL, &priv->opt_only_8bit}, - {"disable-osd", OPT_ARG_BOOL, &priv->opt_disable_osd}, - {"force-power-of-2", OPT_ARG_BOOL, &priv->opt_force_power_of_2}, - {"disable-texture-align", OPT_ARG_BOOL, &priv->opt_disable_texture_align}, - {"texture-memory", OPT_ARG_INT, &priv->opt_texture_memory}, - {"swap-discard", OPT_ARG_BOOL, &priv->opt_swap_discard}, - {"exact-backbuffer", OPT_ARG_BOOL, &priv->opt_exact_backbuffer}, - {"16bit-textures", OPT_ARG_BOOL, &priv->opt_16bit_textures}, - {NULL} - }; - if (subopt_parse(arg, subopts) != 0) { - mp_msg(MSGT_VO, MSGL_FATAL, options_help_text); - return -1; - } - - priv->d3d9_dll = LoadLibraryA("d3d9.dll"); - if (!priv->d3d9_dll) { - mp_msg(MSGT_VO, MSGL_ERR, - "<vo_direct3d>Unable to dynamically load d3d9.dll\n"); - goto err_out; - } - - priv->pDirect3DCreate9 = (void *)GetProcAddress(priv->d3d9_dll, - "Direct3DCreate9"); - if (!priv->pDirect3DCreate9) { - mp_msg(MSGT_VO, MSGL_ERR, - "<vo_direct3d>Unable to find entry point of Direct3DCreate9\n"); - goto err_out; - } - - if (!init_d3d(priv)) - goto err_out; - - /* w32_common framework call. Configures window on the screen, gets - * fullscreen dimensions and does other useful stuff. - */ - if (!vo_w32_init(vo)) { - mp_msg(MSGT_VO, MSGL_V, - "<vo_direct3d>Configuring onscreen window failed.\n"); - goto err_out; - } - - return 0; - -err_out: - uninit(vo); - return -1; -} - -static int preinit_standard(struct vo *vo, const char *arg) -{ - return preinit_internal(vo, arg, false); -} - -static int preinit_shaders(struct vo *vo, const char *arg) -{ - return preinit_internal(vo, arg, true); -} - -/** @brief libvo Callback: Handle control requests. - * @return VO_TRUE on success, VO_NOTIMPL when not implemented - */ -static int control(struct vo *vo, uint32_t request, void *data) -{ - d3d_priv *priv = vo->priv; - - switch (request) { - case VOCTRL_QUERY_FORMAT: - return query_format(priv, *(uint32_t*) data); - case VOCTRL_DRAW_IMAGE: - return d3d_upload_and_render_frame(priv, data); - case VOCTRL_FULLSCREEN: - vo_w32_fullscreen(vo); - resize_d3d(priv); - return VO_TRUE; - case VOCTRL_RESET: - return VO_NOTIMPL; - case VOCTRL_REDRAW_FRAME: - priv->is_clear_needed = 1; - d3d_draw_frame(priv); - return VO_TRUE; - case VOCTRL_SET_YUV_COLORSPACE: - priv->colorspace = *(struct mp_csp_details *)data; - update_colorspace(priv); - vo->want_redraw = true; - return VO_TRUE; - case VOCTRL_GET_YUV_COLORSPACE: - if (!priv->use_shaders) - break; // no idea what the heck D3D YUV uses - *(struct mp_csp_details *)data = priv->colorspace; - return VO_TRUE; - case VOCTRL_SET_EQUALIZER: { - if (!priv->use_shaders) - break; - struct voctrl_set_equalizer_args *args = data; - if (mp_csp_equalizer_set(&priv->video_eq, args->name, args->value) < 0) - return VO_NOTIMPL; - update_colorspace(priv); - vo->want_redraw = true; - return VO_TRUE; - } - case VOCTRL_GET_EQUALIZER: { - if (!priv->use_shaders) - break; - struct voctrl_get_equalizer_args *args = data; - return mp_csp_equalizer_get(&priv->video_eq, args->name, args->valueptr) - >= 0 ? VO_TRUE : VO_NOTIMPL; - } - case VOCTRL_ONTOP: - vo_w32_ontop(vo); - return VO_TRUE; - case VOCTRL_BORDER: - vo_w32_border(vo); - return VO_TRUE; - case VOCTRL_UPDATE_SCREENINFO: - w32_update_xinerama_info(vo); - return VO_TRUE; - case VOCTRL_SET_PANSCAN: - calc_fs_rect(priv); - return VO_TRUE; - case VOCTRL_GET_PANSCAN: - return VO_TRUE; - case VOCTRL_SCREENSHOT: { - struct voctrl_screenshot_args *args = data; - if (args->full_window) - args->out_image = get_window_screenshot(priv); - else - args->out_image = get_screenshot(priv); - return !!args->out_image; - } - } - return VO_NOTIMPL; -} - -/** @brief libvo Callback: Configre the Direct3D adapter. - * @param width Movie source width - * @param height Movie source height - * @param d_width Screen (destination) width - * @param d_height Screen (destination) height - * @param options Options bitmap - * @param format Movie colorspace format (using MPlayer's - * defines, e.g. IMGFMT_YUY2) - * @return 0 on success, VO_ERROR on failure - */ -static int config(struct vo *vo, uint32_t width, uint32_t height, - uint32_t d_width, uint32_t d_height, uint32_t options, - uint32_t format) -{ - d3d_priv *priv = vo->priv; - - /* w32_common framework call. Creates window on the screen with - * the given coordinates. - */ - if (!vo_w32_config(vo, d_width, d_height, options)) { - mp_msg(MSGT_VO, MSGL_V, "<vo_direct3d>Creating window failed.\n"); - return VO_ERROR; - } - - if ((priv->image_format != format) - || (priv->src_width != width) - || (priv->src_height != height)) - { - d3d_destroy_video_objects(priv); - - priv->src_width = width; - priv->src_height = height; - init_rendering_mode(priv, format, true); - } - - if (!resize_d3d(priv)) - return VO_ERROR; - - return 0; /* Success */ -} - -/** @brief libvo Callback: Flip next already drawn frame on the - * screen. - */ -static void flip_page(struct vo *vo) -{ - d3d_priv *priv = vo->priv; - - if (priv->d3d_device && priv->d3d_in_scene) { - if (FAILED(IDirect3DDevice9_EndScene(priv->d3d_device))) { - mp_msg(MSGT_VO, MSGL_ERR, "<vo_direct3d>EndScene failed.\n"); - } - } - priv->d3d_in_scene = false; - - RECT rect = {0, 0, vo->dwidth, vo->dheight}; - if (!priv->d3d_device || - FAILED(IDirect3DDevice9_Present(priv->d3d_device, &rect, 0, 0, 0))) { - mp_msg(MSGT_VO, MSGL_V, - "<vo_direct3d>Trying to reinitialize uncooperative video adapter.\n"); - if (!reconfigure_d3d(priv)) { - mp_msg(MSGT_VO, MSGL_V, "<vo_direct3d>Reinitialization failed.\n"); - return; - } else { - mp_msg(MSGT_VO, MSGL_V, - "<vo_direct3d>Video adapter reinitialized.\n"); - } - } -} - -/** @brief libvo Callback: Uninitializes all pointers and closes - * all D3D related stuff, - */ -static void uninit(struct vo *vo) -{ - d3d_priv *priv = vo->priv; - - mp_msg(MSGT_VO, MSGL_V, "<vo_direct3d>uninit called.\n"); - - uninit_d3d(priv); - vo_w32_uninit(vo); - if (priv->d3d9_dll) - FreeLibrary(priv->d3d9_dll); - priv->d3d9_dll = NULL; -} - -/** @brief libvo Callback: Handles video window events. - */ -static void check_events(struct vo *vo) -{ - d3d_priv *priv = vo->priv; - - int flags = vo_w32_check_events(vo); - if (flags & VO_EVENT_RESIZE) - resize_d3d(priv); - - if (flags & VO_EVENT_EXPOSE) - vo->want_redraw = true; -} - -static int draw_slice_textures(d3d_priv *priv, uint8_t *src[], int stride[], - int w, int h, int x, int y) -{ - if (!d3d_lock_video_textures(priv)) - return VO_FALSE; - - for (int n = 0; n < priv->plane_count; n++) { - struct texplane *plane = &priv->planes[n]; - - int dst_stride = plane->locked_rect.Pitch; - uint8_t *pdst = (uint8_t*)plane->locked_rect.pBits - + (y >> plane->shift_y) * dst_stride - + (x >> plane->shift_x) * plane->bytes_per_pixel; - - memcpy_pic(pdst, src[n], (w >> plane->shift_x) * plane->bytes_per_pixel, - h >> plane->shift_y, dst_stride, stride[n]); - } - - return 0; -} - -/** @brief libvo Callback: Draw slice - * @return 0 on success - */ -static int draw_slice(struct vo *vo, uint8_t *src[], int stride[], int w, int h, - int x, int y) -{ - d3d_priv *priv = vo->priv; - - if (!priv->d3d_device) - return 0; - - char *my_src; /**< Pointer to the source image */ - char *dst; /**< Pointer to the destination image */ - int uv_stride; /**< Stride of the U/V planes */ - - if (priv->use_textures) - return draw_slice_textures(priv, src, stride, w, h, x, y); - - /* Lock the offscreen surface if it's not already locked. */ - if (!priv->locked_rect.pBits) { - if (FAILED(IDirect3DSurface9_LockRect(priv->d3d_surface, - &priv->locked_rect, NULL, 0))) { - mp_msg(MSGT_VO, MSGL_V, "<vo_direct3d>Surface lock failure.\n"); - return VO_FALSE; - } - } - - uv_stride = priv->locked_rect.Pitch / 2; - - /* Copy Y */ - dst = priv->locked_rect.pBits; - dst = dst + priv->locked_rect.Pitch * y + x; - my_src = src[0]; - memcpy_pic(dst, my_src, w, h, priv->locked_rect.Pitch, stride[0]); - - w /= 2; - h /= 2; - x /= 2; - y /= 2; - - /* Copy U */ - dst = priv->locked_rect.pBits; - dst = dst + priv->locked_rect.Pitch * priv->src_height - + uv_stride * y + x; - if (priv->movie_src_fmt == MAKEFOURCC('Y','V','1','2')) - my_src = src[2]; - else - my_src = src[1]; - - memcpy_pic(dst, my_src, w, h, uv_stride, stride[1]); - - /* Copy V */ - dst = priv->locked_rect.pBits; - dst = dst + priv->locked_rect.Pitch * priv->src_height - + uv_stride * (priv->src_height / 2) + uv_stride * y + x; - if (priv->movie_src_fmt == MAKEFOURCC('Y','V','1','2')) - my_src=src[1]; - else - my_src=src[2]; - - memcpy_pic(dst, my_src, w, h, uv_stride, stride[2]); - - return 0; /* Success */ -} - -static bool get_screenshot_from_surface(d3d_priv *priv, mp_image_t *image) -{ - if (!priv->locked_rect.pBits) { - if (FAILED(IDirect3DSurface9_LockRect(priv->d3d_surface, - &priv->locked_rect, NULL, 0))) { - mp_msg(MSGT_VO, MSGL_ERR, "<vo_direct3d>Surface lock failed.\n"); - return false; - } - } - - if (image->flags & MP_IMGFLAG_PLANAR) { - char *src; - int w = priv->src_width; - int h = priv->src_height; - int swapped = priv->movie_src_fmt == MAKEFOURCC('Y','V','1','2'); - int plane1 = swapped ? 2 : 1; - int plane2 = swapped ? 1 : 2; - - int uv_stride = priv->locked_rect.Pitch / 2; - - /* Copy Y */ - src = priv->locked_rect.pBits; - memcpy_pic(image->planes[0], src, w, h, priv->locked_rect.Pitch, - image->stride[0]); - - w /= 2; - h /= 2; - - /* Copy U */ - src = priv->locked_rect.pBits; - src = src + priv->locked_rect.Pitch * priv->src_height; - - memcpy_pic(image->planes[plane1], src, w, h, uv_stride, - image->stride[1]); - - /* Copy V */ - src = priv->locked_rect.pBits; - src = src + priv->locked_rect.Pitch * priv->src_height - + uv_stride * (priv->src_height / 2); - - memcpy_pic(image->planes[plane2], src, w, h, uv_stride, - image->stride[2]); - } else { - // packed YUV or RGB - memcpy_pic(image->planes[0], priv->locked_rect.pBits, image->stride[0], - image->height, priv->locked_rect.Pitch, image->stride[0]); - } - - d3d_unlock_video_objects(priv); - return true; -} - -static bool get_screenshot_from_texture(d3d_priv *priv, mp_image_t *image) -{ - if (!d3d_lock_video_textures(priv)) { - d3d_unlock_video_objects(priv); - return false; - } - - assert(image->num_planes == priv->plane_count); - - for (int n = 0; n < priv->plane_count; n++) { - struct texplane *plane = &priv->planes[n]; - - int width = priv->src_width >> plane->shift_x; - int height = priv->src_height >> plane->shift_y; - - memcpy_pic(image->planes[n], plane->locked_rect.pBits, - width * plane->bytes_per_pixel, height, - image->stride[n], plane->locked_rect.Pitch); - } - - return true; -} - -static mp_image_t *get_screenshot(d3d_priv *priv) -{ - if (!priv->d3d_device) - return NULL; - - mp_image_t *image = alloc_mpi(priv->src_width, priv->src_height, - priv->image_format); - - bool res; - - if (priv->use_textures) - res = get_screenshot_from_texture(priv, image); - else - res = get_screenshot_from_surface(priv, image); - - if (!res) { - free_mp_image(image); - return NULL; - } - - image->display_w = priv->vo->aspdat.prew; - image->display_h = priv->vo->aspdat.preh; - - mp_image_set_colorspace_details(image, &priv->colorspace); - - return image; -} - -static mp_image_t *get_window_screenshot(d3d_priv *priv) -{ - D3DDISPLAYMODE mode; - mp_image_t *image = NULL; - RECT window_rc; - RECT screen_rc; - RECT visible; - POINT pt; - D3DLOCKED_RECT locked_rect; - int width, height; - - if (FAILED(IDirect3DDevice9_GetDisplayMode(priv->d3d_device, 0, &mode))) { - mp_msg(MSGT_VO,MSGL_ERR, "<vo_direct3d>GetDisplayMode failed.\n"); - goto error_exit; - } - - IDirect3DSurface9 *surface = NULL; - if (FAILED(IDirect3DDevice9_CreateOffscreenPlainSurface(priv->d3d_device, - mode.Width, mode.Height, D3DFMT_A8R8G8B8, D3DPOOL_SYSTEMMEM, &surface, - NULL))) - { - mp_msg(MSGT_VO,MSGL_ERR, "<vo_direct3d>Couldn't create surface.\n"); - goto error_exit; - } - - if (FAILED(IDirect3DDevice9_GetFrontBufferData(priv->d3d_device, 0, - surface))) - { - mp_msg(MSGT_VO,MSGL_ERR, "<vo_direct3d>Couldn't copy frontbuffer.\n"); - goto error_exit; - } - - GetClientRect(priv->vo->w32->window, &window_rc); - pt = (POINT) { 0, 0 }; - ClientToScreen(priv->vo->w32->window, &pt); - window_rc.left = pt.x; - window_rc.top = pt.y; - window_rc.right += window_rc.left; - window_rc.bottom += window_rc.top; - - screen_rc = (RECT) { 0, 0, mode.Width, mode.Height }; - - if (!IntersectRect(&visible, &screen_rc, &window_rc)) - goto error_exit; - width = visible.right - visible.left; - height = visible.bottom - visible.top; - if (width < 1 || height < 1) - goto error_exit; - - image = alloc_mpi(width, height, IMGFMT_BGR32); - - IDirect3DSurface9_LockRect(surface, &locked_rect, NULL, 0); - - memcpy_pic(image->planes[0], (char*)locked_rect.pBits + visible.top * - locked_rect.Pitch + visible.left * 4, width * 4, height, - image->stride[0], locked_rect.Pitch); - - IDirect3DSurface9_UnlockRect(surface); - IDirect3DSurface9_Release(surface); - - return image; - -error_exit: - if (image) - free_mp_image(image); - if (surface) - IDirect3DSurface9_Release(surface); - return NULL; -} - -static bool upload_osd(d3d_priv *priv, struct osdpart *osd, - struct sub_bitmaps *imgs) -{ - D3DFORMAT fmt = osd_fmt_table[imgs->format]; - - osd->packer->w_max = priv->max_texture_width; - osd->packer->h_max = priv->max_texture_height; - - osd->packer->padding = imgs->scaled; // assume 2x2 filter on scaling - int r = packer_pack_from_subbitmaps(osd->packer, imgs); - if (r < 0) { - mp_msg(MSGT_VO, MSGL_ERR, "<vo_direct3d>OSD bitmaps do not fit on " - "a surface with the maximum supported size %dx%d.\n", - osd->packer->w_max, osd->packer->h_max); - return false; - } - - if (osd->packer->w > osd->texture.tex_w - || osd->packer->h > osd->texture.tex_h - || osd->format != imgs->format) - { - osd->format = imgs->format; - - int new_w = osd->packer->w; - int new_h = osd->packer->h; - d3d_fix_texture_size(priv, &new_w, &new_h); - - mp_msg(MSGT_VO, MSGL_DBG2, "<vo_direct3d>reallocate OSD surface.\n"); - - d3dtex_release(priv, &osd->texture); - d3dtex_allocate(priv, &osd->texture, fmt, new_w, new_h); - - if (!osd->texture.system) - return false; // failed to allocate - } - - struct pos bb[2]; - packer_get_bb(osd->packer, bb); - RECT dirty_rc = { bb[0].x, bb[0].y, bb[1].x, bb[1].y }; - - D3DLOCKED_RECT locked_rect; - - if (FAILED(IDirect3DTexture9_LockRect(osd->texture.system, 0, &locked_rect, - &dirty_rc, 0))) - { - mp_msg(MSGT_VO,MSGL_ERR, "<vo_direct3d>OSD texture lock failed.\n"); - return false; - } - - int ps = fmt == D3DFMT_A8 ? 1 : 4; - packer_copy_subbitmaps(osd->packer, imgs, locked_rect.pBits, ps, - locked_rect.Pitch); - - if (FAILED(IDirect3DTexture9_UnlockRect(osd->texture.system, 0))) { - mp_msg(MSGT_VO,MSGL_ERR, "<vo_direct3d>OSD texture unlock failed.\n"); - return false; - } - - return d3dtex_update(priv, &osd->texture); -} - -static struct osdpart *generate_osd(d3d_priv *priv, struct sub_bitmaps *imgs) -{ - if (imgs->num_parts == 0 || !osd_fmt_table[imgs->format]) - return NULL; - - struct osdpart *osd = priv->osd[imgs->render_index]; - - if (imgs->bitmap_pos_id != osd->bitmap_pos_id) { - if (imgs->bitmap_id != osd->bitmap_id) { - if (!upload_osd(priv, osd, imgs)) - osd->packer->count = 0; - } - - osd->bitmap_id = imgs->bitmap_id; - osd->bitmap_pos_id = imgs->bitmap_pos_id; - osd->num_vertices = 0; - } - - return osd->packer->count ? osd : NULL; -} - -static D3DCOLOR ass_to_d3d_color(uint32_t color) -{ - uint32_t r = (color >> 24) & 0xff; - uint32_t g = (color >> 16) & 0xff; - uint32_t b = (color >> 8) & 0xff; - uint32_t a = 0xff - (color & 0xff); - return D3DCOLOR_ARGB(a, r, g, b); -} - -static void draw_osd_cb(void *ctx, struct sub_bitmaps *imgs) -{ - d3d_priv *priv = ctx; - - struct osdpart *osd = generate_osd(priv, imgs); - if (!osd) - return; - - if (osd->packer->count && !osd->num_vertices) { - // We need 2 primitives per quad which makes 6 vertices (we could reduce - // the number of vertices by using an indexed vertex array, but it's - // probably not worth doing) - osd->num_vertices = osd->packer->count * 6; - osd->vertices = talloc_realloc(osd, osd->vertices, vertex_osd, - osd->num_vertices); - - float tex_w = osd->texture.tex_w; - float tex_h = osd->texture.tex_h; - - for (int n = 0; n < osd->packer->count; n++) { - struct sub_bitmap *b = &imgs->parts[n]; - struct pos p = osd->packer->result[n]; - - D3DCOLOR color = imgs->format == SUBBITMAP_LIBASS - ? ass_to_d3d_color(b->libass.color) - : D3DCOLOR_ARGB(255, 255, 255, 255); - - float x0 = b->x; - float y0 = b->y; - float x1 = b->x + b->dw; - float y1 = b->y + b->dh; - float tx0 = p.x / tex_w; - float ty0 = p.y / tex_h; - float tx1 = (p.x + b->w) / tex_w; - float ty1 = (p.y + b->h) / tex_h; - - vertex_osd *v = &osd->vertices[n * 6]; - v[0] = (vertex_osd) { x0, y0, 0, color, tx0, ty0 }; - v[1] = (vertex_osd) { x1, y0, 0, color, tx1, ty0 }; - v[2] = (vertex_osd) { x0, y1, 0, color, tx0, ty1 }; - v[3] = (vertex_osd) { x1, y1, 0, color, tx1, ty1 }; - v[4] = v[2]; - v[5] = v[1]; - } - } - - d3d_begin_scene(priv); - - IDirect3DDevice9_SetRenderState(priv->d3d_device, - D3DRS_ALPHABLENDENABLE, TRUE); - - IDirect3DDevice9_SetTexture(priv->d3d_device, 0, - d3dtex_get_render_texture(priv, &osd->texture)); - - if (imgs->format == SUBBITMAP_LIBASS) { - // do not use the color value from the A8 texture, because that is black - IDirect3DDevice9_SetRenderState(priv->d3d_device,D3DRS_TEXTUREFACTOR, - 0xFFFFFFFF); - IDirect3DDevice9_SetTextureStageState(priv->d3d_device,0, - D3DTSS_COLORARG1, D3DTA_TFACTOR); - - IDirect3DDevice9_SetTextureStageState(priv->d3d_device, 0, - D3DTSS_ALPHAOP, D3DTOP_MODULATE); - } else { - IDirect3DDevice9_SetRenderState(priv->d3d_device, D3DRS_SRCBLEND, - D3DBLEND_ONE); - } - - IDirect3DDevice9_SetFVF(priv->d3d_device, D3DFVF_OSD_VERTEX); - IDirect3DDevice9_DrawPrimitiveUP(priv->d3d_device, D3DPT_TRIANGLELIST, - osd->num_vertices / 3, - osd->vertices, sizeof(vertex_osd)); - - IDirect3DDevice9_SetTextureStageState(priv->d3d_device,0, - D3DTSS_COLORARG1, D3DTA_TEXTURE); - IDirect3DDevice9_SetTextureStageState(priv->d3d_device, 0, - D3DTSS_ALPHAOP, D3DTOP_SELECTARG1); - IDirect3DDevice9_SetRenderState(priv->d3d_device, - D3DRS_SRCBLEND, D3DBLEND_SRCALPHA); - - IDirect3DDevice9_SetTexture(priv->d3d_device, 0, NULL); - - IDirect3DDevice9_SetRenderState(priv->d3d_device, - D3DRS_ALPHABLENDENABLE, FALSE); -} - - -static void draw_osd(struct vo *vo, struct osd_state *osd) -{ - d3d_priv *priv = vo->priv; - if (!priv->d3d_device) - return; - - osd_draw(osd, priv->osd_res, osd->vo_pts, 0, osd_fmt_supported, - draw_osd_cb, priv); -} - -#define AUTHOR "Georgi Petrov (gogothebee) <gogothebee@gmail.com> and others" - -const struct vo_driver video_out_direct3d = { - .is_new = true, - .info = &(const vo_info_t) { - "Direct3D 9 Renderer", - "direct3d", - AUTHOR, - "" - }, - .preinit = preinit_standard, - .config = config, - .control = control, - .draw_slice = draw_slice, - .draw_osd = draw_osd, - .flip_page = flip_page, - .check_events = check_events, - .uninit = uninit, -}; - -const struct vo_driver video_out_direct3d_shaders = { - .is_new = true, - .info = &(const vo_info_t) { - "Direct3D 9 Renderer (using shaders for YUV conversion)", - "direct3d_shaders", - AUTHOR, - "" - }, - .preinit = preinit_shaders, - .config = config, - .control = control, - .draw_slice = draw_slice, - .draw_osd = draw_osd, - .flip_page = flip_page, - .check_events = check_events, - .uninit = uninit, -}; diff --git a/libvo/vo_image.c b/libvo/vo_image.c deleted file mode 100644 index 7f80a16f35..0000000000 --- a/libvo/vo_image.c +++ /dev/null @@ -1,198 +0,0 @@ -/* - * 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, see <http://www.gnu.org/licenses/>. - */ - -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <math.h> -#include <stdbool.h> -#include <sys/stat.h> - -#include <libswscale/swscale.h> - -#include "config.h" -#include "bstr.h" -#include "osdep/io.h" -#include "path.h" -#include "talloc.h" -#include "mp_msg.h" -#include "libvo/video_out.h" -#include "libvo/csputils.h" -#include "libmpcodecs/vfcap.h" -#include "libmpcodecs/mp_image.h" -#include "fmt-conversion.h" -#include "image_writer.h" -#include "m_config.h" -#include "m_option.h" - -struct priv { - struct image_writer_opts *opts; - char *outdir; - - int frame; - - uint32_t d_width; - uint32_t d_height; - - struct mp_csp_details colorspace; -}; - -static bool checked_mkdir(const char *buf) -{ - mp_msg(MSGT_VO, MSGL_INFO, "[vo_image] Creating output directory '%s'...\n", - buf); - if (mkdir(buf, 0755) < 0) { - char *errstr = strerror(errno); - if (errno == EEXIST) { - struct stat stat_p; - if (mp_stat(buf, &stat_p ) == 0 && S_ISDIR(stat_p.st_mode)) - return true; - } - mp_msg(MSGT_VO, MSGL_ERR, "[vo_image] Error creating output directory" - ": %s\n", errstr); - return false; - } - return true; -} - -static int config(struct vo *vo, uint32_t width, uint32_t height, - uint32_t d_width, uint32_t d_height, uint32_t flags, - uint32_t format) -{ - struct priv *p = vo->priv; - - p->d_width = d_width; - p->d_height = d_height; - - if (p->outdir && vo->config_count < 1) - if (!checked_mkdir(p->outdir)) - return -1; - - return 0; -} - -static void check_events(struct vo *vo) -{ -} - -static void draw_osd(struct vo *vo, struct osd_state *osd) -{ -} - -static void flip_page(struct vo *vo) -{ -} - -static uint32_t draw_image(struct vo *vo, mp_image_t *mpi) -{ - struct priv *p = vo->priv; - - mp_image_t img = *mpi; - img.width = p->d_width; - img.height = p->d_height; - mp_image_set_colorspace_details(&img, &p->colorspace); - - void *t = talloc_new(NULL); - char *filename = talloc_asprintf(t, "%08d.%s", p->frame, - image_writer_file_ext(p->opts)); - - if (p->outdir && strlen(p->outdir)) - filename = mp_path_join(t, bstr0(p->outdir), bstr0(filename)); - - mp_msg(MSGT_VO, MSGL_STATUS, "\nSaving %s\n", filename); - write_image(&img, p->opts, filename); - - talloc_free(t); - - (p->frame)++; - - return VO_TRUE; -} - -static int query_format(struct vo *vo, uint32_t fmt) -{ - enum PixelFormat av_format = imgfmt2pixfmt(fmt); - - // NOTE: accept everything that can be converted by swscale. screenshot.c - // always wants RGB (at least for now), but it probably doesn't matter - // whether we or screenshot.c do the conversion. - if (av_format != PIX_FMT_NONE && sws_isSupportedInput(av_format)) - return VFCAP_CSP_SUPPORTED | VFCAP_CSP_SUPPORTED_BY_HW | - VFCAP_HWSCALE_UP | VFCAP_HWSCALE_DOWN; - return 0; -} - -static void uninit(struct vo *vo) -{ -} - -static int preinit(struct vo *vo, const char *arg) -{ - return 0; -} - -static int control(struct vo *vo, uint32_t request, void *data) -{ - struct priv *p = vo->priv; - - switch (request) { - case VOCTRL_QUERY_FORMAT: - return query_format(vo, *(uint32_t *)data); - case VOCTRL_DRAW_IMAGE: - return draw_image(vo, data); - case VOCTRL_SET_YUV_COLORSPACE: - p->colorspace = *(struct mp_csp_details *)data; - return true; - case VOCTRL_GET_YUV_COLORSPACE: - *(struct mp_csp_details *)data = p->colorspace; - return true; - // prevent random frame stepping by frontend - case VOCTRL_REDRAW_FRAME: - return true; - } - return VO_NOTIMPL; -} - -#undef OPT_BASE_STRUCT -#define OPT_BASE_STRUCT struct priv - -const struct vo_driver video_out_image = -{ - .is_new = true, - .info = &(const vo_info_t) { - "Write video frames to image files", - "image", - "wm4", - "" - }, - .priv_size = sizeof(struct priv), - .priv_defaults = &(const struct priv) { - .colorspace = MP_CSP_DETAILS_DEFAULTS, - }, - .options = (const struct m_option[]) { - OPT_SUBSTRUCT(opts, image_writer_conf, M_OPT_MERGE), - OPT_STRING("outdir", outdir, 0), - {0}, - }, - .preinit = preinit, - .config = config, - .control = control, - .draw_osd = draw_osd, - .flip_page = flip_page, - .check_events = check_events, - .uninit = uninit, -}; diff --git a/libvo/vo_lavc.c b/libvo/vo_lavc.c deleted file mode 100644 index b86cd76509..0000000000 --- a/libvo/vo_lavc.c +++ /dev/null @@ -1,553 +0,0 @@ -/* - * video encoding using libavformat - * Copyright (C) 2010 Nicolas George <george@nsup.org> - * Copyright (C) 2011 Rudolf Polzer <divVerent@xonotic.org> - * - * 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 "mpcommon.h" -#include "options.h" -#include "fmt-conversion.h" -#include "libmpcodecs/mp_image.h" -#include "libmpcodecs/vfcap.h" -#include "subopt-helper.h" -#include "talloc.h" -#include "video_out.h" - -#include "encode_lavc.h" - -#include "sub/sub.h" -#include "sub/dec_sub.h" - -struct priv { - uint8_t *buffer; - size_t buffer_size; - AVStream *stream; - int have_first_packet; - - int harddup; - - double lastpts; - int64_t lastipts; - int64_t lastframeipts; - double expected_next_pts; - mp_image_t *lastimg; - int lastimg_wants_osd; - int lastdisplaycount; - - AVRational worst_time_base; - int worst_time_base_is_stream; - - struct mp_csp_details colorspace; -}; - -static int preinit(struct vo *vo, const char *arg) -{ - struct priv *vc; - if (!encode_lavc_available(vo->encode_lavc_ctx)) { - mp_msg(MSGT_ENCODE, MSGL_ERR, - "vo-lavc: the option -o (output file) must be specified\n"); - return -1; - } - vo->priv = talloc_zero(vo, struct priv); - vc = vo->priv; - vc->harddup = vo->encode_lavc_ctx->options->harddup; - vc->colorspace = (struct mp_csp_details) MP_CSP_DETAILS_DEFAULTS; - return 0; -} - -static void draw_image(struct vo *vo, mp_image_t *mpi, double pts); -static void uninit(struct vo *vo) -{ - struct priv *vc = vo->priv; - if (!vc) - return; - - if (vc->lastipts >= 0 && vc->stream) - draw_image(vo, NULL, MP_NOPTS_VALUE); - - if (vc->lastimg) { - // palette hack - if (vc->lastimg->imgfmt == IMGFMT_RGB8 - || vc->lastimg->imgfmt == IMGFMT_BGR8) - vc->lastimg->planes[1] = NULL; - free_mp_image(vc->lastimg); - vc->lastimg = NULL; - } - - vo->priv = NULL; -} - -static int config(struct vo *vo, uint32_t width, uint32_t height, - uint32_t d_width, uint32_t d_height, uint32_t flags, - uint32_t format) -{ - struct priv *vc = vo->priv; - enum PixelFormat pix_fmt = imgfmt2pixfmt(format); - AVRational display_aspect_ratio, image_aspect_ratio; - AVRational aspect; - - if (!vc) - return -1; - - display_aspect_ratio.num = d_width; - display_aspect_ratio.den = d_height; - image_aspect_ratio.num = width; - image_aspect_ratio.den = height; - aspect = av_div_q(display_aspect_ratio, image_aspect_ratio); - - if (vc->stream) { - /* NOTE: - * in debug builds we get a "comparison between signed and unsigned" - * warning here. We choose to ignore that; just because ffmpeg currently - * uses a plain 'int' for these struct fields, it doesn't mean it always - * will */ - if (width == vc->stream->codec->width && - height == vc->stream->codec->height) { - if (aspect.num != vc->stream->codec->sample_aspect_ratio.num || - aspect.den != vc->stream->codec->sample_aspect_ratio.den) { - /* aspect-only changes are not critical */ - mp_msg(MSGT_ENCODE, MSGL_WARN, "vo-lavc: unsupported pixel aspect " - "ratio change from %d:%d to %d:%d\n", - vc->stream->codec->sample_aspect_ratio.num, - vc->stream->codec->sample_aspect_ratio.den, - aspect.num, aspect.den); - } - return 0; - } - - /* FIXME Is it possible with raw video? */ - mp_msg(MSGT_ENCODE, MSGL_ERR, - "vo-lavc: resolution changes not supported.\n"); - goto error; - } - - vc->lastipts = MP_NOPTS_VALUE; - vc->lastframeipts = MP_NOPTS_VALUE; - - if (pix_fmt == PIX_FMT_NONE) - goto error; /* imgfmt2pixfmt already prints something */ - - vc->stream = encode_lavc_alloc_stream(vo->encode_lavc_ctx, - AVMEDIA_TYPE_VIDEO); - vc->stream->sample_aspect_ratio = vc->stream->codec->sample_aspect_ratio = - aspect; - vc->stream->codec->width = width; - vc->stream->codec->height = height; - vc->stream->codec->pix_fmt = pix_fmt; - - encode_lavc_set_csp(vo->encode_lavc_ctx, vc->stream, vc->colorspace.format); - encode_lavc_set_csp_levels(vo->encode_lavc_ctx, vc->stream, vc->colorspace.levels_out); - - if (encode_lavc_open_codec(vo->encode_lavc_ctx, vc->stream) < 0) - goto error; - - vc->colorspace.format = encode_lavc_get_csp(vo->encode_lavc_ctx, vc->stream); - vc->colorspace.levels_out = encode_lavc_get_csp_levels(vo->encode_lavc_ctx, vc->stream); - - vc->buffer_size = 6 * width * height + 200; - if (vc->buffer_size < FF_MIN_BUFFER_SIZE) - vc->buffer_size = FF_MIN_BUFFER_SIZE; - if (vc->buffer_size < sizeof(AVPicture)) - vc->buffer_size = sizeof(AVPicture); - - vc->buffer = talloc_size(vc, vc->buffer_size); - - vc->lastimg = alloc_mpi(width, height, format); - - // palette hack - if (vc->lastimg->imgfmt == IMGFMT_RGB8 || - vc->lastimg->imgfmt == IMGFMT_BGR8) - vc->lastimg->planes[1] = talloc_zero_size(vc, 1024); - - return 0; - -error: - uninit(vo); - return -1; -} - -static int query_format(struct vo *vo, uint32_t format) -{ - enum PixelFormat pix_fmt = imgfmt2pixfmt(format); - - if (!vo->encode_lavc_ctx) - return 0; - - if (!encode_lavc_supports_pixfmt(vo->encode_lavc_ctx, pix_fmt)) - return 0; - - return - VFCAP_CSP_SUPPORTED | - // we can do it - VFCAP_CSP_SUPPORTED_BY_HW | - // we don't convert colorspaces here - VFCAP_OSD | - // we have OSD - VOCAP_NOSLICES; - // we don't use slices -} - -static void write_packet(struct vo *vo, int size, AVPacket *packet) -{ - struct priv *vc = vo->priv; - - if (size < 0) { - mp_msg(MSGT_ENCODE, MSGL_ERR, "vo-lavc: error encoding\n"); - return; - } - - if (size > 0) { - packet->stream_index = vc->stream->index; - if (packet->pts != AV_NOPTS_VALUE) { - packet->pts = av_rescale_q(packet->pts, - vc->stream->codec->time_base, - vc->stream->time_base); - } else { - mp_msg(MSGT_ENCODE, MSGL_WARN, "vo-lavc: codec did not provide pts\n"); - packet->pts = av_rescale_q(vc->lastipts, vc->worst_time_base, - vc->stream->time_base); - } - if (packet->dts != AV_NOPTS_VALUE) { - packet->dts = av_rescale_q(packet->dts, - vc->stream->codec->time_base, - vc->stream->time_base); - } - if (packet->duration > 0) { - packet->duration = av_rescale_q(packet->duration, - vc->stream->codec->time_base, - vc->stream->time_base); - } else { - // HACK: libavformat calculates dts wrong if the initial packet - // duration is not set, but ONLY if the time base is "high" and if we - // have b-frames! - if (!packet->duration) - if (!vc->have_first_packet) - if (vc->stream->codec->has_b_frames - || vc->stream->codec->max_b_frames) - if (vc->stream->time_base.num * 1000LL <= - vc->stream->time_base.den) - packet->duration = FFMAX(1, av_rescale_q(1, - vc->stream->codec->time_base, vc->stream->time_base)); - } - - if (encode_lavc_write_frame(vo->encode_lavc_ctx, packet) < 0) { - mp_msg(MSGT_ENCODE, MSGL_ERR, "vo-lavc: error writing\n"); - return; - } - - vc->have_first_packet = 1; - } -} - -static int encode_video(struct vo *vo, AVFrame *frame, AVPacket *packet) -{ - struct priv *vc = vo->priv; - if (encode_lavc_oformat_flags(vo->encode_lavc_ctx) & AVFMT_RAWPICTURE) { - if (!frame) - return 0; - memcpy(vc->buffer, frame, sizeof(AVPicture)); - mp_msg(MSGT_ENCODE, MSGL_DBG2, "vo-lavc: got pts %f\n", - frame->pts * (double) vc->stream->codec->time_base.num / - (double) vc->stream->codec->time_base.den); - packet->size = sizeof(AVPicture); - return packet->size; - } else { - int got_packet = 0; - int status = avcodec_encode_video2(vc->stream->codec, packet, - frame, &got_packet); - int size = (status < 0) ? status : got_packet ? packet->size : 0; - - if (frame) - mp_msg(MSGT_ENCODE, MSGL_DBG2, "vo-lavc: got pts %f; out size: %d\n", - frame->pts * (double) vc->stream->codec->time_base.num / - (double) vc->stream->codec->time_base.den, size); - - encode_lavc_write_stats(vo->encode_lavc_ctx, vc->stream); - return size; - } -} - -static void draw_image(struct vo *vo, mp_image_t *mpi, double pts) -{ - struct priv *vc = vo->priv; - struct encode_lavc_context *ectx = vo->encode_lavc_ctx; - int i, size; - AVFrame *frame; - AVCodecContext *avc; - int64_t frameipts; - double nextpts; - - if (!vc) - return; - if (!encode_lavc_start(ectx)) { - mp_msg(MSGT_ENCODE, MSGL_WARN, "vo-lavc: NOTE: skipped initial video frame (probably because audio is not there yet)\n"); - return; - } - if (pts == MP_NOPTS_VALUE) { - if (mpi) - mp_msg(MSGT_ENCODE, MSGL_WARN, "vo-lavc: frame without pts, please report; synthesizing pts instead\n"); - pts = vc->expected_next_pts; - } - - avc = vc->stream->codec; - - if (vc->worst_time_base.den == 0) { - //if (avc->time_base.num / avc->time_base.den >= vc->stream->time_base.num / vc->stream->time_base.den) - if (avc->time_base.num * (double) vc->stream->time_base.den >= - vc->stream->time_base.num * (double) avc->time_base.den) { - mp_msg(MSGT_ENCODE, MSGL_V, "vo-lavc: NOTE: using codec time base " - "(%d/%d) for frame dropping; the stream base (%d/%d) is " - "not worse.\n", (int)avc->time_base.num, - (int)avc->time_base.den, (int)vc->stream->time_base.num, - (int)vc->stream->time_base.den); - vc->worst_time_base = avc->time_base; - vc->worst_time_base_is_stream = 0; - } else { - mp_msg(MSGT_ENCODE, MSGL_WARN, "vo-lavc: NOTE: not using codec time " - "base (%d/%d) for frame dropping; the stream base (%d/%d) " - "is worse.\n", (int)avc->time_base.num, - (int)avc->time_base.den, (int)vc->stream->time_base.num, - (int)vc->stream->time_base.den); - vc->worst_time_base = vc->stream->time_base; - vc->worst_time_base_is_stream = 1; - } - - // NOTE: we use the following "axiom" of av_rescale_q: - // if time base A is worse than time base B, then - // av_rescale_q(av_rescale_q(x, A, B), B, A) == x - // this can be proven as long as av_rescale_q rounds to nearest, which - // it currently does - - // av_rescale_q(x, A, B) * B = "round x*A to nearest multiple of B" - // and: - // av_rescale_q(av_rescale_q(x, A, B), B, A) * A - // == "round av_rescale_q(x, A, B)*B to nearest multiple of A" - // == "round 'round x*A to nearest multiple of B' to nearest multiple of A" - // - // assume this fails. Then there is a value of x*A, for which the - // nearest multiple of B is outside the range [(x-0.5)*A, (x+0.5)*A[. - // Absurd, as this range MUST contain at least one multiple of B. - } - - double timeunit = (double)vc->worst_time_base.num / vc->worst_time_base.den; - - double outpts; - if (ectx->options->rawts) - outpts = pts; - else if (ectx->options->copyts) { - // fix the discontinuity pts offset - nextpts = pts; - if (ectx->discontinuity_pts_offset == MP_NOPTS_VALUE) { - ectx->discontinuity_pts_offset = ectx->next_in_pts - nextpts; - } - else if (fabs(nextpts + ectx->discontinuity_pts_offset - ectx->next_in_pts) > 30) { - mp_msg(MSGT_ENCODE, MSGL_WARN, - "vo-lavc: detected an unexpected discontinuity (pts jumped by " - "%f seconds)\n", - nextpts + ectx->discontinuity_pts_offset - ectx->next_in_pts); - ectx->discontinuity_pts_offset = ectx->next_in_pts - nextpts; - } - - outpts = pts + ectx->discontinuity_pts_offset; - } - else { - // adjust pts by knowledge of audio pts vs audio playback time - double duration = 0; - if (ectx->last_video_in_pts != MP_NOPTS_VALUE) - duration = pts - ectx->last_video_in_pts; - if (duration < 0) - duration = timeunit; // XXX warn about discontinuity? - outpts = vc->lastpts + duration; - if (ectx->audio_pts_offset != MP_NOPTS_VALUE) { - double adj = outpts - pts - ectx->audio_pts_offset; - adj = FFMIN(adj, duration * 0.1); - adj = FFMAX(adj, -duration * 0.1); - outpts -= adj; - } - } - vc->lastpts = outpts; - ectx->last_video_in_pts = pts; - frameipts = floor((outpts + encode_lavc_getoffset(ectx, vc->stream)) - / timeunit + 0.5); - - // calculate expected pts of next video frame - vc->expected_next_pts = pts + timeunit; - - if (!ectx->options->rawts && ectx->options->copyts) { - // set next allowed output pts value - nextpts = vc->expected_next_pts + ectx->discontinuity_pts_offset; - if (nextpts > ectx->next_in_pts) - ectx->next_in_pts = nextpts; - } - - // never-drop mode - if (ectx->options->neverdrop && frameipts <= vc->lastipts) { - mp_msg(MSGT_ENCODE, MSGL_INFO, "vo-lavc: -oneverdrop increased pts by %d\n", - (int) (vc->lastipts - frameipts + 1)); - frameipts = vc->lastipts + 1; - vc->lastpts = frameipts * timeunit - encode_lavc_getoffset(ectx, vc->stream); - } - - if (vc->lastipts != MP_NOPTS_VALUE) { - frame = avcodec_alloc_frame(); - - // we have a valid image in lastimg - while (vc->lastipts < frameipts) { - int64_t thisduration = vc->harddup ? 1 : (frameipts - vc->lastipts); - AVPacket packet; - - avcodec_get_frame_defaults(frame); - - // this is a nop, unless the worst time base is the STREAM time base - frame->pts = av_rescale_q(vc->lastipts, vc->worst_time_base, - avc->time_base); - - for (i = 0; i < 4; i++) { - frame->data[i] = vc->lastimg->planes[i]; - frame->linesize[i] = vc->lastimg->stride[i]; - } - frame->quality = avc->global_quality; - - av_init_packet(&packet); - packet.data = vc->buffer; - packet.size = vc->buffer_size; - size = encode_video(vo, frame, &packet); - write_packet(vo, size, &packet); - - vc->lastipts += thisduration; - ++vc->lastdisplaycount; - } - - avcodec_free_frame(&frame); - } - - if (!mpi) { - // finish encoding - do { - AVPacket packet; - av_init_packet(&packet); - packet.data = vc->buffer; - packet.size = vc->buffer_size; - size = encode_video(vo, NULL, &packet); - write_packet(vo, size, &packet); - } while (size > 0); - } else { - if (frameipts >= vc->lastframeipts) { - if (vc->lastframeipts != MP_NOPTS_VALUE && vc->lastdisplaycount != 1) - mp_msg(MSGT_ENCODE, MSGL_INFO, - "vo-lavc: Frame at pts %d got displayed %d times\n", - (int) vc->lastframeipts, vc->lastdisplaycount); - copy_mpi(vc->lastimg, mpi); - vc->lastimg_wants_osd = true; - - // palette hack - if (vc->lastimg->imgfmt == IMGFMT_RGB8 || - vc->lastimg->imgfmt == IMGFMT_BGR8) - memcpy(vc->lastimg->planes[1], mpi->planes[1], 1024); - - vc->lastframeipts = vc->lastipts = frameipts; - if (ectx->options->rawts && vc->lastipts < 0) { - mp_msg(MSGT_ENCODE, MSGL_ERR, "vo-lavc: why does this happen? DEBUG THIS! vc->lastipts = %lld\n", (long long) vc->lastipts); - vc->lastipts = -1; - } - vc->lastdisplaycount = 0; - } else { - mp_msg(MSGT_ENCODE, MSGL_INFO, "vo-lavc: Frame at pts %d got dropped " - "entirely because pts went backwards\n", (int) frameipts); - vc->lastimg_wants_osd = false; - } - } -} - -static void flip_page_timed(struct vo *vo, unsigned int pts_us, int duration) -{ -} - -static void check_events(struct vo *vo) -{ -} - -static void draw_osd(struct vo *vo, struct osd_state *osd) -{ - struct priv *vc = vo->priv; - - if (vc->lastimg && vc->lastimg_wants_osd) { - struct aspect_data asp = vo->aspdat; - double sar = (double)asp.orgw / asp.orgh; - double dar = (double)asp.prew / asp.preh; - - struct mp_osd_res dim = { - .w = asp.orgw, - .h = asp.orgh, - .display_par = sar / dar, - .video_par = dar / sar, - }; - - mp_image_set_colorspace_details(vc->lastimg, &vc->colorspace); - - osd_draw_on_image(osd, dim, osd->vo_pts, OSD_DRAW_SUB_ONLY, vc->lastimg); - } -} - -static int control(struct vo *vo, uint32_t request, void *data) -{ - struct priv *vc = vo->priv; - switch (request) { - case VOCTRL_QUERY_FORMAT: - return query_format(vo, *((uint32_t *)data)); - case VOCTRL_DRAW_IMAGE: - draw_image(vo, (mp_image_t *)data, vo->next_pts); - return 0; - case VOCTRL_SET_YUV_COLORSPACE: - vc->colorspace = *(struct mp_csp_details *)data; - if (vc->stream) { - encode_lavc_set_csp(vo->encode_lavc_ctx, vc->stream, vc->colorspace.format); - encode_lavc_set_csp_levels(vo->encode_lavc_ctx, vc->stream, vc->colorspace.levels_out); - vc->colorspace.format = encode_lavc_get_csp(vo->encode_lavc_ctx, vc->stream); - vc->colorspace.levels_out = encode_lavc_get_csp_levels(vo->encode_lavc_ctx, vc->stream); - } - return 1; - case VOCTRL_GET_YUV_COLORSPACE: - *(struct mp_csp_details *)data = vc->colorspace; - return 1; - } - return VO_NOTIMPL; -} - -const struct vo_driver video_out_lavc = { - .is_new = true, - .buffer_frames = false, - .info = &(const struct vo_info_s){ - "video encoding using libavcodec", - "lavc", - "Nicolas George <george@nsup.org>, Rudolf Polzer <divVerent@xonotic.org>", - "" - }, - .preinit = preinit, - .config = config, - .control = control, - .uninit = uninit, - .check_events = check_events, - .draw_osd = draw_osd, - .flip_page_timed = flip_page_timed, -}; - -// vim: sw=4 ts=4 et tw=80 diff --git a/libvo/vo_null.c b/libvo/vo_null.c deleted file mode 100644 index 1f307f7f5b..0000000000 --- a/libvo/vo_null.c +++ /dev/null @@ -1,103 +0,0 @@ -/* - * based on video_out_null.c from mpeg2dec - * - * Copyright (C) Aaron Holtzman - June 2000 - * - * 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 <errno.h> -#include "config.h" -#include "mp_msg.h" -#include "video_out.h" -#include "libmpcodecs/vfcap.h" -#include "libmpcodecs/mp_image.h" - -static int draw_slice(struct vo *vo, uint8_t *image[], int stride[], - int w, int h, int x, int y) -{ - return 0; -} - -static void draw_osd(struct vo *vo, struct osd_state *osd) -{ -} - -static void flip_page(struct vo *vo) -{ -} - -static int query_format(struct vo *vo, uint32_t format) -{ - if (IMGFMT_IS_HWACCEL(format)) - return 0; - return VFCAP_CSP_SUPPORTED; -} - -static int config(struct vo *vo, uint32_t width, uint32_t height, - uint32_t d_width, uint32_t d_height, uint32_t flags, - uint32_t format) -{ - return 0; -} - -static void uninit(struct vo *vo) -{ -} - -static void check_events(struct vo *vo) -{ -} - -static int preinit(struct vo *vo, const char *arg) -{ - if (arg) { - mp_tmsg(MSGT_VO, MSGL_WARN, "[VO_NULL] Unknown subdevice: %s.\n", arg); - return ENOSYS; - } - return 0; -} - -static int control(struct vo *vo, uint32_t request, void *data) -{ - switch (request) { - case VOCTRL_QUERY_FORMAT: - return query_format(vo, *((uint32_t *)data)); - } - return VO_NOTIMPL; -} - -const struct vo_driver video_out_null = { - .is_new = false, - .info = &(const vo_info_t) { - "Null video output", - "null", - "Aaron Holtzman <aholtzma@ess.engr.uvic.ca>", - "" - }, - .preinit = preinit, - .config = config, - .control = control, - .draw_slice = draw_slice, - .draw_osd = draw_osd, - .flip_page = flip_page, - .check_events = check_events, - .uninit = uninit, -}; diff --git a/libvo/vo_opengl.c b/libvo/vo_opengl.c deleted file mode 100644 index 7b5289838f..0000000000 --- a/libvo/vo_opengl.c +++ /dev/null @@ -1,2419 +0,0 @@ -/* - * 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. - * - * You can alternatively redistribute this file and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - */ - -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <math.h> -#include <stdbool.h> -#include <assert.h> -#include "config.h" - -#include <libavutil/common.h> - -#ifdef CONFIG_LCMS2 -#include <lcms2.h> -#include "stream/stream.h" -#endif - -#include "talloc.h" -#include "mpcommon.h" -#include "bstr.h" -#include "mp_msg.h" -#include "subopt-helper.h" -#include "video_out.h" -#include "libmpcodecs/vfcap.h" -#include "libmpcodecs/mp_image.h" -#include "geometry.h" -#include "sub/sub.h" -#include "bitmap_packer.h" - -#include "gl_common.h" -#include "gl_osd.h" -#include "filter_kernels.h" -#include "aspect.h" -#include "fastmemcpy.h" - -static const char vo_opengl_shaders[] = -// Generated from libvo/vo_opengl_shaders.glsl -#include "libvo/vo_opengl_shaders.h" -; - -// Pixel width of 1D lookup textures. -#define LOOKUP_TEXTURE_SIZE 256 - -// Texture units 0-2 are used by the video, with unit 0 for free use. -// Units 3-4 are used for scaler LUTs. -#define TEXUNIT_SCALERS 3 -#define TEXUNIT_3DLUT 5 -#define TEXUNIT_DITHER 6 - -// lscale/cscale arguments that map directly to shader filter routines. -// Note that the convolution filters are not included in this list. -static const char *fixed_scale_filters[] = { - "bilinear", - "bicubic_fast", - "sharpen3", - "sharpen5", - NULL -}; - -struct lut_tex_format { - int pixels; - GLint internal_format; - GLenum format; -}; - -// Indexed with filter_kernel->size. -// This must match the weightsN functions in the shader. -// Each entry uses (size+3)/4 pixels per LUT entry, and size/pixels components -// per pixel. -struct lut_tex_format lut_tex_formats[] = { - [2] = {1, GL_RG16F, GL_RG}, - [4] = {1, GL_RGBA16F, GL_RGBA}, - [6] = {2, GL_RGB16F, GL_RGB}, - [8] = {2, GL_RGBA16F, GL_RGBA}, - [12] = {3, GL_RGBA16F, GL_RGBA}, - [16] = {4, GL_RGBA16F, GL_RGBA}, -}; - -// must be sorted, and terminated with 0 -static const int filter_sizes[] = {2, 4, 6, 8, 12, 16, 0}; - -struct vertex { - float position[2]; - uint8_t color[4]; - float texcoord[2]; -}; - -#define VERTEX_ATTRIB_POSITION 0 -#define VERTEX_ATTRIB_COLOR 1 -#define VERTEX_ATTRIB_TEXCOORD 2 - -// 2 triangles primitives per quad = 6 vertices per quad -// (GL_QUAD is deprecated, strips can't be used with OSD image lists) -#define VERTICES_PER_QUAD 6 - -struct texplane { - int shift_x, shift_y; - GLuint gl_texture; - int gl_buffer; - int buffer_size; - void *buffer_ptr; -}; - -struct scaler { - int index; - const char *name; - float params[2]; - struct filter_kernel *kernel; - GLuint gl_lut; - const char *lut_name; - - // kernel points here - struct filter_kernel kernel_storage; -}; - -struct fbotex { - GLuint fbo; - GLuint texture; - int tex_w, tex_h; // size of .texture - int vp_w, vp_h; // viewport of fbo / used part of the texture -}; - -struct gl_priv { - struct vo *vo; - MPGLContext *glctx; - GL *gl; - - int use_indirect; - int use_gamma; - int use_srgb; - int use_scale_sep; - int use_fancy_downscaling; - int use_lut_3d; - int use_npot; - int use_pbo; - int use_glFinish; - int use_gl_debug; - int allow_sw; - - int dither_depth; - int swap_interval; - GLint fbo_format; - int stereo_mode; - int osd_color; - - struct gl_priv *defaults; - struct gl_priv *orig_cmdline; - - GLuint vertex_buffer; - GLuint vao; - - GLuint osd_programs[SUBBITMAP_COUNT]; - GLuint indirect_program, scale_sep_program, final_program; - - struct mpgl_osd *osd; - - GLuint lut_3d_texture; - int lut_3d_w, lut_3d_h, lut_3d_d; - void *lut_3d_data; - - GLuint dither_texture; - float dither_quantization; - float dither_multiply; - int dither_size; - - uint32_t image_width; - uint32_t image_height; - uint32_t image_format; - int texture_width; - int texture_height; - - bool is_yuv; - bool is_linear_rgb; - - // per pixel (full pixel when packed, each component when planar) - int plane_bytes; - int plane_bits; - int component_bits; - - GLint gl_internal_format; - GLenum gl_format; - GLenum gl_type; - - int plane_count; - struct texplane planes[3]; - - struct fbotex indirect_fbo; // RGB target - struct fbotex scale_sep_fbo; // first pass when doing 2 pass scaling - - // state for luma (0) and chroma (1) scalers - struct scaler scalers[2]; - // luma scaler parameters (the same are used for chroma) - float scaler_params[2]; - - struct mp_csp_details colorspace; - struct mp_csp_equalizer video_eq; - - int mpi_flipped; - int vo_flipped; - - struct mp_rect src_rect; // displayed part of the source video - struct mp_rect dst_rect; // video rectangle on output window - struct mp_osd_res osd_rect; // OSD size/margins - int vp_x, vp_y, vp_w, vp_h; // GL viewport - - int frames_rendered; - - void *scratch; -}; - -struct fmt_entry { - int mp_format; - GLint internal_format; - GLenum format; - int component_bits; - GLenum type; -}; - -static const struct fmt_entry mp_to_gl_formats[] = { - {IMGFMT_RGB48NE, GL_RGB16, GL_RGB, 16, GL_UNSIGNED_SHORT}, - {IMGFMT_RGB24, GL_RGB, GL_RGB, 8, GL_UNSIGNED_BYTE}, - {IMGFMT_RGBA, GL_RGBA, GL_RGBA, 8, GL_UNSIGNED_BYTE}, - {IMGFMT_RGB15, GL_RGBA, GL_RGBA, 5, GL_UNSIGNED_SHORT_1_5_5_5_REV}, - {IMGFMT_RGB16, GL_RGB, GL_RGB, 6, GL_UNSIGNED_SHORT_5_6_5_REV}, - {IMGFMT_BGR15, GL_RGBA, GL_BGRA, 5, GL_UNSIGNED_SHORT_1_5_5_5_REV}, - {IMGFMT_BGR16, GL_RGB, GL_RGB, 6, GL_UNSIGNED_SHORT_5_6_5}, - {IMGFMT_BGR24, GL_RGB, GL_BGR, 8, GL_UNSIGNED_BYTE}, - {IMGFMT_BGRA, GL_RGBA, GL_BGRA, 8, GL_UNSIGNED_BYTE}, - {0}, -}; - -static const char *osd_shaders[SUBBITMAP_COUNT] = { - [SUBBITMAP_LIBASS] = "frag_osd_libass", - [SUBBITMAP_RGBA] = "frag_osd_rgba", -}; - - -static const char help_text[]; - -static void uninit_rendering(struct gl_priv *p); -static void delete_shaders(struct gl_priv *p); -static bool reparse_cmdline(struct gl_priv *p, char *arg); - - -static void default_tex_params(struct GL *gl, GLenum target, GLint filter) -{ - gl->TexParameteri(target, GL_TEXTURE_MIN_FILTER, filter); - gl->TexParameteri(target, GL_TEXTURE_MAG_FILTER, filter); - gl->TexParameteri(target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - gl->TexParameteri(target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); -} - -static void debug_check_gl(struct gl_priv *p, const char *msg) -{ - if (p->use_gl_debug || p->frames_rendered < 5) - glCheckError(p->gl, msg); -} - -static void tex_size(struct gl_priv *p, int w, int h, int *texw, int *texh) -{ - if (p->use_npot) { - *texw = w; - *texh = h; - } else { - *texw = 32; - while (*texw < w) - *texw *= 2; - *texh = 32; - while (*texh < h) - *texh *= 2; - } -} - -static void draw_triangles(struct gl_priv *p, struct vertex *vb, int vert_count) -{ - GL *gl = p->gl; - - assert(vert_count % 3 == 0); - - gl->BindBuffer(GL_ARRAY_BUFFER, p->vertex_buffer); - gl->BufferData(GL_ARRAY_BUFFER, vert_count * sizeof(struct vertex), vb, - GL_DYNAMIC_DRAW); - gl->BindBuffer(GL_ARRAY_BUFFER, 0); - - if (gl->BindVertexArray) - gl->BindVertexArray(p->vao); - - gl->DrawArrays(GL_TRIANGLES, 0, vert_count); - - if (gl->BindVertexArray) - gl->BindVertexArray(0); - - debug_check_gl(p, "after rendering"); -} - -// Write a textured quad to a vertex array. -// va = destination vertex array, VERTICES_PER_QUAD entries will be overwritten -// x0, y0, x1, y1 = destination coordinates of the quad -// tx0, ty0, tx1, ty1 = source texture coordinates (usually in pixels) -// texture_w, texture_h = size of the texture, or an inverse factor -// color = optional color for all vertices, NULL for opaque white -// flip = flip vertically -static void write_quad(struct vertex *va, - float x0, float y0, float x1, float y1, - float tx0, float ty0, float tx1, float ty1, - float texture_w, float texture_h, - const uint8_t color[4], bool flip) -{ - static const uint8_t white[4] = { 255, 255, 255, 255 }; - - if (!color) - color = white; - - tx0 /= texture_w; - ty0 /= texture_h; - tx1 /= texture_w; - ty1 /= texture_h; - - if (flip) { - float tmp = ty0; - ty0 = ty1; - ty1 = tmp; - } - -#define COLOR_INIT {color[0], color[1], color[2], color[3]} - va[0] = (struct vertex) { {x0, y0}, COLOR_INIT, {tx0, ty0} }; - va[1] = (struct vertex) { {x0, y1}, COLOR_INIT, {tx0, ty1} }; - va[2] = (struct vertex) { {x1, y0}, COLOR_INIT, {tx1, ty0} }; - va[3] = (struct vertex) { {x1, y1}, COLOR_INIT, {tx1, ty1} }; - va[4] = va[2]; - va[5] = va[1]; -#undef COLOR_INIT -} - -static bool fbotex_init(struct gl_priv *p, struct fbotex *fbo, int w, int h) -{ - GL *gl = p->gl; - bool res = true; - - assert(gl->mpgl_caps & MPGL_CAP_FB); - assert(!fbo->fbo); - assert(!fbo->texture); - - tex_size(p, w, h, &fbo->tex_w, &fbo->tex_h); - - fbo->vp_w = w; - fbo->vp_h = h; - - mp_msg(MSGT_VO, MSGL_V, "[gl] Create FBO: %dx%d\n", fbo->tex_w, fbo->tex_h); - - gl->GenFramebuffers(1, &fbo->fbo); - gl->GenTextures(1, &fbo->texture); - gl->BindTexture(GL_TEXTURE_2D, fbo->texture); - gl->TexImage2D(GL_TEXTURE_2D, 0, p->fbo_format, fbo->tex_w, fbo->tex_h, 0, - GL_RGB, GL_UNSIGNED_BYTE, NULL); - default_tex_params(gl, GL_TEXTURE_2D, GL_LINEAR); - gl->BindFramebuffer(GL_FRAMEBUFFER, fbo->fbo); - gl->FramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, - GL_TEXTURE_2D, fbo->texture, 0); - - if (gl->CheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) { - mp_msg(MSGT_VO, MSGL_ERR, "[gl] Error: framebuffer completeness " - "check failed!\n"); - res = false; - } - - gl->BindFramebuffer(GL_FRAMEBUFFER, 0); - - debug_check_gl(p, "after creating framebuffer & associated texture"); - - return res; -} - -static void fbotex_uninit(struct gl_priv *p, struct fbotex *fbo) -{ - GL *gl = p->gl; - - if (gl->mpgl_caps & MPGL_CAP_FB) { - gl->DeleteFramebuffers(1, &fbo->fbo); - gl->DeleteTextures(1, &fbo->texture); - *fbo = (struct fbotex) {0}; - } -} - -static void matrix_ortho2d(float m[3][3], float x0, float x1, - float y0, float y1) -{ - memset(m, 0, 9 * sizeof(float)); - m[0][0] = 2.0f / (x1 - x0); - m[1][1] = 2.0f / (y1 - y0); - m[2][0] = -(x1 + x0) / (x1 - x0); - m[2][1] = -(y1 + y0) / (y1 - y0); - m[2][2] = 1.0f; -} - -static void update_uniforms(struct gl_priv *p, GLuint program) -{ - GL *gl = p->gl; - GLint loc; - - if (program == 0) - return; - - gl->UseProgram(program); - - struct mp_csp_params cparams = { - .colorspace = p->colorspace, - .input_bits = p->plane_bits, - .texture_bits = (p->plane_bits + 7) & ~7, - }; - mp_csp_copy_equalizer_values(&cparams, &p->video_eq); - - loc = gl->GetUniformLocation(program, "transform"); - if (loc >= 0) { - float matrix[3][3]; - matrix_ortho2d(matrix, 0, p->vp_w, p->vp_h, 0); - gl->UniformMatrix3fv(loc, 1, GL_FALSE, &matrix[0][0]); - } - - loc = gl->GetUniformLocation(program, "colormatrix"); - if (loc >= 0) { - float yuv2rgb[3][4] = {{0}}; - if (p->is_yuv) - mp_get_yuv2rgb_coeffs(&cparams, yuv2rgb); - gl->UniformMatrix4x3fv(loc, 1, GL_TRUE, &yuv2rgb[0][0]); - } - - gl->Uniform3f(gl->GetUniformLocation(program, "inv_gamma"), - 1.0 / cparams.rgamma, - 1.0 / cparams.ggamma, - 1.0 / cparams.bgamma); - - for (int n = 0; n < p->plane_count; n++) { - char textures_n[32]; - char textures_size_n[32]; - snprintf(textures_n, sizeof(textures_n), "textures[%d]", n); - snprintf(textures_size_n, sizeof(textures_size_n), "textures_size[%d]", n); - - gl->Uniform1i(gl->GetUniformLocation(program, textures_n), n); - gl->Uniform2f(gl->GetUniformLocation(program, textures_size_n), - p->texture_width >> p->planes[n].shift_x, - p->texture_height >> p->planes[n].shift_y); - } - - gl->Uniform2f(gl->GetUniformLocation(program, "dither_size"), - p->dither_size, p->dither_size); - - gl->Uniform1i(gl->GetUniformLocation(program, "lut_3d"), TEXUNIT_3DLUT); - - for (int n = 0; n < 2; n++) { - const char *lut = p->scalers[n].lut_name; - if (lut) - gl->Uniform1i(gl->GetUniformLocation(program, lut), - TEXUNIT_SCALERS + n); - } - - gl->Uniform1i(gl->GetUniformLocation(program, "dither"), TEXUNIT_DITHER); - gl->Uniform1f(gl->GetUniformLocation(program, "dither_quantization"), - p->dither_quantization); - gl->Uniform1f(gl->GetUniformLocation(program, "dither_multiply"), - p->dither_multiply); - - float sparam1 = p->scaler_params[0]; - gl->Uniform1f(gl->GetUniformLocation(program, "filter_param1"), - isnan(sparam1) ? 0.5f : sparam1); - - loc = gl->GetUniformLocation(program, "osd_color"); - if (loc >= 0) { - int r = (p->osd_color >> 16) & 0xff; - int g = (p->osd_color >> 8) & 0xff; - int b = p->osd_color & 0xff; - int a = 0xff - (p->osd_color >> 24); - gl->Uniform4f(loc, r / 255.0f, g / 255.0f, b / 255.0f, a / 255.0f); - } - - gl->UseProgram(0); - - debug_check_gl(p, "update_uniforms()"); -} - -static void update_all_uniforms(struct gl_priv *p) -{ - for (int n = 0; n < SUBBITMAP_COUNT; n++) - update_uniforms(p, p->osd_programs[n]); - update_uniforms(p, p->indirect_program); - update_uniforms(p, p->scale_sep_program); - update_uniforms(p, p->final_program); -} - -#define SECTION_HEADER "#!section " - -static char *get_section(void *talloc_ctx, struct bstr source, - const char *section) -{ - char *res = talloc_strdup(talloc_ctx, ""); - bool copy = false; - while (source.len) { - struct bstr line = bstr_strip_linebreaks(bstr_getline(source, &source)); - if (bstr_eatstart(&line, bstr0(SECTION_HEADER))) { - copy = bstrcmp0(line, section) == 0; - } else if (copy) { - res = talloc_asprintf_append_buffer(res, "%.*s\n", BSTR_P(line)); - } - } - return res; -} - -static char *t_concat(void *talloc_ctx, const char *s1, const char *s2) -{ - return talloc_asprintf(talloc_ctx, "%s%s", s1, s2); -} - -static GLuint create_shader(GL *gl, GLenum type, const char *header, - const char *source) -{ - void *tmp = talloc_new(NULL); - const char *full_source = t_concat(tmp, header, source); - - GLuint shader = gl->CreateShader(type); - gl->ShaderSource(shader, 1, &full_source, NULL); - gl->CompileShader(shader); - GLint status; - gl->GetShaderiv(shader, GL_COMPILE_STATUS, &status); - GLint log_length; - gl->GetShaderiv(shader, GL_INFO_LOG_LENGTH, &log_length); - - int pri = status ? (log_length > 1 ? MSGL_V : MSGL_DBG2) : MSGL_ERR; - const char *typestr = type == GL_VERTEX_SHADER ? "vertex" : "fragment"; - if (mp_msg_test(MSGT_VO, pri)) { - mp_msg(MSGT_VO, pri, "[gl] %s shader source:\n", typestr); - mp_log_source(MSGT_VO, pri, full_source); - } - if (log_length > 1) { - GLchar *log = talloc_zero_size(tmp, log_length + 1); - gl->GetShaderInfoLog(shader, log_length, NULL, log); - mp_msg(MSGT_VO, pri, "[gl] %s shader compile log (status=%d):\n%s\n", - typestr, status, log); - } - - talloc_free(tmp); - - return shader; -} - -static void prog_create_shader(GL *gl, GLuint program, GLenum type, - const char *header, const char *source) -{ - GLuint shader = create_shader(gl, type, header, source); - gl->AttachShader(program, shader); - gl->DeleteShader(shader); -} - -static void link_shader(GL *gl, GLuint program) -{ - gl->LinkProgram(program); - GLint status; - gl->GetProgramiv(program, GL_LINK_STATUS, &status); - GLint log_length; - gl->GetProgramiv(program, GL_INFO_LOG_LENGTH, &log_length); - - int pri = status ? (log_length > 1 ? MSGL_V : MSGL_DBG2) : MSGL_ERR; - if (mp_msg_test(MSGT_VO, pri)) { - GLchar *log = talloc_zero_size(NULL, log_length + 1); - gl->GetProgramInfoLog(program, log_length, NULL, log); - mp_msg(MSGT_VO, pri, "[gl] shader link log (status=%d): %s\n", - status, log); - talloc_free(log); - } -} - -static void bind_attrib_locs(GL *gl, GLuint program) -{ - gl->BindAttribLocation(program, VERTEX_ATTRIB_POSITION, "vertex_position"); - gl->BindAttribLocation(program, VERTEX_ATTRIB_COLOR, "vertex_color"); - gl->BindAttribLocation(program, VERTEX_ATTRIB_TEXCOORD, "vertex_texcoord"); -} - -static GLuint create_program(GL *gl, const char *name, const char *header, - const char *vertex, const char *frag) -{ - mp_msg(MSGT_VO, MSGL_V, "[gl] compiling shader program '%s'\n", name); - mp_msg(MSGT_VO, MSGL_V, "[gl] header:\n"); - mp_log_source(MSGT_VO, MSGL_V, header); - GLuint prog = gl->CreateProgram(); - prog_create_shader(gl, prog, GL_VERTEX_SHADER, header, vertex); - prog_create_shader(gl, prog, GL_FRAGMENT_SHADER, header, frag); - bind_attrib_locs(gl, prog); - link_shader(gl, prog); - return prog; -} - -static void shader_def(char **shader, const char *name, - const char *value) -{ - *shader = talloc_asprintf_append(*shader, "#define %s %s\n", name, value); -} - -static void shader_def_opt(char **shader, const char *name, bool b) -{ - if (b) - shader_def(shader, name, "1"); -} - -static void shader_setup_scaler(char **shader, struct scaler *scaler, int pass) -{ - const char *target = scaler->index == 0 ? "SAMPLE_L" : "SAMPLE_C"; - if (!scaler->kernel) { - *shader = talloc_asprintf_append(*shader, "#define %s sample_%s\n", - target, scaler->name); - } else { - int size = scaler->kernel->size; - if (pass != -1) { - // The direction/pass assignment is rather arbitrary, but fixed in - // other parts of the code (like FBO setup). - const char *direction = pass == 0 ? "0, 1" : "1, 0"; - *shader = talloc_asprintf_append(*shader, "#define %s(p0, p1, p2) " - "sample_convolution_sep%d(vec2(%s), %s, p0, p1, p2)\n", - target, size, direction, scaler->lut_name); - } else { - *shader = talloc_asprintf_append(*shader, "#define %s(p0, p1, p2) " - "sample_convolution%d(%s, p0, p1, p2)\n", - target, size, scaler->lut_name); - } - } -} - -// return false if RGB or 4:4:4 YUV -static bool input_is_subsampled(struct gl_priv *p) -{ - for (int i = 0; i < p->plane_count; i++) - if (p->planes[i].shift_x || p->planes[i].shift_y) - return true; - return false; -} - -static void compile_shaders(struct gl_priv *p) -{ - GL *gl = p->gl; - - delete_shaders(p); - - void *tmp = talloc_new(NULL); - - struct bstr src = bstr0(vo_opengl_shaders); - char *vertex_shader = get_section(tmp, src, "vertex_all"); - char *shader_prelude = get_section(tmp, src, "prelude"); - char *s_video = get_section(tmp, src, "frag_video"); - - char *header = talloc_asprintf(tmp, "#version %d\n%s", gl->glsl_version, - shader_prelude); - - char *header_osd = talloc_strdup(tmp, header); - shader_def_opt(&header_osd, "USE_OSD_LINEAR_CONV", p->use_srgb && - !p->use_lut_3d); - shader_def_opt(&header_osd, "USE_OSD_3DLUT", p->use_lut_3d); - shader_def_opt(&header_osd, "USE_OSD_SRGB", p->use_srgb); - - for (int n = 0; n < SUBBITMAP_COUNT; n++) { - const char *name = osd_shaders[n]; - if (name) { - char *s_osd = get_section(tmp, src, name); - p->osd_programs[n] = - create_program(gl, name, header_osd, vertex_shader, s_osd); - } - } - - char *header_conv = talloc_strdup(tmp, ""); - char *header_final = talloc_strdup(tmp, ""); - char *header_sep = NULL; - - bool convert_input_to_linear = !p->is_linear_rgb - && (p->use_srgb || p->use_lut_3d); - - shader_def_opt(&header_conv, "USE_PLANAR", p->plane_count > 1); - shader_def_opt(&header_conv, "USE_GBRP", p->image_format == IMGFMT_GBRP); - shader_def_opt(&header_conv, "USE_YGRAY", p->is_yuv && p->plane_count == 1); - shader_def_opt(&header_conv, "USE_COLORMATRIX", p->is_yuv); - shader_def_opt(&header_conv, "USE_LINEAR_CONV", convert_input_to_linear); - - shader_def_opt(&header_final, "USE_LINEAR_CONV_INV", p->use_lut_3d); - shader_def_opt(&header_final, "USE_GAMMA_POW", p->use_gamma); - shader_def_opt(&header_final, "USE_3DLUT", p->use_lut_3d); - shader_def_opt(&header_final, "USE_SRGB", p->use_srgb); - shader_def_opt(&header_final, "USE_DITHER", p->dither_texture != 0); - - if (p->use_scale_sep && p->scalers[0].kernel) { - header_sep = talloc_strdup(tmp, ""); - shader_def_opt(&header_sep, "FIXED_SCALE", true); - shader_setup_scaler(&header_sep, &p->scalers[0], 0); - shader_setup_scaler(&header_final, &p->scalers[0], 1); - } else { - shader_setup_scaler(&header_final, &p->scalers[0], -1); - } - - // We want to do scaling in linear light. Scaling is closely connected to - // texture sampling due to how the shader is structured (or if GL bilinear - // scaling is used). The purpose of the "indirect" pass is to convert the - // input video to linear RGB. - // Another purpose is reducing input to a single texture for scaling. - bool use_indirect = p->use_indirect; - - // Don't sample from input video textures before converting the input to - // linear light. (Unneeded when sRGB textures are used.) - if (convert_input_to_linear) - use_indirect = true; - - // It doesn't make sense to scale the chroma with cscale in the 1. scale - // step and with lscale in the 2. step. If the chroma is subsampled, a - // convolution filter wouldn't even work entirely correctly, because the - // luma scaler would sample two texels instead of one per tap for chroma. - // Also, even with 4:4:4 YUV or planar RGB, the indirection might be faster, - // because the shader can't use one scaler for sampling from 3 textures. It - // has to fetch the coefficients for each texture separately, even though - // they're the same (this is not an inherent restriction, but would require - // to restructure the shader). - if (header_sep && p->plane_count > 1) - use_indirect = true; - - if (input_is_subsampled(p)) { - shader_setup_scaler(&header_conv, &p->scalers[1], -1); - } else { - // Force using the luma scaler on chroma. If the "indirect" stage is - // used, the actual scaling will happen in the next stage. - shader_def(&header_conv, "SAMPLE_C", - use_indirect ? "sample_bilinear" : "SAMPLE_L"); - } - - if (use_indirect) { - // We don't use filtering for the Y-plane (luma), because it's never - // scaled in this scenario. - shader_def(&header_conv, "SAMPLE_L", "sample_bilinear"); - shader_def_opt(&header_conv, "FIXED_SCALE", true); - header_conv = t_concat(tmp, header, header_conv); - p->indirect_program = - create_program(gl, "indirect", header_conv, vertex_shader, s_video); - } else if (header_sep) { - header_sep = t_concat(tmp, header_sep, header_conv); - } else { - header_final = t_concat(tmp, header_final, header_conv); - } - - if (header_sep) { - header_sep = t_concat(tmp, header, header_sep); - p->scale_sep_program = - create_program(gl, "scale_sep", header_sep, vertex_shader, s_video); - } - - header_final = t_concat(tmp, header, header_final); - p->final_program = - create_program(gl, "final", header_final, vertex_shader, s_video); - - debug_check_gl(p, "shader compilation"); - - talloc_free(tmp); -} - -static void delete_program(GL *gl, GLuint *prog) -{ - gl->DeleteProgram(*prog); - *prog = 0; -} - -static void delete_shaders(struct gl_priv *p) -{ - GL *gl = p->gl; - - for (int n = 0; n < SUBBITMAP_COUNT; n++) - delete_program(gl, &p->osd_programs[n]); - delete_program(gl, &p->indirect_program); - delete_program(gl, &p->scale_sep_program); - delete_program(gl, &p->final_program); -} - -static double get_scale_factor(struct gl_priv *p) -{ - double sx = (p->dst_rect.x1 - p->dst_rect.x0) / - (double)(p->src_rect.x1 - p->src_rect.x0); - double sy = (p->dst_rect.y1 - p->dst_rect.y0) / - (double)(p->src_rect.y1 - p->src_rect.y0); - // xxx: actually we should use different scalers in X/Y directions if the - // scale factors are different due to anamorphic content - return FFMIN(sx, sy); -} - -static bool update_scale_factor(struct gl_priv *p, struct filter_kernel *kernel) -{ - double scale = get_scale_factor(p); - if (!p->use_fancy_downscaling && scale < 1.0) - scale = 1.0; - return mp_init_filter(kernel, filter_sizes, FFMAX(1.0, 1.0 / scale)); -} - -static void init_scaler(struct gl_priv *p, struct scaler *scaler) -{ - GL *gl = p->gl; - - assert(scaler->name); - - scaler->kernel = NULL; - - const struct filter_kernel *t_kernel = mp_find_filter_kernel(scaler->name); - if (!t_kernel) - return; - - scaler->kernel_storage = *t_kernel; - scaler->kernel = &scaler->kernel_storage; - - for (int n = 0; n < 2; n++) { - if (!isnan(p->scaler_params[n])) - scaler->kernel->params[n] = p->scaler_params[n]; - } - - update_scale_factor(p, scaler->kernel); - - int size = scaler->kernel->size; - assert(size < FF_ARRAY_ELEMS(lut_tex_formats)); - struct lut_tex_format *fmt = &lut_tex_formats[size]; - bool use_2d = fmt->pixels > 1; - bool is_luma = scaler->index == 0; - scaler->lut_name = use_2d - ? (is_luma ? "lut_l_2d" : "lut_c_2d") - : (is_luma ? "lut_l_1d" : "lut_c_1d"); - - gl->ActiveTexture(GL_TEXTURE0 + TEXUNIT_SCALERS + scaler->index); - GLenum target = use_2d ? GL_TEXTURE_2D : GL_TEXTURE_1D; - - if (!scaler->gl_lut) - gl->GenTextures(1, &scaler->gl_lut); - - gl->BindTexture(target, scaler->gl_lut); - gl->PixelStorei(GL_UNPACK_ALIGNMENT, 4); - gl->PixelStorei(GL_UNPACK_ROW_LENGTH, 0); - - float *weights = talloc_array(NULL, float, LOOKUP_TEXTURE_SIZE * size); - mp_compute_lut(scaler->kernel, LOOKUP_TEXTURE_SIZE, weights); - if (use_2d) { - gl->TexImage2D(GL_TEXTURE_2D, 0, fmt->internal_format, fmt->pixels, - LOOKUP_TEXTURE_SIZE, 0, fmt->format, GL_FLOAT, - weights); - } else { - gl->TexImage1D(GL_TEXTURE_1D, 0, fmt->internal_format, - LOOKUP_TEXTURE_SIZE, 0, fmt->format, GL_FLOAT, - weights); - } - talloc_free(weights); - - gl->TexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - gl->TexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - gl->TexParameteri(target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - gl->TexParameteri(target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - - gl->ActiveTexture(GL_TEXTURE0); - - debug_check_gl(p, "after initializing scaler"); -} - -static void make_dither_matrix(unsigned char *m, int size) -{ - m[0] = 0; - for (int sz = 1; sz < size; sz *= 2) { - int offset[] = {sz*size, sz, sz * (size+1), 0}; - for (int i = 0; i < 4; i++) - for (int y = 0; y < sz * size; y += size) - for (int x = 0; x < sz; x++) - m[x+y+offset[i]] = m[x+y] * 4 + (3-i) * 256/size/size; - } -} - -static void init_dither(struct gl_priv *p) -{ - GL *gl = p->gl; - - // Assume 8 bits per component if unknown. - int dst_depth = p->glctx->depth_g ? p->glctx->depth_g : 8; - if (p->dither_depth > 0) - dst_depth = p->dither_depth; - - int src_depth = p->component_bits; - if (p->use_lut_3d) - src_depth = 16; - - if (dst_depth >= src_depth || p->dither_depth < 0 || src_depth < 0) - return; - - mp_msg(MSGT_VO, MSGL_V, "[gl] Dither %d->%d.\n", src_depth, dst_depth); - - // This defines how many bits are considered significant for output on - // screen. The superfluous bits will be used for rounded according to the - // dither matrix. The precision of the source implicitly decides how many - // dither patterns can be visible. - p->dither_quantization = (1 << dst_depth) - 1; - int size = 8; - p->dither_multiply = p->dither_quantization + 1.0 / (size*size); - unsigned char dither[256]; - make_dither_matrix(dither, size); - - p->dither_size = size; - - gl->ActiveTexture(GL_TEXTURE0 + TEXUNIT_DITHER); - gl->GenTextures(1, &p->dither_texture); - gl->BindTexture(GL_TEXTURE_2D, p->dither_texture); - gl->PixelStorei(GL_UNPACK_ALIGNMENT, 1); - gl->PixelStorei(GL_UNPACK_ROW_LENGTH, 0); - gl->TexImage2D(GL_TEXTURE_2D, 0, GL_RED, size, size, 0, GL_RED, - GL_UNSIGNED_BYTE, dither); - gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); - gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); - gl->ActiveTexture(GL_TEXTURE0); -} - -static void reinit_rendering(struct gl_priv *p) -{ - mp_msg(MSGT_VO, MSGL_V, "[gl] Reinit rendering.\n"); - - if (p->gl->SwapInterval && p->swap_interval >= 0) - p->gl->SwapInterval(p->swap_interval); - - debug_check_gl(p, "before scaler initialization"); - - uninit_rendering(p); - - init_dither(p); - - init_scaler(p, &p->scalers[0]); - init_scaler(p, &p->scalers[1]); - - compile_shaders(p); - - if (p->indirect_program && !p->indirect_fbo.fbo) - fbotex_init(p, &p->indirect_fbo, p->texture_width, p->texture_height); - - if (!p->osd) { - p->osd = mpgl_osd_init(p->gl, false); - p->osd->use_pbo = p->use_pbo; - } -} - -static void uninit_rendering(struct gl_priv *p) -{ - GL *gl = p->gl; - - delete_shaders(p); - - for (int n = 0; n < 2; n++) { - gl->DeleteTextures(1, &p->scalers[n].gl_lut); - p->scalers[n].gl_lut = 0; - p->scalers[n].lut_name = NULL; - p->scalers[n].kernel = NULL; - } - - gl->DeleteTextures(1, &p->dither_texture); - p->dither_texture = 0; - - if (p->osd) - mpgl_osd_destroy(p->osd); - p->osd = NULL; -} - -static void init_lut_3d(struct gl_priv *p) -{ - GL *gl = p->gl; - - gl->GenTextures(1, &p->lut_3d_texture); - gl->ActiveTexture(GL_TEXTURE0 + TEXUNIT_3DLUT); - gl->BindTexture(GL_TEXTURE_3D, p->lut_3d_texture); - gl->PixelStorei(GL_UNPACK_ALIGNMENT, 4); - gl->PixelStorei(GL_UNPACK_ROW_LENGTH, 0); - gl->TexImage3D(GL_TEXTURE_3D, 0, GL_RGB16, p->lut_3d_w, p->lut_3d_h, - p->lut_3d_d, 0, GL_RGB, GL_UNSIGNED_SHORT, p->lut_3d_data); - gl->TexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - gl->TexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - gl->TexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - gl->TexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - gl->TexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE); - gl->ActiveTexture(GL_TEXTURE0); - - debug_check_gl(p, "after 3d lut creation"); -} - -static void init_video(struct gl_priv *p) -{ - GL *gl = p->gl; - - if (p->use_lut_3d && !p->lut_3d_texture) - init_lut_3d(p); - - if (!p->is_yuv && (p->use_srgb || p->use_lut_3d)) { - p->is_linear_rgb = true; - p->gl_internal_format = GL_SRGB; - } - - int eq_caps = MP_CSP_EQ_CAPS_GAMMA; - if (p->is_yuv) - eq_caps |= MP_CSP_EQ_CAPS_COLORMATRIX; - p->video_eq.capabilities = eq_caps; - - debug_check_gl(p, "before video texture creation"); - - tex_size(p, p->image_width, p->image_height, - &p->texture_width, &p->texture_height); - - for (int n = 0; n < p->plane_count; n++) { - struct texplane *plane = &p->planes[n]; - - int w = p->texture_width >> plane->shift_x; - int h = p->texture_height >> plane->shift_y; - - mp_msg(MSGT_VO, MSGL_V, "[gl] Texture for plane %d: %dx%d\n", n, w, h); - - gl->ActiveTexture(GL_TEXTURE0 + n); - gl->GenTextures(1, &plane->gl_texture); - gl->BindTexture(GL_TEXTURE_2D, plane->gl_texture); - - gl->TexImage2D(GL_TEXTURE_2D, 0, p->gl_internal_format, w, h, 0, - p->gl_format, p->gl_type, NULL); - default_tex_params(gl, GL_TEXTURE_2D, GL_LINEAR); - } - gl->ActiveTexture(GL_TEXTURE0); - - debug_check_gl(p, "after video texture creation"); - - reinit_rendering(p); -} - -static void uninit_video(struct gl_priv *p) -{ - GL *gl = p->gl; - - uninit_rendering(p); - - for (int n = 0; n < 3; n++) { - struct texplane *plane = &p->planes[n]; - - gl->DeleteTextures(1, &plane->gl_texture); - plane->gl_texture = 0; - gl->DeleteBuffers(1, &plane->gl_buffer); - plane->gl_buffer = 0; - plane->buffer_ptr = NULL; - plane->buffer_size = 0; - } - - fbotex_uninit(p, &p->indirect_fbo); - fbotex_uninit(p, &p->scale_sep_fbo); -} - -static void render_to_fbo(struct gl_priv *p, struct fbotex *fbo, int w, int h, - int tex_w, int tex_h) -{ - GL *gl = p->gl; - - gl->Viewport(0, 0, fbo->vp_w, fbo->vp_h); - gl->BindFramebuffer(GL_FRAMEBUFFER, fbo->fbo); - - struct vertex vb[VERTICES_PER_QUAD]; - write_quad(vb, -1, -1, 1, 1, - 0, 0, w, h, - tex_w, tex_h, - NULL, false); - draw_triangles(p, vb, VERTICES_PER_QUAD); - - gl->BindFramebuffer(GL_FRAMEBUFFER, 0); - gl->Viewport(p->vp_x, p->vp_y, p->vp_w, p->vp_h); - -} - -static void handle_pass(struct gl_priv *p, struct fbotex **source, - struct fbotex *fbo, GLuint program) -{ - GL *gl = p->gl; - - if (!program) - return; - - gl->BindTexture(GL_TEXTURE_2D, (*source)->texture); - gl->UseProgram(program); - render_to_fbo(p, fbo, (*source)->vp_w, (*source)->vp_h, - (*source)->tex_w, (*source)->tex_h); - *source = fbo; -} - -static void do_render(struct gl_priv *p) -{ - GL *gl = p->gl; - struct vertex vb[VERTICES_PER_QUAD]; - bool is_flipped = p->mpi_flipped ^ p->vo_flipped; - - // Order of processing: - // [indirect -> [scale_sep ->]] final - - struct fbotex dummy = { - .vp_w = p->image_width, .vp_h = p->image_height, - .tex_w = p->texture_width, .tex_h = p->texture_height, - .texture = p->planes[0].gl_texture, - }; - struct fbotex *source = &dummy; - - handle_pass(p, &source, &p->indirect_fbo, p->indirect_program); - handle_pass(p, &source, &p->scale_sep_fbo, p->scale_sep_program); - - gl->BindTexture(GL_TEXTURE_2D, source->texture); - gl->UseProgram(p->final_program); - - float final_texw = p->image_width * source->tex_w / (float)source->vp_w; - float final_texh = p->image_height * source->tex_h / (float)source->vp_h; - - if (p->stereo_mode) { - int w = p->src_rect.x1 - p->src_rect.x0; - int imgw = p->image_width; - - glEnable3DLeft(gl, p->stereo_mode); - - write_quad(vb, - p->dst_rect.x0, p->dst_rect.y0, - p->dst_rect.x1, p->dst_rect.y1, - p->src_rect.x0 / 2, p->src_rect.y0, - p->src_rect.x0 / 2 + w / 2, p->src_rect.y1, - final_texw, final_texh, - NULL, is_flipped); - draw_triangles(p, vb, VERTICES_PER_QUAD); - - glEnable3DRight(gl, p->stereo_mode); - - write_quad(vb, - p->dst_rect.x0, p->dst_rect.y0, - p->dst_rect.x1, p->dst_rect.y1, - p->src_rect.x0 / 2 + imgw / 2, p->src_rect.y0, - p->src_rect.x0 / 2 + imgw / 2 + w / 2, p->src_rect.y1, - final_texw, final_texh, - NULL, is_flipped); - draw_triangles(p, vb, VERTICES_PER_QUAD); - - glDisable3D(gl, p->stereo_mode); - } else { - write_quad(vb, - p->dst_rect.x0, p->dst_rect.y0, - p->dst_rect.x1, p->dst_rect.y1, - p->src_rect.x0, p->src_rect.y0, - p->src_rect.x1, p->src_rect.y1, - final_texw, final_texh, - NULL, is_flipped); - draw_triangles(p, vb, VERTICES_PER_QUAD); - } - - gl->UseProgram(0); - - debug_check_gl(p, "after video rendering"); -} - -static void update_window_sized_objects(struct gl_priv *p) -{ - if (p->scale_sep_program) { - int h = p->dst_rect.y1 - p->dst_rect.y0; - if (h > p->scale_sep_fbo.tex_h) { - fbotex_uninit(p, &p->scale_sep_fbo); - // Round up to an arbitrary alignment to make window resizing or - // panscan controls smoother (less texture reallocations). - int height = FFALIGN(h, 256); - fbotex_init(p, &p->scale_sep_fbo, p->image_width, height); - } - p->scale_sep_fbo.vp_w = p->image_width; - p->scale_sep_fbo.vp_h = h; - } -} - -static void resize(struct gl_priv *p) -{ - GL *gl = p->gl; - struct vo *vo = p->vo; - - mp_msg(MSGT_VO, MSGL_V, "[gl] Resize: %dx%d\n", vo->dwidth, vo->dheight); - p->vp_x = 0, p->vp_y = 0; - p->vp_w = vo->dwidth, p->vp_h = vo->dheight; - gl->Viewport(p->vp_x, p->vp_y, p->vp_w, p->vp_h); - - vo_get_src_dst_rects(vo, &p->src_rect, &p->dst_rect, &p->osd_rect); - - bool need_scaler_reinit = false; // filter size change needed - bool need_scaler_update = false; // filter LUT change needed - bool too_small = false; - for (int n = 0; n < 2; n++) { - if (p->scalers[n].kernel) { - struct filter_kernel tkernel = *p->scalers[n].kernel; - struct filter_kernel old = tkernel; - bool ok = update_scale_factor(p, &tkernel); - too_small |= !ok; - need_scaler_reinit |= (tkernel.size != old.size); - need_scaler_update |= (tkernel.inv_scale != old.inv_scale); - } - } - if (need_scaler_reinit) { - reinit_rendering(p); - } else if (need_scaler_update) { - init_scaler(p, &p->scalers[0]); - init_scaler(p, &p->scalers[1]); - } - if (too_small) - mp_msg(MSGT_VO, MSGL_WARN, "[gl] Can't downscale that much, window " - "output may look suboptimal.\n"); - - update_window_sized_objects(p); - update_all_uniforms(p); - - gl->Clear(GL_COLOR_BUFFER_BIT); - vo->want_redraw = true; -} - -static void flip_page(struct vo *vo) -{ - struct gl_priv *p = vo->priv; - GL *gl = p->gl; - - if (p->use_glFinish) - gl->Finish(); - - p->glctx->swapGlBuffers(p->glctx); - - if (p->dst_rect.x0 > p->vp_x || p->dst_rect.y0 > p->vp_y - || p->dst_rect.x1 < p->vp_x + p->vp_w - || p->dst_rect.y1 < p->vp_y + p->vp_h) - { - gl->Clear(GL_COLOR_BUFFER_BIT); - } - - p->frames_rendered++; -} - -static int draw_slice(struct vo *vo, uint8_t *src[], int stride[], int w, int h, - int x, int y) -{ - struct gl_priv *p = vo->priv; - GL *gl = p->gl; - - p->mpi_flipped = stride[0] < 0; - - for (int n = 0; n < p->plane_count; n++) { - gl->ActiveTexture(GL_TEXTURE0 + n); - gl->BindTexture(GL_TEXTURE_2D, p->planes[n].gl_texture); - int xs = p->planes[n].shift_x, ys = p->planes[n].shift_y; - glUploadTex(gl, GL_TEXTURE_2D, p->gl_format, p->gl_type, src[n], - stride[n], x >> xs, y >> ys, w >> xs, h >> ys, 0); - } - gl->ActiveTexture(GL_TEXTURE0); - - return 0; -} - -static uint32_t get_image(struct vo *vo, mp_image_t *mpi) -{ - struct gl_priv *p = vo->priv; - GL *gl = p->gl; - - if (!p->use_pbo) - return VO_FALSE; - - // We don't support alpha planes. (Disabling PBOs with normal draw calls is - // an undesired, but harmless side-effect.) - if (mpi->num_planes != p->plane_count) - return VO_FALSE; - - if (mpi->flags & MP_IMGFLAG_READABLE) - return VO_FALSE; - if (mpi->type != MP_IMGTYPE_STATIC && mpi->type != MP_IMGTYPE_TEMP && - (mpi->type != MP_IMGTYPE_NUMBERED || mpi->number)) - return VO_FALSE; - mpi->flags &= ~MP_IMGFLAG_COMMON_PLANE; - for (int n = 0; n < p->plane_count; n++) { - struct texplane *plane = &p->planes[n]; - mpi->stride[n] = (mpi->width >> plane->shift_x) * p->plane_bytes; - int needed_size = (mpi->height >> plane->shift_y) * mpi->stride[n]; - if (!plane->gl_buffer) - gl->GenBuffers(1, &plane->gl_buffer); - gl->BindBuffer(GL_PIXEL_UNPACK_BUFFER, plane->gl_buffer); - if (needed_size > plane->buffer_size) { - plane->buffer_size = needed_size; - gl->BufferData(GL_PIXEL_UNPACK_BUFFER, plane->buffer_size, - NULL, GL_DYNAMIC_DRAW); - } - if (!plane->buffer_ptr) - plane->buffer_ptr = gl->MapBuffer(GL_PIXEL_UNPACK_BUFFER, - GL_WRITE_ONLY); - mpi->planes[n] = plane->buffer_ptr; - gl->BindBuffer(GL_PIXEL_UNPACK_BUFFER, 0); - } - mpi->flags |= MP_IMGFLAG_DIRECT; - return VO_TRUE; -} - -static uint32_t draw_image(struct gl_priv *p, mp_image_t *mpi) -{ - GL *gl = p->gl; - int n; - - assert(mpi->num_planes >= p->plane_count); - - mp_image_t mpi2 = *mpi; - int w = mpi->w, h = mpi->h; - if (mpi->flags & MP_IMGFLAG_DRAW_CALLBACK) - goto skip_upload; - mpi2.flags = 0; - mpi2.type = MP_IMGTYPE_TEMP; - mpi2.width = mpi2.w; - mpi2.height = mpi2.h; - if (!(mpi->flags & MP_IMGFLAG_DIRECT) - && !p->planes[0].buffer_ptr - && get_image(p->vo, &mpi2) == VO_TRUE) - { - for (n = 0; n < p->plane_count; n++) { - struct texplane *plane = &p->planes[n]; - int xs = plane->shift_x, ys = plane->shift_y; - int line_bytes = (mpi->w >> xs) * p->plane_bytes; - memcpy_pic(mpi2.planes[n], mpi->planes[n], line_bytes, mpi->h >> ys, - mpi2.stride[n], mpi->stride[n]); - } - mpi = &mpi2; - } - p->mpi_flipped = mpi->stride[0] < 0; - for (n = 0; n < p->plane_count; n++) { - struct texplane *plane = &p->planes[n]; - int xs = plane->shift_x, ys = plane->shift_y; - void *plane_ptr = mpi->planes[n]; - if (mpi->flags & MP_IMGFLAG_DIRECT) { - gl->BindBuffer(GL_PIXEL_UNPACK_BUFFER, plane->gl_buffer); - if (!gl->UnmapBuffer(GL_PIXEL_UNPACK_BUFFER)) - mp_msg(MSGT_VO, MSGL_FATAL, "[gl] Video PBO upload failed. " - "Remove the 'pbo' suboption.\n"); - plane->buffer_ptr = NULL; - plane_ptr = NULL; // PBO offset 0 - } - gl->ActiveTexture(GL_TEXTURE0 + n); - gl->BindTexture(GL_TEXTURE_2D, plane->gl_texture); - glUploadTex(gl, GL_TEXTURE_2D, p->gl_format, p->gl_type, plane_ptr, - mpi->stride[n], 0, 0, w >> xs, h >> ys, 0); - } - gl->ActiveTexture(GL_TEXTURE0); - gl->BindBuffer(GL_PIXEL_UNPACK_BUFFER, 0); -skip_upload: - do_render(p); - return VO_TRUE; -} - -static mp_image_t *get_screenshot(struct gl_priv *p) -{ - GL *gl = p->gl; - - mp_image_t *image = alloc_mpi(p->texture_width, p->texture_height, - p->image_format); - - // NOTE about image formats with alpha plane: we don't even have the alpha - // anymore. We never upload it to any texture, as it would be a waste of - // time. On the other hand, we can't find a "similar", non-alpha image - // format easily. So we just leave the alpha plane of the newly allocated - // image as-is, and hope that the alpha is ignored by the receiver of the - // screenshot. (If not, code should be added to make it fully opaque.) - - for (int n = 0; n < p->plane_count; n++) { - gl->ActiveTexture(GL_TEXTURE0 + n); - gl->BindTexture(GL_TEXTURE_2D, p->planes[n].gl_texture); - glDownloadTex(gl, GL_TEXTURE_2D, p->gl_format, p->gl_type, - image->planes[n], image->stride[n]); - } - gl->ActiveTexture(GL_TEXTURE0); - - image->w = p->image_width; - image->h = p->image_height; - image->display_w = p->vo->aspdat.prew; - image->display_h = p->vo->aspdat.preh; - - mp_image_set_colorspace_details(image, &p->colorspace); - - return image; -} - -static void draw_osd_cb(void *ctx, struct sub_bitmaps *imgs) -{ - struct gl_priv *p = ctx; - GL *gl = p->gl; - - struct mpgl_osd_part *osd = mpgl_osd_generate(p->osd, imgs); - if (!osd) - return; - - assert(osd->format != SUBBITMAP_EMPTY); - - if (!osd->num_vertices) { - osd->vertices = talloc_realloc(osd, osd->vertices, struct vertex, - osd->packer->count * VERTICES_PER_QUAD); - - struct vertex *va = osd->vertices; - - for (int n = 0; n < osd->packer->count; n++) { - struct sub_bitmap *b = &imgs->parts[n]; - struct pos p = osd->packer->result[n]; - - // NOTE: the blend color is used with SUBBITMAP_LIBASS only, so it - // doesn't matter that we upload garbage for the other formats - uint32_t c = b->libass.color; - uint8_t color[4] = { c >> 24, (c >> 16) & 0xff, - (c >> 8) & 0xff, 255 - (c & 0xff) }; - - write_quad(&va[osd->num_vertices], - b->x, b->y, b->x + b->dw, b->y + b->dh, - p.x, p.y, p.x + b->w, p.y + b->h, - osd->w, osd->h, color, false); - osd->num_vertices += VERTICES_PER_QUAD; - } - } - - debug_check_gl(p, "before drawing osd"); - - gl->UseProgram(p->osd_programs[osd->format]); - mpgl_osd_set_gl_state(p->osd, osd); - draw_triangles(p, osd->vertices, osd->num_vertices); - mpgl_osd_unset_gl_state(p->osd, osd); - gl->UseProgram(0); - - debug_check_gl(p, "after drawing osd"); -} - -static void draw_osd(struct vo *vo, struct osd_state *osd) -{ - struct gl_priv *p = vo->priv; - assert(p->osd); - - osd_draw(osd, p->osd_rect, osd->vo_pts, 0, p->osd->formats, draw_osd_cb, p); -} - -// Disable features that are not supported with the current OpenGL version. -static void check_gl_features(struct gl_priv *p) -{ - GL *gl = p->gl; - bool have_float_tex = gl->mpgl_caps & MPGL_CAP_FLOAT_TEX; - bool have_fbo = gl->mpgl_caps & MPGL_CAP_FB; - bool have_srgb = gl->mpgl_caps & MPGL_CAP_SRGB_TEX; - - // srgb_compand() not available - if (gl->glsl_version < 130) - have_srgb = false; - - char *disabled[10]; - int n_disabled = 0; - - if (have_fbo) { - struct fbotex fbo = {0}; - have_fbo = fbotex_init(p, &fbo, 16, 16); - fbotex_uninit(p, &fbo); - } - - // Disable these only if the user didn't disable scale-sep on the command - // line, so convolution filter can still be forced to be run. - // Normally, we want to disable them by default if FBOs are unavailable, - // because they will be slow (not critically slow, but still slower). - // Without FP textures, we must always disable them. - if (!have_float_tex || (!have_fbo && p->use_scale_sep)) { - for (int n = 0; n < 2; n++) { - struct scaler *scaler = &p->scalers[n]; - if (mp_find_filter_kernel(scaler->name)) { - scaler->name = "bilinear"; - disabled[n_disabled++] - = have_float_tex ? "scaler (FBO)" : "scaler (float tex.)"; - } - } - } - - if (!have_srgb && p->use_srgb) { - p->use_srgb = false; - disabled[n_disabled++] = "sRGB"; - } - if (!have_fbo && p->use_lut_3d) { - p->use_lut_3d = false; - disabled[n_disabled++] = "color management (FBO)"; - } - if (!have_srgb && p->use_lut_3d) { - p->use_lut_3d = false; - disabled[n_disabled++] = "color management (sRGB)"; - } - - if (!have_fbo) { - p->use_scale_sep = false; - p->use_indirect = false; - } - - if (n_disabled) { - mp_msg(MSGT_VO, MSGL_ERR, "[gl] Some OpenGL extensions not detected, " - "disabling: "); - for (int n = 0; n < n_disabled; n++) { - if (n) - mp_msg(MSGT_VO, MSGL_ERR, ", "); - mp_msg(MSGT_VO, MSGL_ERR, "%s", disabled[n]); - } - mp_msg(MSGT_VO, MSGL_ERR, ".\n"); - } -} - -static void setup_vertex_array(GL *gl) -{ - size_t stride = sizeof(struct vertex); - - gl->EnableVertexAttribArray(VERTEX_ATTRIB_POSITION); - gl->VertexAttribPointer(VERTEX_ATTRIB_POSITION, 2, GL_FLOAT, GL_FALSE, - stride, (void*)offsetof(struct vertex, position)); - - gl->EnableVertexAttribArray(VERTEX_ATTRIB_COLOR); - gl->VertexAttribPointer(VERTEX_ATTRIB_COLOR, 4, GL_UNSIGNED_BYTE, GL_TRUE, - stride, (void*)offsetof(struct vertex, color)); - - gl->EnableVertexAttribArray(VERTEX_ATTRIB_TEXCOORD); - gl->VertexAttribPointer(VERTEX_ATTRIB_TEXCOORD, 2, GL_FLOAT, GL_FALSE, - stride, (void*)offsetof(struct vertex, texcoord)); -} - -static int init_gl(struct gl_priv *p) -{ - GL *gl = p->gl; - - debug_check_gl(p, "before init_gl"); - - const char *vendor = gl->GetString(GL_VENDOR); - const char *version = gl->GetString(GL_VERSION); - const char *renderer = gl->GetString(GL_RENDERER); - const char *glsl = gl->GetString(GL_SHADING_LANGUAGE_VERSION); - mp_msg(MSGT_VO, MSGL_V, "[gl] GL_RENDERER='%s', GL_VENDOR='%s', " - "GL_VERSION='%s', GL_SHADING_LANGUAGE_VERSION='%s'" - "\n", renderer, vendor, version, glsl); - mp_msg(MSGT_VO, MSGL_V, "[gl] Display depth: R=%d, G=%d, B=%d\n", - p->glctx->depth_r, p->glctx->depth_g, p->glctx->depth_b); - - check_gl_features(p); - - gl->Disable(GL_DITHER); - gl->Disable(GL_BLEND); - gl->Disable(GL_DEPTH_TEST); - gl->DepthMask(GL_FALSE); - gl->Disable(GL_CULL_FACE); - gl->DrawBuffer(GL_BACK); - - gl->GenBuffers(1, &p->vertex_buffer); - gl->BindBuffer(GL_ARRAY_BUFFER, p->vertex_buffer); - - if (gl->BindVertexArray) { - gl->GenVertexArrays(1, &p->vao); - gl->BindVertexArray(p->vao); - setup_vertex_array(gl); - gl->BindVertexArray(0); - } else { - setup_vertex_array(gl); - } - - gl->BindBuffer(GL_ARRAY_BUFFER, 0); - - gl->ClearColor(0.0f, 0.0f, 0.0f, 0.0f); - gl->Clear(GL_COLOR_BUFFER_BIT); - - debug_check_gl(p, "after init_gl"); - - return 1; -} - -static void uninit_gl(struct gl_priv *p) -{ - GL *gl = p->gl; - - // NOTE: GL functions might not be loaded yet - if (!(p->glctx && p->gl->DeleteTextures)) - return; - - uninit_video(p); - - if (gl->DeleteVertexArrays) - gl->DeleteVertexArrays(1, &p->vao); - p->vao = 0; - gl->DeleteBuffers(1, &p->vertex_buffer); - p->vertex_buffer = 0; - - gl->DeleteTextures(1, &p->lut_3d_texture); - p->lut_3d_texture = 0; -} - -static bool init_format(int fmt, struct gl_priv *init) -{ - bool supported = false; - struct gl_priv dummy; - if (!init) - init = &dummy; - - mp_image_t dummy_img = {0}; - mp_image_setfmt(&dummy_img, fmt); - - init->image_format = fmt; - init->component_bits = -1; - - // RGB/packed formats - for (const struct fmt_entry *e = mp_to_gl_formats; e->mp_format; e++) { - if (e->mp_format == fmt) { - supported = true; - init->plane_bits = dummy_img.bpp; - init->gl_format = e->format; - init->gl_internal_format = e->internal_format; - init->component_bits = e->component_bits; - init->gl_type = e->type; - break; - } - } - - // YUV/planar formats - if (!supported && mp_get_chroma_shift(fmt, NULL, NULL, &init->plane_bits)) { - init->gl_format = GL_RED; - init->component_bits = init->plane_bits; - if (init->plane_bits == 8) { - supported = true; - init->gl_internal_format = GL_RED; - init->gl_type = GL_UNSIGNED_BYTE; - } else if (IMGFMT_IS_YUVP16_NE(fmt)) { - supported = true; - init->gl_internal_format = GL_R16; - init->gl_type = GL_UNSIGNED_SHORT; - } - } - - // RGB/planar - if (!supported && fmt == IMGFMT_GBRP) { - supported = true; - init->plane_bits = init->component_bits = 8; - init->gl_format = GL_RED; - init->gl_internal_format = GL_RED; - init->gl_type = GL_UNSIGNED_BYTE; - } - - if (!supported) - return false; - - init->plane_bytes = (init->plane_bits + 7) / 8; - init->is_yuv = dummy_img.flags & MP_IMGFLAG_YUV; - init->is_linear_rgb = false; - - // NOTE: we throw away the additional alpha plane, if one exists. - init->plane_count = dummy_img.num_planes > 2 ? 3 : 1; - assert(dummy_img.num_planes >= init->plane_count); - assert(dummy_img.num_planes <= init->plane_count + 1); - - for (int n = 0; n < init->plane_count; n++) { - struct texplane *plane = &init->planes[n]; - - plane->shift_x = n > 0 ? dummy_img.chroma_x_shift : 0; - plane->shift_y = n > 0 ? dummy_img.chroma_y_shift : 0; - } - - return true; -} - -static int query_format(uint32_t format) -{ - int caps = VFCAP_CSP_SUPPORTED | VFCAP_CSP_SUPPORTED_BY_HW | VFCAP_FLIP | - VFCAP_HWSCALE_UP | VFCAP_HWSCALE_DOWN | VFCAP_ACCEPT_STRIDE | - VFCAP_OSD; - if (!init_format(format, NULL)) - return 0; - return caps; -} - -static bool create_window(struct gl_priv *p, uint32_t d_width, - uint32_t d_height, uint32_t flags) -{ - if (p->stereo_mode == GL_3D_QUADBUFFER) - flags |= VOFLAG_STEREO; - - if (p->use_gl_debug) - flags |= VOFLAG_GL_DEBUG; - - int mpgl_caps = MPGL_CAP_GL21 | MPGL_CAP_TEX_RG; - if (!p->allow_sw) - mpgl_caps |= MPGL_CAP_NO_SW; - return mpgl_create_window(p->glctx, mpgl_caps, d_width, d_height, flags); -} - -static int config(struct vo *vo, uint32_t width, uint32_t height, - uint32_t d_width, uint32_t d_height, uint32_t flags, - uint32_t format) -{ - struct gl_priv *p = vo->priv; - - if (!create_window(p, d_width, d_height, flags)) - return -1; - - if (!p->vertex_buffer) - init_gl(p); - - p->vo_flipped = !!(flags & VOFLAG_FLIPPING); - - if (p->image_format != format || p->image_width != width - || p->image_height != height) - { - uninit_video(p); - p->image_height = height; - p->image_width = width; - init_format(format, p); - init_video(p); - } - - resize(p); - - return 0; -} - -static void check_events(struct vo *vo) -{ - struct gl_priv *p = vo->priv; - - int e = p->glctx->check_events(vo); - if (e & VO_EVENT_REINIT) { - uninit_gl(p); - init_gl(p); - init_video(p); - resize(p); - } - if (e & VO_EVENT_RESIZE) - resize(p); - if (e & VO_EVENT_EXPOSE) - vo->want_redraw = true; -} - -static int control(struct vo *vo, uint32_t request, void *data) -{ - struct gl_priv *p = vo->priv; - - switch (request) { - case VOCTRL_QUERY_FORMAT: - return query_format(*(uint32_t *)data); - case VOCTRL_DRAW_IMAGE: - return draw_image(p, data); - case VOCTRL_ONTOP: - if (!p->glctx->ontop) - break; - p->glctx->ontop(vo); - return VO_TRUE; - case VOCTRL_PAUSE: - if (!p->glctx->pause) - break; - p->glctx->pause(vo); - return VO_TRUE; - case VOCTRL_RESUME: - if (!p->glctx->resume) - break; - p->glctx->resume(vo); - return VO_TRUE; - case VOCTRL_FULLSCREEN: - p->glctx->fullscreen(vo); - resize(p); - return VO_TRUE; - case VOCTRL_BORDER: - if (!p->glctx->border) - break; - p->glctx->border(vo); - resize(p); - return VO_TRUE; - case VOCTRL_GET_PANSCAN: - return VO_TRUE; - case VOCTRL_SET_PANSCAN: - resize(p); - return VO_TRUE; - case VOCTRL_GET_EQUALIZER: { - struct voctrl_get_equalizer_args *args = data; - return mp_csp_equalizer_get(&p->video_eq, args->name, args->valueptr) - >= 0 ? VO_TRUE : VO_NOTIMPL; - } - case VOCTRL_SET_EQUALIZER: { - struct voctrl_set_equalizer_args *args = data; - if (mp_csp_equalizer_set(&p->video_eq, args->name, args->value) < 0) - return VO_NOTIMPL; - if (!p->use_gamma && p->video_eq.values[MP_CSP_EQ_GAMMA] != 0) { - mp_msg(MSGT_VO, MSGL_V, "[gl] Auto-enabling gamma.\n"); - p->use_gamma = true; - compile_shaders(p); - } - update_all_uniforms(p); - vo->want_redraw = true; - return VO_TRUE; - } - case VOCTRL_SET_YUV_COLORSPACE: { - if (p->is_yuv) { - p->colorspace = *(struct mp_csp_details *)data; - update_all_uniforms(p); - vo->want_redraw = true; - } - return VO_TRUE; - } - case VOCTRL_GET_YUV_COLORSPACE: - *(struct mp_csp_details *)data = p->colorspace; - return VO_TRUE; - case VOCTRL_UPDATE_SCREENINFO: - if (!p->glctx->update_xinerama_info) - break; - p->glctx->update_xinerama_info(vo); - return VO_TRUE; - case VOCTRL_SCREENSHOT: { - struct voctrl_screenshot_args *args = data; - if (args->full_window) - args->out_image = glGetWindowScreenshot(p->gl); - else - args->out_image = get_screenshot(p); - return true; - } - case VOCTRL_REDRAW_FRAME: - do_render(p); - return true; - case VOCTRL_SET_COMMAND_LINE: { - char *arg = data; - if (!reparse_cmdline(p, arg)) - return false; - check_gl_features(p); - reinit_rendering(p); - resize(p); - vo->want_redraw = true; - return true; - } - } - return VO_NOTIMPL; -} - -static void uninit(struct vo *vo) -{ - struct gl_priv *p = vo->priv; - - uninit_gl(p); - mpgl_uninit(p->glctx); - p->glctx = NULL; - p->gl = NULL; -} - -#ifdef CONFIG_LCMS2 - -static void lcms2_error_handler(cmsContext ctx, cmsUInt32Number code, - const char *msg) -{ - mp_msg(MSGT_VO, MSGL_ERR, "[gl] lcms2: %s\n", msg); -} - -static struct bstr load_file(struct gl_priv *p, void *talloc_ctx, - const char *filename) -{ - struct bstr res = {0}; - stream_t *s = open_stream(filename, p->vo->opts, NULL); - if (s) { - res = stream_read_complete(s, talloc_ctx, 1000000000, 0); - free_stream(s); - } - return res; -} - -#define LUT3D_CACHE_HEADER "mpv 3dlut cache 1.0\n" - -static bool load_icc(struct gl_priv *p, const char *icc_file, - const char *icc_cache, int icc_intent, - int s_r, int s_g, int s_b) -{ - void *tmp = talloc_new(p); - uint16_t *output = talloc_array(tmp, uint16_t, s_r * s_g * s_b * 3); - - if (icc_intent == -1) - icc_intent = INTENT_ABSOLUTE_COLORIMETRIC; - - mp_msg(MSGT_VO, MSGL_INFO, "[gl] Opening ICC profile '%s'\n", icc_file); - struct bstr iccdata = load_file(p, tmp, icc_file); - if (!iccdata.len) - goto error_exit; - - char *cache_info = talloc_asprintf(tmp, "intent=%d, size=%dx%dx%d\n", - icc_intent, s_r, s_g, s_b); - - // check cache - if (icc_cache) { - mp_msg(MSGT_VO, MSGL_INFO, "[gl] Opening 3D LUT cache in file '%s'.\n", - icc_cache); - struct bstr cachedata = load_file(p, tmp, icc_cache); - if (bstr_eatstart(&cachedata, bstr0(LUT3D_CACHE_HEADER)) - && bstr_eatstart(&cachedata, bstr0(cache_info)) - && bstr_eatstart(&cachedata, iccdata) - && cachedata.len == talloc_get_size(output)) - { - memcpy(output, cachedata.start, cachedata.len); - goto done; - } else { - mp_msg(MSGT_VO, MSGL_WARN, "[gl] 3D LUT cache invalid!\n"); - } - } - - cmsSetLogErrorHandler(lcms2_error_handler); - - cmsHPROFILE profile = cmsOpenProfileFromMem(iccdata.start, iccdata.len); - if (!profile) - goto error_exit; - - cmsCIExyY d65; - cmsWhitePointFromTemp(&d65, 6504); - static const cmsCIExyYTRIPLE bt709prim = { - .Red = {0.64, 0.33, 1.0}, - .Green = {0.30, 0.60, 1.0}, - .Blue = {0.15, 0.06, 1.0}, - }; - cmsToneCurve *tonecurve = cmsBuildGamma(NULL, 2.2); - cmsHPROFILE vid_profile = cmsCreateRGBProfile(&d65, &bt709prim, - (cmsToneCurve*[3]){tonecurve, tonecurve, tonecurve}); - cmsFreeToneCurve(tonecurve); - cmsHTRANSFORM trafo = cmsCreateTransform(vid_profile, TYPE_RGB_16, - profile, TYPE_RGB_16, - icc_intent, - cmsFLAGS_HIGHRESPRECALC); - cmsCloseProfile(profile); - cmsCloseProfile(vid_profile); - - if (!trafo) - goto error_exit; - - // transform a (s_r)x(s_g)x(s_b) cube, with 3 components per channel - uint16_t *input = talloc_array(tmp, uint16_t, s_r * 3); - for (int b = 0; b < s_b; b++) { - for (int g = 0; g < s_g; g++) { - for (int r = 0; r < s_r; r++) { - input[r * 3 + 0] = r * 65535 / (s_r - 1); - input[r * 3 + 1] = g * 65535 / (s_g - 1); - input[r * 3 + 2] = b * 65535 / (s_b - 1); - } - size_t base = (b * s_r * s_g + g * s_r) * 3; - cmsDoTransform(trafo, input, output + base, s_r); - } - } - - cmsDeleteTransform(trafo); - - if (icc_cache) { - FILE *out = fopen(icc_cache, "wb"); - if (out) { - fprintf(out, "%s%s", LUT3D_CACHE_HEADER, cache_info); - fwrite(iccdata.start, iccdata.len, 1, out); - fwrite(output, talloc_get_size(output), 1, out); - fclose(out); - } - } - -done: - - p->lut_3d_data = talloc_steal(p, output); - p->lut_3d_w = s_r, p->lut_3d_h = s_g, p->lut_3d_d = s_b; - p->use_lut_3d = true; - - talloc_free(tmp); - return true; - -error_exit: - mp_msg(MSGT_VO, MSGL_FATAL, "[gl] Error loading ICC profile.\n"); - talloc_free(tmp); - return false; -} - -#else /* CONFIG_LCMS2 */ - -static bool load_icc(struct gl_priv *p, ...) -{ - mp_msg(MSGT_VO, MSGL_FATAL, "[gl] LCMS2 support not compiled.\n"); - return false; -} - -#endif /* CONFIG_LCMS2 */ - -static bool parse_3dlut_size(const char *s, int *p1, int *p2, int *p3) -{ - if (sscanf(s, "%dx%dx%d", p1, p2, p3) != 3) - return false; - for (int n = 0; n < 3; n++) { - int s = ((int[]) { *p1, *p2, *p3 })[n]; - if (s < 2 || s > 256 || ((s - 1) & s)) - return false; - } - return true; -} - -static int lut3d_size_valid(void *arg) -{ - char *s = *(char **)arg; - int p1, p2, p3; - return parse_3dlut_size(s, &p1, &p2, &p3); -} - -static int backend_valid(void *arg) -{ - return mpgl_find_backend(*(const char **)arg) >= 0; -} - -struct fbo_format { - const char *name; - GLint format; -}; - -const struct fbo_format fbo_formats[] = { - {"rgb", GL_RGB}, - {"rgba", GL_RGBA}, - {"rgb8", GL_RGB8}, - {"rgb10", GL_RGB10}, - {"rgb16", GL_RGB16}, - {"rgb16f", GL_RGB16F}, - {"rgb32f", GL_RGB32F}, - {0} -}; - -static GLint find_fbo_format(const char *name) -{ - for (const struct fbo_format *fmt = fbo_formats; fmt->name; fmt++) { - if (strcmp(fmt->name, name) == 0) - return fmt->format; - } - return -1; -} - -static int fbo_format_valid(void *arg) -{ - return find_fbo_format(*(const char **)arg) >= 0; -} - -static bool can_use_filter_kernel(const struct filter_kernel *kernel) -{ - if (!kernel) - return false; - struct filter_kernel k = *kernel; - return mp_init_filter(&k, filter_sizes, 1); -} - -static const char* handle_scaler_opt(const char *name) -{ - const struct filter_kernel *kernel = mp_find_filter_kernel(name); - if (can_use_filter_kernel(kernel)) - return kernel->name; - - for (const char **filter = fixed_scale_filters; *filter; filter++) { - if (strcmp(*filter, name) == 0) - return *filter; - } - - return NULL; -} - -static int scaler_valid(void *arg) -{ - return handle_scaler_opt(*(const char **)arg) != NULL; -} - -#if 0 -static void print_scalers(void) -{ - mp_msg(MSGT_VO, MSGL_INFO, "Available scalers:\n"); - for (const char **e = fixed_scale_filters; *e; e++) { - mp_msg(MSGT_VO, MSGL_INFO, " %s\n", *e); - } - for (const struct filter_kernel *e = mp_filter_kernels; e->name; e++) { - if (can_use_filter_kernel(e)) - mp_msg(MSGT_VO, MSGL_INFO, " %s\n", e->name); - } -} -#endif - -static bool reparse_cmdline(struct gl_priv *p, char *arg) -{ - struct gl_priv tmp = *p->defaults; - struct gl_priv *opt = &tmp; - - if (strcmp(arg, "-") == 0) { - tmp = *p->orig_cmdline; - arg = ""; - } - - char *scalers[2] = {0}; - char *fbo_format = NULL; - - const opt_t subopts[] = { - {"srgb", OPT_ARG_BOOL, &opt->use_srgb}, - {"pbo", OPT_ARG_BOOL, &opt->use_pbo}, - {"glfinish", OPT_ARG_BOOL, &opt->use_glFinish}, - {"swapinterval", OPT_ARG_INT, &opt->swap_interval}, - {"osdcolor", OPT_ARG_INT, &opt->osd_color}, - {"lscale", OPT_ARG_MSTRZ, &scalers[0], scaler_valid}, - {"cscale", OPT_ARG_MSTRZ, &scalers[1], scaler_valid}, - {"lparam1", OPT_ARG_FLOAT, &opt->scaler_params[0]}, - {"lparam2", OPT_ARG_FLOAT, &opt->scaler_params[1]}, - {"fancy-downscaling", OPT_ARG_BOOL, &opt->use_fancy_downscaling}, - {"indirect", OPT_ARG_BOOL, &opt->use_indirect}, - {"scale-sep", OPT_ARG_BOOL, &opt->use_scale_sep}, - {"fbo-format", OPT_ARG_MSTRZ, &fbo_format, fbo_format_valid}, - {"dither-depth", OPT_ARG_INT, &opt->dither_depth}, - {NULL} - }; - - if (subopt_parse(arg, subopts) != 0) - return false; - - p->fbo_format = opt->fbo_format; - if (fbo_format) - p->fbo_format = find_fbo_format(fbo_format); - free(fbo_format); - - for (int n = 0; n < 2; n++) { - p->scalers[n].name = opt->scalers[n].name; - if (scalers[n]) - p->scalers[n].name = handle_scaler_opt(scalers[n]); - free(scalers[n]); - } - - // xxx ideally we'd put all options into an option struct, and just copy - p->use_srgb = opt->use_srgb; //xxx changing srgb will be wrong on RGB input! - p->use_pbo = opt->use_pbo; - p->use_glFinish = opt->use_glFinish; - p->swap_interval = opt->swap_interval; - p->osd_color = opt->osd_color; - memcpy(p->scaler_params, opt->scaler_params, sizeof(p->scaler_params)); - p->use_fancy_downscaling = opt->use_fancy_downscaling; - p->use_indirect = opt->use_indirect; - p->use_scale_sep = opt->use_scale_sep; - p->dither_depth = opt->dither_depth; - - check_gl_features(p); - - return true; -} - -static int preinit(struct vo *vo, const char *arg) -{ - struct gl_priv *p = talloc_zero(vo, struct gl_priv); - vo->priv = p; - - bool hq = strcmp(vo->driver->info->short_name, "opengl-hq") == 0; - - *p = (struct gl_priv) { - .vo = vo, - .colorspace = MP_CSP_DETAILS_DEFAULTS, - .use_npot = 1, - .use_pbo = hq, - .swap_interval = vo_vsync, - .osd_color = 0xffffff, - .dither_depth = hq ? 0 : -1, - .fbo_format = hq ? GL_RGB16 : GL_RGB, - .use_scale_sep = 1, - .scalers = { - { .index = 0, .name = hq ? "lanczos2" : "bilinear" }, - { .index = 1, .name = "bilinear" }, - }, - .scaler_params = {NAN, NAN}, - .scratch = talloc_zero_array(p, char *, 1), - }; - - p->defaults = talloc(p, struct gl_priv); - *p->defaults = *p; - - char *scalers[2] = {0}; - char *backend_arg = NULL; - char *fbo_format = NULL; - char *icc_profile = NULL; - char *icc_cache = NULL; - int icc_intent = -1; - char *icc_size_str = NULL; - - const opt_t subopts[] = { - {"gamma", OPT_ARG_BOOL, &p->use_gamma}, - {"srgb", OPT_ARG_BOOL, &p->use_srgb}, - {"npot", OPT_ARG_BOOL, &p->use_npot}, - {"pbo", OPT_ARG_BOOL, &p->use_pbo}, - {"glfinish", OPT_ARG_BOOL, &p->use_glFinish}, - {"swapinterval", OPT_ARG_INT, &p->swap_interval}, - {"osdcolor", OPT_ARG_INT, &p->osd_color}, - {"stereo", OPT_ARG_INT, &p->stereo_mode}, - {"lscale", OPT_ARG_MSTRZ, &scalers[0], scaler_valid}, - {"cscale", OPT_ARG_MSTRZ, &scalers[1], scaler_valid}, - {"lparam1", OPT_ARG_FLOAT, &p->scaler_params[0]}, - {"lparam2", OPT_ARG_FLOAT, &p->scaler_params[1]}, - {"fancy-downscaling", OPT_ARG_BOOL, &p->use_fancy_downscaling}, - {"debug", OPT_ARG_BOOL, &p->use_gl_debug}, - {"indirect", OPT_ARG_BOOL, &p->use_indirect}, - {"scale-sep", OPT_ARG_BOOL, &p->use_scale_sep}, - {"fbo-format", OPT_ARG_MSTRZ, &fbo_format, fbo_format_valid}, - {"backend", OPT_ARG_MSTRZ, &backend_arg, backend_valid}, - {"sw", OPT_ARG_BOOL, &p->allow_sw}, - {"icc-profile", OPT_ARG_MSTRZ, &icc_profile}, - {"icc-cache", OPT_ARG_MSTRZ, &icc_cache}, - {"icc-intent", OPT_ARG_INT, &icc_intent}, - {"3dlut-size", OPT_ARG_MSTRZ, &icc_size_str, - lut3d_size_valid}, - {"dither-depth", OPT_ARG_INT, &p->dither_depth}, - {NULL} - }; - - if (subopt_parse(arg, subopts) != 0) { - mp_msg(MSGT_VO, MSGL_FATAL, help_text); - goto err_out; - } - - int backend = backend_arg ? mpgl_find_backend(backend_arg) : GLTYPE_AUTO; - free(backend_arg); - - if (fbo_format) - p->fbo_format = find_fbo_format(fbo_format); - free(fbo_format); - - for (int n = 0; n < 2; n++) { - if (scalers[n]) - p->scalers[n].name = handle_scaler_opt(scalers[n]); - free(scalers[n]); - } - - int s_r = 128, s_g = 256, s_b = 64; - if (icc_size_str) - parse_3dlut_size(icc_size_str, &s_r, &s_g, &s_b); - free(icc_size_str); - - bool success = true; - if (icc_profile) { - success = load_icc(p, icc_profile, icc_cache, icc_intent, - s_r, s_g, s_b); - } - free(icc_profile); - free(icc_cache); - - if (!success) - goto err_out; - - p->orig_cmdline = talloc(p, struct gl_priv); - *p->orig_cmdline = *p; - - p->glctx = mpgl_init(backend, vo); - if (!p->glctx) - goto err_out; - p->gl = p->glctx->gl; - - if (!create_window(p, 320, 200, VOFLAG_HIDDEN)) - goto err_out; - check_gl_features(p); - // We created a window to test whether the GL context could be - // created and so on. Destroy that window to make sure all state - // associated with it is lost. - uninit_gl(p); - if (!mpgl_destroy_window(p->glctx)) - goto err_out; - - return 0; - -err_out: - uninit(vo); - return -1; -} - -const struct vo_driver video_out_opengl = { - .is_new = true, - .info = &(const vo_info_t) { - "Extended OpenGL Renderer", - "opengl", - "Based on vo_gl.c by Reimar Doeffinger", - "" - }, - .preinit = preinit, - .config = config, - .control = control, - .draw_slice = draw_slice, - .draw_osd = draw_osd, - .flip_page = flip_page, - .check_events = check_events, - .uninit = uninit, -}; - -const struct vo_driver video_out_opengl_hq = { - .is_new = true, - .info = &(const vo_info_t) { - "Extended OpenGL Renderer (high quality rendering preset)", - "opengl-hq", - "Based on vo_gl.c by Reimar Doeffinger", - "" - }, - .preinit = preinit, - .config = config, - .control = control, - .draw_slice = draw_slice, - .draw_osd = draw_osd, - .flip_page = flip_page, - .check_events = check_events, - .uninit = uninit, -}; - -static const char help_text[] = -"\n--vo=opengl command line help:\n" -"Example: mpv --vo=opengl:scale-sep:lscale=lanczos2\n" -"\nOptions:\n" -" lscale=<filter>\n" -" Set the scaling filter. Possible choices:\n" -" bilinear: bilinear texture filtering (fastest).\n" -" bicubic_fast: bicubic filter (without lookup texture).\n" -" sharpen3: unsharp masking (sharpening) with radius=3.\n" -" sharpen5: unsharp masking (sharpening) with radius=5.\n" -" lanczos2: Lanczos with radius=2 (recommended).\n" -" lanczos3: Lanczos with radius=3 (not recommended).\n" -" mitchell: Mitchell-Netravali.\n" -" Default: bilinear\n" -" lparam1=<value> / lparam2=<value>\n" -" Set parameters for configurable filters. Affects chroma scaler\n" -" as well.\n" -" Filters which use this:\n" -" mitchell: b and c params (defaults: b=1/3 c=1/3)\n" -" kaiser: (defaults: 6.33 6.33)\n" -" sharpen3: lparam1 sets sharpening strength (default: 0.5)\n" -" sharpen5: as with sharpen3\n" -" osdcolor=<0xAARRGGBB>\n" -" Use the given color for the OSD.\n" -" stereo=<n>\n" -" 0: normal display\n" -" 1: side-by-side to red-cyan stereo\n" -" 2: side-by-side to green-magenta stereo\n" -" 3: side-by-side to quadbuffer stereo\n" -" srgb\n" -" Enable gamma-correct scaling by working in linear light. This\n" -" makes use of sRGB textures and framebuffers.\n" -" This option forces the options 'indirect' and 'gamma'.\n" -" NOTE: For YUV colorspaces, gamma 2.2 is assumed. RGB input is always\n" -" assumed to be in sRGB.\n" -" pbo\n" -" Enable use of PBOs. This is faster, but can sometimes lead to\n" -" sporadic and temporary image corruption.\n" -" dither-depth=<n>\n" -" Positive non-zero values select the target bit depth.\n" -" -1: Disable any dithering done by mpv.\n" -" 0: Automatic selection. If output bit depth can't be detected,\n" -" 8 bits per component are assumed.\n" -" 8: Dither to 8 bit output.\n" -" Default: -1.\n" -" Note that dithering will always be disabled if the bit depth\n" -" of the video is lower or qual to the detected dither-depth.\n" -" If color management is enabled, input depth is assumed to be\n" -" 16 bits, because the 3D LUT output is 16 bit wide.\n" -" debug\n" -" Check for OpenGL errors, i.e. call glGetError(). Also request a\n" -" debug OpenGL context.\n" -"Less useful options:\n" -" swapinterval=<n>\n" -" Interval in displayed frames between to buffer swaps.\n" -" 1 is equivalent to enable VSYNC, 0 to disable VSYNC.\n" -" no-scale-sep\n" -" When using a separable scale filter for luma, usually two filter\n" -" passes are done. This is often faster. However, it forces\n" -" conversion to RGB in an extra pass, so it can actually be slower\n" -" if used with fast filters on small screen resolutions. Using\n" -" this options will make rendering a single operation.\n" -" Note that chroma scalers are always done as 1-pass filters.\n" -" cscale=<n>\n" -" As lscale but for chroma (2x slower with little visible effect).\n" -" Note that with some scaling filters, upscaling is always done in\n" -" RGB. If chroma is not subsampled, this option is ignored, and the\n" -" luma scaler is used instead. Setting this option is often useless.\n" -" fancy-downscaling\n" -" When using convolution based filters, extend the filter size\n" -" when downscaling. Trades quality for reduced downscaling performance.\n" -" no-npot\n" -" Force use of power-of-2 texture sizes. For debugging only.\n" -" Borders will look discolored due to filtering.\n" -" glfinish\n" -" Call glFinish() before swapping buffers\n" -" backend=<sys>\n" -" auto: auto-select (default)\n" -" cocoa: Cocoa/OSX\n" -" win: Win32/WGL\n" -" x11: X11/GLX\n" -" indirect\n" -" Do YUV conversion and scaling as separate passes. This will\n" -" first render the video into a video-sized RGB texture, and\n" -" draw the result on screen. The luma scaler is used to scale\n" -" the RGB image when rendering to screen. The chroma scaler\n" -" is used only on YUV conversion, and only if the video uses\n" -" chroma-subsampling.\n" -" This mechanism is disabled on RGB input.\n" -" fbo-format=<fmt>\n" -" Selects the internal format of any FBO textures used.\n" -" fmt can be one of: rgb, rgba, rgb8, rgb10, rgb16, rgb16f, rgb32f\n" -" Default: rgb.\n" -" gamma\n" -" Always enable gamma control. (Disables delayed enabling.)\n" -"Color management:\n" -" icc-profile=<file>\n" -" Load an ICC profile and use it to transform linear RGB to\n" -" screen output. Needs LittleCMS2 support compiled in.\n" -" icc-cache=<file>\n" -" Store and load the 3D LUT created from the ICC profile in\n" -" this file. This can be used to speed up loading, since\n" -" LittleCMS2 can take a while to create the 3D LUT.\n" -" Note that this file will be up to ~100 MB big.\n" -" icc-intent=<value>\n" -" 0: perceptual\n" -" 1: relative colorimetric\n" -" 2: saturation\n" -" 3: absolute colorimetric (default)\n" -" 3dlut-size=<r>x<g>x<b>\n" -" Size of the 3D LUT generated from the ICC profile in each\n" -" dimension. Default is 128x256x64.\n" -" Sizes must be a power of two, and 256 at most.\n" -"Note: all defaults mentioned are for 'opengl', not 'opengl-hq'.\n" -"\n"; diff --git a/libvo/vo_opengl_old.c b/libvo/vo_opengl_old.c deleted file mode 100644 index b8b1fd4813..0000000000 --- a/libvo/vo_opengl_old.c +++ /dev/null @@ -1,1166 +0,0 @@ -/* - * 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. - * - * You can alternatively redistribute this file and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - */ - -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <math.h> -#include <stdbool.h> -#include <assert.h> - -#include "config.h" -#include "talloc.h" -#include "mp_msg.h" -#include "subopt-helper.h" -#include "video_out.h" -#include "libmpcodecs/vfcap.h" -#include "libmpcodecs/mp_image.h" -#include "geometry.h" -#include "sub/sub.h" - -#include "gl_common.h" -#include "gl_osd.h" -#include "aspect.h" -#include "fastmemcpy.h" - -//for gl_priv.use_yuv -#define MASK_ALL_YUV (~(1 << YUV_CONVERSION_NONE)) -#define MASK_NOT_COMBINERS (~((1 << YUV_CONVERSION_NONE) | (1 << YUV_CONVERSION_COMBINERS))) -#define MASK_GAMMA_SUPPORT (MASK_NOT_COMBINERS & ~(1 << YUV_CONVERSION_FRAGMENT)) - -struct gl_priv { - MPGLContext *glctx; - GL *gl; - - int allow_sw; - - int use_osd; - int scaled_osd; - struct mpgl_osd *osd; - int osd_color; - - int use_ycbcr; - int use_yuv; - struct mp_csp_details colorspace; - int is_yuv; - int lscale; - int cscale; - float filter_strength; - float noise_strength; - int yuvconvtype; - int use_rectangle; - int err_shown; - uint32_t image_width; - uint32_t image_height; - uint32_t image_format; - int many_fmts; - int have_texture_rg; - int ati_hack; - int force_pbo; - int use_glFinish; - int swap_interval; - GLenum target; - GLint texfmt; - GLenum gl_format; - GLenum gl_type; - GLuint buffer; - GLuint buffer_uv[2]; - int buffersize; - int buffersize_uv; - void *bufferptr; - void *bufferptr_uv[2]; - GLuint fragprog; - GLuint default_texs[22]; - char *custom_prog; - char *custom_tex; - int custom_tlin; - int custom_trect; - int mipmap_gen; - int stereo_mode; - - struct mp_csp_equalizer video_eq; - - int texture_width; - int texture_height; - int mpi_flipped; - int vo_flipped; - int ass_border_x, ass_border_y; - - unsigned int slice_height; -}; - -static void resize(struct vo *vo, int x, int y) -{ - struct gl_priv *p = vo->priv; - GL *gl = p->gl; - - mp_msg(MSGT_VO, MSGL_V, "[gl] Resize: %dx%d\n", x, y); - gl->Viewport(0, 0, x, y); - - gl->MatrixMode(GL_PROJECTION); - gl->LoadIdentity(); - p->ass_border_x = p->ass_border_y = 0; - if (aspect_scaling()) { - int new_w, new_h; - GLdouble scale_x, scale_y; - aspect(vo, &new_w, &new_h, A_WINZOOM); - panscan_calc_windowed(vo); - new_w += vo->panscan_x; - new_h += vo->panscan_y; - scale_x = (GLdouble)new_w / (GLdouble)x; - scale_y = (GLdouble)new_h / (GLdouble)y; - gl->Scaled(scale_x, scale_y, 1); - p->ass_border_x = (vo->dwidth - new_w) / 2; - p->ass_border_y = (vo->dheight - new_h) / 2; - } - gl->Ortho(0, p->image_width, p->image_height, 0, -1, 1); - - gl->MatrixMode(GL_MODELVIEW); - gl->LoadIdentity(); - - gl->Clear(GL_COLOR_BUFFER_BIT); - vo->want_redraw = true; -} - -static void texSize(struct vo *vo, int w, int h, int *texw, int *texh) -{ - struct gl_priv *p = vo->priv; - - if (p->use_rectangle) { - *texw = w; - *texh = h; - } else { - *texw = 32; - while (*texw < w) - *texw *= 2; - *texh = 32; - while (*texh < h) - *texh *= 2; - } - if (p->ati_hack) - *texw = (*texw + 511) & ~511; -} - -//! maximum size of custom fragment program -#define MAX_CUSTOM_PROG_SIZE (1024 * 1024) -static void update_yuvconv(struct vo *vo) -{ - struct gl_priv *p = vo->priv; - GL *gl = p->gl; - - int xs, ys, depth; - struct mp_csp_params cparams = { .colorspace = p->colorspace }; - mp_csp_copy_equalizer_values(&cparams, &p->video_eq); - gl_conversion_params_t params = { - p->target, p->yuvconvtype, cparams, - p->texture_width, p->texture_height, 0, 0, p->filter_strength, - p->noise_strength - }; - mp_get_chroma_shift(p->image_format, &xs, &ys, &depth); - params.chrom_texw = params.texw >> xs; - params.chrom_texh = params.texh >> ys; - params.csp_params.input_bits = depth; - params.csp_params.texture_bits = depth+7 & ~7; - glSetupYUVConversion(gl, ¶ms); - if (p->custom_prog) { - FILE *f = fopen(p->custom_prog, "rb"); - if (!f) { - mp_msg(MSGT_VO, MSGL_WARN, - "[gl] Could not read customprog %s\n", p->custom_prog); - } else { - char *prog = calloc(1, MAX_CUSTOM_PROG_SIZE + 1); - fread(prog, 1, MAX_CUSTOM_PROG_SIZE, f); - fclose(f); - loadGPUProgram(gl, GL_FRAGMENT_PROGRAM, prog); - free(prog); - } - gl->ProgramEnvParameter4f(GL_FRAGMENT_PROGRAM, 0, - 1.0 / p->texture_width, - 1.0 / p->texture_height, - p->texture_width, p->texture_height); - } - if (p->custom_tex) { - FILE *f = fopen(p->custom_tex, "rb"); - if (!f) { - mp_msg(MSGT_VO, MSGL_WARN, - "[gl] Could not read customtex %s\n", p->custom_tex); - } else { - int width, height, maxval; - gl->ActiveTexture(GL_TEXTURE3); - if (glCreatePPMTex(gl, p->custom_trect ? GL_TEXTURE_RECTANGLE : GL_TEXTURE_2D, - 0, p->custom_tlin ? GL_LINEAR : GL_NEAREST, - f, &width, &height, &maxval)) { - gl->ProgramEnvParameter4f(GL_FRAGMENT_PROGRAM, 1, - 1.0 / width, 1.0 / height, - width, height); - } else - mp_msg(MSGT_VO, MSGL_WARN, - "[gl] Error parsing customtex %s\n", p->custom_tex); - fclose(f); - gl->ActiveTexture(GL_TEXTURE0); - } - } -} - -static void draw_osd(struct vo *vo, struct osd_state *osd) -{ - struct gl_priv *p = vo->priv; - GL *gl = p->gl; - assert(p->osd); - - if (!p->use_osd) - return; - - if (!p->scaled_osd) { - gl->MatrixMode(GL_PROJECTION); - gl->PushMatrix(); - gl->LoadIdentity(); - gl->Ortho(0, vo->dwidth, vo->dheight, 0, -1, 1); - } - - gl->Color4ub((p->osd_color >> 16) & 0xff, (p->osd_color >> 8) & 0xff, - p->osd_color & 0xff, 0xff - (p->osd_color >> 24)); - - struct mp_osd_res res = { - .w = vo->dwidth, - .h = vo->dheight, - .display_par = vo->monitor_par, - .video_par = vo->aspdat.par, - }; - if (p->scaled_osd) { - res.w = p->image_width; - res.h = p->image_height; - } else if (aspect_scaling()) { - res.ml = res.mr = p->ass_border_x; - res.mt = res.mb = p->ass_border_y; - } - - mpgl_osd_draw_legacy(p->osd, osd, res); - - if (!p->scaled_osd) - gl->PopMatrix(); -} - -/** - * \brief uninitialize OpenGL context, freeing textures, buffers etc. - */ -static void uninitGl(struct vo *vo) -{ - struct gl_priv *p = vo->priv; - GL *gl = p->gl; - - if (!gl) - return; - - int i = 0; - if (gl->DeletePrograms && p->fragprog) - gl->DeletePrograms(1, &p->fragprog); - p->fragprog = 0; - while (p->default_texs[i] != 0) - i++; - if (i) - gl->DeleteTextures(i, p->default_texs); - p->default_texs[0] = 0; - if (p->osd) - mpgl_osd_destroy(p->osd); - p->osd = NULL; - p->buffer = 0; - p->buffersize = 0; - p->bufferptr = NULL; - if (gl->DeleteBuffers && p->buffer_uv[0]) - gl->DeleteBuffers(2, p->buffer_uv); - p->buffer_uv[0] = p->buffer_uv[1] = 0; - p->buffersize_uv = 0; - p->bufferptr_uv[0] = p->bufferptr_uv[1] = 0; - p->err_shown = 0; -} - -static void autodetectGlExtensions(struct vo *vo) -{ - struct gl_priv *p = vo->priv; - GL *gl = p->gl; - - const char *extensions = gl->GetString(GL_EXTENSIONS); - const char *vendor = gl->GetString(GL_VENDOR); - const char *version = gl->GetString(GL_VERSION); - const char *renderer = gl->GetString(GL_RENDERER); - int is_ati = vendor && strstr(vendor, "ATI") != NULL; - int ati_broken_pbo = 0; - mp_msg(MSGT_VO, MSGL_V, "[gl] Running on OpenGL '%s' by '%s', version '%s'\n", - renderer, vendor, version); - if (is_ati && strncmp(version, "2.1.", 4) == 0) { - int ver = atoi(version + 4); - mp_msg(MSGT_VO, MSGL_V, "[gl] Detected ATI driver version: %i\n", ver); - ati_broken_pbo = ver && ver < 8395; - } - if (p->ati_hack == -1) - p->ati_hack = ati_broken_pbo; - if (p->force_pbo == -1) { - p->force_pbo = 0; - if (extensions && strstr(extensions, "_pixel_buffer_object")) - p->force_pbo = is_ati; - } - p->have_texture_rg = extensions && strstr(extensions, "GL_ARB_texture_rg"); - if (p->use_rectangle == -1) { - p->use_rectangle = 0; - if (extensions) { -// if (strstr(extensions, "_texture_non_power_of_two")) - if (strstr(extensions, "_texture_rectangle")) - p->use_rectangle = renderer - && strstr(renderer, "Mesa DRI R200") ? 1 : 0; - } - } - if (p->use_osd == -1) - p->use_osd = gl->BindTexture != NULL; - if (p->use_yuv == -1) - p->use_yuv = glAutodetectYUVConversion(gl); - - int eq_caps = 0; - int yuv_mask = (1 << p->use_yuv); - if (!(yuv_mask & MASK_NOT_COMBINERS)) { - // combiners - eq_caps = (1 << MP_CSP_EQ_HUE) | (1 << MP_CSP_EQ_SATURATION); - } else if (yuv_mask & MASK_ALL_YUV) { - eq_caps = MP_CSP_EQ_CAPS_COLORMATRIX; - if (yuv_mask & MASK_GAMMA_SUPPORT) - eq_caps |= MP_CSP_EQ_CAPS_GAMMA; - } - p->video_eq.capabilities = eq_caps; - - if (is_ati && (p->lscale == 1 || p->lscale == 2 || p->cscale == 1 || p->cscale == 2)) - mp_msg(MSGT_VO, MSGL_WARN, "[gl] Selected scaling mode may be broken on" - " ATI cards.\n" - "Tell _them_ to fix GL_REPEAT if you have issues.\n"); - mp_msg(MSGT_VO, MSGL_V, "[gl] Settings after autodetection: ati-hack = %i, " - "force-pbo = %i, rectangle = %i, yuv = %i\n", - p->ati_hack, p->force_pbo, p->use_rectangle, p->use_yuv); -} - -static GLint get_scale_type(struct vo *vo, int chroma) -{ - struct gl_priv *p = vo->priv; - - int nearest = (chroma ? p->cscale : p->lscale) & 64; - if (nearest) - return p->mipmap_gen ? GL_NEAREST_MIPMAP_NEAREST : GL_NEAREST; - return p->mipmap_gen ? GL_LINEAR_MIPMAP_NEAREST : GL_LINEAR; -} - -// Return the high byte of the value that represents white in chroma (U/V) -static int get_chroma_clear_val(int bit_depth) -{ - return 1 << (bit_depth - 1 & 7); -} - -/** - * \brief Initialize a (new or reused) OpenGL context. - * set global gl-related variables to their default values - */ -static int initGl(struct vo *vo, uint32_t d_width, uint32_t d_height) -{ - struct gl_priv *p = vo->priv; - GL *gl = p->gl; - - GLint scale_type = get_scale_type(vo, 0); - autodetectGlExtensions(vo); - p->target = p->use_rectangle == 1 ? GL_TEXTURE_RECTANGLE : GL_TEXTURE_2D; - p->yuvconvtype = SET_YUV_CONVERSION(p->use_yuv) | - SET_YUV_LUM_SCALER(p->lscale) | - SET_YUV_CHROM_SCALER(p->cscale); - - texSize(vo, p->image_width, p->image_height, - &p->texture_width, &p->texture_height); - - gl->Disable(GL_BLEND); - gl->Disable(GL_DEPTH_TEST); - gl->DepthMask(GL_FALSE); - gl->Disable(GL_CULL_FACE); - gl->Enable(p->target); - gl->DrawBuffer(GL_BACK); - gl->TexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); - - mp_msg(MSGT_VO, MSGL_V, "[gl] Creating %dx%d texture...\n", - p->texture_width, p->texture_height); - - glCreateClearTex(gl, p->target, p->texfmt, p->gl_format, - p->gl_type, scale_type, - p->texture_width, p->texture_height, 0); - - if (p->mipmap_gen) - gl->TexParameteri(p->target, GL_GENERATE_MIPMAP, GL_TRUE); - - if (p->is_yuv) { - int i; - int xs, ys, depth; - scale_type = get_scale_type(vo, 1); - mp_get_chroma_shift(p->image_format, &xs, &ys, &depth); - int clear = get_chroma_clear_val(depth); - gl->GenTextures(21, p->default_texs); - p->default_texs[21] = 0; - for (i = 0; i < 7; i++) { - gl->ActiveTexture(GL_TEXTURE1 + i); - gl->BindTexture(GL_TEXTURE_2D, p->default_texs[i]); - gl->BindTexture(GL_TEXTURE_RECTANGLE, p->default_texs[i + 7]); - gl->BindTexture(GL_TEXTURE_3D, p->default_texs[i + 14]); - } - gl->ActiveTexture(GL_TEXTURE1); - glCreateClearTex(gl, p->target, p->texfmt, p->gl_format, - p->gl_type, scale_type, - p->texture_width >> xs, p->texture_height >> ys, - clear); - if (p->mipmap_gen) - gl->TexParameteri(p->target, GL_GENERATE_MIPMAP, GL_TRUE); - gl->ActiveTexture(GL_TEXTURE2); - glCreateClearTex(gl, p->target, p->texfmt, p->gl_format, - p->gl_type, scale_type, - p->texture_width >> xs, p->texture_height >> ys, - clear); - if (p->mipmap_gen) - gl->TexParameteri(p->target, GL_GENERATE_MIPMAP, GL_TRUE); - gl->ActiveTexture(GL_TEXTURE0); - gl->BindTexture(p->target, 0); - } - if (p->is_yuv || p->custom_prog) { - if ((MASK_NOT_COMBINERS & (1 << p->use_yuv)) || p->custom_prog) { - if (!gl->GenPrograms || !gl->BindProgram) - mp_msg(MSGT_VO, MSGL_ERR, - "[gl] fragment program functions missing!\n"); - else { - gl->GenPrograms(1, &p->fragprog); - gl->BindProgram(GL_FRAGMENT_PROGRAM, p->fragprog); - } - } - update_yuvconv(vo); - } - - p->osd = mpgl_osd_init(gl, true); - p->osd->scaled = p->scaled_osd; - - resize(vo, d_width, d_height); - - gl->ClearColor(0.0f, 0.0f, 0.0f, 0.0f); - gl->Clear(GL_COLOR_BUFFER_BIT); - if (gl->SwapInterval && p->swap_interval >= 0) - gl->SwapInterval(p->swap_interval); - return 1; -} - -static bool create_window(struct vo *vo, uint32_t d_width, uint32_t d_height, - uint32_t flags) -{ - struct gl_priv *p = vo->priv; - - if (p->stereo_mode == GL_3D_QUADBUFFER) - flags |= VOFLAG_STEREO; - - int mpgl_caps = MPGL_CAP_GL_LEGACY; - if (!p->allow_sw) - mpgl_caps |= MPGL_CAP_NO_SW; - return mpgl_create_window(p->glctx, mpgl_caps, d_width, d_height, flags); -} - -static int config(struct vo *vo, uint32_t width, uint32_t height, - uint32_t d_width, uint32_t d_height, uint32_t flags, - uint32_t format) -{ - struct gl_priv *p = vo->priv; - - int xs, ys; - p->image_height = height; - p->image_width = width; - p->image_format = format; - p->is_yuv = mp_get_chroma_shift(p->image_format, &xs, &ys, NULL) > 0; - p->is_yuv |= (xs << 8) | (ys << 16); - glFindFormat(format, p->have_texture_rg, NULL, &p->texfmt, &p->gl_format, - &p->gl_type); - - p->vo_flipped = !!(flags & VOFLAG_FLIPPING); - - if (vo->config_count) - uninitGl(vo); - - if (!create_window(vo, d_width, d_height, flags)) - return -1; - - initGl(vo, vo->dwidth, vo->dheight); - - return 0; -} - -static void check_events(struct vo *vo) -{ - struct gl_priv *p = vo->priv; - - int e = p->glctx->check_events(vo); - if (e & VO_EVENT_REINIT) { - uninitGl(vo); - initGl(vo, vo->dwidth, vo->dheight); - } - if (e & VO_EVENT_RESIZE) - resize(vo, vo->dwidth, vo->dheight); - if (e & VO_EVENT_EXPOSE) - vo->want_redraw = true; -} - -static void do_render(struct vo *vo) -{ - struct gl_priv *p = vo->priv; - GL *gl = p->gl; - -// Enable(GL_TEXTURE_2D); -// BindTexture(GL_TEXTURE_2D, texture_id); - - gl->Color4f(1, 1, 1, 1); - if (p->is_yuv || p->custom_prog) - glEnableYUVConversion(gl, p->target, p->yuvconvtype); - if (p->stereo_mode) { - glEnable3DLeft(gl, p->stereo_mode); - glDrawTex(gl, 0, 0, p->image_width, p->image_height, - 0, 0, p->image_width >> 1, p->image_height, - p->texture_width, p->texture_height, - p->use_rectangle == 1, p->is_yuv, - p->mpi_flipped ^ p->vo_flipped); - glEnable3DRight(gl, p->stereo_mode); - glDrawTex(gl, 0, 0, p->image_width, p->image_height, - p->image_width >> 1, 0, p->image_width >> 1, - p->image_height, p->texture_width, p->texture_height, - p->use_rectangle == 1, p->is_yuv, - p->mpi_flipped ^ p->vo_flipped); - glDisable3D(gl, p->stereo_mode); - } else { - glDrawTex(gl, 0, 0, p->image_width, p->image_height, - 0, 0, p->image_width, p->image_height, - p->texture_width, p->texture_height, - p->use_rectangle == 1, p->is_yuv, - p->mpi_flipped ^ p->vo_flipped); - } - if (p->is_yuv || p->custom_prog) - glDisableYUVConversion(gl, p->target, p->yuvconvtype); -} - -static void flip_page(struct vo *vo) -{ - struct gl_priv *p = vo->priv; - GL *gl = p->gl; - - if (p->use_glFinish) - gl->Finish(); - p->glctx->swapGlBuffers(p->glctx); - if (aspect_scaling()) - gl->Clear(GL_COLOR_BUFFER_BIT); -} - -static int draw_slice(struct vo *vo, uint8_t *src[], int stride[], int w, int h, - int x, int y) -{ - struct gl_priv *p = vo->priv; - GL *gl = p->gl; - - p->mpi_flipped = stride[0] < 0; - glUploadTex(gl, p->target, p->gl_format, p->gl_type, src[0], stride[0], - x, y, w, h, p->slice_height); - if (p->is_yuv) { - int xs, ys; - mp_get_chroma_shift(p->image_format, &xs, &ys, NULL); - gl->ActiveTexture(GL_TEXTURE1); - glUploadTex(gl, p->target, p->gl_format, p->gl_type, src[1], stride[1], - x >> xs, y >> ys, w >> xs, h >> ys, p->slice_height); - gl->ActiveTexture(GL_TEXTURE2); - glUploadTex(gl, p->target, p->gl_format, p->gl_type, src[2], stride[2], - x >> xs, y >> ys, w >> xs, h >> ys, p->slice_height); - gl->ActiveTexture(GL_TEXTURE0); - } - return 0; -} - -static uint32_t get_image(struct vo *vo, mp_image_t *mpi) -{ - struct gl_priv *p = vo->priv; - GL *gl = p->gl; - - int needed_size; - if (!gl->GenBuffers || !gl->BindBuffer || !gl->BufferData || !gl->MapBuffer) { - if (!p->err_shown) - mp_msg(MSGT_VO, MSGL_ERR, "[gl] extensions missing for dr\n" - "Expect a _major_ speed penalty\n"); - p->err_shown = 1; - return VO_FALSE; - } - if (mpi->flags & MP_IMGFLAG_READABLE) - return VO_FALSE; - if (mpi->type != MP_IMGTYPE_STATIC && mpi->type != MP_IMGTYPE_TEMP && - (mpi->type != MP_IMGTYPE_NUMBERED || mpi->number)) - return VO_FALSE; - if (p->ati_hack) { - mpi->width = p->texture_width; - mpi->height = p->texture_height; - } - mpi->stride[0] = mpi->width * mpi->bpp / 8; - needed_size = mpi->stride[0] * mpi->height; - if (!p->buffer) - gl->GenBuffers(1, &p->buffer); - gl->BindBuffer(GL_PIXEL_UNPACK_BUFFER, p->buffer); - if (needed_size > p->buffersize) { - p->buffersize = needed_size; - gl->BufferData(GL_PIXEL_UNPACK_BUFFER, p->buffersize, - NULL, GL_DYNAMIC_DRAW); - } - if (!p->bufferptr) - p->bufferptr = gl->MapBuffer(GL_PIXEL_UNPACK_BUFFER, GL_WRITE_ONLY); - mpi->planes[0] = p->bufferptr; - gl->BindBuffer(GL_PIXEL_UNPACK_BUFFER, 0); - if (!mpi->planes[0]) { - if (!p->err_shown) - mp_msg(MSGT_VO, MSGL_ERR, "[gl] could not acquire buffer for dr\n" - "Expect a _major_ speed penalty\n"); - p->err_shown = 1; - return VO_FALSE; - } - if (p->is_yuv) { - // planar YUV - int xs, ys, component_bits; - mp_get_chroma_shift(p->image_format, &xs, &ys, &component_bits); - int bp = (component_bits + 7) / 8; - mpi->flags |= MP_IMGFLAG_COMMON_STRIDE | MP_IMGFLAG_COMMON_PLANE; - mpi->stride[0] = mpi->width * bp; - mpi->planes[1] = mpi->planes[0] + mpi->stride[0] * mpi->height; - mpi->stride[1] = (mpi->width >> xs) * bp; - mpi->planes[2] = mpi->planes[1] + mpi->stride[1] * (mpi->height >> ys); - mpi->stride[2] = (mpi->width >> xs) * bp; - if (p->ati_hack) { - mpi->flags &= ~MP_IMGFLAG_COMMON_PLANE; - if (!p->buffer_uv[0]) - gl->GenBuffers(2, p->buffer_uv); - int buffer_size = mpi->stride[1] * mpi->height; - if (buffer_size > p->buffersize_uv) { - gl->BindBuffer(GL_PIXEL_UNPACK_BUFFER, p->buffer_uv[0]); - gl->BufferData(GL_PIXEL_UNPACK_BUFFER, buffer_size, NULL, - GL_DYNAMIC_DRAW); - gl->BindBuffer(GL_PIXEL_UNPACK_BUFFER, p->buffer_uv[1]); - gl->BufferData(GL_PIXEL_UNPACK_BUFFER, buffer_size, NULL, - GL_DYNAMIC_DRAW); - p->buffersize_uv = buffer_size; - } - if (!p->bufferptr_uv[0]) { - gl->BindBuffer(GL_PIXEL_UNPACK_BUFFER, p->buffer_uv[0]); - p->bufferptr_uv[0] = gl->MapBuffer(GL_PIXEL_UNPACK_BUFFER, - GL_WRITE_ONLY); - gl->BindBuffer(GL_PIXEL_UNPACK_BUFFER, p->buffer_uv[1]); - p->bufferptr_uv[1] = gl->MapBuffer(GL_PIXEL_UNPACK_BUFFER, - GL_WRITE_ONLY); - } - mpi->planes[1] = p->bufferptr_uv[0]; - mpi->planes[2] = p->bufferptr_uv[1]; - } - } - mpi->flags |= MP_IMGFLAG_DIRECT; - return VO_TRUE; -} - -static void clear_border(struct vo *vo, uint8_t *dst, int start, int stride, - int height, int full_height, int value) -{ - int right_border = stride - start; - int bottom_border = full_height - height; - while (height > 0) { - if (right_border > 0) - memset(dst + start, value, right_border); - dst += stride; - height--; - } - if (bottom_border > 0) - memset(dst, value, stride * bottom_border); -} - -static uint32_t draw_image(struct vo *vo, mp_image_t *mpi) -{ - struct gl_priv *p = vo->priv; - GL *gl = p->gl; - - int slice = p->slice_height; - int stride[3]; - unsigned char *planes[3]; - mp_image_t mpi2 = *mpi; - int w = mpi->w, h = mpi->h; - if (mpi->flags & MP_IMGFLAG_DRAW_CALLBACK) - goto skip_upload; - mpi2.flags = 0; - mpi2.type = MP_IMGTYPE_TEMP; - mpi2.width = mpi2.w; - mpi2.height = mpi2.h; - if (p->force_pbo && !(mpi->flags & MP_IMGFLAG_DIRECT) && !p->bufferptr - && get_image(vo, &mpi2) == VO_TRUE) - { - int bp = mpi->bpp / 8; - int xs, ys, component_bits; - mp_get_chroma_shift(p->image_format, &xs, &ys, &component_bits); - if (p->is_yuv) - bp = (component_bits + 7) / 8; - memcpy_pic(mpi2.planes[0], mpi->planes[0], mpi->w * bp, mpi->h, - mpi2.stride[0], mpi->stride[0]); - int uv_bytes = (mpi->w >> xs) * bp; - if (p->is_yuv) { - memcpy_pic(mpi2.planes[1], mpi->planes[1], uv_bytes, mpi->h >> ys, - mpi2.stride[1], mpi->stride[1]); - memcpy_pic(mpi2.planes[2], mpi->planes[2], uv_bytes, mpi->h >> ys, - mpi2.stride[2], mpi->stride[2]); - } - if (p->ati_hack) { - // since we have to do a full upload we need to clear the borders - clear_border(vo, mpi2.planes[0], mpi->w * bp, mpi2.stride[0], - mpi->h, mpi2.height, 0); - if (p->is_yuv) { - int clear = get_chroma_clear_val(component_bits); - clear_border(vo, mpi2.planes[1], uv_bytes, mpi2.stride[1], - mpi->h >> ys, mpi2.height >> ys, clear); - clear_border(vo, mpi2.planes[2], uv_bytes, mpi2.stride[2], - mpi->h >> ys, mpi2.height >> ys, clear); - } - } - mpi = &mpi2; - } - stride[0] = mpi->stride[0]; - stride[1] = mpi->stride[1]; - stride[2] = mpi->stride[2]; - planes[0] = mpi->planes[0]; - planes[1] = mpi->planes[1]; - planes[2] = mpi->planes[2]; - p->mpi_flipped = stride[0] < 0; - if (mpi->flags & MP_IMGFLAG_DIRECT) { - intptr_t base = (intptr_t)planes[0]; - if (p->ati_hack) { - w = p->texture_width; - h = p->texture_height; - } - if (p->mpi_flipped) - base += (mpi->h - 1) * stride[0]; - planes[0] -= base; - planes[1] -= base; - planes[2] -= base; - gl->BindBuffer(GL_PIXEL_UNPACK_BUFFER, p->buffer); - gl->UnmapBuffer(GL_PIXEL_UNPACK_BUFFER); - p->bufferptr = NULL; - if (!(mpi->flags & MP_IMGFLAG_COMMON_PLANE)) - planes[0] = planes[1] = planes[2] = NULL; - slice = 0; // always "upload" full texture - } - glUploadTex(gl, p->target, p->gl_format, p->gl_type, planes[0], - stride[0], 0, 0, w, h, slice); - if (p->is_yuv) { - int xs, ys; - mp_get_chroma_shift(p->image_format, &xs, &ys, NULL); - if ((mpi->flags & MP_IMGFLAG_DIRECT) && !(mpi->flags & MP_IMGFLAG_COMMON_PLANE)) { - gl->BindBuffer(GL_PIXEL_UNPACK_BUFFER, p->buffer_uv[0]); - gl->UnmapBuffer(GL_PIXEL_UNPACK_BUFFER); - p->bufferptr_uv[0] = NULL; - } - gl->ActiveTexture(GL_TEXTURE1); - glUploadTex(gl, p->target, p->gl_format, p->gl_type, planes[1], - stride[1], 0, 0, w >> xs, h >> ys, slice); - if ((mpi->flags & MP_IMGFLAG_DIRECT) && !(mpi->flags & MP_IMGFLAG_COMMON_PLANE)) { - gl->BindBuffer(GL_PIXEL_UNPACK_BUFFER, p->buffer_uv[1]); - gl->UnmapBuffer(GL_PIXEL_UNPACK_BUFFER); - p->bufferptr_uv[1] = NULL; - } - gl->ActiveTexture(GL_TEXTURE2); - glUploadTex(gl, p->target, p->gl_format, p->gl_type, planes[2], - stride[2], 0, 0, w >> xs, h >> ys, slice); - gl->ActiveTexture(GL_TEXTURE0); - } - if (mpi->flags & MP_IMGFLAG_DIRECT) { - gl->BindBuffer(GL_PIXEL_UNPACK_BUFFER, 0); - } -skip_upload: - do_render(vo); - return VO_TRUE; -} - -static mp_image_t *get_screenshot(struct vo *vo) -{ - struct gl_priv *p = vo->priv; - GL *gl = p->gl; - - mp_image_t *image = alloc_mpi(p->texture_width, p->texture_height, - p->image_format); - - glDownloadTex(gl, p->target, p->gl_format, p->gl_type, image->planes[0], - image->stride[0]); - - if (p->is_yuv) { - gl->ActiveTexture(GL_TEXTURE1); - glDownloadTex(gl, p->target, p->gl_format, p->gl_type, image->planes[1], - image->stride[1]); - gl->ActiveTexture(GL_TEXTURE2); - glDownloadTex(gl, p->target, p->gl_format, p->gl_type, image->planes[2], - image->stride[2]); - gl->ActiveTexture(GL_TEXTURE0); - } - - image->w = p->image_width; - image->h = p->image_height; - image->display_w = vo->aspdat.prew; - image->display_h = vo->aspdat.preh; - - mp_image_set_colorspace_details(image, &p->colorspace); - - return image; -} - -static int query_format(struct vo *vo, uint32_t format) -{ - struct gl_priv *p = vo->priv; - - int depth; - int caps = VFCAP_CSP_SUPPORTED | VFCAP_CSP_SUPPORTED_BY_HW | VFCAP_FLIP | - VFCAP_HWSCALE_UP | VFCAP_HWSCALE_DOWN | VFCAP_ACCEPT_STRIDE; - if (p->use_osd) - caps |= VFCAP_OSD; - if (format == IMGFMT_RGB24 || format == IMGFMT_RGBA) - return caps; - if (p->use_yuv && mp_get_chroma_shift(format, NULL, NULL, &depth) && - (depth == 8 || depth == 16 || glYUVLargeRange(p->use_yuv)) && - (IMGFMT_IS_YUVP16_NE(format) || !IMGFMT_IS_YUVP16(format))) - return caps; - // HACK, otherwise we get only b&w with some filters (e.g. -vf eq) - // ideally MPlayer should be fixed instead not to use Y800 when it has the choice - if (!p->use_yuv && (format == IMGFMT_Y8 || format == IMGFMT_Y800)) - return 0; - if (!p->use_ycbcr && (format == IMGFMT_UYVY || format == IMGFMT_YVYU)) - return 0; - if (p->many_fmts && - glFindFormat(format, p->have_texture_rg, NULL, NULL, NULL, NULL)) - return caps; - return 0; -} - -static void uninit(struct vo *vo) -{ - struct gl_priv *p = vo->priv; - - uninitGl(vo); - free(p->custom_prog); - p->custom_prog = NULL; - free(p->custom_tex); - p->custom_tex = NULL; - mpgl_uninit(p->glctx); - p->glctx = NULL; - p->gl = NULL; -} - -static int backend_valid(void *arg) -{ - return mpgl_find_backend(*(const char **)arg) >= 0; -} - -static int preinit(struct vo *vo, const char *arg) -{ - struct gl_priv *p = talloc_zero(vo, struct gl_priv); - vo->priv = p; - - *p = (struct gl_priv) { - .many_fmts = 1, - .use_osd = -1, - .use_yuv = -1, - .colorspace = MP_CSP_DETAILS_DEFAULTS, - .filter_strength = 0.5, - .use_rectangle = -1, - .ati_hack = -1, - .force_pbo = -1, - .swap_interval = vo_vsync, - .custom_prog = NULL, - .custom_tex = NULL, - .custom_tlin = 1, - .osd_color = 0xffffff, - }; - - char *backend_arg = NULL; - - //essentially unused; for legacy warnings only - int user_colorspace = 0; - int levelconv = -1; - int aspect = -1; - - const opt_t subopts[] = { - {"manyfmts", OPT_ARG_BOOL, &p->many_fmts, NULL}, - {"osd", OPT_ARG_BOOL, &p->use_osd, NULL}, - {"scaled-osd", OPT_ARG_BOOL, &p->scaled_osd, NULL}, - {"ycbcr", OPT_ARG_BOOL, &p->use_ycbcr, NULL}, - {"slice-height", OPT_ARG_INT, &p->slice_height, int_non_neg}, - {"rectangle", OPT_ARG_INT, &p->use_rectangle,int_non_neg}, - {"yuv", OPT_ARG_INT, &p->use_yuv, int_non_neg}, - {"lscale", OPT_ARG_INT, &p->lscale, int_non_neg}, - {"cscale", OPT_ARG_INT, &p->cscale, int_non_neg}, - {"filter-strength", OPT_ARG_FLOAT, &p->filter_strength, NULL}, - {"noise-strength", OPT_ARG_FLOAT, &p->noise_strength, NULL}, - {"ati-hack", OPT_ARG_BOOL, &p->ati_hack, NULL}, - {"force-pbo", OPT_ARG_BOOL, &p->force_pbo, NULL}, - {"glfinish", OPT_ARG_BOOL, &p->use_glFinish, NULL}, - {"swapinterval", OPT_ARG_INT, &p->swap_interval,NULL}, - {"customprog", OPT_ARG_MSTRZ,&p->custom_prog, NULL}, - {"customtex", OPT_ARG_MSTRZ,&p->custom_tex, NULL}, - {"customtlin", OPT_ARG_BOOL, &p->custom_tlin, NULL}, - {"customtrect", OPT_ARG_BOOL, &p->custom_trect, NULL}, - {"mipmapgen", OPT_ARG_BOOL, &p->mipmap_gen, NULL}, - {"osdcolor", OPT_ARG_INT, &p->osd_color, NULL}, - {"stereo", OPT_ARG_INT, &p->stereo_mode, NULL}, - {"sw", OPT_ARG_BOOL, &p->allow_sw, NULL}, - {"backend", OPT_ARG_MSTRZ,&backend_arg, backend_valid}, - // Removed options. - // They are only parsed to notify the user about the replacements. - {"aspect", OPT_ARG_BOOL, &aspect, NULL}, - {"colorspace", OPT_ARG_INT, &user_colorspace, NULL}, - {"levelconv", OPT_ARG_INT, &levelconv, NULL}, - {NULL} - }; - - if (subopt_parse(arg, subopts) != 0) { - mp_msg(MSGT_VO, MSGL_FATAL, - "\n-vo opengl_old command line help:\n" - "Example: mpv -vo opengl_old:slice-height=4\n" - "\nOptions:\n" - " nomanyfmts\n" - " Disable extended color formats for OpenGL 1.2 and later\n" - " slice-height=<0-...>\n" - " Slice size for texture transfer, 0 for whole image\n" - " noosd\n" - " Do not use OpenGL OSD code\n" - " scaled-osd\n" - " Render OSD at movie resolution and scale it\n" - " rectangle=<0,1,2>\n" - " 0: use power-of-two textures\n" - " 1: use texture_rectangle\n" - " 2: use texture_non_power_of_two\n" - " ati-hack\n" - " Workaround ATI bug with PBOs\n" - " force-pbo\n" - " Force use of PBO even if this involves an extra memcpy\n" - " glfinish\n" - " Call glFinish() before swapping buffers\n" - " swapinterval=<n>\n" - " Interval in displayed frames between to buffer swaps.\n" - " 1 is equivalent to enable VSYNC, 0 to disable VSYNC.\n" - " Requires GLX_SGI_swap_control support to work.\n" - " ycbcr\n" - " also try to use the GL_MESA_ycbcr_texture extension\n" - " yuv=<n>\n" - " 0: use software YUV to RGB conversion.\n" - " 1: deprecated, will use yuv=2 (used to be nVidia register combiners).\n" - " 2: use fragment program.\n" - " 3: use fragment program with gamma correction.\n" - " 4: use fragment program with gamma correction via lookup.\n" - " 5: use ATI-specific method (for older cards).\n" - " 6: use lookup via 3D texture.\n" - " lscale=<n>\n" - " 0: use standard bilinear scaling for luma.\n" - " 1: use improved bicubic scaling for luma.\n" - " 2: use cubic in X, linear in Y direction scaling for luma.\n" - " 3: as 1 but without using a lookup texture.\n" - " 4: experimental unsharp masking (sharpening).\n" - " 5: experimental unsharp masking (sharpening) with larger radius.\n" - " cscale=<n>\n" - " as lscale but for chroma (2x slower with little visible effect).\n" - " filter-strength=<value>\n" - " set the effect strength for some lscale/cscale filters\n" - " noise-strength=<value>\n" - " set how much noise to add. 1.0 is suitable for dithering to 6 bit.\n" - " customprog=<filename>\n" - " use a custom YUV conversion program\n" - " customtex=<filename>\n" - " use a custom YUV conversion lookup texture\n" - " nocustomtlin\n" - " use GL_NEAREST scaling for customtex texture\n" - " customtrect\n" - " use texture_rectangle for customtex texture\n" - " mipmapgen\n" - " generate mipmaps for the video image (use with TXB in customprog)\n" - " osdcolor=<0xAARRGGBB>\n" - " use the given color for the OSD\n" - " stereo=<n>\n" - " 0: normal display\n" - " 1: side-by-side to red-cyan stereo\n" - " 2: side-by-side to green-magenta stereo\n" - " 3: side-by-side to quadbuffer stereo\n" - " sw\n" - " allow using a software renderer, if such is detected\n" - " backend=<sys>\n" - " auto: auto-select (default)\n" - " cocoa: Cocoa/OSX\n" - " win: Win32/WGL\n" - " x11: X11/GLX\n" - "\n"); - return -1; - } - if (user_colorspace != 0 || levelconv != -1) { - mp_msg(MSGT_VO, MSGL_ERR, "[gl] \"colorspace\" and \"levelconv\" " - "suboptions have been removed. Use options --colormatrix and" - " --colormatrix-input-range/--colormatrix-output-range instead.\n"); - return -1; - } - if (aspect != -1) { - mp_msg(MSGT_VO, MSGL_ERR, "[gl] \"noaspect\" suboption has been " - "removed. Use --noaspect instead.\n"); - return -1; - } - if (p->use_yuv == 1) { - mp_msg(MSGT_VO, MSGL_WARN, "[gl] yuv=1 (nVidia register combiners) have" - " been removed, using yuv=2 instead.\n"); - p->use_yuv = 2; - } - - int backend = backend_arg ? mpgl_find_backend(backend_arg) : GLTYPE_AUTO; - free(backend_arg); - - p->glctx = mpgl_init(backend, vo); - if (!p->glctx) - goto err_out; - p->gl = p->glctx->gl; - - if (p->use_yuv == -1) { - if (!create_window(vo, 320, 200, VOFLAG_HIDDEN)) - goto err_out; - autodetectGlExtensions(vo); - // We created a window to test whether the GL context supports hardware - // acceleration and so on. Destroy that window to make sure all state - // associated with it is lost. - uninitGl(vo); - if (!mpgl_destroy_window(p->glctx)) - goto err_out; - } - if (p->many_fmts) - mp_msg(MSGT_VO, MSGL_INFO, "[gl] using extended formats. " - "Use -vo gl:nomanyfmts if playback fails.\n"); - mp_msg(MSGT_VO, MSGL_V, "[gl] Using %d as slice height " - "(0 means image height).\n", p->slice_height); - - return 0; - -err_out: - uninit(vo); - return -1; -} - -static int control(struct vo *vo, uint32_t request, void *data) -{ - struct gl_priv *p = vo->priv; - - switch (request) { - case VOCTRL_QUERY_FORMAT: - return query_format(vo, *(uint32_t *)data); - case VOCTRL_DRAW_IMAGE: - return draw_image(vo, data); - case VOCTRL_ONTOP: - if (!p->glctx->ontop) - break; - p->glctx->ontop(vo); - return VO_TRUE; - case VOCTRL_FULLSCREEN: - p->glctx->fullscreen(vo); - resize(vo, vo->dwidth, vo->dheight); - return VO_TRUE; - case VOCTRL_BORDER: - if (!p->glctx->border) - break; - p->glctx->border(vo); - resize(vo, vo->dwidth, vo->dheight); - return VO_TRUE; - case VOCTRL_GET_PANSCAN: - return VO_TRUE; - case VOCTRL_SET_PANSCAN: - resize(vo, vo->dwidth, vo->dheight); - return VO_TRUE; - case VOCTRL_GET_EQUALIZER: - if (p->is_yuv) { - struct voctrl_get_equalizer_args *args = data; - return mp_csp_equalizer_get(&p->video_eq, args->name, args->valueptr) - >= 0 ? VO_TRUE : VO_NOTIMPL; - } - break; - case VOCTRL_SET_EQUALIZER: - if (p->is_yuv) { - struct voctrl_set_equalizer_args *args = data; - if (mp_csp_equalizer_set(&p->video_eq, args->name, args->value) < 0) - return VO_NOTIMPL; - update_yuvconv(vo); - vo->want_redraw = true; - return VO_TRUE; - } - break; - case VOCTRL_SET_YUV_COLORSPACE: { - bool supports_csp = (1 << p->use_yuv) & MASK_NOT_COMBINERS; - if (vo->config_count && supports_csp) { - p->colorspace = *(struct mp_csp_details *)data; - update_yuvconv(vo); - vo->want_redraw = true; - } - return VO_TRUE; - } - case VOCTRL_GET_YUV_COLORSPACE: - *(struct mp_csp_details *)data = p->colorspace; - return VO_TRUE; - case VOCTRL_UPDATE_SCREENINFO: - if (!p->glctx->update_xinerama_info) - break; - p->glctx->update_xinerama_info(vo); - return VO_TRUE; - case VOCTRL_REDRAW_FRAME: - do_render(vo); - return true; - case VOCTRL_PAUSE: - if (!p->glctx->pause) - break; - p->glctx->pause(vo); - return VO_TRUE; - case VOCTRL_RESUME: - if (!p->glctx->resume) - break; - p->glctx->resume(vo); - return VO_TRUE; - case VOCTRL_SCREENSHOT: { - struct voctrl_screenshot_args *args = data; - if (args->full_window) - args->out_image = glGetWindowScreenshot(p->gl); - else - args->out_image = get_screenshot(vo); - return true; - } - } - return VO_NOTIMPL; -} - -const struct vo_driver video_out_opengl_old = { - .is_new = true, - .info = &(const vo_info_t) { - "OpenGL", - "opengl-old", - "Reimar Doeffinger <Reimar.Doeffinger@gmx.de>", - "" - }, - .preinit = preinit, - .config = config, - .control = control, - .draw_slice = draw_slice, - .draw_osd = draw_osd, - .flip_page = flip_page, - .check_events = check_events, - .uninit = uninit, -}; diff --git a/libvo/vo_opengl_shaders.glsl b/libvo/vo_opengl_shaders.glsl deleted file mode 100644 index 1f302889e4..0000000000 --- a/libvo/vo_opengl_shaders.glsl +++ /dev/null @@ -1,355 +0,0 @@ -/* - * This file is part of mplayer2. - * - * mplayer2 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. - * - * mplayer2 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 mplayer2; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -// Note that this file is not directly passed as shader, but run through some -// text processing functions, and in fact contains multiple vertex and fragment -// shaders. - -// inserted at the beginning of all shaders -#!section prelude - -// GLSL 1.20 compatibility layer -// texture() should be assumed to always map to texture2D() -#if __VERSION__ >= 130 -# define texture1D texture -# define texture3D texture -# define DECLARE_FRAGPARMS \ - out vec4 out_color; -#else -# define texture texture2D -# define DECLARE_FRAGPARMS -# define out_color gl_FragColor -# define in varying -#endif - -// Earlier GLSL doesn't support mix() with bvec -#if __VERSION__ >= 130 -vec3 srgb_compand(vec3 v) -{ - return mix(1.055 * pow(v, vec3(1.0/2.4)) - vec3(0.055), v * 12.92, - lessThanEqual(v, vec3(0.0031308))); -} -#endif - -#!section vertex_all - -#if __VERSION__ < 130 -# undef in -# define in attribute -# define out varying -#endif - -uniform mat3 transform; -uniform sampler3D lut_3d; - -in vec2 vertex_position; -in vec4 vertex_color; -out vec4 color; -in vec2 vertex_texcoord; -out vec2 texcoord; - -void main() { - vec3 position = vec3(vertex_position, 1); -#ifndef FIXED_SCALE - position = transform * position; -#endif - gl_Position = vec4(position, 1); - color = vertex_color; - -#ifdef USE_OSD_LINEAR_CONV - // If no 3dlut is being used, we need to pull up to linear light for - // the sRGB function. *IF* 3dlut is used, we do not. - color.rgb = pow(color.rgb, vec3(2.2)); -#endif -#ifdef USE_OSD_3DLUT - color = vec4(texture3D(lut_3d, color.rgb).rgb, color.a); -#endif -#ifdef USE_OSD_SRGB - color.rgb = srgb_compand(color.rgb); -#endif - - texcoord = vertex_texcoord; -} - -#!section frag_osd_libass -uniform sampler2D textures[3]; - -in vec2 texcoord; -in vec4 color; -DECLARE_FRAGPARMS - -void main() { - out_color = vec4(color.rgb, color.a * texture(textures[0], texcoord).r); -} - -#!section frag_osd_rgba -uniform sampler2D textures[3]; - -in vec2 texcoord; -DECLARE_FRAGPARMS - -void main() { - out_color = texture(textures[0], texcoord); -} - -#!section frag_video -uniform sampler2D textures[3]; -uniform vec2 textures_size[3]; -uniform sampler1D lut_c_1d; -uniform sampler1D lut_l_1d; -uniform sampler2D lut_c_2d; -uniform sampler2D lut_l_2d; -uniform sampler3D lut_3d; -uniform sampler2D dither; -uniform mat4x3 colormatrix; -uniform vec3 inv_gamma; -uniform float conv_gamma; -uniform float dither_quantization; -uniform float dither_multiply; -uniform float filter_param1; -uniform vec2 dither_size; - -in vec2 texcoord; -DECLARE_FRAGPARMS - -vec4 sample_bilinear(sampler2D tex, vec2 texsize, vec2 texcoord) { - return texture(tex, texcoord); -} - -// Explanation how bicubic scaling with only 4 texel fetches is done: -// http://www.mate.tue.nl/mate/pdfs/10318.pdf -// 'Efficient GPU-Based Texture Interpolation using Uniform B-Splines' -// Explanation why this algorithm normally always blurs, even with unit scaling: -// http://bigwww.epfl.ch/preprints/ruijters1001p.pdf -// 'GPU Prefilter for Accurate Cubic B-spline Interpolation' -vec4 calcweights(float s) { - vec4 t = vec4(-0.5, 0.1666, 0.3333, -0.3333) * s + vec4(1, 0, -0.5, 0.5); - t = t * s + vec4(0, 0, -0.5, 0.5); - t = t * s + vec4(-0.6666, 0, 0.8333, 0.1666); - vec2 a = vec2(1 / t.z, 1 / t.w); - t.xy = t.xy * a + vec2(1, 1); - t.x = t.x + s; - t.y = t.y - s; - return t; -} - -vec4 sample_bicubic_fast(sampler2D tex, vec2 texsize, vec2 texcoord) { - vec2 pt = 1 / texsize; - vec2 fcoord = fract(texcoord * texsize + vec2(0.5, 0.5)); - vec4 parmx = calcweights(fcoord.x); - vec4 parmy = calcweights(fcoord.y); - vec4 cdelta; - cdelta.xz = parmx.rg * vec2(-pt.x, pt.x); - cdelta.yw = parmy.rg * vec2(-pt.y, pt.y); - // first y-interpolation - vec4 ar = texture(tex, texcoord + cdelta.xy); - vec4 ag = texture(tex, texcoord + cdelta.xw); - vec4 ab = mix(ag, ar, parmy.b); - // second y-interpolation - vec4 br = texture(tex, texcoord + cdelta.zy); - vec4 bg = texture(tex, texcoord + cdelta.zw); - vec4 aa = mix(bg, br, parmy.b); - // x-interpolation - return mix(aa, ab, parmx.b); -} - -float[2] weights2(sampler1D lookup, float f) { - vec4 c = texture1D(lookup, f); - return float[2](c.r, c.g); -} - -float[4] weights4(sampler1D lookup, float f) { - vec4 c = texture1D(lookup, f); - return float[4](c.r, c.g, c.b, c.a); -} - -float[6] weights6(sampler2D lookup, float f) { - vec4 c1 = texture(lookup, vec2(0.25, f)); - vec4 c2 = texture(lookup, vec2(0.75, f)); - return float[6](c1.r, c1.g, c1.b, c2.r, c2.g, c2.b); -} - -float[8] weights8(sampler2D lookup, float f) { - vec4 c1 = texture(lookup, vec2(0.25, f)); - vec4 c2 = texture(lookup, vec2(0.75, f)); - return float[8](c1.r, c1.g, c1.b, c1.a, c2.r, c2.g, c2.b, c2.a); -} - -float[12] weights12(sampler2D lookup, float f) { - vec4 c1 = texture(lookup, vec2(1.0/6.0, f)); - vec4 c2 = texture(lookup, vec2(0.5, f)); - vec4 c3 = texture(lookup, vec2(5.0/6.0, f)); - return float[12](c1.r, c1.g, c1.b, c1.a, - c2.r, c2.g, c2.b, c2.a, - c3.r, c3.g, c3.b, c3.a); -} - -float[16] weights16(sampler2D lookup, float f) { - vec4 c1 = texture(lookup, vec2(0.125, f)); - vec4 c2 = texture(lookup, vec2(0.375, f)); - vec4 c3 = texture(lookup, vec2(0.625, f)); - vec4 c4 = texture(lookup, vec2(0.875, f)); - return float[16](c1.r, c1.g, c1.b, c1.a, c2.r, c2.g, c2.b, c2.a, - c3.r, c3.g, c3.b, c3.a, c4.r, c4.g, c4.b, c4.a); -} - -#define CONVOLUTION_SEP_N(NAME, N) \ - vec4 NAME(sampler2D tex, vec2 texcoord, vec2 pt, float weights[N]) { \ - vec4 res = vec4(0); \ - for (int n = 0; n < N; n++) { \ - res += weights[n] * texture(tex, texcoord + pt * n); \ - } \ - return res; \ - } - -CONVOLUTION_SEP_N(convolution_sep2, 2) -CONVOLUTION_SEP_N(convolution_sep4, 4) -CONVOLUTION_SEP_N(convolution_sep6, 6) -CONVOLUTION_SEP_N(convolution_sep8, 8) -CONVOLUTION_SEP_N(convolution_sep12, 12) -CONVOLUTION_SEP_N(convolution_sep16, 16) - -// The dir parameter is (0, 1) or (1, 0), and we expect the shader compiler to -// remove all the redundant multiplications and additions. -#define SAMPLE_CONVOLUTION_SEP_N(NAME, N, SAMPLERT, CONV_FUNC, WEIGHTS_FUNC)\ - vec4 NAME(vec2 dir, SAMPLERT lookup, sampler2D tex, vec2 texsize, \ - vec2 texcoord) { \ - vec2 pt = (1 / texsize) * dir; \ - float fcoord = dot(fract(texcoord * texsize - 0.5), dir); \ - vec2 base = texcoord - fcoord * pt; \ - return CONV_FUNC(tex, base - pt * (N / 2 - 1), pt, \ - WEIGHTS_FUNC(lookup, fcoord)); \ - } - -SAMPLE_CONVOLUTION_SEP_N(sample_convolution_sep2, 2, sampler1D, convolution_sep2, weights2) -SAMPLE_CONVOLUTION_SEP_N(sample_convolution_sep4, 4, sampler1D, convolution_sep4, weights4) -SAMPLE_CONVOLUTION_SEP_N(sample_convolution_sep6, 6, sampler2D, convolution_sep6, weights6) -SAMPLE_CONVOLUTION_SEP_N(sample_convolution_sep8, 8, sampler2D, convolution_sep8, weights8) -SAMPLE_CONVOLUTION_SEP_N(sample_convolution_sep12, 12, sampler2D, convolution_sep12, weights12) -SAMPLE_CONVOLUTION_SEP_N(sample_convolution_sep16, 16, sampler2D, convolution_sep16, weights16) - - -#define CONVOLUTION_N(NAME, N) \ - vec4 NAME(sampler2D tex, vec2 texcoord, vec2 pt, float taps_x[N], \ - float taps_y[N]) { \ - vec4 res = vec4(0); \ - for (int y = 0; y < N; y++) { \ - vec4 line = vec4(0); \ - for (int x = 0; x < N; x++) \ - line += taps_x[x] * texture(tex, texcoord + pt * vec2(x, y));\ - res += taps_y[y] * line; \ - } \ - return res; \ - } - -CONVOLUTION_N(convolution2, 2) -CONVOLUTION_N(convolution4, 4) -CONVOLUTION_N(convolution6, 6) -CONVOLUTION_N(convolution8, 8) -CONVOLUTION_N(convolution12, 12) -CONVOLUTION_N(convolution16, 16) - -#define SAMPLE_CONVOLUTION_N(NAME, N, SAMPLERT, CONV_FUNC, WEIGHTS_FUNC) \ - vec4 NAME(SAMPLERT lookup, sampler2D tex, vec2 texsize, vec2 texcoord) {\ - vec2 pt = 1 / texsize; \ - vec2 fcoord = fract(texcoord * texsize - 0.5); \ - vec2 base = texcoord - fcoord * pt; \ - return CONV_FUNC(tex, base - pt * (N / 2 - 1), pt, \ - WEIGHTS_FUNC(lookup, fcoord.x), \ - WEIGHTS_FUNC(lookup, fcoord.y)); \ - } - -SAMPLE_CONVOLUTION_N(sample_convolution2, 2, sampler1D, convolution2, weights2) -SAMPLE_CONVOLUTION_N(sample_convolution4, 4, sampler1D, convolution4, weights4) -SAMPLE_CONVOLUTION_N(sample_convolution6, 6, sampler2D, convolution6, weights6) -SAMPLE_CONVOLUTION_N(sample_convolution8, 8, sampler2D, convolution8, weights8) -SAMPLE_CONVOLUTION_N(sample_convolution12, 12, sampler2D, convolution12, weights12) -SAMPLE_CONVOLUTION_N(sample_convolution16, 16, sampler2D, convolution16, weights16) - - -// Unsharp masking -vec4 sample_sharpen3(sampler2D tex, vec2 texsize, vec2 texcoord) { - vec2 pt = 1 / texsize; - vec2 st = pt * 0.5; - vec4 p = texture(tex, texcoord); - vec4 sum = texture(tex, texcoord + st * vec2(+1, +1)) - + texture(tex, texcoord + st * vec2(+1, -1)) - + texture(tex, texcoord + st * vec2(-1, +1)) - + texture(tex, texcoord + st * vec2(-1, -1)); - return p + (p - 0.25 * sum) * filter_param1; -} - -vec4 sample_sharpen5(sampler2D tex, vec2 texsize, vec2 texcoord) { - vec2 pt = 1 / texsize; - vec2 st1 = pt * 1.2; - vec4 p = texture(tex, texcoord); - vec4 sum1 = texture(tex, texcoord + st1 * vec2(+1, +1)) - + texture(tex, texcoord + st1 * vec2(+1, -1)) - + texture(tex, texcoord + st1 * vec2(-1, +1)) - + texture(tex, texcoord + st1 * vec2(-1, -1)); - vec2 st2 = pt * 1.5; - vec4 sum2 = texture(tex, texcoord + st2 * vec2(+1, 0)) - + texture(tex, texcoord + st2 * vec2( 0, +1)) - + texture(tex, texcoord + st2 * vec2(-1, 0)) - + texture(tex, texcoord + st2 * vec2( 0, -1)); - vec4 t = p * 0.859375 + sum2 * -0.1171875 + sum1 * -0.09765625; - return p + t * filter_param1; -} - -void main() { -#ifdef USE_PLANAR - vec3 color = vec3(SAMPLE_L(textures[0], textures_size[0], texcoord).r, - SAMPLE_C(textures[1], textures_size[1], texcoord).r, - SAMPLE_C(textures[2], textures_size[2], texcoord).r); -#else - vec3 color = SAMPLE_L(textures[0], textures_size[0], texcoord).rgb; -#endif -#ifdef USE_GBRP - color.gbr = color; -#endif -#ifdef USE_YGRAY - // NOTE: actually slightly wrong for 16 bit input video, and completely - // wrong for 9/10 bit input - color.gb = vec2(128.0/255.0); -#endif -#ifdef USE_COLORMATRIX - color = mat3(colormatrix) * color + colormatrix[3]; -#endif -#ifdef USE_LINEAR_CONV - color = pow(color, vec3(2.2)); -#endif -#ifdef USE_LINEAR_CONV_INV - // Convert from linear RGB to gamma RGB before putting it through the 3D-LUT - // in the final stage. - color = pow(color, vec3(1.0/2.2)); -#endif -#ifdef USE_GAMMA_POW - color = pow(color, inv_gamma); -#endif -#ifdef USE_3DLUT - color = texture3D(lut_3d, color).rgb; -#endif -#ifdef USE_SRGB - color.rgb = srgb_compand(color.rgb); -#endif -#ifdef USE_DITHER - float dither_value = texture(dither, gl_FragCoord.xy / dither_size).r; - color = floor(color * dither_multiply + dither_value ) / dither_quantization; -#endif - out_color = vec4(color, 1); -} diff --git a/libvo/vo_vdpau.c b/libvo/vo_vdpau.c deleted file mode 100644 index a523ea5815..0000000000 --- a/libvo/vo_vdpau.c +++ /dev/null @@ -1,1718 +0,0 @@ -/* - * VDPAU video output driver - * - * Copyright (C) 2008 NVIDIA - * Copyright (C) 2009 Uoti Urpala - * - * 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. - */ - -/* - * Actual decoding and presentation are implemented here. - * All necessary frame information is collected through - * the "vdpau_render_state" structure after parsing all headers - * etc. in libavcodec for different codecs. - */ - -#include <stdio.h> -#include <stdlib.h> -#include <stdint.h> -#include <stdbool.h> -#include <limits.h> -#include <assert.h> - -#include <libavutil/common.h> -#include <libavcodec/vdpau.h> - -#include "config.h" -#include "mp_msg.h" -#include "options.h" -#include "talloc.h" -#include "video_out.h" -#include "x11_common.h" -#include "aspect.h" -#include "csputils.h" -#include "sub/sub.h" -#include "m_option.h" -#include "libmpcodecs/vfcap.h" -#include "libmpcodecs/mp_image.h" -#include "osdep/timer.h" -#include "bitmap_packer.h" - -#define WRAP_ADD(x, a, m) ((a) < 0 \ - ? ((x)+(a)+(m) < (m) ? (x)+(a)+(m) : (x)+(a)) \ - : ((x)+(a) < (m) ? (x)+(a) : (x)+(a)-(m))) - -#define CHECK_ST_ERROR(message) \ - do { \ - if (vdp_st != VDP_STATUS_OK) { \ - mp_msg(MSGT_VO, MSGL_ERR, "[vdpau] %s: %s\n", \ - message, vdp->get_error_string(vdp_st)); \ - return -1; \ - } \ - } while (0) - -#define CHECK_ST_WARNING(message) \ - do { \ - if (vdp_st != VDP_STATUS_OK) \ - mp_msg(MSGT_VO, MSGL_WARN, "[ vdpau] %s: %s\n", \ - message, vdp->get_error_string(vdp_st)); \ - } while (0) - -/* number of video and output surfaces */ -#define MAX_OUTPUT_SURFACES 15 -#define MAX_VIDEO_SURFACES 50 -#define NUM_BUFFERED_VIDEO 5 - -/* Pixelformat used for output surfaces */ -#define OUTPUT_RGBA_FORMAT VDP_RGBA_FORMAT_B8G8R8A8 - -/* - * Global variable declaration - VDPAU specific - */ - -struct vdp_functions { -#define VDP_FUNCTION(vdp_type, _, mp_name) vdp_type *mp_name; -#include "vdpau_template.c" -#undef VDP_FUNCTION -}; - -struct vdpctx { - struct vdp_functions *vdp; - - VdpDevice vdp_device; - bool is_preempted; - bool preemption_acked; - bool preemption_user_notified; - unsigned int last_preemption_retry_fail; - VdpGetProcAddress *vdp_get_proc_address; - - VdpPresentationQueueTarget flip_target; - VdpPresentationQueue flip_queue; - uint64_t last_vdp_time; - unsigned int last_sync_update; - - VdpOutputSurface output_surfaces[MAX_OUTPUT_SURFACES]; - VdpOutputSurface screenshot_surface; - int num_output_surfaces; - struct buffered_video_surface { - VdpVideoSurface surface; - double pts; - mp_image_t *mpi; - } buffered_video[NUM_BUFFERED_VIDEO]; - int deint_queue_pos; - int output_surface_width, output_surface_height; - - VdpVideoMixer video_mixer; - struct mp_csp_details colorspace; - int deint; - int deint_type; - int deint_counter; - int pullup; - float denoise; - float sharpen; - int hqscaling; - int chroma_deint; - int flip_offset_window; - int flip_offset_fs; - int top_field_first; - bool flip; - - VdpDecoder decoder; - int decoder_max_refs; - - VdpRect src_rect_vid; - VdpRect out_rect_vid; - struct mp_osd_res osd_rect; - - struct vdpau_render_state surface_render[MAX_VIDEO_SURFACES]; - int surface_num; - int query_surface_num; - VdpTime recent_vsync_time; - float user_fps; - int composite_detect; - unsigned int vsync_interval; - uint64_t last_queue_time; - uint64_t queue_time[MAX_OUTPUT_SURFACES]; - uint64_t last_ideal_time; - bool dropped_frame; - uint64_t dropped_time; - uint32_t vid_width, vid_height; - uint32_t image_format; - VdpChromaType vdp_chroma_type; - VdpYCbCrFormat vdp_pixel_format; - - // OSD - struct osd_bitmap_surface { - VdpRGBAFormat format; - VdpBitmapSurface surface; - uint32_t max_width; - uint32_t max_height; - struct bitmap_packer *packer; - // List of surfaces to be rendered - struct osd_target { - VdpRect source; - VdpRect dest; - VdpColor color; - } *targets; - int targets_size; - int render_count; - int bitmap_id; - int bitmap_pos_id; - } osd_surfaces[MAX_OSD_PARTS]; - - // Video equalizer - struct mp_csp_equalizer video_eq; - - // These tell what's been initialized and uninit() should free/uninitialize - bool mode_switched; -}; - -static bool status_ok(struct vo *vo); - -static int change_vdptime_sync(struct vdpctx *vc, unsigned int *t) -{ - struct vdp_functions *vdp = vc->vdp; - VdpStatus vdp_st; - VdpTime vdp_time; - vdp_st = vdp->presentation_queue_get_time(vc->flip_queue, &vdp_time); - CHECK_ST_ERROR("Error when calling vdp_presentation_queue_get_time"); - unsigned int t1 = *t; - unsigned int t2 = GetTimer(); - uint64_t old = vc->last_vdp_time + (t1 - vc->last_sync_update) * 1000ULL; - if (vdp_time > old) - if (vdp_time > old + (t2 - t1) * 1000ULL) - vdp_time -= (t2 - t1) * 1000ULL; - else - vdp_time = old; - mp_msg(MSGT_VO, MSGL_DBG2, "[vdpau] adjusting VdpTime offset by %f µs\n", - (int64_t)(vdp_time - old) / 1000.); - vc->last_vdp_time = vdp_time; - vc->last_sync_update = t1; - *t = t2; - return 0; -} - -static uint64_t sync_vdptime(struct vo *vo) -{ - struct vdpctx *vc = vo->priv; - - unsigned int t = GetTimer(); - if (t - vc->last_sync_update > 5000000) - change_vdptime_sync(vc, &t); - uint64_t now = (t - vc->last_sync_update) * 1000ULL + vc->last_vdp_time; - // Make sure nanosecond inaccuracies don't make things inconsistent - now = FFMAX(now, vc->recent_vsync_time); - return now; -} - -static uint64_t convert_to_vdptime(struct vo *vo, unsigned int t) -{ - struct vdpctx *vc = vo->priv; - return (int)(t - vc->last_sync_update) * 1000LL + vc->last_vdp_time; -} - -static int render_video_to_output_surface(struct vo *vo, - VdpOutputSurface output_surface, - VdpRect *output_rect) -{ - struct vdpctx *vc = vo->priv; - struct vdp_functions *vdp = vc->vdp; - VdpTime dummy; - VdpStatus vdp_st; - if (vc->deint_queue_pos < 0) - return -1; - - struct buffered_video_surface *bv = vc->buffered_video; - int field = VDP_VIDEO_MIXER_PICTURE_STRUCTURE_FRAME; - unsigned int dp = vc->deint_queue_pos; - // dp==0 means last field of latest frame, 1 earlier field of latest frame, - // 2 last field of previous frame and so on - if (vc->deint) { - field = vc->top_field_first ^ (dp & 1) ? - VDP_VIDEO_MIXER_PICTURE_STRUCTURE_BOTTOM_FIELD: - VDP_VIDEO_MIXER_PICTURE_STRUCTURE_TOP_FIELD; - } - const VdpVideoSurface *past_fields = (const VdpVideoSurface []){ - bv[(dp+1)/2].surface, bv[(dp+2)/2].surface}; - const VdpVideoSurface *future_fields = (const VdpVideoSurface []){ - dp >= 1 ? bv[(dp-1)/2].surface : VDP_INVALID_HANDLE}; - vdp_st = vdp->presentation_queue_block_until_surface_idle(vc->flip_queue, - output_surface, - &dummy); - CHECK_ST_WARNING("Error when calling " - "vdp_presentation_queue_block_until_surface_idle"); - - vdp_st = vdp->video_mixer_render(vc->video_mixer, VDP_INVALID_HANDLE, - 0, field, 2, past_fields, - bv[dp/2].surface, 1, future_fields, - &vc->src_rect_vid, output_surface, - NULL, output_rect, 0, NULL); - CHECK_ST_WARNING("Error when calling vdp_video_mixer_render"); - return 0; -} - -static int video_to_output_surface(struct vo *vo) -{ - struct vdpctx *vc = vo->priv; - - return render_video_to_output_surface(vo, - vc->output_surfaces[vc->surface_num], - &vc->out_rect_vid); -} - -static int next_deint_queue_pos(struct vo *vo, bool eof) -{ - struct vdpctx *vc = vo->priv; - - int dqp = vc->deint_queue_pos; - if (dqp < 0) - dqp += 1000; - else - dqp = vc->deint >= 2 ? dqp - 1 : dqp - 2 | 1; - if (dqp < (eof ? 0 : 3)) - return -1; - return dqp; -} - -static void set_next_frame_info(struct vo *vo, bool eof) -{ - struct vdpctx *vc = vo->priv; - - vo->frame_loaded = false; - int dqp = next_deint_queue_pos(vo, eof); - if (dqp < 0) - return; - vo->frame_loaded = true; - - // Set pts values - struct buffered_video_surface *bv = vc->buffered_video; - int idx = dqp >> 1; - if (idx == 0) { // no future frame/pts available - vo->next_pts = bv[0].pts; - vo->next_pts2 = MP_NOPTS_VALUE; - } else if (!(vc->deint >= 2)) { // no field-splitting deinterlace - vo->next_pts = bv[idx].pts; - vo->next_pts2 = bv[idx - 1].pts; - } else { // deinterlace with separate fields - double intermediate_pts; - double diff = bv[idx - 1].pts - bv[idx].pts; - if (diff > 0 && diff < 0.5) - intermediate_pts = (bv[idx].pts + bv[idx - 1].pts) / 2; - else - intermediate_pts = bv[idx].pts; - if (dqp & 1) { // first field - vo->next_pts = bv[idx].pts; - vo->next_pts2 = intermediate_pts; - } else { - vo->next_pts = intermediate_pts; - vo->next_pts2 = bv[idx - 1].pts; - } - } -} - -static void add_new_video_surface(struct vo *vo, VdpVideoSurface surface, - struct mp_image *reserved_mpi, double pts) -{ - struct vdpctx *vc = vo->priv; - struct buffered_video_surface *bv = vc->buffered_video; - - if (reserved_mpi) - reserved_mpi->usage_count++; - if (bv[NUM_BUFFERED_VIDEO - 1].mpi) - bv[NUM_BUFFERED_VIDEO - 1].mpi->usage_count--; - - for (int i = NUM_BUFFERED_VIDEO - 1; i > 0; i--) - bv[i] = bv[i - 1]; - bv[0] = (struct buffered_video_surface){ - .mpi = reserved_mpi, - .surface = surface, - .pts = pts, - }; - - vc->deint_queue_pos = FFMIN(vc->deint_queue_pos + 2, - NUM_BUFFERED_VIDEO * 2 - 3); - set_next_frame_info(vo, false); -} - -static void forget_frames(struct vo *vo) -{ - struct vdpctx *vc = vo->priv; - - vc->deint_queue_pos = -1001; - vc->dropped_frame = false; - for (int i = 0; i < NUM_BUFFERED_VIDEO; i++) { - struct buffered_video_surface *p = vc->buffered_video + i; - if (p->mpi) - p->mpi->usage_count--; - *p = (struct buffered_video_surface){ - .surface = VDP_INVALID_HANDLE, - }; - } -} - -static void resize(struct vo *vo) -{ - struct vdpctx *vc = vo->priv; - struct vdp_functions *vdp = vc->vdp; - VdpStatus vdp_st; - struct mp_rect src_rect; - struct mp_rect dst_rect; - vo_get_src_dst_rects(vo, &src_rect, &dst_rect, &vc->osd_rect); - vc->out_rect_vid.x0 = dst_rect.x0; - vc->out_rect_vid.x1 = dst_rect.x1; - vc->out_rect_vid.y0 = dst_rect.y0; - vc->out_rect_vid.y1 = dst_rect.y1; - vc->src_rect_vid.x0 = src_rect.x0; - vc->src_rect_vid.x1 = src_rect.x1; - vc->src_rect_vid.y0 = vc->flip ? src_rect.y1 : src_rect.y0; - vc->src_rect_vid.y1 = vc->flip ? src_rect.y0 : src_rect.y1; - - int flip_offset_ms = vo_fs ? vc->flip_offset_fs : vc->flip_offset_window; - vo->flip_queue_offset = flip_offset_ms / 1000.; - - if (vc->output_surface_width < vo->dwidth - || vc->output_surface_height < vo->dheight) { - if (vc->output_surface_width < vo->dwidth) { - vc->output_surface_width += vc->output_surface_width >> 1; - vc->output_surface_width = FFMAX(vc->output_surface_width, - vo->dwidth); - } - if (vc->output_surface_height < vo->dheight) { - vc->output_surface_height += vc->output_surface_height >> 1; - vc->output_surface_height = FFMAX(vc->output_surface_height, - vo->dheight); - } - // Creation of output_surfaces - for (int i = 0; i < vc->num_output_surfaces; i++) - if (vc->output_surfaces[i] != VDP_INVALID_HANDLE) { - vdp_st = vdp->output_surface_destroy(vc->output_surfaces[i]); - CHECK_ST_WARNING("Error when calling " - "vdp_output_surface_destroy"); - } - for (int i = 0; i < vc->num_output_surfaces; i++) { - vdp_st = vdp->output_surface_create(vc->vdp_device, - OUTPUT_RGBA_FORMAT, - vc->output_surface_width, - vc->output_surface_height, - &vc->output_surfaces[i]); - CHECK_ST_WARNING("Error when calling vdp_output_surface_create"); - mp_msg(MSGT_VO, MSGL_DBG2, "vdpau out create: %u\n", - vc->output_surfaces[i]); - } - } - vo->want_redraw = true; -} - -static void preemption_callback(VdpDevice device, void *context) -{ - struct vdpctx *vc = context; - vc->is_preempted = true; - vc->preemption_acked = false; -} - -/* Initialize vdp_get_proc_address, called from preinit() */ -static int win_x11_init_vdpau_procs(struct vo *vo) -{ - struct vo_x11_state *x11 = vo->x11; - struct vdpctx *vc = vo->priv; - if (vc->vdp) // reinitialization after preemption - memset(vc->vdp, 0, sizeof(*vc->vdp)); - else - vc->vdp = talloc_zero(vc, struct vdp_functions); - struct vdp_functions *vdp = vc->vdp; - VdpStatus vdp_st; - - struct vdp_function { - const int id; - int offset; - }; - - const struct vdp_function *dsc; - - static const struct vdp_function vdp_func[] = { -#define VDP_FUNCTION(_, macro_name, mp_name) {macro_name, offsetof(struct vdp_functions, mp_name)}, -#include "vdpau_template.c" -#undef VDP_FUNCTION - {0, -1} - }; - - vdp_st = vdp_device_create_x11(x11->display, x11->screen, &vc->vdp_device, - &vc->vdp_get_proc_address); - if (vdp_st != VDP_STATUS_OK) { - if (vc->is_preempted) - mp_msg(MSGT_VO, MSGL_DBG2, "[vdpau] Error calling " - "vdp_device_create_x11 while preempted: %d\n", vdp_st); - else - mp_msg(MSGT_VO, MSGL_ERR, "[vdpau] Error when calling " - "vdp_device_create_x11: %d\n", vdp_st); - return -1; - } - - vdp->get_error_string = NULL; - for (dsc = vdp_func; dsc->offset >= 0; dsc++) { - vdp_st = vc->vdp_get_proc_address(vc->vdp_device, dsc->id, - (void **)((char *)vdp + dsc->offset)); - if (vdp_st != VDP_STATUS_OK) { - mp_msg(MSGT_VO, MSGL_ERR, "[vdpau] Error when calling " - "vdp_get_proc_address(function id %d): %s\n", dsc->id, - vdp->get_error_string ? vdp->get_error_string(vdp_st) : "?"); - return -1; - } - } - vdp_st = vdp->preemption_callback_register(vc->vdp_device, - preemption_callback, vc); - return 0; -} - -static int win_x11_init_vdpau_flip_queue(struct vo *vo) -{ - struct vdpctx *vc = vo->priv; - struct vdp_functions *vdp = vc->vdp; - struct vo_x11_state *x11 = vo->x11; - VdpStatus vdp_st; - - if (vc->flip_target == VDP_INVALID_HANDLE) { - vdp_st = vdp->presentation_queue_target_create_x11(vc->vdp_device, - x11->window, - &vc->flip_target); - CHECK_ST_ERROR("Error when calling " - "vdp_presentation_queue_target_create_x11"); - } - - /* Emperically this seems to be the first call which fails when we - * try to reinit after preemption while the user is still switched - * from X to a virtual terminal (creating the vdp_device initially - * succeeds, as does creating the flip_target above). This is - * probably not guaranteed behavior, but we'll assume it as a simple - * way to reduce warnings while trying to recover from preemption. - */ - if (vc->flip_queue == VDP_INVALID_HANDLE) { - vdp_st = vdp->presentation_queue_create(vc->vdp_device, vc->flip_target, - &vc->flip_queue); - if (vc->is_preempted && vdp_st != VDP_STATUS_OK) { - mp_msg(MSGT_VO, MSGL_DBG2, "[vdpau] Failed to create flip queue " - "while preempted: %s\n", vdp->get_error_string(vdp_st)); - return -1; - } else - CHECK_ST_ERROR("Error when calling vdp_presentation_queue_create"); - } - - VdpTime vdp_time; - vdp_st = vdp->presentation_queue_get_time(vc->flip_queue, &vdp_time); - CHECK_ST_ERROR("Error when calling vdp_presentation_queue_get_time"); - vc->last_vdp_time = vdp_time; - vc->last_sync_update = GetTimer(); - - vc->vsync_interval = 1; - if (vc->composite_detect && vo_x11_screen_is_composited(vo)) { - mp_msg(MSGT_VO, MSGL_INFO, "[vdpau] Compositing window manager " - "detected. Assuming timing info is inaccurate.\n"); - } else if (vc->user_fps > 0) { - vc->vsync_interval = 1e9 / vc->user_fps; - mp_msg(MSGT_VO, MSGL_INFO, "[vdpau] Assuming user-specified display " - "refresh rate of %.3f Hz.\n", vc->user_fps); - } else if (vc->user_fps == 0) { -#ifdef CONFIG_XF86VM - double fps = vo_vm_get_fps(vo); - if (!fps) - mp_msg(MSGT_VO, MSGL_WARN, "[vdpau] Failed to get display FPS\n"); - else { - vc->vsync_interval = 1e9 / fps; - // This is verbose, but I'm not yet sure how common wrong values are - mp_msg(MSGT_VO, MSGL_INFO, - "[vdpau] Got display refresh rate %.3f Hz.\n" - "[vdpau] If that value looks wrong give the " - "-vo vdpau:fps=X suboption manually.\n", fps); - } -#else - mp_msg(MSGT_VO, MSGL_INFO, "[vdpau] This binary has been compiled " - "without XF86VidMode support.\n"); - mp_msg(MSGT_VO, MSGL_INFO, "[vdpau] Can't use vsync-aware timing " - "without manually provided -vo vdpau:fps=X suboption.\n"); -#endif - } else - mp_msg(MSGT_VO, MSGL_V, "[vdpau] framedrop/timing logic disabled by " - "user.\n"); - - return 0; -} - -static int set_video_attribute(struct vdpctx *vc, VdpVideoMixerAttribute attr, - const void *value, char *attr_name) -{ - struct vdp_functions *vdp = vc->vdp; - VdpStatus vdp_st; - - vdp_st = vdp->video_mixer_set_attribute_values(vc->video_mixer, 1, &attr, - &value); - if (vdp_st != VDP_STATUS_OK) { - mp_msg(MSGT_VO, MSGL_ERR, "[vdpau] Error setting video mixer " - "attribute %s: %s\n", attr_name, vdp->get_error_string(vdp_st)); - return -1; - } - return 0; -} - -static void update_csc_matrix(struct vo *vo) -{ - struct vdpctx *vc = vo->priv; - - mp_msg(MSGT_VO, MSGL_V, "[vdpau] Updating CSC matrix\n"); - - // VdpCSCMatrix happens to be compatible with mplayer's CSC matrix type - // both are float[3][4] - VdpCSCMatrix matrix; - - struct mp_csp_params cparams = { - .colorspace = vc->colorspace, .input_bits = 8, .texture_bits = 8 }; - mp_csp_copy_equalizer_values(&cparams, &vc->video_eq); - mp_get_yuv2rgb_coeffs(&cparams, matrix); - - set_video_attribute(vc, VDP_VIDEO_MIXER_ATTRIBUTE_CSC_MATRIX, - &matrix, "CSC matrix"); -} - -#define SET_VIDEO_ATTR(attr_name, attr_type, value) set_video_attribute(vc, \ - VDP_VIDEO_MIXER_ATTRIBUTE_ ## attr_name, &(attr_type){value},\ - # attr_name) -static int create_vdp_mixer(struct vo *vo, VdpChromaType vdp_chroma_type) -{ - struct vdpctx *vc = vo->priv; - struct vdp_functions *vdp = vc->vdp; -#define VDP_NUM_MIXER_PARAMETER 3 -#define MAX_NUM_FEATURES 6 - int i; - VdpStatus vdp_st; - - if (vc->video_mixer != VDP_INVALID_HANDLE) - return 0; - - int feature_count = 0; - VdpVideoMixerFeature features[MAX_NUM_FEATURES]; - VdpBool feature_enables[MAX_NUM_FEATURES]; - static const VdpVideoMixerParameter parameters[VDP_NUM_MIXER_PARAMETER] = { - VDP_VIDEO_MIXER_PARAMETER_VIDEO_SURFACE_WIDTH, - VDP_VIDEO_MIXER_PARAMETER_VIDEO_SURFACE_HEIGHT, - VDP_VIDEO_MIXER_PARAMETER_CHROMA_TYPE, - }; - const void *const parameter_values[VDP_NUM_MIXER_PARAMETER] = { - &vc->vid_width, - &vc->vid_height, - &vdp_chroma_type, - }; - features[feature_count++] = VDP_VIDEO_MIXER_FEATURE_DEINTERLACE_TEMPORAL; - if (vc->deint_type == 4) - features[feature_count++] = - VDP_VIDEO_MIXER_FEATURE_DEINTERLACE_TEMPORAL_SPATIAL; - if (vc->pullup) - features[feature_count++] = VDP_VIDEO_MIXER_FEATURE_INVERSE_TELECINE; - if (vc->denoise) - features[feature_count++] = VDP_VIDEO_MIXER_FEATURE_NOISE_REDUCTION; - if (vc->sharpen) - features[feature_count++] = VDP_VIDEO_MIXER_FEATURE_SHARPNESS; - if (vc->hqscaling) { - VdpVideoMixerFeature hqscaling_feature = - VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L1 + vc->hqscaling-1; - VdpBool hqscaling_available; - vdp_st = vdp->video_mixer_query_feature_support(vc->vdp_device, - hqscaling_feature, - &hqscaling_available); - CHECK_ST_ERROR("Error when calling video_mixer_query_feature_support"); - if (hqscaling_available) - features[feature_count++] = hqscaling_feature; - else - mp_msg(MSGT_VO, MSGL_ERR, "[vdpau] Your hardware or VDPAU " - "library does not support requested hqscaling.\n"); - } - - vdp_st = vdp->video_mixer_create(vc->vdp_device, feature_count, features, - VDP_NUM_MIXER_PARAMETER, - parameters, parameter_values, - &vc->video_mixer); - CHECK_ST_ERROR("Error when calling vdp_video_mixer_create"); - - for (i = 0; i < feature_count; i++) - feature_enables[i] = VDP_TRUE; - if (vc->deint < 3) - feature_enables[0] = VDP_FALSE; - if (vc->deint_type == 4 && vc->deint < 4) - feature_enables[1] = VDP_FALSE; - if (feature_count) { - vdp_st = vdp->video_mixer_set_feature_enables(vc->video_mixer, - feature_count, features, - feature_enables); - CHECK_ST_WARNING("Error calling vdp_video_mixer_set_feature_enables"); - } - if (vc->denoise) - SET_VIDEO_ATTR(NOISE_REDUCTION_LEVEL, float, vc->denoise); - if (vc->sharpen) - SET_VIDEO_ATTR(SHARPNESS_LEVEL, float, vc->sharpen); - if (!vc->chroma_deint) - SET_VIDEO_ATTR(SKIP_CHROMA_DEINTERLACE, uint8_t, 1); - - update_csc_matrix(vo); - return 0; -} - -// Free everything specific to a certain video file -static void free_video_specific(struct vo *vo) -{ - struct vdpctx *vc = vo->priv; - struct vdp_functions *vdp = vc->vdp; - int i; - VdpStatus vdp_st; - - if (vc->decoder != VDP_INVALID_HANDLE) - vdp->decoder_destroy(vc->decoder); - vc->decoder = VDP_INVALID_HANDLE; - vc->decoder_max_refs = -1; - - forget_frames(vo); - - for (i = 0; i < MAX_VIDEO_SURFACES; i++) { - if (vc->surface_render[i].surface != VDP_INVALID_HANDLE) { - vdp_st = vdp->video_surface_destroy(vc->surface_render[i].surface); - CHECK_ST_WARNING("Error when calling vdp_video_surface_destroy"); - } - vc->surface_render[i].surface = VDP_INVALID_HANDLE; - } - - if (vc->video_mixer != VDP_INVALID_HANDLE) { - vdp_st = vdp->video_mixer_destroy(vc->video_mixer); - CHECK_ST_WARNING("Error when calling vdp_video_mixer_destroy"); - } - vc->video_mixer = VDP_INVALID_HANDLE; - - if (vc->screenshot_surface != VDP_INVALID_HANDLE) { - vdp_st = vdp->output_surface_destroy(vc->screenshot_surface); - CHECK_ST_WARNING("Error when calling vdp_output_surface_destroy"); - } - vc->screenshot_surface = VDP_INVALID_HANDLE; -} - -static int create_vdp_decoder(struct vo *vo, int max_refs) -{ - struct vdpctx *vc = vo->priv; - struct vdp_functions *vdp = vc->vdp; - VdpStatus vdp_st; - VdpDecoderProfile vdp_decoder_profile; - if (vc->decoder != VDP_INVALID_HANDLE) - vdp->decoder_destroy(vc->decoder); - switch (vc->image_format) { - case IMGFMT_VDPAU_MPEG1: - vdp_decoder_profile = VDP_DECODER_PROFILE_MPEG1; - break; - case IMGFMT_VDPAU_MPEG2: - vdp_decoder_profile = VDP_DECODER_PROFILE_MPEG2_MAIN; - break; - case IMGFMT_VDPAU_H264: - vdp_decoder_profile = VDP_DECODER_PROFILE_H264_HIGH; - mp_msg(MSGT_VO, MSGL_V, "[vdpau] Creating H264 hardware decoder " - "for %d reference frames.\n", max_refs); - break; - case IMGFMT_VDPAU_WMV3: - vdp_decoder_profile = VDP_DECODER_PROFILE_VC1_MAIN; - break; - case IMGFMT_VDPAU_VC1: - vdp_decoder_profile = VDP_DECODER_PROFILE_VC1_ADVANCED; - break; - case IMGFMT_VDPAU_MPEG4: - vdp_decoder_profile = VDP_DECODER_PROFILE_MPEG4_PART2_ASP; - break; - default: - mp_msg(MSGT_VO, MSGL_ERR, "[vdpau] Unknown image format!\n"); - goto fail; - } - vdp_st = vdp->decoder_create(vc->vdp_device, vdp_decoder_profile, - vc->vid_width, vc->vid_height, max_refs, - &vc->decoder); - CHECK_ST_WARNING("Failed creating VDPAU decoder"); - if (vdp_st != VDP_STATUS_OK) { - fail: - vc->decoder = VDP_INVALID_HANDLE; - vc->decoder_max_refs = 0; - return 0; - } - vc->decoder_max_refs = max_refs; - return 1; -} - -static int initialize_vdpau_objects(struct vo *vo) -{ - struct vdpctx *vc = vo->priv; - - vc->vdp_chroma_type = VDP_CHROMA_TYPE_420; - switch (vc->image_format) { - case IMGFMT_YV12: - case IMGFMT_I420: - case IMGFMT_IYUV: - vc->vdp_pixel_format = VDP_YCBCR_FORMAT_YV12; - break; - case IMGFMT_NV12: - vc->vdp_pixel_format = VDP_YCBCR_FORMAT_NV12; - break; - case IMGFMT_YUY2: - vc->vdp_pixel_format = VDP_YCBCR_FORMAT_YUYV; - vc->vdp_chroma_type = VDP_CHROMA_TYPE_422; - break; - case IMGFMT_UYVY: - vc->vdp_pixel_format = VDP_YCBCR_FORMAT_UYVY; - vc->vdp_chroma_type = VDP_CHROMA_TYPE_422; - } - if (win_x11_init_vdpau_flip_queue(vo) < 0) - return -1; - - if (create_vdp_mixer(vo, vc->vdp_chroma_type) < 0) - return -1; - - forget_frames(vo); - resize(vo); - return 0; -} - -static void mark_vdpau_objects_uninitialized(struct vo *vo) -{ - struct vdpctx *vc = vo->priv; - - vc->decoder = VDP_INVALID_HANDLE; - for (int i = 0; i < MAX_VIDEO_SURFACES; i++) - vc->surface_render[i].surface = VDP_INVALID_HANDLE; - forget_frames(vo); - vc->video_mixer = VDP_INVALID_HANDLE; - vc->flip_queue = VDP_INVALID_HANDLE; - vc->flip_target = VDP_INVALID_HANDLE; - for (int i = 0; i < MAX_OUTPUT_SURFACES; i++) - vc->output_surfaces[i] = VDP_INVALID_HANDLE; - vc->screenshot_surface = VDP_INVALID_HANDLE; - vc->vdp_device = VDP_INVALID_HANDLE; - for (int i = 0; i < MAX_OSD_PARTS; i++) { - struct osd_bitmap_surface *sfc = &vc->osd_surfaces[i]; - talloc_free(sfc->packer); - sfc->bitmap_id = sfc->bitmap_pos_id = 0; - *sfc = (struct osd_bitmap_surface){ - .surface = VDP_INVALID_HANDLE, - }; - } - vc->output_surface_width = vc->output_surface_height = -1; -} - -static int handle_preemption(struct vo *vo) -{ - struct vdpctx *vc = vo->priv; - - if (!vc->is_preempted) - return 0; - if (!vc->preemption_acked) - mark_vdpau_objects_uninitialized(vo); - vc->preemption_acked = true; - if (!vc->preemption_user_notified) { - mp_tmsg(MSGT_VO, MSGL_ERR, "[vdpau] Got display preemption notice! " - "Will attempt to recover.\n"); - vc->preemption_user_notified = true; - } - /* Trying to initialize seems to be quite slow, so only try once a - * second to avoid using 100% CPU. */ - if (vc->last_preemption_retry_fail - && GetTimerMS() - vc->last_preemption_retry_fail < 1000) - return -1; - if (win_x11_init_vdpau_procs(vo) < 0 || initialize_vdpau_objects(vo) < 0) { - vc->last_preemption_retry_fail = GetTimerMS() | 1; - return -1; - } - vc->last_preemption_retry_fail = 0; - vc->is_preempted = false; - vc->preemption_user_notified = false; - mp_tmsg(MSGT_VO, MSGL_INFO, "[vdpau] Recovered from display preemption.\n"); - return 1; -} - -/* - * connect to X server, create and map window, initialize all - * VDPAU objects, create different surfaces etc. - */ -static int config(struct vo *vo, uint32_t width, uint32_t height, - uint32_t d_width, uint32_t d_height, uint32_t flags, - uint32_t format) -{ - struct vdpctx *vc = vo->priv; - struct vo_x11_state *x11 = vo->x11; - XVisualInfo vinfo; - XSetWindowAttributes xswa; - XWindowAttributes attribs; - unsigned long xswamask; - int depth; - -#ifdef CONFIG_XF86VM - int vm = flags & VOFLAG_MODESWITCHING; -#endif - - if (handle_preemption(vo) < 0) - return -1; - - vc->flip = flags & VOFLAG_FLIPPING; - vc->image_format = format; - vc->vid_width = width; - vc->vid_height = height; - - free_video_specific(vo); - if (IMGFMT_IS_VDPAU(vc->image_format) && !create_vdp_decoder(vo, 2)) - return -1; - -#ifdef CONFIG_XF86VM - if (vm) { - vo_vm_switch(vo); - vc->mode_switched = true; - } -#endif - XGetWindowAttributes(x11->display, DefaultRootWindow(x11->display), - &attribs); - depth = attribs.depth; - if (depth != 15 && depth != 16 && depth != 24 && depth != 32) - depth = 24; - XMatchVisualInfo(x11->display, x11->screen, depth, TrueColor, &vinfo); - - xswa.background_pixel = 0; - xswa.border_pixel = 0; - /* Do not use CWBackPixel: It leads to VDPAU errors after - * aspect ratio changes. */ - xswamask = CWBorderPixel; - - vo_x11_create_vo_window(vo, &vinfo, vo->dx, vo->dy, d_width, d_height, - flags, CopyFromParent, "vdpau"); - XChangeWindowAttributes(x11->display, x11->window, xswamask, &xswa); - -#ifdef CONFIG_XF86VM - if (vm) { - /* Grab the mouse pointer in our window */ - if (vo_grabpointer) - XGrabPointer(x11->display, x11->window, True, 0, - GrabModeAsync, GrabModeAsync, - x11->window, None, CurrentTime); - XSetInputFocus(x11->display, x11->window, RevertToNone, CurrentTime); - } -#endif - - if (initialize_vdpau_objects(vo) < 0) - return -1; - - return 0; -} - -static void check_events(struct vo *vo) -{ - if (handle_preemption(vo) < 0) - return; - - int e = vo_x11_check_events(vo); - - if (e & VO_EVENT_RESIZE) - resize(vo); - else if (e & VO_EVENT_EXPOSE) { - vo->want_redraw = true; - } -} - -static struct bitmap_packer *make_packer(struct vo *vo, VdpRGBAFormat format) -{ - struct vdpctx *vc = vo->priv; - struct vdp_functions *vdp = vc->vdp; - - struct bitmap_packer *packer = talloc_zero(vo, struct bitmap_packer); - uint32_t w_max = 0, h_max = 0; - VdpStatus vdp_st = vdp-> - bitmap_surface_query_capabilities(vc->vdp_device, format, - &(VdpBool){0}, &w_max, &h_max); - CHECK_ST_WARNING("Query to get max OSD surface size failed"); - packer->w_max = w_max; - packer->h_max = h_max; - return packer; -} - -static void draw_osd_part(struct vo *vo, int index) -{ - struct vdpctx *vc = vo->priv; - struct vdp_functions *vdp = vc->vdp; - VdpStatus vdp_st; - struct osd_bitmap_surface *sfc = &vc->osd_surfaces[index]; - VdpOutputSurface output_surface = vc->output_surfaces[vc->surface_num]; - int i; - - VdpOutputSurfaceRenderBlendState blend_state = { - .struct_version = VDP_OUTPUT_SURFACE_RENDER_BLEND_STATE_VERSION, - .blend_factor_source_color = - VDP_OUTPUT_SURFACE_RENDER_BLEND_FACTOR_SRC_ALPHA, - .blend_factor_source_alpha = - VDP_OUTPUT_SURFACE_RENDER_BLEND_FACTOR_ONE, - .blend_factor_destination_color = - VDP_OUTPUT_SURFACE_RENDER_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA, - .blend_factor_destination_alpha = - VDP_OUTPUT_SURFACE_RENDER_BLEND_FACTOR_SRC_ALPHA, - .blend_equation_color = VDP_OUTPUT_SURFACE_RENDER_BLEND_EQUATION_ADD, - .blend_equation_alpha = VDP_OUTPUT_SURFACE_RENDER_BLEND_EQUATION_ADD, - }; - - VdpOutputSurfaceRenderBlendState blend_state_premultiplied = blend_state; - blend_state_premultiplied.blend_factor_source_color = - VDP_OUTPUT_SURFACE_RENDER_BLEND_FACTOR_ONE; - - for (i = 0; i < sfc->render_count; i++) { - VdpOutputSurfaceRenderBlendState *blend = &blend_state; - if (sfc->format == VDP_RGBA_FORMAT_B8G8R8A8) - blend = &blend_state_premultiplied; - vdp_st = vdp-> - output_surface_render_bitmap_surface(output_surface, - &sfc->targets[i].dest, - sfc->surface, - &sfc->targets[i].source, - &sfc->targets[i].color, - blend, - VDP_OUTPUT_SURFACE_RENDER_ROTATE_0); - CHECK_ST_WARNING("OSD: Error when rendering"); - } -} - -static void generate_osd_part(struct vo *vo, struct sub_bitmaps *imgs) -{ - struct vdpctx *vc = vo->priv; - struct vdp_functions *vdp = vc->vdp; - VdpStatus vdp_st; - struct osd_bitmap_surface *sfc = &vc->osd_surfaces[imgs->render_index]; - bool need_upload = false; - - if (imgs->bitmap_pos_id == sfc->bitmap_pos_id) - return; // Nothing changed and we still have the old data - - sfc->render_count = 0; - - if (imgs->format == SUBBITMAP_EMPTY || imgs->num_parts == 0) - return; - - if (imgs->bitmap_id == sfc->bitmap_id) - goto osd_skip_upload; - - need_upload = true; - VdpRGBAFormat format; - int format_size; - switch (imgs->format) { - case SUBBITMAP_LIBASS: - format = VDP_RGBA_FORMAT_A8; - format_size = 1; - break; - case SUBBITMAP_RGBA: - format = VDP_RGBA_FORMAT_B8G8R8A8; - format_size = 4; - break; - default: - abort(); - }; - if (sfc->format != format) { - talloc_free(sfc->packer); - sfc->packer = NULL; - }; - sfc->format = format; - if (!sfc->packer) - sfc->packer = make_packer(vo, format); - sfc->packer->padding = imgs->scaled; // assume 2x2 filter on scaling - int r = packer_pack_from_subbitmaps(sfc->packer, imgs); - if (r < 0) { - mp_msg(MSGT_VO, MSGL_ERR, "[vdpau] OSD bitmaps do not fit on " - "a surface with the maximum supported size\n"); - return; - } else if (r == 1) { - if (sfc->surface != VDP_INVALID_HANDLE) { - vdp_st = vdp->bitmap_surface_destroy(sfc->surface); - CHECK_ST_WARNING("Error when calling vdp_bitmap_surface_destroy"); - } - mp_msg(MSGT_VO, MSGL_V, "[vdpau] Allocating a %dx%d surface for " - "OSD bitmaps.\n", sfc->packer->w, sfc->packer->h); - vdp_st = vdp->bitmap_surface_create(vc->vdp_device, format, - sfc->packer->w, sfc->packer->h, - true, &sfc->surface); - if (vdp_st != VDP_STATUS_OK) - sfc->surface = VDP_INVALID_HANDLE; - CHECK_ST_WARNING("OSD: error when creating surface"); - } - if (imgs->scaled) { - char zeros[sfc->packer->used_width * format_size]; - memset(zeros, 0, sizeof(zeros)); - vdp_st = vdp->bitmap_surface_put_bits_native(sfc->surface, - &(const void *){zeros}, &(uint32_t){0}, - &(VdpRect){0, 0, sfc->packer->used_width, - sfc->packer->used_height}); - } - -osd_skip_upload: - if (sfc->surface == VDP_INVALID_HANDLE) - return; - if (sfc->packer->count > sfc->targets_size) { - talloc_free(sfc->targets); - sfc->targets_size = sfc->packer->count; - sfc->targets = talloc_size(vc, sfc->targets_size - * sizeof(*sfc->targets)); - } - - for (int i = 0 ;i < sfc->packer->count; i++) { - struct sub_bitmap *b = &imgs->parts[i]; - struct osd_target *target = sfc->targets + sfc->render_count; - int x = sfc->packer->result[i].x; - int y = sfc->packer->result[i].y; - target->source = (VdpRect){x, y, x + b->w, y + b->h}; - target->dest = (VdpRect){b->x, b->y, b->x + b->dw, b->y + b->dh}; - target->color = (VdpColor){1, 1, 1, 1}; - if (imgs->format == SUBBITMAP_LIBASS) { - uint32_t color = b->libass.color; - target->color.alpha = 1.0 - ((color >> 0) & 0xff) / 255.0; - target->color.blue = ((color >> 8) & 0xff) / 255.0; - target->color.green = ((color >> 16) & 0xff) / 255.0; - target->color.red = ((color >> 24) & 0xff) / 255.0; - } - if (need_upload) { - vdp_st = vdp-> - bitmap_surface_put_bits_native(sfc->surface, - &(const void *){b->bitmap}, - &(uint32_t){b->stride}, - &target->source); - CHECK_ST_WARNING("OSD: putbits failed"); - } - sfc->render_count++; - } - - sfc->bitmap_id = imgs->bitmap_id; - sfc->bitmap_pos_id = imgs->bitmap_pos_id; -} - -static void draw_osd_cb(void *ctx, struct sub_bitmaps *imgs) -{ - struct vo *vo = ctx; - generate_osd_part(vo, imgs); - draw_osd_part(vo, imgs->render_index); -} - -static void draw_osd(struct vo *vo, struct osd_state *osd) -{ - struct vdpctx *vc = vo->priv; - - if (!status_ok(vo)) - return; - - static const bool formats[SUBBITMAP_COUNT] = { - [SUBBITMAP_LIBASS] = true, - [SUBBITMAP_RGBA] = true, - }; - - osd_draw(osd, vc->osd_rect, osd->vo_pts, 0, formats, draw_osd_cb, vo); -} - -static int update_presentation_queue_status(struct vo *vo) -{ - struct vdpctx *vc = vo->priv; - struct vdp_functions *vdp = vc->vdp; - VdpStatus vdp_st; - - while (vc->query_surface_num != vc->surface_num) { - VdpTime vtime; - VdpPresentationQueueStatus status; - VdpOutputSurface surface = vc->output_surfaces[vc->query_surface_num]; - vdp_st = vdp->presentation_queue_query_surface_status(vc->flip_queue, - surface, - &status, &vtime); - CHECK_ST_WARNING("Error calling " - "presentation_queue_query_surface_status"); - if (status == VDP_PRESENTATION_QUEUE_STATUS_QUEUED) - break; - if (vc->vsync_interval > 1) { - uint64_t qtime = vc->queue_time[vc->query_surface_num]; - if (vtime < qtime + vc->vsync_interval / 2) - mp_msg(MSGT_VO, MSGL_V, "[vdpau] Frame shown too early\n"); - if (vtime > qtime + vc->vsync_interval) - mp_msg(MSGT_VO, MSGL_V, "[vdpau] Frame shown late\n"); - } - vc->query_surface_num = WRAP_ADD(vc->query_surface_num, 1, - vc->num_output_surfaces); - vc->recent_vsync_time = vtime; - } - int num_queued = WRAP_ADD(vc->surface_num, -vc->query_surface_num, - vc->num_output_surfaces); - mp_msg(MSGT_VO, MSGL_DBG3, "[vdpau] Queued surface count (before add): " - "%d\n", num_queued); - return num_queued; -} - -static inline uint64_t prev_vs2(struct vdpctx *vc, uint64_t ts, int shift) -{ - uint64_t offset = ts - vc->recent_vsync_time; - // Fix negative values for 1<<shift vsyncs before vc->recent_vsync_time - offset += (uint64_t)vc->vsync_interval << shift; - offset %= vc->vsync_interval; - return ts - offset; -} - -static void flip_page_timed(struct vo *vo, unsigned int pts_us, int duration) -{ - struct vdpctx *vc = vo->priv; - struct vdp_functions *vdp = vc->vdp; - VdpStatus vdp_st; - uint32_t vsync_interval = vc->vsync_interval; - - if (handle_preemption(vo) < 0) - return; - - if (duration > INT_MAX / 1000) - duration = -1; - else - duration *= 1000; - - if (vc->vsync_interval == 1) - duration = -1; // Make sure drop logic is disabled - - uint64_t now = sync_vdptime(vo); - uint64_t pts = pts_us ? convert_to_vdptime(vo, pts_us) : now; - uint64_t ideal_pts = pts; - uint64_t npts = duration >= 0 ? pts + duration : UINT64_MAX; - -#define PREV_VS2(ts, shift) prev_vs2(vc, ts, shift) - // Only gives accurate results for ts >= vc->recent_vsync_time -#define PREV_VSYNC(ts) PREV_VS2(ts, 0) - - /* We hope to be here at least one vsync before the frame should be shown. - * If we are running late then don't drop the frame unless there is - * already one queued for the next vsync; even if we _hope_ to show the - * next frame soon enough to mean this one should be dropped we might - * not make the target time in reality. Without this check we could drop - * every frame, freezing the display completely if video lags behind. - */ - if (now > PREV_VSYNC(FFMAX(pts, vc->last_queue_time + vsync_interval))) - npts = UINT64_MAX; - - /* Allow flipping a frame at a vsync if its presentation time is a - * bit after that vsync and the change makes the flip time delta - * from previous frame better match the target timestamp delta. - * This avoids instability with frame timestamps falling near vsyncs. - * For example if the frame timestamps were (with vsyncs at - * integer values) 0.01, 1.99, 4.01, 5.99, 8.01, ... then - * straightforward timing at next vsync would flip the frames at - * 1, 2, 5, 6, 9; this changes it to 1, 2, 4, 6, 8 and so on with - * regular 2-vsync intervals. - * - * Also allow moving the frame forward if it looks like we dropped - * the previous frame incorrectly (now that we know better after - * having final exact timestamp information for this frame) and - * there would unnecessarily be a vsync without a frame change. - */ - uint64_t vsync = PREV_VSYNC(pts); - if (pts < vsync + vsync_interval / 4 - && (vsync - PREV_VS2(vc->last_queue_time, 16) - > pts - vc->last_ideal_time + vsync_interval / 2 - || vc->dropped_frame && vsync > vc->dropped_time)) - pts -= vsync_interval / 2; - - vc->dropped_frame = true; // changed at end if false - vc->dropped_time = ideal_pts; - - pts = FFMAX(pts, vc->last_queue_time + vsync_interval); - pts = FFMAX(pts, now); - if (npts < PREV_VSYNC(pts) + vsync_interval) - return; - - int num_flips = update_presentation_queue_status(vo); - vsync = vc->recent_vsync_time + num_flips * vc->vsync_interval; - now = sync_vdptime(vo); - pts = FFMAX(pts, now); - pts = FFMAX(pts, vsync + (vsync_interval >> 2)); - vsync = PREV_VSYNC(pts); - if (npts < vsync + vsync_interval) - return; - pts = vsync + (vsync_interval >> 2); - vdp_st = - vdp->presentation_queue_display(vc->flip_queue, - vc->output_surfaces[vc->surface_num], - vo->dwidth, vo->dheight, pts); - CHECK_ST_WARNING("Error when calling vdp_presentation_queue_display"); - - vc->last_queue_time = pts; - vc->queue_time[vc->surface_num] = pts; - vc->last_ideal_time = ideal_pts; - vc->dropped_frame = false; - vc->surface_num = WRAP_ADD(vc->surface_num, 1, vc->num_output_surfaces); -} - -static int draw_slice(struct vo *vo, uint8_t *image[], int stride[], int w, - int h, int x, int y) -{ - struct vdpctx *vc = vo->priv; - struct vdp_functions *vdp = vc->vdp; - VdpStatus vdp_st; - - if (handle_preemption(vo) < 0) - return VO_TRUE; - - struct vdpau_render_state *rndr = (struct vdpau_render_state *)image[0]; - int max_refs = vc->image_format == IMGFMT_VDPAU_H264 ? - rndr->info.h264.num_ref_frames : 2; - if (!IMGFMT_IS_VDPAU(vc->image_format)) - return VO_FALSE; - if ((vc->decoder == VDP_INVALID_HANDLE || vc->decoder_max_refs < max_refs) - && !create_vdp_decoder(vo, max_refs)) - return VO_FALSE; - - vdp_st = vdp->decoder_render(vc->decoder, rndr->surface, - (void *)&rndr->info, - rndr->bitstream_buffers_used, - rndr->bitstream_buffers); - CHECK_ST_WARNING("Failed VDPAU decoder rendering"); - return VO_TRUE; -} - - -static struct vdpau_render_state *get_surface(struct vo *vo, int number) -{ - struct vdpctx *vc = vo->priv; - struct vdp_functions *vdp = vc->vdp; - - if (number >= MAX_VIDEO_SURFACES) - return NULL; - if (vc->surface_render[number].surface == VDP_INVALID_HANDLE - && !vc->is_preempted) { - VdpStatus vdp_st; - vdp_st = vdp->video_surface_create(vc->vdp_device, vc->vdp_chroma_type, - vc->vid_width, vc->vid_height, - &vc->surface_render[number].surface); - CHECK_ST_WARNING("Error when calling vdp_video_surface_create"); - } - mp_msg(MSGT_VO, MSGL_DBG3, "vdpau vid create: %u\n", - vc->surface_render[number].surface); - return &vc->surface_render[number]; -} - -static void draw_image(struct vo *vo, mp_image_t *mpi, double pts) -{ - struct vdpctx *vc = vo->priv; - struct vdp_functions *vdp = vc->vdp; - struct mp_image *reserved_mpi = NULL; - struct vdpau_render_state *rndr; - - if (IMGFMT_IS_VDPAU(vc->image_format)) { - rndr = mpi->priv; - reserved_mpi = mpi; - } else if (!(mpi->flags & MP_IMGFLAG_DRAW_CALLBACK)) { - rndr = get_surface(vo, vc->deint_counter); - vc->deint_counter = WRAP_ADD(vc->deint_counter, 1, NUM_BUFFERED_VIDEO); - if (handle_preemption(vo) >= 0) { - VdpStatus vdp_st; - const void *destdata[3] = {mpi->planes[0], mpi->planes[2], - mpi->planes[1]}; - if (vc->image_format == IMGFMT_NV12) - destdata[1] = destdata[2]; - vdp_st = vdp->video_surface_put_bits_y_cb_cr(rndr->surface, - vc->vdp_pixel_format, destdata, mpi->stride); - CHECK_ST_WARNING("Error when calling " - "vdp_video_surface_put_bits_y_cb_cr"); - } - } else - // We don't support slice callbacks so this shouldn't occur - - // I think the flags test above in pointless, but I'm adding - // this instead of removing it just in case. - abort(); - if (mpi->fields & MP_IMGFIELD_ORDERED) - vc->top_field_first = !!(mpi->fields & MP_IMGFIELD_TOP_FIRST); - else - vc->top_field_first = 1; - - add_new_video_surface(vo, rndr->surface, reserved_mpi, pts); - - return; -} - -// warning: the size and pixel format of surface must match that of the -// surfaces in vc->output_surfaces -static struct mp_image *read_output_surface(struct vdpctx *vc, - VdpOutputSurface surface, - int width, int height) -{ - VdpStatus vdp_st; - struct vdp_functions *vdp = vc->vdp; - struct mp_image *image = alloc_mpi(width, height, IMGFMT_BGR32); - image->colorspace = MP_CSP_RGB; - image->levels = vc->colorspace.levels_out; // hardcoded with conv. matrix - - void *dst_planes[] = { image->planes[0] }; - uint32_t dst_pitches[] = { image->stride[0] }; - vdp_st = vdp->output_surface_get_bits_native(surface, NULL, dst_planes, - dst_pitches); - CHECK_ST_WARNING("Error when calling vdp_output_surface_get_bits_native"); - - return image; -} - -static struct mp_image *get_screenshot(struct vo *vo) -{ - struct vdpctx *vc = vo->priv; - VdpStatus vdp_st; - struct vdp_functions *vdp = vc->vdp; - - if (vc->screenshot_surface == VDP_INVALID_HANDLE) { - vdp_st = vdp->output_surface_create(vc->vdp_device, - OUTPUT_RGBA_FORMAT, - vc->vid_width, vc->vid_height, - &vc->screenshot_surface); - CHECK_ST_WARNING("Error when calling vdp_output_surface_create"); - } - - VdpRect rc = { .x1 = vc->vid_width, .y1 = vc->vid_height }; - render_video_to_output_surface(vo, vc->screenshot_surface, &rc); - - struct mp_image *image = read_output_surface(vc, vc->screenshot_surface, - vc->vid_width, vc->vid_height); - - image->display_w = vo->aspdat.prew; - image->display_h = vo->aspdat.preh; - - return image; -} - -static struct mp_image *get_window_screenshot(struct vo *vo) -{ - struct vdpctx *vc = vo->priv; - int last_surface = WRAP_ADD(vc->surface_num, -1, vc->num_output_surfaces); - VdpOutputSurface screen = vc->output_surfaces[last_surface]; - struct mp_image *image = read_output_surface(vo->priv, screen, - vc->output_surface_width, - vc->output_surface_height); - image->width = image->w = vo->dwidth; - image->height = image->h = vo->dheight; - return image; -} - -static uint32_t get_image(struct vo *vo, mp_image_t *mpi) -{ - struct vdpctx *vc = vo->priv; - struct vdpau_render_state *rndr; - - // no dr for non-decoding for now - if (!IMGFMT_IS_VDPAU(vc->image_format)) - return VO_FALSE; - if (mpi->type != MP_IMGTYPE_NUMBERED) - return VO_FALSE; - - rndr = get_surface(vo, mpi->number); - if (!rndr) { - mp_msg(MSGT_VO, MSGL_ERR, "[vdpau] no surfaces available in " - "get_image\n"); - // TODO: this probably breaks things forever, provide a dummy buffer? - return VO_FALSE; - } - mpi->flags |= MP_IMGFLAG_DIRECT; - mpi->stride[0] = mpi->stride[1] = mpi->stride[2] = 0; - mpi->planes[0] = mpi->planes[1] = mpi->planes[2] = NULL; - // hack to get around a check and to avoid a special-case in vd_ffmpeg.c - mpi->planes[0] = (void *)rndr; - mpi->num_planes = 1; - mpi->priv = rndr; - return VO_TRUE; -} - -static int query_format(uint32_t format) -{ - int default_flags = VFCAP_CSP_SUPPORTED | VFCAP_CSP_SUPPORTED_BY_HW - | VFCAP_HWSCALE_UP | VFCAP_HWSCALE_DOWN | VFCAP_OSD - | VFCAP_FLIP; - switch (format) { - case IMGFMT_YV12: - case IMGFMT_I420: - case IMGFMT_IYUV: - case IMGFMT_NV12: - case IMGFMT_YUY2: - case IMGFMT_UYVY: - return default_flags | VOCAP_NOSLICES; - case IMGFMT_VDPAU_MPEG1: - case IMGFMT_VDPAU_MPEG2: - case IMGFMT_VDPAU_H264: - case IMGFMT_VDPAU_WMV3: - case IMGFMT_VDPAU_VC1: - case IMGFMT_VDPAU_MPEG4: - return default_flags; - } - return 0; -} - -static void destroy_vdpau_objects(struct vo *vo) -{ - struct vdpctx *vc = vo->priv; - struct vdp_functions *vdp = vc->vdp; - - int i; - VdpStatus vdp_st; - - free_video_specific(vo); - - if (vc->flip_queue != VDP_INVALID_HANDLE) { - vdp_st = vdp->presentation_queue_destroy(vc->flip_queue); - CHECK_ST_WARNING("Error when calling vdp_presentation_queue_destroy"); - } - - if (vc->flip_target != VDP_INVALID_HANDLE) { - vdp_st = vdp->presentation_queue_target_destroy(vc->flip_target); - CHECK_ST_WARNING("Error when calling " - "vdp_presentation_queue_target_destroy"); - } - - for (i = 0; i < vc->num_output_surfaces; i++) { - if (vc->output_surfaces[i] == VDP_INVALID_HANDLE) - continue; - vdp_st = vdp->output_surface_destroy(vc->output_surfaces[i]); - CHECK_ST_WARNING("Error when calling vdp_output_surface_destroy"); - } - - for (int i = 0; i < MAX_OSD_PARTS; i++) { - struct osd_bitmap_surface *sfc = &vc->osd_surfaces[i]; - if (sfc->surface != VDP_INVALID_HANDLE) { - vdp_st = vdp->bitmap_surface_destroy(sfc->surface); - CHECK_ST_WARNING("Error when calling vdp_bitmap_surface_destroy"); - } - } - - vdp_st = vdp->device_destroy(vc->vdp_device); - CHECK_ST_WARNING("Error when calling vdp_device_destroy"); -} - -static void uninit(struct vo *vo) -{ - struct vdpctx *vc = vo->priv; - - /* Destroy all vdpau objects */ - destroy_vdpau_objects(vo); - -#ifdef CONFIG_XF86VM - if (vc->mode_switched) - vo_vm_close(vo); -#endif - vo_x11_uninit(vo); - - // Free bitstream buffers allocated by FFmpeg - for (int i = 0; i < MAX_VIDEO_SURFACES; i++) - av_freep(&vc->surface_render[i].bitstream_buffers); -} - -static int preinit(struct vo *vo, const char *arg) -{ - struct vdpctx *vc = vo->priv; - - // Mark everything as invalid first so uninit() can tell what has been - // allocated - mark_vdpau_objects_uninitialized(vo); - - vc->colorspace = (struct mp_csp_details) MP_CSP_DETAILS_DEFAULTS; - vc->video_eq.capabilities = MP_CSP_EQ_CAPS_COLORMATRIX; - - vc->deint_type = vc->deint ? FFABS(vc->deint) : 3; - if (vc->deint < 0) - vc->deint = 0; - - if (!vo_init(vo)) - return -1; - - // After this calling uninit() should work to free resources - - if (win_x11_init_vdpau_procs(vo) < 0) { - if (vc->vdp && vc->vdp->device_destroy) - vc->vdp->device_destroy(vc->vdp_device); - vo_x11_uninit(vo); - return -1; - } - - return 0; -} - -static int get_equalizer(struct vo *vo, const char *name, int *value) -{ - struct vdpctx *vc = vo->priv; - return mp_csp_equalizer_get(&vc->video_eq, name, value) >= 0 ? - VO_TRUE : VO_NOTIMPL; -} - -static bool status_ok(struct vo *vo) -{ - if (!vo->config_ok || handle_preemption(vo) < 0) - return false; - return true; -} - -static int set_equalizer(struct vo *vo, const char *name, int value) -{ - struct vdpctx *vc = vo->priv; - - if (mp_csp_equalizer_set(&vc->video_eq, name, value) < 0) - return VO_NOTIMPL; - - if (status_ok(vo)) - update_csc_matrix(vo); - return true; -} - -static void checked_resize(struct vo *vo) -{ - if (!status_ok(vo)) - return; - resize(vo); -} - -static int control(struct vo *vo, uint32_t request, void *data) -{ - struct vdpctx *vc = vo->priv; - struct vdp_functions *vdp = vc->vdp; - - handle_preemption(vo); - - switch (request) { - case VOCTRL_GET_DEINTERLACE: - *(int *)data = vc->deint; - return VO_TRUE; - case VOCTRL_SET_DEINTERLACE: - vc->deint = *(int *)data; - if (vc->deint) - vc->deint = vc->deint_type; - if (vc->deint_type > 2 && status_ok(vo)) { - VdpStatus vdp_st; - VdpVideoMixerFeature features[1] = - {vc->deint_type == 3 ? - VDP_VIDEO_MIXER_FEATURE_DEINTERLACE_TEMPORAL : - VDP_VIDEO_MIXER_FEATURE_DEINTERLACE_TEMPORAL_SPATIAL}; - VdpBool feature_enables[1] = {vc->deint ? VDP_TRUE : VDP_FALSE}; - vdp_st = vdp->video_mixer_set_feature_enables(vc->video_mixer, - 1, features, - feature_enables); - CHECK_ST_WARNING("Error changing deinterlacing settings"); - } - vo->want_redraw = true; - return VO_TRUE; - case VOCTRL_PAUSE: - if (vc->dropped_frame) - vo->want_redraw = true; - return true; - case VOCTRL_QUERY_FORMAT: - return query_format(*(uint32_t *)data); - case VOCTRL_GET_IMAGE: - return get_image(vo, data); - case VOCTRL_DRAW_IMAGE: - abort(); // draw_image() should get called directly - case VOCTRL_BORDER: - vo_x11_border(vo); - checked_resize(vo); - return VO_TRUE; - case VOCTRL_FULLSCREEN: - vo_x11_fullscreen(vo); - checked_resize(vo); - return VO_TRUE; - case VOCTRL_GET_PANSCAN: - return VO_TRUE; - case VOCTRL_SET_PANSCAN: - checked_resize(vo); - return VO_TRUE; - case VOCTRL_SET_EQUALIZER: { - vo->want_redraw = true; - struct voctrl_set_equalizer_args *args = data; - return set_equalizer(vo, args->name, args->value); - } - case VOCTRL_GET_EQUALIZER: { - struct voctrl_get_equalizer_args *args = data; - return get_equalizer(vo, args->name, args->valueptr); - } - case VOCTRL_SET_YUV_COLORSPACE: - vc->colorspace = *(struct mp_csp_details *)data; - if (status_ok(vo)) - update_csc_matrix(vo); - vo->want_redraw = true; - return true; - case VOCTRL_GET_YUV_COLORSPACE: - *(struct mp_csp_details *)data = vc->colorspace; - return true; - case VOCTRL_ONTOP: - vo_x11_ontop(vo); - return VO_TRUE; - case VOCTRL_UPDATE_SCREENINFO: - update_xinerama_info(vo); - return VO_TRUE; - case VOCTRL_NEWFRAME: - vc->deint_queue_pos = next_deint_queue_pos(vo, true); - if (status_ok(vo)) - video_to_output_surface(vo); - return true; - case VOCTRL_SKIPFRAME: - vc->deint_queue_pos = next_deint_queue_pos(vo, true); - return true; - case VOCTRL_REDRAW_FRAME: - if (status_ok(vo)) - video_to_output_surface(vo); - return true; - case VOCTRL_RESET: - forget_frames(vo); - return true; - case VOCTRL_SCREENSHOT: { - if (!status_ok(vo)) - return false; - struct voctrl_screenshot_args *args = data; - if (args->full_window) - args->out_image = get_window_screenshot(vo); - else - args->out_image = get_screenshot(vo); - return true; - } - } - return VO_NOTIMPL; -} - -#undef OPT_BASE_STRUCT -#define OPT_BASE_STRUCT struct vdpctx - -const struct vo_driver video_out_vdpau = { - .is_new = true, - .buffer_frames = true, - .info = &(const struct vo_info_s){ - "VDPAU with X11", - "vdpau", - "Rajib Mahapatra <rmahapatra@nvidia.com> and others", - "" - }, - .preinit = preinit, - .config = config, - .control = control, - .draw_image = draw_image, - .get_buffered_frame = set_next_frame_info, - .draw_slice = draw_slice, - .draw_osd = draw_osd, - .flip_page_timed = flip_page_timed, - .check_events = check_events, - .uninit = uninit, - .priv_size = sizeof(struct vdpctx), - .options = (const struct m_option []){ - OPT_INTRANGE("deint", deint, 0, -4, 4), - OPT_FLAG_ON("chroma-deint", chroma_deint, 0, OPTDEF_INT(1)), - OPT_FLAG_OFF("nochroma-deint", chroma_deint, 0), - OPT_MAKE_FLAGS("pullup", pullup, 0), - OPT_FLOATRANGE("denoise", denoise, 0, 0, 1), - OPT_FLOATRANGE("sharpen", sharpen, 0, -1, 1), - OPT_INTRANGE("hqscaling", hqscaling, 0, 0, 9), - OPT_FLOAT("fps", user_fps, 0), - OPT_FLAG_ON("composite-detect", composite_detect, 0, OPTDEF_INT(1)), - OPT_INT("queuetime_windowed", flip_offset_window, 0, OPTDEF_INT(50)), - OPT_INT("queuetime_fs", flip_offset_fs, 0, OPTDEF_INT(50)), - OPT_INTRANGE("output_surfaces", num_output_surfaces, 0, - 2, MAX_OUTPUT_SURFACES, OPTDEF_INT(3)), - {NULL}, - } -}; diff --git a/libvo/vo_x11.c b/libvo/vo_x11.c deleted file mode 100644 index 2358b0a295..0000000000 --- a/libvo/vo_x11.c +++ /dev/null @@ -1,620 +0,0 @@ -/* - * 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 <sys/types.h> - -#include "config.h" -#include "video_out.h" -#include "aspect.h" -#include "csputils.h" -#include "libmpcodecs/mp_image.h" -#include "libmpcodecs/vfcap.h" - -#include <X11/Xlib.h> -#include <X11/Xutil.h> - -#include <errno.h> - -#include "x11_common.h" - -#ifdef HAVE_SHM -#include <sys/ipc.h> -#include <sys/shm.h> -#include <X11/extensions/XShm.h> -#endif - -#include "sub/sub.h" - -#include "libmpcodecs/sws_utils.h" -#define MODE_RGB 0x1 -#define MODE_BGR 0x2 - -#include "mp_msg.h" - -extern int sws_flags; - -struct priv { - struct vo *vo; - - /* local data */ - unsigned char *ImageData; - //! original unaligned pointer for free - unsigned char *ImageDataOrig; - - /* X11 related variables */ - XImage *myximage; - int depth, bpp; - XWindowAttributes attribs; - - int int_pause; - - int Flip_Flag; - int zoomFlag; - - uint32_t image_width; - uint32_t image_height; - uint32_t in_format; - uint32_t out_format; - int out_offset; - int srcW; - int srcH; - - int old_vo_dwidth; - int old_vo_dheight; - - struct SwsContext *swsContext; - int dst_width; - - XVisualInfo vinfo; - - int firstTime; - -#ifdef HAVE_SHM - int Shmem_Flag; - - XShmSegmentInfo Shminfo[1]; - int gXErrorFlag; - int CompletionType; -#endif -}; - -static void flip_page(struct vo *vo); - -static void check_events(struct vo *vo) -{ - struct priv *p = vo->priv; - - int ret = vo_x11_check_events(vo); - - if (ret & VO_EVENT_RESIZE) - vo_x11_clearwindow(vo, vo->x11->window); - else if (ret & VO_EVENT_EXPOSE) - vo_x11_clearwindow_part(vo, vo->x11->window, p->myximage->width, - p->myximage->height); - if (ret & VO_EVENT_EXPOSE && p->int_pause) - flip_page(vo); -} - -static void getMyXImage(struct priv *p) -{ - struct vo *vo = p->vo; -#ifdef HAVE_SHM - if (vo->x11->display_is_local && XShmQueryExtension(vo->x11->display)) - p->Shmem_Flag = 1; - else { - p->Shmem_Flag = 0; - mp_msg(MSGT_VO, MSGL_WARN, - "Shared memory not supported\nReverting to normal Xlib\n"); - } - if (p->Shmem_Flag) - p->CompletionType = XShmGetEventBase(vo->x11->display) + ShmCompletion; - - if (p->Shmem_Flag) { - p->myximage = - XShmCreateImage(vo->x11->display, p->vinfo.visual, p->depth, - ZPixmap, NULL, &p->Shminfo[0], p->image_width, - p->image_height); - if (p->myximage == NULL) { - mp_msg(MSGT_VO, MSGL_WARN, - "Shared memory error,disabling ( Ximage error )\n"); - goto shmemerror; - } - p->Shminfo[0].shmid = shmget(IPC_PRIVATE, - p->myximage->bytes_per_line * - p->myximage->height, - IPC_CREAT | 0777); - if (p->Shminfo[0].shmid < 0) { - XDestroyImage(p->myximage); - mp_msg(MSGT_VO, MSGL_V, "%s\n", strerror(errno)); - //perror( strerror( errno ) ); - mp_msg(MSGT_VO, MSGL_WARN, - "Shared memory error,disabling ( seg id error )\n"); - goto shmemerror; - } - p->Shminfo[0].shmaddr = (char *) shmat(p->Shminfo[0].shmid, 0, 0); - - if (p->Shminfo[0].shmaddr == ((char *) -1)) { - XDestroyImage(p->myximage); - if (p->Shminfo[0].shmaddr != ((char *) -1)) - shmdt(p->Shminfo[0].shmaddr); - mp_msg(MSGT_VO, MSGL_WARN, - "Shared memory error,disabling ( address error )\n"); - goto shmemerror; - } - p->myximage->data = p->Shminfo[0].shmaddr; - p->ImageData = (unsigned char *) p->myximage->data; - p->Shminfo[0].readOnly = False; - XShmAttach(vo->x11->display, &p->Shminfo[0]); - - XSync(vo->x11->display, False); - - if (p->gXErrorFlag) { - XDestroyImage(p->myximage); - shmdt(p->Shminfo[0].shmaddr); - mp_msg(MSGT_VO, MSGL_WARN, "Shared memory error,disabling.\n"); - p->gXErrorFlag = 0; - goto shmemerror; - } else - shmctl(p->Shminfo[0].shmid, IPC_RMID, 0); - - if (!p->firstTime) { - mp_msg(MSGT_VO, MSGL_V, "Sharing memory.\n"); - p->firstTime = 1; - } - } else { -shmemerror: - p->Shmem_Flag = 0; -#endif - p->myximage = - XCreateImage(vo->x11->display, p->vinfo.visual, p->depth, ZPixmap, - 0, NULL, p->image_width, p->image_height, 8, 0); - p->ImageDataOrig = - malloc(p->myximage->bytes_per_line * p->image_height + 32); - p->myximage->data = p->ImageDataOrig + 16 - ((long)p->ImageDataOrig & 15); - memset(p->myximage->data, 0, p->myximage->bytes_per_line * p->image_height); - p->ImageData = p->myximage->data; -#ifdef HAVE_SHM -} -#endif -} - -static void freeMyXImage(struct priv *p) -{ - struct vo *vo = p->vo; -#ifdef HAVE_SHM - if (p->Shmem_Flag) { - XShmDetach(vo->x11->display, &p->Shminfo[0]); - XDestroyImage(p->myximage); - shmdt(p->Shminfo[0].shmaddr); - } else -#endif - { - p->myximage->data = p->ImageDataOrig; - XDestroyImage(p->myximage); - p->ImageDataOrig = NULL; - } - p->myximage = NULL; - p->ImageData = NULL; -} - -#if BYTE_ORDER == BIG_ENDIAN -#define BO_NATIVE MSBFirst -#define BO_NONNATIVE LSBFirst -#else -#define BO_NATIVE LSBFirst -#define BO_NONNATIVE MSBFirst -#endif -const struct fmt2Xfmtentry_s { - uint32_t mpfmt; - int byte_order; - unsigned red_mask; - unsigned green_mask; - unsigned blue_mask; -} fmt2Xfmt[] = { - {IMGFMT_RGB8, BO_NATIVE, 0x00000007, 0x00000038, 0x000000C0}, - {IMGFMT_RGB8, BO_NONNATIVE, 0x00000007, 0x00000038, 0x000000C0}, - {IMGFMT_BGR8, BO_NATIVE, 0x000000E0, 0x0000001C, 0x00000003}, - {IMGFMT_BGR8, BO_NONNATIVE, 0x000000E0, 0x0000001C, 0x00000003}, - {IMGFMT_RGB15, BO_NATIVE, 0x0000001F, 0x000003E0, 0x00007C00}, - {IMGFMT_BGR15, BO_NATIVE, 0x00007C00, 0x000003E0, 0x0000001F}, - {IMGFMT_RGB16, BO_NATIVE, 0x0000001F, 0x000007E0, 0x0000F800}, - {IMGFMT_BGR16, BO_NATIVE, 0x0000F800, 0x000007E0, 0x0000001F}, - {IMGFMT_RGB24, MSBFirst, 0x00FF0000, 0x0000FF00, 0x000000FF}, - {IMGFMT_RGB24, LSBFirst, 0x000000FF, 0x0000FF00, 0x00FF0000}, - {IMGFMT_BGR24, MSBFirst, 0x000000FF, 0x0000FF00, 0x00FF0000}, - {IMGFMT_BGR24, LSBFirst, 0x00FF0000, 0x0000FF00, 0x000000FF}, - {IMGFMT_RGB32, BO_NATIVE, 0x000000FF, 0x0000FF00, 0x00FF0000}, - {IMGFMT_RGB32, BO_NONNATIVE, 0xFF000000, 0x00FF0000, 0x0000FF00}, - {IMGFMT_BGR32, BO_NATIVE, 0x00FF0000, 0x0000FF00, 0x000000FF}, - {IMGFMT_BGR32, BO_NONNATIVE, 0x0000FF00, 0x00FF0000, 0xFF000000}, - {IMGFMT_ARGB, MSBFirst, 0x00FF0000, 0x0000FF00, 0x000000FF}, - {IMGFMT_ARGB, LSBFirst, 0x0000FF00, 0x00FF0000, 0xFF000000}, - {IMGFMT_ABGR, MSBFirst, 0x000000FF, 0x0000FF00, 0x00FF0000}, - {IMGFMT_ABGR, LSBFirst, 0xFF000000, 0x00FF0000, 0x0000FF00}, - {IMGFMT_RGBA, MSBFirst, 0xFF000000, 0x00FF0000, 0x0000FF00}, - {IMGFMT_RGBA, LSBFirst, 0x000000FF, 0x0000FF00, 0x00FF0000}, - {IMGFMT_BGRA, MSBFirst, 0x0000FF00, 0x00FF0000, 0xFF000000}, - {IMGFMT_BGRA, LSBFirst, 0x00FF0000, 0x0000FF00, 0x000000FF}, - {0} -}; - -static int config(struct vo *vo, uint32_t width, uint32_t height, - uint32_t d_width, uint32_t d_height, uint32_t flags, - uint32_t format) -{ - struct priv *p = vo->priv; - - Colormap theCmap; - const struct fmt2Xfmtentry_s *fmte = fmt2Xfmt; - -#ifdef CONFIG_XF86VM - int vm = flags & VOFLAG_MODESWITCHING; -#endif - p->Flip_Flag = flags & VOFLAG_FLIPPING; - p->zoomFlag = flags & VOFLAG_SWSCALE; - - p->old_vo_dwidth = -1; - p->old_vo_dheight = -1; - - p->in_format = format; - p->srcW = width; - p->srcH = height; - - XGetWindowAttributes(vo->x11->display, vo->x11->rootwin, &p->attribs); - p->depth = p->attribs.depth; - - if (p->depth != 15 && p->depth != 16 && p->depth != 24 && p->depth != 32) { - Visual *visual; - - p->depth = vo_find_depth_from_visuals(vo->x11->display, vo->x11->screen, - &visual); - } - if (!XMatchVisualInfo(vo->x11->display, vo->x11->screen, p->depth, - DirectColor, &p->vinfo) - || (WinID > 0 - && p->vinfo.visualid != XVisualIDFromVisual(p->attribs.visual))) - { - XMatchVisualInfo(vo->x11->display, vo->x11->screen, p->depth, TrueColor, - &p->vinfo); - } - - /* set image size (which is indeed neither the input nor output size), - if zoom is on it will be changed during draw_slice anyway so we don't - duplicate the aspect code here - */ - p->image_width = (width + 7) & (~7); - p->image_height = height; - - { -#ifdef CONFIG_XF86VM - if (vm) - vo_vm_switch(vo); - -#endif - theCmap = vo_x11_create_colormap(vo, &p->vinfo); - - vo_x11_create_vo_window(vo, &p->vinfo, vo->dx, vo->dy, vo->dwidth, - vo->dheight, flags, theCmap, "x11"); - if (WinID > 0) - p->depth = vo_x11_update_geometry(vo, true); - -#ifdef CONFIG_XF86VM - if (vm) { - /* Grab the mouse pointer in our window */ - if (vo_grabpointer) - XGrabPointer(vo->x11->display, vo->x11->window, True, 0, - GrabModeAsync, GrabModeAsync, - vo->x11->window, None, CurrentTime); - XSetInputFocus(vo->x11->display, vo->x11->window, RevertToNone, - CurrentTime); - } -#endif - } - - if (p->myximage) { - freeMyXImage(p); - sws_freeContext(p->swsContext); - } - getMyXImage(p); - - while (fmte->mpfmt) { - int depth = IMGFMT_RGB_DEPTH(fmte->mpfmt); - /* bits_per_pixel in X seems to be set to 16 for 15 bit formats - => force depth to 16 so that only the color masks are used for the format check */ - if (depth == 15) - depth = 16; - - if (depth == p->myximage->bits_per_pixel && - fmte->byte_order == p->myximage->byte_order && - fmte->red_mask == p->myximage->red_mask && - fmte->green_mask == p->myximage->green_mask && - fmte->blue_mask == p->myximage->blue_mask) - break; - fmte++; - } - if (!fmte->mpfmt) { - mp_msg( - MSGT_VO, MSGL_ERR, - "X server image format not supported, please contact the developers\n"); - return -1; - } - p->out_format = fmte->mpfmt; - p->bpp = p->myximage->bits_per_pixel; - p->out_offset = 0; - // We can easily "emulate" non-native RGB32 and BGR32 - if (p->out_format == (IMGFMT_BGR32 | 128) - || p->out_format == (IMGFMT_RGB32 | 128)) - { - p->out_format &= ~128; -#if BYTE_ORDER == BIG_ENDIAN - p->out_offset = 1; -#else - p->out_offset = -1; -#endif - } - - /* always allocate swsContext as size could change between frames */ - p->swsContext = sws_getContextFromCmdLine(width, height, p->in_format, - width, height, p->out_format); - if (!p->swsContext) - return -1; - - p->dst_width = width; - - return 0; -} - -static void Display_Image(struct priv *p, XImage *myximage, uint8_t *ImageData) -{ - struct vo *vo = p->vo; - - int x = (vo->dwidth - p->dst_width) / 2; - int y = (vo->dheight - p->myximage->height) / 2; - - // do not draw if the image needs rescaling - if ((p->old_vo_dwidth != vo->dwidth || - p->old_vo_dheight != vo->dheight) && p->zoomFlag) - return; - - if (WinID == 0) { - x = vo->dx; - y = vo->dy; - } - p->myximage->data += p->out_offset; -#ifdef HAVE_SHM - if (p->Shmem_Flag) { - XShmPutImage(vo->x11->display, vo->x11->window, vo->x11->vo_gc, - p->myximage, 0, 0, x, y, p->dst_width, p->myximage->height, - True); - } else -#endif - { - XPutImage(vo->x11->display, vo->x11->window, vo->x11->vo_gc, - p->myximage, 0, 0, x, y, p->dst_width, p->myximage->height); - } - p->myximage->data -= p->out_offset; -} - -static struct mp_image get_x_buffer(struct priv *p) -{ - struct mp_image img = {0}; - img.w = img.width = p->image_width; - img.h = img.height = p->image_height; - mp_image_setfmt(&img, p->out_format); - - img.planes[0] = p->ImageData; - img.stride[0] = p->image_width * ((p->bpp + 7) / 8); - - return img; -} - -static void draw_osd(struct vo *vo, struct osd_state *osd) -{ - struct priv *p = vo->priv; - - struct mp_image img = get_x_buffer(p); - - struct mp_osd_res res = { - .w = img.w, - .h = img.h, - .display_par = vo->monitor_par, - .video_par = vo->aspdat.par, - }; - - osd_draw_on_image(osd, res, osd->vo_pts, 0, &img); -} - -static void flip_page(struct vo *vo) -{ - struct priv *p = vo->priv; - Display_Image(p, p->myximage, p->ImageData); - XSync(vo->x11->display, False); -} - -static int draw_slice(struct vo *vo, uint8_t *src[], int stride[], int w, int h, - int x, int y) -{ - struct priv *p = vo->priv; - uint8_t *dst[MP_MAX_PLANES] = {NULL}; - int dstStride[MP_MAX_PLANES] = {0}; - - if ((p->old_vo_dwidth != vo->dwidth || p->old_vo_dheight != vo->dheight) - /*&& y==0 */ && p->zoomFlag) - { - int newW = vo->dwidth; - int newH = vo->dheight; - struct SwsContext *oldContext = p->swsContext; - - p->old_vo_dwidth = vo->dwidth; - p->old_vo_dheight = vo->dheight; - - if (vo_fs) - aspect(vo, &newW, &newH, A_ZOOM); - if (sws_flags == 0) - newW &= (~31); // not needed but, if the user wants the FAST_BILINEAR SCALER, then its needed - - p->swsContext - = sws_getContextFromCmdLine(p->srcW, p->srcH, p->in_format, newW, - newH, p->out_format); - if (p->swsContext) { - p->image_width = (newW + 7) & (~7); - p->image_height = newH; - - freeMyXImage(p); - getMyXImage(p); - sws_freeContext(oldContext); - } else - p->swsContext = oldContext; - p->dst_width = newW; - } - - dstStride[0] = p->image_width * ((p->bpp + 7) / 8); - dst[0] = p->ImageData; - if (p->Flip_Flag) { - dst[0] += dstStride[0] * (p->image_height - 1); - dstStride[0] = -dstStride[0]; - } - sws_scale(p->swsContext, (const uint8_t **)src, stride, y, h, dst, - dstStride); - return 0; -} - -static int query_format(struct vo *vo, uint32_t format) -{ - mp_msg(MSGT_VO, MSGL_DBG2, - "vo_x11: query_format was called: %x (%s)\n", format, - vo_format_name(format)); - if (IMGFMT_IS_BGR(format)) { - if (IMGFMT_BGR_DEPTH(format) <= 8) - return 0; // TODO 8bpp not yet fully implemented - if (IMGFMT_BGR_DEPTH(format) == vo->x11->depthonscreen) - return VFCAP_CSP_SUPPORTED | VFCAP_CSP_SUPPORTED_BY_HW | - VFCAP_OSD | VFCAP_SWSCALE | VFCAP_FLIP | - VFCAP_ACCEPT_STRIDE; - else - return VFCAP_CSP_SUPPORTED | VFCAP_OSD | VFCAP_SWSCALE | - VFCAP_FLIP | - VFCAP_ACCEPT_STRIDE; - } - - switch (format) { - case IMGFMT_I420: - case IMGFMT_IYUV: - case IMGFMT_YV12: - return VFCAP_CSP_SUPPORTED | VFCAP_OSD | VFCAP_SWSCALE | - VFCAP_ACCEPT_STRIDE; - } - return 0; -} - - -static void uninit(struct vo *vo) -{ - struct priv *p = vo->priv; - if (p->myximage) - freeMyXImage(p); - -#ifdef CONFIG_XF86VM - vo_vm_close(vo); -#endif - - p->zoomFlag = 0; - vo_x11_uninit(vo); - - sws_freeContext(p->swsContext); -} - -static int preinit(struct vo *vo, const char *arg) -{ - struct priv *p = vo->priv; - p->vo = vo; - - if (arg) { - mp_msg(MSGT_VO, MSGL_ERR, "vo_x11: Unknown subdevice: %s\n", arg); - return ENOSYS; - } - - if (!vo_init(vo)) - return -1; // Can't open X11 - return 0; -} - -static int control(struct vo *vo, uint32_t request, void *data) -{ - struct priv *p = vo->priv; - switch (request) { - case VOCTRL_PAUSE: - return p->int_pause = 1; - case VOCTRL_RESUME: - return p->int_pause = 0; - case VOCTRL_QUERY_FORMAT: - return query_format(vo, *((uint32_t *) data)); - case VOCTRL_FULLSCREEN: - vo_x11_fullscreen(vo); - vo_x11_clearwindow(vo, vo->x11->window); - return VO_TRUE; - case VOCTRL_SET_EQUALIZER: - { - struct voctrl_set_equalizer_args *args = data; - return vo_x11_set_equalizer(vo, args->name, args->value); - } - case VOCTRL_GET_EQUALIZER: - { - struct voctrl_get_equalizer_args *args = data; - return vo_x11_get_equalizer(args->name, args->valueptr); - } - case VOCTRL_ONTOP: - vo_x11_ontop(vo); - return VO_TRUE; - case VOCTRL_UPDATE_SCREENINFO: - update_xinerama_info(vo); - return VO_TRUE; - } - return VO_NOTIMPL; -} - -const struct vo_driver video_out_x11 = { - .is_new = false, - .info = &(const vo_info_t) { - "X11 ( XImage/Shm )", - "x11", - "Aaron Holtzman <aholtzma@ess.engr.uvic.ca>", - "" - }, - .priv_size = sizeof(struct priv), - .priv_defaults = &(const struct priv) { - .srcW = -1, - .srcH = -1, - .old_vo_dwidth = -1, - .old_vo_dheight = -1, -#ifdef HAVE_SHM - .CompletionType = -1, -#endif - }, - .preinit = preinit, - .config = config, - .control = control, - .draw_slice = draw_slice, - .draw_osd = draw_osd, - .flip_page = flip_page, - .check_events = check_events, - .uninit = uninit, -}; diff --git a/libvo/vo_xv.c b/libvo/vo_xv.c deleted file mode 100644 index 3673764ed4..0000000000 --- a/libvo/vo_xv.c +++ /dev/null @@ -1,716 +0,0 @@ -/* - * X11 Xv interface - * - * 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 <stdint.h> -#include <stdbool.h> -#include <errno.h> -#include <X11/Xlib.h> -#include <X11/Xutil.h> - -#include <libavutil/common.h> - -#include "config.h" - -#ifdef HAVE_SHM -#include <sys/ipc.h> -#include <sys/shm.h> -#include <X11/extensions/XShm.h> -#endif - -// Note: depends on the inclusion of X11/extensions/XShm.h -#include <X11/extensions/Xv.h> -#include <X11/extensions/Xvlib.h> - -#include "options.h" -#include "talloc.h" -#include "mp_msg.h" -#include "video_out.h" -#include "libmpcodecs/vfcap.h" -#include "libmpcodecs/mp_image.h" -#include "x11_common.h" -#include "fastmemcpy.h" -#include "sub/sub.h" -#include "aspect.h" -#include "csputils.h" -#include "subopt-helper.h" - -static const vo_info_t info = { - "X11/Xv", - "xv", - "Gerd Knorr <kraxel@goldbach.in-berlin.de> and others", - "" -}; - -struct xvctx { - XvAdaptorInfo *ai; - XvImageFormatValues *fo; - unsigned int formats, adaptors, xv_format; - int current_buf; - int current_ip_buf; - int num_buffers; - int total_buffers; - bool have_image_copy; - bool unchanged_image; - int visible_buf; - XvImage *xvimage[2 + 1]; - uint32_t image_width; - uint32_t image_height; - uint32_t image_format; - struct mp_csp_details cached_csp; - int is_paused; - struct mp_rect src_rect; - struct mp_rect dst_rect; - uint32_t max_width, max_height; // zero means: not set - int mode_switched; -#ifdef HAVE_SHM - XShmSegmentInfo Shminfo[2 + 1]; - int Shmem_Flag; -#endif -}; - -static void allocate_xvimage(struct vo *, int); -static void deallocate_xvimage(struct vo *vo, int foo); - -static void read_xv_csp(struct vo *vo) -{ - struct xvctx *ctx = vo->priv; - struct vo_x11_state *x11 = vo->x11; - struct mp_csp_details *cspc = &ctx->cached_csp; - *cspc = (struct mp_csp_details) MP_CSP_DETAILS_DEFAULTS; - int bt709_enabled; - if (vo_xv_get_eq(vo, x11->xv_port, "bt_709", &bt709_enabled)) - cspc->format = bt709_enabled == 100 ? MP_CSP_BT_709 : MP_CSP_BT_601; -} - -static void resize(struct vo *vo) -{ - struct xvctx *ctx = vo->priv; - - // Can't be used, because the function calculates screen-space coordinates, - // while we need video-space. - struct mp_osd_res unused; - - vo_get_src_dst_rects(vo, &ctx->src_rect, &ctx->dst_rect, &unused); - - struct mp_rect *dst = &ctx->dst_rect; - int dw = dst->x1 - dst->x0, dh = dst->y1 - dst->y0; - vo_x11_clearwindow_part(vo, vo->x11->window, dw, dh); - vo_xv_draw_colorkey(vo, dst->x0, dst->y0, dw, dh); - read_xv_csp(vo); -} - -/* - * connect to server, create and map window, - * allocate colors and (shared) memory - */ -static int config(struct vo *vo, uint32_t width, uint32_t height, - uint32_t d_width, uint32_t d_height, uint32_t flags, - uint32_t format) -{ - struct vo_x11_state *x11 = vo->x11; - XVisualInfo vinfo; - XSetWindowAttributes xswa; - XWindowAttributes attribs; - unsigned long xswamask; - int depth; - struct xvctx *ctx = vo->priv; - int i; - - ctx->image_height = height; - ctx->image_width = width; - ctx->image_format = format; - - if ((ctx->max_width != 0 && ctx->max_height != 0) - && (ctx->image_width > ctx->max_width - || ctx->image_height > ctx->max_height)) { - mp_tmsg(MSGT_VO, MSGL_ERR, "Source image dimensions are too high: %ux%u (maximum is %ux%u)\n", - ctx->image_width, ctx->image_height, ctx->max_width, - ctx->max_height); - return -1; - } - - ctx->visible_buf = -1; - ctx->have_image_copy = false; - - /* check image formats */ - ctx->xv_format = 0; - for (i = 0; i < ctx->formats; i++) { - mp_msg(MSGT_VO, MSGL_V, "Xvideo image format: 0x%x (%4.4s) %s\n", - ctx->fo[i].id, (char *) &ctx->fo[i].id, - (ctx->fo[i].format == XvPacked) ? "packed" : "planar"); - if (ctx->fo[i].id == format) - ctx->xv_format = ctx->fo[i].id; - } - if (!ctx->xv_format) - return -1; - - { -#ifdef CONFIG_XF86VM - int vm = flags & VOFLAG_MODESWITCHING; - if (vm) { - vo_vm_switch(vo); - ctx->mode_switched = 1; - } -#endif - XGetWindowAttributes(x11->display, DefaultRootWindow(x11->display), - &attribs); - depth = attribs.depth; - if (depth != 15 && depth != 16 && depth != 24 && depth != 32) - depth = 24; - XMatchVisualInfo(x11->display, x11->screen, depth, TrueColor, &vinfo); - - xswa.border_pixel = 0; - xswamask = CWBorderPixel; - if (x11->xv_ck_info.method == CK_METHOD_BACKGROUND) { - xswa.background_pixel = x11->xv_colorkey; - xswamask |= CWBackPixel; - } - - vo_x11_create_vo_window(vo, &vinfo, vo->dx, vo->dy, vo->dwidth, - vo->dheight, flags, CopyFromParent, "xv"); - XChangeWindowAttributes(x11->display, x11->window, xswamask, &xswa); - -#ifdef CONFIG_XF86VM - if (vm) { - /* Grab the mouse pointer in our window */ - if (vo_grabpointer) - XGrabPointer(x11->display, x11->window, True, 0, GrabModeAsync, - GrabModeAsync, x11->window, None, CurrentTime); - XSetInputFocus(x11->display, x11->window, RevertToNone, - CurrentTime); - } -#endif - } - - mp_msg(MSGT_VO, MSGL_V, "using Xvideo port %d for hw scaling\n", - x11->xv_port); - - // In case config has been called before - for (i = 0; i < ctx->total_buffers; i++) - deallocate_xvimage(vo, i); - - ctx->num_buffers = 2; - ctx->total_buffers = ctx->num_buffers + 1; - - for (i = 0; i < ctx->total_buffers; i++) - allocate_xvimage(vo, i); - - ctx->current_buf = 0; - ctx->current_ip_buf = 0; - - - resize(vo); - - return 0; -} - -static void allocate_xvimage(struct vo *vo, int foo) -{ - struct xvctx *ctx = vo->priv; - struct vo_x11_state *x11 = vo->x11; - /* - * allocate XvImages. FIXME: no error checking, without - * mit-shm this will bomb... trzing to fix ::atmos - */ -#ifdef HAVE_SHM - if (x11->display_is_local && XShmQueryExtension(x11->display)) - ctx->Shmem_Flag = 1; - else { - ctx->Shmem_Flag = 0; - mp_tmsg(MSGT_VO, MSGL_INFO, "[VO_XV] Shared memory not supported\nReverting to normal Xv.\n"); - } - if (ctx->Shmem_Flag) { - ctx->xvimage[foo] = - (XvImage *) XvShmCreateImage(x11->display, x11->xv_port, - ctx->xv_format, NULL, - ctx->image_width, ctx->image_height, - &ctx->Shminfo[foo]); - - ctx->Shminfo[foo].shmid = shmget(IPC_PRIVATE, - ctx->xvimage[foo]->data_size, - IPC_CREAT | 0777); - ctx->Shminfo[foo].shmaddr = (char *) shmat(ctx->Shminfo[foo].shmid, 0, - 0); - ctx->Shminfo[foo].readOnly = False; - - ctx->xvimage[foo]->data = ctx->Shminfo[foo].shmaddr; - XShmAttach(x11->display, &ctx->Shminfo[foo]); - XSync(x11->display, False); - shmctl(ctx->Shminfo[foo].shmid, IPC_RMID, 0); - } else -#endif - { - ctx->xvimage[foo] = - (XvImage *) XvCreateImage(x11->display, x11->xv_port, - ctx->xv_format, NULL, ctx->image_width, - ctx->image_height); - ctx->xvimage[foo]->data = malloc(ctx->xvimage[foo]->data_size); - XSync(x11->display, False); - } - memset(ctx->xvimage[foo]->data, 128, ctx->xvimage[foo]->data_size); - return; -} - -static void deallocate_xvimage(struct vo *vo, int foo) -{ - struct xvctx *ctx = vo->priv; -#ifdef HAVE_SHM - if (ctx->Shmem_Flag) { - XShmDetach(vo->x11->display, &ctx->Shminfo[foo]); - shmdt(ctx->Shminfo[foo].shmaddr); - } else -#endif - { - free(ctx->xvimage[foo]->data); - } - XFree(ctx->xvimage[foo]); - - XSync(vo->x11->display, False); - return; -} - -static inline void put_xvimage(struct vo *vo, XvImage *xvi) -{ - struct xvctx *ctx = vo->priv; - struct vo_x11_state *x11 = vo->x11; - struct mp_rect *src = &ctx->src_rect; - struct mp_rect *dst = &ctx->dst_rect; - int dw = dst->x1 - dst->x0, dh = dst->y1 - dst->y0; - int sw = src->x1 - src->x0, sh = src->y1 - src->y0; -#ifdef HAVE_SHM - if (ctx->Shmem_Flag) { - XvShmPutImage(x11->display, x11->xv_port, x11->window, x11->vo_gc, xvi, - src->x0, src->y0, sw, sh, - dst->x0, dst->y0, dw, dh, - False); - } else -#endif - { - XvPutImage(x11->display, x11->xv_port, x11->window, x11->vo_gc, xvi, - src->x0, src->y0, sw, sh, - dst->x0, dst->y0, dw, dh); - } -} - -static struct mp_image get_xv_buffer(struct vo *vo, int buf_index) -{ - struct xvctx *ctx = vo->priv; - XvImage *xv_image = ctx->xvimage[buf_index]; - - struct mp_image img = {0}; - img.w = img.width = xv_image->width; - img.h = img.height = xv_image->height; - mp_image_setfmt(&img, ctx->image_format); - - bool swapuv = ctx->image_format == IMGFMT_YV12; - for (int n = 0; n < img.num_planes; n++) { - int sn = n > 0 && swapuv ? (n == 1 ? 2 : 1) : n; - img.planes[n] = xv_image->data + xv_image->offsets[sn]; - img.stride[n] = xv_image->pitches[sn]; - } - - mp_image_set_colorspace_details(&img, &ctx->cached_csp); - - return img; -} - -static void copy_backup_image(struct vo *vo, int dest, int src) -{ - struct mp_image img_dest = get_xv_buffer(vo, dest); - struct mp_image img_src = get_xv_buffer(vo, src); - - copy_mpi(&img_dest, &img_src); -} - -static void check_events(struct vo *vo) -{ - int e = vo_x11_check_events(vo); - - if (e & VO_EVENT_EXPOSE || e & VO_EVENT_RESIZE) { - resize(vo); - vo->want_redraw = true; - } -} - -static void draw_osd(struct vo *vo, struct osd_state *osd) -{ - struct xvctx *ctx = vo->priv; - - struct mp_image img = get_xv_buffer(vo, ctx->current_buf); - - struct mp_rect *src = &ctx->src_rect; - struct mp_rect *dst = &ctx->dst_rect; - int dw = dst->x1 - dst->x0, dh = dst->y1 - dst->y0; - int sw = src->x1 - src->x0, sh = src->y1 - src->y0; - double xvpar = (double)dw / dh * sh / sw; - - struct mp_osd_res res = { - .w = ctx->image_width, - .h = ctx->image_height, - .display_par = vo->monitor_par / xvpar, - .video_par = vo->aspdat.par, - }; - - if (osd_draw_on_image(osd, res, osd->vo_pts, 0, &img)) - ctx->unchanged_image = false; -} - -static int redraw_frame(struct vo *vo) -{ - struct xvctx *ctx = vo->priv; - - if (ctx->have_image_copy) - copy_backup_image(vo, ctx->visible_buf, ctx->num_buffers); - else if (ctx->unchanged_image) { - copy_backup_image(vo, ctx->num_buffers, ctx->visible_buf); - ctx->have_image_copy = true; - } else - return false; - ctx->current_buf = ctx->visible_buf; - return true; -} - -static void flip_page(struct vo *vo) -{ - struct xvctx *ctx = vo->priv; - put_xvimage(vo, ctx->xvimage[ctx->current_buf]); - - /* remember the currently visible buffer */ - ctx->visible_buf = ctx->current_buf; - - ctx->current_buf = (ctx->current_buf + 1) % ctx->num_buffers; - XFlush(vo->x11->display); - return; -} - -static int draw_slice(struct vo *vo, uint8_t *image[], int stride[], int w, - int h, int x, int y) -{ - struct xvctx *ctx = vo->priv; - uint8_t *dst; - XvImage *current_image = ctx->xvimage[ctx->current_buf]; - - dst = current_image->data + current_image->offsets[0] - + current_image->pitches[0] * y + x; - memcpy_pic(dst, image[0], w, h, current_image->pitches[0], stride[0]); - - x /= 2; - y /= 2; - w /= 2; - h /= 2; - - dst = current_image->data + current_image->offsets[1] - + current_image->pitches[1] * y + x; - if (ctx->image_format != IMGFMT_YV12) - memcpy_pic(dst, image[1], w, h, current_image->pitches[1], stride[1]); - else - memcpy_pic(dst, image[2], w, h, current_image->pitches[1], stride[2]); - - dst = current_image->data + current_image->offsets[2] - + current_image->pitches[2] * y + x; - if (ctx->image_format == IMGFMT_YV12) - memcpy_pic(dst, image[1], w, h, current_image->pitches[1], stride[1]); - else - memcpy_pic(dst, image[2], w, h, current_image->pitches[1], stride[2]); - - return 0; -} - -static mp_image_t *get_screenshot(struct vo *vo) -{ - struct xvctx *ctx = vo->priv; - - // try to get an image without OSD - int id = ctx->have_image_copy ? ctx->num_buffers : ctx->visible_buf; - struct mp_image img = get_xv_buffer(vo, id); - img.display_w = vo->aspdat.prew; - img.display_h = vo->aspdat.preh; - - return talloc_memdup(NULL, &img, sizeof(img)); -} - -static uint32_t draw_image(struct vo *vo, mp_image_t *mpi) -{ - struct xvctx *ctx = vo->priv; - - ctx->have_image_copy = false; - - if (mpi->flags & MP_IMGFLAG_DRAW_CALLBACK) - ; // done - else if (mpi->flags & MP_IMGFLAG_PLANAR) - draw_slice(vo, mpi->planes, mpi->stride, mpi->w, mpi->h, 0, 0); - else if (mpi->flags & MP_IMGFLAG_YUV) - // packed YUV: - memcpy_pic(ctx->xvimage[ctx->current_buf]->data + - ctx->xvimage[ctx->current_buf]->offsets[0], mpi->planes[0], - mpi->w * (mpi->bpp / 8), mpi->h, - ctx->xvimage[ctx->current_buf]->pitches[0], mpi->stride[0]); - else - return false; - - if (ctx->is_paused) { - copy_backup_image(vo, ctx->num_buffers, ctx->current_buf); - ctx->have_image_copy = true; - } - ctx->unchanged_image = true; - return true; -} - -static int query_format(struct xvctx *ctx, uint32_t format) -{ - uint32_t i; - int flag = VFCAP_CSP_SUPPORTED | VFCAP_CSP_SUPPORTED_BY_HW | VFCAP_HWSCALE_UP | VFCAP_HWSCALE_DOWN | VFCAP_OSD | VFCAP_ACCEPT_STRIDE; // FIXME! check for DOWN - - /* check image formats */ - for (i = 0; i < ctx->formats; i++) { - if (ctx->fo[i].id == format) - return flag; //xv_format = fo[i].id; - } - return 0; -} - -static void uninit(struct vo *vo) -{ - struct xvctx *ctx = vo->priv; - int i; - - ctx->visible_buf = -1; - if (ctx->ai) - XvFreeAdaptorInfo(ctx->ai); - ctx->ai = NULL; - if (ctx->fo) { - XFree(ctx->fo); - ctx->fo = NULL; - } - for (i = 0; i < ctx->total_buffers; i++) - deallocate_xvimage(vo, i); -#ifdef CONFIG_XF86VM - if (ctx->mode_switched) - vo_vm_close(vo); -#endif - // uninit() shouldn't get called unless initialization went past vo_init() - vo_x11_uninit(vo); -} - -static int preinit(struct vo *vo, const char *arg) -{ - XvPortID xv_p; - int busy_ports = 0; - unsigned int i; - strarg_t ck_src_arg = { 0, NULL }; - strarg_t ck_method_arg = { 0, NULL }; - struct xvctx *ctx = talloc_zero(vo, struct xvctx); - vo->priv = ctx; - int xv_adaptor = -1; - - if (!vo_init(vo)) - return -1; - - struct vo_x11_state *x11 = vo->x11; - - const opt_t subopts[] = - { - /* name arg type arg var test */ - { "port", OPT_ARG_INT, &x11->xv_port, int_pos }, - { "adaptor", OPT_ARG_INT, &xv_adaptor, int_non_neg }, - { "ck", OPT_ARG_STR, &ck_src_arg, xv_test_ck }, - { "ck-method", OPT_ARG_STR, &ck_method_arg, xv_test_ckm }, - { NULL } - }; - - x11->xv_port = 0; - - /* parse suboptions */ - if (subopt_parse(arg, subopts) != 0) { - return -1; - } - - /* modify colorkey settings according to the given options */ - xv_setup_colorkeyhandling(vo, ck_method_arg.str, ck_src_arg.str); - - /* check for Xvideo extension */ - unsigned int ver, rel, req, ev, err; - if (Success != XvQueryExtension(x11->display, &ver, &rel, &req, &ev, &err)) { - mp_tmsg(MSGT_VO, MSGL_ERR, "[VO_XV] Sorry, Xv not supported by this X11 version/driver\n[VO_XV] ******** Try with -vo x11 *********\n"); - goto error; - } - - /* check for Xvideo support */ - if (Success != - XvQueryAdaptors(x11->display, DefaultRootWindow(x11->display), - &ctx->adaptors, &ctx->ai)) { - mp_tmsg(MSGT_VO, MSGL_ERR, "[VO_XV] XvQueryAdaptors failed.\n"); - goto error; - } - - /* check adaptors */ - if (x11->xv_port) { - int port_found; - - for (port_found = 0, i = 0; !port_found && i < ctx->adaptors; i++) { - if ((ctx->ai[i].type & XvInputMask) - && (ctx->ai[i].type & XvImageMask)) { - for (xv_p = ctx->ai[i].base_id; - xv_p < ctx->ai[i].base_id + ctx->ai[i].num_ports; - ++xv_p) { - if (xv_p == x11->xv_port) { - port_found = 1; - break; - } - } - } - } - if (port_found) { - if (XvGrabPort(x11->display, x11->xv_port, CurrentTime)) - x11->xv_port = 0; - } else { - mp_tmsg(MSGT_VO, MSGL_WARN, "[VO_XV] Invalid port parameter, overriding with port 0.\n"); - x11->xv_port = 0; - } - } - - for (i = 0; i < ctx->adaptors && x11->xv_port == 0; i++) { - /* check if adaptor number has been specified */ - if (xv_adaptor != -1 && xv_adaptor != i) - continue; - - if ((ctx->ai[i].type & XvInputMask) && (ctx->ai[i].type & XvImageMask)) { - for (xv_p = ctx->ai[i].base_id; - xv_p < ctx->ai[i].base_id + ctx->ai[i].num_ports; ++xv_p) - if (!XvGrabPort(x11->display, xv_p, CurrentTime)) { - x11->xv_port = xv_p; - mp_msg(MSGT_VO, MSGL_V, - "[VO_XV] Using Xv Adapter #%d (%s)\n", - i, ctx->ai[i].name); - break; - } else { - mp_tmsg(MSGT_VO, MSGL_WARN, "[VO_XV] Could not grab port %i.\n", - (int) xv_p); - ++busy_ports; - } - } - } - if (!x11->xv_port) { - if (busy_ports) - mp_tmsg(MSGT_VO, MSGL_ERR, - "[VO_XV] Could not find free Xvideo port - maybe another process is already\n"\ - "[VO_XV] using it. Close all video applications, and try again. If that does\n"\ - "[VO_XV] not help, see 'mpv -vo help' for other (non-xv) video out drivers.\n"); - else - mp_tmsg(MSGT_VO, MSGL_ERR, - "[VO_XV] It seems there is no Xvideo support for your video card available.\n"\ - "[VO_XV] Run 'xvinfo' to verify its Xv support and read\n"\ - "[VO_XV] DOCS/HTML/en/video.html#xv!\n"\ - "[VO_XV] See 'mpv -vo help' for other (non-xv) video out drivers.\n"\ - "[VO_XV] Try -vo x11.\n"); - goto error; - } - - if (!vo_xv_init_colorkey(vo)) { - goto error; // bail out, colorkey setup failed - } - vo_xv_enable_vsync(vo); - vo_xv_get_max_img_dim(vo, &ctx->max_width, &ctx->max_height); - - ctx->fo = XvListImageFormats(x11->display, x11->xv_port, - (int *) &ctx->formats); - - return 0; - - error: - uninit(vo); // free resources - return -1; -} - -static int control(struct vo *vo, uint32_t request, void *data) -{ - struct xvctx *ctx = vo->priv; - struct vo_x11_state *x11 = vo->x11; - switch (request) { - case VOCTRL_PAUSE: - return (ctx->is_paused = 1); - case VOCTRL_RESUME: - return (ctx->is_paused = 0); - case VOCTRL_QUERY_FORMAT: - return query_format(ctx, *((uint32_t *) data)); - case VOCTRL_DRAW_IMAGE: - return draw_image(vo, data); - case VOCTRL_GET_PANSCAN: - return VO_TRUE; - case VOCTRL_FULLSCREEN: - vo_x11_fullscreen(vo); - /* indended, fallthrough to update panscan on fullscreen/windowed switch */ - case VOCTRL_SET_PANSCAN: - resize(vo); - return VO_TRUE; - case VOCTRL_SET_EQUALIZER: { - vo->want_redraw = true; - struct voctrl_set_equalizer_args *args = data; - return vo_xv_set_eq(vo, x11->xv_port, args->name, args->value); - } - case VOCTRL_GET_EQUALIZER: { - struct voctrl_get_equalizer_args *args = data; - return vo_xv_get_eq(vo, x11->xv_port, args->name, args->valueptr); - } - case VOCTRL_SET_YUV_COLORSPACE:; - struct mp_csp_details* given_cspc = data; - int is_709 = given_cspc->format == MP_CSP_BT_709; - vo_xv_set_eq(vo, x11->xv_port, "bt_709", is_709 * 200 - 100); - read_xv_csp(vo); - vo->want_redraw = true; - return true; - case VOCTRL_GET_YUV_COLORSPACE:; - struct mp_csp_details* cspc = data; - read_xv_csp(vo); - *cspc = ctx->cached_csp; - return true; - case VOCTRL_ONTOP: - vo_x11_ontop(vo); - return VO_TRUE; - case VOCTRL_UPDATE_SCREENINFO: - update_xinerama_info(vo); - return VO_TRUE; - case VOCTRL_REDRAW_FRAME: - return redraw_frame(vo); - case VOCTRL_SCREENSHOT: { - struct voctrl_screenshot_args *args = data; - args->out_image = get_screenshot(vo); - args->has_osd = !ctx->have_image_copy; - return true; - } - } - return VO_NOTIMPL; -} - -const struct vo_driver video_out_xv = { - .is_new = 1, - .info = &info, - .preinit = preinit, - .config = config, - .control = control, - .draw_slice = draw_slice, - .draw_osd = draw_osd, - .flip_page = flip_page, - .check_events = check_events, - .uninit = uninit -}; diff --git a/libvo/w32_common.c b/libvo/w32_common.c deleted file mode 100644 index f60f5328de..0000000000 --- a/libvo/w32_common.c +++ /dev/null @@ -1,757 +0,0 @@ -/* - * 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 <limits.h> -#include <assert.h> -#include <windows.h> -#include <windowsx.h> - -#include "options.h" -#include "input/keycodes.h" -#include "input/input.h" -#include "mp_msg.h" -#include "video_out.h" -#include "aspect.h" -#include "w32_common.h" -#include "mp_fifo.h" -#include "osdep/io.h" -#include "talloc.h" - -#define WIN_ID_TO_HWND(x) ((HWND)(uint32_t)(x)) - -static const wchar_t classname[] = L"mpv"; - -static const struct mp_keymap vk_map[] = { - // special keys - {VK_ESCAPE, KEY_ESC}, {VK_BACK, KEY_BS}, {VK_TAB, KEY_TAB}, - {VK_RETURN, KEY_ENTER}, {VK_PAUSE, KEY_PAUSE}, {VK_SNAPSHOT, KEY_PRINT}, - - // cursor keys - {VK_LEFT, KEY_LEFT}, {VK_UP, KEY_UP}, {VK_RIGHT, KEY_RIGHT}, {VK_DOWN, KEY_DOWN}, - - // navigation block - {VK_INSERT, KEY_INSERT}, {VK_DELETE, KEY_DELETE}, {VK_HOME, KEY_HOME}, {VK_END, KEY_END}, - {VK_PRIOR, KEY_PAGE_UP}, {VK_NEXT, KEY_PAGE_DOWN}, - - // F-keys - {VK_F1, KEY_F+1}, {VK_F2, KEY_F+2}, {VK_F3, KEY_F+3}, {VK_F4, KEY_F+4}, - {VK_F5, KEY_F+5}, {VK_F6, KEY_F+6}, {VK_F7, KEY_F+7}, {VK_F8, KEY_F+8}, - {VK_F9, KEY_F+9}, {VK_F10, KEY_F+10}, {VK_F11, KEY_F+11}, {VK_F12, KEY_F+12}, - // numpad - {VK_NUMPAD0, KEY_KP0}, {VK_NUMPAD1, KEY_KP1}, {VK_NUMPAD2, KEY_KP2}, - {VK_NUMPAD3, KEY_KP3}, {VK_NUMPAD4, KEY_KP4}, {VK_NUMPAD5, KEY_KP5}, - {VK_NUMPAD6, KEY_KP6}, {VK_NUMPAD7, KEY_KP7}, {VK_NUMPAD8, KEY_KP8}, - {VK_NUMPAD9, KEY_KP9}, {VK_DECIMAL, KEY_KPDEC}, - - {0, 0} -}; - -static void add_window_borders(HWND hwnd, RECT *rc) -{ - AdjustWindowRect(rc, GetWindowLong(hwnd, GWL_STYLE), 0); -} - -// basically a reverse AdjustWindowRect (win32 doesn't appear to have this) -static void subtract_window_borders(HWND hwnd, RECT *rc) -{ - RECT b = { 0, 0, 0, 0 }; - add_window_borders(hwnd, &b); - rc->left -= b.left; - rc->top -= b.top; - rc->right -= b.right; - rc->bottom -= b.bottom; -} - -// turn a WMSZ_* input value in v into the border that should be resized -// returns: 0=left, 1=top, 2=right, 3=bottom, -1=undefined -static int get_resize_border(int v) { - switch (v) { - case WMSZ_LEFT: return 3; - case WMSZ_TOP: return 2; - case WMSZ_RIGHT: return 3; - case WMSZ_BOTTOM: return 2; - case WMSZ_TOPLEFT: return 1; - case WMSZ_TOPRIGHT: return 1; - case WMSZ_BOTTOMLEFT: return 3; - case WMSZ_BOTTOMRIGHT: return 3; - default: return -1; - } -} - -static bool key_state(struct vo *vo, int vk) -{ - return GetKeyState(vk) & 0x8000; -} - -static int mod_state(struct vo *vo) -{ - int res = 0; - if (key_state(vo, VK_CONTROL)) - res |= KEY_MODIFIER_CTRL; - if (key_state(vo, VK_SHIFT)) - res |= KEY_MODIFIER_SHIFT; - if (key_state(vo, VK_MENU)) - res |= KEY_MODIFIER_ALT; - return res; -} - -static LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, - LPARAM lParam) -{ - if (message == WM_NCCREATE) { - CREATESTRUCT *cs = (void*)lParam; - SetWindowLongPtrW(hWnd, GWLP_USERDATA, (LONG_PTR)cs->lpCreateParams); - } - struct vo *vo = (void*)GetWindowLongPtrW(hWnd, GWLP_USERDATA); - // message before WM_NCCREATE, pray to Raymond Chen that it's not important - if (!vo) - return DefWindowProcW(hWnd, message, wParam, lParam); - struct vo_w32_state *w32 = vo->w32; - - switch (message) { - case WM_ERASEBKGND: // no need to erase background seperately - return 1; - case WM_PAINT: - w32->event_flags |= VO_EVENT_EXPOSE; - break; - case WM_MOVE: { - w32->event_flags |= VO_EVENT_MOVE; - POINT p = {0}; - ClientToScreen(w32->window, &p); - w32->window_x = p.x; - w32->window_y = p.y; - mp_msg(MSGT_VO, MSGL_V, "[vo] move window: %d:%d\n", - w32->window_x, w32->window_y); - break; - } - case WM_SIZE: { - w32->event_flags |= VO_EVENT_RESIZE; - RECT r; - GetClientRect(w32->window, &r); - vo->dwidth = r.right; - vo->dheight = r.bottom; - mp_msg(MSGT_VO, MSGL_V, "[vo] resize window: %d:%d\n", - vo->dwidth, vo->dheight); - break; - } - case WM_SIZING: - if (vo_keepaspect && !vo_fs && WinID < 0) { - RECT *rc = (RECT*)lParam; - // get client area of the windows if it had the rect rc - // (subtracting the window borders) - RECT r = *rc; - subtract_window_borders(w32->window, &r); - int c_w = r.right - r.left, c_h = r.bottom - r.top; - float aspect = vo->aspdat.asp; - int d_w = c_h * aspect - c_w; - int d_h = c_w / aspect - c_h; - int d_corners[4] = { d_w, d_h, -d_w, -d_h }; - int corners[4] = { rc->left, rc->top, rc->right, rc->bottom }; - int corner = get_resize_border(wParam); - if (corner >= 0) - corners[corner] -= d_corners[corner]; - *rc = (RECT) { corners[0], corners[1], corners[2], corners[3] }; - return TRUE; - } - break; - case WM_CLOSE: - mplayer_put_key(vo->key_fifo, KEY_CLOSE_WIN); - break; - case WM_SYSCOMMAND: - switch (wParam) { - case SC_SCREENSAVE: - case SC_MONITORPOWER: - mp_msg(MSGT_VO, MSGL_V, "vo: win32: killing screensaver\n"); - return 0; - } - break; - case WM_KEYDOWN: - case WM_SYSKEYDOWN: { - int mpkey = lookup_keymap_table(vk_map, wParam); - if (mpkey) - mplayer_put_key(vo->key_fifo, mpkey | mod_state(vo)); - if (wParam == VK_F10) - return 0; - break; - } - case WM_CHAR: - case WM_SYSCHAR: { - int mods = mod_state(vo); - int code = wParam; - // Windows enables Ctrl+Alt when AltGr (VK_RMENU) is pressed. - // E.g. AltGr+9 on a German keyboard would yield Ctrl+Alt+[ - // Warning: wine handles this differently. Don't test this on wine! - if (key_state(vo, VK_RMENU)) - mods &= ~(KEY_MODIFIER_CTRL | KEY_MODIFIER_ALT); - // Apparently Ctrl+A to Ctrl+Z is special cased, and produces - // character codes from 1-26. Work it around. - // Also, enter/return (including the keypad variant) and CTRL+J both - // map to wParam==10. As a workaround, check VK_RETURN to - // distinguish these two key combinations. - if ((mods & KEY_MODIFIER_CTRL) && code >= 1 && code <= 26 - && !key_state(vo, VK_RETURN)) - code = code - 1 + (mods & KEY_MODIFIER_SHIFT ? 'A' : 'a'); - if (code >= 32 && code < (1<<21)) { - mplayer_put_key(vo->key_fifo, code | mods); - // At least with Alt+char, not calling DefWindowProcW stops - // Windows from emitting a beep. - return 0; - } - break; - } - case WM_LBUTTONDOWN: - if (!vo_nomouse_input && (vo_fs || (wParam & MK_CONTROL))) { - mplayer_put_key(vo->key_fifo, MOUSE_BTN0 | mod_state(vo)); - break; - } - if (!vo_fs) { - ReleaseCapture(); - SendMessage(hWnd, WM_NCLBUTTONDOWN, HTCAPTION, 0); - return 0; - } - break; - case WM_MBUTTONDOWN: - if (!vo_nomouse_input) - mplayer_put_key(vo->key_fifo, MOUSE_BTN1 | mod_state(vo)); - break; - case WM_RBUTTONDOWN: - if (!vo_nomouse_input) - mplayer_put_key(vo->key_fifo, MOUSE_BTN2 | mod_state(vo)); - break; - case WM_MOUSEMOVE: - vo_mouse_movement(vo, GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)); - break; - case WM_MOUSEWHEEL: - if (!vo_nomouse_input) { - int x = GET_WHEEL_DELTA_WPARAM(wParam); - if (x > 0) - mplayer_put_key(vo->key_fifo, MOUSE_BTN3 | mod_state(vo)); - else - mplayer_put_key(vo->key_fifo, MOUSE_BTN4 | mod_state(vo)); - } - break; - case WM_XBUTTONDOWN: - if (!vo_nomouse_input) { - int x = HIWORD(wParam); - if (x == 1) - mplayer_put_key(vo->key_fifo, MOUSE_BTN5 | mod_state(vo)); - else // if (x == 2) - mplayer_put_key(vo->key_fifo, MOUSE_BTN6 | mod_state(vo)); - } - break; - } - - return DefWindowProcW(hWnd, message, wParam, lParam); -} - -/** - * \brief Dispatch incoming window events and handle them. - * - * This function should be placed inside libvo's function "check_events". - * - * \return int with these flags possibly set, take care to handle in the right order - * if it matters in your driver: - * - * VO_EVENT_RESIZE = The window was resized. If necessary reinit your - * driver render context accordingly. - * VO_EVENT_EXPOSE = The window was exposed. Call e.g. flip_frame() to redraw - * the window if the movie is paused. - */ -int vo_w32_check_events(struct vo *vo) -{ - struct vo_w32_state *w32 = vo->w32; - MSG msg; - w32->event_flags = 0; - while (PeekMessageW(&msg, 0, 0, 0, PM_REMOVE)) { - TranslateMessage(&msg); - DispatchMessageW(&msg); - } - if (WinID >= 0) { - BOOL res; - RECT r; - POINT p; - res = GetClientRect(w32->window, &r); - if (res && (r.right != vo->dwidth || r.bottom != vo->dheight)) { - vo->dwidth = r.right; vo->dheight = r.bottom; - w32->event_flags |= VO_EVENT_RESIZE; - } - p.x = 0; p.y = 0; - ClientToScreen(w32->window, &p); - if (p.x != w32->window_x || p.y != w32->window_y) { - w32->window_x = p.x; w32->window_y = p.y; - w32->event_flags |= VO_EVENT_MOVE; - } - res = GetClientRect(WIN_ID_TO_HWND(WinID), &r); - if (res && (r.right != vo->dwidth || r.bottom != vo->dheight)) - MoveWindow(w32->window, 0, 0, r.right, r.bottom, FALSE); - if (!IsWindow(WIN_ID_TO_HWND(WinID))) - // Window has probably been closed, e.g. due to program crash - mplayer_put_key(vo->key_fifo, KEY_CLOSE_WIN); - } - - return w32->event_flags; -} - -static BOOL CALLBACK mon_enum(HMONITOR hmon, HDC hdc, LPRECT r, LPARAM p) -{ - struct vo *vo = (void*)p; - struct vo_w32_state *w32 = vo->w32; - // this defaults to the last screen if specified number does not exist - xinerama_x = r->left; - xinerama_y = r->top; - vo->opts->vo_screenwidth = r->right - r->left; - vo->opts->vo_screenheight = r->bottom - r->top; - if (w32->mon_cnt == xinerama_screen) - return FALSE; - w32->mon_cnt++; - return TRUE; -} - -/** - * \brief Update screen information. - * - * This function should be called in libvo's "control" callback - * with parameter VOCTRL_UPDATE_SCREENINFO. - * Note that this also enables the new API where geometry and aspect - * calculations are done in video_out.c:config_video_out - * - * Global libvo variables changed: - * xinerama_x - * xinerama_y - * vo_screenwidth - * vo_screenheight - */ -void w32_update_xinerama_info(struct vo *vo) -{ - struct vo_w32_state *w32 = vo->w32; - xinerama_x = xinerama_y = 0; - if (xinerama_screen < -1) { - int tmp; - xinerama_x = GetSystemMetrics(SM_XVIRTUALSCREEN); - xinerama_y = GetSystemMetrics(SM_YVIRTUALSCREEN); - tmp = GetSystemMetrics(SM_CXVIRTUALSCREEN); - if (tmp) vo->opts->vo_screenwidth = tmp; - tmp = GetSystemMetrics(SM_CYVIRTUALSCREEN); - if (tmp) vo->opts->vo_screenheight = tmp; - } else if (xinerama_screen == -1) { - MONITORINFO mi; - HMONITOR m = MonitorFromWindow(w32->window, MONITOR_DEFAULTTOPRIMARY); - mi.cbSize = sizeof(mi); - GetMonitorInfoW(m, &mi); - xinerama_x = mi.rcMonitor.left; - xinerama_y = mi.rcMonitor.top; - vo->opts->vo_screenwidth = mi.rcMonitor.right - mi.rcMonitor.left; - vo->opts->vo_screenheight = mi.rcMonitor.bottom - mi.rcMonitor.top; - } else if (xinerama_screen > 0) { - w32->mon_cnt = 0; - EnumDisplayMonitors(NULL, NULL, mon_enum, (LONG_PTR)vo); - } - aspect_save_screenres(vo, vo->opts->vo_screenwidth, - vo->opts->vo_screenheight); -} - -static void updateScreenProperties(struct vo *vo) -{ - struct vo_w32_state *w32 = vo->w32; - DEVMODE dm; - dm.dmSize = sizeof dm; - dm.dmDriverExtra = 0; - dm.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT; - if (!EnumDisplaySettings(0, ENUM_CURRENT_SETTINGS, &dm)) { - mp_msg(MSGT_VO, MSGL_ERR, - "vo: win32: unable to enumerate display settings!\n"); - return; - } - - vo->opts->vo_screenwidth = dm.dmPelsWidth; - vo->opts->vo_screenheight = dm.dmPelsHeight; - w32->depthonscreen = dm.dmBitsPerPel; - w32_update_xinerama_info(vo); -} - -static void changeMode(struct vo *vo) -{ - struct vo_w32_state *w32 = vo->w32; - DEVMODE dm; - dm.dmSize = sizeof dm; - dm.dmDriverExtra = 0; - - dm.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT; - dm.dmBitsPerPel = w32->depthonscreen; - dm.dmPelsWidth = vo->opts->vo_screenwidth; - dm.dmPelsHeight = vo->opts->vo_screenheight; - - if (w32->vm) { - int bestMode = -1; - int bestScore = INT_MAX; - int i; - for (i = 0; EnumDisplaySettings(0, i, &dm); ++i) { - int score = (dm.dmPelsWidth - w32->o_dwidth) - * (dm.dmPelsHeight - w32->o_dheight); - if (dm.dmBitsPerPel != w32->depthonscreen - || dm.dmPelsWidth < w32->o_dwidth - || dm.dmPelsHeight < w32->o_dheight) - continue; - - if (score < bestScore) { - bestScore = score; - bestMode = i; - } - } - - if (bestMode != -1) - EnumDisplaySettings(0, bestMode, &dm); - - ChangeDisplaySettings(&dm, CDS_FULLSCREEN); - } -} - -static void resetMode(struct vo *vo) -{ - struct vo_w32_state *w32 = vo->w32; - if (w32->vm) - ChangeDisplaySettings(0, 0); -} - -static DWORD update_style(struct vo *vo, DWORD style) -{ - const DWORD NO_FRAME = WS_POPUP; - const DWORD FRAME = WS_OVERLAPPEDWINDOW | WS_SIZEBOX; - style &= ~(NO_FRAME | FRAME); - style |= (vo_border && !vo_fs) ? FRAME : NO_FRAME; - return style; -} - -// Update the window title, position, size, and border style from vo_* values. -static int reinit_window_state(struct vo *vo) -{ - struct vo_w32_state *w32 = vo->w32; - HWND layer = HWND_NOTOPMOST; - RECT r; - - if (WinID >= 0) - return 1; - - wchar_t *title = mp_from_utf8(NULL, vo_get_window_title(vo)); - SetWindowTextW(w32->window, title); - talloc_free(title); - - bool toggle_fs = w32->current_fs != vo_fs; - w32->current_fs = vo_fs; - - DWORD style = update_style(vo, GetWindowLong(w32->window, GWL_STYLE)); - - if (vo_fs || vo->opts->vo_ontop) - layer = HWND_TOPMOST; - - // xxx not sure if this can trigger any unwanted messages (WM_MOVE/WM_SIZE) - if (vo_fs) { - changeMode(vo); - while (ShowCursor(0) >= 0) /**/ ; - } else { - resetMode(vo); - while (ShowCursor(1) < 0) /**/ ; - } - updateScreenProperties(vo); - - if (vo_fs) { - // Save window position and size when switching to fullscreen. - if (toggle_fs) { - w32->prev_width = vo->dwidth; - w32->prev_height = vo->dheight; - w32->prev_x = w32->window_x; - w32->prev_y = w32->window_y; - mp_msg(MSGT_VO, MSGL_V, "[vo] save window bounds: %d:%d:%d:%d\n", - w32->prev_x, w32->prev_y, w32->prev_width, w32->prev_height); - } - vo->dwidth = vo->opts->vo_screenwidth; - vo->dheight = vo->opts->vo_screenheight; - w32->window_x = xinerama_x; - w32->window_y = xinerama_y; - } else { - if (toggle_fs) { - // Restore window position and size when switching from fullscreen. - mp_msg(MSGT_VO, MSGL_V, "[vo] restore window bounds: %d:%d:%d:%d\n", - w32->prev_x, w32->prev_y, w32->prev_width, w32->prev_height); - vo->dwidth = w32->prev_width; - vo->dheight = w32->prev_height; - w32->window_x = w32->prev_x; - w32->window_y = w32->prev_y; - } - } - - r.left = w32->window_x; - r.right = r.left + vo->dwidth; - r.top = w32->window_y; - r.bottom = r.top + vo->dheight; - - SetWindowLong(w32->window, GWL_STYLE, style); - add_window_borders(w32->window, &r); - - mp_msg(MSGT_VO, MSGL_V, "[vo] reset window bounds: %ld:%ld:%ld:%ld\n", - r.left, r.top, r.right - r.left, r.bottom - r.top); - - SetWindowPos(w32->window, layer, r.left, r.top, r.right - r.left, - r.bottom - r.top, SWP_FRAMECHANGED); - // For some reason, moving SWP_SHOWWINDOW to a second call works better - // with wine: returning from fullscreen doesn't cause a bogus resize to - // screen size. - // It's not needed on Windows XP or wine with a virtual desktop. - // It doesn't seem to have any negative effects. - SetWindowPos(w32->window, NULL, 0, 0, 0, 0, - SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_SHOWWINDOW); - - return 1; -} - -/** - * \brief Configure and show window on the screen. - * - * This function should be called in libvo's "config" callback. - * It configures a window and shows it on the screen. - * - * \return 1 - Success, 0 - Failure - */ -int vo_w32_config(struct vo *vo, uint32_t width, uint32_t height, - uint32_t flags) -{ - struct vo_w32_state *w32 = vo->w32; - PIXELFORMATDESCRIPTOR pfd; - int pf; - HDC vo_hdc = vo_w32_get_dc(vo, w32->window); - - memset(&pfd, 0, sizeof pfd); - pfd.nSize = sizeof pfd; - pfd.nVersion = 1; - pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER; - if (flags & VOFLAG_STEREO) - pfd.dwFlags |= PFD_STEREO; - pfd.iPixelType = PFD_TYPE_RGBA; - pfd.cColorBits = 24; - pfd.iLayerType = PFD_MAIN_PLANE; - pf = ChoosePixelFormat(vo_hdc, &pfd); - if (!pf) { - mp_msg(MSGT_VO, MSGL_ERR, "vo: win32: unable to select a valid pixel format!\n"); - vo_w32_release_dc(vo, w32->window, vo_hdc); - return 0; - } - - SetPixelFormat(vo_hdc, pf, &pfd); - vo_w32_release_dc(vo, w32->window, vo_hdc); - - // we already have a fully initialized window, so nothing needs to be done - if (flags & VOFLAG_HIDDEN) - return 1; - - bool reset_size = !(w32->o_dwidth == width && w32->o_dheight == height); - - w32->o_dwidth = width; - w32->o_dheight = height; - - // the desired size is ignored in wid mode, it always matches the window size. - if (WinID < 0) { - if (w32->window_bounds_initialized) { - // restore vo_dwidth/vo_dheight, which are reset against our will - // in vo_config() - RECT r; - GetClientRect(w32->window, &r); - vo->dwidth = r.right; - vo->dheight = r.bottom; - } else { - // first vo_config call; vo_config() will always set vo_dx/dy so - // that the window is centered on the screen, and this is the only - // time we actually want to use vo_dy/dy (this is not sane, and - // video_out.h should provide a function to query the initial - // window position instead) - w32->window_bounds_initialized = true; - reset_size = true; - w32->window_x = w32->prev_x = vo->dx; - w32->window_y = w32->prev_y = vo->dy; - } - if (reset_size) { - w32->prev_width = vo->dwidth = width; - w32->prev_height = vo->dheight = height; - } - } - - vo_fs = flags & VOFLAG_FULLSCREEN; - w32->vm = flags & VOFLAG_MODESWITCHING; - return reinit_window_state(vo); -} - -/** - * \brief Initialize w32_common framework. - * - * The first function that should be called from the w32_common framework. - * It handles window creation on the screen with proper title and attributes. - * It also initializes the framework's internal variables. The function should - * be called after your own preinit initialization and you shouldn't do any - * window management on your own. - * - * Global libvo variables changed: - * vo_w32_window - * vo_screenwidth - * vo_screenheight - * - * \return 1 = Success, 0 = Failure - */ -int vo_w32_init(struct vo *vo) -{ - struct vo_w32_state *w32 = vo->w32; - if (w32 && w32->window) - return 1; - - if (!w32) - w32 = vo->w32 = talloc_zero(vo, struct vo_w32_state); - - HINSTANCE hInstance = GetModuleHandleW(NULL); - - HICON mplayerIcon = LoadIconW(hInstance, L"IDI_ICON1"); - - WNDCLASSEXW wcex = { - .cbSize = sizeof wcex, - .style = CS_OWNDC | CS_DBLCLKS | CS_HREDRAW | CS_VREDRAW, - .lpfnWndProc = WndProc, - .hInstance = hInstance, - .hIcon = mplayerIcon, - .hCursor = LoadCursor(0, IDC_ARROW), - .lpszClassName = classname, - .hIconSm = mplayerIcon, - }; - - if (!RegisterClassExW(&wcex)) { - mp_msg(MSGT_VO, MSGL_ERR, - "vo: win32: unable to register window class!\n"); - return 0; - } - - if (WinID >= 0) { - RECT r; - GetClientRect(WIN_ID_TO_HWND(WinID), &r); - vo->dwidth = r.right; vo->dheight = r.bottom; - w32->window = CreateWindowExW(WS_EX_NOPARENTNOTIFY, classname, - classname, - WS_CHILD | WS_VISIBLE, - 0, 0, vo->dwidth, vo->dheight, - WIN_ID_TO_HWND(WinID), 0, hInstance, vo); - } else { - w32->window = CreateWindowExW(0, classname, - classname, - update_style(vo, 0), - CW_USEDEFAULT, 0, 100, 100, - 0, 0, hInstance, vo); - } - - if (!w32->window) { - mp_msg(MSGT_VO, MSGL_ERR, "vo: win32: unable to create window!\n"); - return 0; - } - - if (WinID >= 0) - EnableWindow(w32->window, 0); - - updateScreenProperties(vo); - - mp_msg(MSGT_VO, MSGL_V, "vo: win32: running at %dx%d with depth %d\n", - vo->opts->vo_screenwidth, vo->opts->vo_screenheight, - w32->depthonscreen); - - return 1; -} - -/** - * \brief Toogle fullscreen / windowed mode. - * - * Should be called on VOCTRL_FULLSCREEN event. The window is - * always resized during this call, so the rendering context - * should be reinitialized with the new dimensions. - * It is unspecified if vo_check_events will create a resize - * event in addition or not. - */ - -void vo_w32_fullscreen(struct vo *vo) -{ - vo_fs = !vo_fs; - reinit_window_state(vo); -} - -/** - * \brief Toogle window border attribute. - * - * Should be called on VOCTRL_BORDER event. - */ -void vo_w32_border(struct vo *vo) -{ - vo_border = !vo_border; - reinit_window_state(vo); -} - -/** - * \brief Toogle window ontop attribute. - * - * Should be called on VOCTRL_ONTOP event. - */ -void vo_w32_ontop(struct vo *vo) -{ - vo->opts->vo_ontop = !vo->opts->vo_ontop; - reinit_window_state(vo); -} - -/** - * \brief Uninitialize w32_common framework. - * - * Should be called last in video driver's uninit function. First release - * anything built on top of the created window e.g. rendering context inside - * and call vo_w32_uninit at the end. - */ -void vo_w32_uninit(struct vo *vo) -{ - struct vo_w32_state *w32 = vo->w32; - mp_msg(MSGT_VO, MSGL_V, "vo: win32: uninit\n"); - if (!w32) - return; - resetMode(vo); - ShowCursor(1); - DestroyWindow(w32->window); - UnregisterClassW(classname, 0); - talloc_free(w32); - vo->w32 = NULL; -} - -/** - * \brief get a device context to draw in - * - * \param wnd window the DC should belong to if it makes sense - */ -HDC vo_w32_get_dc(struct vo *vo, HWND wnd) -{ - struct vo_w32_state *w32 = vo->w32; - return GetDC(wnd); -} - -/** - * \brief release a device context - * - * \param wnd window the DC probably belongs to - */ -void vo_w32_release_dc(struct vo *vo, HWND wnd, HDC dc) -{ - struct vo_w32_state *w32 = vo->w32; - ReleaseDC(wnd, dc); -} diff --git a/libvo/w32_common.h b/libvo/w32_common.h deleted file mode 100644 index c6d9fc7653..0000000000 --- a/libvo/w32_common.h +++ /dev/null @@ -1,66 +0,0 @@ -/* - * 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_W32_COMMON_H -#define MPLAYER_W32_COMMON_H - -#include <stdint.h> -#include <stdbool.h> -#include <windows.h> - -struct vo_w32_state { - HWND window; - - bool vm; - - int depthonscreen; - - // last non-fullscreen extends (updated only on fullscreen or on initialization) - int prev_width; - int prev_height; - int prev_x; - int prev_y; - - // whether the window position and size were intialized - bool window_bounds_initialized; - - bool current_fs; - - int window_x; - int window_y; - - // video size - uint32_t o_dwidth; - uint32_t o_dheight; - - int event_flags; - int mon_cnt; -}; - -int vo_w32_init(struct vo *vo); -void vo_w32_uninit(struct vo *vo); -void vo_w32_ontop(struct vo *vo); -void vo_w32_border(struct vo *vo); -void vo_w32_fullscreen(struct vo *vo); -int vo_w32_check_events(struct vo *vo); -int vo_w32_config(struct vo *vo, uint32_t, uint32_t, uint32_t); -void w32_update_xinerama_info(struct vo *vo); -HDC vo_w32_get_dc(struct vo *vo, HWND wnd); -void vo_w32_release_dc(struct vo *vo, HWND wnd, HDC dc); - -#endif /* MPLAYER_W32_COMMON_H */ diff --git a/libvo/x11_common.c b/libvo/x11_common.c deleted file mode 100644 index 04d5c6880b..0000000000 --- a/libvo/x11_common.c +++ /dev/null @@ -1,2404 +0,0 @@ -/* - * 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 <math.h> -#include <inttypes.h> -#include <limits.h> - -#include "config.h" -#include "bstr.h" -#include "options.h" -#include "mp_msg.h" -#include "mp_fifo.h" -#include "libavutil/common.h" -#include "x11_common.h" -#include "talloc.h" - -#include <string.h> -#include <unistd.h> -#include <assert.h> - -#include "video_out.h" -#include "aspect.h" -#include "geometry.h" -#include "osdep/timer.h" - -#include <X11/Xmd.h> -#include <X11/Xlib.h> -#include <X11/Xutil.h> -#include <X11/Xatom.h> -#include <X11/keysym.h> - -#ifdef CONFIG_XSS -#include <X11/extensions/scrnsaver.h> -#endif - -#ifdef CONFIG_XDPMS -#include <X11/extensions/dpms.h> -#endif - -#ifdef CONFIG_XINERAMA -#include <X11/extensions/Xinerama.h> -#endif - -#ifdef CONFIG_XF86VM -#include <X11/extensions/xf86vmode.h> -#endif - -#ifdef CONFIG_XF86XK -#include <X11/XF86keysym.h> -#endif - -#ifdef CONFIG_XV -#include <X11/extensions/Xv.h> -#include <X11/extensions/Xvlib.h> - -#include "subopt-helper.h" -#endif - -#include "input/input.h" -#include "input/keycodes.h" - -#define WIN_LAYER_ONBOTTOM 2 -#define WIN_LAYER_NORMAL 4 -#define WIN_LAYER_ONTOP 6 -#define WIN_LAYER_ABOVE_DOCK 10 - -int fs_layer = WIN_LAYER_ABOVE_DOCK; - -int stop_xscreensaver = 1; - -static int dpms_disabled = 0; - -char *mDisplayName = NULL; - -char **vo_fstype_list; - -/* 1 means that the WM is metacity (broken as hell) */ -int metacity_hack = 0; - -#ifdef CONFIG_XF86VM -static int modecount; -static XF86VidModeModeInfo **vidmodes; -static XF86VidModeModeLine modeline; -#endif - -static int vo_x11_get_fs_type(int supported); -static void saver_off(Display *); -static void saver_on(Display *); - -/* - * Sends the EWMH fullscreen state event. - * - * action: could be one of _NET_WM_STATE_REMOVE -- remove state - * _NET_WM_STATE_ADD -- add state - * _NET_WM_STATE_TOGGLE -- toggle - */ -void vo_x11_ewmh_fullscreen(struct vo_x11_state *x11, int action) -{ - assert(action == _NET_WM_STATE_REMOVE || - action == _NET_WM_STATE_ADD || action == _NET_WM_STATE_TOGGLE); - - if (x11->fs_type & vo_wm_FULLSCREEN) - { - XEvent xev; - - /* init X event structure for _NET_WM_FULLSCREEN client message */ - xev.xclient.type = ClientMessage; - xev.xclient.serial = 0; - xev.xclient.send_event = True; - xev.xclient.message_type = x11->XA_NET_WM_STATE; - xev.xclient.window = x11->window; - xev.xclient.format = 32; - xev.xclient.data.l[0] = action; - xev.xclient.data.l[1] = x11->XA_NET_WM_STATE_FULLSCREEN; - xev.xclient.data.l[2] = 0; - xev.xclient.data.l[3] = 0; - xev.xclient.data.l[4] = 0; - - /* finally send that damn thing */ - if (!XSendEvent(x11->display, DefaultRootWindow(x11->display), False, - SubstructureRedirectMask | SubstructureNotifyMask, - &xev)) - { - mp_tmsg(MSGT_VO, MSGL_ERR, "\nX11: Couldn't send EWMH fullscreen event!\n"); - } - } -} - -static void vo_hidecursor(Display * disp, Window win) -{ - Cursor no_ptr; - Pixmap bm_no; - XColor black, dummy; - Colormap colormap; - const char bm_no_data[] = { 0, 0, 0, 0, 0, 0, 0, 0 }; - - if (WinID == 0) - return; // do not hide if playing on the root window - - colormap = DefaultColormap(disp, DefaultScreen(disp)); - if ( !XAllocNamedColor(disp, colormap, "black", &black, &dummy) ) - { - return; // color alloc failed, give up - } - bm_no = XCreateBitmapFromData(disp, win, bm_no_data, 8, 8); - no_ptr = XCreatePixmapCursor(disp, bm_no, bm_no, &black, &black, 0, 0); - XDefineCursor(disp, win, no_ptr); - XFreeCursor(disp, no_ptr); - if (bm_no != None) - XFreePixmap(disp, bm_no); - XFreeColors(disp,colormap,&black.pixel,1,0); -} - -static void vo_showcursor(Display * disp, Window win) -{ - if (WinID == 0) - return; - XDefineCursor(disp, win, 0); -} - -static int x11_errorhandler(Display * display, XErrorEvent * event) -{ -#define MSGLEN 60 - char msg[MSGLEN]; - - XGetErrorText(display, event->error_code, (char *) &msg, MSGLEN); - - mp_msg(MSGT_VO, MSGL_ERR, "X11 error: %s\n", msg); - - mp_msg(MSGT_VO, MSGL_V, - "Type: %x, display: %p, resourceid: %lx, serial: %lx\n", - event->type, event->display, event->resourceid, event->serial); - mp_msg(MSGT_VO, MSGL_V, - "Error code: %x, request code: %x, minor code: %x\n", - event->error_code, event->request_code, event->minor_code); - -// abort(); - return 0; -#undef MSGLEN -} - -void fstype_help(void) -{ - mp_tmsg(MSGT_VO, MSGL_INFO, "Available fullscreen layer change modes:\n"); - mp_msg(MSGT_IDENTIFY, MSGL_INFO, "ID_FULL_SCREEN_TYPES\n"); - - mp_msg(MSGT_VO, MSGL_INFO, " %-15s %s\n", "none", - "don't set fullscreen window layer"); - mp_msg(MSGT_VO, MSGL_INFO, " %-15s %s\n", "layer", - "use _WIN_LAYER hint with default layer"); - mp_msg(MSGT_VO, MSGL_INFO, " %-15s %s\n", "layer=<0..15>", - "use _WIN_LAYER hint with a given layer number"); - mp_msg(MSGT_VO, MSGL_INFO, " %-15s %s\n", "netwm", - "force NETWM style"); - mp_msg(MSGT_VO, MSGL_INFO, " %-15s %s\n", "above", - "use _NETWM_STATE_ABOVE hint if available"); - mp_msg(MSGT_VO, MSGL_INFO, " %-15s %s\n", "below", - "use _NETWM_STATE_BELOW hint if available"); - mp_msg(MSGT_VO, MSGL_INFO, " %-15s %s\n", "fullscreen", - "use _NETWM_STATE_FULLSCREEN hint if available"); - mp_msg(MSGT_VO, MSGL_INFO, " %-15s %s\n", "stays_on_top", - "use _NETWM_STATE_STAYS_ON_TOP hint if available"); - mp_msg(MSGT_VO, MSGL_INFO, - "You can also negate the settings with simply putting '-' in the beginning"); - mp_msg(MSGT_VO, MSGL_INFO, "\n"); -} - -static void fstype_dump(int fstype) -{ - if (fstype) - { - mp_msg(MSGT_VO, MSGL_V, "[x11] Current fstype setting honours"); - if (fstype & vo_wm_LAYER) - mp_msg(MSGT_VO, MSGL_V, " LAYER"); - if (fstype & vo_wm_FULLSCREEN) - mp_msg(MSGT_VO, MSGL_V, " FULLSCREEN"); - if (fstype & vo_wm_STAYS_ON_TOP) - mp_msg(MSGT_VO, MSGL_V, " STAYS_ON_TOP"); - if (fstype & vo_wm_ABOVE) - mp_msg(MSGT_VO, MSGL_V, " ABOVE"); - if (fstype & vo_wm_BELOW) - mp_msg(MSGT_VO, MSGL_V, " BELOW"); - mp_msg(MSGT_VO, MSGL_V, " X atoms\n"); - } else - mp_msg(MSGT_VO, MSGL_V, - "[x11] Current fstype setting doesn't honour any X atoms\n"); -} - -static int net_wm_support_state_test(struct vo_x11_state *x11, Atom atom) -{ -#define NET_WM_STATE_TEST(x) { if (atom == x11->XA_NET_WM_STATE_##x) { mp_msg( MSGT_VO,MSGL_V, "[x11] Detected wm supports " #x " state.\n" ); return vo_wm_##x; } } - - NET_WM_STATE_TEST(FULLSCREEN); - NET_WM_STATE_TEST(ABOVE); - NET_WM_STATE_TEST(STAYS_ON_TOP); - NET_WM_STATE_TEST(BELOW); - return 0; -} - -static int x11_get_property(struct vo_x11_state *x11, Atom type, Atom ** args, - unsigned long *nitems) -{ - int format; - unsigned long bytesafter; - - return Success == - XGetWindowProperty(x11->display, x11->rootwin, type, 0, 16384, False, - AnyPropertyType, &type, &format, nitems, - &bytesafter, (unsigned char **) args) - && *nitems > 0; -} - -static int vo_wm_detect(struct vo *vo) -{ - struct vo_x11_state *x11 = vo->x11; - int i; - int wm = 0; - unsigned long nitems; - Atom *args = NULL; - - if (WinID >= 0) - return 0; - -// -- supports layers - if (x11_get_property(x11, x11->XA_WIN_PROTOCOLS, &args, &nitems)) - { - mp_msg(MSGT_VO, MSGL_V, "[x11] Detected wm supports layers.\n"); - for (i = 0; i < nitems; i++) - { - if (args[i] == x11->XA_WIN_LAYER) - { - wm |= vo_wm_LAYER; - metacity_hack |= 1; - } else - /* metacity is the only window manager I know which reports - * supporting only the _WIN_LAYER hint in _WIN_PROTOCOLS. - * (what's more support for it is broken) */ - metacity_hack |= 2; - } - XFree(args); - if (wm && (metacity_hack == 1)) - { - // metacity claims to support layers, but it is not the truth :-) - wm ^= vo_wm_LAYER; - mp_msg(MSGT_VO, MSGL_V, - "[x11] Using workaround for Metacity bugs.\n"); - } - } -// --- netwm - if (x11_get_property(x11, x11->XA_NET_SUPPORTED, &args, &nitems)) - { - mp_msg(MSGT_VO, MSGL_V, "[x11] Detected wm supports NetWM.\n"); - for (i = 0; i < nitems; i++) - wm |= net_wm_support_state_test(vo->x11, args[i]); - XFree(args); - } - - if (wm == 0) - mp_msg(MSGT_VO, MSGL_V, "[x11] Unknown wm type...\n"); - return wm; -} - -#define XA_INIT(x) x11->XA##x = XInternAtom(x11->display, #x, False) -static void init_atoms(struct vo_x11_state *x11) -{ - XA_INIT(_NET_SUPPORTED); - XA_INIT(_NET_WM_STATE); - XA_INIT(_NET_WM_STATE_FULLSCREEN); - XA_INIT(_NET_WM_STATE_ABOVE); - XA_INIT(_NET_WM_STATE_STAYS_ON_TOP); - XA_INIT(_NET_WM_STATE_BELOW); - XA_INIT(_NET_WM_PID); - XA_INIT(_NET_WM_NAME); - XA_INIT(_NET_WM_ICON_NAME); - XA_INIT(_WIN_PROTOCOLS); - XA_INIT(_WIN_LAYER); - XA_INIT(_WIN_HINTS); - XA_INIT(WM_PROTOCOLS); - XA_INIT(WM_DELETE_WINDOW); - XA_INIT(UTF8_STRING); - char buf[50]; - sprintf(buf, "_NET_WM_CM_S%d", x11->screen); - x11->XA_NET_WM_CM = XInternAtom(x11->display, buf, False); -} - -void update_xinerama_info(struct vo *vo) { - struct MPOpts *opts = vo->opts; - xinerama_x = xinerama_y = 0; -#ifdef CONFIG_XINERAMA - if (xinerama_screen >= -1 && XineramaIsActive(vo->x11->display)) - { - int screen = xinerama_screen; - XineramaScreenInfo *screens; - int num_screens; - - screens = XineramaQueryScreens(vo->x11->display, &num_screens); - if (screen >= num_screens) - screen = num_screens - 1; - if (screen == -1) { - int x = vo->dx + vo->dwidth / 2; - int y = vo->dy + vo->dheight / 2; - for (screen = num_screens - 1; screen > 0; screen--) { - int left = screens[screen].x_org; - int right = left + screens[screen].width; - int top = screens[screen].y_org; - int bottom = top + screens[screen].height; - if (left <= x && x <= right && top <= y && y <= bottom) - break; - } - } - if (screen < 0) - screen = 0; - opts->vo_screenwidth = screens[screen].width; - opts->vo_screenheight = screens[screen].height; - xinerama_x = screens[screen].x_org; - xinerama_y = screens[screen].y_org; - - XFree(screens); - } -#endif - aspect_save_screenres(vo, opts->vo_screenwidth, opts->vo_screenheight); -} - -int vo_init(struct vo *vo) -{ - struct MPOpts *opts = vo->opts; -// int mScreen; - int depth, bpp; - unsigned int mask; - -// char * DisplayName = ":0.0"; -// Display * mDisplay; - XImage *mXImage = NULL; - -// Window mRootWin; - XWindowAttributes attribs; - char *dispName; - - if (vo->x11) - return 1; - - vo->x11 = vo_x11_init_state(); - struct vo_x11_state *x11 = vo->x11; - - if (vo_rootwin) - WinID = 0; // use root window - - if (x11->depthonscreen) - { - saver_off(x11->display); - return 1; // already called - } - - XSetErrorHandler(x11_errorhandler); - -#if 0 - if (!mDisplayName) - if (!(mDisplayName = getenv("DISPLAY"))) - mDisplayName = strdup(":0.0"); -#else - dispName = XDisplayName(mDisplayName); -#endif - - mp_msg(MSGT_VO, MSGL_V, "X11 opening display: %s\n", dispName); - - x11->display = XOpenDisplay(dispName); - if (!x11->display) - { - mp_msg(MSGT_VO, MSGL_ERR, - "vo: couldn't open the X11 display (%s)!\n", dispName); - talloc_free(x11); - vo->x11 = NULL; - return 0; - } - x11->screen = DefaultScreen(x11->display); // screen ID - x11->rootwin = RootWindow(x11->display, x11->screen); // root window ID - - x11->xim = XOpenIM(x11->display, NULL, NULL, NULL); - - init_atoms(vo->x11); - -#ifdef CONFIG_XF86VM - { - int clock; - - XF86VidModeGetModeLine(x11->display, x11->screen, &clock, &modeline); - if (!opts->vo_screenwidth) - opts->vo_screenwidth = modeline.hdisplay; - if (!opts->vo_screenheight) - opts->vo_screenheight = modeline.vdisplay; - } -#endif - { - if (!opts->vo_screenwidth) - opts->vo_screenwidth = DisplayWidth(x11->display, x11->screen); - if (!opts->vo_screenheight) - opts->vo_screenheight = DisplayHeight(x11->display, x11->screen); - } - // get color depth (from root window, or the best visual): - XGetWindowAttributes(x11->display, x11->rootwin, &attribs); - depth = attribs.depth; - - if (depth != 15 && depth != 16 && depth != 24 && depth != 32) - { - Visual *visual; - - depth = vo_find_depth_from_visuals(x11->display, x11->screen, &visual); - if (depth != -1) - mXImage = XCreateImage(x11->display, visual, depth, ZPixmap, - 0, NULL, 1, 1, 8, 1); - } else - mXImage = - XGetImage(x11->display, x11->rootwin, 0, 0, 1, 1, AllPlanes, ZPixmap); - - x11->depthonscreen = depth; // display depth on screen - - // get bits/pixel from XImage structure: - if (mXImage == NULL) - { - mask = 0; - } else - { - /* - * for the depth==24 case, the XImage structures might use - * 24 or 32 bits of data per pixel. The x11->depthonscreen - * field stores the amount of data per pixel in the - * XImage structure! - * - * Maybe we should rename vo_depthonscreen to (or add) vo_bpp? - */ - bpp = mXImage->bits_per_pixel; - if ((x11->depthonscreen + 7) / 8 != (bpp + 7) / 8) - x11->depthonscreen = bpp; // by A'rpi - mask = - mXImage->red_mask | mXImage->green_mask | mXImage->blue_mask; - mp_msg(MSGT_VO, MSGL_V, - "vo: X11 color mask: %X (R:%lX G:%lX B:%lX)\n", mask, - mXImage->red_mask, mXImage->green_mask, mXImage->blue_mask); - XDestroyImage(mXImage); - } - if (((x11->depthonscreen + 7) / 8) == 2) - { - if (mask == 0x7FFF) - x11->depthonscreen = 15; - else if (mask == 0xFFFF) - x11->depthonscreen = 16; - } -// XCloseDisplay( mDisplay ); -/* slightly improved local display detection AST */ - if (strncmp(dispName, "unix:", 5) == 0) - dispName += 4; - else if (strncmp(dispName, "localhost:", 10) == 0) - dispName += 9; - if (*dispName == ':' && atoi(dispName + 1) < 10) - x11->display_is_local = 1; - else - x11->display_is_local = 0; - mp_msg(MSGT_VO, MSGL_V, - "vo: X11 running at %dx%d with depth %d and %d bpp (\"%s\" => %s display)\n", - opts->vo_screenwidth, opts->vo_screenheight, depth, x11->depthonscreen, - dispName, x11->display_is_local ? "local" : "remote"); - - x11->wm_type = vo_wm_detect(vo); - - x11->fs_type = vo_x11_get_fs_type(x11->wm_type); - - fstype_dump(x11->fs_type); - - saver_off(x11->display); - return 1; -} - -void vo_uninit(struct vo_x11_state *x11) -{ - if (!x11) - return; - if (!x11->display) - { - mp_msg(MSGT_VO, MSGL_V, - "vo: x11 uninit called but X11 not initialized..\n"); - } else { - mp_msg(MSGT_VO, MSGL_V, "vo: uninit ...\n"); - if (x11->xim) - XCloseIM(x11->xim); - XSetErrorHandler(NULL); - XCloseDisplay(x11->display); - x11->depthonscreen = 0; - x11->display = NULL; - } - talloc_free(x11); -} - -static const struct mp_keymap keymap[] = { - // special keys - {XK_Pause, KEY_PAUSE}, {XK_Escape, KEY_ESC}, {XK_BackSpace, KEY_BS}, - {XK_Tab, KEY_TAB}, {XK_Return, KEY_ENTER}, - {XK_Menu, KEY_MENU}, {XK_Print, KEY_PRINT}, - - // cursor keys - {XK_Left, KEY_LEFT}, {XK_Right, KEY_RIGHT}, {XK_Up, KEY_UP}, {XK_Down, KEY_DOWN}, - - // navigation block - {XK_Insert, KEY_INSERT}, {XK_Delete, KEY_DELETE}, {XK_Home, KEY_HOME}, {XK_End, KEY_END}, - {XK_Page_Up, KEY_PAGE_UP}, {XK_Page_Down, KEY_PAGE_DOWN}, - - // F-keys - {XK_F1, KEY_F+1}, {XK_F2, KEY_F+2}, {XK_F3, KEY_F+3}, {XK_F4, KEY_F+4}, - {XK_F5, KEY_F+5}, {XK_F6, KEY_F+6}, {XK_F7, KEY_F+7}, {XK_F8, KEY_F+8}, - {XK_F9, KEY_F+9}, {XK_F10, KEY_F+10}, {XK_F11, KEY_F+11}, {XK_F12, KEY_F+12}, - - // numpad independent of numlock - {XK_KP_Subtract, '-'}, {XK_KP_Add, '+'}, {XK_KP_Multiply, '*'}, {XK_KP_Divide, '/'}, - {XK_KP_Enter, KEY_KPENTER}, - - // numpad with numlock - {XK_KP_0, KEY_KP0}, {XK_KP_1, KEY_KP1}, {XK_KP_2, KEY_KP2}, - {XK_KP_3, KEY_KP3}, {XK_KP_4, KEY_KP4}, {XK_KP_5, KEY_KP5}, - {XK_KP_6, KEY_KP6}, {XK_KP_7, KEY_KP7}, {XK_KP_8, KEY_KP8}, - {XK_KP_9, KEY_KP9}, {XK_KP_Decimal, KEY_KPDEC}, - {XK_KP_Separator, KEY_KPDEC}, - - // numpad without numlock - {XK_KP_Insert, KEY_KPINS}, {XK_KP_End, KEY_KP1}, {XK_KP_Down, KEY_KP2}, - {XK_KP_Page_Down, KEY_KP3}, {XK_KP_Left, KEY_KP4}, {XK_KP_Begin, KEY_KP5}, - {XK_KP_Right, KEY_KP6}, {XK_KP_Home, KEY_KP7}, {XK_KP_Up, KEY_KP8}, - {XK_KP_Page_Up, KEY_KP9}, {XK_KP_Delete, KEY_KPDEL}, - -#ifdef XF86XK_AudioPause - {XF86XK_MenuKB, KEY_MENU}, - {XF86XK_AudioPlay, KEY_PLAY}, {XF86XK_AudioPause, KEY_PAUSE}, {XF86XK_AudioStop, KEY_STOP}, - {XF86XK_AudioPrev, KEY_PREV}, {XF86XK_AudioNext, KEY_NEXT}, - {XF86XK_AudioMute, KEY_MUTE}, {XF86XK_AudioLowerVolume, KEY_VOLUME_DOWN}, {XF86XK_AudioRaiseVolume, KEY_VOLUME_UP}, -#endif - - {0, 0} -}; - -static int vo_x11_lookupkey(int key) -{ - static const char *passthrough_keys = " -+*/<>`~!@#$%^&()_{}:;\"\',.?\\|=[]"; - int mpkey = 0; - if ((key >= 'a' && key <= 'z') || - (key >= 'A' && key <= 'Z') || - (key >= '0' && key <= '9') || - (key > 0 && key < 256 && strchr(passthrough_keys, key))) - mpkey = key; - - if (!mpkey) - mpkey = lookup_keymap_table(keymap, key); - - return mpkey; -} - - -// ----- Motif header: ------- - -#define MWM_HINTS_FUNCTIONS (1L << 0) -#define MWM_HINTS_DECORATIONS (1L << 1) -#define MWM_HINTS_INPUT_MODE (1L << 2) -#define MWM_HINTS_STATUS (1L << 3) - -#define MWM_FUNC_ALL (1L << 0) -#define MWM_FUNC_RESIZE (1L << 1) -#define MWM_FUNC_MOVE (1L << 2) -#define MWM_FUNC_MINIMIZE (1L << 3) -#define MWM_FUNC_MAXIMIZE (1L << 4) -#define MWM_FUNC_CLOSE (1L << 5) - -#define MWM_DECOR_ALL (1L << 0) -#define MWM_DECOR_BORDER (1L << 1) -#define MWM_DECOR_RESIZEH (1L << 2) -#define MWM_DECOR_TITLE (1L << 3) -#define MWM_DECOR_MENU (1L << 4) -#define MWM_DECOR_MINIMIZE (1L << 5) -#define MWM_DECOR_MAXIMIZE (1L << 6) - -#define MWM_INPUT_MODELESS 0 -#define MWM_INPUT_PRIMARY_APPLICATION_MODAL 1 -#define MWM_INPUT_SYSTEM_MODAL 2 -#define MWM_INPUT_FULL_APPLICATION_MODAL 3 -#define MWM_INPUT_APPLICATION_MODAL MWM_INPUT_PRIMARY_APPLICATION_MODAL - -#define MWM_TEAROFF_WINDOW (1L<<0) - -typedef struct -{ - long flags; - long functions; - long decorations; - long input_mode; - long state; -} MotifWmHints; - -static MotifWmHints vo_MotifWmHints; -static Atom vo_MotifHints = None; - -void vo_x11_decoration(struct vo *vo, int d) -{ - struct vo_x11_state *x11 = vo->x11; - Atom mtype; - int mformat; - unsigned long mn, mb; - - if (!WinID) - return; - - if (vo_fsmode & 8) - { - XSetTransientForHint(x11->display, x11->window, - RootWindow(x11->display, x11->screen)); - } - - vo_MotifHints = XInternAtom(x11->display, "_MOTIF_WM_HINTS", 0); - if (vo_MotifHints != None) - { - if (!d) - { - MotifWmHints *mhints = NULL; - - XGetWindowProperty(x11->display, x11->window, - vo_MotifHints, 0, 20, False, - vo_MotifHints, &mtype, &mformat, &mn, - &mb, (unsigned char **) &mhints); - if (mhints) - { - if (mhints->flags & MWM_HINTS_DECORATIONS) - x11->olddecor = mhints->decorations; - if (mhints->flags & MWM_HINTS_FUNCTIONS) - x11->oldfuncs = mhints->functions; - XFree(mhints); - } - } - - memset(&vo_MotifWmHints, 0, sizeof(MotifWmHints)); - vo_MotifWmHints.flags = - MWM_HINTS_FUNCTIONS | MWM_HINTS_DECORATIONS; - if (d) - { - vo_MotifWmHints.functions = x11->oldfuncs; - d = x11->olddecor; - } -#if 0 - vo_MotifWmHints.decorations = - d | ((vo_fsmode & 2) ? 0 : MWM_DECOR_MENU); -#else - vo_MotifWmHints.decorations = - d | ((vo_fsmode & 2) ? MWM_DECOR_MENU : 0); -#endif - XChangeProperty(x11->display, x11->window, vo_MotifHints, - vo_MotifHints, 32, - PropModeReplace, - (unsigned char *) &vo_MotifWmHints, - (vo_fsmode & 4) ? 4 : 5); - } -} - -void vo_x11_classhint(struct vo *vo, Window window, const char *name) -{ - struct MPOpts *opts = vo->opts; - struct vo_x11_state *x11 = vo->x11; - XClassHint wmClass; - pid_t pid = getpid(); - - wmClass.res_name = opts->vo_winname ? opts->vo_winname : (char *)name; - wmClass.res_class = "mpv"; - XSetClassHint(x11->display, window, &wmClass); - XChangeProperty(x11->display, window, x11->XA_NET_WM_PID, XA_CARDINAL, - 32, PropModeReplace, (unsigned char *) &pid, 1); -} - -void vo_x11_uninit(struct vo *vo) -{ - struct vo_x11_state *x11 = vo->x11; - saver_on(x11->display); - if (x11->window != None) - vo_showcursor(x11->display, x11->window); - - if (x11->f_gc != None) - { - XFreeGC(vo->x11->display, x11->f_gc); - x11->f_gc = None; - } - { - if (x11->vo_gc != None) - { - XFreeGC(vo->x11->display, x11->vo_gc); - x11->vo_gc = None; - } - if (x11->window != None) - { - XClearWindow(x11->display, x11->window); - if (WinID < 0) - { - XEvent xev; - - if (x11->xic) - XDestroyIC(x11->xic); - x11->xic = NULL; - - XUnmapWindow(x11->display, x11->window); - XSelectInput(x11->display, x11->window, StructureNotifyMask); - XDestroyWindow(x11->display, x11->window); - do - { - XNextEvent(x11->display, &xev); - } - while (xev.type != DestroyNotify - || xev.xdestroywindow.event != x11->window); - } - x11->window = None; - } - vo_fs = 0; - x11->vo_old_width = x11->vo_old_height = 0; - x11->last_video_width = 0; - x11->last_video_height = 0; - x11->size_changed_during_fs = false; - } - vo_uninit(x11); - vo->x11 = NULL; -} - -static int check_resize(struct vo *vo) -{ - int old_w = vo->dwidth, old_h = vo->dheight; - int old_x = vo->dx, old_y = vo->dy; - int rc = 0; - vo_x11_update_geometry(vo, true); - if (vo->dwidth != old_w || vo->dheight != old_h) - rc |= VO_EVENT_RESIZE; - if (vo->dx != old_x || vo->dy != old_y) - rc |= VO_EVENT_MOVE; - return rc; -} - -int vo_x11_check_events(struct vo *vo) -{ - struct vo_x11_state *x11 = vo->x11; - struct MPOpts *opts = vo->opts; - Display *display = vo->x11->display; - int ret = 0; - XEvent Event; - - if (x11->mouse_waiting_hide && opts->cursor_autohide_delay != -1 && - (GetTimerMS() - x11->mouse_timer >= opts->cursor_autohide_delay)) { - vo_hidecursor(display, x11->window); - x11->mouse_waiting_hide = 0; - } - - if (WinID > 0) - ret |= check_resize(vo); - while (XPending(display)) - { - XNextEvent(display, &Event); -// printf("\rEvent.type=%X \n",Event.type); - switch (Event.type) - { - case Expose: - ret |= VO_EVENT_EXPOSE; - break; - case ConfigureNotify: - if (x11->window == None) - break; - ret |= check_resize(vo); - break; - case KeyPress: - { - char buf[100]; - KeySym keySym = 0; - int modifiers = 0; - if (Event.xkey.state & ShiftMask) - modifiers |= KEY_MODIFIER_SHIFT; - if (Event.xkey.state & ControlMask) - modifiers |= KEY_MODIFIER_CTRL; - if (Event.xkey.state & Mod1Mask) - modifiers |= KEY_MODIFIER_ALT; - if (Event.xkey.state & Mod4Mask) - modifiers |= KEY_MODIFIER_META; - if (x11->xic) { - Status status; - int len = Xutf8LookupString(x11->xic, &Event.xkey, buf, - sizeof(buf), &keySym, - &status); - int mpkey = vo_x11_lookupkey(keySym); - if (mpkey) { - mplayer_put_key(vo->key_fifo, mpkey | modifiers); - } else if (status == XLookupChars - || status == XLookupBoth) - { - struct bstr t = { buf, len }; - mplayer_put_key_utf8(vo->key_fifo, modifiers, t); - } - } else { - XLookupString(&Event.xkey, buf, sizeof(buf), &keySym, - &x11->compose_status); - int mpkey = vo_x11_lookupkey(keySym); - if (mpkey) - mplayer_put_key(vo->key_fifo, mpkey | modifiers); - } - ret |= VO_EVENT_KEYPRESS; - } - break; - case MotionNotify: - vo_mouse_movement(vo, Event.xmotion.x, Event.xmotion.y); - - if (opts->cursor_autohide_delay > -2) { - vo_showcursor(display, x11->window); - x11->mouse_waiting_hide = 1; - x11->mouse_timer = GetTimerMS(); - } - break; - case ButtonPress: - if (opts->cursor_autohide_delay > -2) { - vo_showcursor(display, x11->window); - x11->mouse_waiting_hide = 1; - x11->mouse_timer = GetTimerMS(); - } - mplayer_put_key(vo->key_fifo, - (MOUSE_BTN0 + Event.xbutton.button - 1) - | MP_KEY_DOWN); - break; - case ButtonRelease: - if (opts->cursor_autohide_delay > -2) { - vo_showcursor(display, x11->window); - x11->mouse_waiting_hide = 1; - x11->mouse_timer = GetTimerMS(); - } - mplayer_put_key(vo->key_fifo, - MOUSE_BTN0 + Event.xbutton.button - 1); - break; - case PropertyNotify: - { - char *name = - XGetAtomName(display, Event.xproperty.atom); - - if (!name) - break; - -// fprintf(stderr,"[ws] PropertyNotify ( 0x%x ) %s ( 0x%x )\n",vo_window,name,Event.xproperty.atom ); - - XFree(name); - } - break; - case MapNotify: - x11->vo_hint.win_gravity = x11->old_gravity; - XSetWMNormalHints(display, x11->window, &x11->vo_hint); - x11->fs_flip = 0; - break; - case DestroyNotify: - mp_msg(MSGT_VO, MSGL_WARN, "Our window was destroyed, exiting\n"); - mplayer_put_key(vo->key_fifo, KEY_CLOSE_WIN); - break; - case ClientMessage: - if (Event.xclient.message_type == x11->XAWM_PROTOCOLS && - Event.xclient.data.l[0] == x11->XAWM_DELETE_WINDOW) - mplayer_put_key(vo->key_fifo, KEY_CLOSE_WIN); - break; - } - } - return ret; -} - -/** - * \brief sets the size and position of the non-fullscreen window. - */ -static void vo_x11_nofs_sizepos(struct vo *vo, int x, int y, - int width, int height) -{ - struct vo_x11_state *x11 = vo->x11; - if (width == x11->last_video_width && height == x11->last_video_height) { - if (!vo->opts->force_window_position && !x11->size_changed_during_fs) - return; - } else if (vo_fs) - x11->size_changed_during_fs = true; - x11->last_video_height = height; - x11->last_video_width = width; - vo_x11_sizehint(vo, x, y, width, height, 0); - if (vo_fs) { - x11->vo_old_x = x; - x11->vo_old_y = y; - x11->vo_old_width = width; - x11->vo_old_height = height; - } - else - { - vo->dwidth = width; - vo->dheight = height; - if (vo->opts->force_window_position) - XMoveResizeWindow(vo->x11->display, vo->x11->window, x, y, width, - height); - else - XResizeWindow(vo->x11->display, vo->x11->window, width, height); - } -} - -void vo_x11_sizehint(struct vo *vo, int x, int y, int width, int height, int max) -{ - struct vo_x11_state *x11 = vo->x11; - x11->vo_hint.flags = 0; - if (vo_keepaspect) - { - x11->vo_hint.flags |= PAspect; - x11->vo_hint.min_aspect.x = width; - x11->vo_hint.min_aspect.y = height; - x11->vo_hint.max_aspect.x = width; - x11->vo_hint.max_aspect.y = height; - } - - x11->vo_hint.flags |= PPosition | PSize; - x11->vo_hint.x = x; - x11->vo_hint.y = y; - x11->vo_hint.width = width; - x11->vo_hint.height = height; - if (max) - { - x11->vo_hint.flags |= PMaxSize; - x11->vo_hint.max_width = width; - x11->vo_hint.max_height = height; - } else - { - x11->vo_hint.max_width = 0; - x11->vo_hint.max_height = 0; - } - - // Set minimum height/width to 4 to avoid off-by-one errors. - x11->vo_hint.flags |= PMinSize; - x11->vo_hint.min_width = x11->vo_hint.min_height = 4; - - // Set the base size. A window manager might display the window - // size to the user relative to this. - // Setting these to width/height might be nice, but e.g. fluxbox can't handle it. - x11->vo_hint.flags |= PBaseSize; - x11->vo_hint.base_width = 0 /*width*/; - x11->vo_hint.base_height = 0 /*height*/; - - x11->vo_hint.flags |= PWinGravity; - x11->vo_hint.win_gravity = StaticGravity; - XSetWMNormalHints(x11->display, x11->window, &x11->vo_hint); -} - -static int vo_x11_get_gnome_layer(struct vo_x11_state *x11, Window win) -{ - Atom type; - int format; - unsigned long nitems; - unsigned long bytesafter; - unsigned short *args = NULL; - - if (XGetWindowProperty(x11->display, win, x11->XA_WIN_LAYER, 0, 16384, - False, AnyPropertyType, &type, &format, &nitems, - &bytesafter, - (unsigned char **) &args) == Success - && nitems > 0 && args) - { - mp_msg(MSGT_VO, MSGL_V, "[x11] original window layer is %d.\n", - *args); - return *args; - } - return WIN_LAYER_NORMAL; -} - -// set a X text property that expects a UTF8_STRING type -static void vo_x11_set_property_utf8(struct vo *vo, Atom name, const char *t) -{ - struct vo_x11_state *x11 = vo->x11; - - XChangeProperty(x11->display, x11->window, name, x11->XAUTF8_STRING, 8, - PropModeReplace, t, strlen(t)); -} - -// set a X text property that expects a STRING or COMPOUND_TEXT type -static void vo_x11_set_property_string(struct vo *vo, Atom name, const char *t) -{ - struct vo_x11_state *x11 = vo->x11; - XTextProperty prop = {0}; - - if (Xutf8TextListToTextProperty(x11->display, (char **)&t, 1, - XStdICCTextStyle, &prop) == Success) - { - XSetTextProperty(x11->display, x11->window, &prop, name); - } else { - // Strictly speaking this violates the ICCCM, but there's no way we - // can do this correctly. - vo_x11_set_property_utf8(vo, name, t); - } - - if (prop.value) - XFree(prop.value); -} - -static void vo_x11_update_window_title(struct vo *vo) -{ - struct vo_x11_state *x11 = vo->x11; - - const char *title = vo_get_window_title(vo); - vo_x11_set_property_string(vo, XA_WM_NAME, title); - vo_x11_set_property_string(vo, XA_WM_ICON_NAME, title); - vo_x11_set_property_utf8(vo, x11->XA_NET_WM_NAME, title); - vo_x11_set_property_utf8(vo, x11->XA_NET_WM_ICON_NAME, title); -} - -// -static Window vo_x11_create_smooth_window(struct vo_x11_state *x11, Window mRoot, - Visual * vis, int x, int y, - unsigned int width, unsigned int height, - int depth, Colormap col_map) -{ - unsigned long xswamask = CWBorderPixel; - XSetWindowAttributes xswa; - Window ret_win; - - if (col_map != CopyFromParent) - { - xswa.colormap = col_map; - xswamask |= CWColormap; - } - xswa.background_pixel = 0; - xswa.border_pixel = 0; - xswa.backing_store = NotUseful; - xswa.bit_gravity = StaticGravity; - - ret_win = - XCreateWindow(x11->display, x11->rootwin, x, y, width, height, 0, depth, - CopyFromParent, vis, xswamask, &xswa); - XSetWMProtocols(x11->display, ret_win, &x11->XAWM_DELETE_WINDOW, 1); - if (x11->f_gc == None) - x11->f_gc = XCreateGC(x11->display, ret_win, 0, 0); - XSetForeground(x11->display, x11->f_gc, 0); - - return ret_win; -} - -/** - * \brief create and setup a window suitable for display - * \param vis Visual to use for creating the window - * \param x x position of window - * \param y y position of window - * \param width width of window - * \param height height of window - * \param flags flags for window creation. - * Only VOFLAG_FULLSCREEN is supported so far. - * \param col_map Colourmap for window or CopyFromParent if a specific colormap isn't needed - * \param classname name to use for the classhint - * - * This also does the grunt-work like setting Window Manager hints etc. - * If vo_window is already set it just moves and resizes it. - */ -void vo_x11_create_vo_window(struct vo *vo, XVisualInfo *vis, int x, int y, - unsigned int width, unsigned int height, int flags, - Colormap col_map, const char *classname) -{ - struct MPOpts *opts = vo->opts; - struct vo_x11_state *x11 = vo->x11; - Display *mDisplay = vo->x11->display; - if (WinID >= 0) { - vo_fs = flags & VOFLAG_FULLSCREEN; - x11->window = WinID ? (Window)WinID : x11->rootwin; - if (col_map != CopyFromParent) { - unsigned long xswamask = CWColormap; - XSetWindowAttributes xswa; - xswa.colormap = col_map; - XChangeWindowAttributes(mDisplay, x11->window, xswamask, &xswa); - XInstallColormap(mDisplay, col_map); - } - if (WinID) { - // Expose events can only really be handled by us, so request them. - vo_x11_selectinput_witherr(mDisplay, x11->window, ExposureMask); - } else - // Do not capture events since it might break the parent application - // if it relies on events being forwarded to the parent of WinID. - // It also is consistent with the w32_common.c code. - vo_x11_selectinput_witherr(mDisplay, x11->window, - StructureNotifyMask | KeyPressMask | PointerMotionMask | - ButtonPressMask | ButtonReleaseMask | ExposureMask); - - vo_x11_update_geometry(vo, true); - goto final; - } - if (x11->window == None) { - vo_fs = 0; - vo->dwidth = width; - vo->dheight = height; - x11->window = vo_x11_create_smooth_window(x11, x11->rootwin, vis->visual, - x, y, width, height, vis->depth, col_map); - x11->window_state = VOFLAG_HIDDEN; - } - if (flags & VOFLAG_HIDDEN) - goto final; - if (x11->window_state & VOFLAG_HIDDEN) { - XSizeHints hint; - x11->window_state &= ~VOFLAG_HIDDEN; - vo_x11_classhint(vo, x11->window, classname); - vo_hidecursor(mDisplay, x11->window); - XSelectInput(mDisplay, x11->window, StructureNotifyMask); - hint.x = x; hint.y = y; - hint.width = width; hint.height = height; - hint.flags = PSize; - if (geometry_xy_changed) - hint.flags |= PPosition; - XSetWMNormalHints(mDisplay, x11->window, &hint); - if (!vo_border) vo_x11_decoration(vo, 0); - // map window - x11->xic = XCreateIC(x11->xim, - XNInputStyle, XIMPreeditNone | XIMStatusNone, - XNClientWindow, x11->window, - XNFocusWindow, x11->window, - NULL); - XSelectInput(mDisplay, x11->window, NoEventMask); - vo_x11_selectinput_witherr(mDisplay, x11->window, - StructureNotifyMask | KeyPressMask | PointerMotionMask | - ButtonPressMask | ButtonReleaseMask | ExposureMask); - XMapWindow(mDisplay, x11->window); - vo_x11_clearwindow(vo, x11->window); - } - vo_x11_update_window_title(vo); - if (opts->vo_ontop) vo_x11_setlayer(vo, x11->window, opts->vo_ontop); - vo_x11_update_geometry(vo, !geometry_xy_changed); - vo_x11_nofs_sizepos(vo, vo->dx, vo->dy, width, height); - if (!!vo_fs != !!(flags & VOFLAG_FULLSCREEN)) - vo_x11_fullscreen(vo); - else if (vo_fs) { - // if we are already in fullscreen do not switch back and forth, just - // set the size values right. - vo->dwidth = vo->opts->vo_screenwidth; - vo->dheight = vo->opts->vo_screenheight; - } -final: - if (x11->vo_gc != None) - XFreeGC(mDisplay, x11->vo_gc); - x11->vo_gc = XCreateGC(mDisplay, x11->window, 0, NULL); - - XSync(mDisplay, False); - vo->event_fd = ConnectionNumber(x11->display); -} - -void vo_x11_clearwindow_part(struct vo *vo, Window vo_window, - int img_width, int img_height) -{ - struct vo_x11_state *x11 = vo->x11; - Display *mDisplay = vo->x11->display; - int u_dheight, u_dwidth, left_ov, left_ov2; - - if (x11->f_gc == None) - return; - - u_dheight = vo->dheight; - u_dwidth = vo->dwidth; - if ((u_dheight <= img_height) && (u_dwidth <= img_width)) - return; - - left_ov = (u_dheight - img_height) / 2; - left_ov2 = (u_dwidth - img_width) / 2; - - XFillRectangle(mDisplay, vo_window, x11->f_gc, 0, 0, u_dwidth, left_ov); - XFillRectangle(mDisplay, vo_window, x11->f_gc, 0, u_dheight - left_ov - 1, - u_dwidth, left_ov + 1); - - if (u_dwidth > img_width) - { - XFillRectangle(mDisplay, vo_window, x11->f_gc, 0, left_ov, left_ov2, - img_height); - XFillRectangle(mDisplay, vo_window, x11->f_gc, u_dwidth - left_ov2 - 1, - left_ov, left_ov2 + 1, img_height); - } - - XFlush(mDisplay); -} - -void vo_x11_clearwindow(struct vo *vo, Window vo_window) -{ - struct vo_x11_state *x11 = vo->x11; - struct MPOpts *opts = vo->opts; - if (x11->f_gc == None) - return; - XFillRectangle(x11->display, vo_window, x11->f_gc, 0, 0, - opts->vo_screenwidth, opts->vo_screenheight); - // - XFlush(x11->display); -} - - -void vo_x11_setlayer(struct vo *vo, Window vo_window, int layer) -{ - struct vo_x11_state *x11 = vo->x11; - if (WinID >= 0) - return; - - if (x11->fs_type & vo_wm_LAYER) - { - XClientMessageEvent xev; - - if (!x11->orig_layer) - x11->orig_layer = vo_x11_get_gnome_layer(x11, vo_window); - - memset(&xev, 0, sizeof(xev)); - xev.type = ClientMessage; - xev.display = x11->display; - xev.window = vo_window; - xev.message_type = x11->XA_WIN_LAYER; - xev.format = 32; - xev.data.l[0] = layer ? fs_layer : x11->orig_layer; // if not fullscreen, stay on default layer - xev.data.l[1] = CurrentTime; - mp_msg(MSGT_VO, MSGL_V, - "[x11] Layered style stay on top (layer %ld).\n", - xev.data.l[0]); - XSendEvent(x11->display, x11->rootwin, False, SubstructureNotifyMask, - (XEvent *) & xev); - } else if (x11->fs_type & vo_wm_NETWM) - { - XClientMessageEvent xev; - char *state; - - memset(&xev, 0, sizeof(xev)); - xev.type = ClientMessage; - xev.message_type = x11->XA_NET_WM_STATE; - xev.display = x11->display; - xev.window = vo_window; - xev.format = 32; - xev.data.l[0] = layer; - - if (x11->fs_type & vo_wm_STAYS_ON_TOP) - xev.data.l[1] = x11->XA_NET_WM_STATE_STAYS_ON_TOP; - else if (x11->fs_type & vo_wm_ABOVE) - xev.data.l[1] = x11->XA_NET_WM_STATE_ABOVE; - else if (x11->fs_type & vo_wm_FULLSCREEN) - xev.data.l[1] = x11->XA_NET_WM_STATE_FULLSCREEN; - else if (x11->fs_type & vo_wm_BELOW) - // This is not fallback. We can safely assume that the situation - // where only NETWM_STATE_BELOW is supported doesn't exist. - xev.data.l[1] = x11->XA_NET_WM_STATE_BELOW; - - XSendEvent(x11->display, x11->rootwin, False, SubstructureRedirectMask, - (XEvent *) & xev); - state = XGetAtomName(x11->display, xev.data.l[1]); - mp_msg(MSGT_VO, MSGL_V, - "[x11] NET style stay on top (layer %d). Using state %s.\n", - layer, state); - XFree(state); - } -} - -static int vo_x11_get_fs_type(int supported) -{ - int i; - int type = supported; - - if (vo_fstype_list) - { - for (i = 0; vo_fstype_list[i]; i++) - { - int neg = 0; - char *arg = vo_fstype_list[i]; - - if (vo_fstype_list[i][0] == '-') - { - neg = 1; - arg = vo_fstype_list[i] + 1; - } - - if (!strncmp(arg, "layer", 5)) - { - if (!neg && (arg[5] == '=')) - { - char *endptr = NULL; - int layer = strtol(vo_fstype_list[i] + 6, &endptr, 10); - - if (endptr && *endptr == '\0' && layer >= 0 - && layer <= 15) - fs_layer = layer; - } - if (neg) - type &= ~vo_wm_LAYER; - else - type |= vo_wm_LAYER; - } else if (!strcmp(arg, "above")) - { - if (neg) - type &= ~vo_wm_ABOVE; - else - type |= vo_wm_ABOVE; - } else if (!strcmp(arg, "fullscreen")) - { - if (neg) - type &= ~vo_wm_FULLSCREEN; - else - type |= vo_wm_FULLSCREEN; - } else if (!strcmp(arg, "stays_on_top")) - { - if (neg) - type &= ~vo_wm_STAYS_ON_TOP; - else - type |= vo_wm_STAYS_ON_TOP; - } else if (!strcmp(arg, "below")) - { - if (neg) - type &= ~vo_wm_BELOW; - else - type |= vo_wm_BELOW; - } else if (!strcmp(arg, "netwm")) - { - if (neg) - type &= ~vo_wm_NETWM; - else - type |= vo_wm_NETWM; - } else if (!strcmp(arg, "none")) - type = 0; // clear; keep parsing - } - } - - return type; -} - -/** - * \brief update vo->dx, vo->dy, vo->dwidth and vo->dheight with current values of vo->x11->window - * \return returns current color depth of vo->x11->window - */ -int vo_x11_update_geometry(struct vo *vo, bool update_pos) -{ - struct vo_x11_state *x11 = vo->x11; - unsigned depth, w, h; - int dummy_int; - Window dummy_win; - XGetGeometry(x11->display, x11->window, &dummy_win, &dummy_int, &dummy_int, - &w, &h, &dummy_int, &depth); - if (w <= INT_MAX && h <= INT_MAX) { - vo->dwidth = w; - vo->dheight = h; - } - if (update_pos) - XTranslateCoordinates(x11->display, x11->window, x11->rootwin, 0, 0, - &vo->dx, &vo->dy, &dummy_win); - - return depth <= INT_MAX ? depth : 0; -} - -void vo_x11_fullscreen(struct vo *vo) -{ - struct MPOpts *opts = vo->opts; - struct vo_x11_state *x11 = vo->x11; - int x, y, w, h; - x = x11->vo_old_x; - y = x11->vo_old_y; - w = x11->vo_old_width; - h = x11->vo_old_height; - - if (WinID >= 0) { - vo_fs = !vo_fs; - return; - } - if (x11->fs_flip) - return; - - if (vo_fs) - { - vo_x11_ewmh_fullscreen(x11, _NET_WM_STATE_REMOVE); // removes fullscreen state if wm supports EWMH - vo_fs = VO_FALSE; - if (x11->size_changed_during_fs && (x11->fs_type & vo_wm_FULLSCREEN)) - vo_x11_nofs_sizepos(vo, vo->dx, vo->dy, x11->last_video_width, - x11->last_video_height); - x11->size_changed_during_fs = false; - } else - { - // win->fs - vo_x11_ewmh_fullscreen(x11, _NET_WM_STATE_ADD); // sends fullscreen state to be added if wm supports EWMH - - vo_fs = VO_TRUE; - if ( ! (x11->fs_type & vo_wm_FULLSCREEN) ) // not needed with EWMH fs - { - x11->vo_old_x = vo->dx; - x11->vo_old_y = vo->dy; - x11->vo_old_width = vo->dwidth; - x11->vo_old_height = vo->dheight; - } - update_xinerama_info(vo); - x = xinerama_x; - y = xinerama_y; - w = opts->vo_screenwidth; - h = opts->vo_screenheight; - } - { - long dummy; - - XGetWMNormalHints(x11->display, x11->window, &x11->vo_hint, &dummy); - if (!(x11->vo_hint.flags & PWinGravity)) - x11->old_gravity = NorthWestGravity; - else - x11->old_gravity = x11->vo_hint.win_gravity; - } - if (x11->wm_type == 0 && !(vo_fsmode & 16)) - { - XUnmapWindow(x11->display, x11->window); // required for MWM - XWithdrawWindow(x11->display, x11->window, x11->screen); - x11->fs_flip = 1; - } - - if ( ! (x11->fs_type & vo_wm_FULLSCREEN) ) // not needed with EWMH fs - { - vo_x11_decoration(vo, vo_border && !vo_fs); - vo_x11_sizehint(vo, x, y, w, h, 0); - vo_x11_setlayer(vo, x11->window, vo_fs); - - - XMoveResizeWindow(x11->display, x11->window, x, y, w, h); - } - /* some WMs lose ontop after fullscreen */ - if ((!(vo_fs)) & opts->vo_ontop) - vo_x11_setlayer(vo, x11->window, opts->vo_ontop); - - XMapRaised(x11->display, x11->window); - if ( ! (x11->fs_type & vo_wm_FULLSCREEN) ) // some WMs change window pos on map - XMoveResizeWindow(x11->display, x11->window, x, y, w, h); - XRaiseWindow(x11->display, x11->window); - XFlush(x11->display); -} - -void vo_x11_ontop(struct vo *vo) -{ - struct MPOpts *opts = vo->opts; - opts->vo_ontop = !opts->vo_ontop; - - vo_x11_setlayer(vo, vo->x11->window, opts->vo_ontop); -} - -void vo_x11_border(struct vo *vo) -{ - vo_border = !vo_border; - vo_x11_decoration(vo, vo_border && !vo_fs); -} - -/* - * XScreensaver stuff - */ - -static int screensaver_off; -static unsigned int time_last; - -void xscreensaver_heartbeat(struct vo_x11_state *x11) -{ - unsigned int time = GetTimerMS(); - - if (x11->display && screensaver_off && (time - time_last) > 30000) - { - time_last = time; - - XResetScreenSaver(x11->display); - } -} - -static int xss_suspend(Display *mDisplay, Bool suspend) -{ -#ifndef CONFIG_XSS - return 0; -#else - int event, error, major, minor; - if (XScreenSaverQueryExtension(mDisplay, &event, &error) != True || - XScreenSaverQueryVersion(mDisplay, &major, &minor) != True) - return 0; - if (major < 1 || (major == 1 && minor < 1)) - return 0; - XScreenSaverSuspend(mDisplay, suspend); - return 1; -#endif -} - -/* - * End of XScreensaver stuff - */ - -static void saver_on(Display * mDisplay) -{ - - if (!screensaver_off) - return; - screensaver_off = 0; - if (xss_suspend(mDisplay, False)) - return; -#ifdef CONFIG_XDPMS - if (dpms_disabled) - { - int nothing; - if (DPMSQueryExtension(mDisplay, ¬hing, ¬hing)) - { - if (!DPMSEnable(mDisplay)) - { // restoring power saving settings - mp_msg(MSGT_VO, MSGL_WARN, "DPMS not available?\n"); - } else - { - // DPMS does not seem to be enabled unless we call DPMSInfo - BOOL onoff; - CARD16 state; - - DPMSForceLevel(mDisplay, DPMSModeOn); - DPMSInfo(mDisplay, &state, &onoff); - if (onoff) - { - mp_msg(MSGT_VO, MSGL_V, - "Successfully enabled DPMS\n"); - } else - { - mp_msg(MSGT_VO, MSGL_WARN, "Could not enable DPMS\n"); - } - } - } - dpms_disabled = 0; - } -#endif -} - -static void saver_off(Display * mDisplay) -{ - int nothing; - - if (!stop_xscreensaver || screensaver_off) - return; - screensaver_off = 1; - if (xss_suspend(mDisplay, True)) - return; -#ifdef CONFIG_XDPMS - if (DPMSQueryExtension(mDisplay, ¬hing, ¬hing)) - { - BOOL onoff; - CARD16 state; - - DPMSInfo(mDisplay, &state, &onoff); - if (onoff) - { - Status stat; - - mp_msg(MSGT_VO, MSGL_V, "Disabling DPMS\n"); - dpms_disabled = 1; - stat = DPMSDisable(mDisplay); // monitor powersave off - mp_msg(MSGT_VO, MSGL_V, "DPMSDisable stat: %d\n", stat); - } - } -#endif -} - -static XErrorHandler old_handler = NULL; -static int selectinput_err = 0; -static int x11_selectinput_errorhandler(Display * display, - XErrorEvent * event) -{ - if (event->error_code == BadAccess) - { - selectinput_err = 1; - mp_msg(MSGT_VO, MSGL_ERR, - "X11 error: BadAccess during XSelectInput Call\n"); - mp_msg(MSGT_VO, MSGL_ERR, - "X11 error: The 'ButtonPressMask' mask of specified window has probably already used by another appication (see man XSelectInput)\n"); - /* If you think MPlayer should shutdown with this error, - * comment out the following line */ - return 0; - } - if (old_handler != NULL) - old_handler(display, event); - else - x11_errorhandler(display, event); - return 0; -} - -void vo_x11_selectinput_witherr(Display * display, Window w, - long event_mask) -{ - XSync(display, False); - old_handler = XSetErrorHandler(x11_selectinput_errorhandler); - selectinput_err = 0; - if (vo_nomouse_input) - { - XSelectInput(display, w, - event_mask & - (~(ButtonPressMask | ButtonReleaseMask))); - } else - { - XSelectInput(display, w, event_mask); - } - XSync(display, False); - XSetErrorHandler(old_handler); - if (selectinput_err) - { - mp_msg(MSGT_VO, MSGL_ERR, - "X11 error: mpv discards mouse control (reconfiguring)\n"); - XSelectInput(display, w, - event_mask & - (~ - (ButtonPressMask | ButtonReleaseMask | - PointerMotionMask))); - } -} - -#ifdef CONFIG_XF86VM -void vo_vm_switch(struct vo *vo) -{ - struct vo_x11_state *x11 = vo->x11; - struct MPOpts *opts = vo->opts; - Display *mDisplay = x11->display; - int vm_event, vm_error; - int vm_ver, vm_rev; - int i, j, have_vm = 0; - int X = vo->dwidth, Y = vo->dheight; - int modeline_width, modeline_height; - - if (XF86VidModeQueryExtension(mDisplay, &vm_event, &vm_error)) - { - XF86VidModeQueryVersion(mDisplay, &vm_ver, &vm_rev); - mp_msg(MSGT_VO, MSGL_V, "XF86VidMode extension v%i.%i\n", vm_ver, - vm_rev); - have_vm = 1; - } else { - mp_msg(MSGT_VO, MSGL_WARN, - "XF86VidMode extension not available.\n"); - } - - if (have_vm) - { - if (vidmodes == NULL) - XF86VidModeGetAllModeLines(mDisplay, x11->screen, &modecount, - &vidmodes); - j = 0; - modeline_width = vidmodes[0]->hdisplay; - modeline_height = vidmodes[0]->vdisplay; - - for (i = 1; i < modecount; i++) - if ((vidmodes[i]->hdisplay >= X) - && (vidmodes[i]->vdisplay >= Y)) - if ((vidmodes[i]->hdisplay <= modeline_width) - && (vidmodes[i]->vdisplay <= modeline_height)) - { - modeline_width = vidmodes[i]->hdisplay; - modeline_height = vidmodes[i]->vdisplay; - j = i; - } - - mp_tmsg(MSGT_VO, MSGL_INFO, "XF86VM: Selected video mode %dx%d for image size %dx%d.\n", - modeline_width, modeline_height, X, Y); - XF86VidModeLockModeSwitch(mDisplay, x11->screen, 0); - XF86VidModeSwitchToMode(mDisplay, x11->screen, vidmodes[j]); - XF86VidModeSwitchToMode(mDisplay, x11->screen, vidmodes[j]); - - // FIXME: all this is more of a hack than proper solution - X = (opts->vo_screenwidth - modeline_width) / 2; - Y = (opts->vo_screenheight - modeline_height) / 2; - XF86VidModeSetViewPort(mDisplay, x11->screen, X, Y); - vo->dx = X; - vo->dy = Y; - vo->dwidth = modeline_width; - vo->dheight = modeline_height; - aspect_save_screenres(vo, modeline_width, modeline_height); - } -} - -void vo_vm_close(struct vo *vo) -{ - Display *dpy = vo->x11->display; - struct MPOpts *opts = vo->opts; - if (vidmodes != NULL) - { - int i; - - free(vidmodes); - vidmodes = NULL; - XF86VidModeGetAllModeLines(dpy, vo->x11->screen, &modecount, - &vidmodes); - for (i = 0; i < modecount; i++) - if ((vidmodes[i]->hdisplay == opts->vo_screenwidth) - && (vidmodes[i]->vdisplay == opts->vo_screenheight)) - { - mp_msg(MSGT_VO, MSGL_INFO, - "Returning to original mode %dx%d\n", - opts->vo_screenwidth, opts->vo_screenheight); - break; - } - - XF86VidModeSwitchToMode(dpy, vo->x11->screen, vidmodes[i]); - XF86VidModeSwitchToMode(dpy, vo->x11->screen, vidmodes[i]); - free(vidmodes); - vidmodes = NULL; - modecount = 0; - } -} - -double vo_vm_get_fps(struct vo *vo) -{ - struct vo_x11_state *x11 = vo->x11; - int clock; - XF86VidModeModeLine modeline; - if (!XF86VidModeGetModeLine(x11->display, x11->screen, &clock, &modeline)) - return 0; - if (modeline.privsize) - XFree(modeline.private); - return 1e3 * clock / modeline.htotal / modeline.vtotal; -} -#endif - - -/* - * Scan the available visuals on this Display/Screen. Try to find - * the 'best' available TrueColor visual that has a decent color - * depth (at least 15bit). If there are multiple visuals with depth - * >= 15bit, we prefer visuals with a smaller color depth. - */ -int vo_find_depth_from_visuals(Display * dpy, int screen, - Visual ** visual_return) -{ - XVisualInfo visual_tmpl; - XVisualInfo *visuals; - int nvisuals, i; - int bestvisual = -1; - int bestvisual_depth = -1; - - visual_tmpl.screen = screen; - visual_tmpl.class = TrueColor; - visuals = XGetVisualInfo(dpy, - VisualScreenMask | VisualClassMask, - &visual_tmpl, &nvisuals); - if (visuals != NULL) - { - for (i = 0; i < nvisuals; i++) - { - mp_msg(MSGT_VO, MSGL_V, - "vo: X11 truecolor visual %#lx, depth %d, R:%lX G:%lX B:%lX\n", - visuals[i].visualid, visuals[i].depth, - visuals[i].red_mask, visuals[i].green_mask, - visuals[i].blue_mask); - /* - * Save the visual index and its depth, if this is the first - * truecolor visul, or a visual that is 'preferred' over the - * previous 'best' visual. - */ - if (bestvisual_depth == -1 - || (visuals[i].depth >= 15 - && (visuals[i].depth < bestvisual_depth - || bestvisual_depth < 15))) - { - bestvisual = i; - bestvisual_depth = visuals[i].depth; - } - } - - if (bestvisual != -1 && visual_return != NULL) - *visual_return = visuals[bestvisual].visual; - - XFree(visuals); - } - return bestvisual_depth; -} - - -static Colormap cmap = None; -static XColor cols[256]; -static int cm_size, red_mask, green_mask, blue_mask; - - -Colormap vo_x11_create_colormap(struct vo *vo, XVisualInfo *vinfo) -{ - struct vo_x11_state *x11 = vo->x11; - unsigned k, r, g, b, ru, gu, bu, m, rv, gv, bv, rvu, gvu, bvu; - - if (vinfo->class != DirectColor) - return XCreateColormap(x11->display, x11->rootwin, vinfo->visual, - AllocNone); - - /* can this function get called twice or more? */ - if (cmap) - return cmap; - cm_size = vinfo->colormap_size; - red_mask = vinfo->red_mask; - green_mask = vinfo->green_mask; - blue_mask = vinfo->blue_mask; - ru = (red_mask & (red_mask - 1)) ^ red_mask; - gu = (green_mask & (green_mask - 1)) ^ green_mask; - bu = (blue_mask & (blue_mask - 1)) ^ blue_mask; - rvu = 65536ull * ru / (red_mask + ru); - gvu = 65536ull * gu / (green_mask + gu); - bvu = 65536ull * bu / (blue_mask + bu); - r = g = b = 0; - rv = gv = bv = 0; - m = DoRed | DoGreen | DoBlue; - for (k = 0; k < cm_size; k++) - { - int t; - - cols[k].pixel = r | g | b; - cols[k].red = rv; - cols[k].green = gv; - cols[k].blue = bv; - cols[k].flags = m; - t = (r + ru) & red_mask; - if (t < r) - m &= ~DoRed; - r = t; - t = (g + gu) & green_mask; - if (t < g) - m &= ~DoGreen; - g = t; - t = (b + bu) & blue_mask; - if (t < b) - m &= ~DoBlue; - b = t; - rv += rvu; - gv += gvu; - bv += bvu; - } - cmap = XCreateColormap(x11->display, x11->rootwin, vinfo->visual, AllocAll); - XStoreColors(x11->display, cmap, cols, cm_size); - return cmap; -} - -/* - * Via colormaps/gamma ramps we can do gamma, brightness, contrast, - * hue and red/green/blue intensity, but we cannot do saturation. - * Currently only gamma, brightness and contrast are implemented. - * Is there sufficient interest for hue and/or red/green/blue intensity? - */ -/* these values have range [-100,100] and are initially 0 */ -static int vo_gamma = 0; -static int vo_brightness = 0; -static int vo_contrast = 0; - -static int transform_color(float val, - float brightness, float contrast, float gamma) { - float s = pow(val, gamma); - s = (s - 0.5) * contrast + 0.5; - s += brightness; - if (s < 0) - s = 0; - if (s > 1) - s = 1; - return (unsigned short) (s * 65535); -} - -uint32_t vo_x11_set_equalizer(struct vo *vo, const char *name, int value) -{ - float gamma, brightness, contrast; - float rf, gf, bf; - int k; - - /* - * IMPLEMENTME: consider using XF86VidModeSetGammaRamp in the case - * of TrueColor-ed window but be careful: - * Unlike the colormaps, which are private for the X client - * who created them and thus automatically destroyed on client - * disconnect, this gamma ramp is a system-wide (X-server-wide) - * setting and _must_ be restored before the process exits. - * Unforunately when the process crashes (or gets killed - * for some reason) it is impossible to restore the setting, - * and such behaviour could be rather annoying for the users. - */ - if (cmap == None) - return VO_NOTAVAIL; - - if (!strcasecmp(name, "brightness")) - vo_brightness = value; - else if (!strcasecmp(name, "contrast")) - vo_contrast = value; - else if (!strcasecmp(name, "gamma")) - vo_gamma = value; - else - return VO_NOTIMPL; - - brightness = 0.01 * vo_brightness; - contrast = tan(0.0095 * (vo_contrast + 100) * M_PI / 4); - gamma = pow(2, -0.02 * vo_gamma); - - rf = (float) ((red_mask & (red_mask - 1)) ^ red_mask) / red_mask; - gf = (float) ((green_mask & (green_mask - 1)) ^ green_mask) / - green_mask; - bf = (float) ((blue_mask & (blue_mask - 1)) ^ blue_mask) / blue_mask; - - /* now recalculate the colormap using the newly set value */ - for (k = 0; k < cm_size; k++) - { - cols[k].red = transform_color(rf * k, brightness, contrast, gamma); - cols[k].green = transform_color(gf * k, brightness, contrast, gamma); - cols[k].blue = transform_color(bf * k, brightness, contrast, gamma); - } - - XStoreColors(vo->x11->display, cmap, cols, cm_size); - XFlush(vo->x11->display); - return VO_TRUE; -} - -uint32_t vo_x11_get_equalizer(const char *name, int *value) -{ - if (cmap == None) - return VO_NOTAVAIL; - if (!strcasecmp(name, "brightness")) - *value = vo_brightness; - else if (!strcasecmp(name, "contrast")) - *value = vo_contrast; - else if (!strcasecmp(name, "gamma")) - *value = vo_gamma; - else - return VO_NOTIMPL; - return VO_TRUE; -} - -bool vo_x11_screen_is_composited(struct vo *vo) -{ - struct vo_x11_state *x11 = vo->x11; - return XGetSelectionOwner(x11->display, x11->XA_NET_WM_CM) != None; -} - -#ifdef CONFIG_XV - -static int xv_find_atom(struct vo *vo, uint32_t xv_port, const char *name, - bool get, int *min, int *max) -{ - Atom atom = None; - int howmany = 0; - XvAttribute *attributes = XvQueryPortAttributes(vo->x11->display, xv_port, - &howmany); - for (int i = 0; i < howmany && attributes; i++) { - int flag = get ? XvGettable : XvSettable; - if (attributes[i].flags & flag) { - atom = XInternAtom(vo->x11->display, attributes[i].name, True); - *min = attributes[i].min_value; - *max = attributes[i].max_value; -/* since we have SET_DEFAULTS first in our list, we can check if it's available - then trigger it if it's ok so that the other values are at default upon query */ - if (atom != None) { - if (!strcmp(attributes[i].name, "XV_BRIGHTNESS") && - (!strcasecmp(name, "brightness"))) - break; - else if (!strcmp(attributes[i].name, "XV_CONTRAST") && - (!strcasecmp(name, "contrast"))) - break; - else if (!strcmp(attributes[i].name, "XV_SATURATION") && - (!strcasecmp(name, "saturation"))) - break; - else if (!strcmp(attributes[i].name, "XV_HUE") && - (!strcasecmp(name, "hue"))) - break; - if (!strcmp(attributes[i].name, "XV_RED_INTENSITY") && - (!strcasecmp(name, "red_intensity"))) - break; - else if (!strcmp(attributes[i].name, "XV_GREEN_INTENSITY") - && (!strcasecmp(name, "green_intensity"))) - break; - else if (!strcmp(attributes[i].name, "XV_BLUE_INTENSITY") - && (!strcasecmp(name, "blue_intensity"))) - break; - else if ((!strcmp(attributes[i].name, "XV_ITURBT_709") //NVIDIA - || !strcmp(attributes[i].name, "XV_COLORSPACE"))//ATI - && (!strcasecmp(name, "bt_709"))) - break; - atom = None; - continue; - } - } - } - XFree(attributes); - return atom; -} - -int vo_xv_set_eq(struct vo *vo, uint32_t xv_port, const char *name, int value) -{ - mp_dbg(MSGT_VO, MSGL_V, "xv_set_eq called! (%s, %d)\n", name, value); - - int min, max; - int atom = xv_find_atom(vo, xv_port, name, false, &min, &max); - if (atom != None) { - // -100 -> min - // 0 -> (max+min)/2 - // +100 -> max - int port_value = (value + 100) * (max - min) / 200 + min; - XvSetPortAttribute(vo->x11->display, xv_port, atom, port_value); - return VO_TRUE; - } - return VO_FALSE; -} - -int vo_xv_get_eq(struct vo *vo, uint32_t xv_port, const char *name, int *value) -{ - int min, max; - int atom = xv_find_atom(vo, xv_port, name, true, &min, &max); - if (atom != None) { - int port_value = 0; - XvGetPortAttribute(vo->x11->display, xv_port, atom, &port_value); - - *value = (port_value - min) * 200 / (max - min) - 100; - mp_dbg(MSGT_VO, MSGL_V, "xv_get_eq called! (%s, %d)\n", - name, *value); - return VO_TRUE; - } - return VO_FALSE; -} - -/** - * \brief Interns the requested atom if it is available. - * - * \param atom_name String containing the name of the requested atom. - * - * \return Returns the atom if available, else None is returned. - * - */ -static Atom xv_intern_atom_if_exists(struct vo_x11_state *x11, - char const *atom_name) -{ - XvAttribute * attributes; - int attrib_count,i; - Atom xv_atom = None; - - attributes = XvQueryPortAttributes(x11->display, x11->xv_port, &attrib_count ); - if( attributes!=NULL ) - { - for ( i = 0; i < attrib_count; ++i ) - { - if ( strcmp(attributes[i].name, atom_name ) == 0 ) - { - xv_atom = XInternAtom(x11->display, atom_name, False ); - break; // found what we want, break out - } - } - XFree( attributes ); - } - - return xv_atom; -} - -/** - * \brief Try to enable vsync for xv. - * \return Returns -1 if not available, 0 on failure and 1 on success. - */ -int vo_xv_enable_vsync(struct vo *vo) -{ - struct vo_x11_state *x11 = vo->x11; - Atom xv_atom = xv_intern_atom_if_exists(x11, "XV_SYNC_TO_VBLANK"); - if (xv_atom == None) - return -1; - return XvSetPortAttribute(x11->display, x11->xv_port, xv_atom, 1) == Success; -} - -/** - * \brief Get maximum supported source image dimensions. - * - * This function does not set the variables pointed to by - * width and height if the information could not be retrieved, - * so the caller is reponsible for properly initializing them. - * - * \param width [out] The maximum width gets stored here. - * \param height [out] The maximum height gets stored here. - * - */ -void vo_xv_get_max_img_dim(struct vo *vo, uint32_t * width, uint32_t * height) -{ - struct vo_x11_state *x11 = vo->x11; - XvEncodingInfo * encodings; - //unsigned long num_encodings, idx; to int or too long?! - unsigned int num_encodings, idx; - - XvQueryEncodings(x11->display, x11->xv_port, &num_encodings, &encodings); - - if ( encodings ) - { - for ( idx = 0; idx < num_encodings; ++idx ) - { - if ( strcmp( encodings[idx].name, "XV_IMAGE" ) == 0 ) - { - *width = encodings[idx].width; - *height = encodings[idx].height; - break; - } - } - } - - mp_msg( MSGT_VO, MSGL_V, - "[xv common] Maximum source image dimensions: %ux%u\n", - *width, *height ); - - XvFreeEncodingInfo( encodings ); -} - -/** - * \brief Print information about the colorkey method and source. - * - * \param ck_handling Integer value containing the information about - * colorkey handling (see x11_common.h). - * - * Outputs the content of |ck_handling| as a readable message. - * - */ -static void vo_xv_print_ck_info(struct vo_x11_state *x11) -{ - mp_msg( MSGT_VO, MSGL_V, "[xv common] " ); - - switch ( x11->xv_ck_info.method ) - { - case CK_METHOD_NONE: - mp_msg( MSGT_VO, MSGL_V, "Drawing no colorkey.\n" ); return; - case CK_METHOD_AUTOPAINT: - mp_msg( MSGT_VO, MSGL_V, "Colorkey is drawn by Xv." ); break; - case CK_METHOD_MANUALFILL: - mp_msg( MSGT_VO, MSGL_V, "Drawing colorkey manually." ); break; - case CK_METHOD_BACKGROUND: - mp_msg( MSGT_VO, MSGL_V, "Colorkey is drawn as window background." ); break; - } - - mp_msg( MSGT_VO, MSGL_V, "\n[xv common] " ); - - switch ( x11->xv_ck_info.source ) - { - case CK_SRC_CUR: - mp_msg( MSGT_VO, MSGL_V, "Using colorkey from Xv (0x%06lx).\n", - x11->xv_colorkey ); - break; - case CK_SRC_USE: - if ( x11->xv_ck_info.method == CK_METHOD_AUTOPAINT ) - { - mp_msg( MSGT_VO, MSGL_V, - "Ignoring colorkey from mpv (0x%06lx).\n", - x11->xv_colorkey ); - } - else - { - mp_msg( MSGT_VO, MSGL_V, - "Using colorkey from mpv (0x%06lx)." - " Use -colorkey to change.\n", - x11->xv_colorkey ); - } - break; - case CK_SRC_SET: - mp_msg( MSGT_VO, MSGL_V, - "Setting and using colorkey from mpv (0x%06lx)." - " Use -colorkey to change.\n", - x11->xv_colorkey ); - break; - } -} -/** - * \brief Init colorkey depending on the settings in xv_ck_info. - * - * \return Returns 0 on failure and 1 on success. - * - * Sets the colorkey variable according to the CK_SRC_* and CK_METHOD_* - * flags in xv_ck_info. - * - * Possiblilities: - * * Methods - * - manual colorkey drawing ( CK_METHOD_MANUALFILL ) - * - set colorkey as window background ( CK_METHOD_BACKGROUND ) - * - let Xv paint the colorkey ( CK_METHOD_AUTOPAINT ) - * * Sources - * - use currently set colorkey ( CK_SRC_CUR ) - * - use colorkey in vo_colorkey ( CK_SRC_USE ) - * - use and set colorkey in vo_colorkey ( CK_SRC_SET ) - * - * NOTE: If vo_colorkey has bits set after the first 3 low order bytes - * we don't draw anything as this means it was forced to off. - */ -int vo_xv_init_colorkey(struct vo *vo) -{ - struct vo_x11_state *x11 = vo->x11; - Atom xv_atom; - int rez; - - /* check if colorkeying is needed */ - xv_atom = xv_intern_atom_if_exists(vo->x11, "XV_COLORKEY"); - - /* if we have to deal with colorkeying ... */ - if( xv_atom != None && !(vo_colorkey & 0xFF000000) ) - { - /* check if we should use the colorkey specified in vo_colorkey */ - if ( x11->xv_ck_info.source != CK_SRC_CUR ) - { - x11->xv_colorkey = vo_colorkey; - - /* check if we have to set the colorkey too */ - if ( x11->xv_ck_info.source == CK_SRC_SET ) - { - xv_atom = XInternAtom(x11->display, "XV_COLORKEY",False); - - rez = XvSetPortAttribute(x11->display, x11->xv_port, xv_atom, vo_colorkey); - if ( rez != Success ) - { - mp_msg( MSGT_VO, MSGL_FATAL, - "[xv common] Couldn't set colorkey!\n" ); - return 0; // error setting colorkey - } - } - } - else - { - int colorkey_ret; - - rez=XvGetPortAttribute(x11->display,x11->xv_port, xv_atom, &colorkey_ret); - if ( rez == Success ) - { - x11->xv_colorkey = colorkey_ret; - } - else - { - mp_msg( MSGT_VO, MSGL_FATAL, - "[xv common] Couldn't get colorkey!" - "Maybe the selected Xv port has no overlay.\n" ); - return 0; // error getting colorkey - } - } - - xv_atom = xv_intern_atom_if_exists(vo->x11, "XV_AUTOPAINT_COLORKEY"); - - /* should we draw the colorkey ourselves or activate autopainting? */ - if ( x11->xv_ck_info.method == CK_METHOD_AUTOPAINT ) - { - rez = !Success; // reset rez to something different than Success - - if ( xv_atom != None ) // autopaint is supported - { - rez = XvSetPortAttribute(x11->display, x11->xv_port, xv_atom, 1); - } - - if ( rez != Success ) - { - // fallback to manual colorkey drawing - x11->xv_ck_info.method = CK_METHOD_MANUALFILL; - } - } - else // disable colorkey autopainting if supported - { - if ( xv_atom != None ) // we have autopaint attribute - { - XvSetPortAttribute(x11->display, x11->xv_port, xv_atom, 0); - } - } - } - else // do no colorkey drawing at all - { - x11->xv_ck_info.method = CK_METHOD_NONE; - } /* end: should we draw colorkey */ - - /* output information about the current colorkey settings */ - vo_xv_print_ck_info(x11); - - return 1; // success -} - -/** - * \brief Draw the colorkey on the video window. - * - * Draws the colorkey depending on the set method ( colorkey_handling ). - * - * Also draws the black bars ( when the video doesn't fit the display in - * fullscreen ) separately, so they don't overlap with the video area. - * It doesn't call XFlush. - * - */ -void vo_xv_draw_colorkey(struct vo *vo, int32_t x, int32_t y, - int32_t w, int32_t h) -{ - struct vo_x11_state *x11 = vo->x11; - if( x11->xv_ck_info.method == CK_METHOD_MANUALFILL || - x11->xv_ck_info.method == CK_METHOD_BACKGROUND )//less tearing than XClearWindow() - { - XSetForeground(x11->display, x11->vo_gc, x11->xv_colorkey ); - XFillRectangle(x11->display, x11->window, x11->vo_gc, - x, y, - w, h ); - } -} - -/** \brief Tests if a valid argument for the ck suboption was given. */ -int xv_test_ck( void * arg ) -{ - strarg_t * strarg = (strarg_t *)arg; - - if ( strargcmp( strarg, "use" ) == 0 || - strargcmp( strarg, "set" ) == 0 || - strargcmp( strarg, "cur" ) == 0 ) - { - return 1; - } - - return 0; -} -/** \brief Tests if a valid arguments for the ck-method suboption was given. */ -int xv_test_ckm( void * arg ) -{ - strarg_t * strarg = (strarg_t *)arg; - - if ( strargcmp( strarg, "bg" ) == 0 || - strargcmp( strarg, "man" ) == 0 || - strargcmp( strarg, "auto" ) == 0 ) - { - return 1; - } - - return 0; -} - -/** - * \brief Modify the colorkey_handling var according to str - * - * Checks if a valid pointer ( not NULL ) to the string - * was given. And in that case modifies the colorkey_handling - * var to reflect the requested behaviour. - * If nothing happens the content of colorkey_handling stays - * the same. - * - * \param str Pointer to the string or NULL - * - */ -void xv_setup_colorkeyhandling(struct vo *vo, const char *ck_method_str, - const char *ck_str) -{ - struct vo_x11_state *x11 = vo->x11; - /* check if a valid pointer to the string was passed */ - if ( ck_str ) - { - if ( strncmp( ck_str, "use", 3 ) == 0 ) - { - x11->xv_ck_info.source = CK_SRC_USE; - } - else if ( strncmp( ck_str, "set", 3 ) == 0 ) - { - x11->xv_ck_info.source = CK_SRC_SET; - } - } - /* check if a valid pointer to the string was passed */ - if ( ck_method_str ) - { - if ( strncmp( ck_method_str, "bg", 2 ) == 0 ) - { - x11->xv_ck_info.method = CK_METHOD_BACKGROUND; - } - else if ( strncmp( ck_method_str, "man", 3 ) == 0 ) - { - x11->xv_ck_info.method = CK_METHOD_MANUALFILL; - } - else if ( strncmp( ck_method_str, "auto", 4 ) == 0 ) - { - x11->xv_ck_info.method = CK_METHOD_AUTOPAINT; - } - } -} - -#endif - -struct vo_x11_state *vo_x11_init_state(void) -{ - struct vo_x11_state *s = talloc_ptrtype(NULL, s); - *s = (struct vo_x11_state){ - .xv_ck_info = { CK_METHOD_MANUALFILL, CK_SRC_CUR }, - .olddecor = MWM_DECOR_ALL, - .oldfuncs = MWM_FUNC_MOVE | MWM_FUNC_CLOSE | MWM_FUNC_MINIMIZE | - MWM_FUNC_MAXIMIZE | MWM_FUNC_RESIZE, - .old_gravity = NorthWestGravity, - }; - return s; -} diff --git a/libvo/x11_common.h b/libvo/x11_common.h deleted file mode 100644 index cb8b39a3b1..0000000000 --- a/libvo/x11_common.h +++ /dev/null @@ -1,184 +0,0 @@ -/* - * 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_X11_COMMON_H -#define MPLAYER_X11_COMMON_H - -#include <stdint.h> -#include <stdbool.h> -#include <X11/Xlib.h> -#include <X11/Xutil.h> - -#include "config.h" - -struct vo; - -struct vo_x11_state { - Display *display; - Window window; - Window rootwin; - int screen; - int display_is_local; - int depthonscreen; - - XIM xim; - XIC xic; - - GC vo_gc; - - struct xv_ck_info_s { - int method; ///< CK_METHOD_* constants - int source; ///< CK_SRC_* constants - } xv_ck_info; - unsigned long xv_colorkey; - unsigned int xv_port; - - int wm_type; - int fs_type; - int window_state; - int fs_flip; - - GC f_gc; - XSizeHints vo_hint; - unsigned int mouse_timer; - int mouse_waiting_hide; - int orig_layer; - int old_gravity; - int vo_old_x; - int vo_old_y; - int vo_old_width; - int vo_old_height; - - /* Keep track of original video width/height to determine when to - * resize window when reconfiguring. Resize window when video size - * changes, but don't force window size changes as long as video size - * stays the same (even if that size is different from the current - * window size after the user modified the latter). */ - int last_video_width; - int last_video_height; - /* Video size changed during fullscreen when we couldn't tell the new - * size to the window manager. Must set window size when turning - * fullscreen off. */ - bool size_changed_during_fs; - - unsigned int olddecor; - unsigned int oldfuncs; - XComposeStatus compose_status; - - Atom XA_NET_SUPPORTED; - Atom XA_NET_WM_STATE; - Atom XA_NET_WM_STATE_FULLSCREEN; - Atom XA_NET_WM_STATE_ABOVE; - Atom XA_NET_WM_STATE_STAYS_ON_TOP; - Atom XA_NET_WM_STATE_BELOW; - Atom XA_NET_WM_PID; - Atom XA_NET_WM_NAME; - Atom XA_NET_WM_ICON_NAME; - Atom XA_WIN_PROTOCOLS; - Atom XA_WIN_LAYER; - Atom XA_WIN_HINTS; - Atom XAWM_PROTOCOLS; - Atom XAWM_DELETE_WINDOW; - Atom XAUTF8_STRING; - Atom XA_NET_WM_CM; -}; - -#define vo_wm_LAYER 1 -#define vo_wm_FULLSCREEN 2 -#define vo_wm_STAYS_ON_TOP 4 -#define vo_wm_ABOVE 8 -#define vo_wm_BELOW 16 -#define vo_wm_NETWM (vo_wm_FULLSCREEN | vo_wm_STAYS_ON_TOP | vo_wm_ABOVE | vo_wm_BELOW) - -/* EWMH state actions, see - http://freedesktop.org/Standards/wm-spec/index.html#id2768769 */ -#define _NET_WM_STATE_REMOVE 0 /* remove/unset property */ -#define _NET_WM_STATE_ADD 1 /* add/set property */ -#define _NET_WM_STATE_TOGGLE 2 /* toggle property */ - -extern int metacity_hack; - -extern char** vo_fstype_list; - -extern char *mDisplayName; - -struct vo_x11_state *vo_x11_init_state(void); -int vo_init(struct vo *vo); -void vo_uninit(struct vo_x11_state *x11); -void vo_x11_decoration(struct vo *vo, int d ); -void vo_x11_classhint(struct vo *vo, Window window, const char *name); -void vo_x11_sizehint(struct vo *vo, int x, int y, int width, int height, int max); -int vo_x11_check_events(struct vo *vo); -void vo_x11_selectinput_witherr(Display *display, Window w, long event_mask); -void vo_x11_fullscreen(struct vo *vo); -int vo_x11_update_geometry(struct vo *vo, bool update_pos); -void vo_x11_setlayer(struct vo *vo, Window vo_window, int layer); -void vo_x11_uninit(struct vo *vo); -Colormap vo_x11_create_colormap(struct vo *vo, XVisualInfo *vinfo); -uint32_t vo_x11_set_equalizer(struct vo *vo, const char *name, int value); -uint32_t vo_x11_get_equalizer(const char *name, int *value); -bool vo_x11_screen_is_composited(struct vo *vo); -void fstype_help(void); -void vo_x11_create_vo_window(struct vo *vo, XVisualInfo *vis, - int x, int y, unsigned int width, unsigned int height, int flags, - Colormap col_map, const char *classname); -void vo_x11_clearwindow_part(struct vo *vo, Window vo_window, - int img_width, int img_height); -void vo_x11_clearwindow(struct vo *vo, Window vo_window); -void vo_x11_ontop(struct vo *vo); -void vo_x11_border(struct vo *vo); -void vo_x11_ewmh_fullscreen(struct vo_x11_state *x11, int action); - - -int vo_xv_set_eq(struct vo *vo, uint32_t xv_port, const char *name, int value); -int vo_xv_get_eq(struct vo *vo, uint32_t xv_port, const char *name, int *value); - -int vo_xv_enable_vsync(struct vo *vo); - -void vo_xv_get_max_img_dim(struct vo *vo, uint32_t * width, uint32_t * height); - -/*** colorkey handling ***/ - -#define CK_METHOD_NONE 0 ///< no colorkey drawing -#define CK_METHOD_BACKGROUND 1 ///< set colorkey as window background -#define CK_METHOD_AUTOPAINT 2 ///< let xv draw the colorkey -#define CK_METHOD_MANUALFILL 3 ///< manually draw the colorkey -#define CK_SRC_USE 0 ///< use specified / default colorkey -#define CK_SRC_SET 1 ///< use and set specified / default colorkey -#define CK_SRC_CUR 2 ///< use current colorkey ( get it from xv ) - -int vo_xv_init_colorkey(struct vo *vo); -void vo_xv_draw_colorkey(struct vo *vo, int32_t x, int32_t y, int32_t w, int32_t h); -void xv_setup_colorkeyhandling(struct vo *vo, const char *ck_method_str, const char *ck_str); - -/*** test functions for common suboptions ***/ -int xv_test_ck( void * arg ); -int xv_test_ckm( void * arg ); - -#ifdef CONFIG_XF86VM -void vo_vm_switch(struct vo *vo); -void vo_vm_close(struct vo *vo); -double vo_vm_get_fps(struct vo *vo); -#endif - -void update_xinerama_info(struct vo *vo); - -int vo_find_depth_from_visuals(Display *dpy, int screen, Visual **visual_return); -void xscreensaver_heartbeat(struct vo_x11_state *x11); - -#endif /* MPLAYER_X11_COMMON_H */ |