[MPlayer-dev-eng] proposed new feature: ppm decoder

Hernan Badino hernan.badino at gmail.com
Fri Aug 24 16:43:03 CEST 2012


Hi All,

I'm sending you a patch file for a new ppm decoder. The proposed
changes add the capability of to using ppm and pgm as input files
(e.g., using mf://*.ppm).

The new changes don't add any new dependency, since ppm and pgm are
very easy to decode. I've wrote the code in plain C.

The changes are a new file libmpcodecs/vd_mppm.c, and just a few line
insertions in libmpcodecs/vd.c libmpdemux/demux_mf.c  etc/codecs.conf
and Makefile.

I've tested the code on correct and corrupted ppm, pgm, and it works
as expected.

I've also added a long comment in the  libmpcodecs/vd_mppm.c file for
what I think it is a bug. This comment should probably be removed
before submitting the file.

Please, let me know if you have any questions.

Hernan
-------------- next part --------------
Index: libmpcodecs/vd_mppm.c
===================================================================
--- libmpcodecs/vd_mppm.c	(revision 0)
+++ libmpcodecs/vd_mppm.c	(revision 0)
@@ -0,0 +1,266 @@
+/*
+ * Simple P5 and P6 ppm decoder.
+ *
+ * Author: Hernan Badino (hernan.badino at gmail.com)
+ *
+ * This file is part of MPlayer.
+ *
+ * MPlayer 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.
+ *
+ * MPlayer 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 MPlayer; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "config.h"
+#include "mp_msg.h"
+
+#include "libavutil/intreadwrite.h"
+#include "libvo/fastmemcpy.h"
+
+#include "vd_internal.h"
+
+static const vd_info_t info =
+{
+    "PPM decoder",
+    "mppm",
+    "Hernan Badino (hernan.badino at gmail.com)",
+    "Hernan Badino (hernan.badino at gmail.com)",
+    "P5 (pgm) and P6 (ppm) formats supported."
+};
+
+LIBVD_EXTERN(mppm)
+
+static unsigned int out_fmt = 0;
+
+static int last_w = -1;
+static int last_h = -1;
+static int last_c = -1;
+
+
+/* to set/get/query special features/parameters */
+static int control(sh_video_t *sh, int cmd, void *arg, ...)
+{
+    switch (cmd)
+    {
+    case VDCTRL_QUERY_FORMAT:
+        if (*((int *) arg) == out_fmt) return CONTROL_TRUE;
+        return CONTROL_FALSE;
+    }
+    return CONTROL_UNKNOWN;
+}
+
+/* init driver */
+static int init(sh_video_t *sh)
+{
+    last_w = -1;
+
+    return 1;
+}
+
+
+/* uninit driver */
+static void uninit(sh_video_t *sh)
+{
+    return;
+}
+
+struct PpmInfo
+{
+    unsigned char *data;       /*  data */
+    int            length;     /*  length of data */
+
+    int            magic_num;  /*  5 for P5, 6 for P6 */
+
+    int            width;      /*  width  */
+    int            height;     /*  height */
+
+    int            bypp;       /*  bytes per pixel */
+
+    int            offset;     /*  offset to image data */
+};
+
+static int read_header( unsigned char *data, int length, struct PpmInfo *ppm_info )
+{
+    int c, colors;    
+    
+    ppm_info->data   = data;
+    ppm_info->length = length;
+    
+    if (length < 10)
+    {
+        mp_msg(MSGT_DECVIDEO, MSGL_INFO, "Not enough image data!\n");
+        return 0;
+    }    
+
+    /* Read header. */
+    if (data[0] != 'P' || ( data[1] != '6' && data[1] != '5'  ) )
+    {
+        mp_msg(MSGT_DECVIDEO, MSGL_INFO, "Unsupported PPM type! Only P5 and P6 type allowed\n");
+        return 0;
+    }
+    
+    /* set magic number */
+    ppm_info->magic_num = data[1] - '0';
+    
+    /* set bytes per pixel */
+    ppm_info->bypp = ppm_info->magic_num==5?1:3;
+
+    c = 2;
+    while (c < length && data[c] != '\n') ++c;
+
+    if ( c >= length-1 ) 
+    {
+        mp_msg(MSGT_DECVIDEO, MSGL_INFO, "Unsupported PPM type!\n");
+        return 0;
+    }
+
+    /* Skip comments. */
+    ++c;
+    while (c < length && data[c] == '#')
+    {
+        while (c < length && data[c] != '\n') ++c; 
+        while (c < length && data[c] == '\n') ++c; 
+    }
+    
+    if ( c >= length ) 
+    {
+        mp_msg(MSGT_DECVIDEO, MSGL_INFO, "Unsupported PPM type!\n");
+        return 0;
+    }
+
+    /* read image size information */
+    if (sscanf(data+c, "%d %d", &ppm_info->width, &ppm_info->height) != 2) 
+    {
+        mp_msg(MSGT_DECVIDEO, MSGL_INFO, "Unsupported PPM type!\n");
+        return 0;
+    }
+
+    if ( ppm_info->width <= 0 || ppm_info->height <= 0 )
+    {
+        mp_msg(MSGT_DECVIDEO, MSGL_INFO, "Unsupported PPM type!\n");
+        return 0;
+    }
+
+    while (c < length && data[c] != '\n') ++c;
+
+    if ( c >= length-1 ) 
+    {
+        mp_msg(MSGT_DECVIDEO, MSGL_INFO, "Unsupported PPM type!\n");
+        return 0;
+    }
+    
+    ++c;
+
+    if (sscanf(data+c, "%d", &colors) != 1) 
+    {
+        mp_msg(MSGT_DECVIDEO, MSGL_INFO, "Unsupported PPM type!\n");
+        return 0;
+    }
+
+    if (colors > 255) 
+    {
+        mp_msg(MSGT_DECVIDEO, MSGL_INFO, "Unsupported bit depth: %i\n", colors);
+        return 0;
+    }
+
+    while (c < length && data[c] != '\n') ++c;
+
+    if ( c >= length-1 ) 
+    {
+        mp_msg(MSGT_DECVIDEO, MSGL_INFO, "Unsupported PPM type!\n");
+        return 0;
+    }
+
+    ++c;
+
+    if ( length - c < ppm_info->width*ppm_info->height*ppm_info->bypp )
+    {
+        mp_msg(MSGT_DECVIDEO, MSGL_INFO, "Not enough image data for file of size %ix%i!\n", ppm_info->width, ppm_info->height);
+        return 0;
+    }
+
+    ppm_info->offset = c;
+
+    return 1;
+}
+
+
+/* decode a frame */
+static mp_image_t *decode(sh_video_t *sh, void *vdata_p, int length, int flags)
+{
+    mp_image_t* mpi;
+    struct PpmInfo ppm_info;    
+
+    if ( !read_header ( vdata_p, length, &ppm_info) )
+        return NULL;
+
+    if ( ppm_info.magic_num==5)
+        out_fmt = IMGFMT_Y8;
+    else
+        out_fmt = IMGFMT_RGB24;
+
+    /* (re)init libvo if image parameters changed (width/height/colorspace) */
+    if (last_w != ppm_info.width || last_h != ppm_info.height || last_c != out_fmt)
+    {
+	last_w = ppm_info.width;
+	last_h = ppm_info.height;
+	last_c = out_fmt;
+
+	if (!out_fmt || !mpcodecs_config_vo(sh, ppm_info.width, ppm_info.height, out_fmt))
+	    return NULL;
+        
+    }
+    
+    if (!(mpi = mpcodecs_get_image(sh, MP_IMGTYPE_TEMP, MP_IMGFLAG_ACCEPT_STRIDE, ppm_info.width, ppm_info.height)))        
+	return NULL;
+    
+    {
+        unsigned char *p=ppm_info.data+ppm_info.offset;
+        int step = ppm_info.width*ppm_info.bypp;
+    
+        /*  The next "if" a hack to what I think it is a bug.
+        If the color space changes (i.e.,
+        changing from P5 to P6 format), a reinitialization occurs
+        a few lines above calling mpcodecs_config_vo (at least,
+        this is what I understand it does, based on the other
+        implementations for tga and png file formats). However, 
+        mpcodecs_get_image, still provides an image struct with a
+        stride[0] that corresponds to the previous color space.
+        This can be easily be tested when having both, ppm and pgm
+        files on disk and then running "mplayer mf://*.p?m". 
+        I could trace the error back to the mpi->bpp. When
+        processing only ppm (RGB24), mpi->bpp is 24. When processing only
+        pgm (Y8), mpi->bpp is 8. Now, when processing both,
+        interchangeably, mpi->bpp should jump from 8 to 24, but
+        it doesn't; it remains in 8 even if the current output
+        format has changed to IMGFMT_RGB24.
+        printf("mpi->bpp = %i\n",mpi->bpp); */
+        
+        if (mpi->stride[0] < step)
+        {
+            mpi->planes[0] = realloc(mpi->planes[0], ppm_info.height*step);
+            mpi->stride[0] = step;    
+        }
+        
+        /* "Decode" image now. */
+        for (int i = 0; i < ppm_info.height; ++i, p+=step)
+        {
+            memcpy(mpi->planes[0] + mpi->stride[0]*i, p, step);
+        }        
+    }
+    
+    return mpi;
+}
Index: libmpcodecs/vd.c
===================================================================
--- libmpcodecs/vd.c	(revision 35114)
+++ libmpcodecs/vd.c	(working copy)
@@ -49,6 +49,7 @@
 extern const vd_functions_t mpcodecs_vd_mpng;
 extern const vd_functions_t mpcodecs_vd_ijpg;
 extern const vd_functions_t mpcodecs_vd_mtga;
+extern const vd_functions_t mpcodecs_vd_mppm;
 extern const vd_functions_t mpcodecs_vd_sgi;
 extern const vd_functions_t mpcodecs_vd_libmpeg2;
 extern const vd_functions_t mpcodecs_vd_mpegpes;
@@ -90,6 +91,7 @@
     &mpcodecs_vd_ijpg,
 #endif
     &mpcodecs_vd_mtga,
+    &mpcodecs_vd_mppm,
     &mpcodecs_vd_sgi,
 #ifdef CONFIG_LIBMPEG2
     &mpcodecs_vd_libmpeg2,
Index: Makefile
===================================================================
--- Makefile	(revision 35114)
+++ Makefile	(working copy)
@@ -361,6 +361,7 @@
               libmpcodecs/vd_lzo.c \
               libmpcodecs/vd_mpegpes.c \
               libmpcodecs/vd_mtga.c \
+              libmpcodecs/vd_mppm.c \
               libmpcodecs/vd_null.c \
               libmpcodecs/vd_raw.c \
               libmpcodecs/vd_sgi.c \
Index: libmpdemux/demux_mf.c
===================================================================
--- libmpdemux/demux_mf.c	(revision 35114)
+++ libmpdemux/demux_mf.c	(working copy)
@@ -97,6 +97,8 @@
   { "png",  mmioFOURCC('M', 'P', 'N', 'G') },
   { "pns",  mmioFOURCC('M', 'P', 'N', 'G') },
   { "ptx",  mmioFOURCC('p', 't', 'x', ' ') },
+  { "ppm",  mmioFOURCC('M', 'P', 'P', 'M') },
+  { "pgm",  mmioFOURCC('M', 'P', 'P', 'M') },
   { "tga",  mmioFOURCC('M', 'T', 'G', 'A') },
   { "tif",  mmioFOURCC('t', 'i', 'f', 'f') },
   { "tiff",  mmioFOURCC('t', 'i', 'f', 'f') },
Index: etc/codecs.conf
===================================================================
--- etc/codecs.conf	(revision 35114)
+++ etc/codecs.conf	(working copy)
@@ -685,6 +685,14 @@
   driver mtga
   out BGR32,BGR24
 
+videocodec mppm
+  info "PPM image"
+  status working
+  comment "P5 (pgm) and P6 (ppm) formats supported."
+  fourcc mppm,MPPM
+  driver mppm
+  out RGB24,Y8
+
 videocodec ffsgi
   info "FFmpeg SGI image"
   status working


More information about the MPlayer-dev-eng mailing list