/***************************************************************************** * Win32VoutCloseWindow: close the window created by Win32VoutCreateWindow ***************************************************************************** * This function returns all resources allocated by Win32VoutCreateWindow. *****************************************************************************/ static void Win32VoutCloseWindow( event_thread_t *p_event ) { vout_display_t *vd = p_event->vd; msg_Dbg( vd, "Win32VoutCloseWindow" ); #if defined(MODULE_NAME_IS_direct3d9) || defined(MODULE_NAME_IS_direct3d11) DestroyWindow( p_event->hvideownd ); #endif DestroyWindow( p_event->hwnd ); if( p_event->hfswnd ) DestroyWindow( p_event->hfswnd ); #if defined(MODULE_NAME_IS_direct3d9) || defined(MODULE_NAME_IS_direct3d11) if( !p_event->use_desktop ) #endif vout_display_DeleteWindow( vd, p_event->parent_window ); p_event->hwnd = NULL; HINSTANCE hInstance = GetModuleHandle(NULL); UnregisterClass( p_event->class_video, hInstance ); UnregisterClass( p_event->class_main, hInstance ); if( p_event->vlc_icon ) DestroyIcon( p_event->vlc_icon ); DestroyCursor( p_event->cursor_empty ); CloseGestures( p_event->p_gesture); }
/** * This function allocates and initializes a aa vout method. */ static int Open(vlc_object_t *object) { vout_display_t *vd = (vout_display_t *)object; vout_display_sys_t *sys; #ifndef _WIN32 if (!vlc_xlib_init (object)) return VLC_EGENERIC; #endif /* Allocate structure */ vd->sys = sys = calloc(1, sizeof(*sys)); if (!sys) return VLC_ENOMEM; /* Don't parse any options, but take $AAOPTS into account */ aa_parseoptions(NULL, NULL, NULL, NULL); /* */ sys->aa_context = aa_autoinit(&aa_defparams); if (!sys->aa_context) { msg_Err(vd, "cannot initialize aalib"); goto error; } vout_display_DeleteWindow(vd, NULL); aa_autoinitkbd(sys->aa_context, 0); aa_autoinitmouse(sys->aa_context, AA_MOUSEALLMASK); /* */ video_format_t fmt = vd->fmt; fmt.i_chroma = VLC_CODEC_RGB8; fmt.i_width = aa_imgwidth(sys->aa_context); fmt.i_height = aa_imgheight(sys->aa_context); fmt.i_visible_width = fmt.i_width; fmt.i_visible_height = fmt.i_height; /* Setup vout_display now that everything is fine */ vd->fmt = fmt; vd->info.has_pictures_invalid = true; vd->info.needs_event_thread = true; vd->pool = Pool; vd->prepare = Prepare; vd->display = PictureDisplay; vd->control = Control; vd->manage = Manage; /* Inspect initial configuration and send correction events * FIXME how to handle aspect ratio with aa ? */ vout_display_SendEventDisplaySize(vd, fmt.i_width, fmt.i_height); return VLC_SUCCESS; error: if (sys && sys->aa_context) aa_close(sys->aa_context); free(sys); return VLC_EGENERIC; }
/***************************************************************************** * OpenVideo: activates dummy vout display method *****************************************************************************/ static int Open(vlc_object_t *object, void (*display)(vout_display_t *, picture_t *, subpicture_t *)) { vout_display_t *vd = (vout_display_t *)object; vout_display_sys_t *sys; vd->sys = sys = calloc(1, sizeof(*sys)); if (!sys) return VLC_EGENERIC; sys->pool = NULL; /* p_vd->info is not modified */ char *chroma = var_InheritString(vd, "dummy-chroma"); if (chroma) { vlc_fourcc_t fcc = vlc_fourcc_GetCodecFromString(VIDEO_ES, chroma); if (fcc != 0) { msg_Dbg(vd, "forcing chroma 0x%.8x (%4.4s)", fcc, (char*)&fcc); vd->fmt.i_chroma = fcc; } free(chroma); } vd->pool = Pool; vd->prepare = NULL; vd->display = display; vd->control = Control; vd->manage = NULL; vout_display_DeleteWindow(vd, NULL); return VLC_SUCCESS; }
/** * Destroys the OpenGL context. */ static void Close (vlc_object_t *obj) { vout_display_t *vd = (vout_display_t *)obj; vout_display_sys_t *sys = vd->sys; vout_display_opengl_Clean (&sys->vgl); vlc_gl_Destroy (sys->gl); vout_display_DeleteWindow (vd, sys->window); free (sys); }
/** * Disconnect from the X server. */ static void Close (vlc_object_t *obj) { vout_display_t *vd = (vout_display_t *)obj; vout_display_sys_t *sys = vd->sys; ResetPictures (vd); /* show the default cursor */ xcb_change_window_attributes (sys->conn, sys->embed->handle.xid, XCB_CW_CURSOR, &(uint32_t) { XCB_CURSOR_NONE }); xcb_flush (sys->conn); /* colormap, window and context are garbage-collected by X */ xcb_disconnect (sys->conn); vout_display_DeleteWindow (vd, sys->embed); free (sys); }
/** * Allocates a surface and an OpenGL context for video output. */ static int Open (vlc_object_t *obj) { vout_display_t *vd = (vout_display_t *)obj; vout_display_sys_t *sys = malloc (sizeof (*sys)); if (unlikely(sys == NULL)) return VLC_ENOMEM; sys->gl = NULL; sys->pool = NULL; sys->window = MakeWindow (vd); if (sys->window == NULL) goto error; sys->gl = vlc_gl_Create (sys->window, API, "$" MODULE_VARNAME); if (sys->gl == NULL) goto error; if (vlc_gl_MakeCurrent (sys->gl)) goto error; /* Initialize video display */ sys->vgl = vout_display_opengl_New (&vd->fmt, NULL, sys->gl); if (!sys->vgl) goto error; vd->sys = sys; vd->info.has_pictures_invalid = false; vd->info.has_event_thread = false; vd->pool = Pool; vd->prepare = PictureRender; vd->display = PictureDisplay; vd->control = Control; vd->manage = NULL; return VLC_SUCCESS; error: if (sys->gl != NULL) vlc_gl_Destroy (sys->gl); if (sys->window != NULL) vout_display_DeleteWindow (vd, sys->window); free (sys); return VLC_EGENERIC; }
/***************************************************************************** * DirectXCloseWindow: close the window created by DirectXCreateWindow ***************************************************************************** * This function returns all resources allocated by DirectXCreateWindow. *****************************************************************************/ static void DirectXCloseWindow( event_thread_t *p_event ) { vout_display_t *vd = p_event->vd; msg_Dbg( vd, "DirectXCloseWindow" ); DestroyWindow( p_event->hwnd ); if( p_event->hfswnd ) DestroyWindow( p_event->hfswnd ); #ifdef MODULE_NAME_IS_direct3d if( !p_event->use_desktop ) #endif vout_display_DeleteWindow( vd, p_event->parent_window ); p_event->hwnd = NULL; HINSTANCE hInstance = GetModuleHandle(NULL); UnregisterClass( p_event->class_video, hInstance ); UnregisterClass( p_event->class_main, hInstance ); #ifndef UNDER_CE DestroyCursor( p_event->cursor_empty ); #endif }
/** * This function allocates and initializes a FB vout method. */ static int Open(vlc_object_t *object) { vout_display_t *vd = (vout_display_t *)object; vout_display_sys_t *sys; /* Allocate instance and initialize some members */ vd->sys = sys = calloc(1, sizeof(*sys)); if (!sys) return VLC_ENOMEM; /* Does the framebuffer uses hw acceleration? */ sys->is_hw_accel = var_InheritBool(vd, "fb-hw-accel"); /* Set tty and fb devices */ sys->tty = 0; /* 0 == /dev/tty0 == current console */ sys->is_tty = var_InheritBool(vd, "fb-tty"); #if !defined(_WIN32) && defined(HAVE_ISATTY) /* Check that stdin is a TTY */ if (sys->is_tty && !isatty(0)) { msg_Warn(vd, "standard input is not a TTY"); free(sys); return VLC_EGENERIC; } msg_Warn(vd, "disabling TTY handling, use with caution because " "there is no way to return to the TTY"); #endif const int mode = var_InheritInteger(vd, "fb-mode"); bool force_resolution = true; switch (mode) { case 0: /* QCIF */ sys->width = 176; sys->height = 144; break; case 1: /* CIF */ sys->width = 352; sys->height = 288; break; case 2: /* NTSC */ sys->width = 640; sys->height = 480; break; case 3: /* PAL */ sys->width = 704; sys->height = 576; break; case 4: default: force_resolution = false; break; } char *chroma = var_InheritString(vd, "fb-chroma"); if (chroma) { sys->chroma = vlc_fourcc_GetCodecFromString(VIDEO_ES, chroma); if (sys->chroma) msg_Dbg(vd, "forcing chroma '%s'", chroma); else msg_Warn(vd, "chroma %s invalid, using default", chroma); free(chroma); } else sys->chroma = 0; /* tty handling */ if (sys->is_tty && TtyInit(vd)) { free(sys); return VLC_EGENERIC; } /* */ sys->video_ptr = MAP_FAILED; sys->picture = NULL; sys->pool = NULL; if (OpenDisplay(vd, force_resolution)) { Close(VLC_OBJECT(vd)); return VLC_EGENERIC; } vout_display_DeleteWindow(vd, NULL); /* */ video_format_t fmt = vd->fmt; if (sys->chroma) { fmt.i_chroma = sys->chroma; } else { /* Assume RGB */ msg_Dbg(vd, "%d bppd", sys->var_info.bits_per_pixel); switch (sys->var_info.bits_per_pixel) { case 8: /* FIXME: set the palette */ fmt.i_chroma = VLC_CODEC_RGB8; break; case 15: fmt.i_chroma = VLC_CODEC_RGB15; break; case 16: fmt.i_chroma = VLC_CODEC_RGB16; break; case 24: fmt.i_chroma = VLC_CODEC_RGB24; break; case 32: fmt.i_chroma = VLC_CODEC_RGB32; break; default: msg_Err(vd, "unknown screendepth %i", sys->var_info.bits_per_pixel); Close(VLC_OBJECT(vd)); return VLC_EGENERIC; } if (sys->var_info.bits_per_pixel != 8) { fmt.i_rmask = ((1 << sys->var_info.red.length) - 1) << sys->var_info.red.offset; fmt.i_gmask = ((1 << sys->var_info.green.length) - 1) << sys->var_info.green.offset; fmt.i_bmask = ((1 << sys->var_info.blue.length) - 1) << sys->var_info.blue.offset; } } fmt.i_visible_width = sys->width; fmt.i_visible_height = sys->height; /* */ vout_display_info_t info = vd->info; info.has_hide_mouse = true; /* */ vd->fmt = fmt; vd->info = info; vd->pool = Pool; vd->prepare = NULL; vd->display = Display; vd->control = Control; vd->manage = NULL; /* */ vout_display_SendEventFullscreen(vd, true); vout_display_SendEventDisplaySize(vd, fmt.i_visible_width, fmt.i_visible_height, true); return VLC_SUCCESS; }
/** * This function initializes SDL vout method. */ static int Open(vlc_object_t *object) { vout_display_t *vd = (vout_display_t *)object; vout_display_sys_t *sys; #if !defined(WIN32) && !defined(__OS2__) if (!vlc_xlib_init (object)) return VLC_EGENERIC; #endif /* XXX: check for conflicts with the SDL audio output */ vlc_mutex_lock(&sdl_lock); /* Check if SDL video module has been initialized */ if (SDL_WasInit(SDL_INIT_VIDEO) != 0) { vlc_mutex_unlock(&sdl_lock); return VLC_EGENERIC; } vd->sys = sys = calloc(1, sizeof(*sys)); if (!sys) { vlc_mutex_unlock(&sdl_lock); return VLC_ENOMEM; } /* */ int sdl_flags = SDL_INIT_VIDEO; #ifndef WIN32 /* Win32 SDL implementation doesn't support SDL_INIT_EVENTTHREAD yet*/ sdl_flags |= SDL_INIT_EVENTTHREAD; #endif /* In debug mode you may want vlc to dump a core instead of staying stuck */ sdl_flags |= SDL_INIT_NOPARACHUTE; /* Initialize library */ if (SDL_Init(sdl_flags) < 0) { vlc_mutex_unlock(&sdl_lock); msg_Err(vd, "cannot initialize SDL (%s)", SDL_GetError()); free(sys); return VLC_EGENERIC; } vlc_mutex_unlock(&sdl_lock); /* Translate keys into unicode */ SDL_EnableUNICODE(1); /* Get the desktop resolution */ /* FIXME: SDL has a problem with virtual desktop */ sys->desktop_width = SDL_GetVideoInfo()->current_w; sys->desktop_height = SDL_GetVideoInfo()->current_h; /* */ video_format_t fmt = vd->fmt; /* */ vout_display_info_t info = vd->info; /* Set main window's size */ int display_width; int display_height; if (vd->cfg->is_fullscreen) { display_width = sys->desktop_width; display_height = sys->desktop_height; } else { display_width = vd->cfg->display.width; display_height = vd->cfg->display.height; } /* Initialize flags and cursor */ sys->display_flags = SDL_ANYFORMAT | SDL_HWPALETTE | SDL_HWSURFACE | SDL_DOUBLEBUF; sys->display_flags |= vd->cfg->is_fullscreen ? SDL_FULLSCREEN : SDL_RESIZABLE; sys->display_bpp = SDL_VideoModeOK(display_width, display_height, 16, sys->display_flags); if (sys->display_bpp == 0) { msg_Err(vd, "no video mode available"); goto error; } vout_display_DeleteWindow(vd, NULL); sys->display = SDL_SetVideoMode(display_width, display_height, sys->display_bpp, sys->display_flags); if (!sys->display) { msg_Err(vd, "cannot set video mode"); goto error; } /* We keep the surface locked forever */ SDL_LockSurface(sys->display); /* */ vlc_fourcc_t forced_chroma = 0; char *psz_chroma = var_InheritString(vd, "sdl-chroma"); if (psz_chroma) { forced_chroma = vlc_fourcc_GetCodecFromString(VIDEO_ES, psz_chroma); if (forced_chroma) msg_Dbg(vd, "Forcing chroma to 0x%.8x (%4.4s)", forced_chroma, (const char*)&forced_chroma); free(psz_chroma); } /* Try to open an overlay if requested */ sys->overlay = NULL; const bool is_overlay = var_InheritBool(vd, "overlay"); if (is_overlay) { static const struct { vlc_fourcc_t vlc; uint32_t sdl; } vlc_to_sdl[] = { { VLC_CODEC_YV12, SDL_YV12_OVERLAY }, { VLC_CODEC_I420, SDL_IYUV_OVERLAY }, { VLC_CODEC_YUYV, SDL_YUY2_OVERLAY }, { VLC_CODEC_UYVY, SDL_UYVY_OVERLAY }, { VLC_CODEC_YVYU, SDL_YVYU_OVERLAY }, { 0, 0 } }; const vlc_fourcc_t forced_chromas[] = { forced_chroma, 0 }; const vlc_fourcc_t *fallback_chromas = vlc_fourcc_GetYUVFallback(fmt.i_chroma); const vlc_fourcc_t *chromas = forced_chroma ? forced_chromas : fallback_chromas; for (int pass = forced_chroma ? 1 : 0; pass < 2 && !sys->overlay; pass++) { for (int i = 0; chromas[i] != 0; i++) { const vlc_fourcc_t vlc = chromas[i]; uint32_t sdl = 0; for (int j = 0; vlc_to_sdl[j].vlc != 0 && !sdl; j++) { if (vlc_to_sdl[j].vlc == vlc) sdl = vlc_to_sdl[j].sdl; } if (!sdl) continue; sys->overlay = SDL_CreateYUVOverlay(fmt.i_width, fmt.i_height, sdl, sys->display); if (sys->overlay && !sys->overlay->hw_overlay && pass == 0) { /* Ignore non hardware overlay surface in first pass */ SDL_FreeYUVOverlay(sys->overlay); sys->overlay = NULL; } if (sys->overlay) { /* We keep the surface locked forever */ SDL_LockYUVOverlay(sys->overlay); fmt.i_chroma = vlc; sys->is_uv_swapped = vlc_fourcc_AreUVPlanesSwapped(fmt.i_chroma, vd->fmt.i_chroma); if (sys->is_uv_swapped) fmt.i_chroma = vd->fmt.i_chroma; break; } } } } else { msg_Warn(vd, "SDL overlay disabled by the user"); } /* */ vout_display_cfg_t place_cfg = *vd->cfg; place_cfg.display.width = display_width; place_cfg.display.height = display_height; vout_display_PlacePicture(&sys->place, &vd->source, &place_cfg, !sys->overlay); /* If no overlay, fallback to software output */ if (!sys->overlay) { /* */ switch (sys->display->format->BitsPerPixel) { case 8: fmt.i_chroma = VLC_CODEC_RGB8; break; case 15: fmt.i_chroma = VLC_CODEC_RGB15; break; case 16: fmt.i_chroma = VLC_CODEC_RGB16; break; case 24: fmt.i_chroma = VLC_CODEC_RGB24; break; case 32: fmt.i_chroma = VLC_CODEC_RGB32; break; default: msg_Err(vd, "unknown screen depth %i", sys->display->format->BitsPerPixel); goto error; } /* All we have is an RGB image with square pixels */ fmt.i_width = display_width; fmt.i_height = display_height; fmt.i_rmask = sys->display->format->Rmask; fmt.i_gmask = sys->display->format->Gmask; fmt.i_bmask = sys->display->format->Bmask; info.has_pictures_invalid = true; } if (vd->cfg->display.title) SDL_WM_SetCaption(vd->cfg->display.title, vd->cfg->display.title); else if (!sys->overlay) SDL_WM_SetCaption(VOUT_TITLE " (software RGB SDL output)", VOUT_TITLE " (software RGB SDL output)"); else if (sys->overlay->hw_overlay) SDL_WM_SetCaption(VOUT_TITLE " (hardware YUV SDL output)", VOUT_TITLE " (hardware YUV SDL output)"); else SDL_WM_SetCaption(VOUT_TITLE " (software YUV SDL output)", VOUT_TITLE " (software YUV SDL output)"); /* Setup events */ SDL_EventState(SDL_KEYUP, SDL_IGNORE); /* ignore keys up */ /* Setup vout_display now that everything is fine */ vd->fmt = fmt; vd->info = info; vd->pool = Pool; vd->prepare = NULL; vd->display = PictureDisplay; vd->control = Control; vd->manage = Manage; /* */ vout_display_SendEventDisplaySize(vd, display_width, display_height, vd->cfg->is_fullscreen); return VLC_SUCCESS; error: msg_Err(vd, "cannot set up SDL (%s)", SDL_GetError()); if (sys->display) { SDL_UnlockSurface(sys->display); SDL_FreeSurface(sys->display); } vlc_mutex_lock(&sdl_lock); SDL_QuitSubSystem(SDL_INIT_VIDEO); vlc_mutex_unlock(&sdl_lock); free(sys); return VLC_EGENERIC; }
static void PMThread( void *arg ) { vout_display_t *vd = ( vout_display_t * )arg; vout_display_sys_t * sys = vd->sys; ULONG i_frame_flags; QMSG qm; char *psz_mode; ULONG i_kva_mode; /* */ video_format_t fmt = vd->fmt; /* */ vout_display_info_t info = vd->info; info.is_slow = false; info.has_double_click = true; info.has_hide_mouse = false; info.has_pictures_invalid = false; MorphToPM(); sys->hab = WinInitialize( 0 ); sys->hmq = WinCreateMsgQueue( sys->hab, 0); WinRegisterClass( sys->hab, WC_VLC_KVA, WndProc, CS_SIZEREDRAW | CS_MOVENOTIFY, sizeof( PVOID )); sys->b_fixt23 = var_CreateGetBool( vd, "kva-fixt23"); if( !sys->b_fixt23 ) { vout_window_cfg_t wnd_cfg; wnd_cfg.is_standalone = false; wnd_cfg.type = VOUT_WINDOW_TYPE_HWND; wnd_cfg.x = var_InheritInteger(vd, "video-x"); wnd_cfg.y = var_InheritInteger(vd, "video-y"); wnd_cfg.width = vd->cfg->display.width; wnd_cfg.height = vd->cfg->display.height; /* If an external window was specified, we'll draw in it. */ sys->parent_window = vout_display_NewWindow( vd, &wnd_cfg ); } if( sys->parent_window ) { sys->parent = ( HWND )sys->parent_window->handle.hwnd; /* Workaround : * When an embedded window opened first, it is not positioned * correctly. So reposition it here, again. */ WinSetWindowPos( WinQueryWindow( sys->parent, QW_PARENT ), HWND_TOP, 0, 0, 0, 0, SWP_MOVE ); ULONG i_style = WinQueryWindowULong( sys->parent, QWL_STYLE ); WinSetWindowULong( sys->parent, QWL_STYLE, i_style | WS_CLIPCHILDREN ); i_frame_flags = FCF_TITLEBAR; } else { sys->parent = HWND_DESKTOP; i_frame_flags = FCF_SYSMENU | FCF_TITLEBAR | FCF_MINMAX | FCF_SIZEBORDER | FCF_TASKLIST; } sys->frame = WinCreateStdWindow( sys->parent, /* parent window handle */ WS_VISIBLE, /* frame window style */ &i_frame_flags, /* window style */ WC_VLC_KVA, /* class name */ "", /* window title */ 0L, /* default client style */ NULLHANDLE, /* resource in exe file */ 1, /* frame window id */ &sys->client ); /* client window handle */ if( sys->frame == NULLHANDLE ) { msg_Err( vd, "cannot create a frame window"); goto exit_frame; } WinSetWindowPtr( sys->client, 0, vd ); if( sys->b_fixt23 ) { WinSetWindowPtr( sys->frame, 0, vd ); sys->p_old_frame = WinSubclassWindow( sys->frame, MyFrameWndProc ); } psz_mode = var_CreateGetString( vd, "kva-video-mode" ); i_kva_mode = KVAM_AUTO; if( strcmp( psz_mode, "snap" ) == 0 ) i_kva_mode = KVAM_SNAP; else if( strcmp( psz_mode, "wo" ) == 0 ) i_kva_mode = KVAM_WO; else if( strcmp( psz_mode, "vman" ) == 0 ) i_kva_mode = KVAM_VMAN; else if( strcmp( psz_mode, "dive" ) == 0 ) i_kva_mode = KVAM_DIVE; free( psz_mode ); if( kvaInit( i_kva_mode, sys->client, COLOR_KEY )) { msg_Err( vd, "cannot initialize KVA"); goto exit_kva_init; } kvaCaps( &sys->kvac ); msg_Dbg( vd, "selected video mode = %s", psz_video_mode[ sys->kvac.ulMode - 1 ]); if( OpenDisplay( vd, &fmt ) ) { msg_Err( vd, "cannot open display"); goto exit_open_display; } if( vd->cfg->is_fullscreen ) { if( sys->parent_window ) vout_window_SetFullScreen(sys->parent_window, true); else WinPostMsg( sys->client, WM_VLC_FULLSCREEN_CHANGE, MPFROMLONG( true ), 0 ); } kvaDisableScreenSaver(); /* Setup vout_display now that everything is fine */ vd->fmt = fmt; vd->info = info; vd->pool = Pool; vd->prepare = NULL; vd->display = Display; vd->control = Control; vd->manage = Manage; /* Prevent SIG_FPE */ _control87(MCW_EM, MCW_EM); sys->i_result = VLC_SUCCESS; DosPostEventSem( sys->ack_event ); while( WinGetMsg( sys->hab, &qm, NULLHANDLE, 0, 0 )) WinDispatchMsg( sys->hab, &qm ); kvaEnableScreenSaver(); CloseDisplay( vd ); /* fall through */ exit_open_display : kvaDone(); exit_kva_init : if( sys->b_fixt23 ) WinSubclassWindow( sys->frame, sys->p_old_frame ); WinDestroyWindow( sys->frame ); exit_frame : vout_display_DeleteWindow( vd, sys->parent_window ); if( sys->is_mouse_hidden ) WinShowPointer( HWND_DESKTOP, TRUE ); WinDestroyMsgQueue( sys->hmq ); WinTerminate( sys->hab ); sys->i_result = VLC_EGENERIC; DosPostEventSem( sys->ack_event ); }
static struct decklink_sys_t *OpenDecklink(vout_display_t *vd) { vout_display_sys_t *sys = vd->sys; #define CHECK(message) do { \ if (result != S_OK) \ { \ msg_Err(vd, message ": 0x%X", result); \ goto error; \ } \ } while(0) HRESULT result; IDeckLinkIterator *decklink_iterator = NULL; IDeckLinkDisplayMode *p_display_mode = NULL; IDeckLinkDisplayModeIterator *p_display_iterator = NULL; IDeckLinkConfiguration *p_config = NULL; IDeckLink *p_card = NULL; struct decklink_sys_t *decklink_sys = GetDLSys(VLC_OBJECT(vd)); vlc_mutex_lock(&decklink_sys->lock); decklink_sys->users++; /* wait until aout is ready */ while (decklink_sys->i_rate == -1) vlc_cond_wait(&decklink_sys->cond, &decklink_sys->lock); int i_card_index = var_InheritInteger(vd, CFG_PREFIX "card-index"); BMDVideoConnection vconn = getVConn(vd); char *mode = var_InheritString(vd, VIDEO_CFG_PREFIX "mode"); size_t len = mode ? strlen(mode) : 0; if (!mode || len > 4) { free(mode); msg_Err(vd, "Missing or invalid mode"); goto error; } BMDDisplayMode wanted_mode_id; memset(&wanted_mode_id, ' ', 4); strncpy((char*)&wanted_mode_id, mode, 4); free(mode); if (i_card_index < 0) { msg_Err(vd, "Invalid card index %d", i_card_index); goto error; } decklink_iterator = CreateDeckLinkIteratorInstance(); if (!decklink_iterator) { msg_Err(vd, "DeckLink drivers not found."); goto error; } for(int i = 0; i <= i_card_index; ++i) { if (p_card) p_card->Release(); result = decklink_iterator->Next(&p_card); CHECK("Card not found"); } const char *psz_model_name; result = p_card->GetModelName(&psz_model_name); CHECK("Unknown model name"); msg_Dbg(vd, "Opened DeckLink PCI card %s", psz_model_name); result = p_card->QueryInterface(IID_IDeckLinkOutput, (void**)&decklink_sys->p_output); CHECK("No outputs"); result = p_card->QueryInterface(IID_IDeckLinkConfiguration, (void**)&p_config); CHECK("Could not get config interface"); if (vconn) { result = p_config->SetInt( bmdDeckLinkConfigVideoOutputConnection, vconn); CHECK("Could not set video output connection"); } result = decklink_sys->p_output->GetDisplayModeIterator(&p_display_iterator); CHECK("Could not enumerate display modes"); for (; ; p_display_mode->Release()) { int w, h; result = p_display_iterator->Next(&p_display_mode); if (result != S_OK) break; BMDDisplayMode mode_id = ntohl(p_display_mode->GetDisplayMode()); const char *psz_mode_name; result = p_display_mode->GetName(&psz_mode_name); CHECK("Could not get display mode name"); result = p_display_mode->GetFrameRate(&decklink_sys->frameduration, &decklink_sys->timescale); CHECK("Could not get frame rate"); w = p_display_mode->GetWidth(); h = p_display_mode->GetHeight(); msg_Dbg(vd, "Found mode '%4.4s': %s (%dx%d, %.3f fps)", (char*)&mode_id, psz_mode_name, w, h, double(decklink_sys->timescale) / decklink_sys->frameduration); msg_Dbg(vd, "scale %d dur %d", (int)decklink_sys->timescale, (int)decklink_sys->frameduration); if (wanted_mode_id != mode_id) continue; decklink_sys->i_width = w; decklink_sys->i_height = h; mode_id = htonl(mode_id); BMDVideoOutputFlags flags = bmdVideoOutputVANC; if (mode_id == bmdModeNTSC || mode_id == bmdModeNTSC2398 || mode_id == bmdModePAL) { flags = bmdVideoOutputVITC; } BMDDisplayModeSupport support; IDeckLinkDisplayMode *resultMode; result = decklink_sys->p_output->DoesSupportVideoMode(mode_id, sys->tenbits ? bmdFormat10BitYUV : bmdFormat8BitYUV, flags, &support, &resultMode); CHECK("Does not support video mode"); if (support == bmdDisplayModeNotSupported) { msg_Err(vd, "Video mode not supported"); goto error; } result = decklink_sys->p_output->EnableVideoOutput(mode_id, flags); CHECK("Could not enable video output"); break; } if (decklink_sys->i_width < 0 || decklink_sys->i_width & 1) { msg_Err(vd, "Unknown video mode specified."); goto error; } if (/*decklink_sys->i_channels > 0 &&*/ decklink_sys->i_rate > 0) { result = decklink_sys->p_output->EnableAudioOutput( decklink_sys->i_rate, bmdAudioSampleType16bitInteger, /*decklink_sys->i_channels*/ 2, bmdAudioOutputStreamTimestamped); } CHECK("Could not start audio output"); /* start */ result = decklink_sys->p_output->StartScheduledPlayback( (mdate() * decklink_sys->timescale) / CLOCK_FREQ, decklink_sys->timescale, 1.0); CHECK("Could not start playback"); p_config->Release(); p_display_mode->Release(); p_display_iterator->Release(); p_card->Release(); decklink_iterator->Release(); vlc_mutex_unlock(&decklink_sys->lock); vout_display_DeleteWindow(vd, NULL); return decklink_sys; error: if (decklink_sys->p_output) { decklink_sys->p_output->Release(); decklink_sys->p_output = NULL; } if (p_card) p_card->Release(); if (p_config) p_config->Release(); if (p_display_iterator) p_display_iterator->Release(); if (decklink_iterator) decklink_iterator->Release(); if (p_display_mode) p_display_mode->Release(); vlc_mutex_unlock(&decklink_sys->lock); ReleaseDLSys(VLC_OBJECT(vd)); return NULL; #undef CHECK }
/***************************************************************************** * Win32VoutCreateWindow: create a window for the video. ***************************************************************************** * Before creating a direct draw surface, we need to create a window in which * the video will be displayed. This window will also allow us to capture the * events. *****************************************************************************/ static int Win32VoutCreateWindow( event_thread_t *p_event ) { vout_display_t *vd = p_event->vd; HINSTANCE hInstance; HMENU hMenu; RECT rect_window; WNDCLASS wc; /* window class components */ TCHAR vlc_path[MAX_PATH+1]; int i_style; msg_Dbg( vd, "Win32VoutCreateWindow" ); /* Get this module's instance */ hInstance = GetModuleHandle(NULL); #if defined(MODULE_NAME_IS_direct3d9) || defined(MODULE_NAME_IS_direct3d11) if( !p_event->use_desktop ) #endif { /* If an external window was specified, we'll draw in it. */ p_event->parent_window = vout_display_NewWindow(vd, VOUT_WINDOW_TYPE_HWND); if( p_event->parent_window ) p_event->hparent = p_event->parent_window->handle.hwnd; else p_event->hparent = NULL; } #if defined(MODULE_NAME_IS_direct3d9) || defined(MODULE_NAME_IS_direct3d11) else { vout_display_DeleteWindow(vd, NULL); p_event->parent_window = NULL; p_event->hparent = GetDesktopHandle(vd); } #endif p_event->cursor_arrow = LoadCursor(NULL, IDC_ARROW); p_event->cursor_empty = EmptyCursor(hInstance); /* Get the Icon from the main app */ p_event->vlc_icon = NULL; if( GetModuleFileName( NULL, vlc_path, MAX_PATH ) ) { p_event->vlc_icon = ExtractIcon( hInstance, vlc_path, 0 ); } /* Fill in the window class structure */ wc.style = CS_OWNDC|CS_DBLCLKS; /* style: dbl click */ wc.lpfnWndProc = (WNDPROC)WinVoutEventProc; /* event handler */ wc.cbClsExtra = 0; /* no extra class data */ wc.cbWndExtra = 0; /* no extra window data */ wc.hInstance = hInstance; /* instance */ wc.hIcon = p_event->vlc_icon; /* load the vlc big icon */ wc.hCursor = p_event->is_cursor_hidden ? p_event->cursor_empty : p_event->cursor_arrow; #if !VLC_WINSTORE_APP wc.hbrBackground = GetStockObject(BLACK_BRUSH); /* background color */ #else wc.hbrBackground = NULL; #endif wc.lpszMenuName = NULL; /* no menu */ wc.lpszClassName = p_event->class_main; /* use a special class */ /* Register the window class */ if( !RegisterClass(&wc) ) { if( p_event->vlc_icon ) DestroyIcon( p_event->vlc_icon ); msg_Err( vd, "Win32VoutCreateWindow RegisterClass FAILED (err=%lu)", GetLastError() ); return VLC_EGENERIC; } /* Register the video sub-window class */ wc.lpszClassName = p_event->class_video; wc.hIcon = 0; wc.hbrBackground = NULL; /* no background color */ if( !RegisterClass(&wc) ) { msg_Err( vd, "Win32VoutCreateWindow RegisterClass FAILED (err=%lu)", GetLastError() ); return VLC_EGENERIC; } /* When you create a window you give the dimensions you wish it to * have. Unfortunatly these dimensions will include the borders and * titlebar. We use the following function to find out the size of * the window corresponding to the useable surface we want */ rect_window.left = 10; rect_window.top = 10; rect_window.right = rect_window.left + p_event->width; rect_window.bottom = rect_window.top + p_event->height; i_style = var_GetBool( vd, "video-deco" ) /* Open with window decoration */ ? WS_OVERLAPPEDWINDOW|WS_SIZEBOX /* No window decoration */ : WS_POPUP; AdjustWindowRect( &rect_window, i_style, 0 ); i_style |= WS_VISIBLE|WS_CLIPCHILDREN; if( p_event->hparent ) { i_style = WS_VISIBLE|WS_CLIPCHILDREN|WS_CHILD; /* allow user to regain control over input events if requested */ bool b_mouse_support = var_InheritBool( vd, "mouse-events" ); bool b_key_support = var_InheritBool( vd, "keyboard-events" ); if( !b_mouse_support && !b_key_support ) i_style |= WS_DISABLED; } p_event->i_window_style = i_style; /* Create the window */ p_event->hwnd = CreateWindowEx( WS_EX_NOPARENTNOTIFY, p_event->class_main, /* name of window class */ _T(VOUT_TITLE) _T(" (VLC Video Output)"),/* window title */ i_style, /* window style */ (!p_event->x) ? (UINT)CW_USEDEFAULT : (UINT)p_event->x, /* default X coordinate */ (!p_event->y) ? (UINT)CW_USEDEFAULT : (UINT)p_event->y, /* default Y coordinate */ rect_window.right - rect_window.left, /* window width */ rect_window.bottom - rect_window.top, /* window height */ p_event->hparent, /* parent window */ NULL, /* no menu in this window */ hInstance, /* handle of this program instance */ (LPVOID)p_event ); /* send vd to WM_CREATE */ if( !p_event->hwnd ) { msg_Warn( vd, "Win32VoutCreateWindow create window FAILED (err=%lu)", GetLastError() ); return VLC_EGENERIC; } InitGestures( p_event->hwnd, &p_event->p_gesture ); if( p_event->hparent ) { LONG i_style; /* We don't want the window owner to overwrite our client area */ i_style = GetWindowLong( p_event->hparent, GWL_STYLE ); if( !(i_style & WS_CLIPCHILDREN) ) /* Hmmm, apparently this is a blocking call... */ SetWindowLong( p_event->hparent, GWL_STYLE, i_style | WS_CLIPCHILDREN ); /* Create our fullscreen window */ p_event->hfswnd = CreateWindowEx( WS_EX_APPWINDOW, p_event->class_main, _T(VOUT_TITLE) _T(" (VLC Fullscreen Video Output)"), WS_OVERLAPPEDWINDOW|WS_CLIPCHILDREN|WS_SIZEBOX, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, hInstance, NULL ); } else { p_event->hfswnd = NULL; } /* Append a "Always On Top" entry in the system menu */ hMenu = GetSystemMenu( p_event->hwnd, FALSE ); AppendMenu( hMenu, MF_SEPARATOR, 0, _T("") ); AppendMenu( hMenu, MF_STRING | MF_UNCHECKED, IDM_TOGGLE_ON_TOP, _T("Always on &Top") ); /* Create video sub-window. This sub window will always exactly match * the size of the video, which allows us to use crazy overlay colorkeys * without having them shown outside of the video area. */ /* FIXME vd->source.i_width/i_height seems wrong */ p_event->hvideownd = CreateWindow( p_event->class_video, _T(""), /* window class */ WS_CHILD, /* window style, not visible initially */ 0, 0, vd->source.i_width, /* default width */ vd->source.i_height, /* default height */ p_event->hwnd, /* parent window */ NULL, hInstance, (LPVOID)p_event ); /* send vd to WM_CREATE */ if( !p_event->hvideownd ) msg_Warn( vd, "can't create video sub-window" ); else msg_Dbg( vd, "created video sub-window" ); /* Now display the window */ ShowWindow( p_event->hwnd, SW_SHOW ); return VLC_SUCCESS; }
static int Open(vlc_object_t *object) { vout_display_t *vd = (vout_display_t *)object; vout_display_sys_t *sys; /* Allocate structure */ vd->sys = sys = malloc(sizeof(*sys)); if (!sys) return VLC_ENOMEM; sys->directfb = NULL; sys->primary = NULL; sys->width = 0; sys->height = 0; sys->pool = NULL; /* Init DirectFB */ if (DirectFBInit(NULL,NULL) != DFB_OK) { msg_Err(vd, "Cannot init DirectFB"); free(sys); return VLC_EGENERIC; } if (OpenDisplay(vd)) { msg_Err(vd, "Cannot create primary surface"); Close(VLC_OBJECT(vd)); return VLC_EGENERIC; } vout_display_DeleteWindow(vd, NULL); /* */ video_format_t fmt = vd->fmt; switch (sys->pixel_format) { case DSPF_RGB332: /* 8 bit RGB (1 byte, red 3@5, green 3@2, blue 2@0) */ fmt.i_chroma = VLC_CODEC_RGB8; fmt.i_rmask = 0x7 << 5; fmt.i_gmask = 0x7 << 2; fmt.i_bmask = 0x3 << 0; break; case DSPF_RGB16: /* 16 bit RGB (2 byte, red 5@11, green 6@5, blue 5@0) */ fmt.i_chroma = VLC_CODEC_RGB16; fmt.i_rmask = 0x1f << 11; fmt.i_gmask = 0x3f << 5; fmt.i_bmask = 0x1f << 0; break; case DSPF_RGB24: /* 24 bit RGB (3 byte, red 8@16, green 8@8, blue 8@0) */ fmt.i_chroma = VLC_CODEC_RGB24; fmt.i_rmask = 0xff << 16; fmt.i_gmask = 0xff << 8; fmt.i_bmask = 0xff << 0; break; case DSPF_RGB32: /* 24 bit RGB (4 byte, nothing@24, red 8@16, green 8@8, blue 8@0) */ fmt.i_chroma = VLC_CODEC_RGB32; fmt.i_rmask = 0xff << 16; fmt.i_gmask = 0xff << 8; fmt.i_bmask = 0xff << 0; break; default: msg_Err(vd, "unknown screen depth %i", sys->pixel_format); Close(VLC_OBJECT(vd)); return VLC_EGENERIC; } fmt.i_width = sys->width; fmt.i_height = sys->height; /* */ vout_display_info_t info = vd->info; info.has_hide_mouse = true; /* */ vd->fmt = fmt; vd->info = info; vd->pool = Pool; vd->prepare = NULL; vd->display = Display; vd->control = Control; vd->manage = Manage; /* */ vout_display_SendEventFullscreen(vd, true); vout_display_SendEventDisplaySize(vd, fmt.i_width, fmt.i_height, true); return VLC_SUCCESS; }
static int Open(vlc_object_t *object) { vout_display_t *vd = (vout_display_t *)object; vout_display_sys_t *sys; /* Allocate instance and initialize some members */ vd->sys = sys = malloc(sizeof(*sys)); if (!sys) return VLC_ENOMEM; sys->is_first = false; sys->is_yuv4mpeg2 = var_InheritBool(vd, CFG_PREFIX "yuv4mpeg2"); sys->pool = NULL; /* */ char *psz_fcc = var_InheritString(vd, CFG_PREFIX "chroma"); const vlc_fourcc_t requested_chroma = vlc_fourcc_GetCodecFromString(VIDEO_ES, psz_fcc); free(psz_fcc); const vlc_fourcc_t chroma = requested_chroma ? requested_chroma : VLC_CODEC_I420; if (sys->is_yuv4mpeg2) { switch (chroma) { case VLC_CODEC_YV12: case VLC_CODEC_I420: case VLC_CODEC_J420: break; default: msg_Err(vd, "YUV4MPEG2 mode needs chroma YV12 not %4.4s as requested", (char *)&chroma); free(sys); return VLC_EGENERIC; } } msg_Dbg(vd, "Using chroma %4.4s", (char *)&chroma); /* */ char *name = var_InheritString(vd, CFG_PREFIX "file"); if (!name) { msg_Err(vd, "Empty file name"); free(sys); return VLC_EGENERIC; } sys->f = vlc_fopen(name, "wb"); if (!sys->f) { msg_Err(vd, "Failed to open %s", name); free(name); free(sys); return VLC_EGENERIC; } msg_Dbg(vd, "Writing data to %s", name); free(name); /* */ video_format_t fmt; video_format_ApplyRotation(&fmt, &vd->fmt); fmt.i_chroma = chroma; video_format_FixRgb(&fmt); /* */ vout_display_info_t info = vd->info; info.has_hide_mouse = true; /* */ vd->fmt = fmt; vd->info = info; vd->pool = Pool; vd->prepare = NULL; vd->display = Display; vd->control = Control; vd->manage = NULL; vout_display_SendEventFullscreen(vd, false); vout_display_DeleteWindow(vd, NULL); return VLC_SUCCESS; }
/***************************************************************************** * Open: allocates video thread ***************************************************************************** * This function allocates and initializes a vout method. *****************************************************************************/ static int Open(vlc_object_t *object) { vout_display_t *vd = (vout_display_t *)object; vout_display_sys_t *sys = malloc(sizeof(*sys)); if (unlikely(!sys)) return VLC_ENOMEM; /* Get the callbacks */ vlc_format_cb setup = var_InheritAddress(vd, "vmem-setup"); sys->lock = var_InheritAddress(vd, "vmem-lock"); if (sys->lock == NULL) { msg_Err(vd, "missing lock callback"); free(sys); return VLC_EGENERIC; } sys->unlock = var_InheritAddress(vd, "vmem-unlock"); sys->display = var_InheritAddress(vd, "vmem-display"); sys->cleanup = var_InheritAddress(vd, "vmem-cleanup"); sys->opaque = var_InheritAddress(vd, "vmem-data"); sys->pool = NULL; /* Define the video format */ video_format_t fmt; video_format_ApplyRotation(&fmt, &vd->fmt); if (setup != NULL) { char chroma[5]; memcpy(chroma, &fmt.i_chroma, 4); chroma[4] = '\0'; memset(sys->pitches, 0, sizeof(sys->pitches)); memset(sys->lines, 0, sizeof(sys->lines)); sys->count = setup(&sys->opaque, chroma, &fmt.i_width, &fmt.i_height, sys->pitches, sys->lines); if (sys->count == 0) { msg_Err(vd, "video format setup failure (no pictures)"); free(sys); return VLC_EGENERIC; } fmt.i_chroma = vlc_fourcc_GetCodecFromString(VIDEO_ES, chroma); } else { char *chroma = var_InheritString(vd, "vmem-chroma"); fmt.i_chroma = vlc_fourcc_GetCodecFromString(VIDEO_ES, chroma); free(chroma); fmt.i_width = var_InheritInteger(vd, "vmem-width"); fmt.i_height = var_InheritInteger(vd, "vmem-height"); sys->pitches[0] = var_InheritInteger(vd, "vmem-pitch"); sys->lines[0] = fmt.i_height; for (size_t i = 1; i < PICTURE_PLANE_MAX; i++) { sys->pitches[i] = sys->pitches[0]; sys->lines[i] = sys->lines[0]; } sys->count = 1; sys->cleanup = NULL; } fmt.i_x_offset = fmt.i_y_offset = 0; fmt.i_visible_width = fmt.i_width; fmt.i_visible_height = fmt.i_height; if (!fmt.i_chroma) { msg_Err(vd, "vmem-chroma should be 4 characters long"); free(sys); return VLC_EGENERIC; } /* Define the bitmasks */ switch (fmt.i_chroma) { case VLC_CODEC_RGB15: fmt.i_rmask = 0x001f; fmt.i_gmask = 0x03e0; fmt.i_bmask = 0x7c00; break; case VLC_CODEC_RGB16: fmt.i_rmask = 0x001f; fmt.i_gmask = 0x07e0; fmt.i_bmask = 0xf800; break; case VLC_CODEC_RGB24: case VLC_CODEC_RGB32: fmt.i_rmask = 0xff0000; fmt.i_gmask = 0x00ff00; fmt.i_bmask = 0x0000ff; break; default: fmt.i_rmask = 0; fmt.i_gmask = 0; fmt.i_bmask = 0; break; } /* */ vout_display_info_t info = vd->info; info.has_hide_mouse = true; /* */ vd->sys = sys; vd->fmt = fmt; vd->info = info; vd->pool = Pool; vd->prepare = Prepare; vd->display = Display; vd->control = Control; vd->manage = NULL; /* */ vout_display_SendEventFullscreen(vd, false); vout_display_SendEventDisplaySize(vd, fmt.i_width, fmt.i_height); vout_display_DeleteWindow(vd, NULL); return VLC_SUCCESS; }
/** * This function initializes libcaca vout method. */ static int Open(vlc_object_t *object) { vout_display_t *vd = (vout_display_t *)object; vout_display_sys_t *sys; #if !defined(__APPLE__) && !defined(WIN32) # ifndef X_DISPLAY_MISSING if (!vlc_xlib_init(object)) return VLC_EGENERIC; # endif #endif #if defined(WIN32) CONSOLE_SCREEN_BUFFER_INFO csbiInfo; SMALL_RECT rect; COORD coord; HANDLE hstdout; if (!AllocConsole()) { msg_Err(vd, "cannot create console"); return VLC_EGENERIC; } hstdout = CreateConsoleScreenBuffer(GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, CONSOLE_TEXTMODE_BUFFER, NULL); if (!hstdout || hstdout == INVALID_HANDLE_VALUE) { msg_Err(vd, "cannot create screen buffer"); FreeConsole(); return VLC_EGENERIC; } if (!SetConsoleActiveScreenBuffer(hstdout)) { msg_Err(vd, "cannot set active screen buffer"); FreeConsole(); return VLC_EGENERIC; } coord = GetLargestConsoleWindowSize(hstdout); msg_Dbg(vd, "SetConsoleWindowInfo: %ix%i", coord.X, coord.Y); /* Force size for now */ coord.X = 100; coord.Y = 40; if (!SetConsoleScreenBufferSize(hstdout, coord)) msg_Warn(vd, "SetConsoleScreenBufferSize %i %i", coord.X, coord.Y); /* Get the current screen buffer size and window position. */ if (GetConsoleScreenBufferInfo(hstdout, &csbiInfo)) { rect.Top = 0; rect.Left = 0; rect.Right = csbiInfo.dwMaximumWindowSize.X - 1; rect.Bottom = csbiInfo.dwMaximumWindowSize.Y - 1; if (!SetConsoleWindowInfo(hstdout, TRUE, &rect)) msg_Dbg(vd, "SetConsoleWindowInfo failed: %ix%i", rect.Right, rect.Bottom); } #endif /* Allocate structure */ vd->sys = sys = calloc(1, sizeof(*sys)); if (!sys) goto error; sys->cv = cucul_create_canvas(0, 0); if (!sys->cv) { msg_Err(vd, "cannot initialize libcucul"); goto error; } const char *driver = NULL; #ifdef __APPLE__ // Make sure we don't try to open a window. driver = "ncurses"; #endif sys->dp = caca_create_display_with_driver(sys->cv, driver); if (!sys->dp) { msg_Err(vd, "cannot initialize libcaca"); goto error; } vout_display_DeleteWindow(vd, NULL); if (vd->cfg->display.title) caca_set_display_title(sys->dp, vd->cfg->display.title); else caca_set_display_title(sys->dp, VOUT_TITLE "(Colour AsCii Art)"); /* Fix format */ video_format_t fmt = vd->fmt; if (fmt.i_chroma != VLC_CODEC_RGB32) { fmt.i_chroma = VLC_CODEC_RGB32; fmt.i_rmask = 0x00ff0000; fmt.i_gmask = 0x0000ff00; fmt.i_bmask = 0x000000ff; } /* TODO */ vout_display_info_t info = vd->info; /* Setup vout_display now that everything is fine */ vd->fmt = fmt; vd->info = info; vd->pool = Pool; vd->prepare = Prepare; vd->display = PictureDisplay; vd->control = Control; vd->manage = Manage; /* Fix initial state */ vout_display_SendEventFullscreen(vd, false); Refresh(vd); return VLC_SUCCESS; error: if (sys) { if (sys->pool) picture_pool_Delete(sys->pool); if (sys->dither) cucul_free_dither(sys->dither); if (sys->dp) caca_free_display(sys->dp); if (sys->cv) cucul_free_canvas(sys->cv); free(sys); } #if defined(WIN32) FreeConsole(); #endif return VLC_EGENERIC; }