| @@ -0,0 +1,231 @@ |
| | 1 | /* |
| | 2 | * Mandsoft Screen Capture Codec decoder |
| | 3 | * |
| | 4 | * Copyright (c) 2017 Paul B Mahol |
| | 5 | * |
| | 6 | * This file is part of FFmpeg. |
| | 7 | * |
| | 8 | * FFmpeg 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 | * FFmpeg 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 FFmpeg; if not, write to the Free Software |
| | 20 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
| | 21 | */ |
| | 22 | |
| | 23 | #include <stdio.h> |
| | 24 | #include <stdlib.h> |
| | 25 | #include <string.h> |
| | 26 | |
| | 27 | #include "avcodec.h" |
| | 28 | #include "bytestream.h" |
| | 29 | #include "internal.h" |
| | 30 | |
| | 31 | #include <zlib.h> |
| | 32 | |
| | 33 | typedef struct MSCCContext { |
| | 34 | unsigned bpp; |
| | 35 | unsigned int decomp_size; |
| | 36 | uint8_t *decomp_buf; |
| | 37 | unsigned int uncomp_size; |
| | 38 | uint8_t *uncomp_buf; |
| | 39 | z_stream zstream; |
| | 40 | } MSCCContext; |
| | 41 | |
| | 42 | static int rle_uncompress(AVCodecContext *avctx, GetByteContext *gb, PutByteContext *pb, int bpp) |
| | 43 | { |
| | 44 | while (bytestream2_get_bytes_left(gb) > 0) { |
| | 45 | uint32_t fill; |
| | 46 | int j; |
| | 47 | unsigned run = bytestream2_get_byte(gb); |
| | 48 | |
| | 49 | if (run) { |
| | 50 | switch (avctx->bits_per_coded_sample) { |
| | 51 | case 8: |
| | 52 | fill = bytestream2_get_byte(gb); |
| | 53 | break; |
| | 54 | case 16: |
| | 55 | fill = bytestream2_get_le16(gb); |
| | 56 | break; |
| | 57 | case 24: |
| | 58 | fill = bytestream2_get_le24(gb); |
| | 59 | break; |
| | 60 | case 32: |
| | 61 | fill = bytestream2_get_le32(gb); |
| | 62 | break; |
| | 63 | } |
| | 64 | |
| | 65 | for (j = 0; j < run; j++) { |
| | 66 | switch (avctx->bits_per_coded_sample) { |
| | 67 | case 8: |
| | 68 | bytestream2_put_byte(pb, fill); |
| | 69 | break; |
| | 70 | case 16: |
| | 71 | bytestream2_put_le16(pb, fill); |
| | 72 | break; |
| | 73 | case 24: |
| | 74 | bytestream2_put_le24(pb, fill); |
| | 75 | break; |
| | 76 | case 32: |
| | 77 | bytestream2_put_le32(pb, fill); |
| | 78 | break; |
| | 79 | } |
| | 80 | } |
| | 81 | } else { |
| | 82 | unsigned copy = bytestream2_get_byte(gb); |
| | 83 | |
| | 84 | if (copy == 1) { |
| | 85 | return 0; |
| | 86 | } else if (copy == 2) { |
| | 87 | unsigned x, y; |
| | 88 | |
| | 89 | x = bytestream2_get_byte(gb); |
| | 90 | y = bytestream2_get_byte(gb); |
| | 91 | |
| | 92 | bytestream2_skip_p(pb, x * bpp); |
| | 93 | bytestream2_skip_p(pb, y * bpp * avctx->width); |
| | 94 | } else { |
| | 95 | for (j = 0; j < copy; j++) { |
| | 96 | switch (avctx->bits_per_coded_sample) { |
| | 97 | case 8: |
| | 98 | bytestream2_put_byte(pb, bytestream2_get_byte(gb)); |
| | 99 | break; |
| | 100 | case 16: |
| | 101 | bytestream2_put_le16(pb, bytestream2_get_le16(gb)); |
| | 102 | break; |
| | 103 | case 24: |
| | 104 | bytestream2_put_le24(pb, bytestream2_get_le24(gb)); |
| | 105 | break; |
| | 106 | case 32: |
| | 107 | bytestream2_put_le32(pb, bytestream2_get_le32(gb)); |
| | 108 | break; |
| | 109 | } |
| | 110 | } |
| | 111 | } |
| | 112 | } |
| | 113 | } |
| | 114 | |
| | 115 | return AVERROR_INVALIDDATA; |
| | 116 | } |
| | 117 | |
| | 118 | static int decode_frame(AVCodecContext *avctx, |
| | 119 | void *data, int *got_frame, |
| | 120 | AVPacket *avpkt) |
| | 121 | { |
| | 122 | MSCCContext *s = avctx->priv_data; |
| | 123 | AVFrame *frame = data; |
| | 124 | GetByteContext gb; |
| | 125 | PutByteContext pb; |
| | 126 | int ret, j; |
| | 127 | |
| | 128 | if (avpkt->size < 3) |
| | 129 | return AVERROR_INVALIDDATA; |
| | 130 | if ((ret = ff_get_buffer(avctx, frame, 0)) < 0) |
| | 131 | return ret; |
| | 132 | |
| | 133 | avpkt->data[2] ^= avpkt->data[0]; |
| | 134 | |
| | 135 | ret = inflateReset(&s->zstream); |
| | 136 | if (ret != Z_OK) { |
| | 137 | av_log(avctx, AV_LOG_ERROR, "Inflate reset error: %d\n", ret); |
| | 138 | return AVERROR_UNKNOWN; |
| | 139 | } |
| | 140 | s->zstream.next_in = avpkt->data + 2; |
| | 141 | s->zstream.avail_in = avpkt->size - 2; |
| | 142 | s->zstream.next_out = s->decomp_buf; |
| | 143 | s->zstream.avail_out = s->decomp_size; |
| | 144 | ret = inflate(&s->zstream, Z_FINISH); |
| | 145 | if (ret != Z_STREAM_END) { |
| | 146 | av_log(avctx, AV_LOG_ERROR, "Inflate error: %d\n", ret); |
| | 147 | return AVERROR_UNKNOWN; |
| | 148 | } |
| | 149 | |
| | 150 | bytestream2_init(&gb, s->decomp_buf, s->zstream.total_out); |
| | 151 | bytestream2_init_writer(&pb, s->uncomp_buf, s->uncomp_size); |
| | 152 | |
| | 153 | ret = rle_uncompress(avctx, &gb, &pb, s->bpp); |
| | 154 | if (ret) |
| | 155 | return ret; |
| | 156 | |
| | 157 | for (j = 0; j < avctx->height; j++) { |
| | 158 | memcpy(frame->data[0] + (avctx->height - j - 1) * frame->linesize[0], |
| | 159 | s->uncomp_buf + s->bpp * j * avctx->width, s->bpp * avctx->width); |
| | 160 | } |
| | 161 | |
| | 162 | frame->key_frame = 1; |
| | 163 | frame->pict_type = AV_PICTURE_TYPE_I; |
| | 164 | |
| | 165 | *got_frame = 1; |
| | 166 | |
| | 167 | return avpkt->size; |
| | 168 | } |
| | 169 | |
| | 170 | static av_cold int decode_init(AVCodecContext *avctx) |
| | 171 | { |
| | 172 | MSCCContext *s = avctx->priv_data; |
| | 173 | int zret; |
| | 174 | |
| | 175 | switch (avctx->bits_per_coded_sample) { |
| | 176 | case 8: avctx->pix_fmt = AV_PIX_FMT_GRAY8; break; |
| | 177 | case 16: avctx->pix_fmt = AV_PIX_FMT_RGB555; break; |
| | 178 | case 24: avctx->pix_fmt = AV_PIX_FMT_BGR24; break; |
| | 179 | case 32: avctx->pix_fmt = AV_PIX_FMT_BGRA; break; |
| | 180 | default: |
| | 181 | av_log(avctx, AV_LOG_ERROR, "Unsupported bitdepth %i\n", avctx->bits_per_coded_sample); |
| | 182 | return AVERROR_INVALIDDATA; |
| | 183 | } |
| | 184 | |
| | 185 | s->bpp = avctx->bits_per_coded_sample >> 3; |
| | 186 | memset(&s->zstream, 0, sizeof(z_stream)); |
| | 187 | |
| | 188 | s->decomp_size = 4 * avctx->height * ((avctx->width * avctx->bits_per_coded_sample + 31) / 32); |
| | 189 | if (!(s->decomp_buf = av_malloc(s->decomp_size))) |
| | 190 | return AVERROR(ENOMEM); |
| | 191 | |
| | 192 | s->uncomp_size = 4 * avctx->height * ((avctx->width * avctx->bits_per_coded_sample + 31) / 32); |
| | 193 | if (!(s->uncomp_buf = av_malloc(s->uncomp_size))) |
| | 194 | return AVERROR(ENOMEM); |
| | 195 | |
| | 196 | s->zstream.zalloc = Z_NULL; |
| | 197 | s->zstream.zfree = Z_NULL; |
| | 198 | s->zstream.opaque = Z_NULL; |
| | 199 | zret = inflateInit(&s->zstream); |
| | 200 | if (zret != Z_OK) { |
| | 201 | av_log(avctx, AV_LOG_ERROR, "Inflate init error: %d\n", zret); |
| | 202 | return AVERROR_UNKNOWN; |
| | 203 | } |
| | 204 | |
| | 205 | return 0; |
| | 206 | } |
| | 207 | |
| | 208 | static av_cold int decode_close(AVCodecContext *avctx) |
| | 209 | { |
| | 210 | MSCCContext *s = avctx->priv_data; |
| | 211 | |
| | 212 | av_freep(&s->decomp_buf); |
| | 213 | s->decomp_size = 0; |
| | 214 | av_freep(&s->uncomp_buf); |
| | 215 | s->uncomp_size = 0; |
| | 216 | inflateEnd(&s->zstream); |
| | 217 | |
| | 218 | return 0; |
| | 219 | } |
| | 220 | |
| | 221 | AVCodec ff_mscc_decoder = { |
| | 222 | .name = "mscc", |
| | 223 | .long_name = NULL_IF_CONFIG_SMALL("Mandsoft Screen Capture Codec"), |
| | 224 | .type = AVMEDIA_TYPE_VIDEO, |
| | 225 | .id = AV_CODEC_ID_MSCC, |
| | 226 | .priv_data_size = sizeof(MSCCContext), |
| | 227 | .init = decode_init, |
| | 228 | .close = decode_close, |
| | 229 | .decode = decode_frame, |
| | 230 | .capabilities = AV_CODEC_CAP_DR1, |
| | 231 | }; |