view libmpcodecs/vd_libmpeg2.c @ 8388:45eb2d4d633c

The detection of a NetWM class window manager hints is tested before the test of a gnome class windomanager hints, since the gnome hints are outdated and replaced by the newer NetWM specification. Newer versions of Gnome support this standard, and therefore the test should be placed before the Gnome test. Windowmaker does not support NetWM and is checked after the NetWM test. In fact the new code should be placed also before the test for IceWM. Regarding other WMs such as KDE, IceWM the change is not tested. patch by Svante Signell <svante.signell@telia.com>
author arpi
date Sat, 07 Dec 2002 01:25:30 +0000
parents b465ba5897a3
children 16a7d1f4da38
line wrap: on
line source

#include <stdio.h>
#include <stdlib.h>

#include "config.h"
#ifdef USE_LIBMPEG2

#include "mp_msg.h"

#include "vd_internal.h"

static vd_info_t info = 
{
	"MPEG 1/2 Video decoder v2.0",
	"libmpeg2",
	"A'rpi",
	"Aaron & Walken",
	"native"
};

LIBVD_EXTERN(libmpeg2)

#define USE_SIGJMP_TRICK

#ifdef USE_SIGJMP_TRICK
#include <signal.h>
#include <setjmp.h>
#endif

//#include "libmpdemux/parse_es.h"

#include "libvo/video_out.h"	// FIXME!!!

#include "libmpeg2/mpeg2.h"
#include "libmpeg2/mpeg2_internal.h"
#include "libmpeg2/mm_accel.h"

#include "../cpudetect.h"

mpeg2_config_t config;	// FIXME!!!
static picture_t *picture=NULL;	// exported from libmpeg2/decode.c

static int table_init_state=0;

// to set/get/query special features/parameters
static int control(sh_video_t *sh,int cmd,void* arg,...){
    return CONTROL_UNKNOWN;
}

static vo_frame_t frames[3];

// init driver
static int init(sh_video_t *sh){

    config.flags = 0;
if(gCpuCaps.hasMMX)
    config.flags |= MM_ACCEL_X86_MMX;
if(gCpuCaps.hasMMX2)
    config.flags |= MM_ACCEL_X86_MMXEXT;
if(gCpuCaps.has3DNow)
    config.flags |= MM_ACCEL_X86_3DNOW;
#ifdef HAVE_MLIB
    config.flags |= MM_ACCEL_MLIB;
#endif

    picture=malloc(sizeof(picture_t)); // !!! NEW HACK :) !!!
    memset(picture,0,sizeof(picture_t));
    header_state_init (picture);

    if(!table_init_state){
	idct_init ();
	motion_comp_init ();
	table_init_state=1;
    }

    picture->pp_options=divx_quality;
    
    memset(frames,0,3*sizeof(vo_frame_t));
    
    picture->forward_reference_frame=&frames[0];
    picture->backward_reference_frame=&frames[1];
    picture->temp_frame=&frames[2];
    picture->current_frame=NULL;
    
    // send seq header to the decoder:  *** HACK ***
//    mpeg2_decode_data(NULL,videobuffer,videobuffer+videobuf_len,0);
//    mpeg2_allocate_image_buffers (picture);
    return mpcodecs_config_vo(sh,sh->disp_w,sh->disp_h,IMGFMT_YV12);
}

// uninit driver
static void uninit(sh_video_t *sh){
//    mpeg2_free_image_buffers (picture);
}

static void draw_slice (vo_frame_t * frame, uint8_t ** src){
    int stride[3];
    int y=picture->slice<<4;

    stride[0]=picture->coded_picture_width;
    stride[1]=stride[2]=stride[0]/2;

    mpcodecs_draw_slice(frame->vo, src,
		stride, picture->display_picture_width,
		(y+16<=picture->display_picture_height) ? 16 :
		    picture->display_picture_height-y,
		0, y);
    
    ++picture->slice;
}

static int in_slice_flag=0; // FIXME! move to picture struct
static int drop_frame=0;    // FIXME! move to picture struct

static mp_image_t* parse_chunk (sh_video_t* sh, int code, uint8_t * buffer, int framedrop){
    mp_image_t* mpi=NULL;

//    stats_header (code, buffer);

    if (in_slice_flag && ((!code) || (code >= 0xb0))) {
	// ok, we've completed decoding a frame/field!
	in_slice_flag = 0;
	mpi=picture->display_frame->mpi;
	if(picture->picture_structure!=FRAME_PICTURE && !picture->second_field)
	    mpi=NULL; // we don't draw first fields!
    }

    switch (code) {
    case 0x00:	/* picture_start_code */
	if (header_process_picture_header (picture, buffer)) {
	    printf ("bad picture header\n");
	}
	drop_frame = framedrop && (picture->picture_coding_type == B_TYPE);
	drop_frame |= framedrop>=2; // hard drop
	break;

    case 0xb3:	/* sequence_header_code */
	if (header_process_sequence_header (picture, buffer)) {
	    printf ("bad sequence header\n");
	}
	break;

    case 0xb5:	/* extension_start_code */
	if (header_process_extension (picture, buffer)) {
	    printf ("bad extension\n");
	}
	break;

    default:
	if (code >= 0xb0)  break;

	if (!in_slice_flag) {
	    in_slice_flag = 1;

	    // set current_frame pointer:
	    if (!picture->second_field){
		mp_image_t* mpi;
		int flags;
		if (picture->picture_coding_type == B_TYPE){
		    flags=(!framedrop && vd_use_slices && 
			picture->picture_structure==FRAME_PICTURE) ?
			    MP_IMGFLAG_DRAW_CALLBACK:0;
		    picture->display_frame=
		    picture->current_frame = picture->temp_frame;
		} else {
		    flags=MP_IMGFLAG_PRESERVE|MP_IMGFLAG_READABLE;
		    picture->current_frame = picture->forward_reference_frame;
		    picture->display_frame=
		    picture->forward_reference_frame = picture->backward_reference_frame;
		    picture->backward_reference_frame = picture->current_frame;
		}
		mpi=mpcodecs_get_image(sh,MP_IMGTYPE_IPB, flags,
			picture->coded_picture_width,
			picture->coded_picture_height);
		// ok, lets see what did we get:
		if(mpi->flags&MP_IMGFLAG_DRAW_CALLBACK &&
		 !(mpi->flags&MP_IMGFLAG_DIRECT)){
		    // nice, filter/vo likes draw_callback :)
		    picture->current_frame->copy=draw_slice;
		} else
		    picture->current_frame->copy=NULL;
		// let's, setup pointers!
		picture->current_frame->base[0]=mpi->planes[0];
		picture->current_frame->base[1]=mpi->planes[1];
		picture->current_frame->base[2]=mpi->planes[2];
		picture->current_frame->mpi=mpi;	// tricky!
#if 1
		if(!picture->forward_reference_frame->base[0]){
		    // workaround for sig11
		    picture->forward_reference_frame->base[0]=mpi->planes[0];
		    picture->forward_reference_frame->base[1]=mpi->planes[1];
		    picture->forward_reference_frame->base[2]=mpi->planes[2];
		}
		if(!picture->backward_reference_frame->base[0]){
		    // workaround for sig11
		    picture->backward_reference_frame->base[0]=mpi->planes[0];
		    picture->backward_reference_frame->base[1]=mpi->planes[1];
		    picture->backward_reference_frame->base[2]=mpi->planes[2];
		}
#endif
#ifdef MPEG12_POSTPROC
		mpi->qscale=&picture->current_frame->quant_store[1][1];
		mpi->qstride=(MPEG2_MBC+1);
#endif
		mp_msg(MSGT_DECVIDEO,MSGL_DBG2,"mpeg2: [%c] %p  %s  \n",
		    (picture->picture_coding_type == B_TYPE) ? 'B':'P',
		    mpi, (mpi->flags&MP_IMGFLAG_DIRECT)?"DR!":"");
	    }

	    picture->current_frame->vo=sh;
	    picture->slice=0;

	}

	if (!drop_frame) {
	    slice_process (picture, code, buffer);
#ifdef ARCH_X86
	    if (config.flags & MM_ACCEL_X86_MMX) __asm__ __volatile__ ("emms");
#endif
	}

    }
    return mpi;
}

#ifdef USE_SIGJMP_TRICK

static jmp_buf mpeg2_jmp_buf;

static void mpeg2_sighandler(int sig){
    longjmp(mpeg2_jmp_buf,1);
}
#endif

// decode a frame
static mp_image_t* decode(sh_video_t *sh,void* data,int len,int flags){
    static uint32_t code;
    static uint8_t* pos;
    static uint8_t* current;
    uint8_t* end=data+len;
    static mp_image_t* mpi;
    mp_image_t* ret=NULL;
    int framedrop=flags&3;
    void* old_sigh;

    // Note: static is REQUIRED because of longjmp() may destroy stack!
    pos=NULL;
    current=data;
    mpi=NULL;

#ifdef USE_SIGJMP_TRICK
    old_sigh=signal(SIGSEGV,mpeg2_sighandler);
#endif

while(current<end){
  // FIND NEXT HEAD:
  static unsigned int head;
  static uint8_t c;
  head=-1;
  //--------------------
  while(current<end){
      c=current[0];
      ++current;
      head<<=8;
      if(head==0x100) break; // synced
      head|=c;
  }
  //--------------------
  if(pos){
#ifdef USE_SIGJMP_TRICK
    if(setjmp(mpeg2_jmp_buf)){
#ifdef ARCH_X86
	if (config.flags & MM_ACCEL_X86_MMX) __asm__ __volatile__ ("emms");
#endif
	printf("@@@ libmpeg2 returned from sig11... (bad file?) @@@\n");
    } else
#endif
    {
	ret=parse_chunk(sh, code&0xFF, pos, framedrop);
	if(ret) mpi=ret;
    }
  }
  //--------------------
  pos=current;code=head|c;
}

#ifdef USE_SIGJMP_TRICK
    signal(SIGSEGV,old_sigh); // restore sighandler
#endif

//    if(code==0x1FF){
	ret=parse_chunk(sh, 0xFF, NULL, framedrop); // send 'end of frame'
	if(ret) mpi=ret;
//    }

    if(mpi){
        static int last_non_b_type= 0;

	if(picture->picture_coding_type == B_TYPE)
	    mpi->pict_type= B_TYPE;
	else{
	    mpi->pict_type= last_non_b_type;
	    last_non_b_type= picture->picture_coding_type;
	}
    }

    return mpi;
}
#endif