FFmpeg  4.1.11
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  hnm->palette[writeoffset] |= (0xFFU << 24);
384  count--;
385  writeoffset++;
386  }
387  }
388 }
389 
391 {
392  uint8_t *temp;
393 
394  temp = hnm->current;
395  hnm->current = hnm->previous;
396  hnm->previous = temp;
397 }
398 
399 static int hnm_decode_frame(AVCodecContext *avctx, void *data,
400  int *got_frame, AVPacket *avpkt)
401 {
402  AVFrame *frame = data;
403  Hnm4VideoContext *hnm = avctx->priv_data;
404  int ret;
405  uint16_t chunk_id;
406 
407  if (avpkt->size < 8) {
408  av_log(avctx, AV_LOG_ERROR, "packet too small\n");
409  return AVERROR_INVALIDDATA;
410  }
411 
412  chunk_id = AV_RL16(avpkt->data + 4);
413 
414  if (chunk_id == HNM4_CHUNK_ID_PL) {
415  hnm_update_palette(avctx, avpkt->data, avpkt->size);
416  } else if (chunk_id == HNM4_CHUNK_ID_IZ) {
417  if (avpkt->size < 12) {
418  av_log(avctx, AV_LOG_ERROR, "packet too small\n");
419  return AVERROR_INVALIDDATA;
420  }
421  if ((ret = ff_get_buffer(avctx, frame, 0)) < 0)
422  return ret;
423 
424  unpack_intraframe(avctx, avpkt->data + 12, avpkt->size - 12);
425  memcpy(hnm->previous, hnm->current, hnm->width * hnm->height);
426  if (hnm->version == 0x4a)
427  memcpy(hnm->processed, hnm->current, hnm->width * hnm->height);
428  else
430  copy_processed_frame(avctx, frame);
431  frame->pict_type = AV_PICTURE_TYPE_I;
432  frame->key_frame = 1;
433  memcpy(frame->data[1], hnm->palette, 256 * 4);
434  *got_frame = 1;
435  } else if (chunk_id == HNM4_CHUNK_ID_IU) {
436  if ((ret = ff_get_buffer(avctx, frame, 0)) < 0)
437  return ret;
438 
439  if (hnm->version == 0x4a) {
440  decode_interframe_v4a(avctx, avpkt->data + 8, avpkt->size - 8);
441  memcpy(hnm->processed, hnm->current, hnm->width * hnm->height);
442  } else {
443  int ret = decode_interframe_v4(avctx, avpkt->data + 8, avpkt->size - 8);
444  if (ret < 0)
445  return ret;
447  }
448  copy_processed_frame(avctx, frame);
449  frame->pict_type = AV_PICTURE_TYPE_P;
450  frame->key_frame = 0;
451  memcpy(frame->data[1], hnm->palette, 256 * 4);
452  *got_frame = 1;
453  hnm_flip_buffers(hnm);
454  } else {
455  av_log(avctx, AV_LOG_ERROR, "invalid chunk id: %d\n", chunk_id);
456  return AVERROR_INVALIDDATA;
457  }
458 
459  return avpkt->size;
460 }
461 
463 {
464  Hnm4VideoContext *hnm = avctx->priv_data;
465  int ret;
466 
467  if (avctx->extradata_size < 1) {
468  av_log(avctx, AV_LOG_ERROR,
469  "Extradata missing, decoder requires version number\n");
470  return AVERROR_INVALIDDATA;
471  }
472 
473  ret = av_image_check_size(avctx->width, avctx->height, 0, avctx);
474  if (ret < 0)
475  return ret;
476 
477  hnm->version = avctx->extradata[0];
478  avctx->pix_fmt = AV_PIX_FMT_PAL8;
479  hnm->width = avctx->width;
480  hnm->height = avctx->height;
481  hnm->buffer1 = av_mallocz(avctx->width * avctx->height);
482  hnm->buffer2 = av_mallocz(avctx->width * avctx->height);
483  hnm->processed = av_mallocz(avctx->width * avctx->height);
484 
485  if ( !hnm->buffer1 || !hnm->buffer2 || !hnm->processed
486  || avctx->width * avctx->height == 0
487  || avctx->height % 2) {
488  av_log(avctx, AV_LOG_ERROR, "av_mallocz() failed\n");
489  av_freep(&hnm->buffer1);
490  av_freep(&hnm->buffer2);
491  av_freep(&hnm->processed);
492  return AVERROR(ENOMEM);
493  }
494 
495  hnm->current = hnm->buffer1;
496  hnm->previous = hnm->buffer2;
497 
498  return 0;
499 }
500 
502 {
503  Hnm4VideoContext *hnm = avctx->priv_data;
504 
505  av_freep(&hnm->buffer1);
506  av_freep(&hnm->buffer2);
507  av_freep(&hnm->processed);
508 
509  return 0;
510 }
511 
513  .name = "hnm4video",
514  .long_name = NULL_IF_CONFIG_SMALL("HNM 4 video"),
515  .type = AVMEDIA_TYPE_VIDEO,
517  .priv_data_size = sizeof(Hnm4VideoContext),
519  .close = hnm_decode_end,
521  .capabilities = AV_CODEC_CAP_DR1,
522 };
#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:226
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:1446
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:1743
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:3424
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 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:1634
static int getbit(GetByteContext *gb, uint32_t *bitbuf, int *bits)
Definition: hnm4video.c:50
static AVFrame * frame
const char data[16]
Definition: mxf.c:91
uint8_t * data
Definition: avcodec.h:1445
uint32_t tag
Definition: movenc.c:1478
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
#define U(x)
Definition: vp56_arith.h:37
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:188
void * av_mallocz(size_t size)
Allocate a memory block with alignment suitable for all memory accesses (including vectors if availab...
Definition: mem.c:236
const char * name
Name of the codec implementation.
Definition: avcodec.h:3431
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:282
enum AVPictureType pict_type
Picture type of the frame.
Definition: frame.h:309
uint8_t * current
Definition: hnm4video.c:42
int width
picture width / height.
Definition: avcodec.h:1706
int32_t
uint8_t * previous
Definition: hnm4video.c:43
static av_cold int hnm_decode_end(AVCodecContext *avctx)
Definition: hnm4video.c:501
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:257
#define HNM4_CHUNK_ID_PL
Definition: hnm4video.c:33
main external API structure.
Definition: avcodec.h:1533
int ff_get_buffer(AVCodecContext *avctx, AVFrame *frame, int flags)
Get a buffer for a frame.
Definition: decode.c:1919
int extradata_size
Definition: avcodec.h:1635
#define HNM4_CHUNK_ID_IU
Definition: hnm4video.c:35
static void hnm_flip_buffers(Hnm4VideoContext *hnm)
Definition: hnm4video.c:390
static av_cold int hnm_decode_init(AVCodecContext *avctx)
Definition: hnm4video.c:462
uint8_t * data[AV_NUM_DATA_POINTERS]
pointer to the picture/channel planes.
Definition: frame.h:240
common internal api header.
static int hnm_decode_frame(AVCodecContext *avctx, void *data, int *got_frame, AVPacket *avpkt)
Definition: hnm4video.c:399
static void hnm_update_palette(AVCodecContext *avctx, uint8_t *src, uint32_t size)
Definition: hnm4video.c:357
void * priv_data
Definition: avcodec.h:1560
int key_frame
1 -> keyframe, 0-> not
Definition: frame.h:304
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:512
This structure stores compressed data.
Definition: avcodec.h:1422
#define AV_CODEC_CAP_DR1
Codec uses get_buffer() for allocating buffers and supports custom allocators.
Definition: avcodec.h:968
Predicted.
Definition: avutil.h:275