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
6.0KB

  1. /*
  2. * Screenpresso decoder
  3. * Copyright (C) 2015 Vittorio Giovara <vittorio.giovara@gmail.com>
  4. *
  5. * This file is part of Libav.
  6. *
  7. * Libav 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. * Libav 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 Libav; 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. * Screenpresso decoder
  24. *
  25. * Fourcc: SPV1
  26. *
  27. * Screenpresso simply horizontally flips and then deflates frames,
  28. * alternating full pictures and deltas. Deltas are related to the currently
  29. * rebuilt frame (not the reference), and since there is no coordinate system
  30. * they contain exactly as many pixel as the keyframe.
  31. *
  32. * Supports: BGRA, BGR24, RGB555
  33. */
  34. #include <stdint.h>
  35. #include <string.h>
  36. #include <zlib.h>
  37. #include "libavutil/imgutils.h"
  38. #include "libavutil/internal.h"
  39. #include "libavutil/mem.h"
  40. #include "avcodec.h"
  41. #include "internal.h"
  42. typedef struct ScreenpressoContext {
  43. AVFrame *current;
  44. /* zlib interaction */
  45. uint8_t *inflated_buf;
  46. uLongf inflated_size;
  47. } ScreenpressoContext;
  48. static av_cold int screenpresso_close(AVCodecContext *avctx)
  49. {
  50. ScreenpressoContext *ctx = avctx->priv_data;
  51. av_frame_free(&ctx->current);
  52. av_freep(&ctx->inflated_buf);
  53. return 0;
  54. }
  55. static av_cold int screenpresso_init(AVCodecContext *avctx)
  56. {
  57. ScreenpressoContext *ctx = avctx->priv_data;
  58. /* These needs to be set to estimate uncompressed buffer */
  59. int ret = av_image_check_size(avctx->width, avctx->height, 0, avctx);
  60. if (ret < 0) {
  61. av_log(avctx, AV_LOG_ERROR, "Invalid image size %dx%d.\n",
  62. avctx->width, avctx->height);
  63. return ret;
  64. }
  65. /* Allocate current frame */
  66. ctx->current = av_frame_alloc();
  67. if (!ctx->current)
  68. return AVERROR(ENOMEM);
  69. /* Allocate maximum size possible, a full RGBA frame */
  70. ctx->inflated_size = avctx->width * avctx->height * 4;
  71. ctx->inflated_buf = av_malloc(ctx->inflated_size);
  72. if (!ctx->inflated_buf)
  73. return AVERROR(ENOMEM);
  74. return 0;
  75. }
  76. static void sum_delta_flipped(uint8_t *dst, int dst_linesize,
  77. const uint8_t *src, int src_linesize,
  78. int bytewidth, int height)
  79. {
  80. int i;
  81. for (; height > 0; height--) {
  82. for (i = 0; i < bytewidth; i++)
  83. dst[i] += src[(height - 1) * src_linesize + i];
  84. dst += dst_linesize;
  85. }
  86. }
  87. static int screenpresso_decode_frame(AVCodecContext *avctx, void *data,
  88. int *got_frame, AVPacket *avpkt)
  89. {
  90. ScreenpressoContext *ctx = avctx->priv_data;
  91. AVFrame *frame = data;
  92. uLongf length = ctx->inflated_size;
  93. int keyframe, component_size, src_linesize;
  94. int ret;
  95. /* Size check */
  96. if (avpkt->size < 3) {
  97. av_log(avctx, AV_LOG_ERROR, "Packet too small (%d)\n", avpkt->size);
  98. return AVERROR_INVALIDDATA;
  99. }
  100. /* Compression level (4 bits) and keyframe information (1 bit) */
  101. av_log(avctx, AV_LOG_DEBUG, "Compression level %d\n", avpkt->data[0] >> 4);
  102. keyframe = avpkt->data[0] & 1;
  103. /* Pixel size */
  104. component_size = ((avpkt->data[1] >> 2) & 0x03) + 1;
  105. switch (component_size) {
  106. case 2:
  107. avctx->pix_fmt = AV_PIX_FMT_RGB555LE;
  108. break;
  109. case 3:
  110. avctx->pix_fmt = AV_PIX_FMT_BGR24;
  111. break;
  112. case 4:
  113. avctx->pix_fmt = AV_PIX_FMT_BGRA;
  114. break;
  115. default:
  116. av_log(avctx, AV_LOG_ERROR, "Invalid bits per pixel value (%d)\n",
  117. component_size);
  118. return AVERROR_INVALIDDATA;
  119. }
  120. /* Inflate the frame after the 2 byte header */
  121. ret = uncompress(ctx->inflated_buf, &length,
  122. avpkt->data + 2, avpkt->size - 2);
  123. if (ret) {
  124. av_log(avctx, AV_LOG_ERROR, "Deflate error %d.\n", ret);
  125. return AVERROR_UNKNOWN;
  126. }
  127. ret = ff_reget_buffer(avctx, ctx->current);
  128. if (ret < 0)
  129. return ret;
  130. /* Codec has aligned strides */
  131. src_linesize = FFALIGN(avctx->width * component_size, 4);
  132. /* When a keyframe is found, copy it (flipped) */
  133. if (keyframe)
  134. av_image_copy_plane(ctx->current->data[0] +
  135. ctx->current->linesize[0] * (avctx->height - 1),
  136. -1 * ctx->current->linesize[0],
  137. ctx->inflated_buf, src_linesize,
  138. avctx->width * component_size, avctx->height);
  139. /* Otherwise sum the delta on top of the current frame */
  140. else
  141. sum_delta_flipped(ctx->current->data[0], ctx->current->linesize[0],
  142. ctx->inflated_buf, src_linesize,
  143. avctx->width * component_size, avctx->height);
  144. /* Frame is ready to be output */
  145. ret = av_frame_ref(frame, ctx->current);
  146. if (ret < 0)
  147. return ret;
  148. /* Usual properties */
  149. if (keyframe) {
  150. frame->pict_type = AV_PICTURE_TYPE_I;
  151. frame->key_frame = 1;
  152. } else {
  153. frame->pict_type = AV_PICTURE_TYPE_P;
  154. }
  155. *got_frame = 1;
  156. return 0;
  157. }
  158. AVCodec ff_screenpresso_decoder = {
  159. .name = "screenpresso",
  160. .long_name = NULL_IF_CONFIG_SMALL("Screenpresso"),
  161. .type = AVMEDIA_TYPE_VIDEO,
  162. .id = AV_CODEC_ID_SCREENPRESSO,
  163. .init = screenpresso_init,
  164. .decode = screenpresso_decode_frame,
  165. .close = screenpresso_close,
  166. .priv_data_size = sizeof(ScreenpressoContext),
  167. .capabilities = AV_CODEC_CAP_DR1,
  168. .caps_internal = FF_CODEC_CAP_INIT_THREADSAFE |
  169. FF_CODEC_CAP_INIT_CLEANUP,
  170. };