FFmpeg
rtv1.c
Go to the documentation of this file.
1 /*
2  * RTV1 decoder
3  * Copyright (c) 2023 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 #include <stdio.h>
23 #include <string.h>
24 
25 #include "avcodec.h"
26 #include "bytestream.h"
27 #include "codec_internal.h"
28 #include "decode.h"
29 #include "texturedsp.h"
30 #include "thread.h"
31 
33 {
34  TextureDSPContext *dsp = avctx->priv_data;
35  avctx->pix_fmt = AV_PIX_FMT_BGR0;
36  ff_texturedsp_init(dsp);
37  return 0;
38 }
39 
40 static int decode_rtv1(GetByteContext *gb, uint8_t *dst, ptrdiff_t linesize,
41  int width, int height, int flag,
42  int (*dxt1_block)(uint8_t *dst, ptrdiff_t stride, const uint8_t *block))
43 {
44  uint8_t block[8] = { 0 };
45  int run = 0;
46 
47  for (int y = 0; y < height; y += 4) {
48  for (int x = 0; x < width * 4; x += 16) {
49  int mode = 0;
50 
51  if (run && --run > 0) {
52  dxt1_block(dst + x, linesize, block);
53  } else {
54  int a, b;
55 
56  if (bytestream2_get_bytes_left(gb) < 4)
57  return AVERROR_INVALIDDATA;
58 
59  a = bytestream2_get_le16u(gb);
60  b = bytestream2_get_le16u(gb);
61  if (a == b && flag) {
62  AV_WL32(block + 4, 0);
63  } else if (a == 1 && b == 0xffff) {
64  mode = 1;
65  } else if (b && a == 0) {
66  run = b;
67  } else {
68  AV_WL16(block, a);
69  AV_WL16(block + 2, b);
70  AV_WL32(block + 4, bytestream2_get_le32(gb));
71  }
72  if (run && !mode) {
73  dxt1_block(dst + x, linesize, block);
74  } else if (!mode) {
75  AV_WL16(block, a);
76  AV_WL16(block + 2, b);
77  dxt1_block(dst + x, linesize, block);
78  } else {
79  if (bytestream2_get_bytes_left(gb) < 12 * 4)
80  return AVERROR_INVALIDDATA;
81 
82  for (int by = 0; by < 4; by++) {
83  for (int bx = 0; bx < 4; bx++)
84  AV_WL32(dst + x + bx * 4 + by * linesize, bytestream2_get_le24u(gb));
85  }
86  }
87  }
88  }
89 
90  dst += linesize * 4;
91  }
92 
93  return 0;
94 }
95 
96 static int decode_frame(AVCodecContext *avctx, AVFrame *p,
97  int *got_frame, AVPacket *avpkt)
98 {
99  int ret, width, height, flags;
100  TextureDSPContext *dsp = avctx->priv_data;
101  GetByteContext gb;
102  ptrdiff_t linesize;
103  uint8_t *dst;
104 
105  if (avpkt->size < 22)
106  return AVERROR_INVALIDDATA;
107 
108  bytestream2_init(&gb, avpkt->data, avpkt->size);
109 
110  if (bytestream2_get_le32(&gb) != MKTAG('D','X','T','1'))
111  return AVERROR_INVALIDDATA;
112  flags = bytestream2_get_le32(&gb);
113 
114  width = bytestream2_get_le32(&gb);
115  height = bytestream2_get_le32(&gb);
116  ret = ff_set_dimensions(avctx, FFALIGN(width, 4), FFALIGN(height, 4));
117  if (ret < 0)
118  return ret;
119 
120  avctx->width = width;
121  avctx->height = height;
122 
123  if ((ret = ff_thread_get_buffer(avctx, p, 0)) < 0)
124  return ret;
125 
126  dst = p->data[0] + p->linesize[0] * (avctx->coded_height - 1);
127  linesize = -p->linesize[0];
128 
129  ret = decode_rtv1(&gb, dst, linesize, width, height, flags, dsp->dxt1_block);
130  if (ret < 0)
131  return ret;
132 
134  p->flags |= AV_FRAME_FLAG_KEY;
135 
136  *got_frame = 1;
137 
138  return avpkt->size;
139 }
140 
142  .p.name = "rtv1",
143  CODEC_LONG_NAME("RTV1 (RivaTuner Video)"),
144  .p.type = AVMEDIA_TYPE_VIDEO,
145  .p.id = AV_CODEC_ID_RTV1,
146  .priv_data_size = sizeof(TextureDSPContext),
147  .init = decode_init,
149  .p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_FRAME_THREADS,
150 };
TextureDSPContext::dxt1_block
int(* dxt1_block)(uint8_t *dst, ptrdiff_t stride, const uint8_t *block)
Definition: texturedsp.h:46
AV_WL32
#define AV_WL32(p, v)
Definition: intreadwrite.h:424
GetByteContext
Definition: bytestream.h:33
AVFrame
This structure describes decoded (raw) audio or video data.
Definition: frame.h:340
AVPacket::data
uint8_t * data
Definition: packet.h:522
b
#define b
Definition: input.c:41
FFCodec
Definition: codec_internal.h:127
AV_CODEC_ID_RTV1
@ AV_CODEC_ID_RTV1
Definition: codec_id.h:325
AVFrame::flags
int flags
Frame flags, a combination of AV_FRAME_FLAGS.
Definition: frame.h:649
TextureDSPContext
Definition: texturedsp.h:45
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
decode_frame
static int decode_frame(AVCodecContext *avctx, AVFrame *p, int *got_frame, AVPacket *avpkt)
Definition: rtv1.c:96
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
texturedsp.h
FFCodec::p
AVCodec p
The public AVCodec.
Definition: codec_internal.h:131
AVCodecContext::coded_height
int coded_height
Definition: avcodec.h:640
av_cold
#define av_cold
Definition: attributes.h:90
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
decode.h
ff_texturedsp_init
av_cold void ff_texturedsp_init(TextureDSPContext *c)
Definition: texturedsp.c:640
CODEC_LONG_NAME
#define CODEC_LONG_NAME(str)
Definition: codec_internal.h:272
AV_CODEC_CAP_FRAME_THREADS
#define AV_CODEC_CAP_FRAME_THREADS
Codec supports frame-level multithreading.
Definition: codec.h:110
run
uint8_t run
Definition: svq3.c:203
AV_PICTURE_TYPE_I
@ AV_PICTURE_TYPE_I
Intra.
Definition: avutil.h:279
AV_PIX_FMT_BGR0
@ AV_PIX_FMT_BGR0
packed BGR 8:8:8, 32bpp, BGRXBGRX... X=unused/undefined
Definition: pixfmt.h:265
ff_rtv1_decoder
const FFCodec ff_rtv1_decoder
Definition: rtv1.c:141
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
init
int(* init)(AVBSFContext *ctx)
Definition: dts2pts.c:365
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:523
codec_internal.h
AV_WL16
#define AV_WL16(p, v)
Definition: intreadwrite.h:410
height
#define height
a
The reader does not expect b to be semantically here and if the code is changed by maybe adding a a division or other the signedness will almost certainly be mistaken To avoid this confusion a new type was SUINT is the C unsigned type but it holds a signed int to use the same example SUINT a
Definition: undefined.txt:41
flag
#define flag(name)
Definition: cbs_av1.c:466
AVCodec::name
const char * name
Name of the codec implementation.
Definition: codec.h:194
AVCodecContext::height
int height
Definition: avcodec.h:625
AVCodecContext::pix_fmt
enum AVPixelFormat pix_fmt
Pixel format, see AV_PIX_FMT_xxx.
Definition: avcodec.h:662
avcodec.h
stride
#define stride
Definition: h264pred_template.c:537
ret
ret
Definition: filter_design.txt:187
decode_init
static av_cold int decode_init(AVCodecContext *avctx)
Definition: rtv1.c:32
AVCodecContext
main external API structure.
Definition: avcodec.h:445
mode
mode
Definition: ebur128.h:83
AVMEDIA_TYPE_VIDEO
@ AVMEDIA_TYPE_VIDEO
Definition: avutil.h:201
decode_rtv1
static int decode_rtv1(GetByteContext *gb, uint8_t *dst, ptrdiff_t linesize, int width, int height, int flag, int(*dxt1_block)(uint8_t *dst, ptrdiff_t stride, const uint8_t *block))
Definition: rtv1.c:40
FFALIGN
#define FFALIGN(x, a)
Definition: macros.h:78
AVPacket
This structure stores compressed data.
Definition: packet.h:499
AVCodecContext::priv_data
void * priv_data
Definition: avcodec.h:472
dxt1_block
static int dxt1_block(uint8_t *dst, ptrdiff_t stride, const uint8_t *block)
Decompress one block of a DXT1 texture and store the resulting RGBA pixels in 'dst'.
Definition: texturedsp.c:115
AVCodecContext::width
int width
picture width / height.
Definition: avcodec.h:625
bytestream.h
bytestream2_init
static av_always_inline void bytestream2_init(GetByteContext *g, const uint8_t *buf, int buf_size)
Definition: bytestream.h:137
flags
#define flags(name, subs,...)
Definition: cbs_av1.c:474
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
block
The exact code depends on how similar the blocks are and how related they are to the block
Definition: filter_design.txt:207
AVERROR_INVALIDDATA
#define AVERROR_INVALIDDATA
Invalid data found when processing input.
Definition: error.h:61
MKTAG
#define MKTAG(a, b, c, d)
Definition: macros.h:55