FFmpeg
qoidec.c
Go to the documentation of this file.
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 "avcodec.h"
22 #include "bytestream.h"
23 #include "codec_internal.h"
24 #include "decode.h"
25 #include "thread.h"
26 #include "qoi.h"
27 
28 static int qoi_decode_frame(AVCodecContext *avctx, AVFrame *p,
29  int *got_frame, AVPacket *avpkt)
30 {
31  int width, height, channels, space, run = 0;
32  uint8_t index[64][4] = { 0 };
33  uint8_t px[4] = { 0, 0, 0, 255 };
34  GetByteContext gb;
35  uint8_t *dst;
36  uint64_t len;
37  int ret;
38 
39  if (avpkt->size < 20)
40  return AVERROR_INVALIDDATA;
41 
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);
48  switch (space) {
49  case 0: break;
50  case 1: avctx->color_trc = AVCOL_TRC_LINEAR; break;
51  default: return AVERROR_INVALIDDATA;
52  }
53 
54  if ((ret = ff_set_dimensions(avctx, width, height)) < 0)
55  return ret;
56 
57  switch (channels) {
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;
61  }
62 
63  if (avctx->skip_frame >= AVDISCARD_ALL)
64  return avpkt->size;
65 
66  if ((ret = ff_thread_get_buffer(avctx, p, 0)) < 0)
67  return ret;
68 
69  dst = p->data[0];
70  len = width * height * channels;
71  for (int n = 0, off_x = 0; n < len; n += channels, off_x++) {
72  if (off_x >= width) {
73  off_x = 0;
74  dst += p->linesize[0];
75  }
76  if (run > 0) {
77  run--;
78  } else if (bytestream2_get_bytes_left(&gb) > 4) {
79  int chunk = bytestream2_get_byteu(&gb);
80 
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);
95  px[1] += vg;
96  px[2] += vg - 8 + (b2 & 0x0f);
97  } else if ((chunk & QOI_MASK_2) == QOI_OP_RUN) {
98  run = chunk & 0x3f;
99  }
100 
101  memcpy(index[QOI_COLOR_HASH(px) & 63], px, 4);
102  } else {
103  break;
104  }
105 
106  memcpy(&dst[off_x * channels], px, channels);
107  }
108 
109  p->flags |= AV_FRAME_FLAG_KEY;
111 
112  *got_frame = 1;
113 
114  return avpkt->size;
115 }
116 
118  .p.name = "qoi",
119  CODEC_LONG_NAME("QOI (Quite OK Image format) image"),
120  .p.type = AVMEDIA_TYPE_VIDEO,
121  .p.id = AV_CODEC_ID_QOI,
122  .p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_FRAME_THREADS,
123  .caps_internal = FF_CODEC_CAP_SKIP_FRAME_FILL_PARAM,
125 };
space
Undefined Behavior In the C some operations are like signed integer dereferencing freed accessing outside allocated space
Definition: undefined.txt:4
QOI_OP_LUMA
#define QOI_OP_LUMA
Definition: qoi.h:26
GetByteContext
Definition: bytestream.h:33
AVCOL_TRC_LINEAR
@ AVCOL_TRC_LINEAR
"Linear transfer characteristics"
Definition: pixfmt.h:579
AVFrame
This structure describes decoded (raw) audio or video data.
Definition: frame.h:340
AVCodecContext::color_trc
enum AVColorTransferCharacteristic color_trc
Color Transfer Characteristic.
Definition: avcodec.h:1022
AVPacket::data
uint8_t * data
Definition: packet.h:491
FFCodec
Definition: codec_internal.h:127
AVFrame::flags
int flags
Frame flags, a combination of AV_FRAME_FLAGS.
Definition: frame.h:649
ff_qoi_decoder
const FFCodec ff_qoi_decoder
Definition: qoidec.c:117
ff_set_dimensions
int ff_set_dimensions(AVCodecContext *s, int width, int height)
Check that the provided frame dimensions are valid and set them on the codec context.
Definition: utils.c:94
thread.h
AVFrame::data
uint8_t * data[AV_NUM_DATA_POINTERS]
pointer to the picture/channel planes.
Definition: frame.h:361
ff_thread_get_buffer
the pkt_dts and pkt_pts fields in AVFrame will work as usual Restrictions on codec whose streams don t reset across will not work because their bitstreams cannot be decoded in parallel *The contents of buffers must not be read before as well as code calling up to before the decode process starts Call have so the codec calls ff_thread_report set FF_CODEC_CAP_ALLOCATE_PROGRESS in FFCodec caps_internal and use ff_thread_get_buffer() to allocate frames. Otherwise decode directly into the user-supplied frames. Call ff_thread_report_progress() after some part of the current picture has decoded. A good place to put this is where draw_horiz_band() is called - add this if it isn 't called anywhere
bytestream2_skip
static av_always_inline void bytestream2_skip(GetByteContext *g, unsigned int size)
Definition: bytestream.h:168
FFCodec::p
AVCodec p
The public AVCodec.
Definition: codec_internal.h:131
QOI_OP_RUN
#define QOI_OP_RUN
Definition: qoi.h:27
QOI_OP_INDEX
#define QOI_OP_INDEX
Definition: qoi.h:24
AVCodecContext::skip_frame
enum AVDiscard skip_frame
Skip decoding for selected frames.
Definition: avcodec.h:1766
qoi_decode_frame
static int qoi_decode_frame(AVCodecContext *avctx, AVFrame *p, int *got_frame, AVPacket *avpkt)
Definition: qoidec.c:28
AV_FRAME_FLAG_KEY
#define AV_FRAME_FLAG_KEY
A flag to mark frames that are keyframes.
Definition: frame.h:628
width
#define width
FF_CODEC_DECODE_CB
#define FF_CODEC_DECODE_CB(func)
Definition: codec_internal.h:306
channels
channels
Definition: aptx.h:31
decode.h
CODEC_LONG_NAME
#define CODEC_LONG_NAME(str)
Definition: codec_internal.h:272
AV_PIX_FMT_RGBA
@ AV_PIX_FMT_RGBA
packed RGBA 8:8:8:8, 32bpp, RGBARGBA...
Definition: pixfmt.h:93
QOI_MASK_2
#define QOI_MASK_2
Definition: qoi.h:31
AV_CODEC_CAP_FRAME_THREADS
#define AV_CODEC_CAP_FRAME_THREADS
Codec supports frame-level multithreading.
Definition: codec.h:110
AVDISCARD_ALL
@ AVDISCARD_ALL
discard all
Definition: defs.h:219
run
uint8_t run
Definition: svq3.c:203
qoi.h
AV_PICTURE_TYPE_I
@ AV_PICTURE_TYPE_I
Intra.
Definition: avutil.h:279
index
int index
Definition: gxfenc.c:89
bytestream2_get_bytes_left
static av_always_inline int bytestream2_get_bytes_left(GetByteContext *g)
Definition: bytestream.h:158
AVFrame::pict_type
enum AVPictureType pict_type
Picture type of the frame.
Definition: frame.h:442
AV_PIX_FMT_RGB24
@ AV_PIX_FMT_RGB24
packed RGB 8:8:8, 24bpp, RGBRGB...
Definition: pixfmt.h:68
AV_CODEC_CAP_DR1
#define AV_CODEC_CAP_DR1
Codec uses get_buffer() or get_encode_buffer() for allocating buffers and supports custom allocators.
Definition: codec.h:52
AVPacket::size
int size
Definition: packet.h:492
codec_internal.h
FF_CODEC_CAP_SKIP_FRAME_FILL_PARAM
#define FF_CODEC_CAP_SKIP_FRAME_FILL_PARAM
The decoder extracts and fills its parameters even if the frame is skipped due to the skip_frame sett...
Definition: codec_internal.h:54
AV_CODEC_ID_QOI
@ AV_CODEC_ID_QOI
Definition: codec_id.h:317
height
#define height
b2
static double b2(void *priv, double x, double y)
Definition: vf_xfade.c:2036
QOI_OP_RGBA
#define QOI_OP_RGBA
Definition: qoi.h:29
AVCodec::name
const char * name
Name of the codec implementation.
Definition: codec.h:194
len
int len
Definition: vorbis_enc_data.h:426
QOI_OP_RGB
#define QOI_OP_RGB
Definition: qoi.h:28
AVCodecContext::pix_fmt
enum AVPixelFormat pix_fmt
Pixel format, see AV_PIX_FMT_xxx.
Definition: avcodec.h:658
avcodec.h
ret
ret
Definition: filter_design.txt:187
QOI_COLOR_HASH
#define QOI_COLOR_HASH(px)
Definition: qoi.h:33
AVCodecContext
main external API structure.
Definition: avcodec.h:441
AVMEDIA_TYPE_VIDEO
@ AVMEDIA_TYPE_VIDEO
Definition: avutil.h:201
bytestream2_get_bufferu
static av_always_inline unsigned int bytestream2_get_bufferu(GetByteContext *g, uint8_t *dst, unsigned int size)
Definition: bytestream.h:277
QOI_OP_DIFF
#define QOI_OP_DIFF
Definition: qoi.h:25
AVPacket
This structure stores compressed data.
Definition: packet.h:468
bytestream.h
bytestream2_init
static av_always_inline void bytestream2_init(GetByteContext *g, const uint8_t *buf, int buf_size)
Definition: bytestream.h:137
AVFrame::linesize
int linesize[AV_NUM_DATA_POINTERS]
For video, a positive or negative value, which is typically indicating the size in bytes of each pict...
Definition: frame.h:385
AVERROR_INVALIDDATA
#define AVERROR_INVALIDDATA
Invalid data found when processing input.
Definition: error.h:61