changeset 13995:cbadd7b190b2

libmpeg2 4:2:2 decoding
author henry
date Sat, 20 Nov 2004 14:37:38 +0000
parents a3a16a50b314
children be8f4abbe960
files etc/codecs.conf libmpcodecs/vd_libmpeg2.c libmpeg2/Makefile libmpeg2/uyvy.c
diffstat 4 files changed, 194 insertions(+), 31 deletions(-) [+]
line wrap: on
line diff
--- a/etc/codecs.conf	Sat Nov 20 14:33:39 2004 +0000
+++ b/etc/codecs.conf	Sat Nov 20 14:37:38 2004 +0000
@@ -30,6 +30,7 @@
   driver libmpeg2
 ;  dll "libmpeg2"
   out YV12,I420,IYUV
+  out UYVY
 
 videocodec ffmpeg1
   info "FFmpeg MPEG 1"
--- a/libmpcodecs/vd_libmpeg2.c	Sat Nov 20 14:33:39 2004 +0000
+++ b/libmpcodecs/vd_libmpeg2.c	Sat Nov 20 14:37:38 2004 +0000
@@ -26,19 +26,31 @@
 #include "libmpeg2/mpeg2.h"
 #include "libmpeg2/attributes.h"
 #include "libmpeg2/mpeg2_internal.h"
-//#include "libmpeg2/convert.h"
 
 #include "../cpudetect.h"
 
+mpeg2_convert_t mpeg2convert_uyvy;
+
 // to set/get/query special features/parameters
 static int control(sh_video_t *sh,int cmd,void* arg,...){
+    mpeg2dec_t * mpeg2dec = sh->context;
+
+    switch(cmd) {
+    case VDCTRL_QUERY_FORMAT:
+	if ( (*((int*)arg)) == IMGFMT_YV12 && mpeg2dec->convert == NULL)
+	    return CONTROL_TRUE;
+	if ( (*((int*)arg)) == IMGFMT_UYVY && mpeg2dec->convert == mpeg2convert_uyvy)
+	    return CONTROL_TRUE;
+	return CONTROL_FALSE;
+    }
+    
     return CONTROL_UNKNOWN;
 }
 
 // init driver
 static int init(sh_video_t *sh){
     mpeg2dec_t * mpeg2dec;
-    const mpeg2_info_t * info;
+//    const mpeg2_info_t * info;
     int accel;
 
     accel = 0;
@@ -67,14 +79,16 @@
     mpeg2dec->pending_length = 0;
 
     return 1;
-    //return mpcodecs_config_vo(sh,sh->disp_w,sh->disp_h,IMGFMT_YV12);
 }
 
 // uninit driver
 static void uninit(sh_video_t *sh){
     mpeg2dec_t * mpeg2dec = sh->context;
     if (mpeg2dec->pending_buffer) free(mpeg2dec->pending_buffer);
-    mpeg2dec->decoder.convert_id=NULL;
+    if (mpeg2dec->convert == NULL) {
+	mpeg2dec->decoder.convert=NULL;
+	mpeg2dec->decoder.convert_id=NULL;
+    }
     mpeg2_close (mpeg2dec);
 }
 
@@ -102,10 +116,11 @@
     const mpeg2_info_t * info = mpeg2_info (mpeg2dec);
     int drop_frame, framedrop=flags&3;
 
-    //MPlayer registers its own draw_slice callback, prevent libmpeg2 from freeing the context
-    mpeg2dec->decoder.convert=NULL;
-    mpeg2dec->decoder.convert_id=NULL;
-   
+    // MPlayer registers its own draw_slice callback, prevent libmpeg2 from freeing the context
+    if (mpeg2dec->convert == NULL) {
+	mpeg2dec->decoder.convert=NULL;
+	mpeg2dec->decoder.convert_id=NULL;
+    }
     
     if(len<=0) return NULL; // skipped null frame
     
@@ -124,6 +139,9 @@
     
     while(1){
 	int state=mpeg2_parse (mpeg2dec);
+	int type, use_callback;
+	mp_image_t* mpi_new;
+	
 	switch(state){
 	case STATE_BUFFER:
 	    if (mpeg2dec->pending_length) {
@@ -137,13 +155,21 @@
 	    break;
 	case STATE_SEQUENCE:
 	    // video parameters inited/changed, (re)init libvo:
-	    if(!mpcodecs_config_vo(sh,
-		info->sequence->width,
-		info->sequence->height, IMGFMT_YV12)) return 0;
+	    if (info->sequence->width >> 1 == info->sequence->chroma_width &&
+		info->sequence->height >> 1 == info->sequence->chroma_height) {
+		if(!mpcodecs_config_vo(sh,
+				       info->sequence->width,
+				       info->sequence->height, IMGFMT_YV12)) return 0;
+	    } else if (info->sequence->width >> 1 == info->sequence->chroma_width &&
+		info->sequence->height == info->sequence->chroma_height) {
+		if (mpeg2_convert(mpeg2dec, mpeg2convert_uyvy, NULL)) return 0;
+		if(!mpcodecs_config_vo(sh,
+				       info->sequence->width,
+				       info->sequence->height, IMGFMT_UYVY)) return 0;
+	    } else return 0;
 	    break;
-	case STATE_PICTURE: {
-	    int type=info->current_picture->flags&PIC_MASK_CODING_TYPE;
-	    mp_image_t* mpi_new;
+	case STATE_PICTURE:
+	    type=info->current_picture->flags&PIC_MASK_CODING_TYPE;
 	    
 	    drop_frame = framedrop && (mpeg2dec->decoder.coding_type == B_TYPE);
             drop_frame |= framedrop>=2; // hard drop
@@ -154,15 +180,20 @@
 	    }
             mpeg2_skip(mpeg2dec, 0); //mpeg2skip skips frames until set again to 0
 
+	    if (mpeg2dec->convert == NULL) {
+		use_callback = (!framedrop && vd_use_slices &&
+				(info->current_picture->flags&PIC_FLAG_PROGRESSIVE_FRAME)) ?
+		    MP_IMGFLAG_DRAW_CALLBACK:0;
+	    } else {
+		use_callback = 0;
+	    }
+
 	    // get_buffer "callback":
-	     mpi_new=mpcodecs_get_image(sh,MP_IMGTYPE_IPB,
-				    (type==PIC_FLAG_CODING_TYPE_B)
-		? ((!framedrop && vd_use_slices &&
-		    (info->current_picture->flags&PIC_FLAG_PROGRESSIVE_FRAME)) ?
-			    MP_IMGFLAG_DRAW_CALLBACK:0)
-                : (MP_IMGFLAG_PRESERVE|MP_IMGFLAG_READABLE),
-		(info->sequence->picture_width+15)&(~15),
-		(info->sequence->picture_height+15)&(~15) );
+	    mpi_new=mpcodecs_get_image(sh,MP_IMGTYPE_IPB,
+				       (type==PIC_FLAG_CODING_TYPE_B) ? use_callback : (MP_IMGFLAG_PRESERVE|MP_IMGFLAG_READABLE),
+				       (info->sequence->picture_width+15)&(~15),
+				       (info->sequence->picture_height+15)&(~15) );
+
 	    if(!mpi_new) return 0; // VO ERROR!!!!!!!!
 	    mpeg2_set_buf(mpeg2dec, mpi_new->planes, mpi_new);
 	    if (info->current_picture->flags&PIC_FLAG_TOP_FIELD_FIRST)
@@ -184,15 +215,19 @@
 	    mpi_new->qscale_type= 1;
 #endif
 
-	    if(mpi_new->flags&MP_IMGFLAG_DRAW_CALLBACK &&
-		!(mpi_new->flags&MP_IMGFLAG_DIRECT)){
-		   // nice, filter/vo likes draw_callback :)
+	    if (mpeg2dec->convert == NULL) {
+		if (mpi_new->flags&MP_IMGFLAG_DRAW_CALLBACK
+		    && !(mpi_new->flags&MP_IMGFLAG_DIRECT)) {
+		    // nice, filter/vo likes draw_callback :)
 		    mpeg2dec->decoder.convert=draw_slice;
 		    mpeg2dec->decoder.convert_id=sh;
-		} else
+		} else {
 		    mpeg2dec->decoder.convert=NULL;
+		    mpeg2dec->decoder.convert_id=NULL;
+		}
+	    }
+	    
 	    break;
-	}
 	case STATE_SLICE:
 	case STATE_END:
 	case STATE_INVALID_END:
@@ -200,9 +235,9 @@
 	    if(info->display_fbuf) {
 		mp_image_t* mpi = info->display_fbuf->id;
 		if (mpeg2dec->pending_length == 0) {
-		mpeg2dec->pending_length = mpeg2dec->buf_end - mpeg2dec->buf_start;
-		mpeg2dec->pending_buffer = realloc(mpeg2dec->pending_buffer, mpeg2dec->pending_length);
-		memcpy(mpeg2dec->pending_buffer, mpeg2dec->buf_start, mpeg2dec->pending_length);
+		    mpeg2dec->pending_length = mpeg2dec->buf_end - mpeg2dec->buf_start;
+		    mpeg2dec->pending_buffer = realloc(mpeg2dec->pending_buffer, mpeg2dec->pending_length);
+		    memcpy(mpeg2dec->pending_buffer, mpeg2dec->buf_start, mpeg2dec->pending_length);
 		} else {
 		    // still some data in the pending buffer, shouldn't happen
 		    mpeg2dec->pending_length = mpeg2dec->buf_end - mpeg2dec->buf_start;
--- a/libmpeg2/Makefile	Sat Nov 20 14:33:39 2004 +0000
+++ b/libmpeg2/Makefile	Sat Nov 20 14:37:38 2004 +0000
@@ -3,7 +3,7 @@
 
 include ../config.mak
 
-SRCS	= alloc.c cpu_accel.c cpu_state.c decode.c header.c idct.c motion_comp.c slice.c
+SRCS	= alloc.c cpu_accel.c cpu_state.c decode.c header.c idct.c motion_comp.c slice.c uyvy.c
 
 OBJS	= $(SRCS:.c=.o)
 INCLUDE = -I. -I../libvo -I.. $(EXTRA_INC)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libmpeg2/uyvy.c	Sat Nov 20 14:37:38 2004 +0000
@@ -0,0 +1,127 @@
+/*
+ * uyvy.c
+ * Copyright (C) 2000-2003 Michel Lespinasse <walken@zoy.org>
+ * Copyright (C) 2003      Regis Duchesne <hpreg@zoy.org>
+ * Copyright (C) 1999-2000 Aaron Holtzman <aholtzma@ess.engr.uvic.ca>
+ *
+ * This file is part of mpeg2dec, a free MPEG-2 video stream decoder.
+ * See http://libmpeg2.sourceforge.net/ for updates.
+ *
+ * mpeg2dec is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * mpeg2dec 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include "config.h"
+
+#include <inttypes.h>
+
+#include "mpeg2.h"
+//#include "mpeg2convert.h"
+
+typedef struct {
+    int width;
+    int stride;
+    int chroma420;
+    uint8_t * out;
+} convert_uyvy_t;
+
+static void uyvy_start (void * _id, const mpeg2_fbuf_t * fbuf,
+			const mpeg2_picture_t * picture,
+			const mpeg2_gop_t * gop)
+{
+    convert_uyvy_t * instance = (convert_uyvy_t *) _id;
+
+    instance->out = fbuf->buf[0];
+    instance->stride = instance->width;
+    if (picture->nb_fields == 1) {
+	if (! (picture->flags & PIC_FLAG_TOP_FIELD_FIRST))
+	    instance->out += 2 * instance->stride;
+	instance->stride <<= 1;
+    }
+}
+
+#ifdef WORDS_BIGENDIAN
+#define PACK(a,b,c,d) (((a) << 24) | ((b) << 16) | ((c) << 8) | (d))
+#else
+#define PACK(a,b,c,d) (((d) << 24) | ((c) << 16) | ((b) << 8) | (a))
+#endif
+
+static void uyvy_line (uint8_t * py, uint8_t * pu, uint8_t * pv, void * _dst,
+		       int width)
+{
+    uint32_t * dst = (uint32_t *) _dst;
+
+    width >>= 4;
+    do {
+	dst[0] = PACK (pu[0],  py[0], pv[0],  py[1]);
+	dst[1] = PACK (pu[1],  py[2], pv[1],  py[3]);
+	dst[2] = PACK (pu[2],  py[4], pv[2],  py[5]);
+	dst[3] = PACK (pu[3],  py[6], pv[3],  py[7]);
+	dst[4] = PACK (pu[4],  py[8], pv[4],  py[9]);
+	dst[5] = PACK (pu[5], py[10], pv[5], py[11]);
+	dst[6] = PACK (pu[6], py[12], pv[6], py[13]);
+	dst[7] = PACK (pu[7], py[14], pv[7], py[15]);
+	py += 16;
+	pu += 8;
+	pv += 8;
+	dst += 8;
+    } while (--width);
+}
+
+static void uyvy_copy (void * id, uint8_t * const * src, unsigned int v_offset)
+{
+    const convert_uyvy_t * instance = (convert_uyvy_t *) id;
+    uint8_t * py;
+    uint8_t * pu;
+    uint8_t * pv;
+    uint8_t * dst;
+    int height;
+
+    dst = instance->out + 2 * instance->stride * v_offset;
+    py = src[0]; pu = src[1]; pv = src[2];
+
+    height = 16;
+    do {
+	uyvy_line (py, pu, pv, dst, instance->width);
+	dst += 2 * instance->stride;
+	py += instance->stride;
+	if (! (--height & instance->chroma420)) {
+	    pu += instance->stride >> 1;
+	    pv += instance->stride >> 1;
+	}
+    } while (height);
+}
+
+int mpeg2convert_uyvy (int stage, void * _id, const mpeg2_sequence_t * seq,
+		       int stride, uint32_t accel, void * arg,
+		       mpeg2_convert_init_t * result)
+{
+    convert_uyvy_t * instance = (convert_uyvy_t *) _id;
+
+    if (seq->chroma_width == seq->width)
+	return 1;
+
+    if (instance) {
+	instance->width = seq->width;
+	instance->chroma420 = (seq->chroma_height < seq->height);
+	result->buf_size[0] = seq->width * seq->height * 2;
+	result->buf_size[1] = result->buf_size[2] = 0;
+	result->start = uyvy_start;
+	result->copy = uyvy_copy;
+    } else {
+	result->id_size = sizeof (convert_uyvy_t);
+    }
+
+    return 0;
+}