GCC Code Coverage Report
Directory: ../../../ffmpeg/ Exec Total Coverage
File: src/libavcodec/xfaceenc.c Lines: 105 109 96.3 %
Date: 2020-09-25 23:16:12 Branches: 53 62 85.5 %

Line Branch Exec Source
1
/*
2
 * Copyright (c) 1990 James Ashton - Sydney University
3
 * Copyright (c) 2012 Stefano Sabatini
4
 *
5
 * This file is part of FFmpeg.
6
 *
7
 * FFmpeg is free software; you can redistribute it and/or
8
 * modify it under the terms of the GNU Lesser General Public
9
 * License as published by the Free Software Foundation; either
10
 * version 2.1 of the License, or (at your option) any later version.
11
 *
12
 * FFmpeg is distributed in the hope that it will be useful,
13
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15
 * Lesser General Public License for more details.
16
 *
17
 * You should have received a copy of the GNU Lesser General Public
18
 * License along with FFmpeg; if not, write to the Free Software
19
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20
 */
21
22
/**
23
 * @file
24
 * X-Face encoder, based on libcompface, by James Ashton.
25
 */
26
27
#include "xface.h"
28
#include "avcodec.h"
29
#include "internal.h"
30
#include "libavutil/avassert.h"
31
32
typedef struct XFaceContext {
33
    AVClass *class;
34
    uint8_t bitmap[XFACE_PIXELS]; ///< image used internally for decoding
35
    int max_line_len;             ///< max line length for compressed data
36
    int set_header;               ///< set X-Face header in the output
37
} XFaceContext;
38
39
75946
static int all_same(char *bitmap, int w, int h)
40
{
41
    char val, *row;
42
    int x;
43
44
75946
    val = *bitmap;
45
151013
    while (h--) {
46
124163
        row = bitmap;
47
124163
        x = w;
48
359717
        while (x--)
49
284650
            if (*(row++) != val)
50
49096
                return 0;
51
75067
        bitmap += XFACE_WIDTH;
52
    }
53
26850
    return 1;
54
}
55
56
222970
static int all_black(char *bitmap, int w, int h)
57
{
58
222970
    if (w > 3) {
59
53583
        w /= 2;
60
53583
        h /= 2;
61

119619
        return (all_black(bitmap, w, h) && all_black(bitmap + w, w, h) &&
62

119619
                all_black(bitmap + XFACE_WIDTH * h, w, h) &&
63
23589
                all_black(bitmap + XFACE_WIDTH * h + w, w, h));
64
    } else {
65
        /* at least one pixel in the 2x2 grid is non-zero */
66
105417
        return *bitmap || *(bitmap + 1) ||
67

274804
               *(bitmap + XFACE_WIDTH) || *(bitmap + XFACE_WIDTH + 1);
68
    }
69
}
70
71
106612
static int all_white(char *bitmap, int w, int h)
72
{
73

106612
    return *bitmap == 0 && all_same(bitmap, w, h);
74
}
75
76
typedef struct {
77
    ProbRange prob_ranges[XFACE_PIXELS*2];
78
    int prob_ranges_idx;
79
} ProbRangesQueue;
80
81
193204
static inline int pq_push(ProbRangesQueue *pq, const ProbRange *p)
82
{
83
193204
    if (pq->prob_ranges_idx >= XFACE_PIXELS * 2 - 1)
84
        return -1;
85
193204
    pq->prob_ranges[pq->prob_ranges_idx++] = *p;
86
193204
    return 0;
87
}
88
89
97603
static void push_greys(ProbRangesQueue *pq, char *bitmap, int w, int h)
90
{
91
97603
    if (w > 3) {
92
11011
        w /= 2;
93
11011
        h /= 2;
94
11011
        push_greys(pq, bitmap,                       w, h);
95
11011
        push_greys(pq, bitmap + w,                   w, h);
96
11011
        push_greys(pq, bitmap + XFACE_WIDTH * h,     w, h);
97
11011
        push_greys(pq, bitmap + XFACE_WIDTH * h + w, w, h);
98
    } else {
99
86592
        const ProbRange *p = ff_xface_probranges_2x2 +
100
86592
                 *bitmap +
101
86592
            2 * *(bitmap + 1) +
102
86592
            4 * *(bitmap + XFACE_WIDTH) +
103
86592
            8 * *(bitmap + XFACE_WIDTH + 1);
104
86592
        pq_push(pq, p);
105
    }
106
97603
}
107
108
106612
static void encode_block(char *bitmap, int w, int h, int level, ProbRangesQueue *pq)
109
{
110
106612
    if (all_white(bitmap, w, h)) {
111
26850
        pq_push(pq, &ff_xface_probranges_per_level[level][XFACE_COLOR_WHITE]);
112
79762
    } else if (all_black(bitmap, w, h)) {
113
53559
        pq_push(pq, &ff_xface_probranges_per_level[level][XFACE_COLOR_BLACK]);
114
53559
        push_greys(pq, bitmap, w, h);
115
    } else {
116
26203
        pq_push(pq, &ff_xface_probranges_per_level[level][XFACE_COLOR_GREY]);
117
26203
        w /= 2;
118
26203
        h /= 2;
119
26203
        level++;
120
26203
        encode_block(bitmap,                       w, h, level, pq);
121
26203
        encode_block(bitmap + w,                   w, h, level, pq);
122
26203
        encode_block(bitmap + h * XFACE_WIDTH,     w, h, level, pq);
123
26203
        encode_block(bitmap + w + h * XFACE_WIDTH, w, h, level, pq);
124
    }
125
106612
}
126
127
193204
static void push_integer(BigInt *b, const ProbRange *prange)
128
{
129
    uint8_t r;
130
131
193204
    ff_big_div(b, prange->range, &r);
132
193204
    ff_big_mul(b, 0);
133
193204
    ff_big_add(b, r + prange->offset);
134
193204
}
135
136
200
static int xface_encode_frame(AVCodecContext *avctx, AVPacket *pkt,
137
                              const AVFrame *frame, int *got_packet)
138
{
139
200
    XFaceContext *xface = avctx->priv_data;
140
200
    ProbRangesQueue pq = {{{ 0 }}, 0};
141
    uint8_t bitmap_copy[XFACE_PIXELS];
142
200
    BigInt b = {0};
143
200
    int i, j, k, ret = 0;
144
    const uint8_t *buf;
145
    uint8_t *p;
146
    char intbuf[XFACE_MAX_DIGITS];
147
148

200
    if (avctx->width || avctx->height) {
149

200
        if (avctx->width != XFACE_WIDTH || avctx->height != XFACE_HEIGHT) {
150
            av_log(avctx, AV_LOG_ERROR,
151
                   "Size value %dx%d not supported, only accepts a size of %dx%d\n",
152
                   avctx->width, avctx->height, XFACE_WIDTH, XFACE_HEIGHT);
153
            return AVERROR(EINVAL);
154
        }
155
    }
156
200
    avctx->width  = XFACE_WIDTH;
157
200
    avctx->height = XFACE_HEIGHT;
158
159
    /* convert image from MONOWHITE to 1=black 0=white bitmap */
160
200
    buf = frame->data[0];
161
200
    i = j = 0;
162
    do {
163
518400
        for (k = 0; k < 8; k++)
164
460800
            xface->bitmap[i++] = (buf[j]>>(7-k))&1;
165
57600
        if (++j == XFACE_WIDTH/8) {
166
9600
            buf += frame->linesize[0];
167
9600
            j = 0;
168
        }
169
57600
    } while (i < XFACE_PIXELS);
170
171
    /* create a copy of bitmap */
172
200
    memcpy(bitmap_copy, xface->bitmap, XFACE_PIXELS);
173
200
    ff_xface_generate_face(xface->bitmap, bitmap_copy);
174
175
200
    encode_block(xface->bitmap,                         16, 16, 0, &pq);
176
200
    encode_block(xface->bitmap + 16,                    16, 16, 0, &pq);
177
200
    encode_block(xface->bitmap + 32,                    16, 16, 0, &pq);
178
200
    encode_block(xface->bitmap + XFACE_WIDTH * 16,      16, 16, 0, &pq);
179
200
    encode_block(xface->bitmap + XFACE_WIDTH * 16 + 16, 16, 16, 0, &pq);
180
200
    encode_block(xface->bitmap + XFACE_WIDTH * 16 + 32, 16, 16, 0, &pq);
181
200
    encode_block(xface->bitmap + XFACE_WIDTH * 32,      16, 16, 0, &pq);
182
200
    encode_block(xface->bitmap + XFACE_WIDTH * 32 + 16, 16, 16, 0, &pq);
183
200
    encode_block(xface->bitmap + XFACE_WIDTH * 32 + 32, 16, 16, 0, &pq);
184
185
193404
    while (pq.prob_ranges_idx > 0)
186
193204
        push_integer(&b, &pq.prob_ranges[--pq.prob_ranges_idx]);
187
188
    /* write the inverted big integer in b to intbuf */
189
200
    i = 0;
190
200
    av_assert0(b.nb_words < XFACE_MAX_WORDS);
191
67710
    while (b.nb_words) {
192
        uint8_t r;
193
67510
        ff_big_div(&b, XFACE_PRINTS, &r);
194
67510
        av_assert0(i < sizeof(intbuf));
195
67510
        intbuf[i++] = r + XFACE_FIRST_PRINT;
196
    }
197
198
200
    if ((ret = ff_alloc_packet2(avctx, pkt, i+2, 0)) < 0)
199
        return ret;
200
201
    /* revert the number, and close the buffer */
202
200
    p = pkt->data;
203
67710
    while (--i >= 0)
204
67510
        *(p++) = intbuf[i];
205
200
    *(p++) = '\n';
206
200
    *(p++) = 0;
207
208
200
    pkt->flags |= AV_PKT_FLAG_KEY;
209
200
    *got_packet = 1;
210
211
200
    return 0;
212
}
213
214
AVCodec ff_xface_encoder = {
215
    .name           = "xface",
216
    .long_name      = NULL_IF_CONFIG_SMALL("X-face image"),
217
    .type           = AVMEDIA_TYPE_VIDEO,
218
    .id             = AV_CODEC_ID_XFACE,
219
    .priv_data_size = sizeof(XFaceContext),
220
    .encode2        = xface_encode_frame,
221
    .pix_fmts       = (const enum AVPixelFormat[]) { AV_PIX_FMT_MONOWHITE, AV_PIX_FMT_NONE },
222
};