mvcdec.c
Go to the documentation of this file.
1 /*
2  * Silicon Graphics Motion Video Compressor 1 & 2 decoder
3  * Copyright (c) 2012 Peter Ross
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 /**
23  * @file
24  * Silicon Graphics Motion Video Compressor 1 & 2 decoder
25  */
26 
27 #include "libavutil/intreadwrite.h"
28 #include "avcodec.h"
29 #include "bytestream.h"
30 #include "internal.h"
31 
32 typedef struct MvcContext {
34  int vflip;
35 } MvcContext;
36 
38 {
39  MvcContext *s = avctx->priv_data;
40  int width = avctx->width;
41  int height = avctx->height;
42 
43  if (avctx->codec_id == AV_CODEC_ID_MVC1) {
44  width += 3;
45  height += 3;
46  }
47  width &= ~3;
48  height &= ~3;
49  if (width != avctx->width || height != avctx->height)
50  avcodec_set_dimensions(avctx, width, height);
51 
53  s->frame = av_frame_alloc();
54  if (!s->frame)
55  return AVERROR(ENOMEM);
56 
57  s->vflip = avctx->extradata_size >= 9 && !memcmp(avctx->extradata + avctx->extradata_size - 9, "BottomUp", 9);
58  return 0;
59 }
60 
61 static int decode_mvc1(AVCodecContext *avctx, GetByteContext *gb, uint8_t *dst_start, int width, int height, int linesize)
62 {
63  uint8_t *dst;
64  uint16_t v[8];
65  int mask, x, y, i;
66 
67  x = y= 0;
68  while (bytestream2_get_bytes_left(gb) >= 6) {
69  mask = bytestream2_get_be16u(gb);
70  v[0] = bytestream2_get_be16u(gb);
71  v[1] = bytestream2_get_be16u(gb);
72  if ((v[0] & 0x8000)) {
73  if (bytestream2_get_bytes_left(gb) < 12) {
74  av_log(avctx, AV_LOG_WARNING, "buffer overflow\n");
75  return AVERROR_INVALIDDATA;
76  }
77  for (i = 2; i < 8; i++)
78  v[i] = bytestream2_get_be16u(gb);
79  } else {
80  v[2] = v[4] = v[6] = v[0];
81  v[3] = v[5] = v[7] = v[1];
82  }
83 
84 #define PIX16(target, true, false) \
85  i = (mask & target) ? true : false; \
86  AV_WN16A(dst, (v[i] & 0x7C00) | (v[i] & 0x3E0) | (v[i] & 0x1F)); \
87  dst += 2;
88 
89 #define ROW16(row, a1, a0, b1, b0) \
90  dst = dst_start + (y + row) * linesize + x * 2; \
91  PIX16(1 << (row * 4), a1, a0) \
92  PIX16(1 << (row * 4 + 1), a1, a0) \
93  PIX16(1 << (row * 4 + 2), b1, b0) \
94  PIX16(1 << (row * 4 + 3), b1, b0)
95 
96  ROW16(0, 0, 1, 2, 3);
97  ROW16(1, 0, 1, 2, 3);
98  ROW16(2, 4, 5, 6, 7);
99  ROW16(3, 4, 5, 6, 7);
100 
101  x += 4;
102  if (x >= width) {
103  y += 4;
104  if (y >= height) {
105  break;
106  }
107  x = 0;
108  }
109  }
110  return 0;
111 }
112 
113 static void set_4x4_block(uint8_t *dst, int linesize, uint32_t pixel)
114 {
115  int i, j;
116  for (j = 0; j < 4; j++)
117  for (i = 0; i < 4; i++)
118  AV_WN32A(dst + j * linesize + i * 4, pixel);
119 }
120 
121 #define PIX32(target, true, false) \
122  AV_WN32A(dst, (mask & target) ? v[true] : v[false]); \
123  dst += 4;
124 
125 #define ROW32(row, a1, a0, b1, b0) \
126  dst = dst_start + (y + row) * linesize + x * 4; \
127  PIX32(1 << (row * 4), a1, a0) \
128  PIX32(1 << (row * 4 + 1), a1, a0) \
129  PIX32(1 << (row * 4 + 2), b1, b0) \
130  PIX32(1 << (row * 4 + 3), b1, b0)
131 
132 #define MVC2_BLOCK \
133  ROW32(0, 1, 0, 3, 2); \
134  ROW32(1, 1, 0, 3, 2); \
135  ROW32(2, 5, 4, 7, 6); \
136  ROW32(3, 5, 4, 7, 6);
137 
138 static int decode_mvc2(AVCodecContext *avctx, GetByteContext *gb, uint8_t *dst_start, int width, int height, int linesize, int vflip)
139 {
140  uint8_t *dst;
141  uint32_t color[128], v[8];
142  int w, h, nb_colors, i, x, y, p0, p1, mask;
143 
144  if (bytestream2_get_bytes_left(gb) < 6)
145  return AVERROR_INVALIDDATA;
146 
147  w = bytestream2_get_be16u(gb);
148  h = bytestream2_get_be16u(gb);
149  if ((w & ~3) != width || (h & ~3) != height)
150  av_log(avctx, AV_LOG_WARNING, "dimension mismatch\n");
151 
152  if (bytestream2_get_byteu(gb)) {
153  avpriv_request_sample(avctx, "bitmap feature");
154  return AVERROR_PATCHWELCOME;
155  }
156 
157  nb_colors = bytestream2_get_byteu(gb);
158  if (bytestream2_get_bytes_left(gb) < nb_colors * 3)
159  return AVERROR_INVALIDDATA;
160  for (i = 0; i < FFMIN(nb_colors, 128); i++)
161  color[i] = 0xFF000000 | bytestream2_get_be24u(gb);
162  if (nb_colors > 128)
163  bytestream2_skip(gb, (nb_colors - 128) * 3);
164 
165  if (vflip) {
166  dst_start += (height - 1) * linesize;
167  linesize = -linesize;
168  }
169  x = y = 0;
170  while (bytestream2_get_bytes_left(gb) >= 1) {
171  p0 = bytestream2_get_byteu(gb);
172  if ((p0 & 0x80)) {
173  if ((p0 & 0x40)) {
174  p0 &= 0x3F;
175  p0 = (p0 << 2) | (p0 >> 4);
176  set_4x4_block(dst_start + y * linesize + x * 4, linesize, 0xFF000000 | (p0 << 16) | (p0 << 8) | p0);
177  } else {
178  int g, r;
179  p0 &= 0x3F;
180  p0 = (p0 << 2) | (p0 >> 4);
181  if (bytestream2_get_bytes_left(gb) < 2)
182  return AVERROR_INVALIDDATA;
183  g = bytestream2_get_byteu(gb);
184  r = bytestream2_get_byteu(gb);
185  set_4x4_block(dst_start + y * linesize + x * 4, linesize, 0xFF000000 | (r << 16) | (g << 8) | p0);
186  }
187  } else {
188  if (bytestream2_get_bytes_left(gb) < 1)
189  return AVERROR_INVALIDDATA;
190  p1 = bytestream2_get_byteu(gb);
191  if ((p1 & 0x80)) {
192  if ((p0 & 0x7F) == (p1 & 0x7F)) {
193  set_4x4_block(dst_start + y * linesize + x * 4, linesize, color[p0 & 0x7F]);
194  } else {
195  if (bytestream2_get_bytes_left(gb) < 2)
196  return AVERROR_INVALIDDATA;
197  v[0] = v[2] = v[4] = v[6] = color[p0 & 0x7F];
198  v[1] = v[3] = v[5] = v[7] = color[p1 & 0x7F];
199  mask = bytestream2_get_le16u(gb);
200  MVC2_BLOCK
201  }
202  } else {
203  if (bytestream2_get_bytes_left(gb) < 8)
204  return AVERROR_INVALIDDATA;
205  v[0] = color[p0 & 0x7F];
206  v[1] = color[p1 & 0x7F];
207  for (i = 2; i < 8; i++)
208  v[i] = color[bytestream2_get_byteu(gb) & 0x7F];
209  mask = bytestream2_get_le16u(gb);
210  MVC2_BLOCK
211  }
212  }
213 
214  x += 4;
215  if (x >= width) {
216  y += 4;
217  if (y >= height)
218  break;
219  x = 0;
220  }
221  }
222  return 0;
223 }
224 
226  void *data, int *got_frame,
227  AVPacket *avpkt)
228 {
229  MvcContext *s = avctx->priv_data;
230  GetByteContext gb;
231  int ret;
232 
233  if ((ret = ff_reget_buffer(avctx, s->frame)) < 0)
234  return ret;
235 
236  bytestream2_init(&gb, avpkt->data, avpkt->size);
237  if (avctx->codec_id == AV_CODEC_ID_MVC1)
238  ret = decode_mvc1(avctx, &gb, s->frame->data[0], avctx->width, avctx->height, s->frame->linesize[0]);
239  else
240  ret = decode_mvc2(avctx, &gb, s->frame->data[0], avctx->width, avctx->height, s->frame->linesize[0], s->vflip);
241  if (ret < 0)
242  return ret;
243 
244  *got_frame = 1;
245  if ((ret = av_frame_ref(data, s->frame)) < 0)
246  return ret;
247 
248  return avpkt->size;
249 }
250 
252 {
253  MvcContext *s = avctx->priv_data;
254 
255  av_frame_free(&s->frame);
256 
257  return 0;
258 }
259 
260 #if CONFIG_MVC1_DECODER
261 AVCodec ff_mvc1_decoder = {
262  .name = "mvc1",
263  .type = AVMEDIA_TYPE_VIDEO,
264  .id = AV_CODEC_ID_MVC1,
265  .priv_data_size = sizeof(MvcContext),
269  .capabilities = CODEC_CAP_DR1,
270  .long_name = NULL_IF_CONFIG_SMALL("Silicon Graphics Motion Video Compressor 1"),
271 };
272 #endif
273 
274 #if CONFIG_MVC2_DECODER
275 AVCodec ff_mvc2_decoder = {
276  .name = "mvc2",
277  .type = AVMEDIA_TYPE_VIDEO,
278  .id = AV_CODEC_ID_MVC2,
279  .priv_data_size = sizeof(MvcContext),
283  .capabilities = CODEC_CAP_DR1,
284  .long_name = NULL_IF_CONFIG_SMALL("Silicon Graphics Motion Video Compressor 2"),
285 };
286 #endif
float v
const char * s
Definition: avisynth_c.h:668
#define AVERROR_INVALIDDATA
Invalid data found when processing input.
Definition: error.h:59
This structure describes decoded (raw) audio or video data.
Definition: frame.h:76
static void set_4x4_block(uint8_t *dst, int linesize, uint32_t pixel)
Definition: mvcdec.c:113
static av_always_inline unsigned int bytestream2_get_be24u(GetByteContext *g)
Definition: bytestream.h:90
static av_cold int init(AVCodecContext *avctx)
Definition: avrndec.c:35
#define AV_LOG_WARNING
Something somehow does not look correct.
Definition: log.h:154
void avcodec_set_dimensions(AVCodecContext *s, int width, int height)
enum AVPixelFormat pix_fmt
Pixel format, see AV_PIX_FMT_xxx.
static av_always_inline void bytestream2_init(GetByteContext *g, const uint8_t *buf, int buf_size)
Definition: bytestream.h:130
#define MVC2_BLOCK
Definition: mvcdec.c:132
#define AV_WN32A(p, v)
Definition: intreadwrite.h:530
output residual component w
#define av_cold
Definition: attributes.h:78
static const uint32_t color[16+AV_CLASS_CATEGORY_NB]
Definition: log.c:77
#define ROW16(row, a1, a0, b1, b0)
uint8_t * extradata
some codecs need / can use extradata like Huffman tables.
#define CODEC_CAP_DR1
Codec uses get_buffer() for allocating buffers and supports custom allocators.
static int mvc_decode_frame(AVCodecContext *avctx, void *data, int *got_frame, AVPacket *avpkt)
Definition: mvcdec.c:225
uint8_t * data
uint8_t * data[8]
pointer to the picture/channel planes.
Definition: frame.h:87
Discrete Time axis x
static const uint16_t mask[17]
Definition: lzw.c:37
static av_always_inline void bytestream2_skip(GetByteContext *g, unsigned int size)
Definition: bytestream.h:159
#define NULL_IF_CONFIG_SMALL(x)
Return NULL if CONFIG_SMALL is true, otherwise the argument without modification. ...
packed BGRA 8:8:8:8, 32bpp, BGRABGRA...
Definition: pixfmt.h:99
Spectrum Plot time data
const char * r
Definition: vf_curves.c:94
static av_cold int mvc_decode_init(AVCodecContext *avctx)
Definition: mvcdec.c:37
static av_always_inline unsigned int bytestream2_get_bytes_left(GetByteContext *g)
Definition: bytestream.h:149
void av_log(void *avcl, int level, const char *fmt,...)
Send the specified message to the log if the level is less than or equal to the current av_log_level...
Definition: log.c:246
const char * name
Name of the codec implementation.
external API header
static av_always_inline unsigned int bytestream2_get_be16u(GetByteContext *g)
Definition: bytestream.h:91
struct MvcContext MvcContext
int ff_reget_buffer(AVCodecContext *avctx, AVFrame *frame)
Identical in function to av_frame_make_writable(), except it uses ff_get_buffer() to allocate the buf...
FFT buffer for g
Definition: stft_peak.m:17
#define FFMIN(a, b)
Definition: common.h:58
ret
Definition: avfilter.c:821
int width
picture width / height.
static int decode_mvc2(AVCodecContext *avctx, GetByteContext *gb, uint8_t *dst_start, int width, int height, int linesize, int vflip)
Definition: mvcdec.c:138
#define AVERROR_PATCHWELCOME
Not yet implemented in FFmpeg, patches welcome.
Definition: error.h:62
static int width
Definition: tests/utils.c:158
static av_cold int mvc_decode_end(AVCodecContext *avctx)
Definition: mvcdec.c:251
enum AVCodecID codec_id
main external API structure.
static void close(AVCodecParserContext *s)
Definition: h264_parser.c:375
static av_always_inline unsigned int bytestream2_get_le16u(GetByteContext *g)
Definition: bytestream.h:87
BYTE int const BYTE int int int height
Definition: avisynth_c.h:713
synthesis window for stochastic i
AVFrame * frame
Definition: mvcdec.c:33
const uint8_t ptrdiff_t int h
Definition: hpel_template.c:97
static av_always_inline unsigned int bytestream2_get_byteu(GetByteContext *g)
Definition: bytestream.h:92
Filter the word “frame” indicates either a video frame or a group of audio as stored in an AVFilterBuffer 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 they are references to shared objects When the negotiation mechanism computes the intersection of the formats supported at each end of a all references to both lists are replaced with a reference to the intersection And when a single format is eventually chosen for a link amongst the remaining all references to the list are updated That means that if a filter requires that its input and output have the same format amongst a supported all it has to do is use a reference to the same list of formats query_formats can leave some formats unset and return AVERROR(EAGAIN) to cause the negotiation mechanism toagain later.That can be used by filters with complex requirements to use the format negotiated on one link to set the formats supported on another.Buffer references ownership and permissions
uint8_t pixel
Definition: tiny_ssim.c:40
AVFrame * av_frame_alloc(void)
Allocate an AVFrame and set its fields to default values.
Definition: frame.c:95
int av_frame_ref(AVFrame *dst, AVFrame *src)
Setup a new reference to the data described by an given frame.
Definition: frame.c:228
common internal api header.
int vflip
Definition: mvcdec.c:34
static int decode_mvc1(AVCodecContext *avctx, GetByteContext *gb, uint8_t *dst_start, int width, int height, int linesize)
Definition: mvcdec.c:61
void av_frame_free(AVFrame **frame)
Free the frame and any dynamically allocated objects in it, e.g.
Definition: frame.c:108
#define AV_PIX_FMT_RGB555
Definition: pixfmt.h:269
function y
Definition: D.m:1
int linesize[8]
For video, size in bytes of each picture line.
Definition: frame.h:101
static int decode(AVCodecContext *avctx, void *data, int *got_frame, AVPacket *avpkt)
Definition: crystalhd.c:868
This structure stores compressed data.
void avpriv_request_sample(void *avc, const char *msg,...)
Log a generic warning message about a missing feature.
Definition: log.c:297