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 "decode.h"
30 #include "texturedsp.h"
31 #include "vbn.h"
32 #include "libavutil/imgutils.h"
33 #include "libavutil/mem.h"
34 
35 typedef struct VBNContext {
38 } VBNContext;
39 
40 static av_cold int vbn_init(AVCodecContext *avctx)
41 {
42  VBNContext *ctx = avctx->priv_data;
43  ff_texturedsp_init(&ctx->texdsp);
44  return 0;
45 }
46 
47 static int decompress(AVCodecContext *avctx, GetByteContext *gb,
48  int compression, uint8_t **outbuf)
49 {
50  if (compression == VBN_COMPRESSION_NONE) // outbuf is left NULL because gb->buf can be used directly
51  return bytestream2_get_bytes_left(gb);
52 
53  av_log(avctx, AV_LOG_ERROR, "Unsupported VBN compression: 0x%08x\n", compression);
54  return AVERROR_PATCHWELCOME;
55 }
56 
57 static int vbn_decode_frame(AVCodecContext *avctx,
58  AVFrame *frame, int *got_frame,
59  AVPacket *avpkt)
60 {
61  VBNContext *ctx = avctx->priv_data;
62  GetByteContext gb0, *const gb = &gb0;
63  uint8_t *image_buf = NULL;
64  int image_len;
65  int width, height, components, format, compression, pix_fmt, linesize, data_size;
66  int ret;
67 
68  bytestream2_init(gb, avpkt->data, avpkt->size);
69 
71  av_log(avctx, AV_LOG_ERROR, "VBN header truncated\n");
72  return AVERROR_INVALIDDATA;
73  }
74 
75  if (bytestream2_get_le32u(gb) != VBN_MAGIC ||
76  bytestream2_get_le32u(gb) != VBN_MAJOR ||
77  bytestream2_get_le32u(gb) != VBN_MINOR) {
78  av_log(avctx, AV_LOG_ERROR, "Invalid VBN header\n");
79  return AVERROR_INVALIDDATA;
80  }
81 
82  width = bytestream2_get_le32u(gb);
83  height = bytestream2_get_le32u(gb);
84  components = bytestream2_get_le32u(gb);
85  format = bytestream2_get_le32u(gb);
86  pix_fmt = bytestream2_get_le32u(gb);
87  bytestream2_get_le32u(gb); // mipmaps
88  data_size = bytestream2_get_le32u(gb);
89  bytestream2_seek(gb, VBN_HEADER_SIZE, SEEK_SET);
90 
91  compression = format & 0xffffff00;
92  format = format & 0xff;
93 
94  if (data_size != bytestream2_get_bytes_left(gb)) {
95  av_log(avctx, AV_LOG_ERROR, "Truncated packet\n");
96  return AVERROR_INVALIDDATA;
97  }
98 
99  if (pix_fmt != VBN_PIX_RGBA && pix_fmt != VBN_PIX_RGB) {
100  av_log(avctx, AV_LOG_ERROR, "Unsupported pixel format: 0x%08x\n", pix_fmt);
101  return AVERROR_PATCHWELCOME;
102  }
103 
104  ret = ff_set_dimensions(avctx, width, height);
105  if (ret < 0)
106  return ret;
107 
108  if (format == VBN_FORMAT_RAW) {
109  if (pix_fmt == VBN_PIX_RGB && components == 3) {
110  avctx->pix_fmt = AV_PIX_FMT_RGB24;
111  linesize = avctx->width * 3;
112  } else if (pix_fmt == VBN_PIX_RGBA && components == 4) {
113  avctx->pix_fmt = AV_PIX_FMT_RGBA;
114  linesize = avctx->width * 4;
115  } else {
116  av_log(avctx, AV_LOG_ERROR, "Unsupported number of components: %d\n", components);
117  return AVERROR_PATCHWELCOME;
118  }
119  } else if (format == VBN_FORMAT_DXT1 || format == VBN_FORMAT_DXT5) {
120  if (avctx->width % TEXTURE_BLOCK_W || avctx->height % TEXTURE_BLOCK_H) {
121  av_log(avctx, AV_LOG_ERROR, "DXTx compression only supports 4 pixel aligned resolutions\n");
122  return AVERROR_INVALIDDATA;
123  }
124 
125  avctx->pix_fmt = AV_PIX_FMT_RGBA;
126  if (format == VBN_FORMAT_DXT1) {
127  ctx->dec.tex_funct = ctx->texdsp.dxt1_block;
128  ctx->dec.tex_ratio = 8;
129  linesize = avctx->coded_width / 2;
130  } else {
131  ctx->dec.tex_funct = ctx->texdsp.dxt5_block;
132  ctx->dec.tex_ratio = 16;
133  linesize = avctx->coded_width;
134  }
135  } else {
136  av_log(avctx, AV_LOG_ERROR, "Unsupported VBN format: 0x%02x\n", format);
137  return AVERROR_PATCHWELCOME;
138  }
139 
140  image_len = decompress(avctx, gb, compression, &image_buf);
141  if (image_len < 0)
142  return image_len;
143 
144  if (image_len < linesize * avctx->coded_height) {
145  av_log(avctx, AV_LOG_ERROR, "Insufficent data\n");
147  goto out;
148  }
149 
150  ret = ff_get_buffer(avctx, frame, 0);
151  if (ret < 0)
152  goto out;
153 
154  frame->pict_type = AV_PICTURE_TYPE_I;
155  frame->flags |= AV_FRAME_FLAG_KEY;
156 
157  if (format == VBN_FORMAT_RAW) {
158  uint8_t *flipped = frame->data[0] + frame->linesize[0] * (frame->height - 1);
159  av_image_copy_plane(flipped, -frame->linesize[0], image_buf ? image_buf : gb->buffer, linesize, linesize, frame->height);
160  } else {
161  ctx->dec.slice_count = av_clip(avctx->thread_count, 1, avctx->coded_height / TEXTURE_BLOCK_H);
162  ctx->dec.tex_data.in = image_buf ? image_buf : gb->buffer;
163  ctx->dec.raw_ratio = 16;
164  ctx->dec.frame_data.out = frame->data[0] + frame->linesize[0] * (frame->height - 1);
165  ctx->dec.stride = -frame->linesize[0];
166  ctx->dec.width = avctx->coded_width;
167  ctx->dec.height = avctx->coded_height;
169  }
170 
171  *got_frame = 1;
172  ret = avpkt->size;
173 
174 out:
175  av_freep(&image_buf);
176  return ret;
177 }
178 
180  .p.name = "vbn",
181  CODEC_LONG_NAME("Vizrt Binary Image"),
182  .p.type = AVMEDIA_TYPE_VIDEO,
183  .p.id = AV_CODEC_ID_VBN,
184  .init = vbn_init,
186  .priv_data_size = sizeof(VBNContext),
187  .p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_SLICE_THREADS,
188 };
av_clip
#define av_clip
Definition: common.h:99
TEXTURE_BLOCK_H
#define TEXTURE_BLOCK_H
Definition: texturedsp.h:43
out
FILE * out
Definition: movenc.c:55
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:47
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:374
AVPacket::data
uint8_t * data
Definition: packet.h:524
FFCodec
Definition: codec_internal.h:126
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
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:130
AVCodecContext::thread_count
int thread_count
thread count is used to decide how many independent tasks should be passed to execute()
Definition: avcodec.h:1582
AVCodecContext::coded_height
int coded_height
Definition: avcodec.h:633
VBN_HEADER_SIZE
#define VBN_HEADER_SIZE
Definition: vbn.h:33
TextureDSPThreadContext
Definition: texturedsp.h:69
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
AV_FRAME_FLAG_KEY
#define AV_FRAME_FLAG_KEY
A flag to mark frames that are keyframes.
Definition: frame.h:625
width
#define width
FF_CODEC_DECODE_CB
#define FF_CODEC_DECODE_CB(func)
Definition: codec_internal.h:286
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
pix_fmt
static enum AVPixelFormat pix_fmt
Definition: demux_decode.c:41
GetByteContext::buffer
const uint8_t * buffer
Definition: bytestream.h:34
ctx
AVFormatContext * ctx
Definition: movenc.c:49
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:271
AV_PIX_FMT_RGBA
@ AV_PIX_FMT_RGBA
packed RGBA 8:8:8:8, 32bpp, RGBARGBA...
Definition: pixfmt.h:100
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:279
VBN_MAJOR
#define VBN_MAJOR
Definition: vbn.h:30
VBNContext::texdsp
TextureDSPContext texdsp
Definition: vbndec.c:36
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_texturedsp_exec_decompress_threads
int ff_texturedsp_exec_decompress_threads(struct AVCodecContext *avctx, TextureDSPThreadContext *ctx)
ff_get_buffer
int ff_get_buffer(AVCodecContext *avctx, AVFrame *frame, int flags)
Get a buffer for a frame.
Definition: decode.c:1556
AV_PIX_FMT_RGB24
@ AV_PIX_FMT_RGB24
packed RGB 8:8:8, 24bpp, RGBRGB...
Definition: pixfmt.h:75
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:525
codec_internal.h
vbn_decode_frame
static int vbn_decode_frame(AVCodecContext *avctx, AVFrame *frame, int *got_frame, AVPacket *avpkt)
Definition: vbndec.c:57
VBNContext
Definition: vbndec.c:35
VBN_FORMAT_RAW
#define VBN_FORMAT_RAW
Definition: vbn.h:35
VBNContext::dec
TextureDSPThreadContext dec
Definition: vbndec.c:37
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:114
VBN_FORMAT_DXT5
#define VBN_FORMAT_DXT5
Definition: vbn.h:38
TEXTURE_BLOCK_W
#define TEXTURE_BLOCK_W
Definition: texturedsp.h:42
AVCodec::name
const char * name
Name of the codec implementation.
Definition: codec.h:194
AVCodecContext::height
int height
Definition: avcodec.h:618
AVCodecContext::pix_fmt
enum AVPixelFormat pix_fmt
Pixel format, see AV_PIX_FMT_xxx.
Definition: avcodec.h:657
avcodec.h
ff_vbn_decoder
const FFCodec ff_vbn_decoder
Definition: vbndec.c:179
ret
ret
Definition: filter_design.txt:187
AV_CODEC_ID_VBN
@ AV_CODEC_ID_VBN
Definition: codec_id.h:312
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:445
AVCodecContext::coded_width
int coded_width
Bitstream width / height, may be different from width/height e.g.
Definition: avcodec.h:633
AVMEDIA_TYPE_VIDEO
@ AVMEDIA_TYPE_VIDEO
Definition: avutil.h:201
mem.h
vbn.h
VBN_FORMAT_DXT1
#define VBN_FORMAT_DXT1
Definition: vbn.h:37
AVPacket
This structure stores compressed data.
Definition: packet.h:501
AVCodecContext::priv_data
void * priv_data
Definition: avcodec.h:472
av_freep
#define av_freep(p)
Definition: tableprint_vlc.h:34
AVCodecContext::width
int width
picture width / height.
Definition: avcodec.h:618
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
VBN_PIX_RGBA
#define VBN_PIX_RGBA
Definition: vbn.h:47
vbn_init
static av_cold int vbn_init(AVCodecContext *avctx)
Definition: vbndec.c:40