You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

466 lines
15KB

  1. /*
  2. * Cryo Interactive Entertainment HNM4 video decoder
  3. *
  4. * Copyright (c) 2012 David Kment
  5. *
  6. * This file is part of Libav.
  7. *
  8. * Libav 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. * Libav 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 Libav; if not, write to the Free Software
  20. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  21. */
  22. #include <string.h>
  23. #include "libavutil/imgutils.h"
  24. #include "libavutil/internal.h"
  25. #include "libavutil/intreadwrite.h"
  26. #include "libavutil/mem.h"
  27. #include "avcodec.h"
  28. #include "bytestream.h"
  29. #include "internal.h"
  30. #define HNM4_CHUNK_ID_PL 19536
  31. #define HNM4_CHUNK_ID_IZ 23113
  32. #define HNM4_CHUNK_ID_IU 21833
  33. #define HNM4_CHUNK_ID_SD 17491
  34. typedef struct Hnm4VideoContext {
  35. uint8_t version;
  36. int width;
  37. int height;
  38. uint8_t *current;
  39. uint8_t *previous;
  40. uint8_t *buffer1;
  41. uint8_t *buffer2;
  42. uint8_t *processed;
  43. uint32_t palette[256];
  44. } Hnm4VideoContext;
  45. static int getbit(GetByteContext *gb, uint32_t *bitbuf, int *bits)
  46. {
  47. int ret;
  48. if (!*bits) {
  49. *bitbuf = bytestream2_get_le32(gb);
  50. *bits = 32;
  51. }
  52. ret = *bitbuf >> 31;
  53. *bitbuf <<= 1;
  54. (*bits)--;
  55. return ret;
  56. }
  57. static void unpack_intraframe(AVCodecContext *avctx, uint8_t *src,
  58. uint32_t size)
  59. {
  60. Hnm4VideoContext *hnm = avctx->priv_data;
  61. GetByteContext gb;
  62. uint32_t bitbuf = 0, writeoffset = 0, count = 0;
  63. uint16_t word;
  64. int32_t offset;
  65. int bits = 0;
  66. bytestream2_init(&gb, src, size);
  67. while (bytestream2_tell(&gb) < size) {
  68. if (getbit(&gb, &bitbuf, &bits)) {
  69. if (writeoffset >= hnm->width * hnm->height) {
  70. av_log(avctx, AV_LOG_ERROR,
  71. "Attempting to write out of bounds");
  72. break;
  73. }
  74. hnm->current[writeoffset++] = bytestream2_get_byte(&gb);
  75. } else {
  76. if (getbit(&gb, &bitbuf, &bits)) {
  77. word = bytestream2_get_le16(&gb);
  78. count = word & 0x07;
  79. offset = (word >> 3) - 0x2000;
  80. if (!count)
  81. count = bytestream2_get_byte(&gb);
  82. if (!count)
  83. return;
  84. } else {
  85. count = getbit(&gb, &bitbuf, &bits) * 2;
  86. count += getbit(&gb, &bitbuf, &bits);
  87. offset = bytestream2_get_byte(&gb) - 0x0100;
  88. }
  89. count += 2;
  90. offset += writeoffset;
  91. if (offset < 0 || offset + count >= hnm->width * hnm->height) {
  92. av_log(avctx, AV_LOG_ERROR, "Attempting to read out of bounds");
  93. break;
  94. } else if (writeoffset + count >= hnm->width * hnm->height) {
  95. av_log(avctx, AV_LOG_ERROR,
  96. "Attempting to write out of bounds");
  97. break;
  98. }
  99. while (count--) {
  100. hnm->current[writeoffset++] = hnm->current[offset++];
  101. }
  102. }
  103. }
  104. }
  105. static void postprocess_current_frame(AVCodecContext *avctx)
  106. {
  107. Hnm4VideoContext *hnm = avctx->priv_data;
  108. uint32_t x, y, src_x, src_y;
  109. for (y = 0; y < hnm->height; y++) {
  110. src_y = y - (y % 2);
  111. src_x = src_y * hnm->width + (y % 2);
  112. for (x = 0; x < hnm->width; x++) {
  113. hnm->processed[(y * hnm->width) + x] = hnm->current[src_x];
  114. src_x += 2;
  115. }
  116. }
  117. }
  118. static void copy_processed_frame(AVCodecContext *avctx, AVFrame *frame)
  119. {
  120. Hnm4VideoContext *hnm = avctx->priv_data;
  121. uint8_t *src = hnm->processed;
  122. uint8_t *dst = frame->data[0];
  123. int y;
  124. for (y = 0; y < hnm->height; y++) {
  125. memcpy(dst, src, hnm->width);
  126. src += hnm->width;
  127. dst += frame->linesize[0];
  128. }
  129. }
  130. static void decode_interframe_v4(AVCodecContext *avctx, uint8_t *src, uint32_t size)
  131. {
  132. Hnm4VideoContext *hnm = avctx->priv_data;
  133. GetByteContext gb;
  134. uint32_t writeoffset = 0, count, left, offset;
  135. uint8_t tag, previous, backline, backward, swap;
  136. bytestream2_init(&gb, src, size);
  137. while (bytestream2_tell(&gb) < size) {
  138. count = bytestream2_peek_byte(&gb) & 0x1F;
  139. if (count == 0) {
  140. tag = bytestream2_get_byte(&gb) & 0xE0;
  141. tag = tag >> 5;
  142. if (tag == 0) {
  143. hnm->current[writeoffset++] = bytestream2_get_byte(&gb);
  144. hnm->current[writeoffset++] = bytestream2_get_byte(&gb);
  145. } else if (tag == 1) {
  146. writeoffset += bytestream2_get_byte(&gb) * 2;
  147. } else if (tag == 2) {
  148. count = bytestream2_get_le16(&gb);
  149. count *= 2;
  150. writeoffset += count;
  151. } else if (tag == 3) {
  152. count = bytestream2_get_byte(&gb) * 2;
  153. while (count > 0) {
  154. hnm->current[writeoffset++] = bytestream2_peek_byte(&gb);
  155. count--;
  156. }
  157. bytestream2_skip(&gb, 1);
  158. } else {
  159. break;
  160. }
  161. } else {
  162. previous = bytestream2_peek_byte(&gb) & 0x20;
  163. backline = bytestream2_peek_byte(&gb) & 0x40;
  164. backward = bytestream2_peek_byte(&gb) & 0x80;
  165. bytestream2_skip(&gb, 1);
  166. swap = bytestream2_peek_byte(&gb) & 0x01;
  167. offset = bytestream2_get_le16(&gb);
  168. offset = (offset >> 1) & 0x7FFF;
  169. offset = writeoffset + (offset * 2) - 0x8000;
  170. left = count;
  171. if (!backward && offset + count >= hnm->width * hnm->height) {
  172. av_log(avctx, AV_LOG_ERROR, "Attempting to read out of bounds");
  173. break;
  174. } else if (backward && offset >= hnm->width * hnm->height) {
  175. av_log(avctx, AV_LOG_ERROR, "Attempting to read out of bounds");
  176. break;
  177. } else if (writeoffset + count >= hnm->width * hnm->height) {
  178. av_log(avctx, AV_LOG_ERROR,
  179. "Attempting to write out of bounds");
  180. break;
  181. }
  182. if (previous) {
  183. while (left > 0) {
  184. if (backline) {
  185. hnm->current[writeoffset++] = hnm->previous[offset - (2 * hnm->width) + 1];
  186. hnm->current[writeoffset++] = hnm->previous[offset++];
  187. offset++;
  188. } else {
  189. hnm->current[writeoffset++] = hnm->previous[offset++];
  190. hnm->current[writeoffset++] = hnm->previous[offset++];
  191. }
  192. if (backward)
  193. offset -= 4;
  194. left--;
  195. }
  196. } else {
  197. while (left > 0) {
  198. if (backline) {
  199. hnm->current[writeoffset++] = hnm->current[offset - (2 * hnm->width) + 1];
  200. hnm->current[writeoffset++] = hnm->current[offset++];
  201. offset++;
  202. } else {
  203. hnm->current[writeoffset++] = hnm->current[offset++];
  204. hnm->current[writeoffset++] = hnm->current[offset++];
  205. }
  206. if (backward)
  207. offset -= 4;
  208. left--;
  209. }
  210. }
  211. if (swap) {
  212. left = count;
  213. writeoffset -= count * 2;
  214. while (left > 0) {
  215. swap = hnm->current[writeoffset];
  216. hnm->current[writeoffset] = hnm->current[writeoffset + 1];
  217. hnm->current[writeoffset + 1] = swap;
  218. left--;
  219. writeoffset += 2;
  220. }
  221. }
  222. }
  223. }
  224. }
  225. static void decode_interframe_v4a(AVCodecContext *avctx, uint8_t *src,
  226. uint32_t size)
  227. {
  228. Hnm4VideoContext *hnm = avctx->priv_data;
  229. GetByteContext gb;
  230. uint32_t writeoffset = 0, offset;
  231. uint8_t tag, count, previous, delta;
  232. bytestream2_init(&gb, src, size);
  233. while (bytestream2_tell(&gb) < size) {
  234. count = bytestream2_peek_byte(&gb) & 0x3F;
  235. if (count == 0) {
  236. tag = bytestream2_get_byte(&gb) & 0xC0;
  237. tag = tag >> 6;
  238. if (tag == 0) {
  239. writeoffset += bytestream2_get_byte(&gb);
  240. } else if (tag == 1) {
  241. hnm->current[writeoffset] = bytestream2_get_byte(&gb);
  242. hnm->current[writeoffset + hnm->width] = bytestream2_get_byte(&gb);
  243. writeoffset++;
  244. } else if (tag == 2) {
  245. writeoffset += hnm->width;
  246. } else if (tag == 3) {
  247. break;
  248. }
  249. } else {
  250. delta = bytestream2_peek_byte(&gb) & 0x80;
  251. previous = bytestream2_peek_byte(&gb) & 0x40;
  252. bytestream2_skip(&gb, 1);
  253. offset = writeoffset;
  254. offset += bytestream2_get_le16(&gb);
  255. if (delta)
  256. offset -= 0x10000;
  257. if (offset + hnm->width + count >= hnm->width * hnm->height) {
  258. av_log(avctx, AV_LOG_ERROR, "Attempting to read out of bounds");
  259. break;
  260. } else if (writeoffset + hnm->width + count >= hnm->width * hnm->height) {
  261. av_log(avctx, AV_LOG_ERROR, "Attempting to write out of bounds");
  262. break;
  263. }
  264. if (previous) {
  265. while (count > 0) {
  266. hnm->current[writeoffset] = hnm->previous[offset];
  267. hnm->current[writeoffset + hnm->width] = hnm->previous[offset + hnm->width];
  268. writeoffset++;
  269. offset++;
  270. count--;
  271. }
  272. } else {
  273. while (count > 0) {
  274. hnm->current[writeoffset] = hnm->current[offset];
  275. hnm->current[writeoffset + hnm->width] = hnm->current[offset + hnm->width];
  276. writeoffset++;
  277. offset++;
  278. count--;
  279. }
  280. }
  281. }
  282. }
  283. }
  284. static void hnm_update_palette(AVCodecContext *avctx, uint8_t *src,
  285. uint32_t size)
  286. {
  287. Hnm4VideoContext *hnm = avctx->priv_data;
  288. GetByteContext gb;
  289. uint8_t start, writeoffset;
  290. uint16_t count;
  291. int eight_bit_colors;
  292. eight_bit_colors = src[7] & 0x80 && hnm->version == 0x4a;
  293. // skip first 8 bytes
  294. bytestream2_init(&gb, src + 8, size - 8);
  295. while (bytestream2_tell(&gb) < size - 8) {
  296. start = bytestream2_get_byte(&gb);
  297. count = bytestream2_get_byte(&gb);
  298. if (start == 255 && count == 255)
  299. break;
  300. if (count == 0)
  301. count = 256;
  302. writeoffset = start;
  303. while (count > 0) {
  304. hnm->palette[writeoffset] = bytestream2_get_be24(&gb);
  305. if (!eight_bit_colors)
  306. hnm->palette[writeoffset] <<= 2;
  307. count--;
  308. writeoffset++;
  309. }
  310. }
  311. }
  312. static void hnm_flip_buffers(Hnm4VideoContext *hnm)
  313. {
  314. uint8_t *temp;
  315. temp = hnm->current;
  316. hnm->current = hnm->previous;
  317. hnm->previous = temp;
  318. }
  319. static int hnm_decode_frame(AVCodecContext *avctx, void *data,
  320. int *got_frame, AVPacket *avpkt)
  321. {
  322. AVFrame *frame = data;
  323. Hnm4VideoContext *hnm = avctx->priv_data;
  324. int ret;
  325. uint16_t chunk_id;
  326. if ((ret = ff_get_buffer(avctx, frame, 0)) < 0) {
  327. av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n");
  328. return ret;
  329. }
  330. chunk_id = AV_RL16(avpkt->data + 4);
  331. if (chunk_id == HNM4_CHUNK_ID_PL) {
  332. hnm_update_palette(avctx, avpkt->data, avpkt->size);
  333. frame->palette_has_changed = 1;
  334. } else if (chunk_id == HNM4_CHUNK_ID_IZ) {
  335. unpack_intraframe(avctx, avpkt->data + 12, avpkt->size - 12);
  336. memcpy(hnm->previous, hnm->current, hnm->width * hnm->height);
  337. if (hnm->version == 0x4a)
  338. memcpy(hnm->processed, hnm->current, hnm->width * hnm->height);
  339. else
  340. postprocess_current_frame(avctx);
  341. copy_processed_frame(avctx, frame);
  342. frame->pict_type = AV_PICTURE_TYPE_I;
  343. frame->key_frame = 1;
  344. memcpy(frame->data[1], hnm->palette, 256 * 4);
  345. *got_frame = 1;
  346. } else if (chunk_id == HNM4_CHUNK_ID_IU) {
  347. if (hnm->version == 0x4a) {
  348. decode_interframe_v4a(avctx, avpkt->data + 8, avpkt->size - 8);
  349. memcpy(hnm->processed, hnm->current, hnm->width * hnm->height);
  350. } else {
  351. decode_interframe_v4(avctx, avpkt->data + 8, avpkt->size - 8);
  352. postprocess_current_frame(avctx);
  353. }
  354. copy_processed_frame(avctx, frame);
  355. frame->pict_type = AV_PICTURE_TYPE_P;
  356. frame->key_frame = 0;
  357. memcpy(frame->data[1], hnm->palette, 256 * 4);
  358. *got_frame = 1;
  359. hnm_flip_buffers(hnm);
  360. } else {
  361. av_log(avctx, AV_LOG_ERROR, "invalid chunk id: %d\n", chunk_id);
  362. return AVERROR_INVALIDDATA;
  363. }
  364. return avpkt->size;
  365. }
  366. static av_cold int hnm_decode_init(AVCodecContext *avctx)
  367. {
  368. Hnm4VideoContext *hnm = avctx->priv_data;
  369. int ret;
  370. if (avctx->extradata_size < 1) {
  371. av_log(avctx, AV_LOG_ERROR,
  372. "Extradata missing, decoder requires version number\n");
  373. return AVERROR_INVALIDDATA;
  374. }
  375. ret = av_image_check_size(avctx->width, avctx->height, 0, avctx);
  376. if (ret < 0)
  377. return ret;
  378. hnm->version = avctx->extradata[0];
  379. avctx->pix_fmt = AV_PIX_FMT_PAL8;
  380. hnm->width = avctx->width;
  381. hnm->height = avctx->height;
  382. hnm->buffer1 = av_mallocz(avctx->width * avctx->height);
  383. hnm->buffer2 = av_mallocz(avctx->width * avctx->height);
  384. hnm->processed = av_mallocz(avctx->width * avctx->height);
  385. if (!hnm->buffer1 || !hnm->buffer2 || !hnm->processed) {
  386. av_log(avctx, AV_LOG_ERROR, "av_mallocz() failed\n");
  387. av_freep(&hnm->buffer1);
  388. av_freep(&hnm->buffer2);
  389. av_freep(&hnm->processed);
  390. return AVERROR(ENOMEM);
  391. }
  392. hnm->current = hnm->buffer1;
  393. hnm->previous = hnm->buffer2;
  394. return 0;
  395. }
  396. static av_cold int hnm_decode_end(AVCodecContext *avctx)
  397. {
  398. Hnm4VideoContext *hnm = avctx->priv_data;
  399. av_freep(&hnm->buffer1);
  400. av_freep(&hnm->buffer2);
  401. av_freep(&hnm->processed);
  402. return 0;
  403. }
  404. AVCodec ff_hnm4_video_decoder = {
  405. .name = "hnm4video",
  406. .long_name = NULL_IF_CONFIG_SMALL("HNM 4 video"),
  407. .type = AVMEDIA_TYPE_VIDEO,
  408. .id = AV_CODEC_ID_HNM4_VIDEO,
  409. .priv_data_size = sizeof(Hnm4VideoContext),
  410. .init = hnm_decode_init,
  411. .close = hnm_decode_end,
  412. .decode = hnm_decode_frame,
  413. .capabilities = AV_CODEC_CAP_DR1,
  414. };