xref: /third_party/ffmpeg/libavcodec/mvha.c (revision cabdff1a)
1cabdff1aSopenharmony_ci/*
2cabdff1aSopenharmony_ci * MidiVid Archive codec
3cabdff1aSopenharmony_ci *
4cabdff1aSopenharmony_ci * Copyright (c) 2019 Paul B Mahol
5cabdff1aSopenharmony_ci *
6cabdff1aSopenharmony_ci * This file is part of FFmpeg.
7cabdff1aSopenharmony_ci *
8cabdff1aSopenharmony_ci * FFmpeg is free software; you can redistribute it and/or
9cabdff1aSopenharmony_ci * modify it under the terms of the GNU Lesser General Public
10cabdff1aSopenharmony_ci * License as published by the Free Software Foundation; either
11cabdff1aSopenharmony_ci * version 2.1 of the License, or (at your option) any later version.
12cabdff1aSopenharmony_ci *
13cabdff1aSopenharmony_ci * FFmpeg is distributed in the hope that it will be useful,
14cabdff1aSopenharmony_ci * but WITHOUT ANY WARRANTY; without even the implied warranty of
15cabdff1aSopenharmony_ci * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16cabdff1aSopenharmony_ci * Lesser General Public License for more details.
17cabdff1aSopenharmony_ci *
18cabdff1aSopenharmony_ci * You should have received a copy of the GNU Lesser General Public
19cabdff1aSopenharmony_ci * License along with FFmpeg; if not, write to the Free Software
20cabdff1aSopenharmony_ci * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21cabdff1aSopenharmony_ci */
22cabdff1aSopenharmony_ci
23cabdff1aSopenharmony_ci#include <stdio.h>
24cabdff1aSopenharmony_ci#include <stdlib.h>
25cabdff1aSopenharmony_ci#include <string.h>
26cabdff1aSopenharmony_ci
27cabdff1aSopenharmony_ci#define CACHED_BITSTREAM_READER !ARCH_X86_32
28cabdff1aSopenharmony_ci#include "libavutil/intreadwrite.h"
29cabdff1aSopenharmony_ci
30cabdff1aSopenharmony_ci#include "avcodec.h"
31cabdff1aSopenharmony_ci#include "bytestream.h"
32cabdff1aSopenharmony_ci#include "codec_internal.h"
33cabdff1aSopenharmony_ci#include "get_bits.h"
34cabdff1aSopenharmony_ci#include "internal.h"
35cabdff1aSopenharmony_ci#include "lossless_videodsp.h"
36cabdff1aSopenharmony_ci#include "zlib_wrapper.h"
37cabdff1aSopenharmony_ci
38cabdff1aSopenharmony_ci#include <zlib.h>
39cabdff1aSopenharmony_ci
40cabdff1aSopenharmony_citypedef struct MVHAContext {
41cabdff1aSopenharmony_ci    GetBitContext     gb;
42cabdff1aSopenharmony_ci    int nb_symbols;
43cabdff1aSopenharmony_ci
44cabdff1aSopenharmony_ci    uint8_t           symb[256];
45cabdff1aSopenharmony_ci    uint32_t          prob[256];
46cabdff1aSopenharmony_ci    VLC               vlc;
47cabdff1aSopenharmony_ci
48cabdff1aSopenharmony_ci    FFZStream         zstream;
49cabdff1aSopenharmony_ci    LLVidDSPContext   llviddsp;
50cabdff1aSopenharmony_ci} MVHAContext;
51cabdff1aSopenharmony_ci
52cabdff1aSopenharmony_citypedef struct Node {
53cabdff1aSopenharmony_ci    int16_t  sym;
54cabdff1aSopenharmony_ci    int16_t  n0;
55cabdff1aSopenharmony_ci    int16_t  l, r;
56cabdff1aSopenharmony_ci    uint32_t count;
57cabdff1aSopenharmony_ci} Node;
58cabdff1aSopenharmony_ci
59cabdff1aSopenharmony_cistatic void get_tree_codes(uint32_t *bits, int16_t *lens, uint8_t *xlat,
60cabdff1aSopenharmony_ci                           Node *nodes, int node,
61cabdff1aSopenharmony_ci                           uint32_t pfx, int pl, int *pos)
62cabdff1aSopenharmony_ci{
63cabdff1aSopenharmony_ci    int s;
64cabdff1aSopenharmony_ci
65cabdff1aSopenharmony_ci    s = nodes[node].sym;
66cabdff1aSopenharmony_ci    if (s != -1) {
67cabdff1aSopenharmony_ci        bits[*pos] = (~pfx) & ((1ULL << FFMAX(pl, 1)) - 1);
68cabdff1aSopenharmony_ci        lens[*pos] = FFMAX(pl, 1);
69cabdff1aSopenharmony_ci        xlat[*pos] = s + (pl == 0);
70cabdff1aSopenharmony_ci        (*pos)++;
71cabdff1aSopenharmony_ci    } else {
72cabdff1aSopenharmony_ci        pfx <<= 1;
73cabdff1aSopenharmony_ci        pl++;
74cabdff1aSopenharmony_ci        get_tree_codes(bits, lens, xlat, nodes, nodes[node].l, pfx, pl,
75cabdff1aSopenharmony_ci                       pos);
76cabdff1aSopenharmony_ci        pfx |= 1;
77cabdff1aSopenharmony_ci        get_tree_codes(bits, lens, xlat, nodes, nodes[node].r, pfx, pl,
78cabdff1aSopenharmony_ci                       pos);
79cabdff1aSopenharmony_ci    }
80cabdff1aSopenharmony_ci}
81cabdff1aSopenharmony_ci
82cabdff1aSopenharmony_cistatic int build_vlc(AVCodecContext *avctx, VLC *vlc)
83cabdff1aSopenharmony_ci{
84cabdff1aSopenharmony_ci    MVHAContext *s = avctx->priv_data;
85cabdff1aSopenharmony_ci    Node nodes[512];
86cabdff1aSopenharmony_ci    uint32_t bits[256];
87cabdff1aSopenharmony_ci    int16_t lens[256];
88cabdff1aSopenharmony_ci    uint8_t xlat[256];
89cabdff1aSopenharmony_ci    int cur_node, i, j, pos = 0;
90cabdff1aSopenharmony_ci
91cabdff1aSopenharmony_ci    ff_free_vlc(vlc);
92cabdff1aSopenharmony_ci
93cabdff1aSopenharmony_ci    for (i = 0; i < s->nb_symbols; i++) {
94cabdff1aSopenharmony_ci        nodes[i].count = s->prob[i];
95cabdff1aSopenharmony_ci        nodes[i].sym   = s->symb[i];
96cabdff1aSopenharmony_ci        nodes[i].n0    = -2;
97cabdff1aSopenharmony_ci        nodes[i].l     = i;
98cabdff1aSopenharmony_ci        nodes[i].r     = i;
99cabdff1aSopenharmony_ci    }
100cabdff1aSopenharmony_ci
101cabdff1aSopenharmony_ci    cur_node = s->nb_symbols;
102cabdff1aSopenharmony_ci    j = 0;
103cabdff1aSopenharmony_ci    do {
104cabdff1aSopenharmony_ci        for (i = 0; ; i++) {
105cabdff1aSopenharmony_ci            int new_node = j;
106cabdff1aSopenharmony_ci            int first_node = cur_node;
107cabdff1aSopenharmony_ci            int second_node = cur_node;
108cabdff1aSopenharmony_ci            unsigned nd, st;
109cabdff1aSopenharmony_ci
110cabdff1aSopenharmony_ci            nodes[cur_node].count = -1;
111cabdff1aSopenharmony_ci
112cabdff1aSopenharmony_ci            do {
113cabdff1aSopenharmony_ci                int val = nodes[new_node].count;
114cabdff1aSopenharmony_ci                if (val && (val < nodes[first_node].count)) {
115cabdff1aSopenharmony_ci                    if (val >= nodes[second_node].count) {
116cabdff1aSopenharmony_ci                        first_node = new_node;
117cabdff1aSopenharmony_ci                    } else {
118cabdff1aSopenharmony_ci                        first_node = second_node;
119cabdff1aSopenharmony_ci                        second_node = new_node;
120cabdff1aSopenharmony_ci                    }
121cabdff1aSopenharmony_ci                }
122cabdff1aSopenharmony_ci                new_node += 1;
123cabdff1aSopenharmony_ci            } while (new_node != cur_node);
124cabdff1aSopenharmony_ci
125cabdff1aSopenharmony_ci            if (first_node == cur_node)
126cabdff1aSopenharmony_ci                break;
127cabdff1aSopenharmony_ci
128cabdff1aSopenharmony_ci            nd = nodes[second_node].count;
129cabdff1aSopenharmony_ci            st = nodes[first_node].count;
130cabdff1aSopenharmony_ci            nodes[second_node].count = 0;
131cabdff1aSopenharmony_ci            nodes[first_node].count  = 0;
132cabdff1aSopenharmony_ci            if (nd >= UINT32_MAX - st) {
133cabdff1aSopenharmony_ci                av_log(avctx, AV_LOG_ERROR, "count overflow\n");
134cabdff1aSopenharmony_ci                return AVERROR_INVALIDDATA;
135cabdff1aSopenharmony_ci            }
136cabdff1aSopenharmony_ci            nodes[cur_node].count = nd + st;
137cabdff1aSopenharmony_ci            nodes[cur_node].sym = -1;
138cabdff1aSopenharmony_ci            nodes[cur_node].n0 = cur_node;
139cabdff1aSopenharmony_ci            nodes[cur_node].l = first_node;
140cabdff1aSopenharmony_ci            nodes[cur_node].r = second_node;
141cabdff1aSopenharmony_ci            cur_node++;
142cabdff1aSopenharmony_ci        }
143cabdff1aSopenharmony_ci        j++;
144cabdff1aSopenharmony_ci    } while (cur_node - s->nb_symbols == j);
145cabdff1aSopenharmony_ci
146cabdff1aSopenharmony_ci    get_tree_codes(bits, lens, xlat, nodes, cur_node - 1, 0, 0, &pos);
147cabdff1aSopenharmony_ci
148cabdff1aSopenharmony_ci    return ff_init_vlc_sparse(vlc, 12, pos, lens, 2, 2, bits, 4, 4, xlat, 1, 1, 0);
149cabdff1aSopenharmony_ci}
150cabdff1aSopenharmony_ci
151cabdff1aSopenharmony_cistatic int decode_frame(AVCodecContext *avctx, AVFrame *frame,
152cabdff1aSopenharmony_ci                        int *got_frame, AVPacket *avpkt)
153cabdff1aSopenharmony_ci{
154cabdff1aSopenharmony_ci    MVHAContext *s = avctx->priv_data;
155cabdff1aSopenharmony_ci    uint32_t type, size;
156cabdff1aSopenharmony_ci    int ret;
157cabdff1aSopenharmony_ci
158cabdff1aSopenharmony_ci    if (avpkt->size <= 8)
159cabdff1aSopenharmony_ci        return AVERROR_INVALIDDATA;
160cabdff1aSopenharmony_ci
161cabdff1aSopenharmony_ci    type = AV_RB32(avpkt->data);
162cabdff1aSopenharmony_ci    size = AV_RL32(avpkt->data + 4);
163cabdff1aSopenharmony_ci
164cabdff1aSopenharmony_ci    if (size < 1 || size >= avpkt->size)
165cabdff1aSopenharmony_ci        return AVERROR_INVALIDDATA;
166cabdff1aSopenharmony_ci
167cabdff1aSopenharmony_ci    if ((ret = ff_get_buffer(avctx, frame, 0)) < 0)
168cabdff1aSopenharmony_ci        return ret;
169cabdff1aSopenharmony_ci
170cabdff1aSopenharmony_ci    if (type == MKTAG('L','Z','Y','V')) {
171cabdff1aSopenharmony_ci        z_stream *const zstream = &s->zstream.zstream;
172cabdff1aSopenharmony_ci        ret = inflateReset(zstream);
173cabdff1aSopenharmony_ci        if (ret != Z_OK) {
174cabdff1aSopenharmony_ci            av_log(avctx, AV_LOG_ERROR, "Inflate reset error: %d\n", ret);
175cabdff1aSopenharmony_ci            return AVERROR_EXTERNAL;
176cabdff1aSopenharmony_ci        }
177cabdff1aSopenharmony_ci
178cabdff1aSopenharmony_ci        zstream->next_in  = avpkt->data + 8;
179cabdff1aSopenharmony_ci        zstream->avail_in = avpkt->size - 8;
180cabdff1aSopenharmony_ci
181cabdff1aSopenharmony_ci        for (int p = 0; p < 3; p++) {
182cabdff1aSopenharmony_ci            for (int y = 0; y < avctx->height; y++) {
183cabdff1aSopenharmony_ci                zstream->next_out  = frame->data[p] + (avctx->height - y - 1) * frame->linesize[p];
184cabdff1aSopenharmony_ci                zstream->avail_out = avctx->width >> (p > 0);
185cabdff1aSopenharmony_ci
186cabdff1aSopenharmony_ci                ret = inflate(zstream, Z_SYNC_FLUSH);
187cabdff1aSopenharmony_ci                if (ret != Z_OK && ret != Z_STREAM_END) {
188cabdff1aSopenharmony_ci                    av_log(avctx, AV_LOG_ERROR, "Inflate error: %d\n", ret);
189cabdff1aSopenharmony_ci                    return AVERROR_EXTERNAL;
190cabdff1aSopenharmony_ci                }
191cabdff1aSopenharmony_ci                if (zsteam->avail_out > 0)
192cabdff1aSopenharmony_ci                    memset(zstream->next_out, 0, zstream->avail_out);
193cabdff1aSopenharmony_ci            }
194cabdff1aSopenharmony_ci        }
195cabdff1aSopenharmony_ci    } else if (type == MKTAG('H','U','F','Y')) {
196cabdff1aSopenharmony_ci        GetBitContext *gb = &s->gb;
197cabdff1aSopenharmony_ci        int first_symbol, symbol;
198cabdff1aSopenharmony_ci
199cabdff1aSopenharmony_ci        ret = init_get_bits8(gb, avpkt->data + 8, avpkt->size - 8);
200cabdff1aSopenharmony_ci        if (ret < 0)
201cabdff1aSopenharmony_ci            return ret;
202cabdff1aSopenharmony_ci
203cabdff1aSopenharmony_ci        skip_bits(gb, 24);
204cabdff1aSopenharmony_ci
205cabdff1aSopenharmony_ci        first_symbol = get_bits(gb, 8);
206cabdff1aSopenharmony_ci        s->nb_symbols = get_bits(gb, 8) + 1;
207cabdff1aSopenharmony_ci
208cabdff1aSopenharmony_ci        symbol = first_symbol;
209cabdff1aSopenharmony_ci        for (int i = 0; i < s->nb_symbols; symbol++) {
210cabdff1aSopenharmony_ci            int prob;
211cabdff1aSopenharmony_ci
212cabdff1aSopenharmony_ci            if (get_bits_left(gb) < 4)
213cabdff1aSopenharmony_ci                return AVERROR_INVALIDDATA;
214cabdff1aSopenharmony_ci
215cabdff1aSopenharmony_ci            if (get_bits1(gb)) {
216cabdff1aSopenharmony_ci                prob = get_bits(gb, 12);
217cabdff1aSopenharmony_ci            } else {
218cabdff1aSopenharmony_ci                prob = get_bits(gb, 3);
219cabdff1aSopenharmony_ci            }
220cabdff1aSopenharmony_ci
221cabdff1aSopenharmony_ci            if (prob) {
222cabdff1aSopenharmony_ci                s->symb[i] = symbol;
223cabdff1aSopenharmony_ci                s->prob[i] = prob;
224cabdff1aSopenharmony_ci                i++;
225cabdff1aSopenharmony_ci            }
226cabdff1aSopenharmony_ci        }
227cabdff1aSopenharmony_ci
228cabdff1aSopenharmony_ci        ret = build_vlc(avctx, &s->vlc);
229cabdff1aSopenharmony_ci        if (ret < 0)
230cabdff1aSopenharmony_ci            return ret;
231cabdff1aSopenharmony_ci
232cabdff1aSopenharmony_ci        for (int p = 0; p < 3; p++) {
233cabdff1aSopenharmony_ci            int width = avctx->width >> (p > 0);
234cabdff1aSopenharmony_ci            ptrdiff_t stride = frame->linesize[p];
235cabdff1aSopenharmony_ci            uint8_t *dst;
236cabdff1aSopenharmony_ci
237cabdff1aSopenharmony_ci            dst = frame->data[p] + (avctx->height - 1) * frame->linesize[p];
238cabdff1aSopenharmony_ci            for (int y = 0; y < avctx->height; y++) {
239cabdff1aSopenharmony_ci                if (get_bits_left(gb) < width)
240cabdff1aSopenharmony_ci                    return AVERROR_INVALIDDATA;
241cabdff1aSopenharmony_ci                for (int x = 0; x < width; x++) {
242cabdff1aSopenharmony_ci                    int v = get_vlc2(gb, s->vlc.table, s->vlc.bits, 3);
243cabdff1aSopenharmony_ci
244cabdff1aSopenharmony_ci                    if (v < 0)
245cabdff1aSopenharmony_ci                        return AVERROR_INVALIDDATA;
246cabdff1aSopenharmony_ci
247cabdff1aSopenharmony_ci                    dst[x] = v;
248cabdff1aSopenharmony_ci                }
249cabdff1aSopenharmony_ci                dst -= stride;
250cabdff1aSopenharmony_ci            }
251cabdff1aSopenharmony_ci        }
252cabdff1aSopenharmony_ci    } else {
253cabdff1aSopenharmony_ci        return AVERROR_INVALIDDATA;
254cabdff1aSopenharmony_ci    }
255cabdff1aSopenharmony_ci
256cabdff1aSopenharmony_ci    for (int p = 0; p < 3; p++) {
257cabdff1aSopenharmony_ci        int left, lefttop;
258cabdff1aSopenharmony_ci        int width = avctx->width >> (p > 0);
259cabdff1aSopenharmony_ci        ptrdiff_t stride = frame->linesize[p];
260cabdff1aSopenharmony_ci        uint8_t *dst;
261cabdff1aSopenharmony_ci
262cabdff1aSopenharmony_ci        dst = frame->data[p] + (avctx->height - 1) * frame->linesize[p];
263cabdff1aSopenharmony_ci        s->llviddsp.add_left_pred(dst, dst, width, 0);
264cabdff1aSopenharmony_ci        if (avctx->height > 1) {
265cabdff1aSopenharmony_ci            dst -= stride;
266cabdff1aSopenharmony_ci            lefttop = left = dst[0];
267cabdff1aSopenharmony_ci            for (int y = 1; y < avctx->height; y++) {
268cabdff1aSopenharmony_ci                s->llviddsp.add_median_pred(dst, dst + stride, dst, width, &left, &lefttop);
269cabdff1aSopenharmony_ci                lefttop = left = dst[0];
270cabdff1aSopenharmony_ci                dst -= stride;
271cabdff1aSopenharmony_ci            }
272cabdff1aSopenharmony_ci        }
273cabdff1aSopenharmony_ci    }
274cabdff1aSopenharmony_ci
275cabdff1aSopenharmony_ci    frame->pict_type = AV_PICTURE_TYPE_I;
276cabdff1aSopenharmony_ci    frame->key_frame = 1;
277cabdff1aSopenharmony_ci    *got_frame = 1;
278cabdff1aSopenharmony_ci
279cabdff1aSopenharmony_ci    return avpkt->size;
280cabdff1aSopenharmony_ci}
281cabdff1aSopenharmony_ci
282cabdff1aSopenharmony_cistatic av_cold int decode_init(AVCodecContext *avctx)
283cabdff1aSopenharmony_ci{
284cabdff1aSopenharmony_ci    MVHAContext *s = avctx->priv_data;
285cabdff1aSopenharmony_ci
286cabdff1aSopenharmony_ci    avctx->pix_fmt = AV_PIX_FMT_YUV422P;
287cabdff1aSopenharmony_ci
288cabdff1aSopenharmony_ci    ff_llviddsp_init(&s->llviddsp);
289cabdff1aSopenharmony_ci
290cabdff1aSopenharmony_ci    return ff_inflate_init(&s->zstream, avctx);
291cabdff1aSopenharmony_ci}
292cabdff1aSopenharmony_ci
293cabdff1aSopenharmony_cistatic av_cold int decode_close(AVCodecContext *avctx)
294cabdff1aSopenharmony_ci{
295cabdff1aSopenharmony_ci    MVHAContext *s = avctx->priv_data;
296cabdff1aSopenharmony_ci
297cabdff1aSopenharmony_ci    ff_inflate_end(&s->zstream);
298cabdff1aSopenharmony_ci    ff_free_vlc(&s->vlc);
299cabdff1aSopenharmony_ci
300cabdff1aSopenharmony_ci    return 0;
301cabdff1aSopenharmony_ci}
302cabdff1aSopenharmony_ci
303cabdff1aSopenharmony_ciconst FFCodec ff_mvha_decoder = {
304cabdff1aSopenharmony_ci    .p.name           = "mvha",
305cabdff1aSopenharmony_ci    .p.long_name      = NULL_IF_CONFIG_SMALL("MidiVid Archive Codec"),
306cabdff1aSopenharmony_ci    .p.type           = AVMEDIA_TYPE_VIDEO,
307cabdff1aSopenharmony_ci    .p.id             = AV_CODEC_ID_MVHA,
308cabdff1aSopenharmony_ci    .priv_data_size   = sizeof(MVHAContext),
309cabdff1aSopenharmony_ci    .init             = decode_init,
310cabdff1aSopenharmony_ci    .close            = decode_close,
311cabdff1aSopenharmony_ci    FF_CODEC_DECODE_CB(decode_frame),
312cabdff1aSopenharmony_ci    .p.capabilities   = AV_CODEC_CAP_DR1,
313cabdff1aSopenharmony_ci    .caps_internal    = FF_CODEC_CAP_INIT_THREADSAFE |
314cabdff1aSopenharmony_ci                        FF_CODEC_CAP_INIT_CLEANUP,
315cabdff1aSopenharmony_ci};
316