File:
[DVB] /
libsoftmpeg /
src /
v_directfb.c
Revision
1.5:
download - view:
text,
annotated -
select for diffs
Wed Mar 17 19:14:00 2004 UTC (20 years, 3 months ago) by
hunold
Branches:
MAIN
CVS tags:
HEAD
- remove all references to av_frame, put data into new video_frame structure
- remove software image conversion stuff, no hw support, no libsoftmpeg 8-)
- clean up video_prepare() function, remove libavcodec specific stuff
/*
(c) Copyright 2004 convergence GmbH
All rights reserved.
Written by Michael Hunold <hunold@convergence.de> and
Denis Oliver Kropp <dok@directfb.org>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the
Free Software Foundation, Inc., 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA.
*/
#include "video.h"
static struct v_directfb_data
{
IDirectFB *DirectFB;
IDirectFBDisplayLayer *layer;
IDirectFBSurface *window_surface;
IDirectFBSurface *video_surface;
DFBSurfacePixelFormat format;
unsigned int width;
unsigned int height;
int use_layer;
int field;
} priv;
/* fixme: belongs to DirectFB */
#include <linux/fb.h>
#include <sys/ioctl.h>
static int get_refresh_rates(int *v)
{
int fh;
struct fb_var_screeninfo si;
double drate;
double hrate;
double vrate;
long htotal;
long vtotal;
fh = open("/dev/fb0", O_RDONLY);
if (-1 == fh) {
return -1;
}
if (ioctl(fh, FBIOGET_VSCREENINFO, &si)) {
close(fh);
return -1;
}
htotal = si.left_margin + si.xres + si.right_margin + si.hsync_len;
vtotal = si.upper_margin + si.yres + si.lower_margin + si.vsync_len;
switch (si.vmode & FB_VMODE_MASK) {
case FB_VMODE_INTERLACED:
break;
case FB_VMODE_DOUBLE:
vtotal <<= 2;
break;
default:
vtotal <<= 1;
break;
}
drate = 1E12 / si.pixclock;
hrate = drate / htotal;
vrate = hrate / vtotal * 2;
*v = 1E3 / vrate;
/* h = hrate / 1E3; */
close(fh);
return 0;
}
static int init (struct video_decoder *d, void *init_data, int *v_dura)
{
struct v_directfb_data *data = &priv;
struct softmpeg_directfb_initdata *init = (struct softmpeg_directfb_initdata*)init_data;
DFBDisplayLayerID layerid;
DFBDisplayLayerConfig dlc;
DFBDisplayLayerDescription dldesc;
if (init->layer_id != -1) {
layerid = init->layer_id;
} else {
layerid = DLID_PRIMARY;
}
SOFTMPEG_DEBUG("setting up DirectFB: layer_id:%d window_id:%d\n", layerid, init->window_id);
if (0 != get_refresh_rates(v_dura)) {
VIDEO_OUTPUT("cannot calculate vertical refresh rate\n");
return -1;
}
DirectFBInit(0, NULL);
if (DFB_OK != DirectFBCreate(&data->DirectFB)) {
VIDEO_OUTPUT("DirectFB master interface not available..\n");
return -1;
}
if (data->DirectFB->GetDisplayLayer(data->DirectFB, layerid, &data->layer) != DFB_OK) {
VIDEO_OUTPUT("GetDisplayLayer() failed.\n");
return -1;
}
if (init->window_id != -1) {
IDirectFBWindow *dfb_window;
if (DFB_OK != data->layer->SetCooperativeLevel(data->layer, DLSCL_ADMINISTRATIVE)) {
VIDEO_OUTPUT("SetCooperativeLevel() failed.\n");
return -1;
}
if (data->layer->GetWindow(data->layer, init->window_id, &dfb_window) != DFB_OK) {
VIDEO_OUTPUT("cannot get window from window_id\n");
return -1;
}
dfb_window->GetSurface(dfb_window, &data->window_surface);
dfb_window->Release(dfb_window);
data->layer->Release(data->layer);
if (data->window_surface == NULL) {
VIDEO_OUTPUT("window does not have a surface!?\n");
return -1;
}
data->window_surface->GetPixelFormat(data->window_surface, &data->format);
/* Test if blits from DSPF_I420 are hardware accelerated;
* we can avoid the software format conversion then.
*/
if (data->format != DSPF_I420) {
IDirectFBSurface *dest = data->window_surface;
IDirectFBSurface *src;
DFBSurfaceDescription desc;
DFBAccelerationMask acc;
desc.flags = DSDESC_WIDTH | DSDESC_HEIGHT | DSDESC_PIXELFORMAT;
desc.width = 32;
desc.height = 32;
desc.pixelformat = DSPF_UYVY;
if (data->DirectFB->CreateSurface(data->DirectFB, &desc, &src) == DFB_OK) {
dest->GetAccelerationMask(dest, src, &acc);
if (acc & DFXL_STRETCHBLIT) {
VIDEO_OUTPUT("Looks like our gfx hardware can stretchblit from UYVY to the video window :-)\n");
data->format = DSPF_UYVY;
}
src->Release(src);
} else {
VIDEO_OUTPUT("Arg, no hw stretchblit available.\n");
}
}
switch (data->format) {
case DSPF_UYVY:
case DSPF_I420:
case DSPF_YV12:
break;
default: {
SOFTMPEG_DEBUG("unsupported pixelformat for the destination surface, no hw acceleration available.");
return -1;
}
}
data->use_layer = 0;
SOFTMPEG_DEBUG("using non-layer configuration for video output via DirectFB\n");
return 0;
}
if (DFB_OK != data->layer->SetCooperativeLevel(data->layer, DLSCL_ADMINISTRATIVE)) {
VIDEO_OUTPUT("SetCooperativeLevel() failed.\n");
return -1;
}
data->layer->GetDescription(data->layer, &dldesc);
/* check for usable layer */
dlc.flags = DLCONF_WIDTH | DLCONF_HEIGHT | DLCONF_PIXELFORMAT | DLCONF_BUFFERMODE | DLCONF_OPTIONS;
dlc.width = init->width;
dlc.height = init->height;
dlc.pixelformat = DSPF_YV12;
dlc.buffermode = DLBM_BACKVIDEO;
dlc.options = (dldesc.caps & DLCAPS_DEINTERLACING) ? DLOP_DEINTERLACING : DLOP_NONE;
if (DFB_OK != data->layer->SetConfiguration(data->layer, &dlc)) {
VIDEO_OUTPUT("SetConfiguration() failed.\n");
return -1;
}
data->layer->SetScreenLocation(data->layer, 0.0f, 0.0f, 1.0f, 1.0f);
data->layer->GetSurface(data->layer, &data->video_surface);
data->format = DSPF_YV12;
SOFTMPEG_DEBUG("using layer configuration for video output via DirectFB\n");
data->use_layer = 1;
return 0;
}
static int prepare (struct video_decoder *d, struct video_frame *frame)
{
struct v_directfb_data *data = &priv;
DFBRectangle rect;
int pitch;
void *dst;
data->video_surface->Lock(data->video_surface, DSLF_WRITE, &dst, &pitch);
switch (data->format) {
case DSPF_I420: {
int i;
for (i = 0; i < data->height; i++)
dfb_memcpy(dst + i * pitch, frame->data[0] + i * frame->linesize[0], pitch);
dst += pitch * data->height;
for (i = 0; i < data->height / 2; i++)
dfb_memcpy(dst + i * pitch / 2, frame->data[1] + i * frame->linesize[1], pitch / 2);
dst += (pitch * data->height) / 4;
for (i = 0; i < data->height / 2; i++)
dfb_memcpy(dst + i * pitch / 2, frame->data[2] + i * frame->linesize[2], pitch / 2);
break;
}
case DSPF_YV12: {
int i;
for (i = 0; i < data->height; i++)
dfb_memcpy(dst + i * pitch, frame->data[0] + i * frame->linesize[0], pitch);
dst += pitch * data->height;
for (i = 0; i < data->height / 2; i++)
dfb_memcpy(dst + i * (pitch / 2), frame->data[2] + i * frame->linesize[2], pitch / 2);
dst += (pitch / 2) * (data->height / 2);
for (i = 0; i < data->height / 2; i++)
dfb_memcpy(dst + i * (pitch / 2), frame->data[1] + i * frame->linesize[1], pitch / 2);
break;
}
case DSPF_UYVY: {
int y, x;
uint8_t *src_y = frame->data[0];
uint8_t *src_u = frame->data[1];
uint8_t *src_v = frame->data[2];
uint16_t *dst16 = dst;
for (y = 0; y < data->height; y++) {
for (x = 0; x < data->width; x++) {
if (x & 1)
dst16[x] = (src_y[x] << 8) | src_v[x / 2];
else
dst16[x] = (src_y[x] << 8) | src_u[x / 2];
}
src_y += frame->linesize[0];
if (y & 1) {
src_u += frame->linesize[1];
src_v += frame->linesize[2];
}
dst16 += pitch / 2;
}
break;
}
default: {
VIDEO_OUTPUT("illegal surface format\n");
break;
}
}
data->video_surface->Unlock(data->video_surface);
/* flip backbuffer if necessary */
if (data->use_layer != 0) {
return 0;
}
/* copy stuff to the surface's backbuffer, but don't flip it */
rect.x = 0;
rect.y = 0;
data->window_surface->GetSize(data->window_surface, &rect.w, &rect.h);
data->window_surface->StretchBlit(data->window_surface, data->video_surface, NULL, &rect);
return 0;
}
static int resize (struct video_decoder *d, unsigned int width, unsigned int height)
{
struct v_directfb_data *data = &priv;
DFBSurfaceDescription desc;
int ret;
data->width = width;
data->height = height;
if (data->use_layer != 0) {
DFBDisplayLayerConfig dlc;
SOFTMPEG_DEBUG("changing layer configuration, w:%d, h:%d\n",width,height);
dlc.flags = DLCONF_WIDTH | DLCONF_HEIGHT;
dlc.width = width;
dlc.height = height;
data->layer->SetConfiguration(data->layer, &dlc);
data->layer->SetScreenLocation(data->layer, 0.0f, 0.0f, 1.0f, 1.0f);
return 0;
}
SOFTMPEG_DEBUG("changing window configuration, w:%d, h:%d\n",width,height);
if (data->video_surface) {
data->video_surface->Release(data->video_surface);
data->video_surface = NULL;
}
desc.flags = DSDESC_WIDTH | DSDESC_HEIGHT | DSDESC_PIXELFORMAT | DSDESC_CAPS;
/* fixme: possible bug in DirectFB (or double lock?) -- check and remove me */
desc.caps = DSCAPS_VIDEOONLY;
desc.width = width;
desc.height = height;
desc.pixelformat = data->format;
ret = data->DirectFB->CreateSurface(data->DirectFB, &desc, &data->video_surface);
return ret;
}
static int clear (struct video_decoder *d)
{
struct v_directfb_data *data = &priv;
if (data->use_layer != 0) {
data->video_surface->Clear(data->video_surface,0,0,0,0);
data->video_surface->Flip(data->video_surface, NULL, 0);
return 0;
}
data->window_surface->Clear(data->window_surface,0,0,0,0);
data->window_surface->Flip(data->window_surface, NULL, 0);
return 0;
}
static int wait_for_sync (struct video_decoder *d)
{
struct v_directfb_data *data = &priv;
data->DirectFB->WaitForSync(data->DirectFB);
return 0;
}
static int flip (struct video_decoder *d)
{
struct v_directfb_data *data = &priv;
if (data->use_layer != 0) {
long long t = softmpeg_get_millis();
long long diff;
data->video_surface->Flip(data->video_surface, NULL, DSFLIP_ONSYNC);
data->DirectFB->WaitForSync(data->DirectFB);
if ((softmpeg_get_millis() - t) < 3) {
VIDEO_AVSYNC("*");
data->DirectFB->WaitForSync(data->DirectFB);
} else {
VIDEO_AVSYNC(" ");
}
data->video_surface->SetField(data->video_surface, 1);
diff = softmpeg_get_millis() - t;
VIDEO_AVSYNC("[%2lld] ", diff);
return 0;
}
data->window_surface->Flip(data->window_surface, NULL, DSFLIP_WAITFORSYNC);
return 0;
}
struct video_operations v_directfb_ops =
{
.init = &init,
.resize = &resize,
.clear = &clear,
.prepare = &prepare,
.wait_for_sync = &wait_for_sync,
.flip = &flip,
.priv = &priv,
};
LinuxTV legacy CVS <linuxtv.org/cvs>