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