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 "codec_internal.h"
29 #include "encode.h"
30 #include "bytestream.h"
31 #include "libavutil/lfg.h"
32 #include "elbg.h"
33 #include "libavutil/imgutils.h"
34 /**
35  * Encoder context
36  */
37 typedef struct Msvideo1EncContext {
39  struct ELBGContext *elbg;
41  uint8_t *prev;
42 
43  int block[16*3];
44  int block2[16*3];
45  int codebook[8*3];
46  int codebook2[8*3];
47  int output[16*3];
48  int output2[16*3];
49  int avg[3];
50  int bestpos;
51  int keyint;
53 
54 enum MSV1Mode{
55  MODE_SKIP = 0,
59 };
60 
61 #define SKIP_PREFIX 0x8400
62 #define SKIPS_MAX 0x03FF
63 #define MKRGB555(in, off) (((in)[off] << 10) | ((in)[(off) + 1] << 5) | ((in)[(off) + 2]))
64 
65 static const int remap[16] = { 0, 1, 4, 5, 2, 3, 6, 7, 8, 9, 12, 13, 10, 11, 14, 15 };
66 
68  const AVFrame *pict, int *got_packet)
69 {
70  Msvideo1EncContext * const c = avctx->priv_data;
71  const AVFrame *p = pict;
72  uint16_t *src;
73  uint8_t *prevptr;
74  uint8_t *dst, *buf;
75  int keyframe = 0;
76  int no_skips = 1;
77  int i, j, k, x, y, ret;
78  int skips = 0;
79  int quality = 24;
80 
81  if ((ret = ff_alloc_packet(avctx, pkt, avctx->width*avctx->height*9 + AV_INPUT_BUFFER_MIN_SIZE)) < 0)
82  return ret;
83  dst= buf= pkt->data;
84 
85  if(!c->prev)
86  c->prev = av_malloc(avctx->width * 3 * (avctx->height + 3));
87  prevptr = c->prev + avctx->width * 3 * (FFALIGN(avctx->height, 4) - 1);
88  src = (uint16_t*)(p->data[0] + p->linesize[0]*(FFALIGN(avctx->height, 4) - 1));
89  if(c->keyint >= avctx->keyint_min)
90  keyframe = 1;
91 
92 
93  for(y = 0; y < avctx->height; y += 4){
94  for(x = 0; x < avctx->width; x += 4){
95  int bestmode = MODE_SKIP;
96  int bestscore = INT_MAX;
97  int flags = 0;
98  int score;
99 
100  for(j = 0; j < 4; j++){
101  for(i = 0; i < 4; i++){
102  uint16_t val = src[x + i - j*p->linesize[0]/2];
103  for(k = 0; k < 3; k++){
104  c->block[(i + j*4)*3 + k] =
105  c->block2[remap[i + j*4]*3 + k] = (val >> (10-k*5)) & 0x1F;
106  }
107  }
108  }
109  if(!keyframe){
110  bestscore = 0;
111  for(j = 0; j < 4; j++){
112  for(i = 0; i < 4*3; i++){
113  int t = prevptr[x*3 + i - j*3*avctx->width] - c->block[i + j*4*3];
114  bestscore += t*t;
115  }
116  }
117  bestscore /= quality;
118  }
119  // try to find optimal value to fill whole 4x4 block
120  score = 0;
121  ret = avpriv_elbg_do(&c->elbg, c->block, 3, 16, c->avg,
122  1, 1, c->output, &c->rnd, 0);
123  if (ret < 0)
124  return ret;
125  if(c->avg[0] == 1) // red component = 1 will be written as skip code
126  c->avg[0] = 0;
127  for(j = 0; j < 4; j++){
128  for(i = 0; i < 4; i++){
129  for(k = 0; k < 3; k++){
130  int t = c->avg[k] - c->block[(i+j*4)*3+k];
131  score += t*t;
132  }
133  }
134  }
135  score /= quality;
136  score += 2;
137  if(score < bestscore){
138  bestscore = score;
139  bestmode = MODE_FILL;
140  }
141  // search for optimal filling of 2-color block
142  score = 0;
143  ret = avpriv_elbg_do(&c->elbg, c->block, 3, 16, c->codebook,
144  2, 1, c->output, &c->rnd, 0);
145  if (ret < 0)
146  return ret;
147  // last output value should be always 1, swap codebooks if needed
148  if(!c->output[15]){
149  for(i = 0; i < 3; i++)
150  FFSWAP(uint8_t, c->codebook[i], c->codebook[i+3]);
151  for(i = 0; i < 16; i++)
152  c->output[i] ^= 1;
153  }
154  for(j = 0; j < 4; j++){
155  for(i = 0; i < 4; i++){
156  for(k = 0; k < 3; k++){
157  int t = c->codebook[c->output[i+j*4]*3 + k] - c->block[i*3+k+j*4*3];
158  score += t*t;
159  }
160  }
161  }
162  score /= quality;
163  score += 6;
164  if(score < bestscore){
165  bestscore = score;
166  bestmode = MODE_2COL;
167  }
168  // search for optimal filling of 2-color 2x2 subblocks
169  score = 0;
170  for(i = 0; i < 4; i++){
171  ret = avpriv_elbg_do(&c->elbg, c->block2 + i * 4 * 3, 3, 4,
172  c->codebook2 + i * 2 * 3, 2, 1,
173  c->output2 + i * 4, &c->rnd, 0);
174  if (ret < 0)
175  return ret;
176  }
177  // last value should be always 1, swap codebooks if needed
178  if(!c->output2[15]){
179  for(i = 0; i < 3; i++)
180  FFSWAP(uint8_t, c->codebook2[i+18], c->codebook2[i+21]);
181  for(i = 12; i < 16; i++)
182  c->output2[i] ^= 1;
183  }
184  for(j = 0; j < 4; j++){
185  for(i = 0; i < 4; i++){
186  for(k = 0; k < 3; k++){
187  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];
188  score += t*t;
189  }
190  }
191  }
192  score /= quality;
193  score += 18;
194  if(score < bestscore){
195  bestscore = score;
196  bestmode = MODE_8COL;
197  }
198 
199  if(bestmode == MODE_SKIP){
200  skips++;
201  no_skips = 0;
202  }
203  if((bestmode != MODE_SKIP && skips) || skips == SKIPS_MAX){
204  bytestream_put_le16(&dst, skips | SKIP_PREFIX);
205  skips = 0;
206  }
207 
208  switch(bestmode){
209  case MODE_FILL:
210  bytestream_put_le16(&dst, MKRGB555(c->avg,0) | 0x8000);
211  for(j = 0; j < 4; j++)
212  for(i = 0; i < 4; i++)
213  for(k = 0; k < 3; k++)
214  prevptr[x*3 + i*3 + k - j*3*avctx->width] = c->avg[k];
215  break;
216  case MODE_2COL:
217  for(j = 0; j < 4; j++){
218  for(i = 0; i < 4; i++){
219  flags |= (c->output[i + j*4]^1) << (i + j*4);
220  for(k = 0; k < 3; k++)
221  prevptr[x*3 + i*3 + k - j*3*avctx->width] = c->codebook[c->output[i + j*4]*3 + k];
222  }
223  }
224  bytestream_put_le16(&dst, flags);
225  bytestream_put_le16(&dst, MKRGB555(c->codebook, 0));
226  bytestream_put_le16(&dst, MKRGB555(c->codebook, 3));
227  break;
228  case MODE_8COL:
229  for(j = 0; j < 4; j++){
230  for(i = 0; i < 4; i++){
231  flags |= (c->output2[remap[i + j*4]]^1) << (i + j*4);
232  for(k = 0; k < 3; k++)
233  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];
234  }
235  }
236  bytestream_put_le16(&dst, flags);
237  bytestream_put_le16(&dst, MKRGB555(c->codebook2, 0) | 0x8000);
238  for(i = 3; i < 24; i += 3)
239  bytestream_put_le16(&dst, MKRGB555(c->codebook2, i));
240  break;
241  }
242  }
243  src -= p->linesize[0] << 1;
244  prevptr -= avctx->width * 3 * 4;
245  }
246  if(skips)
247  bytestream_put_le16(&dst, skips | SKIP_PREFIX);
248  //EOF
249  bytestream_put_byte(&dst, 0);
250  bytestream_put_byte(&dst, 0);
251 
252  if(no_skips)
253  keyframe = 1;
254  if(keyframe)
255  c->keyint = 0;
256  else
257  c->keyint++;
258  if (keyframe) pkt->flags |= AV_PKT_FLAG_KEY;
259  pkt->size = dst - buf;
260  *got_packet = 1;
261 
262  return 0;
263 }
264 
265 
266 /**
267  * init encoder
268  */
270 {
271  Msvideo1EncContext * const c = avctx->priv_data;
272 
273  c->avctx = avctx;
274  if (av_image_check_size(avctx->width, avctx->height, 0, avctx) < 0) {
275  return -1;
276  }
277  if((avctx->width&3) || (avctx->height&3)){
278  av_log(avctx, AV_LOG_ERROR, "width and height must be multiples of 4\n");
279  return -1;
280  }
281 
282  avctx->bits_per_coded_sample = 16;
283 
284  c->keyint = avctx->keyint_min;
285  av_lfg_init(&c->rnd, 1);
286 
287  return 0;
288 }
289 
290 
291 
292 /**
293  * Uninit encoder
294  */
296 {
297  Msvideo1EncContext * const c = avctx->priv_data;
298 
299  av_freep(&c->prev);
300  avpriv_elbg_free(&c->elbg);
301 
302  return 0;
303 }
304 
306  .p.name = "msvideo1",
307  .p.long_name = NULL_IF_CONFIG_SMALL("Microsoft Video-1"),
308  .p.type = AVMEDIA_TYPE_VIDEO,
309  .p.id = AV_CODEC_ID_MSVIDEO1,
310  .priv_data_size = sizeof(Msvideo1EncContext),
311  .init = encode_init,
313  .close = encode_end,
314  .p.pix_fmts = (const enum AVPixelFormat[]){AV_PIX_FMT_RGB555, AV_PIX_FMT_NONE},
315  .caps_internal = FF_CODEC_CAP_INIT_THREADSAFE,
316 };
AVPixelFormat
AVPixelFormat
Pixel format.
Definition: pixfmt.h:64
AVCodecContext::keyint_min
int keyint_min
minimum GOP size
Definition: avcodec.h:931
MSV1Mode
MSV1Mode
Definition: msvideo1enc.c:54
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:46
AVFrame
This structure describes decoded (raw) audio or video data.
Definition: frame.h:325
AVPacket::data
uint8_t * data
Definition: packet.h:374
encode.h
Msvideo1EncContext::avg
int avg[3]
Definition: msvideo1enc.c:49
Msvideo1EncContext::block2
int block2[16 *3]
Definition: msvideo1enc.c:44
FFCodec
Definition: codec_internal.h:112
ff_msvideo1_encoder
const FFCodec ff_msvideo1_encoder
Definition: msvideo1enc.c:305
MODE_FILL
@ MODE_FILL
Definition: msvideo1enc.c:56
AV_PKT_FLAG_KEY
#define AV_PKT_FLAG_KEY
The packet contains a keyframe.
Definition: packet.h:429
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:346
av_malloc
#define av_malloc(s)
Definition: tableprint_vlc.h:30
init
static int init
Definition: av_tx.c:47
Msvideo1EncContext::rnd
AVLFG rnd
Definition: msvideo1enc.c:40
FFCodec::p
AVCodec p
The public AVCodec.
Definition: codec_internal.h:116
val
static double val(void *priv, double ch)
Definition: aeval.c:77
Msvideo1EncContext::block
int block[16 *3]
Definition: msvideo1enc.c:43
FF_CODEC_ENCODE_CB
#define FF_CODEC_ENCODE_CB(func)
Definition: codec_internal.h:263
avpriv_elbg_do
int avpriv_elbg_do(ELBGContext **elbgp, int *points, int dim, int numpoints, int *codebook, int num_cb, int max_steps, int *closest_cb, AVLFG *rand_state, uintptr_t flags)
Implementation of the Enhanced LBG Algorithm Based on the paper "Neural Networks 14:1219-1237" that c...
Definition: elbg.c:446
pkt
AVPacket * pkt
Definition: movenc.c:59
AV_LOG_ERROR
#define AV_LOG_ERROR
Something went wrong and cannot losslessly be recovered.
Definition: log.h:180
av_cold
#define av_cold
Definition: attributes.h:90
Msvideo1EncContext::avctx
AVCodecContext * avctx
Definition: msvideo1enc.c:38
lfg.h
SKIP_PREFIX
#define SKIP_PREFIX
Definition: msvideo1enc.c:61
Msvideo1EncContext::output2
int output2[16 *3]
Definition: msvideo1enc.c:48
AV_INPUT_BUFFER_MIN_SIZE
#define AV_INPUT_BUFFER_MIN_SIZE
Definition: avcodec.h:191
elbg.h
Msvideo1EncContext::prev
uint8_t * prev
Definition: msvideo1enc.c:41
Msvideo1EncContext::bestpos
int bestpos
Definition: msvideo1enc.c:50
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:375
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:117
codec_internal.h
MODE_SKIP
@ MODE_SKIP
Definition: msvideo1enc.c:55
avpriv_elbg_free
av_cold void avpriv_elbg_free(ELBGContext **elbgp)
Free an ELBGContext and reset the pointer to it.
Definition: elbg.c:499
remap
static const int remap[16]
Definition: msvideo1enc.c:65
MODE_2COL
@ MODE_2COL
Definition: msvideo1enc.c:57
AVPacket::flags
int flags
A combination of AV_PKT_FLAG values.
Definition: packet.h:380
encode_end
static av_cold int encode_end(AVCodecContext *avctx)
Uninit encoder.
Definition: msvideo1enc.c:295
AVCodecContext::bits_per_coded_sample
int bits_per_coded_sample
bits per sample/pixel from the demuxer (needed for huffyuv).
Definition: avcodec.h:1441
MODE_8COL
@ MODE_8COL
Definition: msvideo1enc.c:58
i
#define i(width, name, range_min, range_max)
Definition: cbs_h2645.c:269
ELBGContext
ELBG internal data.
Definition: elbg.c:46
Msvideo1EncContext
Encoder context.
Definition: msvideo1enc.c:37
AV_PIX_FMT_RGB555
#define AV_PIX_FMT_RGB555
Definition: pixfmt.h:394
FF_CODEC_CAP_INIT_THREADSAFE
#define FF_CODEC_CAP_INIT_THREADSAFE
The codec does not modify any global variables in the init function, allowing to call the init functi...
Definition: codec_internal.h:31
Msvideo1EncContext::output
int output[16 *3]
Definition: msvideo1enc.c:47
AVCodec::name
const char * name
Name of the codec implementation.
Definition: codec.h:203
AVCodecContext::height
int height
Definition: avcodec.h:562
Msvideo1EncContext::codebook
int codebook[8 *3]
Definition: msvideo1enc.c:45
avcodec.h
ret
ret
Definition: filter_design.txt:187
FFSWAP
#define FFSWAP(type, a, b)
Definition: macros.h:52
encode_init
static av_cold int encode_init(AVCodecContext *avctx)
init encoder
Definition: msvideo1enc.c:269
AVCodecContext
main external API structure.
Definition: avcodec.h:389
AV_PIX_FMT_NONE
@ AV_PIX_FMT_NONE
Definition: pixfmt.h:65
Msvideo1EncContext::elbg
struct ELBGContext * elbg
Definition: msvideo1enc.c:39
encode_frame
static int encode_frame(AVCodecContext *avctx, AVPacket *pkt, const AVFrame *pict, int *got_packet)
Definition: msvideo1enc.c:67
AVMEDIA_TYPE_VIDEO
@ AVMEDIA_TYPE_VIDEO
Definition: avutil.h:201
MKRGB555
#define MKRGB555(in, off)
Definition: msvideo1enc.c:63
FFALIGN
#define FFALIGN(x, a)
Definition: macros.h:78
AVCodecContext::priv_data
void * priv_data
Definition: avcodec.h:416
AVPacket
This structure stores compressed data.
Definition: packet.h:351
av_freep
#define av_freep(p)
Definition: tableprint_vlc.h:34
src
INIT_CLIP pixel * src
Definition: h264pred_template.c:418
AVCodecContext::width
int width
picture width / height.
Definition: avcodec.h:562
bytestream.h
imgutils.h
flags
#define flags(name, subs,...)
Definition: cbs_av1.c:561
AVFrame::linesize
int linesize[AV_NUM_DATA_POINTERS]
For video, a positive or negative value, which is typically indicating the size in bytes of each pict...
Definition: frame.h:370
av_log
#define av_log(a,...)
Definition: tableprint_vlc.h:27
Msvideo1EncContext::keyint
int keyint
Definition: msvideo1enc.c:51
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:318
AV_CODEC_ID_MSVIDEO1
@ AV_CODEC_ID_MSVIDEO1
Definition: codec_id.h:96
ff_alloc_packet
int ff_alloc_packet(AVCodecContext *avctx, AVPacket *avpkt, int64_t size)
Check AVPacket size and allocate data.
Definition: encode.c:35
SKIPS_MAX
#define SKIPS_MAX
Definition: msvideo1enc.c:62