📄 video.c
字号:
/*** Sinek (Media Player)** Copyright (c) 2001-2002 Gurer Ozen**** This code is free software; you can redistribute it and/or** modify it under the terms of the GNU General Public License.**** video window*/#include "common.h"#include <gdk/gdkx.h>#include <X11/Xlib.h>#include <X11/Xutil.h>#include <X11/cursorfont.h>#include <X11/Xatom.h>#include <xine/video_out_x11.h>/* missing stuff from X includes */#define MWM_HINTS_DECORATIONS (1L << 1)#define PROP_MWM_HINTS_ELEMENTS 5typedef struct _mwmhints{ uint32_t flags; uint32_t functions; uint32_t decorations; int32_t input_mode; uint32_t status;} MWMHints;static int video_visible = 42;static XClassHint *xc_hint;// static XWMHints *wm_hint;static XSizeHints xs_hint;static Atom wm_delete_window;static int depth;static Visual *visual;static Window videowin;static Display *display;static int screen;static XColor black;static Colormap colormap = 0;static int xfred;static Cursor cursor[2];static void create_bg_window(void);static void find_best_visual(void);int translate_point(int x, int y, int *vid_x, int *vid_y);static void create_window(int fs, int w, int h);static sinek_x11_type display_info;static gboolean handle_event(GIOChannel *gio, GIOCondition cond, gpointer data);static GIOChannel *lala;static void frame_out_cb(void *user_data, sinek_x11_type *di){ sinek.vid_w = di->frame_w; sinek.vid_h = di->frame_h; di->out_x = 0; di->out_y = 0; di->out_w = di->win_w; di->out_h = di->win_h;}int video_init(void){ static unsigned char bm_no_data[] = { 0, 0, 0, 0, 0, 0, 0, 0 }; Pixmap bm_no; XColor dummy; int ret; if(sinek.video_display_name) { display = XOpenDisplay(sinek.video_display_name); if(!display) { printf("Cannot connect to display '%s'.\n", sinek.video_display_name); return 0; } XLockDisplay(display); screen = DefaultScreen(display); } else { display = XOpenDisplay(gdk_get_display()); XLockDisplay(display); screen = gdk_x11_get_default_screen(); } sinek.display = display; xfred = ConnectionNumber(display); find_best_visual(); sinek.depth = depth; XAllocNamedColor(display, DefaultColormap(display, screen), "black", &black, &dummy); xc_hint = XAllocClassHint(); if(xc_hint) { xc_hint->res_name = "video"; xc_hint->res_class = "sinek"; }/* wm_hint = XAllocWMHints(); if(!wm_hint) { printf(_("XAllocWMHints failed.\n")); return 0; }*/ wm_delete_window = XInternAtom(display, "WM_DELETE_WINDOW", False); lala = g_io_channel_unix_new(xfred); g_io_add_watch(lala, G_IO_IN, handle_event, NULL); bm_no = XCreateBitmapFromData(display, RootWindow(display, screen), bm_no_data, 8, 8); cursor[0] = XCreatePixmapCursor(display, bm_no, bm_no, &black, &black, 0, 0); cursor[1] = XCreateFontCursor(display, XC_left_ptr); sinek.vid_w = sinek.geo_w; sinek.vid_h = sinek.geo_h; video_set_mode(sinek.video_mode); display_info.display = display; display_info.screen = screen; display_info.drawable = videowin; display_info.frame_out_cb = frame_out_cb; ret = sinek_video_set_output(media, &display_info); XUnlockDisplay(display); return ret;}void video_show(void){ XMapWindow(display, videowin); XFlush(display); if(video_visible != 1) sinek.nr_mapped++; video_visible = 1;}void video_hide(void){ XUnmapWindow(display, videowin); XFlush(display); if(video_visible == 1) sinek.nr_mapped--; video_visible = 0; if(0 == sinek.nr_mapped) gtk_main_quit();}void video_cursor(int show){ static int old = 2; if(show == old) return; old = show; if(show == 1) sinek.cursor_timer = 0; XLockDisplay(display); XDefineCursor(display, videowin, cursor[show]); XFlush(display); XUnlockDisplay(display);}static int try_subtitle(char *mrl, char *ext){ gchar *tmp, *tmp2; struct stat mystat; int ret = 0; tmp = g_strdup_printf("%s%s", mrl, ext); if(stat(tmp, &mystat) == 0) { osd_load(tmp); ret = 1; } if(0 == ret) { tmp2 = g_strrstr(tmp, ".avi"); if(NULL == tmp2) tmp2 = g_strrstr(tmp, ".mpg"); if(NULL == tmp2) tmp2 = g_strrstr(tmp, ".mpeg"); if(NULL == tmp2) tmp2 = g_strrstr(tmp, ".mov"); if(tmp2) { strcpy(tmp2, ext); if(stat(tmp, &mystat) == 0) { osd_load(tmp); ret = 1; } } } free(tmp); return ret;}int video_play(char *mrl){ int ret; if(!mrl) return(0); if(video_visible == 42) video_show(); if(NULL == strstr(mrl, "://")) { ret = try_subtitle(mrl, ".txt"); if(0 == ret) ret = try_subtitle(mrl, ".sub"); if(0 == ret) try_subtitle(mrl, ".srt"); } if(sinek_open(media, mrl)) { scrsaver_disable(); control_update_slider(0, xine_get_stream_length(sinek.xine)); control_mrl(mrl); sinek.playing = -1; return 1; } return 0;}void video_seek(int secs){ scrsaver_disable(); sinek_seek(media, secs);}void video_zoom(int val){ int tmp; if(val == 0) { /* reset zoom */ tmp = media->vd->get_property(media->vd, VO_PROP_ASPECT_RATIO); media->vd->set_property(media->vd, VO_PROP_ASPECT_RATIO, tmp); return; } else { tmp = media->vd->get_property(media->vd, VO_PROP_ZOOM_FACTOR); media->vd->set_property(media->vd, VO_PROP_ZOOM_FACTOR, tmp + val); }}void video_scale(float factor){ int x, y; unsigned int w, h, b, d; Window root; if(sinek.video_mode != VIDEO_WINDOW) return; XLockDisplay(display); XGetGeometry(display, videowin, &root, &x, &y, &w, &h, &b, &d); w *= factor; h *= factor; XResizeWindow(display, videowin, w, h); XUnlockDisplay(display);}void video_scale_abs(float factor){ int x, y; unsigned int w, h, b, d; Window root; if(sinek.video_mode != VIDEO_WINDOW) return; XLockDisplay(display); XGetGeometry(display, videowin, &root, &x, &y, &w, &h, &b, &d); w = factor * sinek.vid_w; h = factor * sinek.vid_h; XResizeWindow(display, videowin, w, h); XUnlockDisplay(display);}static gboolean handle_event(GIOChannel *gio, GIOCondition cond, gpointer data){ XEvent xev; int x, y; XNextEvent(display, &xev); if(videowin == 0) return TRUE; sinek_video_event(media, (void *)&xev); switch(xev.type) { case MotionNotify: video_cursor(1); if(sinek.osd_place && translate_point(xev.xmotion.x, xev.xmotion.y, &x, &y)) { osd_position(0, y); } break; case ButtonPress: video_cursor(1); sinek.osd_place = 0; switch(xev.xbutton.button) { case 3: popup_pop(xev.xbutton.time); break; case 4: audio_slide_volume(5); break; case 5: audio_slide_volume(-5); break; } break; case KeyPress: { XKeyEvent *ev = (XKeyEvent *)&xev; KeySym key; char buf[256]; int len;// XLockDisplay(display); len = XLookupString(ev, buf, sizeof(buf), &key, NULL);// XUnlockDisplay(display); key_handle(key, ev->state); break; } case ClientMessage: if(xev.xclient.data.l[0] == wm_delete_window) video_hide(); break; } return TRUE;}void video_set_mode(enum video_modes mode){ Window win = videowin; if(videowin && mode == sinek.video_mode) return; XLockDisplay(display); switch(mode) { case VIDEO_WINDOW: create_window(0, sinek.vid_w, sinek.vid_h); break; case VIDEO_FULLSCREEN: create_window(1, DisplayWidth(display, screen), DisplayHeight(display, screen)); break; case VIDEO_BACKGROUND: create_bg_window(); XLowerWindow(display, videowin); break; } if(win) XDestroyWindow(display, win); sinek.video_mode = mode; if(video_visible != 42) video_show(); XUnlockDisplay(display); wm_relayer_all();}static void find_best_visual(void){ XVisualInfo *vi, tmpl; int num, i, prf, best_prf = -1; tmpl.screen = screen; tmpl.class = TrueColor; vi = XGetVisualInfo(display, VisualScreenMask | VisualClassMask, &tmpl, &num); if(vi) { for(i = 0; i < num; i++) { if(vi[i].depth > 8 && vi[i].depth <= 16) prf = 3; else if(vi[i].depth > 16) prf = 2; else prf = 1; if(prf > best_prf) { depth = vi[i].depth; visual = vi[i].visual; } } XFree(vi); } if(best_prf == -1) { XWindowAttributes attr; XVisualInfo vinfo; XGetWindowAttributes(display, RootWindow(display, screen), &attr); depth = attr.depth; if(XMatchVisualInfo(display, screen, depth, TrueColor, &vinfo)) { visual = vinfo.visual; } else { printf(_("couldn't find true color visual.\n")); depth = DefaultDepth(display, screen); visual = DefaultVisual(display, screen); } }}int translate_point(int x, int y, int *vid_x, int *vid_y){ x11_rectangle_t rect; int xwin, ywin; unsigned int wwin, hwin, bwin, dwin; float xf,yf; float scale, width_scale, height_scale, aspect; Window rootwin; rect.x = x; rect.y = y; rect.w = 0; rect.h = 0; if(media->vd->gui_data_exchange(media->vd, GUI_DATA_EX_TRANSLATE_GUI_TO_VIDEO, (void*)&rect) != -1) { *vid_x = rect.x; *vid_y = rect.y; return 1; } if(XGetGeometry(display, videowin, &rootwin, &xwin, &ywin, &wwin, &hwin, &bwin, &dwin) == BadDrawable) return 0; /* Scale co-ordinate to image dimensions. */ height_scale = (float)sinek.vid_h / (float)hwin; width_scale = (float)sinek.vid_w / (float)wwin; aspect = (float)sinek.vid_w / (float)sinek.vid_h; if(((float)wwin / (float)hwin) < aspect) { scale = width_scale; xf = (float)x * scale; yf = (float)y * scale; hwin = hwin * scale; /* FIXME: The 1.25 should really come from the NAV packets. */ *vid_x = xf * 1.25 / aspect; *vid_y = yf - ((hwin - sinek.vid_h) / 2); } else { scale = height_scale; xf = (float)x * scale; yf = (float)y * scale; wwin=wwin * scale; /* FIXME: The 1.25 should really come from the NAV packets. */ *vid_x = (xf - ((wwin - sinek.vid_w) / 2)) * 1.25 / aspect; *vid_y = yf; } return 1;}static void create_window(int fs, int w, int h){ char *title; static Atom XA_WIN_LAYER = None; XSetWindowAttributes attr; Atom prop; MWMHints mwmhints; long data[1]; title = _("Sinek Video Output"); attr.background_pixel = black.pixel; attr.border_pixel = black.pixel; attr.colormap = colormap; videowin = XCreateWindow(display, RootWindow(display, screen), 0, 0, w, h, 0, depth, CopyFromParent, visual, CWBackPixel | CWBorderPixel | CWColormap, &attr); if(!videowin) { printf(_("Cannot create video window!\n")); exit(5); } sinek.video_win = videowin; if(media->vd) media->vd->gui_data_exchange(media->vd, GUI_DATA_EX_DRAWABLE_CHANGED, (void *)videowin); if(!fs && xc_hint) XSetClassHint(display, videowin, xc_hint); xs_hint.x = 0; xs_hint.y = 0; xs_hint.width = w; xs_hint.height = h; xs_hint.win_gravity = StaticGravity; xs_hint.flags = PPosition | PSize; if(fs) xs_hint.flags |= PWinGravity; XSetStandardProperties(display, videowin, title, title, None, NULL, 0, 0); XSetWMNormalHints(display, videowin, &xs_hint);// XSetWMHints(display, videowin, wm_hint); XSelectInput(display, videowin, StructureNotifyMask | ExposureMask | KeyPressMask | ButtonPressMask | PointerMotionMask); if(!fs) XSetWMProtocols(display, videowin, &wm_delete_window, 1); if(fs) { if(XA_WIN_LAYER == None) XA_WIN_LAYER = XInternAtom(display, "_WIN_LAYER", False); data[0] = 10; XChangeProperty(display, videowin, XA_WIN_LAYER, XA_CARDINAL, 32, PropModeReplace, (unsigned char *)data, 1); prop = XInternAtom(display, "_MOTIF_WM_HINTS", False); mwmhints.flags = MWM_HINTS_DECORATIONS; mwmhints.decorations = 0; XChangeProperty(display, videowin, prop, prop, 32, PropModeReplace, (unsigned char *)&mwmhints, PROP_MWM_HINTS_ELEMENTS); XSetTransientForHint(display, videowin, None); }}static void create_bg_window(void){ static Atom XA_WIN_LAYER = None; XSetWindowAttributes attr; Atom prop; MWMHints mwmhints; long data[1]; char *title; title = _("Sinek Video Output"); attr.background_pixel = black.pixel; attr.override_redirect = True; videowin = XCreateWindow(display, DefaultRootWindow(display), 0, 0, DisplayWidth(display, screen), DisplayHeight(display, screen), 0, CopyFromParent, CopyFromParent, CopyFromParent, CWBackPixel | CWOverrideRedirect, &attr); if(!videowin) { printf(_("Cannot create video window!\n")); exit(5); } sinek.video_win = videowin; if(media->vd) media->vd->gui_data_exchange(media->vd, GUI_DATA_EX_DRAWABLE_CHANGED, (void *)videowin); xs_hint.x = 0; xs_hint.y = 0; xs_hint.width = DisplayWidth(display, screen); xs_hint.height = DisplayHeight(display, screen); xs_hint.flags = USSize | USPosition | PPosition | PSize; XSetStandardProperties(display, videowin, title, title, None, NULL, 0, 0); XSetWMNormalHints(display, videowin, &xs_hint);// XSetWMHints(display, videowin, wm_hint); XSelectInput(display, videowin, StructureNotifyMask | ExposureMask | KeyPressMask | ButtonPressMask | PointerMotionMask); if(XA_WIN_LAYER == None) XA_WIN_LAYER = XInternAtom(display, "_WIN_LAYER", False); data[0] = 0; XChangeProperty(display, videowin, XA_WIN_LAYER, XA_CARDINAL, 32, PropModeReplace, (unsigned char *)data, 1); prop = XInternAtom(display, "_MOTIF_WM_HINTS", False); mwmhints.flags = MWM_HINTS_DECORATIONS; mwmhints.decorations = 0; XChangeProperty(display, videowin, prop, prop, 32, PropModeReplace, (unsigned char *)&mwmhints, PROP_MWM_HINTS_ELEMENTS); XSetTransientForHint(display, videowin, None);}void video_lift(GtkWidget *win){ static Atom XA_WIN_LAYER = None; Window w = GDK_WINDOW_XWINDOW(GTK_WIDGET(win)->window); Display *disp = gdk_x11_get_default_xdisplay(); XEvent ev; if(XA_WIN_LAYER == None) XA_WIN_LAYER = XInternAtom(disp, "_WIN_LAYER", False); ev.type = ClientMessage; ev.xclient.type = ClientMessage; ev.xclient.window = w; ev.xclient.message_type = XA_WIN_LAYER; ev.xclient.format = 32; if(sinek.video_mode == VIDEO_FULLSCREEN) ev.xclient.data.l[0] = (long) 11; else ev.xclient.data.l[0] = (long) 4; ev.xclient.data.l[1] = 0; XSendEvent(disp, RootWindow(disp, screen), False, SubstructureNotifyMask, (XEvent *)&ev); XRaiseWindow(disp, w);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -