Unified · Split
| @@ -18,6 +18,7 @@ version 5.1: · 17 unmodified lines | |||
| 18 | - PGS subtitle frame merge bitstream filter | 18 | - PGS subtitle frame merge bitstream filter |
| 19 | - blurdetect filter | 19 | - blurdetect filter |
| 20 | - tiltshelf audio filter | 20 | - tiltshelf audio filter |
| 21 | - QOI image format support | ||
| 21 | 22 | ||
| 22 | 23 | ||
| 23 | version 5.0: | 24 | version 5.0: |
| @@ -593,6 +593,8 @@ OBJS-$(CONFIG_QCELP_DECODER) += qcelpdec.o \ · 592 unmodified lines | |||
| 593 | OBJS-$(CONFIG_QDM2_DECODER) += qdm2.o | 593 | OBJS-$(CONFIG_QDM2_DECODER) += qdm2.o |
| 594 | OBJS-$(CONFIG_QDMC_DECODER) += qdmc.o | 594 | OBJS-$(CONFIG_QDMC_DECODER) += qdmc.o |
| 595 | OBJS-$(CONFIG_QDRAW_DECODER) += qdrw.o | 595 | OBJS-$(CONFIG_QDRAW_DECODER) += qdrw.o |
| 596 | OBJS-$(CONFIG_QOI_DECODER) += qoidec.o | ||
| 597 | OBJS-$(CONFIG_QOI_ENCODER) += qoienc.o | ||
| 596 | OBJS-$(CONFIG_QPEG_DECODER) += qpeg.o | 598 | OBJS-$(CONFIG_QPEG_DECODER) += qpeg.o |
| 597 | OBJS-$(CONFIG_QTRLE_DECODER) += qtrle.o | 599 | OBJS-$(CONFIG_QTRLE_DECODER) += qtrle.o |
| 598 | OBJS-$(CONFIG_QTRLE_ENCODER) += qtrleenc.o | 600 | OBJS-$(CONFIG_QTRLE_ENCODER) += qtrleenc.o |
| @@ -1151,6 +1153,7 @@ OBJS-$(CONFIG_OPUS_PARSER) += opus_parser.o opus.o opustab.o \ · 552 unmodified lines | |||
| 1151 | opus_rc.o vorbis_data.o | 1153 | opus_rc.o vorbis_data.o |
| 1152 | OBJS-$(CONFIG_PNG_PARSER) += png_parser.o | 1154 | OBJS-$(CONFIG_PNG_PARSER) += png_parser.o |
| 1153 | OBJS-$(CONFIG_PNM_PARSER) += pnm_parser.o pnm.o | 1155 | OBJS-$(CONFIG_PNM_PARSER) += pnm_parser.o pnm.o |
| 1156 | OBJS-$(CONFIG_QOI_PARSER) += qoi_parser.o | ||
| 1154 | OBJS-$(CONFIG_RV30_PARSER) += rv34_parser.o | 1157 | OBJS-$(CONFIG_RV30_PARSER) += rv34_parser.o |
| 1155 | OBJS-$(CONFIG_RV40_PARSER) += rv34_parser.o | 1158 | OBJS-$(CONFIG_RV40_PARSER) += rv34_parser.o |
| 1156 | OBJS-$(CONFIG_SBC_PARSER) += sbc_parser.o | 1159 | OBJS-$(CONFIG_SBC_PARSER) += sbc_parser.o |
| @@ -269,6 +269,8 @@ extern const FFCodec ff_prosumer_decoder; · 268 unmodified lines | |||
| 269 | extern const FFCodec ff_psd_decoder; | 269 | extern const FFCodec ff_psd_decoder; |
| 270 | extern const FFCodec ff_ptx_decoder; | 270 | extern const FFCodec ff_ptx_decoder; |
| 271 | extern const FFCodec ff_qdraw_decoder; | 271 | extern const FFCodec ff_qdraw_decoder; |
| 272 | extern const FFCodec ff_qoi_encoder; | ||
| 273 | extern const FFCodec ff_qoi_decoder; | ||
| 272 | extern const FFCodec ff_qpeg_decoder; | 274 | extern const FFCodec ff_qpeg_decoder; |
| 273 | extern const FFCodec ff_qtrle_encoder; | 275 | extern const FFCodec ff_qtrle_encoder; |
| 274 | extern const FFCodec ff_qtrle_decoder; | 276 | extern const FFCodec ff_qtrle_decoder; |
| @@ -1879,6 +1879,13 @@ static const AVCodecDescriptor codec_descriptors[] = { · 1878 unmodified lines | |||
| 1879 | AV_CODEC_PROP_LOSSLESS, | 1879 | AV_CODEC_PROP_LOSSLESS, |
| 1880 | .mime_types= MT("image/jxl"), | 1880 | .mime_types= MT("image/jxl"), |
| 1881 | }, | 1881 | }, |
| 1882 | { | ||
| 1883 | .id = AV_CODEC_ID_QOI, | ||
| 1884 | .type = AVMEDIA_TYPE_VIDEO, | ||
| 1885 | .name = "qoi", | ||
| 1886 | .long_name = NULL_IF_CONFIG_SMALL("QOI (Quite OK Image)"), | ||
| 1887 | .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSLESS, | ||
| 1888 | }, | ||
| 1882 | 1889 | ||
| 1883 | /* various PCM "codecs" */ | 1890 | /* various PCM "codecs" */ |
| 1884 | { | 1891 | { |
| @@ -310,6 +310,7 @@ enum AVCodecID { · 309 unmodified lines | |||
| 310 | AV_CODEC_ID_GEM, | 310 | AV_CODEC_ID_GEM, |
| 311 | AV_CODEC_ID_VBN, | 311 | AV_CODEC_ID_VBN, |
| 312 | AV_CODEC_ID_JPEGXL, | 312 | AV_CODEC_ID_JPEGXL, |
| 313 | AV_CODEC_ID_QOI, | ||
| 313 | 314 | ||
| 314 | /* various PCM "codecs" */ | 315 | /* various PCM "codecs" */ |
| 315 | AV_CODEC_ID_FIRST_AUDIO = 0x10000, ///< A dummy id pointing at the start of audio codecs | 316 | AV_CODEC_ID_FIRST_AUDIO = 0x10000, ///< A dummy id pointing at the start of audio codecs |
| @@ -60,6 +60,7 @@ extern const AVCodecParser ff_mpegvideo_parser; · 59 unmodified lines | |||
| 60 | extern const AVCodecParser ff_opus_parser; | 60 | extern const AVCodecParser ff_opus_parser; |
| 61 | extern const AVCodecParser ff_png_parser; | 61 | extern const AVCodecParser ff_png_parser; |
| 62 | extern const AVCodecParser ff_pnm_parser; | 62 | extern const AVCodecParser ff_pnm_parser; |
| 63 | extern const AVCodecParser ff_qoi_parser; | ||
| 63 | extern const AVCodecParser ff_rv30_parser; | 64 | extern const AVCodecParser ff_rv30_parser; |
| 64 | extern const AVCodecParser ff_rv40_parser; | 65 | extern const AVCodecParser ff_rv40_parser; |
| 65 | extern const AVCodecParser ff_sbc_parser; | 66 | extern const AVCodecParser ff_sbc_parser; |
| @@ -0,0 +1,35 @@ | |||
| 1 | /* | ||
| 2 | * QOI image format | ||
| 3 | * | ||
| 4 | * This file is part of FFmpeg. | ||
| 5 | * | ||
| 6 | * FFmpeg is free software; you can redistribute it and/or | ||
| 7 | * modify it under the terms of the GNU Lesser General Public | ||
| 8 | * License as published by the Free Software Foundation; either | ||
| 9 | * version 2.1 of the License, or (at your option) any later version. | ||
| 10 | * | ||
| 11 | * FFmpeg is distributed in the hope that it will be useful, | ||
| 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
| 14 | * Lesser General Public License for more details. | ||
| 15 | * | ||
| 16 | * You should have received a copy of the GNU Lesser General Public | ||
| 17 | * License along with FFmpeg; if not, write to the Free Software | ||
| 18 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | ||
| 19 | */ | ||
| 20 | |||
| 21 | #ifndef AVCODEC_QOI_H | ||
| 22 | #define AVCODEC_QOI_H | ||
| 23 | |||
| 24 | #define QOI_OP_INDEX 0x00 /* 00xxxxxx */ | ||
| 25 | #define QOI_OP_DIFF 0x40 /* 01xxxxxx */ | ||
| 26 | #define QOI_OP_LUMA 0x80 /* 10xxxxxx */ | ||
| 27 | #define QOI_OP_RUN 0xc0 /* 11xxxxxx */ | ||
| 28 | #define QOI_OP_RGB 0xfe /* 11111110 */ | ||
| 29 | #define QOI_OP_RGBA 0xff /* 11111111 */ | ||
| 30 | |||
| 31 | #define QOI_MASK_2 0xc0 /* 11000000 */ | ||
| 32 | |||
| 33 | #define QOI_COLOR_HASH(px) (px[0]*3 + px[1]*5 + px[2]*7 + px[3]*11) | ||
| 34 | |||
| 35 | #endif /* AVCODEC_QOI_H */ | ||
| @@ -0,0 +1,77 @@ | |||
| 1 | /* | ||
| 2 | * QOI parser | ||
| 3 | * Copyright (c) 2022 Paul B Mahol | ||
| 4 | * | ||
| 5 | * This file is part of FFmpeg. | ||
| 6 | * | ||
| 7 | * FFmpeg is free software; you can redistribute it and/or | ||
| 8 | * modify it under the terms of the GNU Lesser General Public | ||
| 9 | * License as published by the Free Software Foundation; either | ||
| 10 | * version 2.1 of the License, or (at your option) any later version. | ||
| 11 | * | ||
| 12 | * FFmpeg is distributed in the hope that it will be useful, | ||
| 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
| 15 | * Lesser General Public License for more details. | ||
| 16 | * | ||
| 17 | * You should have received a copy of the GNU Lesser General Public | ||
| 18 | * License along with FFmpeg; if not, write to the Free Software | ||
| 19 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | ||
| 20 | */ | ||
| 21 | |||
| 22 | /** | ||
| 23 | * @file | ||
| 24 | * QOI parser | ||
| 25 | */ | ||
| 26 | |||
| 27 | #include "parser.h" | ||
| 28 | |||
| 29 | typedef struct QOIParseContext { | ||
| 30 | ParseContext pc; | ||
| 31 | } QOIParseContext; | ||
| 32 | |||
| 33 | static int qoi_parse(AVCodecParserContext *s, AVCodecContext *avctx, | ||
| 34 | const uint8_t **poutbuf, int *poutbuf_size, | ||
| 35 | const uint8_t *buf, int buf_size) | ||
| 36 | { | ||
| 37 | QOIParseContext *ipc = s->priv_data; | ||
| 38 | uint64_t state = ipc->pc.state64; | ||
| 39 | int next = END_NOT_FOUND, i = 0; | ||
| 40 | |||
| 41 | s->pict_type = AV_PICTURE_TYPE_NONE; | ||
| 42 | s->duration = 1; | ||
| 43 | |||
| 44 | *poutbuf_size = 0; | ||
| 45 | *poutbuf = NULL; | ||
| 46 | |||
| 47 | if (s->flags & PARSER_FLAG_COMPLETE_FRAMES) { | ||
| 48 | next = buf_size; | ||
| 49 | } else { | ||
| 50 | for (; i < buf_size; i++) { | ||
| 51 | state = (state << 8) | buf[i]; | ||
| 52 | if (state == 0x01LL) { | ||
| 53 | next = i + 1; | ||
| 54 | break; | ||
| 55 | } | ||
| 56 | } | ||
| 57 | |||
| 58 | ipc->pc.state64 = state; | ||
| 59 | if (ff_combine_frame(&ipc->pc, next, &buf, &buf_size) < 0) { | ||
| 60 | *poutbuf = NULL; | ||
| 61 | *poutbuf_size = 0; | ||
| 62 | return buf_size; | ||
| 63 | } | ||
| 64 | } | ||
| 65 | |||
| 66 | *poutbuf = buf; | ||
| 67 | *poutbuf_size = buf_size; | ||
| 68 | |||
| 69 | return next; | ||
| 70 | } | ||
| 71 | |||
| 72 | const AVCodecParser ff_qoi_parser = { | ||
| 73 | .codec_ids = { AV_CODEC_ID_QOI }, | ||
| 74 | .priv_data_size = sizeof(QOIParseContext), | ||
| 75 | .parser_parse = qoi_parse, | ||
| 76 | .parser_close = ff_parse_close, | ||
| 77 | }; | ||
| @@ -0,0 +1,126 @@ | |||
| 1 | /* | ||
| 2 | * QOI image format | ||
| 3 | * | ||
| 4 | * This file is part of FFmpeg. | ||
| 5 | * | ||
| 6 | * FFmpeg is free software; you can redistribute it and/or | ||
| 7 | * modify it under the terms of the GNU Lesser General Public | ||
| 8 | * License as published by the Free Software Foundation; either | ||
| 9 | * version 2.1 of the License, or (at your option) any later version. | ||
| 10 | * | ||
| 11 | * FFmpeg is distributed in the hope that it will be useful, | ||
| 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
| 14 | * Lesser General Public License for more details. | ||
| 15 | * | ||
| 16 | * You should have received a copy of the GNU Lesser General Public | ||
| 17 | * License along with FFmpeg; if not, write to the Free Software | ||
| 18 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | ||
| 19 | */ | ||
| 20 | |||
| 21 | #include <stdlib.h> | ||
| 22 | |||
| 23 | #include "libavutil/imgutils.h" | ||
| 24 | #include "avcodec.h" | ||
| 25 | #include "internal.h" | ||
| 26 | #include "bytestream.h" | ||
| 27 | #include "codec_internal.h" | ||
| 28 | #include "thread.h" | ||
| 29 | #include "qoi.h" | ||
| 30 | |||
| 31 | static int qoi_decode_frame(AVCodecContext *avctx, AVFrame *p, | ||
| 32 | int *got_frame, AVPacket *avpkt) | ||
| 33 | { | ||
| 34 | const uint8_t *buf = avpkt->data; | ||
| 35 | int ret, buf_size = avpkt->size; | ||
| 36 | int width, height, channels, space, run = 0; | ||
| 37 | uint8_t index[64][4] = { 0 }; | ||
| 38 | uint8_t px[4] = { 0, 0, 0, 255 }; | ||
| 39 | GetByteContext gb; | ||
| 40 | uint8_t *dst; | ||
| 41 | uint64_t len; | ||
| 42 | |||
| 43 | if (buf_size < 20) | ||
| 44 | return AVERROR_INVALIDDATA; | ||
| 45 | |||
| 46 | bytestream2_init(&gb, buf, buf_size); | ||
| 47 | bytestream2_skip(&gb, 4); | ||
| 48 | width = bytestream2_get_be32(&gb); | ||
| 49 | height = bytestream2_get_be32(&gb); | ||
| 50 | channels = bytestream2_get_byte(&gb); | ||
| 51 | space = bytestream2_get_byte(&gb); | ||
| 52 | switch (space) { | ||
| 53 | case 0: break; | ||
| 54 | case 1: avctx->color_trc = AVCOL_TRC_LINEAR; break; | ||
| 55 | default: return AVERROR_INVALIDDATA; | ||
| 56 | } | ||
| 57 | |||
| 58 | if ((ret = ff_set_dimensions(avctx, width, height)) < 0) | ||
| 59 | return ret; | ||
| 60 | |||
| 61 | switch (channels) { | ||
| 62 | case 3: avctx->pix_fmt = AV_PIX_FMT_RGB24; break; | ||
| 63 | case 4: avctx->pix_fmt = AV_PIX_FMT_RGBA; break; | ||
| 64 | default: return AVERROR_INVALIDDATA; | ||
| 65 | } | ||
| 66 | |||
| 67 | if ((ret = ff_thread_get_buffer(avctx, p, 0)) < 0) | ||
| 68 | return ret; | ||
| 69 | |||
| 70 | dst = p->data[0]; | ||
| 71 | len = width * height * channels; | ||
| 72 | for (int n = 0, off_x = 0, off_y = 0; n < len; n += channels, off_x++) { | ||
| 73 | if (off_x >= width) { | ||
| 74 | off_x = 0; | ||
| 75 | off_y++; | ||
| 76 | dst += p->linesize[0]; | ||
| 77 | } | ||
| 78 | if (run > 0) { | ||
| 79 | run--; | ||
| 80 | } else if (bytestream2_get_bytes_left(&gb) > 4) { | ||
| 81 | int chunk = bytestream2_get_byteu(&gb); | ||
| 82 | |||
| 83 | if (chunk == QOI_OP_RGB) { | ||
| 84 | bytestream2_get_bufferu(&gb, px, 3); | ||
| 85 | } else if (chunk == QOI_OP_RGBA) { | ||
| 86 | bytestream2_get_bufferu(&gb, px, 4); | ||
| 87 | } else if ((chunk & QOI_MASK_2) == QOI_OP_INDEX) { | ||
| 88 | memcpy(px, index[chunk], 4); | ||
| 89 | } else if ((chunk & QOI_MASK_2) == QOI_OP_DIFF) { | ||
| 90 | px[0] += ((chunk >> 4) & 0x03) - 2; | ||
| 91 | px[1] += ((chunk >> 2) & 0x03) - 2; | ||
| 92 | px[2] += ( chunk & 0x03) - 2; | ||
| 93 | } else if ((chunk & QOI_MASK_2) == QOI_OP_LUMA) { | ||
| 94 | int b2 = bytestream2_get_byteu(&gb); | ||
| 95 | int vg = (chunk & 0x3f) - 32; | ||
| 96 | px[0] += vg - 8 + ((b2 >> 4) & 0x0f); | ||
| 97 | px[1] += vg; | ||
| 98 | px[2] += vg - 8 + (b2 & 0x0f); | ||
| 99 | } else if ((chunk & QOI_MASK_2) == QOI_OP_RUN) { | ||
| 100 | run = chunk & 0x3f; | ||
| 101 | } | ||
| 102 | |||
| 103 | memcpy(index[QOI_COLOR_HASH(px) & 63], px, 4); | ||
| 104 | } else { | ||
| 105 | break; | ||
| 106 | } | ||
| 107 | |||
| 108 | memcpy(&dst[off_x * channels], px, channels); | ||
| 109 | } | ||
| 110 | |||
| 111 | p->key_frame = 1; | ||
| 112 | p->pict_type = AV_PICTURE_TYPE_I; | ||
| 113 | |||
| 114 | *got_frame = 1; | ||
| 115 | |||
| 116 | return buf_size; | ||
| 117 | } | ||
| 118 | |||
| 119 | const FFCodec ff_qoi_decoder = { | ||
| 120 | .p.name = "qoi", | ||
| 121 | .p.long_name = NULL_IF_CONFIG_SMALL("QOI (Quite OK Image format) image"), | ||
| 122 | .p.type = AVMEDIA_TYPE_VIDEO, | ||
| 123 | .p.id = AV_CODEC_ID_QOI, | ||
| 124 | .p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_FRAME_THREADS, | ||
| 125 | FF_CODEC_DECODE_CB(qoi_decode_frame), | ||
| 126 | }; | ||
| @@ -0,0 +1,140 @@ | |||
| 1 | /* | ||
| 2 | * QOI image format encoder | ||
| 3 | * | ||
| 4 | * This file is part of FFmpeg. | ||
| 5 | * | ||
| 6 | * FFmpeg is free software; you can redistribute it and/or | ||
| 7 | * modify it under the terms of the GNU Lesser General Public | ||
| 8 | * License as published by the Free Software Foundation; either | ||
| 9 | * version 2.1 of the License, or (at your option) any later version. | ||
| 10 | * | ||
| 11 | * FFmpeg is distributed in the hope that it will be useful, | ||
| 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
| 14 | * Lesser General Public License for more details. | ||
| 15 | * | ||
| 16 | * You should have received a copy of the GNU Lesser General Public | ||
| 17 | * License along with FFmpeg; if not, write to the Free Software | ||
| 18 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | ||
| 19 | */ | ||
| 20 | |||
| 21 | #include "libavutil/imgutils.h" | ||
| 22 | #include "avcodec.h" | ||
| 23 | #include "bytestream.h" | ||
| 24 | #include "codec_internal.h" | ||
| 25 | #include "encode.h" | ||
| 26 | #include "qoi.h" | ||
| 27 | |||
| 28 | static int qoi_encode_frame(AVCodecContext *avctx, AVPacket *pkt, | ||
| 29 | const AVFrame *pict, int *got_packet) | ||
| 30 | { | ||
| 31 | const int channels = 3 + (avctx->pix_fmt == AV_PIX_FMT_RGBA); | ||
| 32 | uint8_t px_prev[4] = { 0, 0, 0, 255 }; | ||
| 33 | uint8_t px[4] = { 0, 0, 0, 255 }; | ||
| 34 | uint8_t index[64][4] = { 0 }; | ||
| 35 | int64_t packet_size; | ||
| 36 | uint8_t *buf, *src; | ||
| 37 | int ret, run = 0; | ||
| 38 | |||
| 39 | packet_size = avctx->width * avctx->height * (channels + 1LL) + 14LL + 8LL; | ||
| 40 | if ((ret = ff_alloc_packet(avctx, pkt, packet_size)) < 0) | ||
| 41 | return ret; | ||
| 42 | |||
| 43 | buf = pkt->data; | ||
| 44 | src = pict->data[0]; | ||
| 45 | |||
| 46 | bytestream_put_buffer(&buf, "qoif", 4); | ||
| 47 | bytestream_put_be32(&buf, avctx->width); | ||
| 48 | bytestream_put_be32(&buf, avctx->height); | ||
| 49 | bytestream_put_byte(&buf, channels); | ||
| 50 | bytestream_put_byte(&buf, avctx->color_trc == AVCOL_TRC_LINEAR); | ||
| 51 | |||
| 52 | for (int y = 0; y < avctx->height; y++) { | ||
| 53 | for (int x = 0; x < avctx->width; x++) { | ||
| 54 | memcpy(px, src + x * channels, channels); | ||
| 55 | |||
| 56 | if (!memcmp(px, px_prev, 4)) { | ||
| 57 | run++; | ||
| 58 | if (run == 62) { | ||
| 59 | bytestream_put_byte(&buf, QOI_OP_RUN | (run - 1)); | ||
| 60 | run = 0; | ||
| 61 | } | ||
| 62 | } else { | ||
| 63 | int index_pos; | ||
| 64 | |||
| 65 | if (run > 0) { | ||
| 66 | bytestream_put_byte(&buf, QOI_OP_RUN | (run - 1)); | ||
| 67 | run = 0; | ||
| 68 | } | ||
| 69 | |||
| 70 | index_pos = QOI_COLOR_HASH(px) & 63; | ||
| 71 | |||
| 72 | if (!memcmp(index[index_pos], px, 4)) { | ||
| 73 | bytestream_put_byte(&buf, QOI_OP_INDEX | index_pos); | ||
| 74 | } else { | ||
| 75 | memcpy(index[index_pos], px, 4); | ||
| 76 | |||
| 77 | if (px[3] == px_prev[3]) { | ||
| 78 | int8_t vr = px[0] - px_prev[0]; | ||
| 79 | int8_t vg = px[1] - px_prev[1]; | ||
| 80 | int8_t vb = px[2] - px_prev[2]; | ||
| 81 | |||
| 82 | int8_t vg_r = vr - vg; | ||
| 83 | int8_t vg_b = vb - vg; | ||
| 84 | |||
| 85 | if (vr > -3 && vr < 2 && | ||
| 86 | vg > -3 && vg < 2 && | ||
| 87 | vb > -3 && vb < 2) { | ||
| 88 | bytestream_put_byte(&buf, QOI_OP_DIFF | (vr + 2) << 4 | (vg + 2) << 2 | (vb + 2)); | ||
| 89 | } else if (vg_r > -9 && vg_r < 8 && | ||
| 90 | vg > -33 && vg < 32 && | ||
| 91 | vg_b > -9 && vg_b < 8) { | ||
| 92 | bytestream_put_byte(&buf, QOI_OP_LUMA | (vg + 32)); | ||
| 93 | bytestream_put_byte(&buf, (vg_r + 8) << 4 | (vg_b + 8)); | ||
| 94 | } else { | ||
| 95 | bytestream_put_byte(&buf, QOI_OP_RGB); | ||
| 96 | bytestream_put_byte(&buf, px[0]); | ||
| 97 | bytestream_put_byte(&buf, px[1]); | ||
| 98 | bytestream_put_byte(&buf, px[2]); | ||
| 99 | } | ||
| 100 | } else { | ||
| 101 | bytestream_put_byte(&buf, QOI_OP_RGBA); | ||
| 102 | bytestream_put_byte(&buf, px[0]); | ||
| 103 | bytestream_put_byte(&buf, px[1]); | ||
| 104 | bytestream_put_byte(&buf, px[2]); | ||
| 105 | bytestream_put_byte(&buf, px[3]); | ||
| 106 | } | ||
| 107 | } | ||
| 108 | } | ||
| 109 | |||
| 110 | memcpy(px_prev, px, 4); | ||
| 111 | } | ||
| 112 | |||
| 113 | src += pict->linesize[0]; | ||
| 114 | } | ||
| 115 | |||
| 116 | if (run) | ||
| 117 | bytestream_put_byte(&buf, QOI_OP_RUN | (run - 1)); | ||
| 118 | |||
| 119 | bytestream_put_be64(&buf, 0x01); | ||
| 120 | |||
| 121 | pkt->size = buf - pkt->data; | ||
| 122 | |||
| 123 | *got_packet = 1; | ||
| 124 | |||
| 125 | return 0; | ||
| 126 | } | ||
| 127 | |||
| 128 | const FFCodec ff_qoi_encoder = { | ||
| 129 | .p.name = "qoi", | ||
| 130 | .p.long_name = NULL_IF_CONFIG_SMALL("QOI (Quite OK Image format) image"), | ||
| 131 | .p.type = AVMEDIA_TYPE_VIDEO, | ||
| 132 | .p.id = AV_CODEC_ID_QOI, | ||
| 133 | .p.capabilities = AV_CODEC_CAP_FRAME_THREADS, | ||
| 134 | FF_CODEC_ENCODE_CB(qoi_encode_frame), | ||
| 135 | .p.pix_fmts = (const enum AVPixelFormat[]){ | ||
| 136 | AV_PIX_FMT_RGBA, AV_PIX_FMT_RGB24, | ||
| 137 | AV_PIX_FMT_NONE | ||
| 138 | }, | ||
| 139 | .caps_internal = FF_CODEC_CAP_INIT_THREADSAFE, | ||
| 140 | }; | ||
| @@ -29,8 +29,8 @@ · 28 unmodified lines | |||
| 29 | 29 | ||
| 30 | #include "version_major.h" | 30 | #include "version_major.h" |
| 31 | 31 | ||
| 32 | #define LIBAVCODEC_VERSION_MINOR 32 | 32 | #define LIBAVCODEC_VERSION_MINOR 33 |
| 33 | #define LIBAVCODEC_VERSION_MICRO 102 | 33 | #define LIBAVCODEC_VERSION_MICRO 100 |
| 34 | 34 | ||
| 35 | #define LIBAVCODEC_VERSION_INT AV_VERSION_INT(LIBAVCODEC_VERSION_MAJOR, \ | 35 | #define LIBAVCODEC_VERSION_INT AV_VERSION_INT(LIBAVCODEC_VERSION_MAJOR, \ |
| 36 | LIBAVCODEC_VERSION_MINOR, \ | 36 | LIBAVCODEC_VERSION_MINOR, \ |
| @@ -289,6 +289,7 @@ OBJS-$(CONFIG_IMAGE_PNG_PIPE_DEMUXER) += img2dec.o img2.o · 288 unmodified lines | |||
| 289 | OBJS-$(CONFIG_IMAGE_PPM_PIPE_DEMUXER) += img2dec.o img2.o | 289 | OBJS-$(CONFIG_IMAGE_PPM_PIPE_DEMUXER) += img2dec.o img2.o |
| 290 | OBJS-$(CONFIG_IMAGE_PSD_PIPE_DEMUXER) += img2dec.o img2.o | 290 | OBJS-$(CONFIG_IMAGE_PSD_PIPE_DEMUXER) += img2dec.o img2.o |
| 291 | OBJS-$(CONFIG_IMAGE_QDRAW_PIPE_DEMUXER) += img2dec.o img2.o | 291 | OBJS-$(CONFIG_IMAGE_QDRAW_PIPE_DEMUXER) += img2dec.o img2.o |
| 292 | OBJS-$(CONFIG_IMAGE_QOI_PIPE_DEMUXER) += img2dec.o img2.o | ||
| 292 | OBJS-$(CONFIG_IMAGE_SGI_PIPE_DEMUXER) += img2dec.o img2.o | 293 | OBJS-$(CONFIG_IMAGE_SGI_PIPE_DEMUXER) += img2dec.o img2.o |
| 293 | OBJS-$(CONFIG_IMAGE_SVG_PIPE_DEMUXER) += img2dec.o img2.o | 294 | OBJS-$(CONFIG_IMAGE_SVG_PIPE_DEMUXER) += img2dec.o img2.o |
| 294 | OBJS-$(CONFIG_IMAGE_SUNRAST_PIPE_DEMUXER) += img2dec.o img2.o | 295 | OBJS-$(CONFIG_IMAGE_SUNRAST_PIPE_DEMUXER) += img2dec.o img2.o |
| @@ -524,6 +524,7 @@ extern const AVInputFormat ff_image_png_pipe_demuxer; · 523 unmodified lines | |||
| 524 | extern const AVInputFormat ff_image_ppm_pipe_demuxer; | 524 | extern const AVInputFormat ff_image_ppm_pipe_demuxer; |
| 525 | extern const AVInputFormat ff_image_psd_pipe_demuxer; | 525 | extern const AVInputFormat ff_image_psd_pipe_demuxer; |
| 526 | extern const AVInputFormat ff_image_qdraw_pipe_demuxer; | 526 | extern const AVInputFormat ff_image_qdraw_pipe_demuxer; |
| 527 | extern const AVInputFormat ff_image_qoi_pipe_demuxer; | ||
| 527 | extern const AVInputFormat ff_image_sgi_pipe_demuxer; | 528 | extern const AVInputFormat ff_image_sgi_pipe_demuxer; |
| 528 | extern const AVInputFormat ff_image_svg_pipe_demuxer; | 529 | extern const AVInputFormat ff_image_svg_pipe_demuxer; |
| 529 | extern const AVInputFormat ff_image_sunrast_pipe_demuxer; | 530 | extern const AVInputFormat ff_image_sunrast_pipe_demuxer; |
| @@ -89,6 +89,7 @@ const IdStrMap ff_img_tags[] = { · 88 unmodified lines | |||
| 89 | { AV_CODEC_ID_GEM, "timg" }, | 89 | { AV_CODEC_ID_GEM, "timg" }, |
| 90 | { AV_CODEC_ID_VBN, "vbn" }, | 90 | { AV_CODEC_ID_VBN, "vbn" }, |
| 91 | { AV_CODEC_ID_JPEGXL, "jxl" }, | 91 | { AV_CODEC_ID_JPEGXL, "jxl" }, |
| 92 | { AV_CODEC_ID_QOI, "qoi" }, | ||
| 92 | { AV_CODEC_ID_NONE, NULL } | 93 | { AV_CODEC_ID_NONE, NULL } |
| 93 | }; | 94 | }; |
| 94 | 95 | ||
| @@ -1131,6 +1131,23 @@ static int photocd_probe(const AVProbeData *p) · 1130 unmodified lines | |||
| 1131 | return AVPROBE_SCORE_MAX - 1; | 1131 | return AVPROBE_SCORE_MAX - 1; |
| 1132 | } | 1132 | } |
| 1133 | 1133 | ||
| 1134 | static int qoi_probe(const AVProbeData *p) | ||
| 1135 | { | ||
| 1136 | if (memcmp(p->buf, "qoif", 4)) | ||
| 1137 | return 0; | ||
| 1138 | |||
| 1139 | if (AV_RB32(p->buf + 4) == 0 || AV_RB32(p->buf + 8) == 0) | ||
| 1140 | return 0; | ||
| 1141 | |||
| 1142 | if (p->buf[12] != 3 && p->buf[12] != 4) | ||
| 1143 | return 0; | ||
| 1144 | |||
| 1145 | if (p->buf[13] > 1) | ||
| 1146 | return 0; | ||
| 1147 | |||
| 1148 | return AVPROBE_SCORE_MAX - 1; | ||
| 1149 | } | ||
| 1150 | |||
| 1134 | static int gem_probe(const AVProbeData *p) | 1151 | static int gem_probe(const AVProbeData *p) |
| 1135 | { | 1152 | { |
| 1136 | const uint8_t *b = p->buf; | 1153 | const uint8_t *b = p->buf; |
| @@ -1208,6 +1225,7 @@ IMAGEAUTO_DEMUXER(png, PNG) · 71 unmodified lines | |||
| 1208 | IMAGEAUTO_DEMUXER(ppm, PPM) | 1225 | IMAGEAUTO_DEMUXER(ppm, PPM) |
| 1209 | IMAGEAUTO_DEMUXER(psd, PSD) | 1226 | IMAGEAUTO_DEMUXER(psd, PSD) |
| 1210 | IMAGEAUTO_DEMUXER(qdraw, QDRAW) | 1227 | IMAGEAUTO_DEMUXER(qdraw, QDRAW) |
| 1228 | IMAGEAUTO_DEMUXER(qoi, QOI) | ||
| 1211 | IMAGEAUTO_DEMUXER(sgi, SGI) | 1229 | IMAGEAUTO_DEMUXER(sgi, SGI) |
| 1212 | IMAGEAUTO_DEMUXER(sunrast, SUNRAST) | 1230 | IMAGEAUTO_DEMUXER(sunrast, SUNRAST) |
| 1213 | IMAGEAUTO_DEMUXER(svg, SVG) | 1231 | IMAGEAUTO_DEMUXER(svg, SVG) |
| @@ -267,7 +267,7 @@ const AVOutputFormat ff_image2_muxer = { · 266 unmodified lines | |||
| 267 | .long_name = NULL_IF_CONFIG_SMALL("image2 sequence"), | 267 | .long_name = NULL_IF_CONFIG_SMALL("image2 sequence"), |
| 268 | .extensions = "bmp,dpx,exr,jls,jpeg,jpg,jxl,ljpg,pam,pbm,pcx,pfm,pgm,pgmyuv," | 268 | .extensions = "bmp,dpx,exr,jls,jpeg,jpg,jxl,ljpg,pam,pbm,pcx,pfm,pgm,pgmyuv," |
| 269 | "png,ppm,sgi,tga,tif,tiff,jp2,j2c,j2k,xwd,sun,ras,rs,im1,im8," | 269 | "png,ppm,sgi,tga,tif,tiff,jp2,j2c,j2k,xwd,sun,ras,rs,im1,im8," |
| 270 | "im24,sunras,vbn,xbm,xface,pix,y,avif", | 270 | "im24,sunras,vbn,xbm,xface,pix,y,avif,qoi", |
| 271 | .priv_data_size = sizeof(VideoMuxData), | 271 | .priv_data_size = sizeof(VideoMuxData), |
| 272 | .video_codec = AV_CODEC_ID_MJPEG, | 272 | .video_codec = AV_CODEC_ID_MJPEG, |
| 273 | .write_header = write_header, | 273 | .write_header = write_header, |