Coverage Report

Created: 2025-12-31 07:57

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/ffmpeg/libavcodec/zerocodec.c
Line
Count
Source
1
/*
2
 * ZeroCodec Decoder
3
 *
4
 * Copyright (c) 2012, Derek Buitenhuis
5
 *
6
 * Permission to use, copy, modify, and/or distribute this software for any
7
 * purpose with or without fee is hereby granted, provided that the above
8
 * copyright notice and this permission notice appear in all copies.
9
 *
10
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17
 */
18
19
#include <zlib.h>
20
21
#include "avcodec.h"
22
#include "codec_internal.h"
23
#include "decode.h"
24
#include "zlib_wrapper.h"
25
#include "libavutil/attributes.h"
26
#include "libavutil/common.h"
27
28
typedef struct ZeroCodecContext {
29
    AVFrame  *previous_frame;
30
    FFZStream zstream;
31
} ZeroCodecContext;
32
33
static int zerocodec_decode_frame(AVCodecContext *avctx, AVFrame *pic,
34
                                  int *got_frame, AVPacket *avpkt)
35
153k
{
36
153k
    ZeroCodecContext *zc = avctx->priv_data;
37
153k
    AVFrame *prev_pic    = zc->previous_frame;
38
153k
    z_stream *const zstream = &zc->zstream.zstream;
39
153k
    uint8_t *prev        = prev_pic->data[0];
40
153k
    uint8_t *dst;
41
153k
    int i, j, zret, ret;
42
43
153k
    if (avpkt->flags & AV_PKT_FLAG_KEY) {
44
74.4k
        pic->flags |= AV_FRAME_FLAG_KEY;
45
74.4k
        pic->pict_type = AV_PICTURE_TYPE_I;
46
78.8k
    } else {
47
78.8k
        if (!prev) {
48
15.0k
            av_log(avctx, AV_LOG_ERROR, "Missing reference frame.\n");
49
15.0k
            return AVERROR_INVALIDDATA;
50
15.0k
        }
51
52
63.7k
        prev += (avctx->height - 1) * prev_pic->linesize[0];
53
54
63.7k
        pic->flags &= ~AV_FRAME_FLAG_KEY;
55
63.7k
        pic->pict_type = AV_PICTURE_TYPE_P;
56
63.7k
    }
57
58
138k
    zret = inflateReset(zstream);
59
138k
    if (zret != Z_OK) {
60
0
        av_log(avctx, AV_LOG_ERROR, "Could not reset inflate: %d.\n", zret);
61
0
        return AVERROR_INVALIDDATA;
62
0
    }
63
64
138k
    if ((ret = ff_get_buffer(avctx, pic, AV_GET_BUFFER_FLAG_REF)) < 0)
65
3.42k
        return ret;
66
67
134k
    zstream->next_in  = avpkt->data;
68
134k
    zstream->avail_in = avpkt->size;
69
70
134k
    dst = pic->data[0] + (avctx->height - 1) * pic->linesize[0];
71
72
    /**
73
     * ZeroCodec has very simple interframe compression. If a value
74
     * is the same as the previous frame, set it to 0.
75
     */
76
77
12.4M
    for (i = 0; i < avctx->height; i++) {
78
12.3M
        zstream->next_out  = dst;
79
12.3M
        zstream->avail_out = avctx->width << 1;
80
81
12.3M
        zret = inflate(zstream, Z_SYNC_FLUSH);
82
12.3M
        if (zret != Z_OK && zret != Z_STREAM_END) {
83
34.7k
            av_log(avctx, AV_LOG_ERROR,
84
34.7k
                   "Inflate failed with return code: %d.\n", zret);
85
34.7k
            return AVERROR_INVALIDDATA;
86
34.7k
        }
87
88
12.3M
        if (!(avpkt->flags & AV_PKT_FLAG_KEY)) {
89
2.80G
            for (j = 0; j < avctx->width << 1; j++)
90
2.80G
                dst[j] += prev[j] & -!dst[j];
91
2.18M
            prev -= prev_pic->linesize[0];
92
2.18M
        }
93
94
12.3M
        dst  -= pic->linesize[0];
95
12.3M
    }
96
97
100k
    if ((ret = av_frame_replace(zc->previous_frame, pic)) < 0)
98
0
        return ret;
99
100
100k
    *got_frame = 1;
101
102
100k
    return avpkt->size;
103
100k
}
104
105
static av_cold int zerocodec_decode_close(AVCodecContext *avctx)
106
1.54k
{
107
1.54k
    ZeroCodecContext *zc = avctx->priv_data;
108
109
1.54k
    av_frame_free(&zc->previous_frame);
110
111
1.54k
    ff_inflate_end(&zc->zstream);
112
113
1.54k
    return 0;
114
1.54k
}
115
116
static av_cold int zerocodec_decode_init(AVCodecContext *avctx)
117
1.54k
{
118
1.54k
    ZeroCodecContext *zc = avctx->priv_data;
119
120
1.54k
    avctx->pix_fmt             = AV_PIX_FMT_UYVY422;
121
1.54k
    avctx->bits_per_raw_sample = 8;
122
123
1.54k
    zc->previous_frame = av_frame_alloc();
124
1.54k
    if (!zc->previous_frame)
125
0
        return AVERROR(ENOMEM);
126
127
1.54k
    return ff_inflate_init(&zc->zstream, avctx);
128
1.54k
}
129
130
static av_cold void zerocodec_decode_flush(AVCodecContext *avctx)
131
8.12k
{
132
8.12k
    ZeroCodecContext *zc = avctx->priv_data;
133
134
8.12k
    av_frame_unref(zc->previous_frame);
135
8.12k
}
136
137
const FFCodec ff_zerocodec_decoder = {
138
    .p.type         = AVMEDIA_TYPE_VIDEO,
139
    .p.name         = "zerocodec",
140
    CODEC_LONG_NAME("ZeroCodec Lossless Video"),
141
    .p.id           = AV_CODEC_ID_ZEROCODEC,
142
    .priv_data_size = sizeof(ZeroCodecContext),
143
    .init           = zerocodec_decode_init,
144
    FF_CODEC_DECODE_CB(zerocodec_decode_frame),
145
    .flush          = zerocodec_decode_flush,
146
    .close          = zerocodec_decode_close,
147
    .p.capabilities = AV_CODEC_CAP_DR1,
148
    .caps_internal  = FF_CODEC_CAP_INIT_CLEANUP,
149
};