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.

197 lines
5.5KB

  1. /*
  2. * Copyright (c) 2021 Paul B Mahol
  3. *
  4. * This file is part of FFmpeg.
  5. *
  6. * FFmpeg is free software; you can redistribute it and/or
  7. * modify it under the terms of the GNU Lesser General Public
  8. * License as published by the Free Software Foundation; either
  9. * version 2.1 of the License, or (at your option) any later version.
  10. *
  11. * FFmpeg is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  14. * Lesser General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU Lesser General Public
  17. * License along with FFmpeg; if not, write to the Free Software
  18. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  19. */
  20. #include "libavutil/common.h"
  21. #include "avcodec.h"
  22. #include "bytestream.h"
  23. #include "internal.h"
  24. typedef struct SimbiosisIMXContext {
  25. AVFrame *frame;
  26. uint32_t pal[256];
  27. uint8_t history[32768];
  28. int pos;
  29. } SimbiosisIMXContext;
  30. static av_cold int imx_decode_init(AVCodecContext *avctx)
  31. {
  32. SimbiosisIMXContext *imx = avctx->priv_data;
  33. avctx->pix_fmt = AV_PIX_FMT_PAL8;
  34. avctx->width = 320;
  35. avctx->height = 160;
  36. imx->frame = av_frame_alloc();
  37. if (!imx->frame)
  38. return AVERROR(ENOMEM);
  39. return 0;
  40. }
  41. static int imx_decode_frame(AVCodecContext *avctx, void *data,
  42. int *got_frame, AVPacket *avpkt)
  43. {
  44. SimbiosisIMXContext *imx = avctx->priv_data;
  45. int ret, x, y, pal_size;
  46. const uint8_t *pal = av_packet_get_side_data(avpkt, AV_PKT_DATA_PALETTE, &pal_size);
  47. AVFrame *frame = imx->frame;
  48. GetByteContext gb;
  49. if ((ret = ff_reget_buffer(avctx, frame, 0)) < 0)
  50. return ret;
  51. if (pal && pal_size == AVPALETTE_SIZE) {
  52. memcpy(imx->pal, pal, pal_size);
  53. frame->palette_has_changed = 1;
  54. frame->key_frame = 1;
  55. } else {
  56. frame->key_frame = 0;
  57. frame->palette_has_changed = 0;
  58. }
  59. bytestream2_init(&gb, avpkt->data, avpkt->size);
  60. memcpy(frame->data[1], imx->pal, AVPALETTE_SIZE);
  61. x = 0, y = 0;
  62. while (bytestream2_get_bytes_left(&gb) > 0 &&
  63. x < 320 && y < 160) {
  64. int b = bytestream2_get_byte(&gb);
  65. int len = b & 0x3f;
  66. int op = b >> 6;
  67. int fill;
  68. switch (op) {
  69. case 3:
  70. len = len * 64 + bytestream2_get_byte(&gb);
  71. case 0:
  72. while (len > 0) {
  73. x++;
  74. len--;
  75. if (x >= 320) {
  76. x = 0;
  77. y++;
  78. }
  79. if (y >= 160)
  80. break;
  81. }
  82. frame->key_frame = 0;
  83. break;
  84. case 1:
  85. if (len == 0) {
  86. int offset = bytestream2_get_le16(&gb);
  87. if (offset < 0 || offset >= 32768)
  88. return AVERROR_INVALIDDATA;
  89. len = bytestream2_get_byte(&gb);
  90. while (len > 0 && offset < 32768) {
  91. frame->data[0][x + y * frame->linesize[0]] = imx->history[offset++];
  92. x++;
  93. len--;
  94. if (x >= 320) {
  95. x = 0;
  96. y++;
  97. }
  98. if (y >= 160)
  99. break;
  100. }
  101. frame->key_frame = 0;
  102. } else {
  103. while (len > 0) {
  104. fill = bytestream2_get_byte(&gb);
  105. frame->data[0][x + y * frame->linesize[0]] = fill;
  106. if (imx->pos < 32768)
  107. imx->history[imx->pos++] = fill;
  108. x++;
  109. len--;
  110. if (x >= 320) {
  111. x = 0;
  112. y++;
  113. }
  114. if (y >= 160)
  115. break;
  116. }
  117. }
  118. break;
  119. case 2:
  120. fill = bytestream2_get_byte(&gb);
  121. while (len > 0) {
  122. frame->data[0][x + y * frame->linesize[0]] = fill;
  123. x++;
  124. len--;
  125. if (x >= 320) {
  126. x = 0;
  127. y++;
  128. }
  129. if (y >= 160)
  130. break;
  131. }
  132. break;
  133. }
  134. }
  135. frame->pict_type = frame->key_frame ? AV_PICTURE_TYPE_I : AV_PICTURE_TYPE_P;
  136. if ((ret = av_frame_ref(data, frame)) < 0)
  137. return ret;
  138. *got_frame = 1;
  139. return avpkt->size;
  140. }
  141. static void imx_decode_flush(AVCodecContext *avctx)
  142. {
  143. SimbiosisIMXContext *imx = avctx->priv_data;
  144. av_frame_unref(imx->frame);
  145. imx->pos = 0;
  146. memset(imx->pal, 0, sizeof(imx->pal));
  147. memset(imx->history, 0, sizeof(imx->history));
  148. }
  149. static int imx_decode_close(AVCodecContext *avctx)
  150. {
  151. SimbiosisIMXContext *imx = avctx->priv_data;
  152. av_frame_free(&imx->frame);
  153. return 0;
  154. }
  155. AVCodec ff_simbiosis_imx_decoder = {
  156. .name = "simbiosis_imx",
  157. .long_name = NULL_IF_CONFIG_SMALL("Simbiosis Interactive IMX Video"),
  158. .type = AVMEDIA_TYPE_VIDEO,
  159. .id = AV_CODEC_ID_SIMBIOSIS_IMX,
  160. .priv_data_size = sizeof(SimbiosisIMXContext),
  161. .init = imx_decode_init,
  162. .decode = imx_decode_frame,
  163. .close = imx_decode_close,
  164. .flush = imx_decode_flush,
  165. .capabilities = AV_CODEC_CAP_DR1,
  166. .caps_internal = FF_CODEC_CAP_INIT_THREADSAFE |
  167. FF_CODEC_CAP_INIT_CLEANUP,
  168. };