📄 video_output_x11.c
字号:
static void display_adjust_size(yuv_image_t *current_image, int given_width, int given_height) { int dpy_sar_frac_n, dpy_sar_frac_d; int sar_frac_n, sar_frac_d; int64_t scale_frac_n, scale_frac_d; int base_width, base_height, max_width, max_height; int new_width, new_height; if(aspect_mode == AspectModeSrcVM) { sar_frac_n // hack = aspect_new_frac_d * current_image->info->picture.horizontal_size; sar_frac_d // hack = aspect_new_frac_n * current_image->info->picture.vertical_size; } /* Use the stream aspect */ else /* if(aspect_mode == AspectModeSrcMPEG) also default */ { sar_frac_n = current_image->info->picture.sar_frac_n; sar_frac_d = current_image->info->picture.sar_frac_d; } DpyInfoGetSAR(mydisplay, screen_nr, &dpy_sar_frac_n, &dpy_sar_frac_d); // TODO replace image->sar.. with image->dar scale_frac_n = (int64_t)dpy_sar_frac_n * (int64_t)sar_frac_d; scale_frac_d = (int64_t)dpy_sar_frac_d * (int64_t)sar_frac_n; #ifdef DEBUG DNOTE("vo: sar: %d/%d, dpy_sar %d/%d, scale: %lld, %lld\n", sar_frac_n, sar_frac_d, dpy_sar_frac_n, dpy_sar_frac_d, scale_frac_n, scale_frac_d); #endif /* area_t src_view_area; switch(view_area_mode) { case user: src_view_area = user_view_area; break; case all: src_view_area = picture_size; break; case pan_scan: src_view_area = picture_display_size; break; } */ if(view_area_mode == 0) { new_view_area.x = 0; new_view_area.y = 0; new_view_area.width = current_image->info->picture.horizontal_size; new_view_area.height = current_image->info->picture.vertical_size; src_view_area = new_view_area; } else if(view_area_mode == 1) { src_view_area = new_view_area; } if(src_view_area.x < 0) { src_view_area.x = 0; new_view_area.x = src_view_area.x; } if(src_view_area.y < 0) { src_view_area.y = 0; new_view_area.y = src_view_area.y; } if(src_view_area.x + src_view_area.width > current_image->info->picture.horizontal_size) { src_view_area.width = current_image->info->picture.horizontal_size - src_view_area.x; new_view_area.width = src_view_area.width; } if(src_view_area.y + src_view_area.height > current_image->info->picture.vertical_size) { src_view_area.height = current_image->info->picture.vertical_size - src_view_area.y; new_view_area.height = src_view_area.height; } /* Keep either the height or the width constant. */ if(scale_frac_n > scale_frac_d) { base_width = (src_view_area.width * scale_frac_n) / scale_frac_d; base_height = src_view_area.height; } else { base_width = src_view_area.width; base_height = (src_view_area.height * scale_frac_d) / scale_frac_n; } //DNOTE("base %d x %d\n", base_width, base_height); /* Do we have a predetermined size for the window? */ if(given_width != -1 && given_height != -1 && (window.win_state != WINDOW_STATE_FULLSCREEN)) { max_width = given_width; max_height = given_height; } else { if(!scale.lock_window_size) { /* Never make the window bigger than the screen. */ DpyInfoGetResolution(mydisplay, screen_nr, &max_width, &max_height); } else { max_width = window.window_area.width; max_height = window.window_area.height; } } //DNOTE("max %d x %d\n", max_width, max_height); /* Fill the given area or keep the image at the same zoom level? */ if((window.win_state == WINDOW_STATE_FULLSCREEN) || (given_width != -1 && given_height != -1)) { /* Zoom so that the image fill the width. */ /* If the height gets to large it's adjusted/fixed below. */ new_width = max_width; new_height = (base_height * max_width) / base_width; } else { //DNOTE("using zoom %d / %d\n", scale.zoom_n, scale.zoom_d); /* Use the provided zoom value. */ new_width = (base_width * scale.zoom_n) / scale.zoom_d; new_height = (base_height * scale.zoom_n) / scale.zoom_d; } //DNOTE("new1 %d x %d\n", new_width, new_height); /* Don't ever make it larger than the max limits. */ if(new_width > max_width) { new_height = (new_height * max_width) / new_width; new_width = max_width; } if(new_height > max_height) { new_width = (new_width * max_height) / new_height; new_height = max_height; } //DNOTE("new2 %d x %d\n", new_width, new_height); /* Remeber what zoom level we ended up with. */ if(window.win_state != WINDOW_STATE_FULLSCREEN) { /* Update zoom values. Use the smalles one. */ if((new_width * base_height) < (new_height * base_width)) { scale.zoom_n = new_width; scale.zoom_d = base_width; } else { scale.zoom_n = new_height; scale.zoom_d = base_height; } //DNOTE("zoom2 %d / %d\n", // scale.zoom_n, scale.zoom_d); } /* Don't care about aspect and can't change the window size, use it all. */ if(!scale.preserve_aspect && (scale.lock_window_size || (window.win_state == WINDOW_STATE_FULLSCREEN))) { new_width = max_width; new_height = max_height; } if((scale.lock_window_size || (window.win_state == WINDOW_STATE_FULLSCREEN)) || (given_width != -1 && given_height != -1)) display_change_size(current_image, new_width, new_height, False); else display_change_size(current_image, new_width, new_height, True);} static void display_toggle_fullscreen(yuv_image_t *current_image) { int root_x, root_y; Window dummy_win; XTranslateCoordinates(mydisplay, window.win, DefaultRootWindow(mydisplay), 0, 0, &root_x, &root_y, &dummy_win); DpyInfoUpdateResolution(mydisplay, screen_nr, root_x, root_y); if(window.win_state != WINDOW_STATE_FULLSCREEN) { ChangeWindowState(mydisplay, window.win, WINDOW_STATE_FULLSCREEN); window.win_state = WINDOW_STATE_FULLSCREEN; } else { ChangeWindowState(mydisplay, window.win, WINDOW_STATE_NORMAL); window.win_state = WINDOW_STATE_NORMAL; } }void clear_borders(void){ // top border if(window.video_area.y > 0) { XClearArea(mydisplay, window.win, 0, 0, window.window_area.width, window.video_area.y - 0, False); } // bottom border if((window.video_area.y + window.video_area.height) < window.window_area.height) { XClearArea(mydisplay, window.win, 0, (window.video_area.y + window.video_area.height), window.window_area.width, window.window_area.height - (window.video_area.y + window.video_area.height), False); } // left border if(window.video_area.x > 0) { XClearArea(mydisplay, window.win, 0, 0, window.video_area.x - 0, window.window_area.height, False); } // right border if((window.video_area.x + window.video_area.width) < window.window_area.width) { XClearArea(mydisplay, window.win, (window.video_area.x + window.video_area.width), 0, window.window_area.width - (window.video_area.x + window.video_area.width), window.window_area.height, False); }}void screenshot_mode(int mode){ switch(mode) { case 0: screenshot = 1; break; case 1: screenshot_spu = 1; break; default: break; }}void check_x_events(yuv_image_t *current_image){ XEvent ev; static clocktime_t prev_time; clocktime_t cur_time; static Bool cursor_visible = True; static Time last_motion; while(XCheckIfEvent(mydisplay, &ev, true_predicate, NULL) != False) { switch(ev.type) { case KeyPress: // send keypress to whoever wants it if(input_mask & INPUT_MASK_KeyPress) { MsgEvent_t m_ev; KeySym keysym; XLookupString(&(ev.xkey), NULL, 0, &keysym, NULL); m_ev.type = MsgEventQInputKeyPress; m_ev.input.x = (ev.xkey.x - window.video_area.x) * src_view_area.width / window.video_area.width + src_view_area.x; m_ev.input.y = (ev.xkey.y - window.video_area.y) * src_view_area.height / window.video_area.height + src_view_area.y; m_ev.input.x_root = ev.xkey.x_root; m_ev.input.y_root = ev.xkey.y_root; m_ev.input.mod_mask = ev.xkey.state; m_ev.input.input = keysym; if(MsgSendEvent(msgq, input_client, &m_ev, IPC_NOWAIT) == -1) { switch(errno) { case EAGAIN: // msgq full, drop message break;#ifdef EIDRM case EIDRM:#endif case EINVAL: FATAL("%s", "keypress\n"); perror("MsgSendEvent"); display_exit(); //TODO clean up and exit break; default: FATAL("%s", "keypress, couldn't send notification\n"); perror("MsgSendEvent"); display_exit(); //TODO clean up and exit break; } } } break; case KeyRelease: // send keyrelease to whoever wants it if(input_mask & INPUT_MASK_KeyRelease) { MsgEvent_t m_ev; KeySym keysym; XLookupString(&(ev.xkey), NULL, 0, &keysym, NULL); m_ev.type = MsgEventQInputKeyRelease; m_ev.input.x = (ev.xkey.x - window.video_area.x) * src_view_area.width / window.video_area.width + src_view_area.x; m_ev.input.y = (ev.xkey.y - window.video_area.y) * src_view_area.height / window.video_area.height + src_view_area.y; m_ev.input.x_root = ev.xkey.x_root; m_ev.input.y_root = ev.xkey.y_root; m_ev.input.mod_mask = ev.xkey.state; m_ev.input.input = keysym; if(MsgSendEvent(msgq, input_client, &m_ev, IPC_NOWAIT) == -1) { switch(errno) { case EAGAIN: // msgq full, drop message break;#ifdef EIDRM case EIDRM:#endif case EINVAL: FATAL("%s", "keyrelease\n"); perror("MsgSendEvent"); display_exit(); //TODO clean up and exit break; default: FATAL("%s", "keyrelease, couldn't send notification\n"); perror("MsgSendEvent"); display_exit(); //TODO clean up and exit break; } } } break; case ButtonPress: // send buttonpress to whoever wants it if(input_mask & INPUT_MASK_ButtonPress) { MsgEvent_t m_ev; m_ev.type = MsgEventQInputButtonPress; m_ev.input.x = (ev.xbutton.x - window.video_area.x)* (int)src_view_area.width / (int)window.video_area.width + src_view_area.x; m_ev.input.y = (ev.xbutton.y - window.video_area.y) * (int)src_view_area.height / (int)window.video_area.height + src_view_area.y; m_ev.input.x_root = ev.xbutton.x_root; m_ev.input.y_root = ev.xbutton.y_root; m_ev.input.mod_mask = ev.xbutton.state; m_ev.input.input = ev.xbutton.button; if(ev.xbutton.button == 2) { view_area_mode = 2; new_view_area.x = m_ev.input.x; new_view_area.y = m_ev.input.y; } if(MsgSendEvent(msgq, input_client, &m_ev, IPC_NOWAIT) == -1) { switch(errno) { case EAGAIN: // msgq full, drop message break;#ifdef EIDRM case EIDRM:#endif case EINVAL: FATAL("%s", "buttonpress\n"); perror("MsgSendEvent"); display_exit(); //TODO clean up and exit break; default: FATAL("%s", "buttonpress, couldn't send notification\n"); perror("MsgSendEvent"); display_exit(); //TODO clean up and exit break; } } } if(cursor_visible == False) { restore_cursor(mydisplay, window.win); cursor_visible = True; } clocktime_get(&prev_time); break; case ButtonRelease: // send buttonrelease to whoever wants it if(1/*input_mask & INPUT_MASK_ButtonRelease*/) { MsgEvent_t m_ev; m_ev.type = MsgEventQInputButtonRelease; m_ev.input.x = (ev.xbutton.x - window.video_area.x)* (int)src_view_area.width / (int)window.video_area.width + src_view_area.x; m_ev.input.y = (ev.xbutton.y - window.video_area.y) * (int)src_view_area.height / (int)window.video_area.height + src_view_area.y; m_ev.input.x_root = ev.xbutton.x_root; m_ev.input.y_root = ev.xbutton.y_root; m_ev.input.mod_mask = ev.xbutton.state; m_ev.input.input = ev.xbutton.button; if(ev.xbutton.button == 2) { int w, h; w = m_ev.input.x - new_view_area.x; h = m_ev.input.y - new_view_area.y; if(w < 1 || h < 1) { view_area_mode = 0; } else { new_view_area.width = w; new_view_area.height = h; view_area_mode = 1; } } if(input_mask & INPUT_MASK_ButtonRelease) { if(MsgSendEvent(msgq, input_client, &m_ev, IPC_NOWAIT) == -1) { switch(errno) { case EAGAIN: // msgq full, drop message break;#ifdef EIDRM case EIDRM:#endif case EINVAL: FATAL("%s", "buttonrelease\n"); perror("MsgSendEvent"); display_exit(); //TODO clean up and exit break; default: FATAL("%s", "buttonrelease, couldn't send notification\n"); perror("MsgSendEvent"); display_exit(); //TODO clean up and exit break; } } } } if(cursor_visible == False) { restore_cursor(mydisplay, window.win); cursor_visible = True; } clocktime_get(&prev_time); break; case MotionNotify: if((ev.xmotion.time - last_motion) > 50) { last_motion = ev.xmotion.time; // send motion notify to whoever wants it if(input_mask & INPUT_MASK_PointerMotion) { MsgEvent_t m_ev; m_ev.type = MsgEventQInputPointerMotion; m_ev.input.x = (ev.xmotion.x - window.video_area.x) * src_view_area.width / window.video_area.width + src_view_area.x; m_ev.input.y = (ev.xmotion.y - window.video_area.y) * src_view_area.height / window.video_area.height + src_view_area.y; m_ev.input.x_root = ev.xmotion.x_root; m_ev.input.y_root = ev.xmotion.y_root; m_ev.input.mod_mask = ev.xmotion.state; m_ev.input.input = 0; if(MsgSendEvent(msgq, input_client, &m_ev, IPC_NOWAIT) == -1) { switch(errno) { case EAGAIN: // msgq full, drop message break;#ifdef EIDRM case EIDRM:#endif case EINVAL: FATAL("%s", "pointermotion\n"); perror("MsgSendEvent"); display_exit(); //TODO clean up and exit break; default: FATAL("%s", "pointermotion, couldn't send notification\n"); perror("MsgSendEvent"); display_exit(); //TODO clean up and exit break; } } } } if(cursor_visible == False) { restore_cursor(mydisplay, window.win); cursor_visible = True; } clocktime_get(&prev_time); break; case Expose: // remove all Expose events in queue while(XCheckTypedEvent(mydisplay, Expose, &ev) == True); if(ev.xexpose.window == window.win) { if(use_xv) { draw_win_xv(&window); } else { draw_win_x11(&window); } } break; case ConfigureNotify: // remove all configure notify in queue while(XCheckTypedEvent(mydisplay, ConfigureNotify, &ev) == True); if(ev.xconfigure.window == window.win) { Window dummy_win; window.window_area.width = ev.xconfigure.width; window.window_area.height = ev.xconfigure.height; display_adjust_size(current_image, ev.xconfigure.width, ev.xconfigure.height); window.video_area.width = scale.image_width; window.video_area.height = scale.image_height; window.video_area.x = (window.window_area.width - window.video_area.width) / 2; window.video_area.y = (window.window_area.height - window.video_area.height) / 2; XTranslateCoordinates(mydisplay, window.win, DefaultRootWindow(mydisplay), 0, 0, &window.window_area.x, &window.window_area.y, &dummy_win); DpyInfoUpdateResolution(mydisplay, screen_nr, window.window_area.x, window.window_area.y); clear_borders(); } break;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -