view libvo/vo_dxr3.c @ 3127:59ac428ae68d

Disable problematic ffmpeg.so support by default and remove die on 2.2.x and older kernel, replacing it with more in depth info. (Kernel SSE check will disable SSE, if needed!)
author atmos4
date Mon, 26 Nov 2001 00:46:44 +0000
parents 9989497ab31e
children 1d4fb4d9aab5
line wrap: on
line source

#define PES_MAX_SIZE 2048
/* 
 * vo_dxr3.c - DXR3/H+ video out
 *
 * Copyright (C) 2001 David Holm <dholm@iname.com>
 *
 * libav - MPEG-PS multiplexer, part of ffmpeg
 * Copyright Gerard Lantau  (see http://ffmpeg.sf.net)
 *
 */

#include "fastmemcpy.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <linux/em8300.h>
#include <sys/ioctl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h>
#include <stdio.h>
#include <time.h>

#include "config.h"
#include "video_out.h"
#include "video_out_internal.h"

#include "../postproc/rgb2rgb.h"
#ifdef HAVE_MMX
#include "mmx.h"
#endif

LIBVO_EXTERN (dxr3)

#ifdef USE_LIBAVCODEC

#ifdef USE_LIBAVCODEC_SO
#include <libffmpeg/avcodec.h>
#else
#include "../libavcodec/avcodec.h"
#endif
static AVPicture picture;
static AVCodec *codec=NULL;
static AVCodecContext codec_context;
extern int avcodec_inited;
#endif

static unsigned char *picture_buf=NULL;
static unsigned char *outbuf=NULL;
static unsigned char *spubuf=NULL;
static int outbuf_size = 0;
static int v_width,v_height;
static int s_width,s_height;
static int s_pos_x,s_pos_y;
static int d_pos_x,d_pos_y;
static int osd_w,osd_h;
static int img_format = 0;
static int palette[] = { 0x000000, 0x494949, 0xb5b5b5, 0xffffff };
static int fd_control = -1;
static int fd_video = -1;
static int fd_spu = -1;
static int ioval = 0;

static vo_info_t vo_info = 
{
	"DXR3/H+ video out",
	"dxr3",
	"David Holm <dholm@iname.com>",
	""
};

static uint32_t
init(uint32_t scr_width, uint32_t scr_height, uint32_t width, uint32_t height, uint32_t fullscreen, char *title, uint32_t format)
{
    int i;
    char tmp;
    
    fd_control = open( "/dev/em8300", O_WRONLY );
    if( fd_control < 1 )
    {
	printf( "VO: [dxr3] Error opening /dev/em8300 for writing!\n" );
	return -1;
    }
    fd_video = open( "/dev/em8300_mv", O_WRONLY );
    if( fd_video < 0 )
    {
	printf( "VO: [dxr3] Error opening /dev/em8300_mv for writing!\n" );
	return -1;
    }
    else printf( "VO: [dxr3] Opened /dev/em8300_mv\n" );
    fd_spu = open( "/dev/em8300_sp", O_WRONLY );
    if( fd_spu < 0 )
    {
	printf( "VO: [dxr3] Error opening /dev/em8300_sp for writing!\n" );
	return -1;
    }

    /* Subpic code isn't working yet, don't set to ON 
       unless you are really sure what you are doing */
    ioval = EM8300_SPUMODE_OFF;
    if( ioctl( fd_control, EM8300_IOCTL_SET_SPUMODE, &ioval ) < 0 )
    {
	printf( "VO: [dxr3] Unable to set subpicture mode!\n" );
	return -1;
    }
    
    if( ioctl( fd_spu, EM8300_IOCTL_SPU_SETPALETTE, palette ) < 0 )
    {
	printf( "VO: [dxr3] Unable to set subpicture palette!\n" );
	return -1;
    }

    ioval = EM8300_PLAYMODE_PLAY;
    if( ioctl( fd_control, EM8300_IOCTL_SET_PLAYMODE, &ioval ) < 0 )
	printf( "VO: [dxr3] Unable to set playmode!\n" );
    
    close( fd_control );

    img_format = format;
    v_width = width;
    v_height = height;
    spubuf = malloc(53220); /* 53220 bytes is the standardized max size of a subpic */
    picture_buf=NULL;

    if( format == IMGFMT_YV12 )
    {
#ifdef USE_LIBAVCODEC

	int size;

	printf("VO: [dxr3] Format: YV12\n");

        if(!avcodec_inited){
	  avcodec_init();
          avcodec_register_all();
          avcodec_inited=1;
        }
    
        /* find the mpeg1 video encoder */
        codec = avcodec_find_encoder(CODEC_ID_MPEG1VIDEO);
        if (!codec) 
	{
            printf( "VO: [dxr3] mpeg1 codec not found! Read DOCS/DXR3!\n");
            return -1;
        }
            
        memset(&codec_context,0,sizeof(codec_context));
        codec_context.bit_rate=100000; // not used
        codec_context.frame_rate=25*FRAME_RATE_BASE;
        codec_context.gop_size=0;
        codec_context.flags=CODEC_FLAG_QSCALE;
        codec_context.quality=1;
	codec_context.pix_fmt = PIX_FMT_YUV420P;
        if(width<=352 && height<=288){
          codec_context.width=352;
          codec_context.height=288;
        } else
        if(width<=352 && height<=576){
          codec_context.width=352;
          codec_context.height=576;
        } else
        if(width<=480 && height<=576){
          codec_context.width=480;
          codec_context.height=576;
        } else
        if(width<=544 && height<=576){
          codec_context.width=544;
          codec_context.height=576;
        } else {
          codec_context.width=704;
          codec_context.height=576;
        }
	s_width = codec_context.width;
	s_height = codec_context.height;;

    
        osd_w=scr_width;
        d_pos_x=(codec_context.width-(int)scr_width)/2;
        if(d_pos_x<0){
          s_pos_x=-d_pos_x;d_pos_x=0;
          osd_w=codec_context.width;
        } else s_pos_x=0;
    
        osd_h=scr_height;
        d_pos_y=(codec_context.height-(int)scr_height)/2;
        if(d_pos_y<0){
          s_pos_y=-d_pos_y;d_pos_y=0;
          osd_h=codec_context.height;
        } else s_pos_y=0;
    
        printf("VO: [dxr3] position mapping: %d;%d => %d;%d\n",s_pos_x,s_pos_y,d_pos_x,d_pos_y);
    
        /* open it */
        if (avcodec_open(&codec_context, codec) < 0) 
	{
            printf( "VO: [dxr3] Could not open codec\n");
            return -1;
        }
        
        outbuf_size=10000+width*height;
        outbuf = malloc(outbuf_size);
    
        size = codec_context.width*codec_context.height;
        picture_buf = malloc((size * 3)/2); /* size for YUV 420 */
        
        picture.data[0] = picture_buf;
        picture.data[1] = picture.data[0] + size;
        picture.data[2] = picture.data[1] + size / 4;
        picture.linesize[0] = codec_context.width;
        picture.linesize[1] = codec_context.width / 2;
        picture.linesize[2] = codec_context.width / 2;

	return 0;
#endif
	return -1;    
    }
    else if(format==IMGFMT_BGR24)
    {
#ifdef USE_LIBAVCODEC
	int size = 0;
	printf("VO: [dxr3] Format: BGR24\n");

        if(!avcodec_inited)
	{
	  avcodec_init();
          avcodec_register_all();
          avcodec_inited=1;
        }
    
        /* find the mpeg1 video encoder */
        codec = avcodec_find_encoder(CODEC_ID_MPEG1VIDEO);
        if (!codec) 
	{
            printf( "VO: [dxr3] mpeg1 codec not found! Read DOCS/DXR3!\n");
            return -1;
        }
            
        outbuf_size=10000+width*height;
        outbuf = malloc(outbuf_size);
	
        memset(&codec_context,0,sizeof(codec_context));
        codec_context.bit_rate=100000;
        codec_context.frame_rate=25*FRAME_RATE_BASE;
        codec_context.gop_size=0;
        codec_context.flags=CODEC_FLAG_QSCALE;
        codec_context.quality=1;
	codec_context.pix_fmt = PIX_FMT_YUV420P;

        if(width<=352 && height<=288){
          codec_context.width=352;
          codec_context.height=288;
        } else
        if(width<=352 && height<=576){
          codec_context.width=352;
          codec_context.height=576;
        } else
        if(width<=480 && height<=576){
          codec_context.width=480;
          codec_context.height=576;
        } else
        if(width<=544 && height<=576){
          codec_context.width=544;
          codec_context.height=576;
        } else {
          codec_context.width=704;
          codec_context.height=576;
        }
/*	s_width = codec_context.width = width;
	s_height = codec_context.height = height;
*/
        osd_w=scr_width;
        d_pos_x=(codec_context.width-(int)scr_width)/2;
        if(d_pos_x<0){
          s_pos_x=-d_pos_x;d_pos_x=0;
          osd_w=codec_context.width;
        } else s_pos_x=0;
    
        osd_h=scr_height;
        d_pos_y=(codec_context.height-(int)scr_height)/2;
        if(d_pos_y<0){
          s_pos_y=-d_pos_y;d_pos_y=0;
          osd_h=codec_context.height;
        } else s_pos_y=0;
    
        printf("VO: [dxr3] position mapping: %d;%d => %d;%d\n",s_pos_x,s_pos_y,d_pos_x,d_pos_y);
    
        /* open it */
        if (avcodec_open(&codec_context, codec) < 0) 
	{
            printf( "VO: [dxr3] could not open codec\n");
            return -1;
        }

        size = 10000+codec_context.width*codec_context.height;
        picture_buf = malloc((size * 3)/2);
        
        picture.data[0] = picture_buf;
        picture.data[1] = picture.data[0] + size;
        picture.data[2] = picture.data[1] + size / 4;
	picture.linesize[0] = codec_context.width;
        picture.linesize[1] = codec_context.width / 2;
        picture.linesize[2] = codec_context.width / 2;
	return 0;
#endif
	return -1;
    }
    else if(format==IMGFMT_YUY2)
    {
#ifdef USE_LIBAVCODEC
	int size = 0;
	printf("VO: [dxr3] Format: YUY2\n");

        if(!avcodec_inited)
	{
	  avcodec_init();
          avcodec_register_all();
          avcodec_inited=1;
        }
    
        /* find the mpeg1 video encoder */
        codec = avcodec_find_encoder(CODEC_ID_MPEG1VIDEO);
        if (!codec) 
	{
            printf( "VO: [dxr3] mpeg1 codec not found! Read DOCS/DXR3!\n");
	    return -1;
        }
            
        outbuf_size=10000+width*height;
        outbuf = malloc(outbuf_size);
	
        memset(&codec_context,0,sizeof(codec_context));
        codec_context.bit_rate=100000;
        codec_context.frame_rate=25*FRAME_RATE_BASE;
        codec_context.gop_size=0;
        codec_context.flags=CODEC_FLAG_QSCALE;
        codec_context.quality=1;
	codec_context.pix_fmt = PIX_FMT_YUV420P;

        if(width<=352 && height<=288){
          codec_context.width=352;
          codec_context.height=288;
        } else
        if(width<=352 && height<=576){
          codec_context.width=352;
          codec_context.height=576;
        } else
        if(width<=480 && height<=576){
          codec_context.width=480;
          codec_context.height=576;
        } else
        if(width<=544 && height<=576){
          codec_context.width=544;
          codec_context.height=576;
        } else {
          codec_context.width=704;
          codec_context.height=576;
        }
	s_width = codec_context.width;
	s_height = codec_context.height;;
	/* FOR DEBUGGING ONLY!! */
	codec_context.width = width;
	codec_context.height = height;
	
        osd_w=scr_width;
        d_pos_x=(codec_context.width-(int)scr_width)/2;
        if(d_pos_x<0){
          s_pos_x=-d_pos_x;d_pos_x=0;
          osd_w=codec_context.width;
        } else s_pos_x=0;
    
        osd_h=scr_height;
        d_pos_y=(codec_context.height-(int)scr_height)/2;
        if(d_pos_y<0){
          s_pos_y=-d_pos_y;d_pos_y=0;
          osd_h=codec_context.height;
        } else s_pos_y=0;
    
        printf("VO: [dxr3] position mapping: %d;%d => %d;%d\n",s_pos_x,s_pos_y,d_pos_x,d_pos_y);
    
        /* open it */
        if (avcodec_open(&codec_context, codec) < 0) 
	{
            printf(stderr, "VO: [dxr3] Could not open codec\n");
            return -1;
        }

        size = 10000+codec_context.width*codec_context.height;
        picture_buf = malloc((size * 3)/2);
        
        picture.data[0] = picture_buf;
        picture.data[1] = picture.data[0] + size;
        picture.data[2] = picture.data[1] + size / 4;
	picture.linesize[0] = codec_context.width;
        picture.linesize[1] = codec_context.width / 2;
        picture.linesize[2] = codec_context.width / 2;
	return 0;
#endif
	return -1;
    }
    else if(format==IMGFMT_MPEGPES)
    {
	printf( "VO: [dxr3] Format: MPEG-PES (no conversion needed)\n" );
	return 0;
    }

    printf( "VO: [dxr3] Format: Unsupported\n" );
    return -1;
}

static const vo_info_t* get_info(void)
{
    return &vo_info;
}

static void draw_alpha(int x0, int y0, int w, int h, unsigned char* src, unsigned char *srca, int srcstride)
{
}

static void draw_osd(void)
{
//    vo_draw_text(osd_w,osd_h,draw_alpha);
}

static uint32_t draw_frame(uint8_t * src[])
{
    int pts = 0;
    if( img_format == IMGFMT_MPEGPES )
    {
        int data_left;
	vo_mpegpes_t *p=(vo_mpegpes_t *)src[0];
	unsigned char *data = p->data;

	data_left = p->size;
	pts = p->timestamp;
	if( ioctl( fd_video, EM8300_IOCTL_VIDEO_SETPTS, &pts ) < 0 )
	    printf( "VO: [dxr3] Unable to set PTS in draw_frame\n" );
	while( data_left )
	    data_left -= write( fd_video, &((unsigned char*)p->data)[p->size-data_left], data_left );

	return 0;
    }
#ifdef USE_LIBAVCODEC
    else if( img_format == IMGFMT_YV12 )
    {
	printf("VO: [dxr3] ERROR: Uninplemented\n");
    }
    else if( img_format == IMGFMT_BGR24 )
    {
	int tmp_size, out_size;
	int wrap, wrap3, x, y;
	int r, g, b, R, G, B, h = v_height, w = v_width;
	unsigned char *s, *Y, *U, *V;

        if(d_pos_x+w>picture.linesize[0]) w=picture.linesize[0]-d_pos_x;
        if(d_pos_y+h>codec_context.height) h=codec_context.height-d_pos_y;
	
	Y = picture.data[0]+d_pos_x+(d_pos_y*picture.linesize[0]);
	U = picture.data[1]+(d_pos_x/2)+((d_pos_y/2)*picture.linesize[1]);
	V = picture.data[2]+(d_pos_x/2)+((d_pos_y/2)*picture.linesize[2]);

	//BGR24->YUV420P from ffmpeg, see ffmpeg.sourceforge.net for terms of license
#define SCALEBITS	8
#define ONE_HALF	(1 << (SCALEBITS - 1))
#define FIX(x)		((int) ((x) * (1L<<SCALEBITS) + 0.5))
	wrap = s_width;
	wrap3 = w * 3;
        s = src[0]+s_pos_x+(s_pos_y*wrap3);
	for( y = 0; y < h; y+=2 )
	{
	    for( x = 0; x < w; x+=2 )
	    {
		b = s[0];
		g = s[1];
		r = s[2];
		R = r;
		G = g;
		B = b;
		Y[0] = (FIX(0.29900) * r + FIX(0.58700) * g + FIX(0.11400) * b + ONE_HALF) >> SCALEBITS;
		b = s[3];
		g = s[4];
		r = s[5];
		R += r;
		G += g;
		B += b;
		Y[1] = (FIX(0.29900) * r + FIX(0.58700) * g + FIX(0.11400) * b + ONE_HALF) >> SCALEBITS;
		s += wrap3;
		Y += wrap;

		b = s[0];
		g = s[1];
		r = s[2];
		R += r;
		G += g;
		B += b;
		Y[0] = (FIX(0.29900) * r + FIX(0.58700) * g + FIX(0.11400) * b + ONE_HALF) >> SCALEBITS;
		b = s[3];
		g = s[4];
		r = s[5];
		R += r;
		G += g;
		B += b;
		Y[1] = (FIX(0.29900) * r + FIX(0.58700) * g + FIX(0.11400) * b + ONE_HALF) >> SCALEBITS;
		U[0] = ((- FIX(0.16874) * R - FIX(0.33126) * G - FIX(0.50000) * B + 4 * ONE_HALF - 1) >> (SCALEBITS + 2)) + 128;
		V[0] = ((FIX(0.50000) * R - FIX(0.41869) * G - FIX(0.08131) * B + 4 * ONE_HALF - 1) >> (SCALEBITS + 2)) + 128;
		
		U++;
		V++;
		s -= (wrap3-6);
		Y -= (wrap-(3/2));
	    }
	    s += wrap3;
	    Y += wrap;
	}
#undef SCALEBITS
#undef ONE_HALF
#undef FIX(x)
	//End of ffmpeg code, see ffmpeg.sourceforge.net for terms of license
	pts = vo_pts;
	if( ioctl( fd_video, EM8300_IOCTL_VIDEO_SETPTS, &pts ) < 0 )
	    printf( "VO: [dxr3] Unable to set PTS in draw_frame\n" );
        tmp_size = out_size = avcodec_encode_video(&codec_context, outbuf, outbuf_size, &picture);
	while( out_size )
		out_size -= write( fd_video, &outbuf[tmp_size-out_size], out_size );
	return 0;
    }
    else if( img_format == IMGFMT_YUY2 )
    {
	int tmp_size, out_size;	
	int x, y, w = v_width, h = v_height;
	
	for( y = 0; y < h; y++ )
	{
	    for( x = 0; x < w; x++ )
	    {
	    }
	}
	pts = vo_pts;
	if( ioctl( fd_video, EM8300_IOCTL_VIDEO_SETPTS, &pts ) < 0 )
	    printf( "VO: [dxr3] Unable to set PTS in draw_frame\n" );
        tmp_size = out_size = avcodec_encode_video(&codec_context, outbuf, outbuf_size, &picture);
        while( out_size )
		out_size -= write( fd_video, &outbuf[tmp_size-out_size], out_size );

	return 0;
    }
#endif
    
    printf( "VO: [dxr3] Error in draw_frame(...)\n" );
    return -1;
}

static void flip_page (void)
{
}

static uint32_t draw_slice( uint8_t *srcimg[], int stride[], int w, int h, int x0, int y0 )
{
    int y, pts;
    unsigned char* s;
    unsigned char* d;
    int data_left;
    vo_mpegpes_t *p = (vo_mpegpes_t *)srcimg[0];

    if( img_format == IMGFMT_YV12 )
    {    
#ifdef USE_LIBAVCODEC
        int out_size, tmp_size;
	x0+=d_pos_x;
        y0+=d_pos_y;
        if(x0+w>picture.linesize[0]) w=picture.linesize[0]-x0; // !!
        if(y0+h>codec_context.height) h=codec_context.height-y0;

	// Y
        s=srcimg[0]+s_pos_x+s_pos_y*stride[0];
        d=picture.data[0]+x0+y0*picture.linesize[0];
	for( y = 0; y < h; y++)
	{
		memcpy(d,s,w);
		s+=stride[0];
		d+=picture.linesize[0];
        }
    
	w/=2;h/=2;x0/=2;y0/=2;

        // U
        s=srcimg[1]+(s_pos_x/2)+(s_pos_y/2)*stride[1];
        d=picture.data[1]+x0+y0*picture.linesize[1];
        for( y = 0; y < h; y++)
	{
	    memcpy(d,s,w);
    	    s+=stride[1];
    	    d+=picture.linesize[1];
        }
    
        // V
        s=srcimg[2]+(s_pos_x/2)+(s_pos_y/2)*stride[2];
        d=picture.data[2]+x0+y0*picture.linesize[2];
        for(y=0;y<h;y++)
	{
	    memcpy(d,s,w);
	    s+=stride[2];
	    d+=picture.linesize[2];
	}
	pts = vo_pts;
	
	if( ioctl( fd_video, EM8300_IOCTL_VIDEO_SETPTS, &pts ) < 0 )
	    printf( "VO: [dxr3] Unable to set PTS in draw_slice\n" );
        tmp_size = out_size = avcodec_encode_video(&codec_context, outbuf, outbuf_size, &picture);
        while( out_size )
		out_size -= write( fd_video, &outbuf[tmp_size-out_size], out_size );

	return 0;
#endif
	printf( "VO: [dxr3] You need to install ffmpeg.so or libavcodec, read DOCS/DXR3\n" );
	return -1;
    }

    return -1;
}


static uint32_t
query_format(uint32_t format)
{
    if(format==IMGFMT_MPEGPES) return 1;
#ifdef USE_LIBAVCODEC
    if(format==IMGFMT_YV12) return 1;
//    if(format==IMGFMT_YUY2) return 0x1|0x4;
    if(format==IMGFMT_BGR24) return 1;
#else
    if(format==IMGFMT_YV12) {printf("VO: [dxr3] You need to compile with libavcodec or ffmpeg.so to play this file!\n" ); return 0;}
    if(format==IMGFMT_YUY2) {printf("VO: [dxr3] You need to compile with libavcodec or ffmpeg.so to play this file!\n" ); return 0;}
    if(format==IMGFMT_BGR24) {printf("VO: [dxr3] You need to compile with libavcodec or ffmpeg.so to play this file!\n" ); return 0;}
#endif    
    return 0;
}

static void
uninit(void)
{
    printf( "VO: [dxr3] Uninitializing\n" );
    free(outbuf);
    free(picture_buf);
    free(spubuf);
    close(fd_video);
    close(fd_spu);
}


static void check_events(void)
{
}