FFmpeg  3.4.9
hnm4video.c
Go to the documentation of this file.
1 /*
2  * Cryo Interactive Entertainment HNM4 video decoder
3  *
4  * Copyright (c) 2012 David Kment
5  *
6  * This file is part of FFmpeg.
7  *
8  * FFmpeg is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Lesser General Public
10  * License as published by the Free Software Foundation; either
11  * version 2.1 of the License, or (at your option) any later version.
12  *
13  * FFmpeg is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16  * Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with FFmpeg; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21  */
22 
23 #include <string.h>
24 
25 #include "libavutil/imgutils.h"
26 #include "libavutil/internal.h"
27 #include "libavutil/intreadwrite.h"
28 #include "libavutil/mem.h"
29 #include "avcodec.h"
30 #include "bytestream.h"
31 #include "internal.h"
32 
33 #define HNM4_CHUNK_ID_PL 19536
34 #define HNM4_CHUNK_ID_IZ 23113
35 #define HNM4_CHUNK_ID_IU 21833
36 #define HNM4_CHUNK_ID_SD 17491
37 
38 typedef struct Hnm4VideoContext {
40  int width;
41  int height;
47  uint32_t palette[256];
49 
50 static int getbit(GetByteContext *gb, uint32_t *bitbuf, int *bits)
51 {
52  int ret;
53 
54  if (!*bits) {
55  *bitbuf = bytestream2_get_le32(gb);
56  *bits = 32;
57  }
58 
59  ret = *bitbuf >> 31;
60  *bitbuf <<= 1;
61  (*bits)--;
62 
63  return ret;
64 }
65 
67  uint32_t size)
68 {
69  Hnm4VideoContext *hnm = avctx->priv_data;
70  GetByteContext gb;
71  uint32_t bitbuf = 0, writeoffset = 0, count = 0;
72  uint16_t word;
74  int bits = 0;
75 
76  bytestream2_init(&gb, src, size);
77 
78  while (bytestream2_tell(&gb) < size) {
79  if (getbit(&gb, &bitbuf, &bits)) {
80  if (writeoffset >= hnm->width * hnm->height) {
81  av_log(avctx, AV_LOG_ERROR,
82  "Attempting to write out of bounds\n");
83  break;
84  }
85  hnm->current[writeoffset++] = bytestream2_get_byte(&gb);
86  } else {
87  if (getbit(&gb, &bitbuf, &bits)) {
88  word = bytestream2_get_le16(&gb);
89  count = word & 0x07;
90  offset = (word >> 3) - 0x2000;
91  if (!count)
92  count = bytestream2_get_byte(&gb);
93  if (!count)
94  return;
95  } else {
96  count = getbit(&gb, &bitbuf, &bits) * 2;
97  count += getbit(&gb, &bitbuf, &bits);
98  offset = bytestream2_get_byte(&gb) - 0x0100;
99  }
100  count += 2;
101  offset += writeoffset;
102  if (offset < 0 || offset + count >= hnm->width * hnm->height) {
103  av_log(avctx, AV_LOG_ERROR, "Attempting to read out of bounds\n");
104  break;
105  } else if (writeoffset + count >= hnm->width * hnm->height) {
106  av_log(avctx, AV_LOG_ERROR,
107  "Attempting to write out of bounds\n");
108  break;
109  }
110  while (count--) {
111  hnm->current[writeoffset++] = hnm->current[offset++];
112  }
113  }
114  }
115 }
116 
118 {
119  Hnm4VideoContext *hnm = avctx->priv_data;
120  uint32_t x, y, src_y;
121  int width = hnm->width;
122 
123  for (y = 0; y < hnm->height; y++) {
124  uint8_t *dst = hnm->processed + y * width;
125  const uint8_t *src = hnm->current;
126  src_y = y - (y % 2);
127  src += src_y * width + (y % 2);
128  for (x = 0; x < width; x++) {
129  dst[x] = *src;
130  src += 2;
131  }
132  }
133 }
134 
136 {
137  Hnm4VideoContext *hnm = avctx->priv_data;
138  uint8_t *src = hnm->processed;
139  uint8_t *dst = frame->data[0];
140  int y;
141 
142  for (y = 0; y < hnm->height; y++) {
143  memcpy(dst, src, hnm->width);
144  src += hnm->width;
145  dst += frame->linesize[0];
146  }
147 }
148 
149 static int decode_interframe_v4(AVCodecContext *avctx, uint8_t *src, uint32_t size)
150 {
151  Hnm4VideoContext *hnm = avctx->priv_data;
152  GetByteContext gb;
153  uint32_t writeoffset = 0;
154  int count, left, offset;
155  uint8_t tag, previous, backline, backward, swap;
156 
157  bytestream2_init(&gb, src, size);
158 
159  while (bytestream2_tell(&gb) < size) {
160  count = bytestream2_peek_byte(&gb) & 0x1F;
161  if (count == 0) {
162  tag = bytestream2_get_byte(&gb) & 0xE0;
163  tag = tag >> 5;
164 
165  if (tag == 0) {
166  if (writeoffset + 2 > hnm->width * hnm->height) {
167  av_log(avctx, AV_LOG_ERROR, "writeoffset out of bounds\n");
168  return AVERROR_INVALIDDATA;
169  }
170  hnm->current[writeoffset++] = bytestream2_get_byte(&gb);
171  hnm->current[writeoffset++] = bytestream2_get_byte(&gb);
172  } else if (tag == 1) {
173  writeoffset += bytestream2_get_byte(&gb) * 2;
174  } else if (tag == 2) {
175  count = bytestream2_get_le16(&gb);
176  count *= 2;
177  writeoffset += count;
178  } else if (tag == 3) {
179  count = bytestream2_get_byte(&gb) * 2;
180  if (writeoffset + count > hnm->width * hnm->height) {
181  av_log(avctx, AV_LOG_ERROR, "writeoffset out of bounds\n");
182  return AVERROR_INVALIDDATA;
183  }
184  while (count > 0) {
185  hnm->current[writeoffset++] = bytestream2_peek_byte(&gb);
186  count--;
187  }
188  bytestream2_skip(&gb, 1);
189  } else {
190  break;
191  }
192  if (writeoffset > hnm->width * hnm->height) {
193  av_log(avctx, AV_LOG_ERROR, "writeoffset out of bounds\n");
194  return AVERROR_INVALIDDATA;
195  }
196  } else {
197  previous = bytestream2_peek_byte(&gb) & 0x20;
198  backline = bytestream2_peek_byte(&gb) & 0x40;
199  backward = bytestream2_peek_byte(&gb) & 0x80;
200  bytestream2_skip(&gb, 1);
201  swap = bytestream2_peek_byte(&gb) & 0x01;
202  offset = bytestream2_get_le16(&gb);
203  offset = (offset >> 1) & 0x7FFF;
204  offset = writeoffset + (offset * 2) - 0x8000;
205 
206  left = count;
207 
208  if (!backward && offset + 2*count > hnm->width * hnm->height) {
209  av_log(avctx, AV_LOG_ERROR, "Attempting to read out of bounds\n");
210  return AVERROR_INVALIDDATA;
211  } else if (backward && offset + 1 >= hnm->width * hnm->height) {
212  av_log(avctx, AV_LOG_ERROR, "Attempting to read out of bounds\n");
213  return AVERROR_INVALIDDATA;
214  } else if (writeoffset + 2*count > hnm->width * hnm->height) {
215  av_log(avctx, AV_LOG_ERROR,
216  "Attempting to write out of bounds\n");
217  return AVERROR_INVALIDDATA;
218 
219  }
220  if(backward) {
221  if (offset < (!!backline)*(2 * hnm->width - 1) + 2*(left-1)) {
222  av_log(avctx, AV_LOG_ERROR, "Attempting to read out of bounds\n");
223  return AVERROR_INVALIDDATA;
224  }
225  } else {
226  if (offset < (!!backline)*(2 * hnm->width - 1)) {
227  av_log(avctx, AV_LOG_ERROR, "Attempting to read out of bounds\n");
228  return AVERROR_INVALIDDATA;
229  }
230  }
231 
232  if (previous) {
233  while (left > 0) {
234  if (backline) {
235  hnm->current[writeoffset++] = hnm->previous[offset - (2 * hnm->width) + 1];
236  hnm->current[writeoffset++] = hnm->previous[offset++];
237  offset++;
238  } else {
239  hnm->current[writeoffset++] = hnm->previous[offset++];
240  hnm->current[writeoffset++] = hnm->previous[offset++];
241  }
242  if (backward)
243  offset -= 4;
244  left--;
245  }
246  } else {
247  while (left > 0) {
248  if (backline) {
249  hnm->current[writeoffset++] = hnm->current[offset - (2 * hnm->width) + 1];
250  hnm->current[writeoffset++] = hnm->current[offset++];
251  offset++;
252  } else {
253  hnm->current[writeoffset++] = hnm->current[offset++];
254  hnm->current[writeoffset++] = hnm->current[offset++];
255  }
256  if (backward)
257  offset -= 4;
258  left--;
259  }
260  }
261 
262  if (swap) {
263  left = count;
264  writeoffset -= count * 2;
265  while (left > 0) {
266  swap = hnm->current[writeoffset];
267  hnm->current[writeoffset] = hnm->current[writeoffset + 1];
268  hnm->current[writeoffset + 1] = swap;
269  left--;
270  writeoffset += 2;
271  }
272  }
273  }
274  }
275  return 0;
276 }
277 
279  uint32_t size)
280 {
281  Hnm4VideoContext *hnm = avctx->priv_data;
282  GetByteContext gb;
283  uint32_t writeoffset = 0, offset;
285 
286  bytestream2_init(&gb, src, size);
287 
288  while (bytestream2_tell(&gb) < size) {
289  count = bytestream2_peek_byte(&gb) & 0x3F;
290  if (count == 0) {
291  tag = bytestream2_get_byte(&gb) & 0xC0;
292  tag = tag >> 6;
293  if (tag == 0) {
294  writeoffset += bytestream2_get_byte(&gb);
295  } else if (tag == 1) {
296  if (writeoffset + hnm->width >= hnm->width * hnm->height) {
297  av_log(avctx, AV_LOG_ERROR, "writeoffset out of bounds\n");
298  break;
299  }
300  hnm->current[writeoffset] = bytestream2_get_byte(&gb);
301  hnm->current[writeoffset + hnm->width] = bytestream2_get_byte(&gb);
302  writeoffset++;
303  } else if (tag == 2) {
304  writeoffset += hnm->width;
305  } else if (tag == 3) {
306  break;
307  }
308  if (writeoffset > hnm->width * hnm->height) {
309  av_log(avctx, AV_LOG_ERROR, "writeoffset out of bounds\n");
310  break;
311  }
312  } else {
313  delta = bytestream2_peek_byte(&gb) & 0x80;
314  previous = bytestream2_peek_byte(&gb) & 0x40;
315  bytestream2_skip(&gb, 1);
316 
317  offset = writeoffset;
318  offset += bytestream2_get_le16(&gb);
319 
320  if (delta) {
321  if (offset < 0x10000) {
322  av_log(avctx, AV_LOG_ERROR, "Attempting to read out of bounds\n");
323  break;
324  }
325  offset -= 0x10000;
326  }
327 
328  if (offset + hnm->width + count >= hnm->width * hnm->height) {
329  av_log(avctx, AV_LOG_ERROR, "Attempting to read out of bounds\n");
330  break;
331  } else if (writeoffset + hnm->width + count >= hnm->width * hnm->height) {
332  av_log(avctx, AV_LOG_ERROR, "Attempting to write out of bounds\n");
333  break;
334  }
335 
336  if (previous) {
337  while (count > 0) {
338  hnm->current[writeoffset] = hnm->previous[offset];
339  hnm->current[writeoffset + hnm->width] = hnm->previous[offset + hnm->width];
340  writeoffset++;
341  offset++;
342  count--;
343  }
344  } else {
345  while (count > 0) {
346  hnm->current[writeoffset] = hnm->current[offset];
347  hnm->current[writeoffset + hnm->width] = hnm->current[offset + hnm->width];
348  writeoffset++;
349  offset++;
350  count--;
351  }
352  }
353  }
354  }
355 }
356 
358  uint32_t size)
359 {
360  Hnm4VideoContext *hnm = avctx->priv_data;
361  GetByteContext gb;
362  uint8_t start, writeoffset;
363  uint16_t count;
364  int eight_bit_colors;
365 
366  eight_bit_colors = src[7] & 0x80 && hnm->version == 0x4a;
367 
368  // skip first 8 bytes
369  bytestream2_init(&gb, src + 8, size - 8);
370 
371  while (bytestream2_tell(&gb) < size - 8) {
372  start = bytestream2_get_byte(&gb);
373  count = bytestream2_get_byte(&gb);
374  if (start == 255 && count == 255)
375  break;
376  if (count == 0)
377  count = 256;
378  writeoffset = start;
379  while (count > 0) {
380  hnm->palette[writeoffset] = bytestream2_get_be24(&gb);
381  if (!eight_bit_colors)
382  hnm->palette[writeoffset] <<= 2;
383  count--;
384  writeoffset++;
385  }
386  }
387 }
388 
390 {
391  uint8_t *temp;
392 
393  temp = hnm->current;
394  hnm->current = hnm->previous;
395  hnm->previous = temp;
396 }
397 
398 static int hnm_decode_frame(AVCodecContext *avctx, void *data,
399  int *got_frame, AVPacket *avpkt)
400 {
401  AVFrame *frame = data;
402  Hnm4VideoContext *hnm = avctx->priv_data;
403  int ret;
404  uint16_t chunk_id;
405 
406  if (avpkt->size < 8) {
407  av_log(avctx, AV_LOG_ERROR, "packet too small\n");
408  return AVERROR_INVALIDDATA;
409  }
410 
411  chunk_id = AV_RL16(avpkt->data + 4);
412 
413  if (chunk_id == HNM4_CHUNK_ID_PL) {
414  hnm_update_palette(avctx, avpkt->data, avpkt->size);
415  } else if (chunk_id == HNM4_CHUNK_ID_IZ) {
416  if (avpkt->size < 12) {
417  av_log(avctx, AV_LOG_ERROR, "packet too small\n");
418  return AVERROR_INVALIDDATA;
419  }
420  if ((ret = ff_get_buffer(avctx, frame, 0)) < 0)
421  return ret;
422 
423  unpack_intraframe(avctx, avpkt->data + 12, avpkt->size - 12);
424  memcpy(hnm->previous, hnm->current, hnm->width * hnm->height);
425  if (hnm->version == 0x4a)
426  memcpy(hnm->processed, hnm->current, hnm->width * hnm->height);
427  else
429  copy_processed_frame(avctx, frame);
430  frame->pict_type = AV_PICTURE_TYPE_I;
431  frame->key_frame = 1;
432  memcpy(frame->data[1], hnm->palette, 256 * 4);
433  *got_frame = 1;
434  } else if (chunk_id == HNM4_CHUNK_ID_IU) {
435  if ((ret = ff_get_buffer(avctx, frame, 0)) < 0)
436  return ret;
437 
438  if (hnm->version == 0x4a) {
439  decode_interframe_v4a(avctx, avpkt->data + 8, avpkt->size - 8);
440  memcpy(hnm->processed, hnm->current, hnm->width * hnm->height);
441  } else {
442  int ret = decode_interframe_v4(avctx, avpkt->data + 8, avpkt->size - 8);
443  if (ret < 0)
444  return ret;
446  }
447  copy_processed_frame(avctx, frame);
448  frame->pict_type = AV_PICTURE_TYPE_P;
449  frame->key_frame = 0;
450  memcpy(frame->data[1], hnm->palette, 256 * 4);
451  *got_frame = 1;
452  hnm_flip_buffers(hnm);
453  } else {
454  av_log(avctx, AV_LOG_ERROR, "invalid chunk id: %d\n", chunk_id);
455  return AVERROR_INVALIDDATA;
456  }
457 
458  return avpkt->size;
459 }
460 
462 {
463  Hnm4VideoContext *hnm = avctx->priv_data;
464  int ret;
465 
466  if (avctx->extradata_size < 1) {
467  av_log(avctx, AV_LOG_ERROR,
468  "Extradata missing, decoder requires version number\n");
469  return AVERROR_INVALIDDATA;
470  }
471 
472  ret = av_image_check_size(avctx->width, avctx->height, 0, avctx);
473  if (ret < 0)
474  return ret;
475 
476  hnm->version = avctx->extradata[0];
477  avctx->pix_fmt = AV_PIX_FMT_PAL8;
478  hnm->width = avctx->width;
479  hnm->height = avctx->height;
480  hnm->buffer1 = av_mallocz(avctx->width * avctx->height);
481  hnm->buffer2 = av_mallocz(avctx->width * avctx->height);
482  hnm->processed = av_mallocz(avctx->width * avctx->height);
483 
484  if ( !hnm->buffer1 || !hnm->buffer2 || !hnm->processed
485  || avctx->width * avctx->height == 0
486  || avctx->height % 2) {
487  av_log(avctx, AV_LOG_ERROR, "av_mallocz() failed\n");
488  av_freep(&hnm->buffer1);
489  av_freep(&hnm->buffer2);
490  av_freep(&hnm->processed);
491  return AVERROR(ENOMEM);
492  }
493 
494  hnm->current = hnm->buffer1;
495  hnm->previous = hnm->buffer2;
496 
497  return 0;
498 }
499 
501 {
502  Hnm4VideoContext *hnm = avctx->priv_data;
503 
504  av_freep(&hnm->buffer1);
505  av_freep(&hnm->buffer2);
506  av_freep(&hnm->processed);
507 
508  return 0;
509 }
510 
512  .name = "hnm4video",
513  .long_name = NULL_IF_CONFIG_SMALL("HNM 4 video"),
514  .type = AVMEDIA_TYPE_VIDEO,
516  .priv_data_size = sizeof(Hnm4VideoContext),
518  .close = hnm_decode_end,
520  .capabilities = AV_CODEC_CAP_DR1,
521 };
#define AVERROR_INVALIDDATA
Invalid data found when processing input.
Definition: error.h:59
int size
This structure describes decoded (raw) audio or video data.
Definition: frame.h:201
misc image utilities
Memory handling functions.
else temp
Definition: vf_mcdeint.c:256
static av_cold int init(AVCodecContext *avctx)
Definition: avrndec.c:35
uint8_t * processed
Definition: hnm4video.c:46
int size
Definition: avcodec.h:1680
static int decode_interframe_v4(AVCodecContext *avctx, uint8_t *src, uint32_t size)
Definition: hnm4video.c:149
enum AVPixelFormat pix_fmt
Pixel format, see AV_PIX_FMT_xxx.
Definition: avcodec.h:1989
static av_always_inline void bytestream2_init(GetByteContext *g, const uint8_t *buf, int buf_size)
Definition: bytestream.h:133
#define AV_RL16
Definition: intreadwrite.h:42
#define src
Definition: vp8dsp.c:254
AVCodec.
Definition: avcodec.h:3739
static void decode(AVCodecContext *dec_ctx, AVPacket *pkt, AVFrame *frame, FILE *outfile)
Definition: decode_audio.c:42
uint8_t * buffer2
Definition: hnm4video.c:45
#define HNM4_CHUNK_ID_IZ
Definition: hnm4video.c:34
uint8_t bits
Definition: crc.c:296
uint8_t version
Definition: hnm4video.c:39
uint8_t
#define av_cold
Definition: attributes.h:82
float delta
8 bits with AV_PIX_FMT_RGB32 palette
Definition: pixfmt.h:77
uint8_t * extradata
some codecs need / can use extradata like Huffman tables.
Definition: avcodec.h:1876
static int getbit(GetByteContext *gb, uint32_t *bitbuf, int *bits)
Definition: hnm4video.c:50
static AVFrame * frame
const char data[16]
Definition: mxf.c:90
uint8_t * data
Definition: avcodec.h:1679
uint32_t tag
Definition: movenc.c:1414
static void unpack_intraframe(AVCodecContext *avctx, uint8_t *src, uint32_t size)
Definition: hnm4video.c:66
#define av_log(a,...)
static void copy_processed_frame(AVCodecContext *avctx, AVFrame *frame)
Definition: hnm4video.c:135
static void decode_interframe_v4a(AVCodecContext *avctx, uint8_t *src, uint32_t size)
Definition: hnm4video.c:278
#define AV_LOG_ERROR
Something went wrong and cannot losslessly be recovered.
Definition: log.h:176
#define AVERROR(e)
Definition: error.h:43
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:181
void * av_mallocz(size_t size)
Allocate a memory block with alignment suitable for all memory accesses (including vectors if availab...
Definition: mem.c:222
const char * name
Name of the codec implementation.
Definition: avcodec.h:3746
static const uint8_t offset[127][2]
Definition: vf_spp.c:92
uint8_t * buffer1
Definition: hnm4video.c:44
common internal API header
int av_image_check_size(unsigned int w, unsigned int h, int log_offset, void *log_ctx)
Check if the given dimension of an image is valid, meaning that all bytes of the image can be address...
Definition: imgutils.c:281
enum AVPictureType pict_type
Picture type of the frame.
Definition: frame.h:284
uint8_t * current
Definition: hnm4video.c:42
int width
picture width / height.
Definition: avcodec.h:1948
int32_t
uint8_t * previous
Definition: hnm4video.c:43
static av_cold int hnm_decode_end(AVCodecContext *avctx)
Definition: hnm4video.c:500
static av_always_inline int bytestream2_tell(GetByteContext *g)
Definition: bytestream.h:188
Libavcodec external API header.
int linesize[AV_NUM_DATA_POINTERS]
For video, size in bytes of each picture line.
Definition: frame.h:232
#define HNM4_CHUNK_ID_PL
Definition: hnm4video.c:33
main external API structure.
Definition: avcodec.h:1761
int ff_get_buffer(AVCodecContext *avctx, AVFrame *frame, int flags)
Get a buffer for a frame.
Definition: decode.c:1669
int extradata_size
Definition: avcodec.h:1877
#define HNM4_CHUNK_ID_IU
Definition: hnm4video.c:35
static void hnm_flip_buffers(Hnm4VideoContext *hnm)
Definition: hnm4video.c:389
static av_cold int hnm_decode_init(AVCodecContext *avctx)
Definition: hnm4video.c:461
uint8_t * data[AV_NUM_DATA_POINTERS]
pointer to the picture/channel planes.
Definition: frame.h:215
common internal api header.
static int hnm_decode_frame(AVCodecContext *avctx, void *data, int *got_frame, AVPacket *avpkt)
Definition: hnm4video.c:398
static void hnm_update_palette(AVCodecContext *avctx, uint8_t *src, uint32_t size)
Definition: hnm4video.c:357
void * priv_data
Definition: avcodec.h:1803
int key_frame
1 -> keyframe, 0-> not
Definition: frame.h:279
uint32_t palette[256]
Definition: hnm4video.c:47
static void postprocess_current_frame(AVCodecContext *avctx)
Definition: hnm4video.c:117
#define av_freep(p)
void INT64 INT64 count
Definition: avisynth_c.h:690
void INT64 start
Definition: avisynth_c.h:690
AVCodec ff_hnm4_video_decoder
Definition: hnm4video.c:511
This structure stores compressed data.
Definition: avcodec.h:1656
#define AV_CODEC_CAP_DR1
Codec uses get_buffer() for allocating buffers and supports custom allocators.
Definition: avcodec.h:1002
Predicted.
Definition: avutil.h:275