You've already forked FFmpeg
							
							
				mirror of
				https://github.com/FFmpeg/FFmpeg.git
				synced 2025-10-30 23:18:11 +02:00 
			
		
		
		
	libavcodec/pgxdec: Add PGX decoder
This patch adds a pgx decoder. Signed-off-by: Michael Niedermayer <michael@niedermayer.cc>
This commit is contained in:
		
				
					committed by
					
						 Michael Niedermayer
						Michael Niedermayer
					
				
			
			
				
	
			
			
			
						parent
						
							76a3ee996b
						
					
				
				
					commit
					cfe2cf0a63
				
			| @@ -4,6 +4,7 @@ releases are sorted from youngest to oldest. | ||||
| version <next>: | ||||
| - AudioToolbox output device | ||||
| - MacCaption demuxer | ||||
| - PGX decoder | ||||
|  | ||||
|  | ||||
| version 4.3: | ||||
|   | ||||
| @@ -751,6 +751,8 @@ following image formats are supported: | ||||
|     @tab Portable GrayMap image | ||||
| @item PGMYUV       @tab X @tab X | ||||
|     @tab PGM with U and V components in YUV 4:2:0 | ||||
| @item PGX          @tab   @tab X | ||||
|     @tab PGX file decoder | ||||
| @item PIC          @tab @tab X | ||||
|     @tab Pictor/PC Paint | ||||
| @item PNG          @tab X @tab X | ||||
|   | ||||
| @@ -536,6 +536,7 @@ OBJS-$(CONFIG_PGM_ENCODER)             += pnmenc.o | ||||
| OBJS-$(CONFIG_PGMYUV_DECODER)          += pnmdec.o pnm.o | ||||
| OBJS-$(CONFIG_PGMYUV_ENCODER)          += pnmenc.o | ||||
| OBJS-$(CONFIG_PGSSUB_DECODER)          += pgssubdec.o | ||||
| OBJS-$(CONFIG_PGX_DECODER)             += pgxdec.o | ||||
| OBJS-$(CONFIG_PICTOR_DECODER)          += pictordec.o cga_data.o | ||||
| OBJS-$(CONFIG_PIXLET_DECODER)          += pixlet.o | ||||
| OBJS-$(CONFIG_PJS_DECODER)             += textdec.o ass.o | ||||
|   | ||||
| @@ -238,6 +238,7 @@ extern AVCodec ff_pgm_encoder; | ||||
| extern AVCodec ff_pgm_decoder; | ||||
| extern AVCodec ff_pgmyuv_encoder; | ||||
| extern AVCodec ff_pgmyuv_decoder; | ||||
| extern AVCodec ff_pgx_decoder; | ||||
| extern AVCodec ff_pictor_decoder; | ||||
| extern AVCodec ff_pixlet_decoder; | ||||
| extern AVCodec ff_png_encoder; | ||||
|   | ||||
| @@ -1405,6 +1405,13 @@ static const AVCodecDescriptor codec_descriptors[] = { | ||||
|         .long_name = NULL_IF_CONFIG_SMALL("AVS2-P2/IEEE1857.4"), | ||||
|         .props     = AV_CODEC_PROP_LOSSY, | ||||
|     }, | ||||
|     { | ||||
|         .id        = AV_CODEC_ID_PGX, | ||||
|         .type      = AVMEDIA_TYPE_VIDEO, | ||||
|         .name      = "pgx", | ||||
|         .long_name = NULL_IF_CONFIG_SMALL("PGX (JPEG2000 Test Format)"), | ||||
|         .props     = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSLESS, | ||||
|     }, | ||||
|     { | ||||
|         .id        = AV_CODEC_ID_Y41P, | ||||
|         .type      = AVMEDIA_TYPE_VIDEO, | ||||
|   | ||||
| @@ -241,6 +241,7 @@ enum AVCodecID { | ||||
|     AV_CODEC_ID_SCREENPRESSO, | ||||
|     AV_CODEC_ID_RSCC, | ||||
|     AV_CODEC_ID_AVS2, | ||||
|     AV_CODEC_ID_PGX, | ||||
|  | ||||
|     AV_CODEC_ID_Y41P = 0x8000, | ||||
|     AV_CODEC_ID_AVRP, | ||||
|   | ||||
							
								
								
									
										168
									
								
								libavcodec/pgxdec.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										168
									
								
								libavcodec/pgxdec.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,168 @@ | ||||
| /* | ||||
|  * PGX image format | ||||
|  * Copyright (c) 2020 Gautam Ramakrishnan | ||||
|  * | ||||
|  * This file is part of FFmpeg. | ||||
|  * | ||||
|  * FFmpeg is free software; you can redistribute it and/or | ||||
|  * modify it under the terms of the GNU Lesser General Public | ||||
|  * License as published by the Free Software Foundation; either | ||||
|  * version 2.1 of the License, or (at your option) any later version. | ||||
|  * | ||||
|  * FFmpeg 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 | ||||
|  * Lesser General Public License for more details. | ||||
|  * | ||||
|  * You should have received a copy of the GNU Lesser General Public | ||||
|  * License along with FFmpeg; if not, write to the Free Software | ||||
|  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | ||||
|  */ | ||||
|  | ||||
| #include "avcodec.h" | ||||
| #include "internal.h" | ||||
| #include "bytestream.h" | ||||
| #include "libavutil/imgutils.h" | ||||
|  | ||||
| static int pgx_get_number(AVCodecContext *avctx, GetByteContext *g, int *number) { | ||||
|     int ret = AVERROR_INVALIDDATA; | ||||
|     char digit; | ||||
|  | ||||
|     *number = 0; | ||||
|     while (1) { | ||||
|         uint64_t temp; | ||||
|         if (!bytestream2_get_bytes_left(g)) | ||||
|             return AVERROR_INVALIDDATA; | ||||
|         digit = bytestream2_get_byte(g); | ||||
|         if (digit == ' ' || digit == 0xA || digit == 0xD) | ||||
|             break; | ||||
|         else if (digit < '0' || digit > '9') | ||||
|             return AVERROR_INVALIDDATA; | ||||
|  | ||||
|         temp = (uint64_t)10 * (*number) + (digit - '0'); | ||||
|         if (temp > INT_MAX) | ||||
|             return AVERROR_INVALIDDATA; | ||||
|         *number = temp; | ||||
|         ret = 0; | ||||
|     } | ||||
|  | ||||
|     return ret; | ||||
| } | ||||
|  | ||||
| static int pgx_decode_header(AVCodecContext *avctx, GetByteContext *g, | ||||
|                              int *depth, int *width, int *height, | ||||
|                              int *sign) | ||||
| { | ||||
|     int byte; | ||||
|  | ||||
|     if (bytestream2_get_bytes_left(g) < 6) { | ||||
|         return AVERROR_INVALIDDATA; | ||||
|     } | ||||
|  | ||||
|     bytestream2_skip(g, 6); | ||||
|  | ||||
|     // Is the component signed? | ||||
|     byte = bytestream2_peek_byte(g); | ||||
|     if (byte == '+') { | ||||
|         *sign = 0; | ||||
|         bytestream2_skip(g, 1); | ||||
|     } else if (byte == '-') { | ||||
|         *sign = 1; | ||||
|         bytestream2_skip(g, 1); | ||||
|     } else if (byte == 0) | ||||
|         goto error; | ||||
|  | ||||
|     byte = bytestream2_peek_byte(g); | ||||
|     if (byte == ' ') | ||||
|         bytestream2_skip(g, 1); | ||||
|     else if (byte == 0) | ||||
|         goto error; | ||||
|  | ||||
|     if (pgx_get_number(avctx, g, depth)) | ||||
|         goto error; | ||||
|     if (pgx_get_number(avctx, g, width)) | ||||
|         goto error; | ||||
|     if (pgx_get_number(avctx, g, height)) | ||||
|         goto error; | ||||
|  | ||||
|     if (bytestream2_peek_byte(g) == 0xA) | ||||
|         bytestream2_skip(g, 1); | ||||
|     return 0; | ||||
|  | ||||
| error: | ||||
|     av_log(avctx, AV_LOG_ERROR, "Error in decoding header.\n"); | ||||
|     return AVERROR_INVALIDDATA; | ||||
| } | ||||
|  | ||||
| #define WRITE_FRAME(D, PIXEL, suffix)                                                       \ | ||||
|     static inline void write_frame_ ##D(AVPacket *avpkt, AVFrame *frame, GetByteContext *g, \ | ||||
|                                         int width, int height, int sign, int depth)         \ | ||||
|     {                                                                                       \ | ||||
|         int i, j;                                                                           \ | ||||
|         for (i = 0; i < height; i++) {                                                      \ | ||||
|             PIXEL *line = (PIXEL*)frame->data[0] + i*frame->linesize[0]/sizeof(PIXEL);      \ | ||||
|             for (j = 0; j < width; j++) {                                                   \ | ||||
|                 int val;                                                                    \ | ||||
|                 if (sign)                                                                   \ | ||||
|                     val = (PIXEL)bytestream2_get_ ##suffix(g) + (1 << (depth - 1));         \ | ||||
|                 else                                                                        \ | ||||
|                     val = bytestream2_get_ ##suffix(g);                                     \ | ||||
|                 val <<= (D - depth);                                                        \ | ||||
|                 *(line + j) = val;                                                          \ | ||||
|             }                                                                               \ | ||||
|         }                                                                                   \ | ||||
|     }                                                                                       \ | ||||
|  | ||||
| WRITE_FRAME(8, int8_t, byte) | ||||
| WRITE_FRAME(16, int16_t, be16) | ||||
|  | ||||
| static int pgx_decode_frame(AVCodecContext *avctx, void *data, | ||||
|                             int *got_frame, AVPacket *avpkt) | ||||
| { | ||||
|     AVFrame *p = data; | ||||
|     int ret; | ||||
|     int bpp; | ||||
|     int width, height, depth; | ||||
|     int sign = 0; | ||||
|     GetByteContext g; | ||||
|     bytestream2_init(&g, avpkt->data, avpkt->size); | ||||
|  | ||||
|     if ((ret = pgx_decode_header(avctx, &g, &depth, &width, &height, &sign)) < 0) | ||||
|         return ret; | ||||
|  | ||||
|     if ((ret = ff_set_dimensions(avctx, width, height)) < 0) | ||||
|         return ret; | ||||
|  | ||||
|     if (depth <= 8) { | ||||
|         avctx->pix_fmt = AV_PIX_FMT_GRAY8; | ||||
|         bpp = 8; | ||||
|     } else if (depth <= 16) { | ||||
|         avctx->pix_fmt = AV_PIX_FMT_GRAY16BE; | ||||
|         bpp = 16; | ||||
|     } else { | ||||
|         av_log(avctx, AV_LOG_ERROR, "Maximum depth of 16 bits supported.\n"); | ||||
|         return AVERROR_PATCHWELCOME; | ||||
|     } | ||||
|     if (bytestream2_get_bytes_left(&g) < width * height * (bpp >> 3)) | ||||
|         return AVERROR_INVALIDDATA; | ||||
|     if ((ret = ff_get_buffer(avctx, p, 0)) < 0) | ||||
|         return ret; | ||||
|     p->pict_type = AV_PICTURE_TYPE_I; | ||||
|     p->key_frame = 1; | ||||
|     avctx->bits_per_raw_sample = depth; | ||||
|     if (bpp == 8) | ||||
|         write_frame_8(avpkt, p, &g, width, height, sign, depth); | ||||
|     else if (bpp == 16) | ||||
|         write_frame_16(avpkt, p, &g, width, height, sign, depth); | ||||
|     *got_frame = 1; | ||||
|     return 0; | ||||
| } | ||||
|  | ||||
| AVCodec ff_pgx_decoder = { | ||||
|     .name           = "pgx", | ||||
|     .long_name      = NULL_IF_CONFIG_SMALL("PGX (JPEG2000 Test Format)"), | ||||
|     .type           = AVMEDIA_TYPE_VIDEO, | ||||
|     .id             = AV_CODEC_ID_PGX, | ||||
|     .decode         = pgx_decode_frame, | ||||
|     .capabilities   = AV_CODEC_CAP_DR1, | ||||
| }; | ||||
| @@ -28,8 +28,8 @@ | ||||
| #include "libavutil/version.h" | ||||
|  | ||||
| #define LIBAVCODEC_VERSION_MAJOR  58 | ||||
| #define LIBAVCODEC_VERSION_MINOR  93 | ||||
| #define LIBAVCODEC_VERSION_MICRO 104 | ||||
| #define LIBAVCODEC_VERSION_MINOR  94 | ||||
| #define LIBAVCODEC_VERSION_MICRO 100 | ||||
|  | ||||
| #define LIBAVCODEC_VERSION_INT  AV_VERSION_INT(LIBAVCODEC_VERSION_MAJOR, \ | ||||
|                                                LIBAVCODEC_VERSION_MINOR, \ | ||||
|   | ||||
		Reference in New Issue
	
	Block a user