FFmpeg
msvideo1enc.c
Go to the documentation of this file.
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 {
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;
51 
52 enum MSV1Mode{
53  MODE_SKIP = 0,
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 
66  const AVFrame *pict, int *got_packet)
67 {
68  Msvideo1EncContext * const c = avctx->priv_data;
69  const AVFrame *p = pict;
70  uint16_t *src;
71  uint8_t *prevptr;
72  uint8_t *dst, *buf;
73  int keyframe = 0;
74  int no_skips = 1;
75  int i, j, k, x, y, ret;
76  int skips = 0;
77  int quality = 24;
78 
79  if ((ret = ff_alloc_packet2(avctx, pkt, avctx->width*avctx->height*9 + AV_INPUT_BUFFER_MIN_SIZE, 0)) < 0)
80  return ret;
81  dst= buf= pkt->data;
82 
83  if(!c->prev)
84  c->prev = av_malloc(avctx->width * 3 * (avctx->height + 3));
85  prevptr = c->prev + avctx->width * 3 * (FFALIGN(avctx->height, 4) - 1);
86  src = (uint16_t*)(p->data[0] + p->linesize[0]*(FFALIGN(avctx->height, 4) - 1));
87  if(c->keyint >= avctx->keyint_min)
88  keyframe = 1;
89 
90 
91  for(y = 0; y < avctx->height; y += 4){
92  for(x = 0; x < avctx->width; x += 4){
93  int bestmode = MODE_SKIP;
94  int bestscore = INT_MAX;
95  int flags = 0;
96  int score;
97 
98  for(j = 0; j < 4; j++){
99  for(i = 0; i < 4; i++){
100  uint16_t val = src[x + i - j*p->linesize[0]/2];
101  for(k = 0; k < 3; k++){
102  c->block[(i + j*4)*3 + k] =
103  c->block2[remap[i + j*4]*3 + k] = (val >> (10-k*5)) & 0x1F;
104  }
105  }
106  }
107  if(!keyframe){
108  bestscore = 0;
109  for(j = 0; j < 4; j++){
110  for(i = 0; i < 4*3; i++){
111  int t = prevptr[x*3 + i - j*3*avctx->width] - c->block[i + j*4*3];
112  bestscore += t*t;
113  }
114  }
115  bestscore /= quality;
116  }
117  // try to find optimal value to fill whole 4x4 block
118  score = 0;
119  avpriv_init_elbg(c->block, 3, 16, c->avg, 1, 1, c->output, &c->rnd);
120  avpriv_do_elbg (c->block, 3, 16, c->avg, 1, 1, c->output, &c->rnd);
121  if(c->avg[0] == 1) // red component = 1 will be written as skip code
122  c->avg[0] = 0;
123  for(j = 0; j < 4; j++){
124  for(i = 0; i < 4; i++){
125  for(k = 0; k < 3; k++){
126  int t = c->avg[k] - c->block[(i+j*4)*3+k];
127  score += t*t;
128  }
129  }
130  }
131  score /= quality;
132  score += 2;
133  if(score < bestscore){
134  bestscore = score;
135  bestmode = MODE_FILL;
136  }
137  // search for optimal filling of 2-color block
138  score = 0;
139  avpriv_init_elbg(c->block, 3, 16, c->codebook, 2, 1, c->output, &c->rnd);
140  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  if(!c->output[15]){
143  for(i = 0; i < 3; i++)
144  FFSWAP(uint8_t, c->codebook[i], c->codebook[i+3]);
145  for(i = 0; i < 16; i++)
146  c->output[i] ^= 1;
147  }
148  for(j = 0; j < 4; j++){
149  for(i = 0; i < 4; i++){
150  for(k = 0; k < 3; k++){
151  int t = c->codebook[c->output[i+j*4]*3 + k] - c->block[i*3+k+j*4*3];
152  score += t*t;
153  }
154  }
155  }
156  score /= quality;
157  score += 6;
158  if(score < bestscore){
159  bestscore = score;
160  bestmode = MODE_2COL;
161  }
162  // search for optimal filling of 2-color 2x2 subblocks
163  score = 0;
164  for(i = 0; i < 4; i++){
165  avpriv_init_elbg(c->block2 + i*4*3, 3, 4, c->codebook2 + i*2*3, 2, 1, c->output2 + i*4, &c->rnd);
166  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  if(!c->output2[15]){
170  for(i = 0; i < 3; i++)
171  FFSWAP(uint8_t, c->codebook2[i+18], c->codebook2[i+21]);
172  for(i = 12; i < 16; i++)
173  c->output2[i] ^= 1;
174  }
175  for(j = 0; j < 4; j++){
176  for(i = 0; i < 4; i++){
177  for(k = 0; k < 3; k++){
178  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  score += t*t;
180  }
181  }
182  }
183  score /= quality;
184  score += 18;
185  if(score < bestscore){
186  bestscore = score;
187  bestmode = MODE_8COL;
188  }
189 
190  if(bestmode == MODE_SKIP){
191  skips++;
192  no_skips = 0;
193  }
194  if((bestmode != MODE_SKIP && skips) || skips == SKIPS_MAX){
195  bytestream_put_le16(&dst, skips | SKIP_PREFIX);
196  skips = 0;
197  }
198 
199  switch(bestmode){
200  case MODE_FILL:
201  bytestream_put_le16(&dst, MKRGB555(c->avg,0) | 0x8000);
202  for(j = 0; j < 4; j++)
203  for(i = 0; i < 4; i++)
204  for(k = 0; k < 3; k++)
205  prevptr[x*3 + i*3 + k - j*3*avctx->width] = c->avg[k];
206  break;
207  case MODE_2COL:
208  for(j = 0; j < 4; j++){
209  for(i = 0; i < 4; i++){
210  flags |= (c->output[i + j*4]^1) << (i + j*4);
211  for(k = 0; k < 3; k++)
212  prevptr[x*3 + i*3 + k - j*3*avctx->width] = c->codebook[c->output[i + j*4]*3 + k];
213  }
214  }
215  bytestream_put_le16(&dst, flags);
216  bytestream_put_le16(&dst, MKRGB555(c->codebook, 0));
217  bytestream_put_le16(&dst, MKRGB555(c->codebook, 3));
218  break;
219  case MODE_8COL:
220  for(j = 0; j < 4; j++){
221  for(i = 0; i < 4; i++){
222  flags |= (c->output2[remap[i + j*4]]^1) << (i + j*4);
223  for(k = 0; k < 3; k++)
224  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  bytestream_put_le16(&dst, flags);
228  bytestream_put_le16(&dst, MKRGB555(c->codebook2, 0) | 0x8000);
229  for(i = 3; i < 24; i += 3)
230  bytestream_put_le16(&dst, MKRGB555(c->codebook2, i));
231  break;
232  }
233  }
234  src -= p->linesize[0] << 1;
235  prevptr -= avctx->width * 3 * 4;
236  }
237  if(skips)
238  bytestream_put_le16(&dst, skips | SKIP_PREFIX);
239  //EOF
240  bytestream_put_byte(&dst, 0);
241  bytestream_put_byte(&dst, 0);
242 
243  if(no_skips)
244  keyframe = 1;
245  if(keyframe)
246  c->keyint = 0;
247  else
248  c->keyint++;
249  if (keyframe) pkt->flags |= AV_PKT_FLAG_KEY;
250  pkt->size = dst - buf;
251  *got_packet = 1;
252 
253  return 0;
254 }
255 
256 
257 /**
258  * init encoder
259  */
261 {
262  Msvideo1EncContext * const c = avctx->priv_data;
263 
264  c->avctx = avctx;
265  if (av_image_check_size(avctx->width, avctx->height, 0, avctx) < 0) {
266  return -1;
267  }
268  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  avctx->bits_per_coded_sample = 16;
274 
275  c->keyint = avctx->keyint_min;
276  av_lfg_init(&c->rnd, 1);
277 
278  return 0;
279 }
280 
281 
282 
283 /**
284  * Uninit encoder
285  */
287 {
288  Msvideo1EncContext * const c = avctx->priv_data;
289 
290  av_freep(&c->prev);
291 
292  return 0;
293 }
294 
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,
305 };
AVCodec
AVCodec.
Definition: codec.h:190
AVPixelFormat
AVPixelFormat
Pixel format.
Definition: pixfmt.h:64
AVCodecContext::keyint_min
int keyint_min
minimum GOP size
Definition: avcodec.h:1107
init
static av_cold int init(AVCodecContext *avctx)
Definition: avrndec.c:35
MSV1Mode
MSV1Mode
Definition: msvideo1enc.c:52
FFSWAP
#define FFSWAP(type, a, b)
Definition: common.h:99
av_lfg_init
av_cold void av_lfg_init(AVLFG *c, unsigned int seed)
Definition: lfg.c:32
Msvideo1EncContext::codebook2
int codebook2[8 *3]
Definition: msvideo1enc.c:44
AVFrame
This structure describes decoded (raw) audio or video data.
Definition: frame.h:300
internal.h
AVPacket::data
uint8_t * data
Definition: packet.h:355
Msvideo1EncContext::avg
int avg[3]
Definition: msvideo1enc.c:47
Msvideo1EncContext::block2
int block2[16 *3]
Definition: msvideo1enc.c:42
MODE_FILL
@ MODE_FILL
Definition: msvideo1enc.c:54
AV_PKT_FLAG_KEY
#define AV_PKT_FLAG_KEY
The packet contains a keyframe.
Definition: packet.h:388
quality
trying all byte sequences megabyte in length and selecting the best looking sequence will yield cases to try But a word about quality
Definition: rate_distortion.txt:12
AVFrame::data
uint8_t * data[AV_NUM_DATA_POINTERS]
pointer to the picture/channel planes.
Definition: frame.h:314
av_malloc
#define av_malloc(s)
Definition: tableprint_vlc.h:31
Msvideo1EncContext::rnd
AVLFG rnd
Definition: msvideo1enc.c:38
val
static double val(void *priv, double ch)
Definition: aeval.c:76
Msvideo1EncContext::block
int block[16 *3]
Definition: msvideo1enc.c:41
AV_LOG_ERROR
#define AV_LOG_ERROR
Something went wrong and cannot losslessly be recovered.
Definition: log.h:176
av_cold
#define av_cold
Definition: attributes.h:90
Msvideo1EncContext::avctx
AVCodecContext * avctx
Definition: msvideo1enc.c:37
lfg.h
SKIP_PREFIX
#define SKIP_PREFIX
Definition: msvideo1enc.c:59
pix_fmts
static enum AVPixelFormat pix_fmts[]
Definition: libkvazaar.c:275
Msvideo1EncContext::output2
int output2[16 *3]
Definition: msvideo1enc.c:46
AV_INPUT_BUFFER_MIN_SIZE
#define AV_INPUT_BUFFER_MIN_SIZE
Definition: avcodec.h:222
elbg.h
Msvideo1EncContext::prev
uint8_t * prev
Definition: msvideo1enc.c:39
avpriv_init_elbg
int avpriv_init_elbg(int *points, int dim, int numpoints, int *codebook, int numCB, int max_steps, int *closest_cb, AVLFG *rand_state)
Initialize the **codebook vector for the elbg algorithm.
Definition: elbg.c:337
src
#define src
Definition: vp8dsp.c:254
Msvideo1EncContext::bestpos
int bestpos
Definition: msvideo1enc.c:48
c
Undefined Behavior In the C some operations are like signed integer dereferencing freed accessing outside allocated Undefined Behavior must not occur in a C it is not safe even if the output of undefined operations is unused The unsafety may seem nit picking but Optimizing compilers have in fact optimized code on the assumption that no undefined Behavior occurs Optimizing code based on wrong assumptions can and has in some cases lead to effects beyond the output of computations The signed integer overflow problem in speed critical code Code which is highly optimized and works with signed integers sometimes has the problem that often the output of the computation does not c
Definition: undefined.txt:32
AVLFG
Context structure for the Lagged Fibonacci PRNG.
Definition: lfg.h:33
AVPacket::size
int size
Definition: packet.h:356
NULL_IF_CONFIG_SMALL
#define NULL_IF_CONFIG_SMALL(x)
Return NULL if CONFIG_SMALL is true, otherwise the argument without modification.
Definition: internal.h:188
MODE_SKIP
@ MODE_SKIP
Definition: msvideo1enc.c:53
remap
static const int remap[16]
Definition: msvideo1enc.c:63
MODE_2COL
@ MODE_2COL
Definition: msvideo1enc.c:55
AVPacket::flags
int flags
A combination of AV_PKT_FLAG values.
Definition: packet.h:361
encode_end
static av_cold int encode_end(AVCodecContext *avctx)
Uninit encoder.
Definition: msvideo1enc.c:286
AVCodecContext::bits_per_coded_sample
int bits_per_coded_sample
bits per sample/pixel from the demuxer (needed for huffyuv).
Definition: avcodec.h:1750
MODE_8COL
@ MODE_8COL
Definition: msvideo1enc.c:56
i
#define i(width, name, range_min, range_max)
Definition: cbs_h2645.c:269
ff_msvideo1_encoder
AVCodec ff_msvideo1_encoder
Definition: msvideo1enc.c:295
Msvideo1EncContext
Encoder context.
Definition: msvideo1enc.c:36
AV_PIX_FMT_RGB555
#define AV_PIX_FMT_RGB555
Definition: pixfmt.h:385
uint8_t
uint8_t
Definition: audio_convert.c:194
Msvideo1EncContext::output
int output[16 *3]
Definition: msvideo1enc.c:45
AVCodec::name
const char * name
Name of the codec implementation.
Definition: codec.h:197
AVCodecContext::height
int height
Definition: avcodec.h:699
Msvideo1EncContext::codebook
int codebook[8 *3]
Definition: msvideo1enc.c:43
avcodec.h
ret
ret
Definition: filter_design.txt:187
encode_init
static av_cold int encode_init(AVCodecContext *avctx)
init encoder
Definition: msvideo1enc.c:260
AVCodecContext
main external API structure.
Definition: avcodec.h:526
pkt
static AVPacket pkt
Definition: demuxing_decoding.c:54
AV_PIX_FMT_NONE
@ AV_PIX_FMT_NONE
Definition: pixfmt.h:65
encode_frame
static int encode_frame(AVCodecContext *avctx, AVPacket *pkt, const AVFrame *pict, int *got_packet)
Definition: msvideo1enc.c:65
AVMEDIA_TYPE_VIDEO
@ AVMEDIA_TYPE_VIDEO
Definition: avutil.h:201
MKRGB555
#define MKRGB555(in, off)
Definition: msvideo1enc.c:61
FFALIGN
#define FFALIGN(x, a)
Definition: macros.h:48
AVCodecContext::priv_data
void * priv_data
Definition: avcodec.h:553
AVPacket
This structure stores compressed data.
Definition: packet.h:332
av_freep
#define av_freep(p)
Definition: tableprint_vlc.h:35
AVCodecContext::width
int width
picture width / height.
Definition: avcodec.h:699
bytestream.h
imgutils.h
flags
#define flags(name, subs,...)
Definition: cbs_av1.c:565
AVFrame::linesize
int linesize[AV_NUM_DATA_POINTERS]
For video, size in bytes of each picture line.
Definition: frame.h:331
av_log
#define av_log(a,...)
Definition: tableprint_vlc.h:28
Msvideo1EncContext::keyint
int keyint
Definition: msvideo1enc.c:49
av_image_check_size
int av_image_check_size(unsigned int w, unsigned int h, int log_offset, void *log_ctx)
Check if the given dimension of an image is valid, meaning that all bytes of the image can be address...
Definition: imgutils.c:282
AV_CODEC_ID_MSVIDEO1
@ AV_CODEC_ID_MSVIDEO1
Definition: codec_id.h:95
ff_alloc_packet2
int ff_alloc_packet2(AVCodecContext *avctx, AVPacket *avpkt, int64_t size, int64_t min_size)
Check AVPacket size and/or allocate data.
Definition: encode.c:32
SKIPS_MAX
#define SKIPS_MAX
Definition: msvideo1enc.c:60
avpriv_do_elbg
int avpriv_do_elbg(int *points, int dim, int numpoints, int *codebook, int numCB, int max_steps, int *closest_cb, AVLFG *rand_state)
Implementation of the Enhanced LBG Algorithm Based on the paper "Neural Networks 14:1219-1237" that c...
Definition: elbg.c:371