1 /*
2  * This file is part of MPlayer.
3  *
4  * MPlayer is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * (at your option) any later version.
8  *
9  * MPlayer is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License along
15  * with MPlayer; if not, write to the Free Software Foundation, Inc.,
16  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17  */
18 
19 #include <stdio.h>
20 #include <stdlib.h>
21 
22 #include "config.h"
23 #include "mp_msg.h"
24 
25 #include <png.h>
26 
27 #include "libavutil/common.h"
28 #include "mpbswap.h"
29 #include "libvo/fastmemcpy.h"
30 
31 #include "vd_internal.h"
32 
33 static const vd_info_t info = {
34 	"PNG Images decoder",
35 	"mpng",
36 	"A'rpi",
37 	".so, based on mpng.c",
38 	"uses libpng, 8bpp modes not supported yet"
39 };
40 
41 LIBVD_EXTERN(mpng)
42 
43 static unsigned int out_fmt=0;
44 
45 static int last_w=-1;
46 static int last_h=-1;
47 static int last_c=-1;
48 
49 // to set/get/query special features/parameters
control(sh_video_t * sh,int cmd,void * arg,...)50 static int control(sh_video_t *sh,int cmd,void* arg,...){
51     switch (cmd)
52     {
53 	case VDCTRL_QUERY_FORMAT:
54 	    if (*((int *) arg) == out_fmt) return CONTROL_TRUE;
55 	    return CONTROL_FALSE;
56     }
57     return CONTROL_UNKNOWN;
58 }
59 
60 // init driver
init(sh_video_t * sh)61 static int init(sh_video_t *sh){
62     last_w=-1;
63     return 1;
64 }
65 
66 // uninit driver
uninit(sh_video_t * sh)67 static void uninit(sh_video_t *sh){
68 }
69 
70 //mp_image_t* mpcodecs_get_image(sh_video_t *sh, int mp_imgtype, int mp_imgflag, int w, int h);
71 
72 static int    pngPointer;
73 static int    pngLength;
74 
pngReadFN(png_structp pngstr,png_bytep buffer,png_size_t size)75 static void pngReadFN( png_structp pngstr,png_bytep buffer,png_size_t size )
76 {
77  char * p = png_get_io_ptr(pngstr);
78  if(size>pngLength-pngPointer && pngLength>=pngPointer) size=pngLength-pngPointer;
79  fast_memcpy( buffer,(char *)&p[pngPointer],size );
80  pngPointer+=size;
81 }
82 
83 // decode a frame
decode(sh_video_t * sh,void * data,int len,int flags)84 static mp_image_t* decode(sh_video_t *sh,void* data,int len,int flags){
85     png_structp     png;
86     png_infop       info;
87     png_infop       endinfo;
88 //    png_bytep       data;
89     png_bytep     * row_p;
90     png_uint_32     png_width=0,png_height=0;
91     int             depth,color;
92     png_uint_32     i;
93     png_byte        color_type;
94     mp_image_t* mpi;
95 
96     int cols;
97     png_colorp pal;
98     unsigned char *p;
99 
100     if(len<=0) return NULL; // skipped frame
101 
102  png=png_create_read_struct( PNG_LIBPNG_VER_STRING,NULL,NULL,NULL );
103  info=png_create_info_struct( png );
104  endinfo=png_create_info_struct( png );
105 
106  pngPointer=8;
107  pngLength=len;
108  png_set_read_fn( png,data,pngReadFN );
109  png_set_strip_16( png );
110  png_set_sig_bytes( png,8 );
111  png_read_info( png,info );
112  png_get_IHDR( png,info,&png_width,&png_height,&depth,&color,NULL,NULL,NULL );
113  png_set_bgr( png );
114 
115  color_type=png_get_color_type(png, info);
116 
117  switch( color_type ) {
118    case PNG_COLOR_TYPE_GRAY_ALPHA:
119       mp_msg( MSGT_DECVIDEO,MSGL_INFO,"Sorry gray scaled png with alpha channel not supported at moment.\n" );
120       break;
121    case PNG_COLOR_TYPE_GRAY:
122       out_fmt=IMGFMT_Y800;
123       break;
124    case PNG_COLOR_TYPE_PALETTE:
125       out_fmt=IMGFMT_BGR8;
126       break;
127    case PNG_COLOR_TYPE_RGB_ALPHA:
128       out_fmt=IMGFMT_BGR32;
129       break;
130    case PNG_COLOR_TYPE_RGB:
131       out_fmt=IMGFMT_BGR24;
132       break;
133    default:
134       mp_msg( MSGT_DECVIDEO,MSGL_INFO,"Sorry, unsupported PNG colorspace: %d.\n" ,color_type);
135  }
136 
137  // (re)init libvo if image parameters changed (width/height/colorspace)
138  if(last_w!=png_width || last_h!=png_height || last_c!=out_fmt){
139     last_w=png_width; last_h=png_height; last_c=out_fmt;
140     if(!out_fmt) return NULL;
141     if(!mpcodecs_config_vo(sh,png_width,png_height,out_fmt)) return NULL;
142  }
143 
144 #if 0
145  switch( info->color_type )
146   {
147    case PNG_COLOR_TYPE_GRAY_ALPHA: printf( "[png] used GrayA -> stripping alpha channel\n" ); break;
148    case PNG_COLOR_TYPE_GRAY:       printf( "[png] used Gray -> rgb\n" ); break;
149    case PNG_COLOR_TYPE_PALETTE:    printf( "[png] used palette -> rgb\n" ); break;
150    case PNG_COLOR_TYPE_RGB_ALPHA:  printf( "[png] used RGBA -> stripping alpha channel\n" ); break;
151    case PNG_COLOR_TYPE_RGB:        printf( "[png] read rgb datas.\n" ); break;
152   }
153 #endif
154 
155     mpi=mpcodecs_get_image(sh, MP_IMGTYPE_TEMP, MP_IMGFLAG_ACCEPT_STRIDE,
156 	png_width,png_height);
157     if(!mpi) return NULL;
158 
159 // Let's DECODE!
160  row_p=malloc( sizeof( png_bytep ) * png_height );
161 //png_get_rowbytes( png,info )
162  for ( i=0; i < png_height; i++ ) row_p[i]=mpi->planes[0] + mpi->stride[0]*i;
163  png_read_image( png,row_p );
164  free( row_p );
165 
166  if (out_fmt==IMGFMT_BGR8) {
167      png_get_PLTE( png,info,&pal,&cols );
168      mpi->planes[1] = realloc(mpi->planes[1], 4*cols);
169      p = mpi->planes[1];
170      for (i = 0; i < cols; i++) {
171 	 *p++ = pal[i].blue;
172 	 *p++ = pal[i].green;
173 	 *p++ = pal[i].red;
174 	 *p++ = 0;
175      }
176  }
177 
178  png_read_end( png,endinfo );
179  png_destroy_read_struct( &png,&info,&endinfo );
180 
181     return mpi;
182 }
183