LCOV - code coverage report
Current view: top level - media_tools - img.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 220 304 72.4 %
Date: 2021-04-29 23:48:07 Functions: 8 14 57.1 %

          Line data    Source code
       1             : /*
       2             :  *                      GPAC - Multimedia Framework C SDK
       3             :  *
       4             :  *                      Authors: Jean Le Feuvre
       5             :  *                      Copyright (c) Telecom ParisTech 2000-2012
       6             :  *                                      All rights reserved
       7             :  *
       8             :  *  This file is part of GPAC / Media Tools sub-project
       9             :  *
      10             :  *  GPAC is free software; you can redistribute it and/or modify
      11             :  *  it under the terms of the GNU Lesser General Public License as published by
      12             :  *  the Free Software Foundation; either version 2, or (at your option)
      13             :  *  any later version.
      14             :  *
      15             :  *  GPAC is distributed in the hope that it will be useful,
      16             :  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
      17             :  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      18             :  *  GNU Lesser General Public License for more details.
      19             :  *
      20             :  *  You should have received a copy of the GNU Lesser General Public
      21             :  *  License along with this library; see the file COPYING.  If not, write to
      22             :  *  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
      23             :  *
      24             :  */
      25             : 
      26             : #include <gpac/internal/media_dev.h>
      27             : #include <gpac/internal/isomedia_dev.h>
      28             : #include <gpac/constants.h>
      29             : 
      30             : #ifdef GPAC_HAS_PNG
      31             : 
      32             : #if (defined(WIN32) || defined(_WIN32_WCE)) && !defined(__GNUC__)
      33             : #pragma comment(lib, "libpng")
      34             : #endif
      35             : 
      36             : /*include png.h before setjmp.h, otherwise we get compilation errors*/
      37             : #include <png.h>
      38             : 
      39             : #endif /*GPAC_HAS_PNG*/
      40             : 
      41             : 
      42             : #ifdef GPAC_HAS_JPEG
      43             : 
      44             : #if (defined(WIN32) || defined(_WIN32_WCE)) && !defined(__GNUC__)
      45             : #pragma comment(lib, "libjpeg")
      46             : #endif
      47             : 
      48             : #include <jpeglib.h>
      49             : #include <setjmp.h>
      50             : 
      51             : #endif  /*GPAC_HAS_JPEG*/
      52             : 
      53             : GF_EXPORT
      54         302 : void gf_img_parse(GF_BitStream *bs, u32 *codecid, u32 *width, u32 *height, u8 **dsi, u32 *dsi_len)
      55             : {
      56             :         u8 b1, b2, b3;
      57             :         u32 size, type;
      58             :         u64 pos;
      59         302 :         pos = gf_bs_get_position(bs);
      60         302 :         gf_bs_seek(bs, 0);
      61             : 
      62         302 :         *width = *height = 0;
      63         302 :         *codecid = 0;
      64         302 :         if (dsi) {
      65         302 :                 *dsi = NULL;
      66         302 :                 *dsi_len = 0;
      67             :         }
      68             : 
      69         302 :         b1 = gf_bs_read_u8(bs);
      70         302 :         b2 = gf_bs_read_u8(bs);
      71         302 :         b3 = gf_bs_read_u8(bs);
      72             :         /*JPEG*/
      73         302 :         if ((b1==0xFF) && (b2==0xD8) && (b3==0xFF)) {
      74             :                 u32 offset = 0;
      75             :                 u32 Xdens, Ydens, nb_comp;
      76         165 :                 gf_bs_read_u8(bs);
      77         165 :                 gf_bs_skip_bytes(bs, 10);       /*2 size, 5 JFIF\0, 2 version, 1 units*/
      78         165 :                 Xdens = gf_bs_read_int(bs, 16);
      79         165 :                 Ydens = gf_bs_read_int(bs, 16);
      80             :                 nb_comp = 0;
      81             : 
      82             :                 /*get frame header FFC0*/
      83    11681437 :                 while (gf_bs_available(bs)) {
      84             :                         u32 w, h,length;
      85    11681107 :                         if (gf_bs_read_u8(bs) != 0xFF) continue;
      86       38120 :                         if (!offset) offset = (u32)gf_bs_get_position(bs) - 1;
      87             : 
      88       38120 :                         type = gf_bs_read_u8(bs);
      89             :                         /*process all Start of Image markers*/
      90             :                         switch (type) {
      91         169 :                         case 0xC0:
      92             :                         case 0xC1:
      93             :                         case 0xC2:
      94             :                         case 0xC3:
      95             :                         case 0xC5:
      96             :                         case 0xC6:
      97             :                         case 0xC7:
      98             :                         case 0xC9:
      99             :                         case 0xCA:
     100             :                         case 0xCB:
     101             :                         case 0xCD:
     102             :                         case 0xCE:
     103             :                         case 0xCF:
     104         169 :                 length = gf_bs_read_u16(bs);
     105         169 :                 /*prec = */gf_bs_read_u8(bs);
     106         169 :                                 h = gf_bs_read_int(bs, 16);
     107         169 :                                 w = gf_bs_read_int(bs, 16);
     108         169 :                 nb_comp = gf_bs_read_int(bs, 8);
     109         169 :                 if (length != 8 + 3*nb_comp) continue;  //This is not the right marker
     110         167 :                                 if ((w > *width) || (h > *height)) {
     111         167 :                                         *width = w;
     112         167 :                                         *height = h;
     113             :                                 }
     114             :                                 break;
     115             :                         }
     116             :                 }
     117         165 :                 *codecid = GF_CODECID_JPEG;
     118         165 :                 if (dsi) {
     119         165 :                         GF_BitStream *bs_dsi = gf_bs_new(NULL, 0, GF_BITSTREAM_WRITE);
     120         165 :                         gf_bs_write_u16(bs_dsi, offset);
     121         165 :                         gf_bs_write_u16(bs_dsi, Xdens);
     122         165 :                         gf_bs_write_u16(bs_dsi, Ydens);
     123         165 :                         gf_bs_write_u8(bs_dsi, nb_comp);
     124         165 :                         gf_bs_get_content(bs_dsi, dsi, dsi_len);
     125         165 :                         gf_bs_del(bs_dsi);
     126             :                 }
     127             :         }
     128             :         /*PNG*/
     129         137 :         else if ((b1==0x89) && (b2==0x50) && (b3==0x4E)) {
     130             :                 /*check for PNG sig*/
     131         399 :                 if ( (gf_bs_read_u8(bs) != 0x47) || (gf_bs_read_u8(bs) != 0x0D) || (gf_bs_read_u8(bs) != 0x0A)
     132         266 :                         || (gf_bs_read_u8(bs) != 0x1A) || (gf_bs_read_u8(bs) != 0x0A) ) goto exit;
     133         133 :                 gf_bs_read_u32(bs);
     134             :                 /*check for PNG IHDR*/
     135         266 :                 if ( (gf_bs_read_u8(bs) != 'I') || (gf_bs_read_u8(bs) != 'H')
     136         266 :                         || (gf_bs_read_u8(bs) != 'D') || (gf_bs_read_u8(bs) != 'R')) goto exit;
     137             : 
     138         133 :                 *width = gf_bs_read_u32(bs);
     139         133 :                 *height = gf_bs_read_u32(bs);
     140         133 :                 *codecid = GF_CODECID_PNG;
     141             :         }
     142             :         /*try j2k*/
     143             :         else {
     144             :                 u32 jp2h_size=0, jp2h_start=0;
     145           4 :                 size = gf_bs_read_u8(bs);
     146           4 :                 type = gf_bs_read_u32(bs);
     147           4 :                 if ( ((size==12) && (type==GF_ISOM_BOX_TYPE_JP ))
     148           0 :                 || (type==GF_ISOM_BOX_TYPE_JP2H ) ) {
     149             : 
     150           4 :                         if (type==GF_ISOM_BOX_TYPE_JP2H) {
     151           0 :                                 *codecid = GF_CODECID_J2K;
     152           0 :                                 goto j2k_restart;
     153             :                         }
     154             : 
     155           4 :                         type = gf_bs_read_u32(bs);
     156           4 :                         if (type!=0x0D0A870A) goto exit;
     157             : 
     158           4 :                         *codecid = GF_CODECID_J2K;
     159             : 
     160          12 :                         while (gf_bs_available(bs)) {
     161           8 : j2k_restart:
     162          12 :                                 size = gf_bs_read_u32(bs);
     163          12 :                                 type = gf_bs_read_u32(bs);
     164          12 :                                 switch (type) {
     165           4 :                                 case GF_ISOM_BOX_TYPE_JP2H:
     166           4 :                                         jp2h_size=size-8;
     167           4 :                                         jp2h_start = (u32) gf_bs_get_position(bs);
     168           4 :                                         goto j2k_restart;
     169           4 :                                 case GF_ISOM_BOX_TYPE_IHDR:
     170             :                                 {
     171           4 :                                         *height = gf_bs_read_u32(bs);
     172           4 :                                         *width = gf_bs_read_u32(bs);
     173             :                                         /*nb_comp = gf_bs_read_u16(bs);
     174             :                                         BPC = gf_bs_read_u8(bs);
     175             :                                         C = gf_bs_read_u8(bs);
     176             :                                         UnkC = gf_bs_read_u8(bs);
     177             :                                         IPR = gf_bs_read_u8(bs);
     178             :                                         */
     179           4 :                                         if (dsi && jp2h_size) {
     180           4 :                                                 *dsi = gf_malloc(sizeof(char)*jp2h_size);
     181           4 :                                                 gf_bs_seek(bs, jp2h_start);
     182           4 :                                                 gf_bs_read_data(bs, *dsi, jp2h_size);
     183           4 :                                                 *dsi_len = jp2h_size;
     184             :                                         }
     185             :                                         goto exit;
     186             :                                 }
     187             :                                 break;
     188           4 :                                 default:
     189           4 :                                         gf_bs_skip_bytes(bs, size-8);
     190           4 :                                         break;
     191             :                                 }
     192             :                         }
     193             :                 }
     194             :         }
     195             : 
     196           0 : exit:
     197         302 :         gf_bs_seek(bs, pos);
     198         302 : }
     199             : 
     200             : #ifdef GPAC_HAS_JPEG
     201             : 
     202        5916 : void gf_jpeg_nonfatal_error2(j_common_ptr cinfo, int lev)
     203             : {
     204             : 
     205        5916 : }
     206             : 
     207             : /*JPG context while decoding*/
     208             : typedef struct
     209             : {
     210             :         struct jpeg_error_mgr pub;
     211             :         jmp_buf jmpbuf;
     212             : } JPGErr;
     213             : 
     214             : typedef struct
     215             : {
     216             :         /*io manager*/
     217             :         struct jpeg_source_mgr src;
     218             : 
     219             :         s32 skip;
     220             :         struct jpeg_decompress_struct cinfo;
     221             : } JPGCtx;
     222             : 
     223           0 : static void gf_jpeg_output_message (j_common_ptr cinfo)
     224             : {
     225           0 :         if (cinfo) {
     226             :                 char buffer[JMSG_LENGTH_MAX];
     227             :                 /* Create the message */
     228           0 :                 (*cinfo->err->format_message) (cinfo, buffer);
     229           0 :                 GF_LOG(GF_LOG_ERROR, GF_LOG_CODEC, ("[JPEG OUTPUT MESSAGE]: %s\n", buffer));
     230             :         }
     231           0 : }
     232             : 
     233           0 : static void gf_jpeg_fatal_error(j_common_ptr cinfo)
     234             : {
     235           0 :         if (cinfo) {
     236           0 :                 JPGErr *err = (JPGErr *) cinfo->err;
     237           0 :                 gf_jpeg_output_message(cinfo);
     238           0 :                 longjmp(err->jmpbuf, 1);
     239             :         }
     240           0 : }
     241             : 
     242         348 : void gf_jpeg_stub(j_decompress_ptr cinfo) {}
     243             : 
     244             : /*a JPEG is always carried in a complete, single MPEG4 AU so no refill*/
     245           0 : static boolean gf_jpeg_fill_input_buffer(j_decompress_ptr cinfo)
     246             : {
     247           0 :         return 0;
     248             : }
     249             : 
     250           0 : static void gf_jpeg_skip_input_data(j_decompress_ptr cinfo, long num_bytes)
     251             : {
     252           0 :         if (cinfo) {
     253           0 :                 JPGCtx *jpx = (JPGCtx *) cinfo->src;
     254           0 :                 if (num_bytes > (long) jpx->src.bytes_in_buffer) {
     255           0 :                         jpx->skip = (s32) (num_bytes - jpx->src.bytes_in_buffer);
     256           0 :                         jpx->src.next_input_byte += jpx->src.bytes_in_buffer;
     257           0 :                         jpx->src.bytes_in_buffer = 0;
     258             :                 } else {
     259           0 :                         jpx->src.bytes_in_buffer -= num_bytes;
     260           0 :                         jpx->src.next_input_byte += num_bytes;
     261           0 :                         jpx->skip = 0;
     262             :                 }
     263             :         }
     264           0 : }
     265             : 
     266             : #define JPEG_MAX_SCAN_BLOCK_HEIGHT              16
     267             : 
     268             : GF_EXPORT
     269         232 : GF_Err gf_img_jpeg_dec(u8 *jpg, u32 jpg_size, u32 *width, u32 *height, u32 *pixel_format, u8 *dst, u32 *dst_size, u32 dst_nb_comp)
     270             : {
     271             :         s32 i, j, scans, k;
     272             :         u32 stride;
     273             :         char *scan_line, *ptr, *tmp;
     274             :         char *lines[JPEG_MAX_SCAN_BLOCK_HEIGHT];
     275             :         JPGErr jper;
     276             :         JPGCtx jpx;
     277             : 
     278             : #ifdef GPAC_ENABLE_COVERAGE
     279         232 :         if (gf_sys_is_cov_mode()) {
     280             :                 gf_jpeg_fatal_error(NULL);
     281             :                 gf_jpeg_output_message(NULL);
     282             :                 gf_jpeg_nonfatal_error2(NULL, 0);
     283             :                 gf_jpeg_fill_input_buffer(NULL);
     284             :                 gf_jpeg_skip_input_data(NULL, 0);
     285             :         }
     286             : #endif
     287         232 :         if (!dst) *dst_size = 0;
     288             :         
     289         232 :         jpx.cinfo.err = jpeg_std_error(&(jper.pub));
     290         232 :         jper.pub.error_exit = gf_jpeg_fatal_error;
     291         232 :         jper.pub.output_message = gf_jpeg_output_message;
     292         232 :         jper.pub.emit_message = gf_jpeg_nonfatal_error2;
     293         232 :         if (setjmp(jper.jmpbuf)) {
     294           0 :                 GF_LOG(GF_LOG_ERROR, GF_LOG_CODEC, ("[JPEGDecode] : Failed to decode\n"));
     295           0 :                 jpeg_destroy_decompress(&jpx.cinfo);
     296             :                 return GF_IO_ERR;
     297             :         }
     298             : 
     299             :         /*create decompress struct*/
     300         232 :         jpeg_create_decompress(&jpx.cinfo);
     301             : 
     302             :         /*prepare IO*/
     303         232 :         jpx.src.init_source = gf_jpeg_stub;
     304         232 :         jpx.src.fill_input_buffer = gf_jpeg_fill_input_buffer;
     305         232 :         jpx.src.skip_input_data = gf_jpeg_skip_input_data;
     306         232 :         jpx.src.resync_to_restart = jpeg_resync_to_restart;
     307         232 :         jpx.src.term_source = gf_jpeg_stub;
     308         232 :         jpx.skip = 0;
     309         232 :         jpx.src.next_input_byte = (JOCTET *) jpg;
     310         232 :         jpx.src.bytes_in_buffer = jpg_size;
     311         232 :         jpx.cinfo.src = (void *) &jpx.src;
     312             : 
     313             :         /*read header*/
     314             :         do {
     315         232 :                 i = jpeg_read_header(&jpx.cinfo, TRUE);
     316         232 :         } while (i == JPEG_HEADER_TABLES_ONLY);
     317             :         /*we're supposed to have the full image in the buffer, wrong stream*/
     318         232 :         if (i == JPEG_SUSPENDED) {
     319           0 :                 jpeg_destroy_decompress(&jpx.cinfo);
     320             :                 return GF_NON_COMPLIANT_BITSTREAM;
     321             :         }
     322             : 
     323         232 :         *width = jpx.cinfo.image_width;
     324         232 :         *height = jpx.cinfo.image_height;
     325         232 :         stride = *width * jpx.cinfo.num_components;
     326             : 
     327         232 :         switch (jpx.cinfo.num_components) {
     328           0 :         case 1:
     329           0 :                 *pixel_format = GF_PIXEL_GREYSCALE;
     330           0 :                 break;
     331         232 :         case 3:
     332         232 :                 *pixel_format = GF_PIXEL_RGB;
     333         232 :                 break;
     334           0 :         default:
     335           0 :                 jpeg_destroy_decompress(&jpx.cinfo);
     336             :                 return GF_NON_COMPLIANT_BITSTREAM;
     337             :         }
     338         232 :         if (!dst || (*dst_size < *height * *width * jpx.cinfo.num_components)) {
     339         116 :                 *dst_size = *height * *width * jpx.cinfo.num_components;
     340         116 :                 jpeg_destroy_decompress(&jpx.cinfo);
     341             :                 return GF_BUFFER_TOO_SMALL;
     342             :         }
     343         116 :         if (!dst_nb_comp) dst_nb_comp = jpx.cinfo.num_components;
     344             : 
     345             :         scan_line = NULL;
     346             :         /*decode*/
     347         116 :         jpx.cinfo.do_fancy_upsampling = FALSE;
     348         116 :         jpx.cinfo.do_block_smoothing = FALSE;
     349         116 :         if (!jpeg_start_decompress(&jpx.cinfo)) {
     350           0 :                 jpeg_destroy_decompress(&jpx.cinfo);
     351             :                 return GF_NON_COMPLIANT_BITSTREAM;
     352             :         }
     353         116 :         if (jpx.cinfo.rec_outbuf_height>JPEG_MAX_SCAN_BLOCK_HEIGHT) {
     354           0 :                 jpeg_destroy_decompress(&jpx.cinfo);
     355           0 :                 GF_LOG(GF_LOG_WARNING, GF_LOG_MEDIA, ("[gf_img_jpeg_dec] : jpx.cinfo.rec_outbuf_height>JPEG_MAX_SCAN_BLOCK_HEIGHT\n"));
     356             :                 return GF_IO_ERR;
     357             :         }
     358             : 
     359             :         /*read scanlines (the scan is not one line by one line so alloc a placeholder for block scaning) */
     360         116 :         scan_line = gf_malloc(sizeof(char) * stride * jpx.cinfo.rec_outbuf_height);
     361         232 :         for (i = 0; i<jpx.cinfo.rec_outbuf_height; i++) {
     362         232 :                 lines[i] = scan_line + i * stride;
     363             :         }
     364             :         tmp = dst;
     365        8756 :         for (j=0; j< (s32) *height; j += jpx.cinfo.rec_outbuf_height) {
     366        8756 :                 jpeg_read_scanlines(&jpx.cinfo, (unsigned char **) lines, jpx.cinfo.rec_outbuf_height);
     367        8756 :                 scans = jpx.cinfo.rec_outbuf_height;
     368        8756 :                 if (( (s32) *height - j) < scans) scans = *height - j;
     369             :                 ptr = scan_line;
     370             :                 /*for each line in the scan*/
     371       26268 :                 for (k = 0; k < scans; k++) {
     372       17512 :                         if (dst_nb_comp==(u32)jpx.cinfo.num_components) {
     373             :                                 memcpy(tmp, ptr, sizeof(char) * stride);
     374       17512 :                                 ptr += stride;
     375       17512 :                                 tmp += stride;
     376             :                         } else {
     377             :                                 u32 z, c;
     378           0 :                                 for (z=0; z<*width; z++) {
     379           0 :                                         for (c=0; c<(u32)jpx.cinfo.num_components; c++) {
     380           0 :                                                 if (c >= dst_nb_comp) break;
     381           0 :                                                 tmp[c] = ptr[c];
     382             :                                         }
     383           0 :                                         ptr += jpx.cinfo.num_components;
     384           0 :                                         tmp += dst_nb_comp;
     385             :                                 }
     386             :                         }
     387             :                 }
     388             :         }
     389             : 
     390             :         /*done*/
     391         116 :         jpeg_finish_decompress(&jpx.cinfo);
     392         116 :         jpeg_destroy_decompress(&jpx.cinfo);
     393             : 
     394         116 :         gf_free(scan_line);
     395             : 
     396             :         return GF_OK;
     397             : }
     398             : #else
     399             : 
     400             : GF_EXPORT
     401             : GF_Err gf_img_jpeg_dec(u8 *jpg, u32 jpg_size, u32 *width, u32 *height, u32 *pixel_format, u8 *dst, u32 *dst_size, u32 dst_nb_comp)
     402             : {
     403             :         return GF_NOT_SUPPORTED;
     404             : }
     405             : 
     406             : #endif  /*GPAC_HAS_JPEG*/
     407             : 
     408             : 
     409             : #ifdef GPAC_HAS_PNG
     410             : 
     411             : typedef struct
     412             : {
     413             :         char *buffer;
     414             :         u32 pos;
     415             :         u32 size;
     416             :         png_byte **rows;
     417             : } GFpng;
     418             : 
     419        5073 : static void gf_png_user_read_data(png_structp png_ptr, png_bytep data, png_size_t length)
     420             : {
     421        5073 :         GFpng *ctx = (GFpng*)png_get_io_ptr(png_ptr);
     422             : 
     423        5073 :         if (ctx->pos + length > ctx->size) {
     424           0 :                 png_error(png_ptr, "Read Error");
     425             :         } else {
     426        5073 :                 memcpy(data, (char*) ctx->buffer + ctx->pos, length);
     427        5073 :                 ctx->pos += (u32) length;
     428             :         }
     429        5073 : }
     430           0 : static void gf_png_user_error_fn(png_structp png_ptr,png_const_charp error_msg)
     431             : {
     432           0 :         if (png_ptr) {
     433           0 :                 longjmp(png_jmpbuf(png_ptr), 1);
     434             :         }
     435           0 : }
     436             : 
     437             : 
     438             : GF_EXPORT
     439         230 : GF_Err gf_img_png_dec(u8 *png, u32 png_size, u32 *width, u32 *height, u32 *pixel_format, u8 *dst, u32 *dst_size)
     440             : {
     441             :         GFpng udta;
     442             :         png_struct *png_ptr;
     443             :         png_info *info_ptr;
     444             :         u32 i, stride, out_size;
     445             :         png_bytep trans_alpha;
     446             :         int num_trans;
     447             :         png_color_16p trans_color;
     448             : 
     449         230 :         if ((png_size<8) || png_sig_cmp((png_bytep)png, 0, 8) ) {
     450           0 :                 GF_LOG(GF_LOG_ERROR, GF_LOG_CODEC, ("[PNG]: Wrong signature\n"));
     451             :                 return GF_NON_COMPLIANT_BITSTREAM;
     452             :         }
     453         230 :         udta.buffer = png;
     454         230 :         udta.size = png_size;
     455         230 :         udta.pos = 0;
     456         230 :         udta.rows=NULL;
     457             : 
     458             : #ifdef GPAC_ENABLE_COVERAGE
     459         230 :         if (gf_sys_is_cov_mode()) {
     460             :                 gf_png_user_error_fn(NULL, NULL);
     461             :         }
     462             : #endif
     463             : 
     464         230 :         png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, (png_voidp) &udta, NULL, NULL);
     465         230 :         if (!png_ptr) return GF_IO_ERR;
     466         230 :         info_ptr = png_create_info_struct(png_ptr);
     467         230 :         if (info_ptr == NULL) {
     468           0 :                 png_destroy_read_struct(&png_ptr, (png_infopp)NULL, (png_infopp)NULL);
     469             :                 return GF_IO_ERR;
     470             :         }
     471         230 :         if (setjmp(png_jmpbuf(png_ptr))) {
     472           0 :                 png_destroy_info_struct(png_ptr,(png_infopp) & info_ptr);
     473           0 :                 png_destroy_read_struct(&png_ptr, (png_infopp)NULL, (png_infopp)NULL);
     474           0 :                 if (udta.rows) gf_free(udta.rows);
     475             :                 return GF_IO_ERR;
     476             :         }
     477         230 :         png_set_read_fn(png_ptr, &udta, (png_rw_ptr) gf_png_user_read_data);
     478         230 :         png_set_error_fn(png_ptr, &udta, (png_error_ptr) gf_png_user_error_fn, NULL);
     479             : 
     480         230 :         png_read_info(png_ptr, info_ptr);
     481             : 
     482             :         /*unpaletize*/
     483         230 :         if (png_get_color_type(png_ptr, info_ptr)==PNG_COLOR_TYPE_PALETTE) {
     484           0 :                 png_set_expand(png_ptr);
     485           0 :                 png_read_update_info(png_ptr, info_ptr);
     486             :         }
     487         230 :         num_trans = 0;
     488         230 :         png_get_tRNS(png_ptr, info_ptr, &trans_alpha, &num_trans, &trans_color);
     489         230 :         if (num_trans) {
     490           0 :                 png_set_tRNS_to_alpha(png_ptr);
     491           0 :                 png_read_update_info(png_ptr, info_ptr);
     492             :         }
     493         230 :         *width = (u32) png_get_image_width(png_ptr, info_ptr);
     494         230 :         *height = (u32) png_get_image_height(png_ptr, info_ptr);
     495             : 
     496         230 :         switch (png_get_color_type(png_ptr, info_ptr)) {
     497           0 :         case PNG_COLOR_TYPE_GRAY:
     498           0 :                 *pixel_format = GF_PIXEL_GREYSCALE;
     499           0 :                 break;
     500           0 :         case PNG_COLOR_TYPE_GRAY_ALPHA:
     501           0 :                 *pixel_format = GF_PIXEL_GREYALPHA;
     502           0 :                 break;
     503           2 :         case PNG_COLOR_TYPE_RGB:
     504           2 :                 *pixel_format = GF_PIXEL_RGB;
     505           2 :                 break;
     506         228 :         case PNG_COLOR_TYPE_RGB_ALPHA:
     507         228 :                 *pixel_format = GF_PIXEL_RGBA;
     508         228 :                 break;
     509           0 :         default:
     510           0 :                 png_destroy_info_struct(png_ptr,(png_infopp) & info_ptr);
     511           0 :                 png_destroy_read_struct(&png_ptr, (png_infopp)NULL, (png_infopp)NULL);
     512             :                 return GF_NOT_SUPPORTED;
     513             : 
     514             :         }
     515             : 
     516         230 :         out_size = (u32) (png_get_rowbytes(png_ptr, info_ptr) * png_get_image_height(png_ptr, info_ptr));
     517             :         /*new cfg, reset*/
     518         230 :         if (*dst_size != out_size) {
     519         115 :                 *dst_size  = out_size;
     520         115 :                 png_destroy_info_struct(png_ptr,(png_infopp) & info_ptr);
     521         115 :                 png_destroy_read_struct(&png_ptr, (png_infopp)NULL, (png_infopp)NULL);
     522             :                 return GF_BUFFER_TOO_SMALL;
     523             :         }
     524         115 :         *dst_size  = out_size;
     525         115 :         if (!dst) return GF_BAD_PARAM;
     526             : 
     527             :         /*read*/
     528         115 :         stride = (u32) png_get_rowbytes(png_ptr, info_ptr);
     529         115 :         udta.rows = (png_bytepp) gf_malloc(sizeof(png_bytep) * png_get_image_height(png_ptr, info_ptr));
     530       19994 :         for (i=0; i<png_get_image_height(png_ptr, info_ptr); i++) {
     531       19879 :                 udta.rows[i] = (png_bytep)dst + i*stride;
     532             :         }
     533         115 :         png_read_image(png_ptr, udta.rows);
     534         115 :         png_read_end(png_ptr, NULL);
     535         115 :         gf_free(udta.rows);
     536             : 
     537         115 :         png_destroy_info_struct(png_ptr,(png_infopp) & info_ptr);
     538         115 :         png_destroy_read_struct(&png_ptr, (png_infopp)NULL, (png_infopp)NULL);
     539             :         return GF_OK;
     540             : }
     541             : 
     542             : 
     543          24 : void gf_png_write(png_structp png, png_bytep data, png_size_t size)
     544             : {
     545          24 :         GFpng *p = (GFpng *)png_get_io_ptr(png);
     546          24 :         memcpy(p->buffer+p->pos, data, sizeof(char)*size);
     547          24 :         p->pos += (u32) size;
     548          24 : }
     549           0 : void gf_png_flush(png_structp png)
     550             : {
     551           0 : }
     552             : 
     553             : /* write a png file */
     554             : GF_EXPORT
     555           2 : GF_Err gf_img_png_enc(u8 *data, u32 width, u32 height, s32 stride, u32 pixel_format, u8 *dst, u32 *dst_size)
     556             : {
     557             :         GFpng udta;
     558             :         png_color_8 sig_bit;
     559             :         png_int_32 k;
     560             :         png_bytep *row_pointers;
     561             :         png_structp png_ptr;
     562             :         png_infop info_ptr;
     563             :         u32 type, nb_comp;
     564             : 
     565           2 :         switch (pixel_format) {
     566             :         case GF_PIXEL_GREYSCALE:
     567             :                 nb_comp = 1;
     568             :                 type = PNG_COLOR_TYPE_GRAY;
     569             :                 break;
     570           0 :         case GF_PIXEL_GREYALPHA:
     571             :                 nb_comp = 1;
     572             :                 type = PNG_COLOR_TYPE_GRAY_ALPHA;
     573           0 :                 break;
     574           2 :         case GF_PIXEL_RGB:
     575             :         case GF_PIXEL_BGR:
     576             :         case GF_PIXEL_RGBX:
     577             :         case GF_PIXEL_BGRX:
     578             :                 nb_comp = 3;
     579             :                 type = PNG_COLOR_TYPE_RGB;
     580           2 :                 break;
     581           0 :         case GF_PIXEL_RGBA:
     582             :         case GF_PIXEL_ARGB:
     583             :                 nb_comp = 4;
     584             :                 type = PNG_COLOR_TYPE_RGB_ALPHA;
     585           0 :                 break;
     586             :         default:
     587             :                 return GF_NOT_SUPPORTED;
     588             :         }
     589           2 :         if (*dst_size < width*height*nb_comp) return GF_BUFFER_TOO_SMALL;
     590             : 
     591             : 
     592           2 :         png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
     593             :         //      png_voidp user_error_ptr, user_error_fn, user_warning_fn);
     594             : 
     595           2 :         if (png_ptr == NULL) return GF_IO_ERR;
     596             : 
     597             : #ifdef GPAC_ENABLE_COVERAGE
     598           2 :         if (gf_sys_is_cov_mode()) {
     599             :                 gf_png_flush(NULL);
     600             :         }
     601             : #endif
     602             : 
     603             :         /* Allocate/initialize the image information data.  REQUIRED */
     604           2 :         info_ptr = png_create_info_struct(png_ptr);
     605           2 :         if (info_ptr == NULL) {
     606           0 :                 png_destroy_write_struct(&png_ptr, NULL);
     607             :                 return GF_IO_ERR;
     608             :         }
     609             : 
     610             :         /* Set error handling.  REQUIRED if you aren't supplying your own
     611             :         * error handling functions in the png_create_write_struct() call.
     612             :         */
     613           2 :         if (setjmp(png_jmpbuf(png_ptr))) {
     614           0 :                 png_destroy_write_struct(&png_ptr, &info_ptr);
     615             :                 return GF_NON_COMPLIANT_BITSTREAM;
     616             :         }
     617             : 
     618           2 :         udta.buffer = dst;
     619           2 :         udta.pos = 0;
     620           2 :         png_set_write_fn(png_ptr, &udta, gf_png_write, gf_png_flush);
     621             : 
     622           2 :         png_set_IHDR(png_ptr, info_ptr, width, height, 8, type, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
     623             : 
     624             :         /* otherwise, if we are dealing with a color image then */
     625           2 :         sig_bit.red = 8;
     626           2 :         sig_bit.green = 8;
     627           2 :         sig_bit.blue = 8;
     628           2 :         sig_bit.gray = 8;
     629           2 :         sig_bit.alpha = 8;
     630           2 :         png_set_sBIT(png_ptr, info_ptr, &sig_bit);
     631             : 
     632             : #if 0
     633             :         /* Optionally write comments into the image */
     634             :         text_ptr[0].key = "Title";
     635             :         text_ptr[0].text = "Mona Lisa";
     636             :         text_ptr[0].compression = PNG_TEXT_COMPRESSION_NONE;
     637             :         text_ptr[1].key = "Author";
     638             :         text_ptr[1].text = "Leonardo DaVinci";
     639             :         text_ptr[1].compression = PNG_TEXT_COMPRESSION_NONE;
     640             :         text_ptr[2].key = "Description";
     641             :         text_ptr[2].text = "<long text>";
     642             :         text_ptr[2].compression = PNG_TEXT_COMPRESSION_zTXt;
     643             : #ifdef PNG_iTXt_SUPPORTED
     644             :         text_ptr[0].lang = NULL;
     645             :         text_ptr[1].lang = NULL;
     646             :         text_ptr[2].lang = NULL;
     647             : #endif
     648             :         png_set_text(png_ptr, info_ptr, text_ptr, 3);
     649             : #endif
     650             : 
     651           2 :         png_write_info(png_ptr, info_ptr);
     652             : 
     653             :         /* Shift the pixels up to a legal bit depth and fill in
     654             :         * as appropriate to correctly scale the image.
     655             :         */
     656           2 :         png_set_shift(png_ptr, &sig_bit);
     657             : 
     658             :         /* pack pixels into bytes */
     659           2 :         png_set_packing(png_ptr);
     660             : 
     661           2 :         if (pixel_format==GF_PIXEL_ARGB) {
     662             : //              png_set_swap_alpha(png_ptr);
     663           0 :                 png_set_bgr(png_ptr);
     664             :         }
     665           2 :         switch (pixel_format) {
     666           0 :         case GF_PIXEL_RGBX:
     667           0 :                 png_set_filler(png_ptr, 0, PNG_FILLER_AFTER);
     668           0 :                 png_set_bgr(png_ptr);
     669             :                 break;
     670           0 :         case GF_PIXEL_BGRX:
     671           0 :                 png_set_filler(png_ptr, 0, PNG_FILLER_AFTER);
     672             :                 break;
     673           0 :         case GF_PIXEL_BGR:
     674           0 :                 png_set_bgr(png_ptr);
     675             :                 break;
     676             :         }
     677           2 :         row_pointers = gf_malloc(sizeof(png_bytep)*height);
     678         400 :         for (k = 0; k < (s32)height; k++)
     679         400 :                 row_pointers[k] = (png_bytep) data + k*stride;
     680             : 
     681           2 :         png_write_image(png_ptr, row_pointers);
     682           2 :         png_write_end(png_ptr, info_ptr);
     683           2 :         gf_free(row_pointers);
     684             :         /* clean up after the write, and free any memory allocated */
     685           2 :         png_destroy_write_struct(&png_ptr, &info_ptr);
     686             : 
     687           2 :         *dst_size = udta.pos;
     688           2 :         return GF_OK;
     689             : }
     690             : 
     691             : #else
     692             : GF_EXPORT
     693             : GF_Err gf_img_png_dec(u8 *png, u32 png_size, u32 *width, u32 *height, u32 *pixel_format, u8 *dst, u32 *dst_size)
     694             : {
     695             :         return GF_NOT_SUPPORTED;
     696             : }
     697             : GF_EXPORT
     698             : GF_Err gf_img_png_enc(u8 *data, u32 width, u32 height, s32 stride, u32 pixel_format, u8 *dst, u32 *dst_size)
     699             : {
     700             :         return GF_NOT_SUPPORTED;
     701             : }
     702             : 
     703             : #endif  /*GPAC_HAS_PNG*/
     704             : 
     705             : 

Generated by: LCOV version 1.13