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