Blame client/X11/xf_tsmf.c

Packit 1fb8d4
/**
Packit 1fb8d4
 * FreeRDP: A Remote Desktop Protocol Implementation
Packit 1fb8d4
 * X11 Video Redirection
Packit 1fb8d4
 *
Packit 1fb8d4
 * Copyright 2010-2011 Vic Lee
Packit 1fb8d4
 *
Packit 1fb8d4
 * Licensed under the Apache License, Version 2.0 (the "License");
Packit 1fb8d4
 * you may not use this file except in compliance with the License.
Packit 1fb8d4
 * You may obtain a copy of the License at
Packit 1fb8d4
 *
Packit 1fb8d4
 *     http://www.apache.org/licenses/LICENSE-2.0
Packit 1fb8d4
 *
Packit 1fb8d4
 * Unless required by applicable law or agreed to in writing, software
Packit 1fb8d4
 * distributed under the License is distributed on an "AS IS" BASIS,
Packit 1fb8d4
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
Packit 1fb8d4
 * See the License for the specific language governing permissions and
Packit 1fb8d4
 * limitations under the License.
Packit 1fb8d4
 */
Packit 1fb8d4
Packit 1fb8d4
#ifdef HAVE_CONFIG_H
Packit 1fb8d4
#include "config.h"
Packit 1fb8d4
#endif
Packit 1fb8d4
Packit 1fb8d4
#include <winpr/crt.h>
Packit 1fb8d4
Packit 1fb8d4
#include <sys/ipc.h>
Packit 1fb8d4
#include <sys/shm.h>
Packit 1fb8d4
Packit 1fb8d4
#include <X11/Xlib.h>
Packit 1fb8d4
#include <X11/Xutil.h>
Packit 1fb8d4
#include <X11/Xatom.h>
Packit 1fb8d4
#include <X11/extensions/XShm.h>
Packit 1fb8d4
Packit 1fb8d4
#include <freerdp/log.h>
Packit 1fb8d4
#include <freerdp/client/tsmf.h>
Packit 1fb8d4
Packit 1fb8d4
#include "xf_tsmf.h"
Packit 1fb8d4
Packit 1fb8d4
#ifdef WITH_XV
Packit 1fb8d4
Packit 1fb8d4
#include <X11/extensions/Xv.h>
Packit 1fb8d4
#include <X11/extensions/Xvlib.h>
Packit 1fb8d4
Packit 1fb8d4
static long xv_port = 0;
Packit 1fb8d4
Packit 1fb8d4
struct xf_xv_context
Packit 1fb8d4
{
Packit 1fb8d4
	long xv_port;
Packit 1fb8d4
	Atom xv_colorkey_atom;
Packit 1fb8d4
	int xv_image_size;
Packit 1fb8d4
	int xv_shmid;
Packit 1fb8d4
	char* xv_shmaddr;
Packit 1fb8d4
	UINT32* xv_pixfmts;
Packit 1fb8d4
};
Packit 1fb8d4
typedef struct xf_xv_context xfXvContext;
Packit 1fb8d4
Packit 1fb8d4
#define TAG CLIENT_TAG("x11")
Packit 1fb8d4
Packit 1fb8d4
static BOOL xf_tsmf_is_format_supported(xfXvContext* xv, UINT32 pixfmt)
Packit 1fb8d4
{
Packit 1fb8d4
	int i;
Packit 1fb8d4
Packit 1fb8d4
	if (!xv->xv_pixfmts)
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	for (i = 0; xv->xv_pixfmts[i]; i++)
Packit 1fb8d4
	{
Packit 1fb8d4
		if (xv->xv_pixfmts[i] == pixfmt)
Packit 1fb8d4
			return TRUE;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	return FALSE;
Packit 1fb8d4
}
Packit 1fb8d4
Packit Service 5a9772
static int xf_tsmf_xv_video_frame_event(TsmfClientContext* tsmf, TSMF_VIDEO_FRAME_EVENT* event)
Packit 1fb8d4
{
Packit 1fb8d4
	int i;
Packit 1fb8d4
	int x, y;
Packit 1fb8d4
	UINT32 width;
Packit 1fb8d4
	UINT32 height;
Packit 1fb8d4
	BYTE* data1;
Packit 1fb8d4
	BYTE* data2;
Packit 1fb8d4
	UINT32 pixfmt;
Packit 1fb8d4
	UINT32 xvpixfmt;
Packit 1fb8d4
	XvImage* image;
Packit 1fb8d4
	int colorkey = 0;
Packit 1fb8d4
	int numRects = 0;
Packit 1fb8d4
	xfContext* xfc;
Packit 1fb8d4
	xfXvContext* xv;
Packit Service 5a9772
	XRectangle* xrects = NULL;
Packit 1fb8d4
	XShmSegmentInfo shminfo;
Packit 1fb8d4
	BOOL converti420yv12 = FALSE;
Packit 1fb8d4
Packit 1fb8d4
	if (!tsmf)
Packit 1fb8d4
		return -1;
Packit 1fb8d4
Packit Service 5a9772
	xfc = (xfContext*)tsmf->custom;
Packit 1fb8d4
Packit 1fb8d4
	if (!xfc)
Packit 1fb8d4
		return -1;
Packit 1fb8d4
Packit Service 5a9772
	xv = (xfXvContext*)xfc->xv_context;
Packit 1fb8d4
Packit 1fb8d4
	if (!xv)
Packit 1fb8d4
		return -1;
Packit 1fb8d4
Packit 1fb8d4
	if (xv->xv_port == 0)
Packit 1fb8d4
		return -1001;
Packit 1fb8d4
Packit 1fb8d4
	/* In case the player is minimized */
Packit 1fb8d4
	if (event->x < -2048 || event->y < -2048 || event->numVisibleRects == 0)
Packit 1fb8d4
	{
Packit 1fb8d4
		return -1002;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	xrects = NULL;
Packit 1fb8d4
	numRects = event->numVisibleRects;
Packit 1fb8d4
Packit 1fb8d4
	if (numRects > 0)
Packit 1fb8d4
	{
Packit Service 5a9772
		xrects = (XRectangle*)calloc(numRects, sizeof(XRectangle));
Packit 1fb8d4
Packit 1fb8d4
		if (!xrects)
Packit 1fb8d4
			return -1;
Packit 1fb8d4
Packit 1fb8d4
		for (i = 0; i < numRects; i++)
Packit 1fb8d4
		{
Packit 1fb8d4
			x = event->x + event->visibleRects[i].left;
Packit 1fb8d4
			y = event->y + event->visibleRects[i].top;
Packit 1fb8d4
			width = event->visibleRects[i].right - event->visibleRects[i].left;
Packit 1fb8d4
			height = event->visibleRects[i].bottom - event->visibleRects[i].top;
Packit 1fb8d4
Packit 1fb8d4
			xrects[i].x = x;
Packit 1fb8d4
			xrects[i].y = y;
Packit 1fb8d4
			xrects[i].width = width;
Packit 1fb8d4
			xrects[i].height = height;
Packit 1fb8d4
		}
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	if (xv->xv_colorkey_atom != None)
Packit 1fb8d4
	{
Packit 1fb8d4
		XvGetPortAttribute(xfc->display, xv->xv_port, xv->xv_colorkey_atom, &colorkey);
Packit 1fb8d4
		XSetFunction(xfc->display, xfc->gc, GXcopy);
Packit 1fb8d4
		XSetFillStyle(xfc->display, xfc->gc, FillSolid);
Packit 1fb8d4
		XSetForeground(xfc->display, xfc->gc, colorkey);
Packit 1fb8d4
Packit 1fb8d4
		if (event->numVisibleRects < 1)
Packit 1fb8d4
		{
Packit 1fb8d4
			XSetClipMask(xfc->display, xfc->gc, None);
Packit 1fb8d4
		}
Packit 1fb8d4
		else
Packit 1fb8d4
		{
Packit 1fb8d4
			XFillRectangles(xfc->display, xfc->window->handle, xfc->gc, xrects, numRects);
Packit 1fb8d4
		}
Packit 1fb8d4
	}
Packit 1fb8d4
	else
Packit 1fb8d4
	{
Packit 1fb8d4
		XSetFunction(xfc->display, xfc->gc, GXcopy);
Packit 1fb8d4
		XSetFillStyle(xfc->display, xfc->gc, FillSolid);
Packit 1fb8d4
Packit 1fb8d4
		if (event->numVisibleRects < 1)
Packit 1fb8d4
		{
Packit 1fb8d4
			XSetClipMask(xfc->display, xfc->gc, None);
Packit 1fb8d4
		}
Packit 1fb8d4
		else
Packit 1fb8d4
		{
Packit 1fb8d4
			XSetClipRectangles(xfc->display, xfc->gc, 0, 0, xrects, numRects, YXBanded);
Packit 1fb8d4
		}
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	pixfmt = event->framePixFmt;
Packit 1fb8d4
Packit 1fb8d4
	if (xf_tsmf_is_format_supported(xv, pixfmt))
Packit 1fb8d4
	{
Packit 1fb8d4
		xvpixfmt = pixfmt;
Packit 1fb8d4
	}
Packit 1fb8d4
	else if (pixfmt == RDP_PIXFMT_I420 && xf_tsmf_is_format_supported(xv, RDP_PIXFMT_YV12))
Packit 1fb8d4
	{
Packit 1fb8d4
		xvpixfmt = RDP_PIXFMT_YV12;
Packit 1fb8d4
		converti420yv12 = TRUE;
Packit 1fb8d4
	}
Packit 1fb8d4
	else if (pixfmt == RDP_PIXFMT_YV12 && xf_tsmf_is_format_supported(xv, RDP_PIXFMT_I420))
Packit 1fb8d4
	{
Packit 1fb8d4
		xvpixfmt = RDP_PIXFMT_I420;
Packit 1fb8d4
		converti420yv12 = TRUE;
Packit 1fb8d4
	}
Packit 1fb8d4
	else
Packit 1fb8d4
	{
Packit Service 5a9772
		WLog_DBG(TAG, "pixel format 0x%" PRIX32 " not supported by hardware.", pixfmt);
Packit 1fb8d4
		free(xrects);
Packit 1fb8d4
		return -1003;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit Service 5a9772
	image = XvShmCreateImage(xfc->display, xv->xv_port, xvpixfmt, 0, event->frameWidth,
Packit Service 5a9772
	                         event->frameHeight, &shminfo);
Packit 1fb8d4
Packit 1fb8d4
	if (xv->xv_image_size != image->data_size)
Packit 1fb8d4
	{
Packit 1fb8d4
		if (xv->xv_image_size > 0)
Packit 1fb8d4
		{
Packit 1fb8d4
			shmdt(xv->xv_shmaddr);
Packit 1fb8d4
			shmctl(xv->xv_shmid, IPC_RMID, NULL);
Packit 1fb8d4
		}
Packit 1fb8d4
Packit 1fb8d4
		xv->xv_image_size = image->data_size;
Packit 1fb8d4
		xv->xv_shmid = shmget(IPC_PRIVATE, image->data_size, IPC_CREAT | 0777);
Packit 1fb8d4
		xv->xv_shmaddr = shmat(xv->xv_shmid, 0, 0);
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	shminfo.shmid = xv->xv_shmid;
Packit 1fb8d4
	shminfo.shmaddr = image->data = xv->xv_shmaddr;
Packit 1fb8d4
	shminfo.readOnly = FALSE;
Packit 1fb8d4
Packit 1fb8d4
	if (!XShmAttach(xfc->display, &shminfo))
Packit 1fb8d4
	{
Packit 1fb8d4
		XFree(image);
Packit 1fb8d4
		free(xrects);
Packit 1fb8d4
		WLog_DBG(TAG, "XShmAttach failed.");
Packit 1fb8d4
		return -1004;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	/* The video driver may align each line to a different size
Packit 1fb8d4
	   and we need to convert our original image data. */
Packit 1fb8d4
	switch (pixfmt)
Packit 1fb8d4
	{
Packit 1fb8d4
		case RDP_PIXFMT_I420:
Packit 1fb8d4
		case RDP_PIXFMT_YV12:
Packit 1fb8d4
			/* Y */
Packit 1fb8d4
			if (image->pitches[0] == event->frameWidth)
Packit 1fb8d4
			{
Packit Service 5a9772
				CopyMemory(image->data + image->offsets[0], event->frameData,
Packit Service 5a9772
				           event->frameWidth * event->frameHeight);
Packit 1fb8d4
			}
Packit 1fb8d4
			else
Packit 1fb8d4
			{
Packit 1fb8d4
				for (i = 0; i < event->frameHeight; i++)
Packit 1fb8d4
				{
Packit 1fb8d4
					CopyMemory(image->data + image->offsets[0] + i * image->pitches[0],
Packit Service 5a9772
					           event->frameData + i * event->frameWidth, event->frameWidth);
Packit 1fb8d4
				}
Packit 1fb8d4
			}
Packit 1fb8d4
			/* UV */
Packit 1fb8d4
			/* Conversion between I420 and YV12 is to simply swap U and V */
Packit 1fb8d4
			if (!converti420yv12)
Packit 1fb8d4
			{
Packit 1fb8d4
				data1 = event->frameData + event->frameWidth * event->frameHeight;
Packit 1fb8d4
				data2 = event->frameData + event->frameWidth * event->frameHeight +
Packit Service 5a9772
				        event->frameWidth * event->frameHeight / 4;
Packit 1fb8d4
			}
Packit 1fb8d4
			else
Packit 1fb8d4
			{
Packit 1fb8d4
				data2 = event->frameData + event->frameWidth * event->frameHeight;
Packit 1fb8d4
				data1 = event->frameData + event->frameWidth * event->frameHeight +
Packit Service 5a9772
				        event->frameWidth * event->frameHeight / 4;
Packit 1fb8d4
				image->id = pixfmt == RDP_PIXFMT_I420 ? RDP_PIXFMT_YV12 : RDP_PIXFMT_I420;
Packit 1fb8d4
			}
Packit 1fb8d4
Packit 1fb8d4
			if (image->pitches[1] * 2 == event->frameWidth)
Packit 1fb8d4
			{
Packit Service 5a9772
				CopyMemory(image->data + image->offsets[1], data1,
Packit Service 5a9772
				           event->frameWidth * event->frameHeight / 4);
Packit Service 5a9772
				CopyMemory(image->data + image->offsets[2], data2,
Packit Service 5a9772
				           event->frameWidth * event->frameHeight / 4);
Packit 1fb8d4
			}
Packit 1fb8d4
			else
Packit 1fb8d4
			{
Packit 1fb8d4
				for (i = 0; i < event->frameHeight / 2; i++)
Packit 1fb8d4
				{
Packit 1fb8d4
					CopyMemory(image->data + image->offsets[1] + i * image->pitches[1],
Packit Service 5a9772
					           data1 + i * event->frameWidth / 2, event->frameWidth / 2);
Packit 1fb8d4
					CopyMemory(image->data + image->offsets[2] + i * image->pitches[2],
Packit Service 5a9772
					           data2 + i * event->frameWidth / 2, event->frameWidth / 2);
Packit 1fb8d4
				}
Packit 1fb8d4
			}
Packit 1fb8d4
			break;
Packit 1fb8d4
Packit 1fb8d4
		default:
Packit Service 5a9772
			if (image->data_size < 0)
Packit Service 5a9772
			{
Packit Service 5a9772
				free(xrects);
Packit Service 5a9772
				return -2000;
Packit Service 5a9772
			}
Packit Service 5a9772
			else
Packit Service 5a9772
			{
Packit Service 5a9772
				const size_t size = ((UINT32)image->data_size <= event->frameSize)
Packit Service 5a9772
				                        ? (UINT32)image->data_size
Packit Service 5a9772
				                        : event->frameSize;
Packit Service 5a9772
				CopyMemory(image->data, event->frameData, size);
Packit Service 5a9772
			}
Packit 1fb8d4
			break;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit Service 5a9772
	XvShmPutImage(xfc->display, xv->xv_port, xfc->window->handle, xfc->gc, image, 0, 0,
Packit Service 5a9772
	              image->width, image->height, event->x, event->y, event->width, event->height,
Packit Service 5a9772
	              FALSE);
Packit 1fb8d4
Packit 1fb8d4
	if (xv->xv_colorkey_atom == None)
Packit 1fb8d4
		XSetClipMask(xfc->display, xfc->gc, None);
Packit 1fb8d4
Packit 1fb8d4
	XSync(xfc->display, FALSE);
Packit 1fb8d4
Packit 1fb8d4
	XShmDetach(xfc->display, &shminfo);
Packit 1fb8d4
	XFree(image);
Packit 1fb8d4
Packit 1fb8d4
	free(xrects);
Packit 1fb8d4
Packit 1fb8d4
	return 1;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
int xf_tsmf_xv_init(xfContext* xfc, TsmfClientContext* tsmf)
Packit 1fb8d4
{
Packit 1fb8d4
	int ret;
Packit 1fb8d4
	unsigned int i;
Packit 1fb8d4
	unsigned int version;
Packit 1fb8d4
	unsigned int release;
Packit 1fb8d4
	unsigned int event_base;
Packit 1fb8d4
	unsigned int error_base;
Packit 1fb8d4
	unsigned int request_base;
Packit 1fb8d4
	unsigned int num_adaptors;
Packit 1fb8d4
	xfXvContext* xv;
Packit 1fb8d4
	XvAdaptorInfo* ai;
Packit 1fb8d4
	XvAttribute* attr;
Packit 1fb8d4
	XvImageFormatValues* fo;
Packit 1fb8d4
Packit 1fb8d4
	if (xfc->xv_context)
Packit 1fb8d4
		return 1; /* context already created */
Packit 1fb8d4
Packit Service 5a9772
	xv = (xfXvContext*)calloc(1, sizeof(xfXvContext));
Packit 1fb8d4
Packit 1fb8d4
	if (!xv)
Packit 1fb8d4
		return -1;
Packit 1fb8d4
Packit 1fb8d4
	xfc->xv_context = xv;
Packit 1fb8d4
Packit 1fb8d4
	xv->xv_colorkey_atom = None;
Packit 1fb8d4
	xv->xv_image_size = 0;
Packit 1fb8d4
	xv->xv_port = xv_port;
Packit 1fb8d4
Packit 1fb8d4
	if (!XShmQueryExtension(xfc->display))
Packit 1fb8d4
	{
Packit 1fb8d4
		WLog_DBG(TAG, "no xshm available.");
Packit 1fb8d4
		return -1;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit Service 5a9772
	ret =
Packit Service 5a9772
	    XvQueryExtension(xfc->display, &version, &release, &request_base, &event_base, &error_base);
Packit 1fb8d4
Packit 1fb8d4
	if (ret != Success)
Packit 1fb8d4
	{
Packit 1fb8d4
		WLog_DBG(TAG, "XvQueryExtension failed %d.", ret);
Packit 1fb8d4
		return -1;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	WLog_DBG(TAG, "version %u release %u", version, release);
Packit 1fb8d4
Packit Service 5a9772
	ret = XvQueryAdaptors(xfc->display, DefaultRootWindow(xfc->display), &num_adaptors, &ai;;
Packit 1fb8d4
Packit 1fb8d4
	if (ret != Success)
Packit 1fb8d4
	{
Packit 1fb8d4
		WLog_DBG(TAG, "XvQueryAdaptors failed %d.", ret);
Packit 1fb8d4
		return -1;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	for (i = 0; i < num_adaptors; i++)
Packit 1fb8d4
	{
Packit 1fb8d4
		WLog_DBG(TAG, "adapter port %lu-%lu (%s)", ai[i].base_id,
Packit Service 5a9772
		         ai[i].base_id + ai[i].num_ports - 1, ai[i].name);
Packit 1fb8d4
Packit 1fb8d4
		if (xv->xv_port == 0 && i == num_adaptors - 1)
Packit 1fb8d4
			xv->xv_port = ai[i].base_id;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	if (num_adaptors > 0)
Packit 1fb8d4
		XvFreeAdaptorInfo(ai);
Packit 1fb8d4
Packit 1fb8d4
	if (xv->xv_port == 0)
Packit 1fb8d4
	{
Packit 1fb8d4
		WLog_DBG(TAG, "no adapter selected, video frames will not be processed.");
Packit 1fb8d4
		return -1;
Packit 1fb8d4
	}
Packit 1fb8d4
	WLog_DBG(TAG, "selected %ld", xv->xv_port);
Packit 1fb8d4
Packit 1fb8d4
	attr = XvQueryPortAttributes(xfc->display, xv->xv_port, &ret;;
Packit 1fb8d4
Packit 1fb8d4
	for (i = 0; i < (unsigned int)ret; i++)
Packit 1fb8d4
	{
Packit 1fb8d4
		if (strcmp(attr[i].name, "XV_COLORKEY") == 0)
Packit 1fb8d4
		{
Packit 1fb8d4
			xv->xv_colorkey_atom = XInternAtom(xfc->display, "XV_COLORKEY", FALSE);
Packit Service 5a9772
			XvSetPortAttribute(xfc->display, xv->xv_port, xv->xv_colorkey_atom,
Packit Service 5a9772
			                   attr[i].min_value + 1);
Packit 1fb8d4
			break;
Packit 1fb8d4
		}
Packit 1fb8d4
	}
Packit 1fb8d4
	XFree(attr);
Packit 1fb8d4
Packit 1fb8d4
	WLog_DBG(TAG, "xf_tsmf_init: pixel format ");
Packit 1fb8d4
Packit 1fb8d4
	fo = XvListImageFormats(xfc->display, xv->xv_port, &ret;;
Packit 1fb8d4
Packit 1fb8d4
	if (ret > 0)
Packit 1fb8d4
	{
Packit Service 5a9772
		xv->xv_pixfmts = (UINT32*)calloc((ret + 1), sizeof(UINT32));
Packit 1fb8d4
Packit Service 5a9772
		for (i = 0; i < (unsigned int)ret; i++)
Packit 1fb8d4
		{
Packit 1fb8d4
			xv->xv_pixfmts[i] = fo[i].id;
Packit Service 5a9772
			WLog_DBG(TAG, "%c%c%c%c ", ((char*)(xv->xv_pixfmts + i))[0],
Packit Service 5a9772
			         ((char*)(xv->xv_pixfmts + i))[1], ((char*)(xv->xv_pixfmts + i))[2],
Packit Service 5a9772
			         ((char*)(xv->xv_pixfmts + i))[3]);
Packit 1fb8d4
		}
Packit 1fb8d4
		xv->xv_pixfmts[i] = 0;
Packit 1fb8d4
	}
Packit 1fb8d4
	XFree(fo);
Packit 1fb8d4
Packit 1fb8d4
	if (tsmf)
Packit 1fb8d4
	{
Packit 1fb8d4
		xfc->tsmf = tsmf;
Packit Service 5a9772
		tsmf->custom = (void*)xfc;
Packit 1fb8d4
Packit 1fb8d4
		tsmf->FrameEvent = xf_tsmf_xv_video_frame_event;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	return 1;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
int xf_tsmf_xv_uninit(xfContext* xfc, TsmfClientContext* tsmf)
Packit 1fb8d4
{
Packit Service 5a9772
	xfXvContext* xv = (xfXvContext*)xfc->xv_context;
Packit 1fb8d4
Packit Service 5a9772
	WINPR_UNUSED(tsmf);
Packit 1fb8d4
	if (xv)
Packit 1fb8d4
	{
Packit 1fb8d4
		if (xv->xv_image_size > 0)
Packit 1fb8d4
		{
Packit 1fb8d4
			shmdt(xv->xv_shmaddr);
Packit 1fb8d4
			shmctl(xv->xv_shmid, IPC_RMID, NULL);
Packit 1fb8d4
		}
Packit 1fb8d4
		if (xv->xv_pixfmts)
Packit 1fb8d4
		{
Packit 1fb8d4
			free(xv->xv_pixfmts);
Packit 1fb8d4
			xv->xv_pixfmts = NULL;
Packit 1fb8d4
		}
Packit 1fb8d4
		free(xv);
Packit 1fb8d4
		xfc->xv_context = NULL;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	if (xfc->tsmf)
Packit 1fb8d4
	{
Packit 1fb8d4
		xfc->tsmf->custom = NULL;
Packit 1fb8d4
		xfc->tsmf = NULL;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	return 1;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
#endif
Packit 1fb8d4
Packit 1fb8d4
int xf_tsmf_init(xfContext* xfc, TsmfClientContext* tsmf)
Packit 1fb8d4
{
Packit 1fb8d4
#ifdef WITH_XV
Packit 1fb8d4
	return xf_tsmf_xv_init(xfc, tsmf);
Packit 1fb8d4
#endif
Packit 1fb8d4
Packit 1fb8d4
	return 1;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
int xf_tsmf_uninit(xfContext* xfc, TsmfClientContext* tsmf)
Packit 1fb8d4
{
Packit 1fb8d4
#ifdef WITH_XV
Packit 1fb8d4
	return xf_tsmf_xv_uninit(xfc, tsmf);
Packit 1fb8d4
#endif
Packit 1fb8d4
Packit 1fb8d4
	return 1;
Packit 1fb8d4
}