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  const 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  if (!c->prev)
88  return AVERROR(ENOMEM);
89  prevptr = c->prev + avctx->width * 3 * (FFALIGN(avctx->height, 4) - 1);
90  src = (const uint16_t*)(p->data[0] + p->linesize[0]*(FFALIGN(avctx->height, 4) - 1));
91  if(c->keyint >= avctx->keyint_min)
92  keyframe = 1;
93 
94 
95  for(y = 0; y < avctx->height; y += 4){
96  for(x = 0; x < avctx->width; x += 4){
97  int bestmode = MODE_SKIP;
98  int bestscore = INT_MAX;
99  int flags = 0;
100  int score;
101 
102  for(j = 0; j < 4; j++){
103  for(i = 0; i < 4; i++){
104  uint16_t val = src[x + i - j*p->linesize[0]/2];
105  for(k = 0; k < 3; k++){
106  c->block[(i + j*4)*3 + k] =
107  c->block2[remap[i + j*4]*3 + k] = (val >> (10-k*5)) & 0x1F;
108  }
109  }
110  }
111  if(!keyframe){
112  bestscore = 0;
113  for(j = 0; j < 4; j++){
114  for(i = 0; i < 4*3; i++){
115  int t = prevptr[x*3 + i - j*3*avctx->width] - c->block[i + j*4*3];
116  bestscore += t*t;
117  }
118  }
119  bestscore /= quality;
120  }
121  // try to find optimal value to fill whole 4x4 block
122  score = 0;
123  ret = avpriv_elbg_do(&c->elbg, c->block, 3, 16, c->avg,
124  1, 1, c->output, &c->rnd, 0);
125  if (ret < 0)
126  return ret;
127  if(c->avg[0] == 1) // red component = 1 will be written as skip code
128  c->avg[0] = 0;
129  for(j = 0; j < 4; j++){
130  for(i = 0; i < 4; i++){
131  for(k = 0; k < 3; k++){
132  int t = c->avg[k] - c->block[(i+j*4)*3+k];
133  score += t*t;
134  }
135  }
136  }
137  score /= quality;
138  score += 2;
139  if(score < bestscore){
140  bestscore = score;
141  bestmode = MODE_FILL;
142  }
143  // search for optimal filling of 2-color block
144  score = 0;
145  ret = avpriv_elbg_do(&c->elbg, c->block, 3, 16, c->codebook,
146  2, 1, c->output, &c->rnd, 0);
147  if (ret < 0)
148  return ret;
149  // last output value should be always 1, swap codebooks if needed
150  if(!c->output[15]){
151  for(i = 0; i < 3; i++)
152  FFSWAP(uint8_t, c->codebook[i], c->codebook[i+3]);
153  for(i = 0; i < 16; i++)
154  c->output[i] ^= 1;
155  }
156  for(j = 0; j < 4; j++){
157  for(i = 0; i < 4; i++){
158  for(k = 0; k < 3; k++){
159  int t = c->codebook[c->output[i+j*4]*3 + k] - c->block[i*3+k+j*4*3];
160  score += t*t;
161  }
162  }
163  }
164  score /= quality;
165  score += 6;
166  if(score < bestscore){
167  bestscore = score;
168  bestmode = MODE_2COL;
169  }
170  // search for optimal filling of 2-color 2x2 subblocks
171  score = 0;
172  for(i = 0; i < 4; i++){
173  ret = avpriv_elbg_do(&c->elbg, c->block2 + i * 4 * 3, 3, 4,
174  c->codebook2 + i * 2 * 3, 2, 1,
175  c->output2 + i * 4, &c->rnd, 0);
176  if (ret < 0)
177  return ret;
178  }
179  // last value should be always 1, swap codebooks if needed
180  if(!c->output2[15]){
181  for(i = 0; i < 3; i++)
182  FFSWAP(uint8_t, c->codebook2[i+18], c->codebook2[i+21]);
183  for(i = 12; i < 16; i++)
184  c->output2[i] ^= 1;
185  }
186  for(j = 0; j < 4; j++){
187  for(i = 0; i < 4; i++){
188  for(k = 0; k < 3; k++){
189  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];
190  score += t*t;
191  }
192  }
193  }
194  score /= quality;
195  score += 18;
196  if(score < bestscore){
197  bestscore = score;
198  bestmode = MODE_8COL;
199  }
200 
201  if(bestmode == MODE_SKIP){
202  skips++;
203  no_skips = 0;
204  }
205  if((bestmode != MODE_SKIP && skips) || skips == SKIPS_MAX){
206  bytestream_put_le16(&dst, skips | SKIP_PREFIX);
207  skips = 0;
208  }
209 
210  switch(bestmode){
211  case MODE_FILL:
212  bytestream_put_le16(&dst, MKRGB555(c->avg,0) | 0x8000);
213  for(j = 0; j < 4; j++)
214  for(i = 0; i < 4; i++)
215  for(k = 0; k < 3; k++)
216  prevptr[x*3 + i*3 + k - j*3*avctx->width] = c->avg[k];
217  break;
218  case MODE_2COL:
219  for(j = 0; j < 4; j++){
220  for(i = 0; i < 4; i++){
221  flags |= (c->output[i + j*4]^1) << (i + j*4);
222  for(k = 0; k < 3; k++)
223  prevptr[x*3 + i*3 + k - j*3*avctx->width] = c->codebook[c->output[i + j*4]*3 + k];
224  }
225  }
226  bytestream_put_le16(&dst, flags);
227  bytestream_put_le16(&dst, MKRGB555(c->codebook, 0));
228  bytestream_put_le16(&dst, MKRGB555(c->codebook, 3));
229  break;
230  case MODE_8COL:
231  for(j = 0; j < 4; j++){
232  for(i = 0; i < 4; i++){
233  flags |= (c->output2[remap[i + j*4]]^1) << (i + j*4);
234  for(k = 0; k < 3; k++)
235  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];
236  }
237  }
238  bytestream_put_le16(&dst, flags);
239  bytestream_put_le16(&dst, MKRGB555(c->codebook2, 0) | 0x8000);
240  for(i = 3; i < 24; i += 3)
241  bytestream_put_le16(&dst, MKRGB555(c->codebook2, i));
242  break;
243  }
244  }
245  src -= p->linesize[0] << 1;
246  prevptr -= avctx->width * 3 * 4;
247  }
248  if(skips)
249  bytestream_put_le16(&dst, skips | SKIP_PREFIX);
250  //EOF
251  bytestream_put_byte(&dst, 0);
252  bytestream_put_byte(&dst, 0);
253 
254  if(no_skips)
255  keyframe = 1;
256  if(keyframe)
257  c->keyint = 0;
258  else
259  c->keyint++;
260  if (keyframe) pkt->flags |= AV_PKT_FLAG_KEY;
261  pkt->size = dst - buf;
262  *got_packet = 1;
263 
264  return 0;
265 }
266 
267 
268 /**
269  * init encoder
270  */
272 {
273  Msvideo1EncContext * const c = avctx->priv_data;
274 
275  c->avctx = avctx;
276  if (av_image_check_size(avctx->width, avctx->height, 0, avctx) < 0) {
277  return -1;
278  }
279  if((avctx->width&3) || (avctx->height&3)){
280  av_log(avctx, AV_LOG_ERROR, "width and height must be multiples of 4\n");
281  return -1;
282  }
283 
284  avctx->bits_per_coded_sample = 16;
285 
286  c->keyint = avctx->keyint_min;
287  av_lfg_init(&c->rnd, 1);
288 
289  return 0;
290 }
291 
292 
293 
294 /**
295  * Uninit encoder
296  */
298 {
299  Msvideo1EncContext * const c = avctx->priv_data;
300 
301  av_freep(&c->prev);
302  avpriv_elbg_free(&c->elbg);
303 
304  return 0;
305 }
306 
308  .p.name = "msvideo1",
309  CODEC_LONG_NAME("Microsoft Video-1"),
310  .p.type = AVMEDIA_TYPE_VIDEO,
311  .p.id = AV_CODEC_ID_MSVIDEO1,
312  .p.capabilities = AV_CODEC_CAP_ENCODER_REORDERED_OPAQUE,
313  .priv_data_size = sizeof(Msvideo1EncContext),
314  .init = encode_init,
316  .close = encode_end,
317  .p.pix_fmts = (const enum AVPixelFormat[]){AV_PIX_FMT_RGB555, AV_PIX_FMT_NONE},
318 };
AVPixelFormat
AVPixelFormat
Pixel format.
Definition: pixfmt.h:64
AVCodecContext::keyint_min
int keyint_min
minimum GOP size
Definition: avcodec.h:994
AVERROR
Filter the word “frame” indicates either a video frame or a group of audio as stored in an AVFrame structure Format for each input and each output the list of supported formats For video that means pixel format For audio that means channel sample they are references to shared objects When the negotiation mechanism computes the intersection of the formats supported at each end of a all references to both lists are replaced with a reference to the intersection And when a single format is eventually chosen for a link amongst the remaining all references to the list are updated That means that if a filter requires that its input and output have the same format amongst a supported all it has to do is use a reference to the same list of formats query_formats can leave some formats unset and return AVERROR(EAGAIN) to cause the negotiation mechanism toagain later. That can be used by filters with complex requirements to use the format negotiated on one link to set the formats supported on another. Frame references ownership and permissions
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:340
AVPacket::data
uint8_t * data
Definition: packet.h:491
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:127
ff_msvideo1_encoder
const FFCodec ff_msvideo1_encoder
Definition: msvideo1enc.c:307
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:546
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:361
av_malloc
#define av_malloc(s)
Definition: tableprint_vlc.h:30
Msvideo1EncContext::rnd
AVLFG rnd
Definition: msvideo1enc.c:40
FFCodec::p
AVCodec p
The public AVCodec.
Definition: codec_internal.h:131
val
static double val(void *priv, double ch)
Definition: aeval.c:78
Msvideo1EncContext::block
int block[16 *3]
Definition: msvideo1enc.c:43
FF_CODEC_ENCODE_CB
#define FF_CODEC_ENCODE_CB(func)
Definition: codec_internal.h:315
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:462
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
init
int(* init)(AVBSFContext *ctx)
Definition: dts2pts_bsf.c:365
AV_CODEC_CAP_ENCODER_REORDERED_OPAQUE
#define AV_CODEC_CAP_ENCODER_REORDERED_OPAQUE
This encoder can reorder user opaque values from input AVFrames and return them with corresponding ou...
Definition: codec.h:159
Msvideo1EncContext::output2
int output2[16 *3]
Definition: msvideo1enc.c:48
AV_INPUT_BUFFER_MIN_SIZE
#define AV_INPUT_BUFFER_MIN_SIZE
Definition: avcodec.h:195
CODEC_LONG_NAME
#define CODEC_LONG_NAME(str)
Definition: codec_internal.h:272
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:492
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:515
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:497
encode_end
static av_cold int encode_end(AVCodecContext *avctx)
Uninit encoder.
Definition: msvideo1enc.c:297
AVCodecContext::bits_per_coded_sample
int bits_per_coded_sample
bits per sample/pixel from the demuxer (needed for huffyuv).
Definition: avcodec.h:1510
MODE_8COL
@ MODE_8COL
Definition: msvideo1enc.c:58
i
#define i(width, name, range_min, range_max)
Definition: cbs_h2645.c:255
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:456
Msvideo1EncContext::output
int output[16 *3]
Definition: msvideo1enc.c:47
AVCodec::name
const char * name
Name of the codec implementation.
Definition: codec.h:194
AVCodecContext::height
int height
Definition: avcodec.h:621
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:271
AVCodecContext
main external API structure.
Definition: avcodec.h:441
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:468
AVPacket
This structure stores compressed data.
Definition: packet.h:468
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:621
bytestream.h
imgutils.h
flags
#define flags(name, subs,...)
Definition: cbs_av1.c:474
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:385
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:98
ff_alloc_packet
int ff_alloc_packet(AVCodecContext *avctx, AVPacket *avpkt, int64_t size)
Check AVPacket size and allocate data.
Definition: encode.c:61
SKIPS_MAX
#define SKIPS_MAX
Definition: msvideo1enc.c:62