FFmpeg
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
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 
29 #include "avcodec.h"
30 #include "bytestream.h"
31 #include "internal.h"
32 
33 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  int ret;
43 
44  if (avctx->codec_id == AV_CODEC_ID_MVC1) {
45  width += 3;
46  height += 3;
47  }
48  width &= ~3;
49  height &= ~3;
50  if ((ret = ff_set_dimensions(avctx, width, height)) < 0)
51  return ret;
52 
53  avctx->pix_fmt = (avctx->codec_id == AV_CODEC_ID_MVC1) ? AV_PIX_FMT_RGB555
55  s->vflip = avctx->extradata_size >= 9 &&
56  !memcmp(avctx->extradata + avctx->extradata_size - 9, "BottomUp", 9);
57  return 0;
58 }
59 
60 static int decode_mvc1(AVCodecContext *avctx, GetByteContext *gb,
61  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  for (y = 0; y < height; y += 4) {
68  for (x = 0; x < width; x += 4) {
69  if (bytestream2_get_bytes_left(gb) < 6)
70  return 0;
71 
72  mask = bytestream2_get_be16u(gb);
73  v[0] = bytestream2_get_be16u(gb);
74  v[1] = bytestream2_get_be16u(gb);
75  if ((v[0] & 0x8000)) {
76  if (bytestream2_get_bytes_left(gb) < 12) {
77  av_log(avctx, AV_LOG_WARNING, "buffer overflow\n");
78  return AVERROR_INVALIDDATA;
79  }
80  for (i = 2; i < 8; i++)
81  v[i] = bytestream2_get_be16u(gb);
82  } else {
83  v[2] = v[4] = v[6] = v[0];
84  v[3] = v[5] = v[7] = v[1];
85  }
86 
87 #define PIX16(target, true, false) \
88  i = (mask & target) ? true : false; \
89  AV_WN16A(dst, v[i] & 0x7FFF); \
90  dst += 2;
91 
92 #define ROW16(row, a1, a0, b1, b0) \
93  dst = dst_start + (y + row) * linesize + x * 2; \
94  PIX16(1 << (row * 4), a1, a0) \
95  PIX16(1 << (row * 4 + 1), a1, a0) \
96  PIX16(1 << (row * 4 + 2), b1, b0) \
97  PIX16(1 << (row * 4 + 3), b1, b0)
98 
99  ROW16(0, 0, 1, 2, 3);
100  ROW16(1, 0, 1, 2, 3);
101  ROW16(2, 4, 5, 6, 7);
102  ROW16(3, 4, 5, 6, 7);
103  }
104  }
105  return 0;
106 }
107 
108 static void set_4x4_block(uint8_t *dst, int linesize, uint32_t pixel)
109 {
110  int i, j;
111  for (j = 0; j < 4; j++)
112  for (i = 0; i < 4; i++)
113  AV_WN32A(dst + j * linesize + i * 4, pixel);
114 }
115 
116 #define PIX32(target, true, false) \
117  AV_WN32A(dst, (mask & target) ? v[true] : v[false]); \
118  dst += 4;
119 
120 #define ROW32(row, a1, a0, b1, b0) \
121  dst = dst_start + (y + row) * linesize + x * 4; \
122  PIX32(1 << (row * 4), a1, a0) \
123  PIX32(1 << (row * 4 + 1), a1, a0) \
124  PIX32(1 << (row * 4 + 2), b1, b0) \
125  PIX32(1 << (row * 4 + 3), b1, b0)
126 
127 #define MVC2_BLOCK \
128  ROW32(0, 1, 0, 3, 2); \
129  ROW32(1, 1, 0, 3, 2); \
130  ROW32(2, 5, 4, 7, 6); \
131  ROW32(3, 5, 4, 7, 6);
132 
134  uint8_t *dst_start, int width, int height,
135  int linesize, int vflip)
136 {
137  uint8_t *dst;
138  uint32_t color[128], v[8];
139  int w, h, nb_colors, i, x, y, p0, p1, mask;
140 
141  if (bytestream2_get_bytes_left(gb) < 6)
142  return AVERROR_INVALIDDATA;
143 
144  w = bytestream2_get_be16u(gb);
145  h = bytestream2_get_be16u(gb);
146  if ((w & ~3) != width || (h & ~3) != height)
147  av_log(avctx, AV_LOG_WARNING, "dimension mismatch\n");
148 
149  if (bytestream2_get_byteu(gb)) {
150  avpriv_request_sample(avctx, "bitmap feature");
151  return AVERROR_PATCHWELCOME;
152  }
153 
154  nb_colors = bytestream2_get_byteu(gb);
155  if (bytestream2_get_bytes_left(gb) < nb_colors * 3)
156  return AVERROR_INVALIDDATA;
157  for (i = 0; i < FFMIN(nb_colors, 128); i++)
158  color[i] = 0xFF000000 | bytestream2_get_be24u(gb);
159  if (nb_colors > 128)
160  bytestream2_skip(gb, (nb_colors - 128) * 3);
161 
162  if (vflip) {
163  dst_start += (height - 1) * linesize;
164  linesize = -linesize;
165  }
166  x = y = 0;
167  while (bytestream2_get_bytes_left(gb) >= 1) {
168  p0 = bytestream2_get_byteu(gb);
169  if ((p0 & 0x80)) {
170  if ((p0 & 0x40)) {
171  p0 &= 0x3F;
172  p0 = (p0 << 2) | (p0 >> 4);
173  set_4x4_block(dst_start + y * linesize + x * 4, linesize,
174  0xFF000000 | (p0 << 16) | (p0 << 8) | p0);
175  } else {
176  int g, r;
177  p0 &= 0x3F;
178  p0 = (p0 << 2) | (p0 >> 4);
179  if (bytestream2_get_bytes_left(gb) < 2)
180  return AVERROR_INVALIDDATA;
181  g = bytestream2_get_byteu(gb);
182  r = bytestream2_get_byteu(gb);
183  set_4x4_block(dst_start + y * linesize + x * 4, linesize,
184  0xFF000000 | (r << 16) | (g << 8) | p0);
185  }
186  } else {
187  if (bytestream2_get_bytes_left(gb) < 1)
188  return AVERROR_INVALIDDATA;
189  p1 = bytestream2_get_byteu(gb);
190  if ((p1 & 0x80)) {
191  if ((p0 & 0x7F) == (p1 & 0x7F)) {
192  set_4x4_block(dst_start + y * linesize + x * 4, linesize,
193  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 
225 static int mvc_decode_frame(AVCodecContext *avctx, void *data, int *got_frame,
226  AVPacket *avpkt)
227 {
228  MvcContext *s = avctx->priv_data;
229  AVFrame *frame = data;
230  GetByteContext gb;
231  int ret;
232 
233  if ((ret = ff_get_buffer(avctx, frame, 0)) < 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, frame->data[0],
239  avctx->width, avctx->height, frame->linesize[0]);
240  else
241  ret = decode_mvc2(avctx, &gb, frame->data[0],
242  avctx->width, avctx->height, frame->linesize[0],
243  s->vflip);
244  if (ret < 0)
245  return ret;
246 
247  frame->pict_type = AV_PICTURE_TYPE_I;
248  frame->key_frame = 1;
249 
250  *got_frame = 1;
251 
252  return avpkt->size;
253 }
254 
255 #if CONFIG_MVC1_DECODER
256 AVCodec ff_mvc1_decoder = {
257  .name = "mvc1",
258  .long_name = NULL_IF_CONFIG_SMALL("Silicon Graphics Motion Video Compressor 1"),
259  .type = AVMEDIA_TYPE_VIDEO,
260  .id = AV_CODEC_ID_MVC1,
261  .priv_data_size = sizeof(MvcContext),
264  .capabilities = AV_CODEC_CAP_DR1,
265 };
266 #endif
267 
268 #if CONFIG_MVC2_DECODER
269 AVCodec ff_mvc2_decoder = {
270  .name = "mvc2",
271  .long_name = NULL_IF_CONFIG_SMALL("Silicon Graphics Motion Video Compressor 2"),
272  .type = AVMEDIA_TYPE_VIDEO,
273  .id = AV_CODEC_ID_MVC2,
274  .priv_data_size = sizeof(MvcContext),
277  .capabilities = AV_CODEC_CAP_DR1,
278 };
279 #endif
const char * s
Definition: avisynth_c.h:768
#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:184
static void set_4x4_block(uint8_t *dst, int linesize, uint32_t pixel)
Definition: mvcdec.c:108
ptrdiff_t const GLvoid * data
Definition: opengl_enc.c:101
#define AV_LOG_WARNING
Something somehow does not look correct.
Definition: log.h:182
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:210
const char * g
Definition: vf_curves.c:112
static av_cold int init(AVCodecContext *avctx)
Definition: avrndec.c:35
int size
Definition: avcodec.h:1601
enum AVPixelFormat pix_fmt
Pixel format, see AV_PIX_FMT_xxx.
Definition: avcodec.h:1903
static av_always_inline void bytestream2_init(GetByteContext *g, const uint8_t *buf, int buf_size)
Definition: bytestream.h:133
#define MVC2_BLOCK
Definition: mvcdec.c:127
AVCodec.
Definition: avcodec.h:3589
#define AV_WN32A(p, v)
Definition: intreadwrite.h:538
void void avpriv_request_sample(void *avc, const char *msg,...) av_printf_format(2
Log a generic warning message about a missing feature.
uint8_t
#define av_cold
Definition: attributes.h:82
#define ROW16(row, a1, a0, b1, b0)
uint8_t * extradata
some codecs need / can use extradata like Huffman tables.
Definition: avcodec.h:1790
static int mvc_decode_frame(AVCodecContext *avctx, void *data, int *got_frame, AVPacket *avpkt)
Definition: mvcdec.c:225
static AVFrame * frame
#define height
uint8_t * data
Definition: avcodec.h:1600
#define av_log(a,...)
static const uint16_t mask[17]
Definition: lzw.c:38
static av_always_inline void bytestream2_skip(GetByteContext *g, unsigned int size)
Definition: bytestream.h:164
#define NULL_IF_CONFIG_SMALL(x)
Return NULL if CONFIG_SMALL is true, otherwise the argument without modification. ...
Definition: internal.h:176
const char * r
Definition: vf_curves.c:111
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:154
const char * name
Name of the codec implementation.
Definition: avcodec.h:3596
enum AVPictureType pict_type
Picture type of the frame.
Definition: frame.h:258
#define FFMIN(a, b)
Definition: common.h:96
#define width
int width
picture width / height.
Definition: avcodec.h:1862
static int decode_mvc2(AVCodecContext *avctx, GetByteContext *gb, uint8_t *dst_start, int width, int height, int linesize, int vflip)
Definition: mvcdec.c:133
#define AVERROR_PATCHWELCOME
Not yet implemented in FFmpeg, patches welcome.
Definition: error.h:62
Libavcodec external API header.
enum AVCodecID codec_id
Definition: avcodec.h:1692
int linesize[AV_NUM_DATA_POINTERS]
For video, size in bytes of each picture line.
Definition: frame.h:215
main external API structure.
Definition: avcodec.h:1675
#define AV_PIX_FMT_RGB32
Definition: pixfmt.h:320
int ff_get_buffer(AVCodecContext *avctx, AVFrame *frame, int flags)
Get a buffer for a frame.
Definition: utils.c:934
int extradata_size
Definition: avcodec.h:1791
uint8_t pixel
Definition: tiny_ssim.c:42
uint8_t * data[AV_NUM_DATA_POINTERS]
pointer to the picture/channel planes.
Definition: frame.h:198
static int decode(AVCodecContext *avctx, void *data, int *got_sub, AVPacket *avpkt)
Definition: ccaption_dec.c:750
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:60
#define AV_PIX_FMT_RGB555
Definition: pixfmt.h:331
void * priv_data
Definition: avcodec.h:1717
int key_frame
1 -> keyframe, 0-> not
Definition: frame.h:253
This structure stores compressed data.
Definition: avcodec.h:1577
#define AV_CODEC_CAP_DR1
Codec uses get_buffer() for allocating buffers and supports custom allocators.
Definition: avcodec.h:958