Unified · Split
| @@ -18,6 +18,7 @@ version 5.1: · 17 unmodified lines | ||
| 18 | 18 | - PGS subtitle frame merge bitstream filter |
| 19 | 19 | - blurdetect filter |
| 20 | 20 | - tiltshelf audio filter |
| 21 | +- QOI image format support | |
| 21 | 22 | |
| 22 | 23 | |
| 23 | 24 | version 5.0: |
| @@ -593,6 +593,8 @@ OBJS-$(CONFIG_QCELP_DECODER) += qcelpdec.o \ · 592 unmodified lines | ||
| 593 | 593 | OBJS-$(CONFIG_QDM2_DECODER) += qdm2.o |
| 594 | 594 | OBJS-$(CONFIG_QDMC_DECODER) += qdmc.o |
| 595 | 595 | OBJS-$(CONFIG_QDRAW_DECODER) += qdrw.o |
| 596 | +OBJS-$(CONFIG_QOI_DECODER) += qoidec.o | |
| 597 | +OBJS-$(CONFIG_QOI_ENCODER) += qoienc.o | |
| 596 | 598 | OBJS-$(CONFIG_QPEG_DECODER) += qpeg.o |
| 597 | 599 | OBJS-$(CONFIG_QTRLE_DECODER) += qtrle.o |
| 598 | 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 | 1153 | opus_rc.o vorbis_data.o |
| 1152 | 1154 | OBJS-$(CONFIG_PNG_PARSER) += png_parser.o |
| 1153 | 1155 | OBJS-$(CONFIG_PNM_PARSER) += pnm_parser.o pnm.o |
| 1156 | +OBJS-$(CONFIG_QOI_PARSER) += qoi_parser.o | |
| 1154 | 1157 | OBJS-$(CONFIG_RV30_PARSER) += rv34_parser.o |
| 1155 | 1158 | OBJS-$(CONFIG_RV40_PARSER) += rv34_parser.o |
| 1156 | 1159 | OBJS-$(CONFIG_SBC_PARSER) += sbc_parser.o |
| @@ -269,6 +269,8 @@ extern const FFCodec ff_prosumer_decoder; · 268 unmodified lines | ||
| 269 | 269 | extern const FFCodec ff_psd_decoder; |
| 270 | 270 | extern const FFCodec ff_ptx_decoder; |
| 271 | 271 | extern const FFCodec ff_qdraw_decoder; |
| 272 | +extern const FFCodec ff_qoi_encoder; | |
| 273 | +extern const FFCodec ff_qoi_decoder; | |
| 272 | 274 | extern const FFCodec ff_qpeg_decoder; |
| 273 | 275 | extern const FFCodec ff_qtrle_encoder; |
| 274 | 276 | extern const FFCodec ff_qtrle_decoder; |
| @@ -1879,6 +1879,13 @@ static const AVCodecDescriptor codec_descriptors[] = { · 1878 unmodified lines | ||
| 1879 | 1879 | AV_CODEC_PROP_LOSSLESS, |
| 1880 | 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 | 1890 | /* various PCM "codecs" */ |
| 1884 | 1891 | { |
| @@ -310,6 +310,7 @@ enum AVCodecID { · 309 unmodified lines | ||
| 310 | 310 | AV_CODEC_ID_GEM, |
| 311 | 311 | AV_CODEC_ID_VBN, |
| 312 | 312 | AV_CODEC_ID_JPEGXL, |
| 313 | + AV_CODEC_ID_QOI, | |
| 313 | 314 | |
| 314 | 315 | /* various PCM "codecs" */ |
| 315 | 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 | 60 | extern const AVCodecParser ff_opus_parser; |
| 61 | 61 | extern const AVCodecParser ff_png_parser; |
| 62 | 62 | extern const AVCodecParser ff_pnm_parser; |
| 63 | +extern const AVCodecParser ff_qoi_parser; | |
| 63 | 64 | extern const AVCodecParser ff_rv30_parser; |
| 64 | 65 | extern const AVCodecParser ff_rv40_parser; |
| 65 | 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 | 30 | #include "version_major.h" |
| 31 | 31 | |
| 32 | −#define LIBAVCODEC_VERSION_MINOR 32 | |
| 33 | −#define LIBAVCODEC_VERSION_MICRO 102 | |
| 32 | +#define LIBAVCODEC_VERSION_MINOR 33 | |
| 33 | +#define LIBAVCODEC_VERSION_MICRO 100 | |
| 34 | 34 | |
| 35 | 35 | #define LIBAVCODEC_VERSION_INT AV_VERSION_INT(LIBAVCODEC_VERSION_MAJOR, \ |
| 36 | 36 | LIBAVCODEC_VERSION_MINOR, \ |
| @@ -289,6 +289,7 @@ OBJS-$(CONFIG_IMAGE_PNG_PIPE_DEMUXER) += img2dec.o img2.o · 288 unmodified lines | ||
| 289 | 289 | OBJS-$(CONFIG_IMAGE_PPM_PIPE_DEMUXER) += img2dec.o img2.o |
| 290 | 290 | OBJS-$(CONFIG_IMAGE_PSD_PIPE_DEMUXER) += img2dec.o img2.o |
| 291 | 291 | OBJS-$(CONFIG_IMAGE_QDRAW_PIPE_DEMUXER) += img2dec.o img2.o |
| 292 | +OBJS-$(CONFIG_IMAGE_QOI_PIPE_DEMUXER) += img2dec.o img2.o | |
| 292 | 293 | OBJS-$(CONFIG_IMAGE_SGI_PIPE_DEMUXER) += img2dec.o img2.o |
| 293 | 294 | OBJS-$(CONFIG_IMAGE_SVG_PIPE_DEMUXER) += img2dec.o img2.o |
| 294 | 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 | 524 | extern const AVInputFormat ff_image_ppm_pipe_demuxer; |
| 525 | 525 | extern const AVInputFormat ff_image_psd_pipe_demuxer; |
| 526 | 526 | extern const AVInputFormat ff_image_qdraw_pipe_demuxer; |
| 527 | +extern const AVInputFormat ff_image_qoi_pipe_demuxer; | |
| 527 | 528 | extern const AVInputFormat ff_image_sgi_pipe_demuxer; |
| 528 | 529 | extern const AVInputFormat ff_image_svg_pipe_demuxer; |
| 529 | 530 | extern const AVInputFormat ff_image_sunrast_pipe_demuxer; |
| @@ -89,6 +89,7 @@ const IdStrMap ff_img_tags[] = { · 88 unmodified lines | ||
| 89 | 89 | { AV_CODEC_ID_GEM, "timg" }, |
| 90 | 90 | { AV_CODEC_ID_VBN, "vbn" }, |
| 91 | 91 | { AV_CODEC_ID_JPEGXL, "jxl" }, |
| 92 | + { AV_CODEC_ID_QOI, "qoi" }, | |
| 92 | 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 | 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 | 1151 | static int gem_probe(const AVProbeData *p) |
| 1135 | 1152 | { |
| 1136 | 1153 | const uint8_t *b = p->buf; |
| @@ -1208,6 +1225,7 @@ IMAGEAUTO_DEMUXER(png, PNG) · 71 unmodified lines | ||
| 1208 | 1225 | IMAGEAUTO_DEMUXER(ppm, PPM) |
| 1209 | 1226 | IMAGEAUTO_DEMUXER(psd, PSD) |
| 1210 | 1227 | IMAGEAUTO_DEMUXER(qdraw, QDRAW) |
| 1228 | +IMAGEAUTO_DEMUXER(qoi, QOI) | |
| 1211 | 1229 | IMAGEAUTO_DEMUXER(sgi, SGI) |
| 1212 | 1230 | IMAGEAUTO_DEMUXER(sunrast, SUNRAST) |
| 1213 | 1231 | IMAGEAUTO_DEMUXER(svg, SVG) |
| @@ -267,7 +267,7 @@ const AVOutputFormat ff_image2_muxer = { · 266 unmodified lines | ||
| 267 | 267 | .long_name = NULL_IF_CONFIG_SMALL("image2 sequence"), |
| 268 | 268 | .extensions = "bmp,dpx,exr,jls,jpeg,jpg,jxl,ljpg,pam,pbm,pcx,pfm,pgm,pgmyuv," |
| 269 | 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 | 271 | .priv_data_size = sizeof(VideoMuxData), |
| 272 | 272 | .video_codec = AV_CODEC_ID_MJPEG, |
| 273 | 273 | .write_header = write_header, |