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.

149 lines
4.4KB

  1. /*
  2. * SGI RLE 8-bit decoder
  3. * Copyright (c) 2012 Peter Ross
  4. *
  5. * This file is part of FFmpeg.
  6. *
  7. * FFmpeg is free software; you can redistribute it and/or
  8. * modify it under the terms of the GNU Lesser General Public
  9. * License as published by the Free Software Foundation; either
  10. * version 2.1 of the License, or (at your option) any later version.
  11. *
  12. * FFmpeg is distributed in the hope that it will be useful,
  13. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  15. * Lesser General Public License for more details.
  16. *
  17. * You should have received a copy of the GNU Lesser General Public
  18. * License along with FFmpeg; if not, write to the Free Software
  19. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  20. */
  21. /**
  22. * @file
  23. * SGI RLE 8-bit decoder
  24. */
  25. #include "libavutil/intreadwrite.h"
  26. #include "avcodec.h"
  27. #include "bytestream.h"
  28. static av_cold int sgirle_decode_init(AVCodecContext *avctx)
  29. {
  30. avctx->pix_fmt = AV_PIX_FMT_BGR8;
  31. avctx->coded_frame = avcodec_alloc_frame();
  32. if (!avctx->coded_frame)
  33. return AVERROR(ENOMEM);
  34. return 0;
  35. }
  36. /**
  37. * Convert SGI RGB332 pixel into PIX_FMT_BGR8
  38. * SGI RGB332 is packed RGB 3:3:2, 8bpp, (msb)3R 2B 3G(lsb)
  39. */
  40. #define RGB332_TO_BGR8(x) (((x << 3) & 0xC0) | ((x << 3) & 0x38) | ((x >> 5) & 7))
  41. static av_always_inline void memcpy_rgb332_to_bgr8(uint8_t *dst, const uint8_t *src, int size)
  42. {
  43. int i;
  44. for (i = 0; i < size; i++)
  45. dst[i] = RGB332_TO_BGR8(src[i]);
  46. }
  47. /**
  48. * @param[out] dst Destination buffer
  49. * @param[in] src Source buffer
  50. * @param src_size Source buffer size (bytes)
  51. * @param width Width of destination buffer (pixels)
  52. * @param height Height of destination buffer (pixels)
  53. * @param linesize Line size of destination buffer (bytes)
  54. * @return <0 on error
  55. */
  56. static int decode_sgirle8(AVCodecContext *avctx, uint8_t *dst, const uint8_t *src, int src_size, int width, int height, int linesize)
  57. {
  58. const uint8_t *src_end = src + src_size;
  59. int x = 0, y = 0;
  60. #define INC_XY(n) \
  61. x += n; \
  62. if (x >= width) { \
  63. y++; \
  64. if (y >= height) \
  65. return 0; \
  66. x = 0; \
  67. }
  68. while (src_end - src >= 2) {
  69. uint8_t v = *src++;
  70. if (v > 0 && v < 0xC0) {
  71. do {
  72. int length = FFMIN(v, width - x);
  73. memset(dst + y*linesize + x, RGB332_TO_BGR8(*src), length);
  74. INC_XY(length);
  75. v -= length;
  76. } while (v > 0);
  77. src++;
  78. } else if (v >= 0xC1) {
  79. v -= 0xC0;
  80. do {
  81. int length = FFMIN3(v, width - x, src_end - src);
  82. if (src_end - src < length)
  83. break;
  84. memcpy_rgb332_to_bgr8(dst + y*linesize + x, src, length);
  85. INC_XY(length);
  86. src += length;
  87. v -= length;
  88. } while (v > 0);
  89. } else {
  90. av_log_ask_for_sample(avctx, "unknown opcode\n");
  91. return AVERROR_PATCHWELCOME;
  92. }
  93. }
  94. return 0;
  95. }
  96. static int sgirle_decode_frame(AVCodecContext *avctx,
  97. void *data, int *got_frame,
  98. AVPacket *avpkt)
  99. {
  100. AVFrame *frame = avctx->coded_frame;
  101. int ret;
  102. frame->reference = 3;
  103. frame->buffer_hints = FF_BUFFER_HINTS_VALID | FF_BUFFER_HINTS_PRESERVE |
  104. FF_BUFFER_HINTS_REUSABLE | FF_BUFFER_HINTS_READABLE;
  105. ret = avctx->reget_buffer(avctx, frame);
  106. if (ret < 0) {
  107. av_log (avctx, AV_LOG_ERROR, "reget_buffer() failed\n");
  108. return ret;
  109. }
  110. ret = decode_sgirle8(avctx, frame->data[0], avpkt->data, avpkt->size, avctx->width, avctx->height, frame->linesize[0]);
  111. if (ret < 0)
  112. return ret;
  113. *got_frame = 1;
  114. *(AVFrame*)data = *frame;
  115. return avpkt->size;
  116. }
  117. static av_cold int sgirle_decode_end(AVCodecContext *avctx)
  118. {
  119. if (avctx->coded_frame->data[0])
  120. avctx->release_buffer(avctx, avctx->coded_frame);
  121. av_freep(&avctx->coded_frame);
  122. return 0;
  123. }
  124. AVCodec ff_sgirle_decoder = {
  125. .name = "sgirle",
  126. .type = AVMEDIA_TYPE_VIDEO,
  127. .id = AV_CODEC_ID_SGIRLE,
  128. .init = sgirle_decode_init,
  129. .close = sgirle_decode_end,
  130. .decode = sgirle_decode_frame,
  131. .capabilities = CODEC_CAP_DR1,
  132. .long_name = NULL_IF_CONFIG_SMALL("SGI RLE 8-bit"),
  133. };