| @@ -0,0 +1,288 @@ |
| | 1 | /* |
| | 2 | * vMix decoder |
| | 3 | * Copyright (c) 2023 Paul B Mahol |
| | 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 | #include <stdio.h> |
| | 23 | #include <stdlib.h> |
| | 24 | #include <string.h> |
| | 25 | |
| | 26 | #include "libavutil/avassert.h" |
| | 27 | #include "libavutil/intreadwrite.h" |
| | 28 | #include "libavutil/mem_internal.h" |
| | 29 | |
| | 30 | #include "avcodec.h" |
| | 31 | #include "codec_internal.h" |
| | 32 | #include "decode.h" |
| | 33 | #define CACHED_BITSTREAM_READER !ARCH_X86_32 |
| | 34 | #include "golomb.h" |
| | 35 | #include "get_bits.h" |
| | 36 | #include "idctdsp.h" |
| | 37 | #include "thread.h" |
| | 38 | |
| | 39 | typedef struct SliceContext { |
| | 40 | const uint8_t *dc_ptr; |
| | 41 | const uint8_t *ac_ptr; |
| | 42 | unsigned dc_size; |
| | 43 | unsigned ac_size; |
| | 44 | } SliceContext; |
| | 45 | |
| | 46 | typedef struct VMIXContext { |
| | 47 | int nb_slices; |
| | 48 | |
| | 49 | int16_t factors[64]; |
| | 50 | uint8_t scan[64]; |
| | 51 | |
| | 52 | SliceContext slices[255]; |
| | 53 | |
| | 54 | IDCTDSPContext idsp; |
| | 55 | } VMIXContext; |
| | 56 | |
| | 57 | static const uint8_t quality[25] = { |
| | 58 | 1, 2, 3, 4, 5, 6, 7, 8, 10, 12, 14, 16, |
| | 59 | 18, 20, 22, 24, 28, 32, 36, 40, 44, 48, 52, 56, 64, |
| | 60 | }; |
| | 61 | |
| | 62 | static const uint8_t quant[64] = { |
| | 63 | 16, 16, 19, 22, 22, 26, 26, 27, |
| | 64 | 16, 16, 22, 22, 26, 27, 27, 29, |
| | 65 | 19, 22, 26, 26, 27, 29, 29, 35, |
| | 66 | 22, 24, 27, 27, 29, 32, 34, 38, |
| | 67 | 26, 27, 29, 29, 32, 35, 38, 46, |
| | 68 | 27, 29, 34, 34, 35, 40, 46, 56, |
| | 69 | 29, 34, 34, 37, 40, 48, 56, 69, |
| | 70 | 34, 37, 38, 40, 48, 58, 69, 83, |
| | 71 | }; |
| | 72 | |
| | 73 | static av_cold int decode_init(AVCodecContext *avctx) |
| | 74 | { |
| | 75 | VMIXContext *s = avctx->priv_data; |
| | 76 | |
| | 77 | avctx->bits_per_raw_sample = 8; |
| | 78 | avctx->pix_fmt = AV_PIX_FMT_YUV422P; |
| | 79 | |
| | 80 | avctx->coded_width = FFALIGN(avctx->width, 16); |
| | 81 | avctx->coded_height = FFALIGN(avctx->height, 16); |
| | 82 | |
| | 83 | ff_idctdsp_init(&s->idsp, avctx); |
| | 84 | ff_permute_scantable(s->scan, ff_zigzag_direct, |
| | 85 | s->idsp.idct_permutation); |
| | 86 | return 0; |
| | 87 | } |
| | 88 | |
| | 89 | static inline int get_se_golomb_vmix(GetBitContext *gb) |
| | 90 | { |
| | 91 | unsigned int buf = get_ue_golomb_long(gb); |
| | 92 | int sign = (buf & 1) - 1; |
| | 93 | return ((buf >> 1) ^ (~sign)); |
| | 94 | } |
| | 95 | |
| | 96 | static int decode_dcac(AVCodecContext *avctx, |
| | 97 | GetBitContext *dc_gb, GetBitContext *ac_gb, |
| | 98 | unsigned *dcrun, unsigned *acrun, |
| | 99 | AVFrame *frame, int width, int by, int plane) |
| | 100 | { |
| | 101 | const ptrdiff_t linesize = frame->linesize[plane]; |
| | 102 | uint8_t *dst = frame->data[plane] + by * linesize; |
| | 103 | unsigned dc_run = *dcrun, ac_run = *acrun; |
| | 104 | LOCAL_ALIGNED_32(int16_t, block, [64]); |
| | 105 | VMIXContext *s = avctx->priv_data; |
| | 106 | const int16_t *factors = s->factors; |
| | 107 | const uint8_t *scan = s->scan; |
| | 108 | const int add = plane ? 0 : 1024; |
| | 109 | int i, dc_v = 0, ac_v = 0, dc = 0; |
| | 110 | |
| | 111 | for (int y = 0; y < 2; y++) { |
| | 112 | for (int x = 0; x < width; x += 8) { |
| | 113 | memset(block, 0, sizeof(*block)*64); |
| | 114 | |
| | 115 | if (dc_run > 0) { |
| | 116 | dc_run--; |
| | 117 | } else { |
| | 118 | dc_v = get_se_golomb_vmix(dc_gb); |
| | 119 | dc += dc_v; |
| | 120 | if (!dc_v) |
| | 121 | dc_run = get_ue_golomb_long(dc_gb); |
| | 122 | } |
| | 123 | |
| | 124 | for (int n = 0; n < 64; n++) { |
| | 125 | if (ac_run > 0) { |
| | 126 | ac_run--; |
| | 127 | continue; |
| | 128 | } |
| | 129 | |
| | 130 | ac_v = get_se_golomb_vmix(ac_gb); |
| | 131 | i = scan[n]; |
| | 132 | block[i] = (ac_v * factors[i]) >> 4; |
| | 133 | if (!ac_v) |
| | 134 | ac_run = get_ue_golomb_long(ac_gb); |
| | 135 | } |
| | 136 | |
| | 137 | block[0] = ((dc + add) * 16) >> 4; |
| | 138 | s->idsp.idct_put(dst + x, linesize, block); |
| | 139 | } |
| | 140 | |
| | 141 | dst += 8 * linesize; |
| | 142 | } |
| | 143 | |
| | 144 | *dcrun = dc_run; |
| | 145 | *acrun = ac_run; |
| | 146 | |
| | 147 | return 0; |
| | 148 | } |
| | 149 | |
| | 150 | static int decode_slice(AVCodecContext *avctx, AVFrame *frame, |
| | 151 | const uint8_t *dc_src, unsigned dc_slice_size, |
| | 152 | const uint8_t *ac_src, unsigned ac_slice_size, |
| | 153 | int by) |
| | 154 | { |
| | 155 | unsigned dc_run = 0, ac_run = 0; |
| | 156 | GetBitContext dc_gb, ac_gb; |
| | 157 | int ret; |
| | 158 | |
| | 159 | ret = init_get_bits8(&dc_gb, dc_src, dc_slice_size); |
| | 160 | if (ret < 0) |
| | 161 | return ret; |
| | 162 | |
| | 163 | ret = init_get_bits8(&ac_gb, ac_src, ac_slice_size); |
| | 164 | if (ret < 0) |
| | 165 | return ret; |
| | 166 | |
| | 167 | for (int p = 0; p < 3; p++) { |
| | 168 | const int rshift = !!p; |
| | 169 | ret = decode_dcac(avctx, &dc_gb, &ac_gb, |
| | 170 | &dc_run, &ac_run, frame, |
| | 171 | frame->width >> rshift, by, p); |
| | 172 | if (ret < 0) |
| | 173 | return ret; |
| | 174 | |
| | 175 | if (get_bits_left(&dc_gb) < 0) |
| | 176 | return AVERROR_INVALIDDATA; |
| | 177 | if (get_bits_left(&ac_gb) < 0) |
| | 178 | return AVERROR_INVALIDDATA; |
| | 179 | |
| | 180 | align_get_bits(&dc_gb); |
| | 181 | align_get_bits(&ac_gb); |
| | 182 | } |
| | 183 | |
| | 184 | if (get_bits_left(&dc_gb) > 0) |
| | 185 | return AVERROR_INVALIDDATA; |
| | 186 | if (get_bits_left(&ac_gb) > 0) |
| | 187 | return AVERROR_INVALIDDATA; |
| | 188 | |
| | 189 | return 0; |
| | 190 | } |
| | 191 | |
| | 192 | static int decode_slices(AVCodecContext *avctx, void *arg, |
| | 193 | int n, int thread_nb) |
| | 194 | { |
| | 195 | VMIXContext *s = avctx->priv_data; |
| | 196 | const uint8_t *dc_slice_ptr = s->slices[n].dc_ptr; |
| | 197 | const uint8_t *ac_slice_ptr = s->slices[n].ac_ptr; |
| | 198 | unsigned dc_slice_size = s->slices[n].dc_size; |
| | 199 | unsigned ac_slice_size = s->slices[n].ac_size; |
| | 200 | AVFrame *frame = arg; |
| | 201 | |
| | 202 | return decode_slice(avctx, frame, dc_slice_ptr, dc_slice_size, |
| | 203 | ac_slice_ptr, ac_slice_size, n * 16); |
| | 204 | } |
| | 205 | |
| | 206 | static int decode_frame(AVCodecContext *avctx, |
| | 207 | AVFrame *frame, int *got_frame, |
| | 208 | AVPacket *avpkt) |
| | 209 | { |
| | 210 | VMIXContext *s = avctx->priv_data; |
| | 211 | unsigned offset = 3, q; |
| | 212 | int ret; |
| | 213 | |
| | 214 | if (avpkt->size <= 7) |
| | 215 | return AVERROR_INVALIDDATA; |
| | 216 | |
| | 217 | if (avpkt->data[0] != 0x01) |
| | 218 | return AVERROR_INVALIDDATA; |
| | 219 | |
| | 220 | q = av_clip(99 - av_clip(avpkt->data[1], 0, 99), 0, FF_ARRAY_ELEMS(quality) - 1); |
| | 221 | for (int n = 0; n < 64; n++) |
| | 222 | s->factors[n] = quant[n] * quality[q]; |
| | 223 | |
| | 224 | s->nb_slices = avpkt->data[2]; |
| | 225 | if (!s->nb_slices || s->nb_slices > (avctx->height + 15) / 16) |
| | 226 | return AVERROR_INVALIDDATA; |
| | 227 | |
| | 228 | for (int n = 0; n < s->nb_slices; n++) { |
| | 229 | unsigned slice_size; |
| | 230 | |
| | 231 | if (offset + 4 > avpkt->size) |
| | 232 | return AVERROR_INVALIDDATA; |
| | 233 | |
| | 234 | slice_size = AV_RL32(avpkt->data + offset); |
| | 235 | if (slice_size > avpkt->size) |
| | 236 | return AVERROR_INVALIDDATA; |
| | 237 | |
| | 238 | if (avpkt->size - slice_size - 4LL < offset) |
| | 239 | return AVERROR_INVALIDDATA; |
| | 240 | |
| | 241 | s->slices[n].dc_size = slice_size; |
| | 242 | s->slices[n].dc_ptr = avpkt->data + offset + 4; |
| | 243 | offset += slice_size + 4; |
| | 244 | } |
| | 245 | |
| | 246 | for (int n = 0; n < s->nb_slices; n++) { |
| | 247 | unsigned slice_size; |
| | 248 | |
| | 249 | if (offset + 4 > avpkt->size) |
| | 250 | return AVERROR_INVALIDDATA; |
| | 251 | |
| | 252 | slice_size = AV_RL32(avpkt->data + offset); |
| | 253 | if (slice_size > avpkt->size) |
| | 254 | return AVERROR_INVALIDDATA; |
| | 255 | |
| | 256 | if (avpkt->size - slice_size - 4LL < offset) |
| | 257 | return AVERROR_INVALIDDATA; |
| | 258 | |
| | 259 | s->slices[n].ac_size = slice_size; |
| | 260 | s->slices[n].ac_ptr = avpkt->data + offset + 4; |
| | 261 | offset += slice_size + 4; |
| | 262 | } |
| | 263 | |
| | 264 | ret = ff_thread_get_buffer(avctx, frame, 0); |
| | 265 | if (ret < 0) |
| | 266 | return ret; |
| | 267 | |
| | 268 | avctx->execute2(avctx, decode_slices, frame, NULL, s->nb_slices); |
| | 269 | |
| | 270 | frame->pict_type = AV_PICTURE_TYPE_I; |
| | 271 | frame->flags |= AV_FRAME_FLAG_KEY; |
| | 272 | |
| | 273 | *got_frame = 1; |
| | 274 | |
| | 275 | return avpkt->size; |
| | 276 | } |
| | 277 | |
| | 278 | const FFCodec ff_vmix_decoder = { |
| | 279 | .p.name = "vmix", |
| | 280 | CODEC_LONG_NAME("vMix Video"), |
| | 281 | .p.type = AVMEDIA_TYPE_VIDEO, |
| | 282 | .p.id = AV_CODEC_ID_VMIX, |
| | 283 | .priv_data_size = sizeof(VMIXContext), |
| | 284 | .init = decode_init, |
| | 285 | FF_CODEC_DECODE_CB(decode_frame), |
| | 286 | .p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_FRAME_THREADS | |
| | 287 | AV_CODEC_CAP_SLICE_THREADS, |
| | 288 | }; |