diff --git a/libmpcodecs/vd_libmpeg2.c b/libmpcodecs/vd_libmpeg2.c index 55e1cdee9f..51554443bb 100644 --- a/libmpcodecs/vd_libmpeg2.c +++ b/libmpcodecs/vd_libmpeg2.c @@ -8,7 +8,7 @@ static vd_info_t info = { - "MPEG 1/2 Video decoder", + "MPEG 1/2 Video decoder v2.0", "libmpeg2", VFM_MPEG, "A'rpi", @@ -18,55 +18,262 @@ static vd_info_t info = LIBVD_EXTERN(libmpeg2) -#include "libmpdemux/parse_es.h" +#define USE_SIGJMP_TRICK + +#ifdef USE_SIGJMP_TRICK +#include +#include +#endif + +//#include "libmpdemux/parse_es.h" + +#include "libvo/video_out.h" // FIXME!!! -#include "libvo/video_out.h" #include "libmpeg2/mpeg2.h" #include "libmpeg2/mpeg2_internal.h" +#include "libmpeg2/mm_accel.h" -extern picture_t *picture; // exported from libmpeg2/decode.c +#include "../cpudetect.h" + +mpeg2_config_t config; // FIXME!!! +static picture_t *picture=NULL; // exported from libmpeg2/decode.c + +static int table_init_state=0; + +#ifdef MPEG12_POSTPROC +#include "../postproc/postprocess.h" +int quant_store[MPEG2_MBR+1][MPEG2_MBC+1]; // [Review] +#endif // 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){ - mpeg2_init(); + + 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; + + 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); +// 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); +// mpeg2_free_image_buffers (picture); } -// decode a frame -static mp_image_t* decode(sh_video_t *sh,void* data,int len,int flags){ - mp_image_t* mpi; - if(sh->codec->outfmt[sh->outfmtidx]==IMGFMT_MPEGPES){ - static vo_mpegpes_t packet; - mpi=mpcodecs_get_image(sh, MP_IMGTYPE_EXPORT, 0, - sh->disp_w, sh->disp_h); - // hardware decoding: -// mpeg2_decode_data(video_out, start, start+in_size,3); // parse headers - packet.data=data; - packet.size=len-4; - packet.timestamp=sh->timer*90000.0; - packet.id=0x1E0; //+sh_video->ds->id; - mpi->planes[0]=(uint8_t*)(&packet); - } else { - mpi=mpcodecs_get_image(sh, MP_IMGTYPE_EXPORT, MP_IMGFLAG_DRAW_CALLBACK, - sh->disp_w, sh->disp_h); - if( - mpeg2_decode_data(sh->video_out, data, data+len,flags&3)==0 // decode - )return NULL;//hack for interlaced mpeg2 +static void draw_slice (vo_frame_t * frame, uint8_t ** src){ + vo_functions_t * output = frame->vo; + int stride[3]; + int y=picture->slice<<4; + + stride[0]=picture->coded_picture_width; + stride[1]=stride[2]=stride[0]/2; + + output->draw_slice (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=0; //MP_IMGFLAG_DRAW_CALLBACK; // FIXME! + 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! + 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->video_out; + 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