xref: /third_party/ffmpeg/libavcodec/imx.c (revision cabdff1a)
1cabdff1aSopenharmony_ci/*
2cabdff1aSopenharmony_ci * Copyright (c) 2021 Paul B Mahol
3cabdff1aSopenharmony_ci *
4cabdff1aSopenharmony_ci * This file is part of FFmpeg.
5cabdff1aSopenharmony_ci *
6cabdff1aSopenharmony_ci * FFmpeg is free software; you can redistribute it and/or
7cabdff1aSopenharmony_ci * modify it under the terms of the GNU Lesser General Public
8cabdff1aSopenharmony_ci * License as published by the Free Software Foundation; either
9cabdff1aSopenharmony_ci * version 2.1 of the License, or (at your option) any later version.
10cabdff1aSopenharmony_ci *
11cabdff1aSopenharmony_ci * FFmpeg is distributed in the hope that it will be useful,
12cabdff1aSopenharmony_ci * but WITHOUT ANY WARRANTY; without even the implied warranty of
13cabdff1aSopenharmony_ci * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14cabdff1aSopenharmony_ci * Lesser General Public License for more details.
15cabdff1aSopenharmony_ci *
16cabdff1aSopenharmony_ci * You should have received a copy of the GNU Lesser General Public
17cabdff1aSopenharmony_ci * License along with FFmpeg; if not, write to the Free Software
18cabdff1aSopenharmony_ci * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19cabdff1aSopenharmony_ci */
20cabdff1aSopenharmony_ci
21cabdff1aSopenharmony_ci#include "libavutil/common.h"
22cabdff1aSopenharmony_ci#include "avcodec.h"
23cabdff1aSopenharmony_ci#include "bytestream.h"
24cabdff1aSopenharmony_ci#include "codec_internal.h"
25cabdff1aSopenharmony_ci#include "decode.h"
26cabdff1aSopenharmony_ci#include "internal.h"
27cabdff1aSopenharmony_ci
28cabdff1aSopenharmony_citypedef struct SimbiosisIMXContext {
29cabdff1aSopenharmony_ci    AVFrame *frame;
30cabdff1aSopenharmony_ci    uint32_t pal[256];
31cabdff1aSopenharmony_ci    uint8_t history[32768];
32cabdff1aSopenharmony_ci    int pos;
33cabdff1aSopenharmony_ci} SimbiosisIMXContext;
34cabdff1aSopenharmony_ci
35cabdff1aSopenharmony_cistatic av_cold int imx_decode_init(AVCodecContext *avctx)
36cabdff1aSopenharmony_ci{
37cabdff1aSopenharmony_ci    SimbiosisIMXContext *imx = avctx->priv_data;
38cabdff1aSopenharmony_ci
39cabdff1aSopenharmony_ci    avctx->pix_fmt = AV_PIX_FMT_PAL8;
40cabdff1aSopenharmony_ci    avctx->width   = 320;
41cabdff1aSopenharmony_ci    avctx->height  = 160;
42cabdff1aSopenharmony_ci
43cabdff1aSopenharmony_ci    imx->frame = av_frame_alloc();
44cabdff1aSopenharmony_ci    if (!imx->frame)
45cabdff1aSopenharmony_ci        return AVERROR(ENOMEM);
46cabdff1aSopenharmony_ci
47cabdff1aSopenharmony_ci    return 0;
48cabdff1aSopenharmony_ci}
49cabdff1aSopenharmony_ci
50cabdff1aSopenharmony_cistatic int imx_decode_frame(AVCodecContext *avctx, AVFrame *rframe,
51cabdff1aSopenharmony_ci                            int *got_frame, AVPacket *avpkt)
52cabdff1aSopenharmony_ci{
53cabdff1aSopenharmony_ci    SimbiosisIMXContext *imx = avctx->priv_data;
54cabdff1aSopenharmony_ci    int ret, x, y;
55cabdff1aSopenharmony_ci    AVFrame *frame = imx->frame;
56cabdff1aSopenharmony_ci    GetByteContext gb;
57cabdff1aSopenharmony_ci
58cabdff1aSopenharmony_ci    if ((ret = ff_reget_buffer(avctx, frame, 0)) < 0)
59cabdff1aSopenharmony_ci        return ret;
60cabdff1aSopenharmony_ci
61cabdff1aSopenharmony_ci    if (ff_copy_palette(imx->pal, avpkt, avctx)) {
62cabdff1aSopenharmony_ci        frame->palette_has_changed = 1;
63cabdff1aSopenharmony_ci        frame->key_frame = 1;
64cabdff1aSopenharmony_ci    } else {
65cabdff1aSopenharmony_ci        frame->key_frame = 0;
66cabdff1aSopenharmony_ci        frame->palette_has_changed = 0;
67cabdff1aSopenharmony_ci    }
68cabdff1aSopenharmony_ci
69cabdff1aSopenharmony_ci    bytestream2_init(&gb, avpkt->data, avpkt->size);
70cabdff1aSopenharmony_ci
71cabdff1aSopenharmony_ci    memcpy(frame->data[1], imx->pal, AVPALETTE_SIZE);
72cabdff1aSopenharmony_ci
73cabdff1aSopenharmony_ci    x = 0, y = 0;
74cabdff1aSopenharmony_ci    while (bytestream2_get_bytes_left(&gb) > 0 &&
75cabdff1aSopenharmony_ci           x < 320 && y < 160) {
76cabdff1aSopenharmony_ci        int b = bytestream2_get_byte(&gb);
77cabdff1aSopenharmony_ci        int len = b & 0x3f;
78cabdff1aSopenharmony_ci        int op = b >> 6;
79cabdff1aSopenharmony_ci        int fill;
80cabdff1aSopenharmony_ci
81cabdff1aSopenharmony_ci        switch (op) {
82cabdff1aSopenharmony_ci        case 3:
83cabdff1aSopenharmony_ci            len = len * 64 + bytestream2_get_byte(&gb);
84cabdff1aSopenharmony_ci        case 0:
85cabdff1aSopenharmony_ci            while (len > 0) {
86cabdff1aSopenharmony_ci                x++;
87cabdff1aSopenharmony_ci                len--;
88cabdff1aSopenharmony_ci                if (x >= 320) {
89cabdff1aSopenharmony_ci                    x = 0;
90cabdff1aSopenharmony_ci                    y++;
91cabdff1aSopenharmony_ci                }
92cabdff1aSopenharmony_ci                if (y >= 160)
93cabdff1aSopenharmony_ci                    break;
94cabdff1aSopenharmony_ci            }
95cabdff1aSopenharmony_ci
96cabdff1aSopenharmony_ci            frame->key_frame = 0;
97cabdff1aSopenharmony_ci            break;
98cabdff1aSopenharmony_ci        case 1:
99cabdff1aSopenharmony_ci            if (len == 0) {
100cabdff1aSopenharmony_ci                int offset = bytestream2_get_le16(&gb);
101cabdff1aSopenharmony_ci
102cabdff1aSopenharmony_ci                if (offset < 0 || offset >= 32768)
103cabdff1aSopenharmony_ci                    return AVERROR_INVALIDDATA;
104cabdff1aSopenharmony_ci
105cabdff1aSopenharmony_ci                len = bytestream2_get_byte(&gb);
106cabdff1aSopenharmony_ci                while (len > 0 && offset < 32768) {
107cabdff1aSopenharmony_ci                    frame->data[0][x + y * frame->linesize[0]] = imx->history[offset++];
108cabdff1aSopenharmony_ci                    x++;
109cabdff1aSopenharmony_ci                    len--;
110cabdff1aSopenharmony_ci                    if (x >= 320) {
111cabdff1aSopenharmony_ci                        x = 0;
112cabdff1aSopenharmony_ci                        y++;
113cabdff1aSopenharmony_ci                    }
114cabdff1aSopenharmony_ci                    if (y >= 160)
115cabdff1aSopenharmony_ci                        break;
116cabdff1aSopenharmony_ci                }
117cabdff1aSopenharmony_ci
118cabdff1aSopenharmony_ci                frame->key_frame = 0;
119cabdff1aSopenharmony_ci            } else {
120cabdff1aSopenharmony_ci                while (len > 0) {
121cabdff1aSopenharmony_ci                    fill = bytestream2_get_byte(&gb);
122cabdff1aSopenharmony_ci                    frame->data[0][x + y * frame->linesize[0]] = fill;
123cabdff1aSopenharmony_ci                    if (imx->pos < 32768)
124cabdff1aSopenharmony_ci                        imx->history[imx->pos++] = fill;
125cabdff1aSopenharmony_ci                    x++;
126cabdff1aSopenharmony_ci                    len--;
127cabdff1aSopenharmony_ci                    if (x >= 320) {
128cabdff1aSopenharmony_ci                        x = 0;
129cabdff1aSopenharmony_ci                        y++;
130cabdff1aSopenharmony_ci                    }
131cabdff1aSopenharmony_ci                    if (y >= 160)
132cabdff1aSopenharmony_ci                        break;
133cabdff1aSopenharmony_ci                }
134cabdff1aSopenharmony_ci            }
135cabdff1aSopenharmony_ci            break;
136cabdff1aSopenharmony_ci        case 2:
137cabdff1aSopenharmony_ci            fill = bytestream2_get_byte(&gb);
138cabdff1aSopenharmony_ci
139cabdff1aSopenharmony_ci            while (len > 0) {
140cabdff1aSopenharmony_ci                frame->data[0][x + y * frame->linesize[0]] = fill;
141cabdff1aSopenharmony_ci                x++;
142cabdff1aSopenharmony_ci                len--;
143cabdff1aSopenharmony_ci                if (x >= 320) {
144cabdff1aSopenharmony_ci                    x = 0;
145cabdff1aSopenharmony_ci                    y++;
146cabdff1aSopenharmony_ci                }
147cabdff1aSopenharmony_ci                if (y >= 160)
148cabdff1aSopenharmony_ci                    break;
149cabdff1aSopenharmony_ci            }
150cabdff1aSopenharmony_ci            break;
151cabdff1aSopenharmony_ci        }
152cabdff1aSopenharmony_ci    }
153cabdff1aSopenharmony_ci
154cabdff1aSopenharmony_ci    frame->pict_type = frame->key_frame ? AV_PICTURE_TYPE_I : AV_PICTURE_TYPE_P;
155cabdff1aSopenharmony_ci
156cabdff1aSopenharmony_ci    if ((ret = av_frame_ref(rframe, frame)) < 0)
157cabdff1aSopenharmony_ci        return ret;
158cabdff1aSopenharmony_ci
159cabdff1aSopenharmony_ci    *got_frame = 1;
160cabdff1aSopenharmony_ci
161cabdff1aSopenharmony_ci    return avpkt->size;
162cabdff1aSopenharmony_ci}
163cabdff1aSopenharmony_ci
164cabdff1aSopenharmony_cistatic void imx_decode_flush(AVCodecContext *avctx)
165cabdff1aSopenharmony_ci{
166cabdff1aSopenharmony_ci    SimbiosisIMXContext *imx = avctx->priv_data;
167cabdff1aSopenharmony_ci
168cabdff1aSopenharmony_ci    av_frame_unref(imx->frame);
169cabdff1aSopenharmony_ci    imx->pos = 0;
170cabdff1aSopenharmony_ci    memset(imx->pal, 0, sizeof(imx->pal));
171cabdff1aSopenharmony_ci    memset(imx->history, 0, sizeof(imx->history));
172cabdff1aSopenharmony_ci}
173cabdff1aSopenharmony_ci
174cabdff1aSopenharmony_cistatic int imx_decode_close(AVCodecContext *avctx)
175cabdff1aSopenharmony_ci{
176cabdff1aSopenharmony_ci    SimbiosisIMXContext *imx = avctx->priv_data;
177cabdff1aSopenharmony_ci
178cabdff1aSopenharmony_ci    av_frame_free(&imx->frame);
179cabdff1aSopenharmony_ci
180cabdff1aSopenharmony_ci    return 0;
181cabdff1aSopenharmony_ci}
182cabdff1aSopenharmony_ci
183cabdff1aSopenharmony_ciconst FFCodec ff_simbiosis_imx_decoder = {
184cabdff1aSopenharmony_ci    .p.name         = "simbiosis_imx",
185cabdff1aSopenharmony_ci    .p.long_name    = NULL_IF_CONFIG_SMALL("Simbiosis Interactive IMX Video"),
186cabdff1aSopenharmony_ci    .p.type         = AVMEDIA_TYPE_VIDEO,
187cabdff1aSopenharmony_ci    .p.id           = AV_CODEC_ID_SIMBIOSIS_IMX,
188cabdff1aSopenharmony_ci    .priv_data_size = sizeof(SimbiosisIMXContext),
189cabdff1aSopenharmony_ci    .init           = imx_decode_init,
190cabdff1aSopenharmony_ci    FF_CODEC_DECODE_CB(imx_decode_frame),
191cabdff1aSopenharmony_ci    .close          = imx_decode_close,
192cabdff1aSopenharmony_ci    .flush          = imx_decode_flush,
193cabdff1aSopenharmony_ci    .p.capabilities = AV_CODEC_CAP_DR1,
194cabdff1aSopenharmony_ci    .caps_internal  = FF_CODEC_CAP_INIT_THREADSAFE |
195cabdff1aSopenharmony_ci                      FF_CODEC_CAP_INIT_CLEANUP,
196cabdff1aSopenharmony_ci};
197