Skip to content

AFNI/NIfTI Server

Sections
Personal tools
You are here: Home » AFNI » Documentation

Doxygen Source Code Documentation


Main Page   Alphabetical List   Data Structures   File List   Data Fields   Globals   Search  

video_out_dx.c

Go to the documentation of this file.
00001 /*
00002  * video_out_dx.c
00003  * Copyright (C) 2000-2002 Michel Lespinasse <walken@zoy.org>
00004  *
00005  * Contributed by Gildas Bazin <gbazin@netcourrier.com>
00006  *
00007  * This file is part of mpeg2dec, a free MPEG-2 video stream decoder.
00008  * See http://libmpeg2.sourceforge.net/ for updates.
00009  *
00010  * mpeg2dec is free software; you can redistribute it and/or modify
00011  * it under the terms of the GNU General Public License as published by
00012  * the Free Software Foundation; either version 2 of the License, or
00013  * (at your option) any later version.
00014  *
00015  * mpeg2dec is distributed in the hope that it will be useful,
00016  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00017  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00018  * GNU General Public License for more details.
00019  *
00020  * You should have received a copy of the GNU General Public License
00021  * along with this program; if not, write to the Free Software
00022  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00023  */
00024 
00025 #include "config.h"
00026 
00027 #ifdef LIBVO_DX
00028 
00029 #include <stdio.h>
00030 #include <stdlib.h>
00031 #include <string.h>
00032 #include <inttypes.h>
00033 
00034 #include "video_out.h"
00035 #include "convert.h"
00036 
00037 #include <ddraw.h>
00038 #include <initguid.h>
00039 
00040 #define USE_OVERLAY_TRIPLE_BUFFERING 0
00041 
00042 /*
00043  * DirectDraw GUIDs.
00044  * Defining them here allows us to get rid of the dxguid library during link.
00045  */
00046 DEFINE_GUID (IID_IDirectDraw2, 0xB3A6F3E0,0x2B43,0x11CF,0xA2,0xDE,0x00,0xAA,0x00,0xB9,0x33,0x56);
00047 DEFINE_GUID (IID_IDirectDrawSurface2, 0x57805885,0x6eec,0x11cf,0x94,0x41,0xa8,0x23,0x03,0xc1,0x0e,0x27);
00048 
00049 #define FOURCC_YV12 0x32315659
00050 
00051 typedef struct {
00052     vo_instance_t vo;
00053     int width;
00054     int height;
00055 
00056     HWND window;
00057     RECT window_coords;
00058     HINSTANCE hddraw_dll;
00059     LPDIRECTDRAW2 ddraw;
00060     LPDIRECTDRAWSURFACE2 display;
00061     LPDIRECTDRAWCLIPPER clipper;
00062     LPDIRECTDRAWSURFACE2 frame[3];
00063     int index;
00064 
00065     LPDIRECTDRAWSURFACE2 overlay;
00066     uint8_t * yuv[3];
00067     int stride;
00068 } dx_instance_t;
00069 
00070 static void update_overlay (dx_instance_t * instance)
00071 {
00072     DDOVERLAYFX ddofx;
00073     DWORD dwFlags;
00074 
00075     memset (&ddofx, 0, sizeof (DDOVERLAYFX));
00076     ddofx.dwSize = sizeof (DDOVERLAYFX);
00077     dwFlags = DDOVER_SHOW | DDOVER_KEYDESTOVERRIDE;
00078     IDirectDrawSurface2_UpdateOverlay (instance->overlay, NULL,
00079                                        instance->display,
00080                                        &instance->window_coords,
00081                                        dwFlags, &ddofx);
00082 }
00083 
00084 static long FAR PASCAL event_procedure (HWND hwnd, UINT message,
00085                                         WPARAM wParam, LPARAM lParam)
00086 {
00087     RECT rect_window;
00088     POINT point_window;
00089     dx_instance_t * instance;
00090 
00091     switch (message) {
00092 
00093     case WM_WINDOWPOSCHANGED:
00094         instance = (dx_instance_t *) GetWindowLong (hwnd, GWL_USERDATA);
00095 
00096         /* update the window position and size */
00097         point_window.x = 0;
00098         point_window.y = 0;
00099         ClientToScreen (hwnd, &point_window);
00100         instance->window_coords.left = point_window.x;
00101         instance->window_coords.top = point_window.y;
00102         GetClientRect (hwnd, &rect_window);
00103         instance->window_coords.right = rect_window.right + point_window.x;
00104         instance->window_coords.bottom = rect_window.bottom + point_window.y;
00105 
00106         /* update the overlay */
00107         if (instance->overlay && instance->display)
00108             update_overlay (instance);
00109 
00110         return 0;
00111 
00112     case WM_CLOSE:      /* forbid the user to close the window */
00113         return 0;
00114 
00115     case WM_DESTROY:    /* just destroy the window */
00116         PostQuitMessage (0);
00117         return 0;
00118     }
00119 
00120     return DefWindowProc (hwnd, message, wParam, lParam);
00121 }
00122 
00123 static void check_events (dx_instance_t * instance)
00124 {
00125     MSG msg;
00126 
00127     while (PeekMessage (&msg, instance->window, 0, 0, PM_REMOVE)) {
00128         TranslateMessage (&msg);
00129         DispatchMessage (&msg);
00130     }
00131 }
00132 
00133 static int create_window (dx_instance_t * instance)
00134 {
00135     RECT rect_window;
00136     WNDCLASSEX wc;
00137 
00138     wc.cbSize        = sizeof (WNDCLASSEX);
00139     wc.style         = CS_DBLCLKS;
00140     wc.lpfnWndProc   = (WNDPROC) event_procedure;
00141     wc.cbClsExtra    = 0;
00142     wc.cbWndExtra    = 0;
00143     wc.hInstance     = GetModuleHandle (NULL);
00144     wc.hIcon         = NULL;
00145     wc.hCursor       = LoadCursor (NULL, IDC_ARROW);
00146     wc.hbrBackground = CreateSolidBrush (RGB (0, 0, 0));
00147     wc.lpszMenuName  = NULL;
00148     wc.lpszClassName = "libvo_dx";
00149     wc.hIconSm       = NULL;
00150     if (!RegisterClassEx (&wc)) {
00151         fprintf (stderr, "Can not register window class\n");
00152         return 1;
00153     }
00154 
00155     rect_window.top    = 10;
00156     rect_window.left   = 10;
00157     rect_window.right  = rect_window.left + instance->width;
00158     rect_window.bottom = rect_window.top + instance->height;
00159     AdjustWindowRect (&rect_window, WS_OVERLAPPEDWINDOW|WS_SIZEBOX, 0);
00160 
00161     instance->window = CreateWindow ("libvo_dx", "mpeg2dec",
00162                                      WS_OVERLAPPEDWINDOW | WS_SIZEBOX,
00163                                      CW_USEDEFAULT, 0,
00164                                      rect_window.right - rect_window.left,
00165                                      rect_window.bottom - rect_window.top,
00166                                      NULL, NULL, GetModuleHandle (NULL), NULL);
00167     if (instance->window == NULL) {
00168         fprintf (stderr, "Can not create window\n");
00169         return 1;
00170     }
00171 
00172     /* store a directx_instance pointer into the window local storage
00173      * (for later use in event_handler).
00174      * We need to use SetWindowLongPtr when it is available in mingw */
00175     SetWindowLong (instance->window, GWL_USERDATA, (LONG) instance);
00176 
00177     ShowWindow (instance->window, SW_SHOW);
00178 
00179     return 0;
00180 }
00181 
00182 static LPDIRECTDRAWSURFACE2 alloc_surface (dx_instance_t * instance,
00183                                            DDSURFACEDESC * ddsd)
00184 {
00185     LPDIRECTDRAWSURFACE surface;
00186     LPDIRECTDRAWSURFACE2 surface2;
00187 
00188     if (DD_OK != IDirectDraw2_CreateSurface (instance->ddraw, ddsd,
00189                                              &surface, NULL) ||
00190         DD_OK != IDirectDrawSurface_QueryInterface (surface,
00191                                                     &IID_IDirectDrawSurface2,
00192                                                     (LPVOID *) &surface2)) {
00193         fprintf (stderr, "Can not create directDraw frame surface\n");
00194         return NULL;
00195     }
00196     IDirectDrawSurface_Release (surface);
00197 
00198     return surface2;
00199 }
00200 
00201 static int dx_init (dx_instance_t *instance)
00202 {
00203     HRESULT (WINAPI * OurDirectDrawCreate) (GUID *, LPDIRECTDRAW *,
00204                                             IUnknown *);
00205     LPDIRECTDRAW ddraw;
00206     DDSURFACEDESC ddsd;
00207 
00208     /* load direct draw DLL */
00209     instance->hddraw_dll = LoadLibrary ("DDRAW.DLL");
00210     if (instance->hddraw_dll == NULL) {
00211         fprintf (stderr, "Can not load DDRAW.DLL\n");
00212         return 1;
00213     }
00214 
00215     ddraw = NULL;
00216     OurDirectDrawCreate = (void *) GetProcAddress (instance->hddraw_dll,
00217                                                    "DirectDrawCreate");
00218     if (OurDirectDrawCreate == NULL ||
00219         DD_OK != OurDirectDrawCreate (NULL, &ddraw, NULL) ||
00220         DD_OK != IDirectDraw_QueryInterface (ddraw, &IID_IDirectDraw2,
00221                                              (LPVOID *) &instance->ddraw) ||
00222         DD_OK != IDirectDraw_SetCooperativeLevel (instance->ddraw,
00223                                                   instance->window,
00224                                                   DDSCL_NORMAL)) {
00225         fprintf (stderr, "Can not initialize directDraw interface\n");
00226         return 1;
00227     }
00228     IDirectDraw_Release (ddraw);
00229 
00230     memset (&ddsd, 0, sizeof (DDSURFACEDESC));
00231     ddsd.dwSize = sizeof (DDSURFACEDESC);
00232     ddsd.dwFlags = DDSD_CAPS;
00233     ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
00234     instance->display = alloc_surface (instance, &ddsd);
00235     if (instance->display == NULL) {
00236         fprintf (stderr, "Can not create directDraw display surface\n");
00237         return 1;
00238     }
00239 
00240     if (DD_OK != IDirectDraw2_CreateClipper (instance->ddraw, 0,
00241                                              &instance->clipper, NULL) ||
00242         DD_OK != IDirectDrawClipper_SetHWnd (instance->clipper, 0,
00243                                              instance->window) ||
00244         DD_OK != IDirectDrawSurface_SetClipper (instance->display,
00245                                                 instance->clipper)) {
00246         fprintf (stderr, "Can not initialize directDraw clipper\n");
00247         return 1;
00248     }
00249 
00250     return 0;
00251 }
00252 
00253 static int common_setup (dx_instance_t * instance, int width, int height)
00254 {
00255     instance->width = width;
00256     instance->height = height;
00257     instance->index = 0;
00258 
00259     if (create_window (instance) || dx_init (instance))
00260         return 1;
00261     return 0;
00262 }
00263 
00264 static int dxrgb_setup (vo_instance_t * _instance, int width, int height,
00265                         vo_setup_result_t * result)
00266 {
00267     dx_instance_t * instance = (dx_instance_t *) _instance;
00268     HDC hdc;
00269     int bpp;
00270 
00271     if (common_setup (instance, width, height))
00272         return 1;
00273 
00274     hdc = GetDC (NULL);
00275     bpp = GetDeviceCaps (hdc, BITSPIXEL);
00276     ReleaseDC (NULL, hdc);
00277 
00278     result->convert = convert_rgb (CONVERT_RGB, bpp);
00279     return 0;
00280 }
00281 
00282 static LPDIRECTDRAWSURFACE2 alloc_frame (dx_instance_t * instance)
00283 {
00284     DDSURFACEDESC ddsd;
00285     LPDIRECTDRAWSURFACE2 surface;
00286 
00287     memset (&ddsd, 0, sizeof (DDSURFACEDESC));
00288     ddsd.dwSize = sizeof (DDSURFACEDESC);
00289     ddsd.ddpfPixelFormat.dwSize = sizeof (DDPIXELFORMAT);
00290     ddsd.dwFlags = DDSD_HEIGHT | DDSD_WIDTH | DDSD_CAPS;
00291     ddsd.dwHeight = instance->height;
00292     ddsd.dwWidth = instance->width;
00293     ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_SYSTEMMEMORY;
00294 
00295     surface = alloc_surface (instance, &ddsd);
00296     if (surface == NULL)
00297         fprintf (stderr, "Can not create directDraw frame surface\n");
00298     return surface;
00299 }
00300 
00301 static void * surface_addr (LPDIRECTDRAWSURFACE2 surface, int * stride)
00302 {
00303     DDSURFACEDESC ddsd;
00304 
00305     memset (&ddsd, 0, sizeof (DDSURFACEDESC));
00306     ddsd.dwSize = sizeof (DDSURFACEDESC);
00307     IDirectDrawSurface2_Lock (surface, NULL, &ddsd,
00308                               DDLOCK_NOSYSLOCK | DDLOCK_WAIT, NULL);
00309     IDirectDrawSurface2_Unlock (surface, NULL);
00310     *stride = ddsd.lPitch;
00311     return ddsd.lpSurface;
00312 }
00313 
00314 static void dx_setup_fbuf (vo_instance_t * _instance,
00315                            uint8_t ** buf, void ** id)
00316 {
00317     dx_instance_t * instance = (dx_instance_t *) _instance;
00318     int stride;
00319 
00320     *id = instance->frame[instance->index++] = alloc_frame (instance);
00321     buf[0] = surface_addr (*id, &stride);
00322     buf[1] = NULL;      buf[2] = NULL;
00323 }
00324 
00325 static void dxrgb_draw_frame (vo_instance_t * _instance,
00326                               uint8_t * const * buf, void * id)
00327 {
00328     dx_instance_t * instance = (dx_instance_t *) _instance;
00329     LPDIRECTDRAWSURFACE2 surface = (LPDIRECTDRAWSURFACE2) id;
00330     DDBLTFX ddbltfx;
00331 
00332     check_events (instance);
00333 
00334     memset (&ddbltfx, 0, sizeof (DDBLTFX));
00335     ddbltfx.dwSize = sizeof (DDBLTFX);
00336     ddbltfx.dwDDFX = DDBLTFX_NOTEARING;
00337     if (DDERR_SURFACELOST ==
00338         IDirectDrawSurface2_Blt (instance->display, &instance->window_coords,
00339                                  surface, NULL, DDBLT_WAIT, &ddbltfx)) {
00340         /* restore surface and try again */
00341         IDirectDrawSurface2_Restore (instance->display);
00342         IDirectDrawSurface2_Blt (instance->display, &instance->window_coords,
00343                                  surface, NULL, DDBLT_WAIT, &ddbltfx);
00344     }
00345 }
00346 
00347 static vo_instance_t * common_open (int (* setup) (vo_instance_t *, int, int,
00348                                                    vo_setup_result_t *),
00349                                     void (* setup_fbuf) (vo_instance_t *,
00350                                                          uint8_t **, void **),
00351                                     void (* draw) (vo_instance_t *,
00352                                                    uint8_t * const *,
00353                                                    void * id))
00354 {
00355     dx_instance_t * instance;
00356 
00357     instance = malloc (sizeof (dx_instance_t));
00358     if (instance == NULL)
00359         return NULL;
00360 
00361     memset (instance, 0, sizeof (dx_instance_t));
00362     instance->vo.setup = setup;
00363     instance->vo.setup_fbuf = setup_fbuf;
00364     instance->vo.set_fbuf = NULL;
00365     instance->vo.start_fbuf = NULL;
00366     instance->vo.draw = draw;
00367     instance->vo.discard = NULL;
00368     instance->vo.close = NULL; //dx_close;
00369 
00370     return (vo_instance_t *) instance;
00371 }
00372 
00373 vo_instance_t * vo_dxrgb_open (void)
00374 {
00375     return common_open (dxrgb_setup, dx_setup_fbuf, dxrgb_draw_frame);
00376 }
00377 
00378 static LPDIRECTDRAWSURFACE2 alloc_overlay (dx_instance_t * instance)
00379 {
00380     DDSURFACEDESC ddsd;
00381     LPDIRECTDRAWSURFACE2 surface;
00382 
00383     memset (&ddsd, 0, sizeof (DDSURFACEDESC));
00384     ddsd.dwSize = sizeof (DDSURFACEDESC);
00385     ddsd.ddpfPixelFormat.dwSize = sizeof (DDPIXELFORMAT);
00386     ddsd.dwFlags = DDSD_HEIGHT | DDSD_WIDTH | DDSD_CAPS;
00387     ddsd.dwHeight = instance->height;
00388     ddsd.dwWidth = instance->width;
00389     ddsd.ddpfPixelFormat.dwFlags = DDPF_FOURCC;
00390     ddsd.ddpfPixelFormat.dwFourCC = FOURCC_YV12;
00391     ddsd.dwFlags |= DDSD_PIXELFORMAT;
00392     ddsd.ddsCaps.dwCaps = DDSCAPS_OVERLAY | DDSCAPS_VIDEOMEMORY;
00393 #if USE_OVERLAY_TRIPLE_BUFFERING
00394     ddsd.dwFlags |= DDSD_BACKBUFFERCOUNT;
00395     ddsd.ddsCaps.dwCaps |= DDSCAPS_COMPLEX | DDSCAPS_FLIP;
00396 #endif
00397     ddsd.dwBackBufferCount = 2;
00398 
00399     surface = alloc_surface (instance, &ddsd);
00400     if (surface == NULL)
00401         fprintf (stderr, "Can not create directDraw frame surface\n");
00402     return surface;
00403 }
00404 
00405 static int dx_setup (vo_instance_t * _instance, int width, int height,
00406                      vo_setup_result_t * result)
00407 {
00408     dx_instance_t * instance = (dx_instance_t *) _instance;
00409     LPDIRECTDRAWSURFACE2 surface;
00410     DDSURFACEDESC ddsd;
00411 
00412     if (common_setup (instance, width, height))
00413         return 1;
00414 
00415     instance->overlay = alloc_overlay (instance);
00416     if (!instance->overlay)
00417         return 1;
00418     update_overlay (instance);
00419 
00420     surface = instance->overlay;
00421 
00422     /* Get the back buffer */
00423     memset (&ddsd.ddsCaps, 0, sizeof (DDSCAPS));
00424     ddsd.ddsCaps.dwCaps = DDSCAPS_BACKBUFFER;
00425     if (DD_OK != IDirectDrawSurface2_GetAttachedSurface (instance->overlay,
00426                                                          &ddsd.ddsCaps,
00427                                                          &surface))
00428         surface = instance->overlay;
00429 
00430     instance->yuv[0] = surface_addr (surface, &instance->stride);
00431     instance->yuv[2] = instance->yuv[0] + instance->stride * instance->height;
00432     instance->yuv[1] =
00433         instance->yuv[2] + (instance->stride * instance->height >> 2);
00434 
00435     result->convert = NULL;
00436     return 0;
00437 }
00438 
00439 static void copy_yuv_picture (dx_instance_t * instance,
00440                               uint8_t * const * buf, void * id)
00441 {
00442     uint8_t * dest[3];
00443     int width, i;
00444 
00445     dest[0] = instance->yuv[0];
00446     dest[1] = instance->yuv[1];
00447     dest[2] = instance->yuv[2];
00448 
00449     width = instance->width;
00450     for (i = 0; i < instance->height >> 1; i++) {
00451         memcpy (dest[0], buf[0] + 2 * i * width, width);
00452         dest[0] += instance->stride;
00453         memcpy (dest[0], buf[0] + (2 * i + 1) * width, width);
00454         dest[0] += instance->stride;
00455         memcpy (dest[1], buf[1] + i * (width >> 1), width >> 1);
00456         dest[1] += instance->stride >> 1;
00457         memcpy (dest[2], buf[2] + i * (width >> 1), width >> 1);
00458         dest[2] += instance->stride >> 1;
00459     }
00460 }
00461 
00462 static void dx_draw_frame (vo_instance_t * _instance,
00463                            uint8_t * const * buf, void * id)
00464 {
00465     dx_instance_t * instance = (dx_instance_t *) _instance;
00466 
00467     check_events (instance);
00468 
00469     copy_yuv_picture (instance, buf, id);
00470 
00471     if (DDERR_SURFACELOST ==
00472         IDirectDrawSurface2_Flip (instance->overlay, NULL, DDFLIP_WAIT)) {
00473         /* restore surfaces and try again */
00474         IDirectDrawSurface2_Restore (instance->display);
00475         IDirectDrawSurface2_Restore (instance->overlay);
00476         IDirectDrawSurface2_Flip (instance->overlay, NULL, DDFLIP_WAIT);
00477     }
00478 }
00479 
00480 vo_instance_t * vo_dx_open (void)
00481 {
00482     return common_open (dx_setup, NULL, dx_draw_frame);
00483 }
00484 
00485 #if 0
00486 static void dx_close (vo_instance_t * _instance)
00487 {
00488     dx_instance_t * instance;
00489     int i;
00490 
00491     instance = (dx_instance_t *) _instance;
00492 
00493     if (instance->using_overlay && instance->overlay) {
00494         IDirectDrawSurface2_Release (instance->overlay);
00495         instance->overlay = NULL;
00496     } else
00497         for (i = 0; i < 3; i++) {
00498             if (instance->frame[i].p_surface != NULL)
00499                 IDirectDrawSurface2_Release (instance->frame[i].p_surface);
00500             instance->frame[i].p_surface = NULL;
00501         }
00502 
00503     if (instance->clipper != NULL)
00504         IDirectDrawClipper_Release (instance->clipper);
00505 
00506     if (instance->display != NULL)
00507         IDirectDrawSurface2_Release (instance->display);
00508 
00509     if (instance->ddraw != NULL)
00510         IDirectDraw2_Release (instance->ddraw);
00511 
00512     if (instance->hddraw_dll != NULL)
00513         FreeLibrary (instance->hddraw_dll);
00514 
00515     if (instance->window != NULL)
00516         DestroyWindow (instance->window);
00517 }
00518 
00519 #endif
00520 #endif
 

Powered by Plone

This site conforms to the following standards: