4 * This file is part of FFmpeg.
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.
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.
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
22 #include "bytestream.h"
23 #include "codec_internal.h"
28 static int qoi_decode_frame(AVCodecContext
*avctx
, AVFrame
*p
,
29 int *got_frame
, AVPacket
*avpkt
)
31 int width
, height
, channels
, space
, run
= 0;
32 uint8_t index
[64][4] = { 0 };
33 uint8_t px
[4] = { 0, 0, 0, 255 };
40 return AVERROR_INVALIDDATA
;
42 bytestream2_init(&gb
, avpkt
->data
, avpkt
->size
);
43 bytestream2_skip(&gb
, 4);
44 width
= bytestream2_get_be32(&gb
);
45 height
= bytestream2_get_be32(&gb
);
46 channels
= bytestream2_get_byte(&gb
);
47 space
= bytestream2_get_byte(&gb
);
50 case 1: avctx
->color_trc
= AVCOL_TRC_LINEAR
; break;
51 default: return AVERROR_INVALIDDATA
;
54 if ((ret
= ff_set_dimensions(avctx
, width
, height
)) < 0)
58 case 3: avctx
->pix_fmt
= AV_PIX_FMT_RGB24
; break;
59 case 4: avctx
->pix_fmt
= AV_PIX_FMT_RGBA
; break;
60 default: return AVERROR_INVALIDDATA
;
63 if (avctx
->skip_frame
>= AVDISCARD_ALL
)
66 if ((ret
= ff_thread_get_buffer(avctx
, p
, 0)) < 0)
70 len
= width
* height
* channels
;
71 for (int n
= 0, off_x
= 0; n
< len
; n
+= channels
, off_x
++) {
74 dst
+= p
->linesize
[0];
78 } else if (bytestream2_get_bytes_left(&gb
) > 4) {
79 int chunk
= bytestream2_get_byteu(&gb
);
81 if (chunk
== QOI_OP_RGB
) {
82 bytestream2_get_bufferu(&gb
, px
, 3);
83 } else if (chunk
== QOI_OP_RGBA
) {
84 bytestream2_get_bufferu(&gb
, px
, 4);
85 } else if ((chunk
& QOI_MASK_2
) == QOI_OP_INDEX
) {
86 memcpy(px
, index
[chunk
], 4);
87 } else if ((chunk
& QOI_MASK_2
) == QOI_OP_DIFF
) {
88 px
[0] += ((chunk
>> 4) & 0x03) - 2;
89 px
[1] += ((chunk
>> 2) & 0x03) - 2;
90 px
[2] += ( chunk
& 0x03) - 2;
91 } else if ((chunk
& QOI_MASK_2
) == QOI_OP_LUMA
) {
92 int b2
= bytestream2_get_byteu(&gb
);
93 int vg
= (chunk
& 0x3f) - 32;
94 px
[0] += vg
- 8 + ((b2
>> 4) & 0x0f);
96 px
[2] += vg
- 8 + (b2
& 0x0f);
97 } else if ((chunk
& QOI_MASK_2
) == QOI_OP_RUN
) {
101 memcpy(index
[QOI_COLOR_HASH(px
) & 63], px
, 4);
106 memcpy(&dst
[off_x
* channels
], px
, channels
);
114 const FFCodec ff_qoi_decoder
= {
116 CODEC_LONG_NAME("QOI (Quite OK Image format) image"),
117 .p
.type
= AVMEDIA_TYPE_VIDEO
,
118 .p
.id
= AV_CODEC_ID_QOI
,
119 .p
.capabilities
= AV_CODEC_CAP_DR1
| AV_CODEC_CAP_FRAME_THREADS
,
120 .caps_internal
= FF_CODEC_CAP_SKIP_FRAME_FILL_PARAM
,
121 FF_CODEC_DECODE_CB(qoi_decode_frame
),