FFmpeg
vbndec.c
Go to the documentation of this file.
1 /*
2  * Vizrt Binary Image decoder
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 /**
22  * @file
23  * Vizrt Binary Image decoder
24  */
25 
26 #include "avcodec.h"
27 #include "bytestream.h"
28 #include "codec_internal.h"
29 #include "internal.h"
30 #include "texturedsp.h"
31 #include "vbn.h"
32 #include "libavutil/imgutils.h"
33 
34 typedef struct VBNContext {
37 } VBNContext;
38 
39 static av_cold int vbn_init(AVCodecContext *avctx)
40 {
41  VBNContext *ctx = avctx->priv_data;
42  ff_texturedsp_init(&ctx->texdsp);
43  return 0;
44 }
45 
46 static int decompress(AVCodecContext *avctx, GetByteContext *gb,
47  int compression, uint8_t **outbuf)
48 {
49  if (compression == VBN_COMPRESSION_NONE) // outbuf is left NULL because gb->buf can be used directly
50  return bytestream2_get_bytes_left(gb);
51 
52  av_log(avctx, AV_LOG_ERROR, "Unsupported VBN compression: 0x%08x\n", compression);
53  return AVERROR_PATCHWELCOME;
54 }
55 
56 static int vbn_decode_frame(AVCodecContext *avctx,
57  AVFrame *frame, int *got_frame,
58  AVPacket *avpkt)
59 {
60  VBNContext *ctx = avctx->priv_data;
61  GetByteContext gb0, *const gb = &gb0;
62  uint8_t *image_buf = NULL;
63  int image_len;
64  int width, height, components, format, compression, pix_fmt, linesize, data_size;
65  int ret;
66 
67  bytestream2_init(gb, avpkt->data, avpkt->size);
68 
70  av_log(avctx, AV_LOG_ERROR, "VBN header truncated\n");
71  return AVERROR_INVALIDDATA;
72  }
73 
74  if (bytestream2_get_le32u(gb) != VBN_MAGIC ||
75  bytestream2_get_le32u(gb) != VBN_MAJOR ||
76  bytestream2_get_le32u(gb) != VBN_MINOR) {
77  av_log(avctx, AV_LOG_ERROR, "Invalid VBN header\n");
78  return AVERROR_INVALIDDATA;
79  }
80 
81  width = bytestream2_get_le32u(gb);
82  height = bytestream2_get_le32u(gb);
83  components = bytestream2_get_le32u(gb);
84  format = bytestream2_get_le32u(gb);
85  pix_fmt = bytestream2_get_le32u(gb);
86  bytestream2_get_le32u(gb); // mipmaps
87  data_size = bytestream2_get_le32u(gb);
88  bytestream2_seek(gb, VBN_HEADER_SIZE, SEEK_SET);
89 
90  compression = format & 0xffffff00;
91  format = format & 0xff;
92 
93  if (data_size != bytestream2_get_bytes_left(gb)) {
94  av_log(avctx, AV_LOG_ERROR, "Truncated packet\n");
95  return AVERROR_INVALIDDATA;
96  }
97 
98  if (pix_fmt != VBN_PIX_RGBA && pix_fmt != VBN_PIX_RGB) {
99  av_log(avctx, AV_LOG_ERROR, "Unsupported pixel format: 0x%08x\n", pix_fmt);
100  return AVERROR_PATCHWELCOME;
101  }
102 
103  ret = ff_set_dimensions(avctx, width, height);
104  if (ret < 0)
105  return ret;
106 
107  if (format == VBN_FORMAT_RAW) {
108  if (pix_fmt == VBN_PIX_RGB && components == 3) {
109  avctx->pix_fmt = AV_PIX_FMT_RGB24;
110  linesize = avctx->width * 3;
111  } else if (pix_fmt == VBN_PIX_RGBA && components == 4) {
112  avctx->pix_fmt = AV_PIX_FMT_RGBA;
113  linesize = avctx->width * 4;
114  } else {
115  av_log(avctx, AV_LOG_ERROR, "Unsupported number of components: %d\n", components);
116  return AVERROR_PATCHWELCOME;
117  }
118  } else if (format == VBN_FORMAT_DXT1 || format == VBN_FORMAT_DXT5) {
119  if (avctx->width % TEXTURE_BLOCK_W || avctx->height % TEXTURE_BLOCK_H) {
120  av_log(avctx, AV_LOG_ERROR, "DXTx compression only supports 4 pixel aligned resolutions\n");
121  return AVERROR_INVALIDDATA;
122  }
123 
124  avctx->pix_fmt = AV_PIX_FMT_RGBA;
125  if (format == VBN_FORMAT_DXT1) {
126  ctx->dec.tex_funct = ctx->texdsp.dxt1_block;
127  ctx->dec.tex_ratio = 8;
128  linesize = avctx->coded_width / 2;
129  } else {
130  ctx->dec.tex_funct = ctx->texdsp.dxt5_block;
131  ctx->dec.tex_ratio = 16;
132  linesize = avctx->coded_width;
133  }
134  } else {
135  av_log(avctx, AV_LOG_ERROR, "Unsupported VBN format: 0x%02x\n", format);
136  return AVERROR_PATCHWELCOME;
137  }
138 
139  image_len = decompress(avctx, gb, compression, &image_buf);
140  if (image_len < 0)
141  return image_len;
142 
143  if (image_len < linesize * avctx->coded_height) {
144  av_log(avctx, AV_LOG_ERROR, "Insufficent data\n");
146  goto out;
147  }
148 
149  ret = ff_get_buffer(avctx, frame, 0);
150  if (ret < 0)
151  goto out;
152 
153  frame->pict_type = AV_PICTURE_TYPE_I;
154  frame->key_frame = 1;
155 
156  if (format == VBN_FORMAT_RAW) {
157  uint8_t *flipped = frame->data[0] + frame->linesize[0] * (frame->height - 1);
158  av_image_copy_plane(flipped, -frame->linesize[0], image_buf ? image_buf : gb->buffer, linesize, linesize, frame->height);
159  } else {
160  ctx->dec.slice_count = av_clip(avctx->thread_count, 1, avctx->coded_height / TEXTURE_BLOCK_H);
161  ctx->dec.tex_data.in = image_buf ? image_buf : gb->buffer;
162  ctx->dec.raw_ratio = 16;
163  ctx->dec.frame_data.out = frame->data[0] + frame->linesize[0] * (frame->height - 1);
164  ctx->dec.stride = -frame->linesize[0];
165  avctx->execute2(avctx, ff_texturedsp_decompress_thread, &ctx->dec, NULL, ctx->dec.slice_count);
166  }
167 
168  *got_frame = 1;
169  ret = avpkt->size;
170 
171 out:
172  av_freep(&image_buf);
173  return ret;
174 }
175 
177  .p.name = "vbn",
178  .p.long_name = NULL_IF_CONFIG_SMALL("Vizrt Binary Image"),
179  .p.type = AVMEDIA_TYPE_VIDEO,
180  .p.id = AV_CODEC_ID_VBN,
181  .init = vbn_init,
183  .priv_data_size = sizeof(VBNContext),
184  .p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_SLICE_THREADS,
185  .caps_internal = FF_CODEC_CAP_INIT_THREADSAFE
186 };
av_clip
#define av_clip
Definition: common.h:95
TEXTURE_BLOCK_H
#define TEXTURE_BLOCK_H
Definition: texturedsp.h:45
out
FILE * out
Definition: movenc.c:54
GetByteContext
Definition: bytestream.h:33
VBN_MINOR
#define VBN_MINOR
Definition: vbn.h:31
decompress
static int decompress(AVCodecContext *avctx, GetByteContext *gb, int compression, uint8_t **outbuf)
Definition: vbndec.c:46
bytestream2_seek
static av_always_inline int bytestream2_seek(GetByteContext *g, int offset, int whence)
Definition: bytestream.h:212
AVFrame
This structure describes decoded (raw) audio or video data.
Definition: frame.h:325
internal.h
AVPacket::data
uint8_t * data
Definition: packet.h:374
FFCodec
Definition: codec_internal.h:112
TextureDSPContext
Definition: texturedsp.h:47
ff_texturedsp_decompress_thread
int ff_texturedsp_decompress_thread(AVCodecContext *avctx, void *arg, int slice, int thread_nb)
av_image_copy_plane
void av_image_copy_plane(uint8_t *dst, int dst_linesize, const uint8_t *src, int src_linesize, int bytewidth, int height)
Copy image plane from src to dst.
Definition: imgutils.c:374
texturedsp.h
FFCodec::p
AVCodec p
The public AVCodec.
Definition: codec_internal.h:116
AVCodecContext::thread_count
int thread_count
thread count is used to decide how many independent tasks should be passed to execute()
Definition: avcodec.h:1463
AVCodecContext::coded_height
int coded_height
Definition: avcodec.h:577
VBN_HEADER_SIZE
#define VBN_HEADER_SIZE
Definition: vbn.h:33
TextureDSPThreadContext
Definition: texturedsp.h:65
AV_LOG_ERROR
#define AV_LOG_ERROR
Something went wrong and cannot losslessly be recovered.
Definition: log.h:180
av_cold
#define av_cold
Definition: attributes.h:90
VBN_COMPRESSION_NONE
#define VBN_COMPRESSION_NONE
Definition: vbn.h:40
width
#define width
FF_CODEC_DECODE_CB
#define FF_CODEC_DECODE_CB(func)
Definition: codec_internal.h:254
format
Filter the word “frame” indicates either a video frame or a group of audio as stored in an AVFrame structure Format for each input and each output the list of supported formats For video that means pixel format For audio that means channel sample format(the sample packing is implied by the sample format) and sample rate. The lists are not just lists
GetByteContext::buffer
const uint8_t * buffer
Definition: bytestream.h:34
ctx
AVFormatContext * ctx
Definition: movenc.c:48
ff_texturedsp_init
av_cold void ff_texturedsp_init(TextureDSPContext *c)
Definition: texturedsp.c:637
pix_fmt
static enum AVPixelFormat pix_fmt
Definition: demuxing_decoding.c:41
AV_PIX_FMT_RGBA
@ AV_PIX_FMT_RGBA
packed RGBA 8:8:8:8, 32bpp, RGBARGBA...
Definition: pixfmt.h:93
NULL
#define NULL
Definition: coverity.c:32
AVERROR_PATCHWELCOME
#define AVERROR_PATCHWELCOME
Not yet implemented in FFmpeg, patches welcome.
Definition: error.h:64
AV_PICTURE_TYPE_I
@ AV_PICTURE_TYPE_I
Intra.
Definition: avutil.h:274
VBN_MAJOR
#define VBN_MAJOR
Definition: vbn.h:30
VBNContext::texdsp
TextureDSPContext texdsp
Definition: vbndec.c:35
VBN_MAGIC
#define VBN_MAGIC
Definition: vbn.h:29
bytestream2_get_bytes_left
static av_always_inline int bytestream2_get_bytes_left(GetByteContext *g)
Definition: bytestream.h:158
ff_get_buffer
int ff_get_buffer(AVCodecContext *avctx, AVFrame *frame, int flags)
Get a buffer for a frame.
Definition: decode.c:1403
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:375
NULL_IF_CONFIG_SMALL
#define NULL_IF_CONFIG_SMALL(x)
Return NULL if CONFIG_SMALL is true, otherwise the argument without modification.
Definition: internal.h:117
codec_internal.h
vbn_decode_frame
static int vbn_decode_frame(AVCodecContext *avctx, AVFrame *frame, int *got_frame, AVPacket *avpkt)
Definition: vbndec.c:56
VBNContext
Definition: vbndec.c:34
VBN_FORMAT_RAW
#define VBN_FORMAT_RAW
Definition: vbn.h:35
VBNContext::dec
TextureDSPThreadContext dec
Definition: vbndec.c:36
height
#define height
AV_CODEC_CAP_SLICE_THREADS
#define AV_CODEC_CAP_SLICE_THREADS
Codec supports slice-based (or partition-based) multithreading.
Definition: codec.h:117
FF_CODEC_CAP_INIT_THREADSAFE
#define FF_CODEC_CAP_INIT_THREADSAFE
The codec does not modify any global variables in the init function, allowing to call the init functi...
Definition: codec_internal.h:31
VBN_FORMAT_DXT5
#define VBN_FORMAT_DXT5
Definition: vbn.h:38
TEXTURE_BLOCK_W
#define TEXTURE_BLOCK_W
Definition: texturedsp.h:44
AVCodec::name
const char * name
Name of the codec implementation.
Definition: codec.h:203
AVCodecContext::height
int height
Definition: avcodec.h:562
AVCodecContext::pix_fmt
enum AVPixelFormat pix_fmt
Pixel format, see AV_PIX_FMT_xxx.
Definition: avcodec.h:599
avcodec.h
ff_vbn_decoder
const FFCodec ff_vbn_decoder
Definition: vbndec.c:176
ret
ret
Definition: filter_design.txt:187
AV_CODEC_ID_VBN
@ AV_CODEC_ID_VBN
Definition: codec_id.h:311
frame
these buffered frames must be flushed immediately if a new input produces new the filter must not call request_frame to get more It must just process the frame or queue it The task of requesting more frames is left to the filter s request_frame method or the application If a filter has several the filter must be ready for frames arriving randomly on any input any filter with several inputs will most likely require some kind of queuing mechanism It is perfectly acceptable to have a limited queue and to drop frames when the inputs are too unbalanced request_frame For filters that do not use the this method is called when a frame is wanted on an output For a it should directly call filter_frame on the corresponding output For a if there are queued frames already one of these frames should be pushed If the filter should request a frame on one of its repeatedly until at least one frame has been pushed Return or at least make progress towards producing a frame
Definition: filter_design.txt:264
VBN_PIX_RGB
#define VBN_PIX_RGB
Definition: vbn.h:46
AVCodecContext
main external API structure.
Definition: avcodec.h:389
AVCodecContext::coded_width
int coded_width
Bitstream width / height, may be different from width/height e.g.
Definition: avcodec.h:577
AVMEDIA_TYPE_VIDEO
@ AVMEDIA_TYPE_VIDEO
Definition: avutil.h:201
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:90
vbn.h
VBN_FORMAT_DXT1
#define VBN_FORMAT_DXT1
Definition: vbn.h:37
AVPacket
This structure stores compressed data.
Definition: packet.h:351
AVCodecContext::priv_data
void * priv_data
Definition: avcodec.h:416
av_freep
#define av_freep(p)
Definition: tableprint_vlc.h:34
AVCodecContext::width
int width
picture width / height.
Definition: avcodec.h:562
bytestream.h
imgutils.h
bytestream2_init
static av_always_inline void bytestream2_init(GetByteContext *g, const uint8_t *buf, int buf_size)
Definition: bytestream.h:137
av_log
#define av_log(a,...)
Definition: tableprint_vlc.h:27
AVERROR_INVALIDDATA
#define AVERROR_INVALIDDATA
Invalid data found when processing input.
Definition: error.h:61
AVCodecContext::execute2
int(* execute2)(struct AVCodecContext *c, int(*func)(struct AVCodecContext *c2, void *arg, int jobnr, int threadnr), void *arg2, int *ret, int count)
The codec may call this to execute several independent things.
Definition: avcodec.h:1533
VBN_PIX_RGBA
#define VBN_PIX_RGBA
Definition: vbn.h:47
vbn_init
static av_cold int vbn_init(AVCodecContext *avctx)
Definition: vbndec.c:39