xref: /third_party/ffmpeg/libavcodec/mvcdec.c (revision cabdff1a)
1cabdff1aSopenharmony_ci/*
2cabdff1aSopenharmony_ci * Silicon Graphics Motion Video Compressor 1 & 2 decoder
3cabdff1aSopenharmony_ci * Copyright (c) 2012 Peter Ross
4cabdff1aSopenharmony_ci *
5cabdff1aSopenharmony_ci * This file is part of FFmpeg.
6cabdff1aSopenharmony_ci *
7cabdff1aSopenharmony_ci * FFmpeg is free software; you can redistribute it and/or
8cabdff1aSopenharmony_ci * modify it under the terms of the GNU Lesser General Public
9cabdff1aSopenharmony_ci * License as published by the Free Software Foundation; either
10cabdff1aSopenharmony_ci * version 2.1 of the License, or (at your option) any later version.
11cabdff1aSopenharmony_ci *
12cabdff1aSopenharmony_ci * FFmpeg is distributed in the hope that it will be useful,
13cabdff1aSopenharmony_ci * but WITHOUT ANY WARRANTY; without even the implied warranty of
14cabdff1aSopenharmony_ci * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15cabdff1aSopenharmony_ci * Lesser General Public License for more details.
16cabdff1aSopenharmony_ci *
17cabdff1aSopenharmony_ci * You should have received a copy of the GNU Lesser General Public
18cabdff1aSopenharmony_ci * License along with FFmpeg; if not, write to the Free Software
19cabdff1aSopenharmony_ci * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20cabdff1aSopenharmony_ci */
21cabdff1aSopenharmony_ci
22cabdff1aSopenharmony_ci/**
23cabdff1aSopenharmony_ci * @file
24cabdff1aSopenharmony_ci * Silicon Graphics Motion Video Compressor 1 & 2 decoder
25cabdff1aSopenharmony_ci */
26cabdff1aSopenharmony_ci
27cabdff1aSopenharmony_ci#include "config_components.h"
28cabdff1aSopenharmony_ci
29cabdff1aSopenharmony_ci#include "libavutil/intreadwrite.h"
30cabdff1aSopenharmony_ci
31cabdff1aSopenharmony_ci#include "avcodec.h"
32cabdff1aSopenharmony_ci#include "bytestream.h"
33cabdff1aSopenharmony_ci#include "codec_internal.h"
34cabdff1aSopenharmony_ci#include "internal.h"
35cabdff1aSopenharmony_ci
36cabdff1aSopenharmony_citypedef struct MvcContext {
37cabdff1aSopenharmony_ci    int vflip;
38cabdff1aSopenharmony_ci} MvcContext;
39cabdff1aSopenharmony_ci
40cabdff1aSopenharmony_cistatic av_cold int mvc_decode_init(AVCodecContext *avctx)
41cabdff1aSopenharmony_ci{
42cabdff1aSopenharmony_ci    MvcContext *s = avctx->priv_data;
43cabdff1aSopenharmony_ci    int width     = avctx->width;
44cabdff1aSopenharmony_ci    int height    = avctx->height;
45cabdff1aSopenharmony_ci    int ret;
46cabdff1aSopenharmony_ci
47cabdff1aSopenharmony_ci    if (avctx->codec_id == AV_CODEC_ID_MVC1) {
48cabdff1aSopenharmony_ci        width  += 3;
49cabdff1aSopenharmony_ci        height += 3;
50cabdff1aSopenharmony_ci    }
51cabdff1aSopenharmony_ci    width  &= ~3;
52cabdff1aSopenharmony_ci    height &= ~3;
53cabdff1aSopenharmony_ci    if ((ret = ff_set_dimensions(avctx, width, height)) < 0)
54cabdff1aSopenharmony_ci        return ret;
55cabdff1aSopenharmony_ci
56cabdff1aSopenharmony_ci    avctx->pix_fmt = (avctx->codec_id == AV_CODEC_ID_MVC1) ? AV_PIX_FMT_RGB555
57cabdff1aSopenharmony_ci                                                           : AV_PIX_FMT_RGB32;
58cabdff1aSopenharmony_ci    s->vflip = avctx->extradata_size >= 9 &&
59cabdff1aSopenharmony_ci               !memcmp(avctx->extradata + avctx->extradata_size - 9, "BottomUp", 9);
60cabdff1aSopenharmony_ci    return 0;
61cabdff1aSopenharmony_ci}
62cabdff1aSopenharmony_ci
63cabdff1aSopenharmony_cistatic int decode_mvc1(AVCodecContext *avctx, GetByteContext *gb,
64cabdff1aSopenharmony_ci                       uint8_t *dst_start, int width, int height, int linesize)
65cabdff1aSopenharmony_ci{
66cabdff1aSopenharmony_ci    uint8_t *dst;
67cabdff1aSopenharmony_ci    uint16_t v[8];
68cabdff1aSopenharmony_ci    int mask, x, y, i;
69cabdff1aSopenharmony_ci
70cabdff1aSopenharmony_ci    for (y = 0; y < height; y += 4) {
71cabdff1aSopenharmony_ci        for (x = 0; x < width; x += 4) {
72cabdff1aSopenharmony_ci            if (bytestream2_get_bytes_left(gb) < 6)
73cabdff1aSopenharmony_ci                return 0;
74cabdff1aSopenharmony_ci
75cabdff1aSopenharmony_ci            mask = bytestream2_get_be16u(gb);
76cabdff1aSopenharmony_ci            v[0] = bytestream2_get_be16u(gb);
77cabdff1aSopenharmony_ci            v[1] = bytestream2_get_be16u(gb);
78cabdff1aSopenharmony_ci            if ((v[0] & 0x8000)) {
79cabdff1aSopenharmony_ci                if (bytestream2_get_bytes_left(gb) < 12) {
80cabdff1aSopenharmony_ci                    av_log(avctx, AV_LOG_WARNING, "buffer overflow\n");
81cabdff1aSopenharmony_ci                    return AVERROR_INVALIDDATA;
82cabdff1aSopenharmony_ci                }
83cabdff1aSopenharmony_ci                for (i = 2; i < 8; i++)
84cabdff1aSopenharmony_ci                    v[i] = bytestream2_get_be16u(gb);
85cabdff1aSopenharmony_ci            } else {
86cabdff1aSopenharmony_ci                v[2] = v[4] = v[6] = v[0];
87cabdff1aSopenharmony_ci                v[3] = v[5] = v[7] = v[1];
88cabdff1aSopenharmony_ci            }
89cabdff1aSopenharmony_ci
90cabdff1aSopenharmony_ci#define PIX16(target, true, false)                                            \
91cabdff1aSopenharmony_ci    i = (mask & target) ? true : false;                                       \
92cabdff1aSopenharmony_ci    AV_WN16A(dst, v[i] & 0x7FFF);                                             \
93cabdff1aSopenharmony_ci    dst += 2;
94cabdff1aSopenharmony_ci
95cabdff1aSopenharmony_ci#define ROW16(row, a1, a0, b1, b0)                                            \
96cabdff1aSopenharmony_ci    dst = dst_start + (y + row) * linesize + x * 2;                           \
97cabdff1aSopenharmony_ci    PIX16(1 << (row * 4), a1, a0)                                             \
98cabdff1aSopenharmony_ci    PIX16(1 << (row * 4 + 1), a1, a0)                                         \
99cabdff1aSopenharmony_ci    PIX16(1 << (row * 4 + 2), b1, b0)                                         \
100cabdff1aSopenharmony_ci    PIX16(1 << (row * 4 + 3), b1, b0)
101cabdff1aSopenharmony_ci
102cabdff1aSopenharmony_ci            ROW16(0, 0, 1, 2, 3);
103cabdff1aSopenharmony_ci            ROW16(1, 0, 1, 2, 3);
104cabdff1aSopenharmony_ci            ROW16(2, 4, 5, 6, 7);
105cabdff1aSopenharmony_ci            ROW16(3, 4, 5, 6, 7);
106cabdff1aSopenharmony_ci        }
107cabdff1aSopenharmony_ci    }
108cabdff1aSopenharmony_ci    return 0;
109cabdff1aSopenharmony_ci}
110cabdff1aSopenharmony_ci
111cabdff1aSopenharmony_cistatic void set_4x4_block(uint8_t *dst, int linesize, uint32_t pixel)
112cabdff1aSopenharmony_ci{
113cabdff1aSopenharmony_ci    int i, j;
114cabdff1aSopenharmony_ci    for (j = 0; j < 4; j++)
115cabdff1aSopenharmony_ci        for (i = 0; i < 4; i++)
116cabdff1aSopenharmony_ci            AV_WN32A(dst + j * linesize + i * 4, pixel);
117cabdff1aSopenharmony_ci}
118cabdff1aSopenharmony_ci
119cabdff1aSopenharmony_ci#define PIX32(target, true, false)                                            \
120cabdff1aSopenharmony_ci    AV_WN32A(dst, (mask & target) ? v[true] : v[false]);                      \
121cabdff1aSopenharmony_ci    dst += 4;
122cabdff1aSopenharmony_ci
123cabdff1aSopenharmony_ci#define ROW32(row, a1, a0, b1, b0)                                            \
124cabdff1aSopenharmony_ci    dst = dst_start + (y + row) * linesize + x * 4;                           \
125cabdff1aSopenharmony_ci    PIX32(1 << (row * 4), a1, a0)                                             \
126cabdff1aSopenharmony_ci    PIX32(1 << (row * 4 + 1), a1, a0)                                         \
127cabdff1aSopenharmony_ci    PIX32(1 << (row * 4 + 2), b1, b0)                                         \
128cabdff1aSopenharmony_ci    PIX32(1 << (row * 4 + 3), b1, b0)
129cabdff1aSopenharmony_ci
130cabdff1aSopenharmony_ci#define MVC2_BLOCK                                                            \
131cabdff1aSopenharmony_ci    ROW32(0, 1, 0, 3, 2);                                                     \
132cabdff1aSopenharmony_ci    ROW32(1, 1, 0, 3, 2);                                                     \
133cabdff1aSopenharmony_ci    ROW32(2, 5, 4, 7, 6);                                                     \
134cabdff1aSopenharmony_ci    ROW32(3, 5, 4, 7, 6);
135cabdff1aSopenharmony_ci
136cabdff1aSopenharmony_cistatic int decode_mvc2(AVCodecContext *avctx, GetByteContext *gb,
137cabdff1aSopenharmony_ci                       uint8_t *dst_start, int width, int height,
138cabdff1aSopenharmony_ci                       int linesize, int vflip)
139cabdff1aSopenharmony_ci{
140cabdff1aSopenharmony_ci    uint8_t *dst;
141cabdff1aSopenharmony_ci    uint32_t color[128], v[8];
142cabdff1aSopenharmony_ci    int w, h, nb_colors, i, x, y, p0, p1, mask;
143cabdff1aSopenharmony_ci
144cabdff1aSopenharmony_ci    if (bytestream2_get_bytes_left(gb) < 6)
145cabdff1aSopenharmony_ci        return AVERROR_INVALIDDATA;
146cabdff1aSopenharmony_ci
147cabdff1aSopenharmony_ci    w = bytestream2_get_be16u(gb);
148cabdff1aSopenharmony_ci    h = bytestream2_get_be16u(gb);
149cabdff1aSopenharmony_ci    if ((w & ~3) != width || (h & ~3) != height)
150cabdff1aSopenharmony_ci        av_log(avctx, AV_LOG_WARNING, "dimension mismatch\n");
151cabdff1aSopenharmony_ci
152cabdff1aSopenharmony_ci    if (bytestream2_get_byteu(gb)) {
153cabdff1aSopenharmony_ci        avpriv_request_sample(avctx, "bitmap feature");
154cabdff1aSopenharmony_ci        return AVERROR_PATCHWELCOME;
155cabdff1aSopenharmony_ci    }
156cabdff1aSopenharmony_ci
157cabdff1aSopenharmony_ci    nb_colors = bytestream2_get_byteu(gb);
158cabdff1aSopenharmony_ci    if (bytestream2_get_bytes_left(gb) < nb_colors * 3)
159cabdff1aSopenharmony_ci        return AVERROR_INVALIDDATA;
160cabdff1aSopenharmony_ci    for (i = 0; i < FFMIN(nb_colors, 128); i++)
161cabdff1aSopenharmony_ci        color[i] = 0xFF000000 | bytestream2_get_be24u(gb);
162cabdff1aSopenharmony_ci    if (nb_colors > 128)
163cabdff1aSopenharmony_ci        bytestream2_skip(gb, (nb_colors - 128) * 3);
164cabdff1aSopenharmony_ci
165cabdff1aSopenharmony_ci    if (vflip) {
166cabdff1aSopenharmony_ci        dst_start += (height - 1) * linesize;
167cabdff1aSopenharmony_ci        linesize   = -linesize;
168cabdff1aSopenharmony_ci    }
169cabdff1aSopenharmony_ci    x = y = 0;
170cabdff1aSopenharmony_ci    while (bytestream2_get_bytes_left(gb) >= 1) {
171cabdff1aSopenharmony_ci        p0 = bytestream2_get_byteu(gb);
172cabdff1aSopenharmony_ci        if ((p0 & 0x80)) {
173cabdff1aSopenharmony_ci            if ((p0 & 0x40)) {
174cabdff1aSopenharmony_ci                p0 &= 0x3F;
175cabdff1aSopenharmony_ci                p0  = (p0 << 2) | (p0 >> 4);
176cabdff1aSopenharmony_ci                set_4x4_block(dst_start + y * linesize + x * 4, linesize,
177cabdff1aSopenharmony_ci                              0xFF000000 | (p0 << 16) | (p0 << 8) | p0);
178cabdff1aSopenharmony_ci            } else {
179cabdff1aSopenharmony_ci                int g, r;
180cabdff1aSopenharmony_ci                p0 &= 0x3F;
181cabdff1aSopenharmony_ci                p0  = (p0 << 2) | (p0 >> 4);
182cabdff1aSopenharmony_ci                if (bytestream2_get_bytes_left(gb) < 2)
183cabdff1aSopenharmony_ci                    return AVERROR_INVALIDDATA;
184cabdff1aSopenharmony_ci                g = bytestream2_get_byteu(gb);
185cabdff1aSopenharmony_ci                r = bytestream2_get_byteu(gb);
186cabdff1aSopenharmony_ci                set_4x4_block(dst_start + y * linesize + x * 4, linesize,
187cabdff1aSopenharmony_ci                              0xFF000000 | (r << 16) | (g << 8) | p0);
188cabdff1aSopenharmony_ci            }
189cabdff1aSopenharmony_ci        } else {
190cabdff1aSopenharmony_ci            if (bytestream2_get_bytes_left(gb) < 1)
191cabdff1aSopenharmony_ci                return AVERROR_INVALIDDATA;
192cabdff1aSopenharmony_ci            p1 = bytestream2_get_byteu(gb);
193cabdff1aSopenharmony_ci            if ((p1 & 0x80)) {
194cabdff1aSopenharmony_ci                if ((p0 & 0x7F) == (p1 & 0x7F)) {
195cabdff1aSopenharmony_ci                    set_4x4_block(dst_start + y * linesize + x * 4, linesize,
196cabdff1aSopenharmony_ci                                  color[p0 & 0x7F]);
197cabdff1aSopenharmony_ci                } else {
198cabdff1aSopenharmony_ci                    if (bytestream2_get_bytes_left(gb) < 2)
199cabdff1aSopenharmony_ci                        return AVERROR_INVALIDDATA;
200cabdff1aSopenharmony_ci                    v[0] = v[2] = v[4] = v[6] = color[p0 & 0x7F];
201cabdff1aSopenharmony_ci                    v[1] = v[3] = v[5] = v[7] = color[p1 & 0x7F];
202cabdff1aSopenharmony_ci                    mask = bytestream2_get_le16u(gb);
203cabdff1aSopenharmony_ci                    MVC2_BLOCK
204cabdff1aSopenharmony_ci                }
205cabdff1aSopenharmony_ci            } else {
206cabdff1aSopenharmony_ci                if (bytestream2_get_bytes_left(gb) < 8)
207cabdff1aSopenharmony_ci                    return AVERROR_INVALIDDATA;
208cabdff1aSopenharmony_ci                v[0] = color[p0 & 0x7F];
209cabdff1aSopenharmony_ci                v[1] = color[p1 & 0x7F];
210cabdff1aSopenharmony_ci                for (i = 2; i < 8; i++)
211cabdff1aSopenharmony_ci                    v[i] = color[bytestream2_get_byteu(gb) & 0x7F];
212cabdff1aSopenharmony_ci                mask = bytestream2_get_le16u(gb);
213cabdff1aSopenharmony_ci                MVC2_BLOCK
214cabdff1aSopenharmony_ci            }
215cabdff1aSopenharmony_ci        }
216cabdff1aSopenharmony_ci
217cabdff1aSopenharmony_ci        x += 4;
218cabdff1aSopenharmony_ci        if (x >= width) {
219cabdff1aSopenharmony_ci            y += 4;
220cabdff1aSopenharmony_ci            if (y >= height)
221cabdff1aSopenharmony_ci                break;
222cabdff1aSopenharmony_ci            x = 0;
223cabdff1aSopenharmony_ci        }
224cabdff1aSopenharmony_ci    }
225cabdff1aSopenharmony_ci    return 0;
226cabdff1aSopenharmony_ci}
227cabdff1aSopenharmony_ci
228cabdff1aSopenharmony_cistatic int mvc_decode_frame(AVCodecContext *avctx, AVFrame *frame,
229cabdff1aSopenharmony_ci                            int *got_frame, AVPacket *avpkt)
230cabdff1aSopenharmony_ci{
231cabdff1aSopenharmony_ci    MvcContext *s = avctx->priv_data;
232cabdff1aSopenharmony_ci    GetByteContext gb;
233cabdff1aSopenharmony_ci    int ret;
234cabdff1aSopenharmony_ci
235cabdff1aSopenharmony_ci    if ((ret = ff_get_buffer(avctx, frame, 0)) < 0)
236cabdff1aSopenharmony_ci        return ret;
237cabdff1aSopenharmony_ci
238cabdff1aSopenharmony_ci    bytestream2_init(&gb, avpkt->data, avpkt->size);
239cabdff1aSopenharmony_ci    if (avctx->codec_id == AV_CODEC_ID_MVC1)
240cabdff1aSopenharmony_ci        ret = decode_mvc1(avctx, &gb, frame->data[0],
241cabdff1aSopenharmony_ci                          avctx->width, avctx->height, frame->linesize[0]);
242cabdff1aSopenharmony_ci    else
243cabdff1aSopenharmony_ci        ret = decode_mvc2(avctx, &gb, frame->data[0],
244cabdff1aSopenharmony_ci                          avctx->width, avctx->height, frame->linesize[0],
245cabdff1aSopenharmony_ci                          s->vflip);
246cabdff1aSopenharmony_ci    if (ret < 0)
247cabdff1aSopenharmony_ci        return ret;
248cabdff1aSopenharmony_ci
249cabdff1aSopenharmony_ci    frame->pict_type = AV_PICTURE_TYPE_I;
250cabdff1aSopenharmony_ci    frame->key_frame = 1;
251cabdff1aSopenharmony_ci
252cabdff1aSopenharmony_ci    *got_frame = 1;
253cabdff1aSopenharmony_ci
254cabdff1aSopenharmony_ci    return avpkt->size;
255cabdff1aSopenharmony_ci}
256cabdff1aSopenharmony_ci
257cabdff1aSopenharmony_ci#if CONFIG_MVC1_DECODER
258cabdff1aSopenharmony_ciconst FFCodec ff_mvc1_decoder = {
259cabdff1aSopenharmony_ci    .p.name         = "mvc1",
260cabdff1aSopenharmony_ci    .p.long_name    = NULL_IF_CONFIG_SMALL("Silicon Graphics Motion Video Compressor 1"),
261cabdff1aSopenharmony_ci    .p.type         = AVMEDIA_TYPE_VIDEO,
262cabdff1aSopenharmony_ci    .p.id           = AV_CODEC_ID_MVC1,
263cabdff1aSopenharmony_ci    .priv_data_size = sizeof(MvcContext),
264cabdff1aSopenharmony_ci    .init           = mvc_decode_init,
265cabdff1aSopenharmony_ci    FF_CODEC_DECODE_CB(mvc_decode_frame),
266cabdff1aSopenharmony_ci    .p.capabilities = AV_CODEC_CAP_DR1,
267cabdff1aSopenharmony_ci    .caps_internal  = FF_CODEC_CAP_INIT_THREADSAFE,
268cabdff1aSopenharmony_ci};
269cabdff1aSopenharmony_ci#endif
270cabdff1aSopenharmony_ci
271cabdff1aSopenharmony_ci#if CONFIG_MVC2_DECODER
272cabdff1aSopenharmony_ciconst FFCodec ff_mvc2_decoder = {
273cabdff1aSopenharmony_ci    .p.name         = "mvc2",
274cabdff1aSopenharmony_ci    .p.long_name    = NULL_IF_CONFIG_SMALL("Silicon Graphics Motion Video Compressor 2"),
275cabdff1aSopenharmony_ci    .p.type         = AVMEDIA_TYPE_VIDEO,
276cabdff1aSopenharmony_ci    .p.id           = AV_CODEC_ID_MVC2,
277cabdff1aSopenharmony_ci    .priv_data_size = sizeof(MvcContext),
278cabdff1aSopenharmony_ci    .init           = mvc_decode_init,
279cabdff1aSopenharmony_ci    FF_CODEC_DECODE_CB(mvc_decode_frame),
280cabdff1aSopenharmony_ci    .p.capabilities = AV_CODEC_CAP_DR1,
281cabdff1aSopenharmony_ci    .caps_internal  = FF_CODEC_CAP_INIT_THREADSAFE,
282cabdff1aSopenharmony_ci};
283cabdff1aSopenharmony_ci#endif
284