[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