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.

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