mmvideo.c
Go to the documentation of this file.
1 /*
2  * American Laser Games MM Video Decoder
3  * Copyright (c) 2006,2008 Peter Ross
4  *
5  * This file is part of Libav.
6  *
7  * Libav 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  * Libav 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 Libav; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20  */
21 
34 #include "libavutil/intreadwrite.h"
35 #include "avcodec.h"
36 #include "bytestream.h"
37 
38 #define MM_PREAMBLE_SIZE 6
39 
40 #define MM_TYPE_INTER 0x5
41 #define MM_TYPE_INTRA 0x8
42 #define MM_TYPE_INTRA_HH 0xc
43 #define MM_TYPE_INTER_HH 0xd
44 #define MM_TYPE_INTRA_HHV 0xe
45 #define MM_TYPE_INTER_HHV 0xf
46 #define MM_TYPE_PALETTE 0x31
47 
48 typedef struct MmContext {
53 } MmContext;
54 
56 {
57  MmContext *s = avctx->priv_data;
58 
59  s->avctx = avctx;
60 
61  avctx->pix_fmt = AV_PIX_FMT_PAL8;
62 
63  if (!avctx->width || !avctx->height ||
64  (avctx->width & 1) || (avctx->height & 1)) {
65  av_log(avctx, AV_LOG_ERROR, "Invalid video dimensions: %dx%d\n",
66  avctx->width, avctx->height);
67  return AVERROR(EINVAL);
68  }
69 
70  s->frame.reference = 1;
71 
72  return 0;
73 }
74 
75 static int mm_decode_pal(MmContext *s)
76 {
77  int i;
78 
79  bytestream2_skip(&s->gb, 4);
80  for (i = 0; i < 128; i++) {
81  s->palette[i] = bytestream2_get_be24(&s->gb);
82  s->palette[i+128] = s->palette[i]<<2;
83  }
84 
85  return 0;
86 }
87 
92 static int mm_decode_intra(MmContext * s, int half_horiz, int half_vert)
93 {
94  int x = 0, y = 0;
95 
96  while (bytestream2_get_bytes_left(&s->gb) > 0) {
97  int run_length, color;
98 
99  if (y >= s->avctx->height)
100  return 0;
101 
102  color = bytestream2_get_byte(&s->gb);
103  if (color & 0x80) {
104  run_length = 1;
105  }else{
106  run_length = (color & 0x7f) + 2;
107  color = bytestream2_get_byte(&s->gb);
108  }
109 
110  if (half_horiz)
111  run_length *=2;
112 
113  if (color) {
114  memset(s->frame.data[0] + y*s->frame.linesize[0] + x, color, run_length);
115  if (half_vert)
116  memset(s->frame.data[0] + (y+1)*s->frame.linesize[0] + x, color, run_length);
117  }
118  x+= run_length;
119 
120  if (x >= s->avctx->width) {
121  x=0;
122  y += 1 + half_vert;
123  }
124  }
125 
126  return 0;
127 }
128 
129 /*
130  * @param half_horiz Half horizontal resolution (0 or 1)
131  * @param half_vert Half vertical resolution (0 or 1)
132  */
133 static int mm_decode_inter(MmContext * s, int half_horiz, int half_vert)
134 {
135  int data_off = bytestream2_get_le16(&s->gb), y;
136  GetByteContext data_ptr;
137 
138  if (bytestream2_get_bytes_left(&s->gb) < data_off)
139  return AVERROR_INVALIDDATA;
140 
141  bytestream2_init(&data_ptr, s->gb.buffer + data_off, bytestream2_get_bytes_left(&s->gb) - data_off);
142  while (s->gb.buffer < data_ptr.buffer_start) {
143  int i, j;
144  int length = bytestream2_get_byte(&s->gb);
145  int x = bytestream2_get_byte(&s->gb) + ((length & 0x80) << 1);
146  length &= 0x7F;
147 
148  if (length==0) {
149  y += x;
150  continue;
151  }
152 
153  if (y + half_vert >= s->avctx->height)
154  return 0;
155 
156  for(i=0; i<length; i++) {
157  int replace_array = bytestream2_get_byte(&s->gb);
158  for(j=0; j<8; j++) {
159  int replace = (replace_array >> (7-j)) & 1;
160  if (x + half_horiz >= s->avctx->width)
161  return AVERROR_INVALIDDATA;
162  if (replace) {
163  int color = bytestream2_get_byte(&data_ptr);
164  s->frame.data[0][y*s->frame.linesize[0] + x] = color;
165  if (half_horiz)
166  s->frame.data[0][y*s->frame.linesize[0] + x + 1] = color;
167  if (half_vert) {
168  s->frame.data[0][(y+1)*s->frame.linesize[0] + x] = color;
169  if (half_horiz)
170  s->frame.data[0][(y+1)*s->frame.linesize[0] + x + 1] = color;
171  }
172  }
173  x += 1 + half_horiz;
174  }
175  }
176 
177  y += 1 + half_vert;
178  }
179 
180  return 0;
181 }
182 
183 static int mm_decode_frame(AVCodecContext *avctx,
184  void *data, int *got_frame,
185  AVPacket *avpkt)
186 {
187  const uint8_t *buf = avpkt->data;
188  int buf_size = avpkt->size;
189  MmContext *s = avctx->priv_data;
190  int type, res;
191 
192  if (buf_size < MM_PREAMBLE_SIZE)
193  return AVERROR_INVALIDDATA;
194  type = AV_RL16(&buf[0]);
195  buf += MM_PREAMBLE_SIZE;
196  buf_size -= MM_PREAMBLE_SIZE;
197  bytestream2_init(&s->gb, buf, buf_size);
198 
199  if (avctx->reget_buffer(avctx, &s->frame) < 0) {
200  av_log(avctx, AV_LOG_ERROR, "reget_buffer() failed\n");
201  return -1;
202  }
203 
204  switch(type) {
205  case MM_TYPE_PALETTE : res = mm_decode_pal(s); return buf_size;
206  case MM_TYPE_INTRA : res = mm_decode_intra(s, 0, 0); break;
207  case MM_TYPE_INTRA_HH : res = mm_decode_intra(s, 1, 0); break;
208  case MM_TYPE_INTRA_HHV : res = mm_decode_intra(s, 1, 1); break;
209  case MM_TYPE_INTER : res = mm_decode_inter(s, 0, 0); break;
210  case MM_TYPE_INTER_HH : res = mm_decode_inter(s, 1, 0); break;
211  case MM_TYPE_INTER_HHV : res = mm_decode_inter(s, 1, 1); break;
212  default:
213  res = AVERROR_INVALIDDATA;
214  break;
215  }
216  if (res < 0)
217  return res;
218 
219  memcpy(s->frame.data[1], s->palette, AVPALETTE_SIZE);
220 
221  *got_frame = 1;
222  *(AVFrame*)data = s->frame;
223 
224  return buf_size;
225 }
226 
228 {
229  MmContext *s = avctx->priv_data;
230 
231  if(s->frame.data[0])
232  avctx->release_buffer(avctx, &s->frame);
233 
234  return 0;
235 }
236 
238  .name = "mmvideo",
239  .type = AVMEDIA_TYPE_VIDEO,
240  .id = AV_CODEC_ID_MMVIDEO,
241  .priv_data_size = sizeof(MmContext),
242  .init = mm_decode_init,
243  .close = mm_decode_end,
245  .capabilities = CODEC_CAP_DR1,
246  .long_name = NULL_IF_CONFIG_SMALL("American Laser Games MM Video"),
247 };
AVFrame frame
Definition: mmvideo.c:50
static int mm_decode_pal(MmContext *s)
Definition: mmvideo.c:75
This structure describes decoded (raw) audio or video data.
Definition: avcodec.h:989
static int mm_decode_intra(MmContext *s, int half_horiz, int half_vert)
Definition: mmvideo.c:92
void(* release_buffer)(struct AVCodecContext *c, AVFrame *pic)
Called to release buffers which were allocated with get_buffer.
Definition: avcodec.h:2259
int size
Definition: avcodec.h:916
enum AVPixelFormat pix_fmt
Pixel format, see AV_PIX_FMT_xxx.
Definition: avcodec.h:1533
static av_always_inline void bytestream2_init(GetByteContext *g, const uint8_t *buf, int buf_size)
Definition: bytestream.h:130
#define AV_RL16
Definition: intreadwrite.h:42
#define MM_TYPE_INTER_HH
Definition: mmvideo.c:43
AVCodec.
Definition: avcodec.h:2960
int(* reget_buffer)(struct AVCodecContext *c, AVFrame *pic)
Called at the beginning of a frame to get cr buffer for it.
Definition: avcodec.h:2273
static int decode(MimicContext *ctx, int quality, int num_coeffs, int is_iframe)
Definition: mimic.c:228
uint8_t
8 bit with PIX_FMT_RGB32 palette
Definition: pixfmt.h:76
static int mm_decode_frame(AVCodecContext *avctx, void *data, int *got_frame, AVPacket *avpkt)
Definition: mmvideo.c:183
const char data[16]
Definition: mxf.c:66
uint8_t * data
Definition: avcodec.h:915
const uint8_t * buffer
Definition: bytestream.h:33
static int init(AVCodecParserContext *s)
Definition: h264_parser.c:335
int palette[AVPALETTE_COUNT]
Definition: mmvideo.c:51
int reference
is this picture used as reference The values for this are the same as the MpegEncContext.picture_structure variable, that is 1->top field, 2->bottom field, 3->frame/both fields.
Definition: avcodec.h:1132
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. ...
Definition: internal.h:88
static av_always_inline unsigned int bytestream2_get_bytes_left(GetByteContext *g)
Definition: bytestream.h:149
static av_cold int mm_decode_end(AVCodecContext *avctx)
Definition: mmvideo.c:227
void av_log(void *avcl, int level, const char *fmt,...)
Definition: log.c:146
const char * name
Name of the codec implementation.
Definition: avcodec.h:2967
#define MM_PREAMBLE_SIZE
Definition: mmvideo.c:38
int width
picture width / height.
Definition: avcodec.h:1508
#define MM_TYPE_INTER
Definition: mmvideo.c:40
#define MM_TYPE_INTRA_HHV
Definition: mmvideo.c:44
#define MM_TYPE_PALETTE
Definition: mmvideo.c:46
AVCodec ff_mmvideo_decoder
Definition: mmvideo.c:237
static int mm_decode_inter(MmContext *s, int half_horiz, int half_vert)
Definition: mmvideo.c:133
struct MmContext MmContext
#define MM_TYPE_INTRA_HH
Definition: mmvideo.c:42
external API header
int linesize[AV_NUM_DATA_POINTERS]
Size, in bytes, of the data for each picture/channel plane.
Definition: avcodec.h:1008
main external API structure.
Definition: avcodec.h:1339
static void close(AVCodecParserContext *s)
Definition: h264_parser.c:326
static av_cold int mm_decode_init(AVCodecContext *avctx)
Definition: mmvideo.c:55
const uint8_t * buffer_start
Definition: bytestream.h:33
#define MM_TYPE_INTRA
Definition: mmvideo.c:41
#define MM_TYPE_INTER_HHV
Definition: mmvideo.c:45
uint8_t * data[AV_NUM_DATA_POINTERS]
pointer to the picture/channel planes.
Definition: avcodec.h:997
GetByteContext gb
Definition: mmvideo.c:52
AVCodecContext * avctx
Definition: mmvideo.c:49
static const uint8_t color[]
Definition: log.c:52
void * priv_data
Definition: avcodec.h:1382
This structure stores compressed data.
Definition: avcodec.h:898
if(!(ptr_align%ac->ptr_align)&&samples_align >=aligned_len)