libmpeg2 4:2:2 decoding
authorhenry <henry@b3059339-0415-0410-9bf9-f77b7e298cf2>
Sat, 20 Nov 2004 14:37:38 +0000 (14:37 +0000)
committerhenry <henry@b3059339-0415-0410-9bf9-f77b7e298cf2>
Sat, 20 Nov 2004 14:37:38 +0000 (14:37 +0000)
git-svn-id: svn://git.mplayerhq.hu/mplayer/trunk@13996 b3059339-0415-0410-9bf9-f77b7e298cf2

etc/codecs.conf
libmpcodecs/vd_libmpeg2.c
libmpeg2/Makefile
libmpeg2/uyvy.c [new file with mode: 0644]

index 746f343..907c2ff 100644 (file)
@@ -30,6 +30,7 @@ videocodec mpeg12
   driver libmpeg2
 ;  dll "libmpeg2"
   out YV12,I420,IYUV
+  out UYVY
 
 videocodec ffmpeg1
   info "FFmpeg MPEG 1"
index 8ad397d..c191a53 100644 (file)
@@ -26,19 +26,31 @@ LIBVD_EXTERN(libmpeg2)
 #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 @@ static int init(sh_video_t *sh){
     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 @@ static mp_image_t* decode(sh_video_t *sh,void* data,int len,int flags){
     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 @@ static mp_image_t* decode(sh_video_t *sh,void* data,int len,int flags){
     
     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 @@ static mp_image_t* decode(sh_video_t *sh,void* data,int len,int flags){
            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 @@ static mp_image_t* decode(sh_video_t *sh,void* data,int len,int flags){
            }
             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 @@ static mp_image_t* decode(sh_video_t *sh,void* data,int len,int flags){
            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 @@ static mp_image_t* decode(sh_video_t *sh,void* data,int len,int flags){
            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;
index 137957b..791493a 100644 (file)
@@ -3,7 +3,7 @@ LIBNAME = libmpeg2.a
 
 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)
diff --git a/libmpeg2/uyvy.c b/libmpeg2/uyvy.c
new file mode 100644 (file)
index 0000000..7b1759e
--- /dev/null
@@ -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;
+}