Coverage Report

Created: 2026-01-16 07:48

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/ffmpeg/libavcodec/cyuv.c
Line
Count
Source
1
/*
2
 * Creative YUV (CYUV) Video Decoder
3
 *   by Mike Melanson (melanson@pcisys.net)
4
 * based on "Creative YUV (CYUV) stream format for AVI":
5
 *   http://www.csse.monash.edu.au/~timf/videocodec/cyuv.txt
6
 *
7
 * Copyright (C) 2003 The FFmpeg project
8
 *
9
 * This file is part of FFmpeg.
10
 *
11
 * FFmpeg is free software; you can redistribute it and/or
12
 * modify it under the terms of the GNU Lesser General Public
13
 * License as published by the Free Software Foundation; either
14
 * version 2.1 of the License, or (at your option) any later version.
15
 *
16
 * FFmpeg is distributed in the hope that it will be useful,
17
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
19
 * Lesser General Public License for more details.
20
 *
21
 * You should have received a copy of the GNU Lesser General Public
22
 * License along with FFmpeg; if not, write to the Free Software
23
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
24
 */
25
26
/**
27
 * @file
28
 * Creative YUV (CYUV) Video Decoder.
29
 */
30
31
#include "config_components.h"
32
33
#include <string.h>
34
35
#include "avcodec.h"
36
#include "codec_internal.h"
37
#include "decode.h"
38
#include "libavutil/internal.h"
39
40
static av_cold int cyuv_decode_init(AVCodecContext *avctx)
41
1.50k
{
42
    /* width needs to be divisible by 4 for this codec to work */
43
1.50k
    if (avctx->width & 0x3)
44
36
        return AVERROR_INVALIDDATA;
45
46
1.47k
    return 0;
47
1.50k
}
48
49
static int cyuv_decode_frame(AVCodecContext *avctx, AVFrame *frame,
50
                             int *got_frame, AVPacket *avpkt)
51
1.70M
{
52
1.70M
    const uint8_t *buf = avpkt->data;
53
1.70M
    int buf_size = avpkt->size;
54
55
1.70M
    unsigned char *y_plane;
56
1.70M
    unsigned char *u_plane;
57
1.70M
    unsigned char *v_plane;
58
1.70M
    int y_ptr;
59
1.70M
    int u_ptr;
60
1.70M
    int v_ptr;
61
62
    /* prediction error tables (make it clear that they are signed values) */
63
1.70M
    const signed char *y_table = (const signed char*)buf +  0;
64
1.70M
    const signed char *u_table = (const signed char*)buf + 16;
65
1.70M
    const signed char *v_table = (const signed char*)buf + 32;
66
67
1.70M
    unsigned char y_pred, u_pred, v_pred;
68
1.70M
    int stream_ptr;
69
1.70M
    unsigned char cur_byte;
70
1.70M
    int pixel_groups;
71
1.70M
    int rawsize = avctx->height * FFALIGN(avctx->width,2) * 2;
72
1.70M
    int ret;
73
74
1.70M
    if (avctx->codec_id == AV_CODEC_ID_AURA) {
75
888k
        y_table = u_table;
76
888k
        u_table = v_table;
77
888k
    }
78
    /* sanity check the buffer size: A buffer has 3x16-bytes tables
79
     * followed by (height) lines each with 3 bytes to represent groups
80
     * of 4 pixels. Thus, the total size of the buffer ought to be:
81
     *    (3 * 16) + height * (width * 3 / 4) */
82
1.70M
    if (buf_size == 48 + avctx->height * (avctx->width * 3 / 4)) {
83
2.72k
        avctx->pix_fmt = AV_PIX_FMT_YUV411P;
84
1.69M
    } else if(buf_size == rawsize ) {
85
240k
        avctx->pix_fmt = AV_PIX_FMT_UYVY422;
86
1.45M
    } else {
87
1.45M
        av_log(avctx, AV_LOG_ERROR, "got a buffer with %d bytes when %d were expected\n",
88
1.45M
               buf_size, 48 + avctx->height * (avctx->width * 3 / 4));
89
1.45M
        return AVERROR_INVALIDDATA;
90
1.45M
    }
91
92
    /* pixel data starts 48 bytes in, after 3x16-byte tables */
93
242k
    stream_ptr = 48;
94
95
242k
    if ((ret = ff_get_buffer(avctx, frame, 0)) < 0)
96
834
        return ret;
97
98
242k
    y_plane = frame->data[0];
99
242k
    u_plane = frame->data[1];
100
242k
    v_plane = frame->data[2];
101
102
242k
    if (buf_size == rawsize) {
103
240k
        int linesize = FFALIGN(avctx->width, 2) * 2;
104
240k
        y_plane += frame->linesize[0] * avctx->height;
105
481k
        for (stream_ptr = 0; stream_ptr < rawsize; stream_ptr += linesize) {
106
240k
            y_plane -= frame->linesize[0];
107
240k
            memcpy(y_plane, buf+stream_ptr, linesize);
108
240k
        }
109
240k
    } else {
110
111
    /* iterate through each line in the height */
112
1.89k
    for (y_ptr = 0, u_ptr = 0, v_ptr = 0;
113
6.23k
         y_ptr < (avctx->height * frame->linesize[0]);
114
4.33k
         y_ptr += frame->linesize[0] - avctx->width,
115
4.33k
         u_ptr += frame->linesize[1] - avctx->width / 4,
116
4.33k
         v_ptr += frame->linesize[2] - avctx->width / 4) {
117
118
        /* reset predictors */
119
4.33k
        cur_byte = buf[stream_ptr++];
120
4.33k
        u_plane[u_ptr++] = u_pred = cur_byte & 0xF0;
121
4.33k
        y_plane[y_ptr++] = y_pred = (cur_byte & 0x0F) << 4;
122
123
4.33k
        cur_byte = buf[stream_ptr++];
124
4.33k
        v_plane[v_ptr++] = v_pred = cur_byte & 0xF0;
125
4.33k
        y_pred += y_table[cur_byte & 0x0F];
126
4.33k
        y_plane[y_ptr++] = y_pred;
127
128
4.33k
        cur_byte = buf[stream_ptr++];
129
4.33k
        y_pred += y_table[cur_byte & 0x0F];
130
4.33k
        y_plane[y_ptr++] = y_pred;
131
4.33k
        y_pred += y_table[(cur_byte & 0xF0) >> 4];
132
4.33k
        y_plane[y_ptr++] = y_pred;
133
134
        /* iterate through the remaining pixel groups (4 pixels/group) */
135
4.33k
        pixel_groups = avctx->width / 4 - 1;
136
376k
        while (pixel_groups--) {
137
138
372k
            cur_byte = buf[stream_ptr++];
139
372k
            u_pred += u_table[(cur_byte & 0xF0) >> 4];
140
372k
            u_plane[u_ptr++] = u_pred;
141
372k
            y_pred += y_table[cur_byte & 0x0F];
142
372k
            y_plane[y_ptr++] = y_pred;
143
144
372k
            cur_byte = buf[stream_ptr++];
145
372k
            v_pred += v_table[(cur_byte & 0xF0) >> 4];
146
372k
            v_plane[v_ptr++] = v_pred;
147
372k
            y_pred += y_table[cur_byte & 0x0F];
148
372k
            y_plane[y_ptr++] = y_pred;
149
150
372k
            cur_byte = buf[stream_ptr++];
151
372k
            y_pred += y_table[cur_byte & 0x0F];
152
372k
            y_plane[y_ptr++] = y_pred;
153
372k
            y_pred += y_table[(cur_byte & 0xF0) >> 4];
154
372k
            y_plane[y_ptr++] = y_pred;
155
156
372k
        }
157
4.33k
    }
158
1.89k
    }
159
160
242k
    *got_frame = 1;
161
162
242k
    return buf_size;
163
242k
}
164
165
#if CONFIG_AURA_DECODER
166
const FFCodec ff_aura_decoder = {
167
    .p.name         = "aura",
168
    CODEC_LONG_NAME("Auravision AURA"),
169
    .p.type         = AVMEDIA_TYPE_VIDEO,
170
    .p.id           = AV_CODEC_ID_AURA,
171
    .init           = cyuv_decode_init,
172
    FF_CODEC_DECODE_CB(cyuv_decode_frame),
173
    .p.capabilities = AV_CODEC_CAP_DR1,
174
};
175
#endif
176
177
#if CONFIG_CYUV_DECODER
178
const FFCodec ff_cyuv_decoder = {
179
    .p.name         = "cyuv",
180
    CODEC_LONG_NAME("Creative YUV (CYUV)"),
181
    .p.type         = AVMEDIA_TYPE_VIDEO,
182
    .p.id           = AV_CODEC_ID_CYUV,
183
    .init           = cyuv_decode_init,
184
    FF_CODEC_DECODE_CB(cyuv_decode_frame),
185
    .p.capabilities = AV_CODEC_CAP_DR1,
186
};
187
#endif