GCC Code Coverage Report
Directory: ../../../ffmpeg/ Exec Total Coverage
File: src/libavcodec/msvideo1enc.c Lines: 149 153 97.4 %
Date: 2019-11-20 04:07:19 Branches: 103 108 95.4 %

Line Branch Exec Source
1
/*
2
 * Microsoft Video-1 Encoder
3
 * Copyright (c) 2009 Konstantin Shishkov
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
 * Microsoft Video-1 encoder
25
 */
26
27
#include "avcodec.h"
28
#include "internal.h"
29
#include "bytestream.h"
30
#include "libavutil/lfg.h"
31
#include "elbg.h"
32
#include "libavutil/imgutils.h"
33
/**
34
 * Encoder context
35
 */
36
typedef struct Msvideo1EncContext {
37
    AVCodecContext *avctx;
38
    AVLFG rnd;
39
    uint8_t *prev;
40
41
    int block[16*3];
42
    int block2[16*3];
43
    int codebook[8*3];
44
    int codebook2[8*3];
45
    int output[16*3];
46
    int output2[16*3];
47
    int avg[3];
48
    int bestpos;
49
    int keyint;
50
} Msvideo1EncContext;
51
52
enum MSV1Mode{
53
    MODE_SKIP = 0,
54
    MODE_FILL,
55
    MODE_2COL,
56
    MODE_8COL,
57
};
58
59
#define SKIP_PREFIX 0x8400
60
#define SKIPS_MAX 0x03FF
61
#define MKRGB555(in, off) (((in)[off] << 10) | ((in)[(off) + 1] << 5) | ((in)[(off) + 2]))
62
63
static const int remap[16] = { 0, 1, 4, 5, 2, 3, 6, 7, 8, 9, 12, 13, 10, 11, 14, 15 };
64
65
150
static int encode_frame(AVCodecContext *avctx, AVPacket *pkt,
66
                               const AVFrame *pict, int *got_packet)
67
{
68
150
    Msvideo1EncContext * const c = avctx->priv_data;
69
150
    const AVFrame *p = pict;
70
    uint16_t *src;
71
    uint8_t *prevptr;
72
    uint8_t *dst, *buf;
73
150
    int keyframe = 0;
74
150
    int no_skips = 1;
75
    int i, j, k, x, y, ret;
76
150
    int skips = 0;
77
150
    int quality = 24;
78
79
150
    if ((ret = ff_alloc_packet2(avctx, pkt, avctx->width*avctx->height*9 + AV_INPUT_BUFFER_MIN_SIZE, 0)) < 0)
80
        return ret;
81
150
    dst= buf= pkt->data;
82
83
150
    if(!c->prev)
84
3
        c->prev = av_malloc(avctx->width * 3 * (avctx->height + 3));
85
150
    prevptr = c->prev + avctx->width * 3 * (FFALIGN(avctx->height, 4) - 1);
86
150
    src = (uint16_t*)(p->data[0] + p->linesize[0]*(FFALIGN(avctx->height, 4) - 1));
87
150
    if(c->keyint >= avctx->keyint_min)
88
6
        keyframe = 1;
89
90
91
10950
    for(y = 0; y < avctx->height; y += 4){
92
961200
        for(x = 0; x < avctx->width; x += 4){
93
950400
            int bestmode = MODE_SKIP;
94
950400
            int bestscore = INT_MAX;
95
950400
            int flags = 0;
96
            int score;
97
98
4752000
            for(j = 0; j < 4; j++){
99
19008000
                for(i = 0; i < 4; i++){
100
15206400
                    uint16_t val = src[x + i - j*p->linesize[0]/2];
101
60825600
                    for(k = 0; k < 3; k++){
102
45619200
                        c->block[(i + j*4)*3 + k] =
103
45619200
                        c->block2[remap[i + j*4]*3 + k] = (val >> (10-k*5)) & 0x1F;
104
                    }
105
                }
106
            }
107
950400
            if(!keyframe){
108
912384
                bestscore = 0;
109
4561920
                for(j = 0; j < 4; j++){
110
47443968
                    for(i = 0; i < 4*3; i++){
111
43794432
                        int t = prevptr[x*3 + i - j*3*avctx->width] - c->block[i + j*4*3];
112
43794432
                        bestscore += t*t;
113
                    }
114
                }
115
912384
                bestscore /= quality;
116
            }
117
            // try to find optimal value to fill whole 4x4 block
118
950400
            score = 0;
119
950400
            avpriv_init_elbg(c->block, 3, 16, c->avg, 1, 1, c->output, &c->rnd);
120
950400
            avpriv_do_elbg  (c->block, 3, 16, c->avg, 1, 1, c->output, &c->rnd);
121
950400
            if(c->avg[0] == 1) // red component = 1 will be written as skip code
122
12469
                c->avg[0] = 0;
123
4752000
            for(j = 0; j < 4; j++){
124
19008000
                for(i = 0; i < 4; i++){
125
60825600
                    for(k = 0; k < 3; k++){
126
45619200
                        int t = c->avg[k] - c->block[(i+j*4)*3+k];
127
45619200
                        score += t*t;
128
                    }
129
                }
130
            }
131
950400
            score /= quality;
132
950400
            score += 2;
133
950400
            if(score < bestscore){
134
555268
                bestscore = score;
135
555268
                bestmode = MODE_FILL;
136
            }
137
            // search for optimal filling of 2-color block
138
950400
            score = 0;
139
950400
            avpriv_init_elbg(c->block, 3, 16, c->codebook, 2, 1, c->output, &c->rnd);
140
950400
            avpriv_do_elbg  (c->block, 3, 16, c->codebook, 2, 1, c->output, &c->rnd);
141
            // last output value should be always 1, swap codebooks if needed
142
950400
            if(!c->output[15]){
143
1485776
                for(i = 0; i < 3; i++)
144
1114332
                    FFSWAP(uint8_t, c->codebook[i], c->codebook[i+3]);
145
6314548
                for(i = 0; i < 16; i++)
146
5943104
                    c->output[i] ^= 1;
147
            }
148
4752000
            for(j = 0; j < 4; j++){
149
19008000
                for(i = 0; i < 4; i++){
150
60825600
                    for(k = 0; k < 3; k++){
151
45619200
                        int t = c->codebook[c->output[i+j*4]*3 + k] - c->block[i*3+k+j*4*3];
152
45619200
                        score += t*t;
153
                    }
154
                }
155
            }
156
950400
            score /= quality;
157
950400
            score += 6;
158
950400
            if(score < bestscore){
159
247307
                bestscore = score;
160
247307
                bestmode = MODE_2COL;
161
            }
162
            // search for optimal filling of 2-color 2x2 subblocks
163
950400
            score = 0;
164
4752000
            for(i = 0; i < 4; i++){
165
3801600
                avpriv_init_elbg(c->block2 + i*4*3, 3, 4, c->codebook2 + i*2*3, 2, 1, c->output2 + i*4, &c->rnd);
166
3801600
                avpriv_do_elbg  (c->block2 + i*4*3, 3, 4, c->codebook2 + i*2*3, 2, 1, c->output2 + i*4, &c->rnd);
167
            }
168
            // last value should be always 1, swap codebooks if needed
169
950400
            if(!c->output2[15]){
170
2270564
                for(i = 0; i < 3; i++)
171
1702923
                    FFSWAP(uint8_t, c->codebook2[i+18], c->codebook2[i+21]);
172
2838205
                for(i = 12; i < 16; i++)
173
2270564
                    c->output2[i] ^= 1;
174
            }
175
4752000
            for(j = 0; j < 4; j++){
176
19008000
                for(i = 0; i < 4; i++){
177
60825600
                    for(k = 0; k < 3; k++){
178
45619200
                        int t = c->codebook2[(c->output2[remap[i+j*4]] + (i&2) + (j&2)*2)*3+k] - c->block[i*3+k + j*4*3];
179
45619200
                        score += t*t;
180
                    }
181
                }
182
            }
183
950400
            score /= quality;
184
950400
            score += 18;
185
950400
            if(score < bestscore){
186
143607
                bestscore = score;
187
143607
                bestmode = MODE_8COL;
188
            }
189
190
950400
            if(bestmode == MODE_SKIP){
191
351933
                skips++;
192
351933
                no_skips = 0;
193
            }
194

950400
            if((bestmode != MODE_SKIP && skips) || skips == SKIPS_MAX){
195
107480
                bytestream_put_le16(&dst, skips | SKIP_PREFIX);
196
107480
                skips = 0;
197
            }
198
199

950400
            switch(bestmode){
200
320440
            case MODE_FILL:
201
320440
                bytestream_put_le16(&dst, MKRGB555(c->avg,0) | 0x8000);
202
1602200
                for(j = 0; j < 4; j++)
203
6408800
                    for(i = 0; i < 4; i++)
204
20508160
                        for(k = 0; k < 3; k++)
205
15381120
                            prevptr[x*3 + i*3 + k - j*3*avctx->width] = c->avg[k];
206
320440
                break;
207
134420
            case MODE_2COL:
208
672100
                for(j = 0; j < 4; j++){
209
2688400
                    for(i = 0; i < 4; i++){
210
2150720
                        flags |= (c->output[i + j*4]^1) << (i + j*4);
211
8602880
                        for(k = 0; k < 3; k++)
212
6452160
                            prevptr[x*3 + i*3 + k - j*3*avctx->width] = c->codebook[c->output[i + j*4]*3 + k];
213
                    }
214
                }
215
134420
                bytestream_put_le16(&dst, flags);
216
134420
                bytestream_put_le16(&dst, MKRGB555(c->codebook, 0));
217
134420
                bytestream_put_le16(&dst, MKRGB555(c->codebook, 3));
218
134420
                break;
219
143607
            case MODE_8COL:
220
718035
                for(j = 0; j < 4; j++){
221
2872140
                    for(i = 0; i < 4; i++){
222
2297712
                        flags |= (c->output2[remap[i + j*4]]^1) << (i + j*4);
223
9190848
                        for(k = 0; k < 3; k++)
224
6893136
                            prevptr[x*3 + i*3 + k - j*3*avctx->width] = c->codebook2[(c->output2[remap[i+j*4]] + (i&2) + (j&2)*2)*3 + k];
225
                    }
226
                }
227
143607
                bytestream_put_le16(&dst, flags);
228
143607
                bytestream_put_le16(&dst, MKRGB555(c->codebook2, 0) | 0x8000);
229
1148856
                for(i = 3; i < 24; i += 3)
230
1005249
                    bytestream_put_le16(&dst, MKRGB555(c->codebook2, i));
231
143607
                break;
232
            }
233
950400
        }
234
10800
        src     -= p->linesize[0] << 1;
235
10800
        prevptr -= avctx->width * 3 * 4;
236
    }
237
150
    if(skips)
238
29
        bytestream_put_le16(&dst, skips | SKIP_PREFIX);
239
    //EOF
240
150
    bytestream_put_byte(&dst, 0);
241
150
    bytestream_put_byte(&dst, 0);
242
243
150
    if(no_skips)
244
6
        keyframe = 1;
245
150
    if(keyframe)
246
6
        c->keyint = 0;
247
    else
248
144
        c->keyint++;
249
150
    if (keyframe) pkt->flags |= AV_PKT_FLAG_KEY;
250
150
    pkt->size = dst - buf;
251
150
    *got_packet = 1;
252
253
150
    return 0;
254
}
255
256
257
/**
258
 * init encoder
259
 */
260
3
static av_cold int encode_init(AVCodecContext *avctx)
261
{
262
3
    Msvideo1EncContext * const c = avctx->priv_data;
263
264
3
    c->avctx = avctx;
265
3
    if (av_image_check_size(avctx->width, avctx->height, 0, avctx) < 0) {
266
        return -1;
267
    }
268

3
    if((avctx->width&3) || (avctx->height&3)){
269
        av_log(avctx, AV_LOG_ERROR, "width and height must be multiples of 4\n");
270
        return -1;
271
    }
272
273
3
    avctx->bits_per_coded_sample = 16;
274
275
3
    c->keyint = avctx->keyint_min;
276
3
    av_lfg_init(&c->rnd, 1);
277
278
3
    return 0;
279
}
280
281
282
283
/**
284
 * Uninit encoder
285
 */
286
3
static av_cold int encode_end(AVCodecContext *avctx)
287
{
288
3
    Msvideo1EncContext * const c = avctx->priv_data;
289
290
3
    av_freep(&c->prev);
291
292
3
    return 0;
293
}
294
295
AVCodec ff_msvideo1_encoder = {
296
    .name           = "msvideo1",
297
    .long_name = NULL_IF_CONFIG_SMALL("Microsoft Video-1"),
298
    .type           = AVMEDIA_TYPE_VIDEO,
299
    .id             = AV_CODEC_ID_MSVIDEO1,
300
    .priv_data_size = sizeof(Msvideo1EncContext),
301
    .init           = encode_init,
302
    .encode2        = encode_frame,
303
    .close          = encode_end,
304
    .pix_fmts = (const enum AVPixelFormat[]){AV_PIX_FMT_RGB555, AV_PIX_FMT_NONE},
305
};