Browse code

MS Video 1 encoder

Kostya Shishkov authored on 2011/01/23 23:58:23
Showing 3 changed files
... ...
@@ -275,6 +275,7 @@ OBJS-$(CONFIG_MSMPEG4V3_ENCODER)       += msmpeg4.o msmpeg4data.o h263dec.o \
275 275
                                           h263.o ituh263dec.o mpeg4videodec.o
276 276
 OBJS-$(CONFIG_MSRLE_DECODER)           += msrle.o msrledec.o
277 277
 OBJS-$(CONFIG_MSVIDEO1_DECODER)        += msvideo1.o
278
+OBJS-$(CONFIG_MSVIDEO1_ENCODER)        += msvideo1enc.o elbg.o
278 279
 OBJS-$(CONFIG_MSZH_DECODER)            += lcldec.o
279 280
 OBJS-$(CONFIG_MXPEG_DECODER)           += mxpegdec.o
280 281
 OBJS-$(CONFIG_NELLYMOSER_DECODER)      += nellymoserdec.o nellymoser.o
... ...
@@ -158,7 +158,7 @@ void avcodec_register_all(void)
158 158
     REGISTER_ENCDEC  (MSMPEG4V2, msmpeg4v2);
159 159
     REGISTER_ENCDEC  (MSMPEG4V3, msmpeg4v3);
160 160
     REGISTER_DECODER (MSRLE, msrle);
161
-    REGISTER_DECODER (MSVIDEO1, msvideo1);
161
+    REGISTER_ENCDEC  (MSVIDEO1, msvideo1);
162 162
     REGISTER_DECODER (MSZH, mszh);
163 163
     REGISTER_DECODER (MXPEG, mxpeg);
164 164
     REGISTER_DECODER (NUV, nuv);
165 165
new file mode 100644
... ...
@@ -0,0 +1,298 @@
0
+/*
1
+ * Microsoft Video-1 Encoder
2
+ * Copyright (c) 2009 Konstantin Shishkov
3
+ *
4
+ * This file is part of FFmpeg.
5
+ *
6
+ * FFmpeg is free software; you can redistribute it and/or
7
+ * modify it under the terms of the GNU Lesser General Public
8
+ * License as published by the Free Software Foundation; either
9
+ * version 2.1 of the License, or (at your option) any later version.
10
+ *
11
+ * FFmpeg is distributed in the hope that it will be useful,
12
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
13
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14
+ * Lesser General Public License for more details.
15
+ *
16
+ * You should have received a copy of the GNU Lesser General Public
17
+ * License along with FFmpeg; if not, write to the Free Software
18
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19
+ */
20
+
21
+/**
22
+ * @file msvideo1enc.c
23
+ * Microsoft Video-1 encoder
24
+ */
25
+
26
+#include "avcodec.h"
27
+#include "bytestream.h"
28
+#include "libavutil/lfg.h"
29
+#include "elbg.h"
30
+#include "libavutil/imgutils.h"
31
+/**
32
+ * Encoder context
33
+ */
34
+typedef struct Msvideo1EncContext {
35
+    AVCodecContext *avctx;
36
+    AVFrame pic;
37
+    AVLFG rnd;
38
+    uint8_t *prev;
39
+
40
+    int block[16*3];
41
+    int block2[16*3];
42
+    int codebook[8*3];
43
+    int codebook2[8*3];
44
+    int output[16*3];
45
+    int output2[16*3];
46
+    int avg[3];
47
+    int bestpos;
48
+    int keyint;
49
+} Msvideo1EncContext;
50
+
51
+enum MSV1Mode{
52
+    MODE_SKIP = 0,
53
+    MODE_FILL,
54
+    MODE_2COL,
55
+    MODE_8COL,
56
+};
57
+
58
+#define SKIP_PREFIX 0x8400
59
+#define SKIPS_MAX 0x0FFF
60
+#define MKRGB555(in, off) ((in[off] << 10) | (in[off + 1] << 5) | (in[off + 2]))
61
+
62
+static const int remap[16] = { 0, 1, 4, 5, 2, 3, 6, 7, 8, 9, 12, 13, 10, 11, 14, 15 };
63
+
64
+static int encode_frame(AVCodecContext *avctx, uint8_t *buf, int buf_size, void *data)
65
+{
66
+    Msvideo1EncContext * const c = avctx->priv_data;
67
+    AVFrame *pict = data;
68
+    AVFrame * const p = &c->pic;
69
+    uint16_t *src;
70
+    uint8_t *prevptr;
71
+    uint8_t *dst = buf;
72
+    int keyframe = 1;
73
+    int no_skips = 1;
74
+    int i, j, k, x, y;
75
+    int skips = 0;
76
+
77
+    *p = *pict;
78
+    if(!c->prev)
79
+        c->prev = av_malloc(avctx->width * 3 * (avctx->height + 3));
80
+    prevptr = c->prev + avctx->width * 3 * (((avctx->height + 3)&~3) - 1);
81
+    src = (uint16_t*)(p->data[0] + p->linesize[0]*(((avctx->height + 3)&~3) - 1));
82
+    if(c->keyint >= avctx->keyint_min)
83
+        keyframe = 1;
84
+
85
+    p->quality = 24;
86
+
87
+    for(y = 0; y < avctx->height; y += 4){
88
+        for(x = 0; x < avctx->width; x += 4){
89
+            int bestmode = MODE_SKIP;
90
+            int bestscore = INT_MAX;
91
+            int flags = 0;
92
+            int score;
93
+
94
+            for(j = 0; j < 4; j++){
95
+                for(i = 0; i < 4; i++){
96
+                    uint16_t val = src[x + i - j*p->linesize[0]/2];
97
+                    for(k = 0; k < 3; k++){
98
+                        c->block[(i + j*4)*3 + k] = (val >> (10-k*5)) & 0x1F;
99
+                        c->block2[remap[i + j*4]*3 + k] = (val >> (10-k*5)) & 0x1F;
100
+                    }
101
+                }
102
+            }
103
+            if(!keyframe){
104
+                bestscore = 0;
105
+                for(j = 0; j < 4; j++){
106
+                    for(i = 0; i < 4*3; i++){
107
+                        int t = prevptr[x*3 + i + j*p->linesize[0]] - c->block[i + j*4*3];
108
+                        bestscore += t*t;
109
+                    }
110
+                }
111
+                bestscore /= p->quality;
112
+            }
113
+            // try to find optimal value to fill whole 4x4 block
114
+            score = 0;
115
+            ff_init_elbg(c->block, 3, 16, c->avg, 1, 1, c->output, &c->rnd);
116
+            ff_do_elbg  (c->block, 3, 16, c->avg, 1, 1, c->output, &c->rnd);
117
+            if(c->avg[0] == 1) // red component = 1 will be written as skip code
118
+                c->avg[0] = 0;
119
+            for(j = 0; j < 4; j++){
120
+                for(i = 0; i < 4; i++){
121
+                    for(k = 0; k < 3; k++){
122
+                        int t = c->avg[k] - c->block[(i+j*4)*3+k];
123
+                        score += t*t;
124
+                    }
125
+                }
126
+            }
127
+            score /= p->quality;
128
+            score += 2;
129
+            if(score < bestscore){
130
+                bestscore = score;
131
+                bestmode = MODE_FILL;
132
+            }
133
+            // search for optimal filling of 2-color block
134
+            score = 0;
135
+            ff_init_elbg(c->block, 3, 16, c->codebook, 2, 1, c->output, &c->rnd);
136
+            ff_do_elbg  (c->block, 3, 16, c->codebook, 2, 1, c->output, &c->rnd);
137
+            // last output value should be always 1, swap codebooks if needed
138
+            if(!c->output[15]){
139
+                for(i = 0; i < 3; i++)
140
+                    FFSWAP(uint8_t, c->codebook[i], c->codebook[i+3]);
141
+                for(i = 0; i < 16; i++)
142
+                    c->output[i] ^= 1;
143
+            }
144
+            for(j = 0; j < 4; j++){
145
+                for(i = 0; i < 4; i++){
146
+                    for(k = 0; k < 3; k++){
147
+                        int t = c->codebook[c->output[i+j*4]*3 + k] - c->block[i*3+k+j*4*3];
148
+                        score += t*t;
149
+                    }
150
+                }
151
+            }
152
+            score /= p->quality;
153
+            score += 6;
154
+            if(score < bestscore){
155
+                bestscore = score;
156
+                bestmode = MODE_2COL;
157
+            }
158
+            // search for optimal filling of 2-color 2x2 subblocks
159
+            score = 0;
160
+            for(i = 0; i < 4; i++){
161
+                ff_init_elbg(c->block2 + i*4*3, 3, 4, c->codebook2 + i*2*3, 2, 1, c->output2 + i*4, &c->rnd);
162
+                ff_do_elbg  (c->block2 + i*4*3, 3, 4, c->codebook2 + i*2*3, 2, 1, c->output2 + i*4, &c->rnd);
163
+            }
164
+            // last value should be always 1, swap codebooks if needed
165
+            if(!c->output2[15]){
166
+                for(i = 0; i < 3; i++)
167
+                    FFSWAP(uint8_t, c->codebook2[i+18], c->codebook2[i+21]);
168
+                for(i = 12; i < 16; i++)
169
+                    c->output2[i] ^= 1;
170
+            }
171
+            for(j = 0; j < 4; j++){
172
+                for(i = 0; i < 4; i++){
173
+                    for(k = 0; k < 3; k++){
174
+                        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];
175
+                        score += t*t;
176
+                    }
177
+                }
178
+            }
179
+            score /= p->quality;
180
+            score += 18;
181
+            if(score < bestscore){
182
+                bestscore = score;
183
+                bestmode = MODE_8COL;
184
+            }
185
+
186
+            if(bestmode == MODE_SKIP){
187
+                skips++;
188
+                no_skips = 0;
189
+            }
190
+            if((bestmode != MODE_SKIP && skips) || skips == SKIPS_MAX){
191
+                bytestream_put_le16(&dst, skips | SKIP_PREFIX);
192
+                skips = 0;
193
+            }
194
+
195
+            switch(bestmode){
196
+            case MODE_FILL:
197
+                bytestream_put_le16(&dst, MKRGB555(c->avg,0) | 0x8000);
198
+                for(j = 0; j < 4; j++)
199
+                    for(i = 0; i < 4; i++)
200
+                        for(k = 0; k < 3; k++)
201
+                            prevptr[i*3 + k - j*3*avctx->width] = c->avg[k];
202
+                break;
203
+            case MODE_2COL:
204
+                for(j = 0; j < 4; j++){
205
+                    for(i = 0; i < 4; i++){
206
+                        flags |= (c->output[i + j*4]^1) << (i + j*4);
207
+                        for(k = 0; k < 3; k++)
208
+                            prevptr[i*3 + k - j*3*avctx->width] = c->codebook[c->output[i + j*4]*3 + k];
209
+                    }
210
+                }
211
+                bytestream_put_le16(&dst, flags);
212
+                bytestream_put_le16(&dst, MKRGB555(c->codebook, 0));
213
+                bytestream_put_le16(&dst, MKRGB555(c->codebook, 3));
214
+                break;
215
+            case MODE_8COL:
216
+                for(j = 0; j < 4; j++){
217
+                    for(i = 0; i < 4; i++){
218
+                        flags |= (c->output2[remap[i + j*4]]^1) << (i + j*4);
219
+                        for(k = 0; k < 3; k++)
220
+                            prevptr[i*3 + k - j*3*avctx->width] = c->codebook2[(c->output2[remap[i+j*4]] + (i&2) + (j&2)*2)*3 + k];
221
+                    }
222
+                }
223
+                bytestream_put_le16(&dst, flags);
224
+                bytestream_put_le16(&dst, MKRGB555(c->codebook2, 0) | 0x8000);
225
+                for(i = 3; i < 24; i += 3)
226
+                    bytestream_put_le16(&dst, MKRGB555(c->codebook2, i));
227
+                break;
228
+            }
229
+        }
230
+        src     -= p->linesize[0] << 1;
231
+        prevptr -= avctx->width * 3 * 4;
232
+    }
233
+    if(skips)
234
+        bytestream_put_le16(&dst, skips | SKIP_PREFIX);
235
+    //EOF
236
+    bytestream_put_byte(&dst, 0);
237
+    bytestream_put_byte(&dst, 0);
238
+
239
+    if(no_skips)
240
+        keyframe = 1;
241
+    if(keyframe)
242
+        c->keyint = 0;
243
+    else
244
+        c->keyint++;
245
+    p->pict_type= keyframe ? FF_I_TYPE : FF_P_TYPE;
246
+    p->key_frame= keyframe;
247
+
248
+    return dst - buf;
249
+}
250
+
251
+
252
+/**
253
+ * init encoder
254
+ */
255
+static av_cold int encode_init(AVCodecContext *avctx)
256
+{
257
+    Msvideo1EncContext * const c = avctx->priv_data;
258
+
259
+    c->avctx = avctx;
260
+    if (av_image_check_size(avctx->width, avctx->height, 0, avctx) < 0) {
261
+        return -1;
262
+    }
263
+
264
+    avcodec_get_frame_defaults(&c->pic);
265
+    avctx->coded_frame = (AVFrame*)&c->pic;
266
+
267
+    c->keyint = avctx->keyint_min;
268
+    av_lfg_init(&c->rnd, 1);
269
+
270
+    return 0;
271
+}
272
+
273
+
274
+
275
+/**
276
+ * Uninit encoder
277
+ */
278
+static av_cold int encode_end(AVCodecContext *avctx)
279
+{
280
+    Msvideo1EncContext * const c = avctx->priv_data;
281
+
282
+    av_freep(&c->prev);
283
+
284
+    return 0;
285
+}
286
+
287
+AVCodec ff_msvideo1_encoder = {
288
+    "msvideo1",
289
+    AVMEDIA_TYPE_VIDEO,
290
+    CODEC_ID_MSVIDEO1,
291
+    sizeof(Msvideo1EncContext),
292
+    encode_init,
293
+    encode_frame,
294
+    encode_end,
295
+    .pix_fmts = (enum PixelFormat[]){PIX_FMT_RGB555, PIX_FMT_NONE},
296
+    .long_name = NULL_IF_CONFIG_SMALL("Microsoft Video-1"),
297
+};