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.

198 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;
  46. buffer_size_t pal_size;
  47. const uint8_t *pal = av_packet_get_side_data(avpkt, AV_PKT_DATA_PALETTE, &pal_size);
  48. AVFrame *frame = imx->frame;
  49. GetByteContext gb;
  50. if ((ret = ff_reget_buffer(avctx, frame, 0)) < 0)
  51. return ret;
  52. if (pal && pal_size == AVPALETTE_SIZE) {
  53. memcpy(imx->pal, pal, pal_size);
  54. frame->palette_has_changed = 1;
  55. frame->key_frame = 1;
  56. } else {
  57. frame->key_frame = 0;
  58. frame->palette_has_changed = 0;
  59. }
  60. bytestream2_init(&gb, avpkt->data, avpkt->size);
  61. memcpy(frame->data[1], imx->pal, AVPALETTE_SIZE);
  62. x = 0, y = 0;
  63. while (bytestream2_get_bytes_left(&gb) > 0 &&
  64. x < 320 && y < 160) {
  65. int b = bytestream2_get_byte(&gb);
  66. int len = b & 0x3f;
  67. int op = b >> 6;
  68. int fill;
  69. switch (op) {
  70. case 3:
  71. len = len * 64 + bytestream2_get_byte(&gb);
  72. case 0:
  73. while (len > 0) {
  74. x++;
  75. len--;
  76. if (x >= 320) {
  77. x = 0;
  78. y++;
  79. }
  80. if (y >= 160)
  81. break;
  82. }
  83. frame->key_frame = 0;
  84. break;
  85. case 1:
  86. if (len == 0) {
  87. int offset = bytestream2_get_le16(&gb);
  88. if (offset < 0 || offset >= 32768)
  89. return AVERROR_INVALIDDATA;
  90. len = bytestream2_get_byte(&gb);
  91. while (len > 0 && offset < 32768) {
  92. frame->data[0][x + y * frame->linesize[0]] = imx->history[offset++];
  93. x++;
  94. len--;
  95. if (x >= 320) {
  96. x = 0;
  97. y++;
  98. }
  99. if (y >= 160)
  100. break;
  101. }
  102. frame->key_frame = 0;
  103. } else {
  104. while (len > 0) {
  105. fill = bytestream2_get_byte(&gb);
  106. frame->data[0][x + y * frame->linesize[0]] = fill;
  107. if (imx->pos < 32768)
  108. imx->history[imx->pos++] = fill;
  109. x++;
  110. len--;
  111. if (x >= 320) {
  112. x = 0;
  113. y++;
  114. }
  115. if (y >= 160)
  116. break;
  117. }
  118. }
  119. break;
  120. case 2:
  121. fill = bytestream2_get_byte(&gb);
  122. while (len > 0) {
  123. frame->data[0][x + y * frame->linesize[0]] = fill;
  124. x++;
  125. len--;
  126. if (x >= 320) {
  127. x = 0;
  128. y++;
  129. }
  130. if (y >= 160)
  131. break;
  132. }
  133. break;
  134. }
  135. }
  136. frame->pict_type = frame->key_frame ? AV_PICTURE_TYPE_I : AV_PICTURE_TYPE_P;
  137. if ((ret = av_frame_ref(data, frame)) < 0)
  138. return ret;
  139. *got_frame = 1;
  140. return avpkt->size;
  141. }
  142. static void imx_decode_flush(AVCodecContext *avctx)
  143. {
  144. SimbiosisIMXContext *imx = avctx->priv_data;
  145. av_frame_unref(imx->frame);
  146. imx->pos = 0;
  147. memset(imx->pal, 0, sizeof(imx->pal));
  148. memset(imx->history, 0, sizeof(imx->history));
  149. }
  150. static int imx_decode_close(AVCodecContext *avctx)
  151. {
  152. SimbiosisIMXContext *imx = avctx->priv_data;
  153. av_frame_free(&imx->frame);
  154. return 0;
  155. }
  156. AVCodec ff_simbiosis_imx_decoder = {
  157. .name = "simbiosis_imx",
  158. .long_name = NULL_IF_CONFIG_SMALL("Simbiosis Interactive IMX Video"),
  159. .type = AVMEDIA_TYPE_VIDEO,
  160. .id = AV_CODEC_ID_SIMBIOSIS_IMX,
  161. .priv_data_size = sizeof(SimbiosisIMXContext),
  162. .init = imx_decode_init,
  163. .decode = imx_decode_frame,
  164. .close = imx_decode_close,
  165. .flush = imx_decode_flush,
  166. .capabilities = AV_CODEC_CAP_DR1,
  167. .caps_internal = FF_CODEC_CAP_INIT_THREADSAFE |
  168. FF_CODEC_CAP_INIT_CLEANUP,
  169. };