Просмотр исходного кода

avcodec: add PHM decoder and encoder

Paul B Mahol 2 лет назад
Родитель
Сommit
ff1450e449

+ 1 - 0
Changelog

@@ -22,6 +22,7 @@ version 5.1:
 - ffprobe -o option
 - virtualbass audio filter
 - VDPAU AV1 hwaccel
+- PHM image format support
 
 
 version 5.0:

+ 2 - 0
doc/general_contents.texi

@@ -775,6 +775,8 @@ following image formats are supported:
     @tab PGM with U and V components in YUV 4:2:0
 @item PGX          @tab   @tab X
     @tab PGX file decoder
+@item PHM          @tab X @tab X
+    @tab Portable HalfFloatMap image
 @item PIC          @tab @tab X
     @tab Pictor/PC Paint
 @item PNG          @tab X @tab X

+ 2 - 0
libavcodec/Makefile

@@ -571,6 +571,8 @@ 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_PHM_DECODER)             += pnmdec.o pnm.o
+OBJS-$(CONFIG_PHM_ENCODER)             += pnmenc.o
 OBJS-$(CONFIG_PHOTOCD_DECODER)         += photocd.o
 OBJS-$(CONFIG_PICTOR_DECODER)          += pictordec.o cga_data.o
 OBJS-$(CONFIG_PIXLET_DECODER)          += pixlet.o

+ 2 - 0
libavcodec/allcodecs.c

@@ -254,6 +254,8 @@ extern const FFCodec ff_pgm_decoder;
 extern const FFCodec ff_pgmyuv_encoder;
 extern const FFCodec ff_pgmyuv_decoder;
 extern const FFCodec ff_pgx_decoder;
+extern const FFCodec ff_phm_encoder;
+extern const FFCodec ff_phm_decoder;
 extern const FFCodec ff_photocd_decoder;
 extern const FFCodec ff_pictor_decoder;
 extern const FFCodec ff_pixlet_decoder;

+ 7 - 0
libavcodec/codec_desc.c

@@ -1886,6 +1886,13 @@ static const AVCodecDescriptor codec_descriptors[] = {
         .long_name = NULL_IF_CONFIG_SMALL("QOI (Quite OK Image)"),
         .props     = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSLESS,
     },
+    {
+        .id        = AV_CODEC_ID_PHM,
+        .type      = AVMEDIA_TYPE_VIDEO,
+        .name      = "phm",
+        .long_name = NULL_IF_CONFIG_SMALL("PHM (Portable HalfFloatMap) image"),
+        .props     = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSLESS,
+    },
 
     /* various PCM "codecs" */
     {

+ 1 - 0
libavcodec/codec_id.h

@@ -311,6 +311,7 @@ enum AVCodecID {
     AV_CODEC_ID_VBN,
     AV_CODEC_ID_JPEGXL,
     AV_CODEC_ID_QOI,
+    AV_CODEC_ID_PHM,
 
     /* various PCM "codecs" */
     AV_CODEC_ID_FIRST_AUDIO = 0x10000,     ///< A dummy id pointing at the start of audio codecs

+ 10 - 1
libavcodec/pnm.c

@@ -73,18 +73,27 @@ int ff_pnm_decode_header(AVCodecContext *avctx, PNMContext * const s)
         (s->bytestream[1] < '1' ||
          s->bytestream[1] > '7' &&
          s->bytestream[1] != 'f' &&
-         s->bytestream[1] != 'F')) {
+         s->bytestream[1] != 'F' &&
+         s->bytestream[1] != 'H' &&
+         s->bytestream[1] != 'h')) {
         s->bytestream += s->bytestream_end > s->bytestream;
         s->bytestream += s->bytestream_end > s->bytestream;
         return AVERROR_INVALIDDATA;
     }
     pnm_get(s, buf1, sizeof(buf1));
     s->type= buf1[1]-'0';
+    s->half = 0;
 
     if (buf1[1] == 'F') {
         avctx->pix_fmt = AV_PIX_FMT_GBRPF32;
     } else if (buf1[1] == 'f') {
         avctx->pix_fmt = AV_PIX_FMT_GRAYF32;
+    } else if (buf1[1] == 'H') {
+        avctx->pix_fmt = AV_PIX_FMT_GBRPF32;
+        s->half = 1;
+    } else if (buf1[1] == 'h') {
+        avctx->pix_fmt = AV_PIX_FMT_GRAYF32;
+        s->half = 1;
     } else if (s->type==1 || s->type==4) {
         avctx->pix_fmt = AV_PIX_FMT_MONOWHITE;
     } else if (s->type==2 || s->type==5) {

+ 5 - 0
libavcodec/pnm.h

@@ -31,7 +31,12 @@ typedef struct PNMContext {
     int maxval;                 ///< maximum value of a pixel
     int type;
     int endian;
+    int half;
     float scale;
+
+    uint32_t mantissatable[2048];
+    uint32_t exponenttable[64];
+    uint16_t offsettable[64];
 } PNMContext;
 
 int ff_pnm_decode_header(AVCodecContext *avctx, PNMContext * const s);

+ 4 - 1
libavcodec/pnm_parser.c

@@ -111,6 +111,8 @@ retry:
     } else {
         int ret = av_image_get_buffer_size(avctx->pix_fmt, avctx->width, avctx->height, 1);
         next = pnmctx.bytestream - pnmctx.bytestream_start + skip;
+        if (ret > 0 && pnmctx.half)
+            ret >>= 1;
         if (ret >= 0 && next + (uint64_t)ret <= INT_MAX)
             next += ret;
     }
@@ -133,7 +135,8 @@ end:
 
 const AVCodecParser ff_pnm_parser = {
     .codec_ids      = { AV_CODEC_ID_PGM, AV_CODEC_ID_PGMYUV, AV_CODEC_ID_PPM,
-                        AV_CODEC_ID_PBM, AV_CODEC_ID_PAM, AV_CODEC_ID_PFM },
+                        AV_CODEC_ID_PBM, AV_CODEC_ID_PAM, AV_CODEC_ID_PFM,
+                        AV_CODEC_ID_PHM },
     .priv_data_size = sizeof(PNMParseContext),
     .parser_parse   = pnm_parse,
     .parser_close   = ff_parse_close,

+ 114 - 0
libavcodec/pnmdec.c

@@ -26,6 +26,7 @@
 #include "internal.h"
 #include "put_bits.h"
 #include "pnm.h"
+#include "half2float.h"
 
 static void samplecpy(uint8_t *dst, const uint8_t *src, int n, int maxval)
 {
@@ -258,6 +259,7 @@ static int pnm_decode_frame(AVCodecContext *avctx, AVFrame *p,
         }
         break;
     case AV_PIX_FMT_GBRPF32:
+        if (!s->half) {
         if (avctx->width * avctx->height * 12 > s->bytestream_end - s->bytestream)
             return AVERROR_INVALIDDATA;
         scale = 1.f / s->scale;
@@ -298,8 +300,68 @@ static int pnm_decode_frame(AVCodecContext *avctx, AVFrame *p,
                 b += p->linesize[1] / 4;
             }
         }
+        } else {
+            if (avctx->width * avctx->height * 6 > s->bytestream_end - s->bytestream)
+                return AVERROR_INVALIDDATA;
+            scale = 1.f / s->scale;
+            if (s->endian) {
+                float *r, *g, *b;
+
+                r = (float *)p->data[2];
+                g = (float *)p->data[0];
+                b = (float *)p->data[1];
+                for (int i = 0; i < avctx->height; i++) {
+                    for (int j = 0; j < avctx->width; j++) {
+                        r[j] = av_int2float(half2float(AV_RL16(s->bytestream+0),
+                                                       s->mantissatable,
+                                                       s->exponenttable,
+                                                       s->offsettable)) * scale;
+                        g[j] = av_int2float(half2float(AV_RL16(s->bytestream+2),
+                                                       s->mantissatable,
+                                                       s->exponenttable,
+                                                       s->offsettable)) * scale;
+                        b[j] = av_int2float(half2float(AV_RL16(s->bytestream+4),
+                                                       s->mantissatable,
+                                                       s->exponenttable,
+                                                       s->offsettable)) * scale;
+                        s->bytestream += 6;
+                    }
+
+                    r += p->linesize[2] / 4;
+                    g += p->linesize[0] / 4;
+                    b += p->linesize[1] / 4;
+                }
+            } else {
+                float *r, *g, *b;
+
+                r = (float *)p->data[2];
+                g = (float *)p->data[0];
+                b = (float *)p->data[1];
+                for (int i = 0; i < avctx->height; i++) {
+                    for (int j = 0; j < avctx->width; j++) {
+                        r[j] = av_int2float(half2float(AV_RB16(s->bytestream+0),
+                                                       s->mantissatable,
+                                                       s->exponenttable,
+                                                       s->offsettable)) * scale;
+                        g[j] = av_int2float(half2float(AV_RB16(s->bytestream+2),
+                                                       s->mantissatable,
+                                                       s->exponenttable,
+                                                       s->offsettable)) * scale;
+                        b[j] = av_int2float(half2float(AV_RB16(s->bytestream+4),
+                                                       s->mantissatable,
+                                                       s->exponenttable,
+                                                       s->offsettable)) * scale;
+                        s->bytestream += 6;
+                    }
+
+                    r += p->linesize[2] / 4;
+                    g += p->linesize[0] / 4;
+                    b += p->linesize[1] / 4;
+                }
+            }        }
         break;
     case AV_PIX_FMT_GRAYF32:
+        if (!s->half) {
         if (avctx->width * avctx->height * 4 > s->bytestream_end - s->bytestream)
             return AVERROR_INVALIDDATA;
         scale = 1.f / s->scale;
@@ -322,6 +384,36 @@ static int pnm_decode_frame(AVCodecContext *avctx, AVFrame *p,
                 g += p->linesize[0] / 4;
             }
         }
+        } else {
+            if (avctx->width * avctx->height * 2 > s->bytestream_end - s->bytestream)
+                return AVERROR_INVALIDDATA;
+            scale = 1.f / s->scale;
+            if (s->endian) {
+                float *g = (float *)p->data[0];
+                for (int i = 0; i < avctx->height; i++) {
+                    for (int j = 0; j < avctx->width; j++) {
+                        g[j] = av_int2float(half2float(AV_RL16(s->bytestream),
+                                                       s->mantissatable,
+                                                       s->exponenttable,
+                                                       s->offsettable)) * scale;
+                        s->bytestream += 2;
+                    }
+                    g += p->linesize[0] / 4;
+                }
+            } else {
+                float *g = (float *)p->data[0];
+                for (int i = 0; i < avctx->height; i++) {
+                    for (int j = 0; j < avctx->width; j++) {
+                        g[j] = av_int2float(half2float(AV_RB16(s->bytestream),
+                                                       s->mantissatable,
+                                                       s->exponenttable,
+                                                       s->offsettable)) * scale;
+                        s->bytestream += 2;
+                    }
+                    g += p->linesize[0] / 4;
+                }
+            }
+        }
         break;
     }
     *got_frame = 1;
@@ -401,3 +493,25 @@ const FFCodec ff_pfm_decoder = {
     FF_CODEC_DECODE_CB(pnm_decode_frame),
 };
 #endif
+
+#if CONFIG_PHM_DECODER
+static av_cold int phm_dec_init(AVCodecContext *avctx)
+{
+    PNMContext *s = avctx->priv_data;
+
+    half2float_table(s->mantissatable, s->exponenttable, s->offsettable);
+
+    return 0;
+}
+
+const FFCodec ff_phm_decoder = {
+    .p.name         = "phm",
+    .p.long_name    = NULL_IF_CONFIG_SMALL("PHM (Portable HalfFloatMap) image"),
+    .p.type         = AVMEDIA_TYPE_VIDEO,
+    .p.id           = AV_CODEC_ID_PHM,
+    .p.capabilities = AV_CODEC_CAP_DR1,
+    .priv_data_size = sizeof(PNMContext),
+    .init           = phm_dec_init,
+    FF_CODEC_DECODE_CB(pnm_decode_frame),
+};
+#endif

Некоторые файлы не были показаны из-за большого количества измененных файлов