FFmpeg
flashsvenc.c
Go to the documentation of this file.
1 /*
2  * Flash Screen Video encoder
3  * Copyright (C) 2004 Alex Beregszaszi
4  * Copyright (C) 2006 Benjamin Larsson
5  *
6  * This file is part of FFmpeg.
7  *
8  * FFmpeg is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Lesser General Public
10  * License as published by the Free Software Foundation; either
11  * version 2.1 of the License, or (at your option) any later version.
12  *
13  * FFmpeg is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16  * Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with FFmpeg; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21  */
22 
23 /* Encoding development sponsored by http://fh-campuswien.ac.at */
24 
25 /**
26  * @file
27  * Flash Screen Video encoder
28  * @author Alex Beregszaszi
29  * @author Benjamin Larsson
30  *
31  * A description of the bitstream format for Flash Screen Video version 1/2
32  * is part of the SWF File Format Specification (version 10), which can be
33  * downloaded from http://www.adobe.com/devnet/swf.html.
34  */
35 
36 /*
37  * Encoding ideas: A basic encoder would just use a fixed block size.
38  * Block sizes can be multiples of 16, from 16 to 256. The blocks don't
39  * have to be quadratic. A brute force search with a set of different
40  * block sizes should give a better result than to just use a fixed size.
41  *
42  * TODO:
43  * Don't reencode the frame in brute force mode if the frame is a dupe.
44  * Speed up. Make the difference check faster.
45  */
46 
47 #include <stdio.h>
48 #include <stdlib.h>
49 #include <zlib.h>
50 
51 #include "avcodec.h"
52 #include "codec_internal.h"
53 #include "encode.h"
54 #include "put_bits.h"
55 #include "bytestream.h"
56 
57 
58 typedef struct FlashSVContext {
60  uint8_t *previous_frame;
63  uint8_t *encbuffer;
64  int block_size;
66  uint8_t tmpblock[3 * 256 * 256];
68 
69 static int copy_region_enc(uint8_t *sptr, uint8_t *dptr, int dx, int dy,
70  int h, int w, int stride, uint8_t *pfptr)
71 {
72  int i, j;
73  uint8_t *nsptr;
74  uint8_t *npfptr;
75  int diff = 0;
76 
77  for (i = dx + h; i > dx; i--) {
78  nsptr = sptr + i * stride + dy * 3;
79  npfptr = pfptr + i * stride + dy * 3;
80  for (j = 0; j < w * 3; j++) {
81  diff |= npfptr[j] ^ nsptr[j];
82  dptr[j] = nsptr[j];
83  }
84  dptr += w * 3;
85  }
86  if (diff)
87  return 1;
88  return 0;
89 }
90 
92 {
93  FlashSVContext *s = avctx->priv_data;
94 
95  av_freep(&s->encbuffer);
96  av_freep(&s->previous_frame);
97 
98  return 0;
99 }
100 
102 {
103  FlashSVContext *s = avctx->priv_data;
104 
105  s->avctx = avctx;
106 
107  if (avctx->width > 4095 || avctx->height > 4095) {
108  av_log(avctx, AV_LOG_ERROR,
109  "Input dimensions too large, input must be max 4095x4095 !\n");
110  return AVERROR_INVALIDDATA;
111  }
112 
113  s->last_key_frame = 0;
114 
115  s->image_width = avctx->width;
116  s->image_height = avctx->height;
117 
118  s->encbuffer = av_mallocz(s->image_width * s->image_height * 3);
119 
120  if (!s->encbuffer) {
121  av_log(avctx, AV_LOG_ERROR, "Memory allocation failed.\n");
122  return AVERROR(ENOMEM);
123  }
124 
125  return 0;
126 }
127 
128 
129 static int encode_bitstream(FlashSVContext *s, const AVFrame *p, uint8_t *buf,
130  int buf_size, int block_width, int block_height,
131  uint8_t *previous_frame, int *I_frame)
132 {
133 
134  PutBitContext pb;
135  int h_blocks, v_blocks, h_part, v_part, i, j;
136  int buf_pos, res;
137  int pred_blocks = 0;
138 
139  init_put_bits(&pb, buf, buf_size);
140 
141  put_bits(&pb, 4, block_width / 16 - 1);
142  put_bits(&pb, 12, s->image_width);
143  put_bits(&pb, 4, block_height / 16 - 1);
144  put_bits(&pb, 12, s->image_height);
145  flush_put_bits(&pb);
146  buf_pos = 4;
147 
148  h_blocks = s->image_width / block_width;
149  h_part = s->image_width % block_width;
150  v_blocks = s->image_height / block_height;
151  v_part = s->image_height % block_height;
152 
153  /* loop over all block columns */
154  for (j = 0; j < v_blocks + (v_part ? 1 : 0); j++) {
155 
156  int y_pos = j * block_height; // vertical position in frame
157  int cur_blk_height = (j < v_blocks) ? block_height : v_part;
158 
159  /* loop over all block rows */
160  for (i = 0; i < h_blocks + (h_part ? 1 : 0); i++) {
161  int x_pos = i * block_width; // horizontal position in frame
162  int cur_blk_width = (i < h_blocks) ? block_width : h_part;
163  int ret = Z_OK;
164  uint8_t *ptr = buf + buf_pos;
165 
166  /* copy the block to the temp buffer before compression
167  * (if it differs from the previous frame's block) */
168  res = copy_region_enc(p->data[0], s->tmpblock,
169  s->image_height - (y_pos + cur_blk_height + 1),
170  x_pos, cur_blk_height, cur_blk_width,
171  p->linesize[0], previous_frame);
172 
173  if (res || *I_frame) {
174  unsigned long zsize = 3 * block_width * block_height;
175  ret = compress2(ptr + 2, &zsize, s->tmpblock,
176  3 * cur_blk_width * cur_blk_height, 9);
177 
178  if (ret != Z_OK)
179  av_log(s->avctx, AV_LOG_ERROR,
180  "error while compressing block %dx%d\n", i, j);
181 
182  bytestream_put_be16(&ptr, zsize);
183  buf_pos += zsize + 2;
184  ff_dlog(s->avctx, "buf_pos = %d\n", buf_pos);
185  } else {
186  pred_blocks++;
187  bytestream_put_be16(&ptr, 0);
188  buf_pos += 2;
189  }
190  }
191  }
192 
193  if (pred_blocks)
194  *I_frame = 0;
195  else
196  *I_frame = 1;
197 
198  return buf_pos;
199 }
200 
201 
203  const AVFrame *pict, int *got_packet)
204 {
205  FlashSVContext * const s = avctx->priv_data;
206  const AVFrame * const p = pict;
207  uint8_t *pfptr;
208  int res;
209  int I_frame = 0;
210  int opt_w = 4, opt_h = 4;
211 
212  /* First frame needs to be a keyframe */
213  if (avctx->frame_number == 0) {
214  s->previous_frame = av_mallocz(FFABS(p->linesize[0]) * s->image_height);
215  if (!s->previous_frame) {
216  av_log(avctx, AV_LOG_ERROR, "Memory allocation failed.\n");
217  return AVERROR(ENOMEM);
218  }
219  I_frame = 1;
220  }
221 
222  if (p->linesize[0] < 0)
223  pfptr = s->previous_frame - (s->image_height - 1) * p->linesize[0];
224  else
225  pfptr = s->previous_frame;
226 
227  /* Check the placement of keyframes */
228  if (avctx->gop_size > 0 &&
229  avctx->frame_number >= s->last_key_frame + avctx->gop_size) {
230  I_frame = 1;
231  }
232 
233  if ((res = ff_alloc_packet(avctx, pkt, s->image_width * s->image_height * 3)) < 0)
234  return res;
235 
236  pkt->size = encode_bitstream(s, p, pkt->data, pkt->size, opt_w * 16, opt_h * 16,
237  pfptr, &I_frame);
238 
239  //save the current frame
240  if (p->linesize[0] > 0)
241  memcpy(s->previous_frame, p->data[0], s->image_height * p->linesize[0]);
242  else
243  memcpy(s->previous_frame,
244  p->data[0] + p->linesize[0] * (s->image_height - 1),
245  s->image_height * FFABS(p->linesize[0]));
246 
247  //mark the frame type so the muxer can mux it correctly
248  if (I_frame) {
249  s->last_key_frame = avctx->frame_number;
250  ff_dlog(avctx, "Inserting keyframe at frame %d\n", avctx->frame_number);
251  }
252 
253  if (I_frame)
255  *got_packet = 1;
256 
257  return 0;
258 }
259 
261  .p.name = "flashsv",
262  .p.long_name = NULL_IF_CONFIG_SMALL("Flash Screen Video"),
263  .p.type = AVMEDIA_TYPE_VIDEO,
264  .p.id = AV_CODEC_ID_FLASHSV,
265  .priv_data_size = sizeof(FlashSVContext),
268  .close = flashsv_encode_end,
269  .p.pix_fmts = (const enum AVPixelFormat[]){ AV_PIX_FMT_BGR24, AV_PIX_FMT_NONE },
270  .caps_internal = FF_CODEC_CAP_INIT_THREADSAFE,
271 };
AVPixelFormat
AVPixelFormat
Pixel format.
Definition: pixfmt.h:64
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
FlashSVContext::image_width
int image_width
Definition: flashsv.c:58
ff_flashsv_encoder
const FFCodec ff_flashsv_encoder
Definition: flashsvenc.c:260
init_put_bits
static void init_put_bits(PutBitContext *s, uint8_t *buffer, int buffer_size)
Initialize the PutBitContext s.
Definition: put_bits.h:62
AVFrame
This structure describes decoded (raw) audio or video data.
Definition: frame.h:325
put_bits
static void put_bits(Jpeg2000EncoderContext *s, int val, int n)
put n times val bit
Definition: j2kenc.c:221
w
uint8_t w
Definition: llviddspenc.c:38
AVPacket::data
uint8_t * data
Definition: packet.h:374
encode.h
FFCodec
Definition: codec_internal.h:112
AV_PIX_FMT_BGR24
@ AV_PIX_FMT_BGR24
packed RGB 8:8:8, 24bpp, BGRBGR...
Definition: pixfmt.h:69
AV_PKT_FLAG_KEY
#define AV_PKT_FLAG_KEY
The packet contains a keyframe.
Definition: packet.h:429
AVFrame::data
uint8_t * data[AV_NUM_DATA_POINTERS]
pointer to the picture/channel planes.
Definition: frame.h:346
init
static int init
Definition: av_tx.c:47
FFCodec::p
AVCodec p
The public AVCodec.
Definition: codec_internal.h:116
FlashSVContext::encbuffer
uint8_t * encbuffer
Definition: flashsvenc.c:63
FF_CODEC_ENCODE_CB
#define FF_CODEC_ENCODE_CB(func)
Definition: codec_internal.h:263
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
FlashSVContext::tmpblock
uint8_t * tmpblock
Definition: flashsv.c:60
s
#define s(width, name)
Definition: cbs_vp9.c:256
flashsv_encode_frame
static int flashsv_encode_frame(AVCodecContext *avctx, AVPacket *pkt, const AVFrame *pict, int *got_packet)
Definition: flashsvenc.c:202
PutBitContext
Definition: put_bits.h:50
FFABS
#define FFABS(a)
Absolute value, Note, INT_MIN / INT64_MIN result in undefined behavior as they are not representable ...
Definition: common.h:64
if
if(ret)
Definition: filter_design.txt:179
FlashSVContext
Definition: flashsv.c:55
AV_CODEC_ID_FLASHSV
@ AV_CODEC_ID_FLASHSV
Definition: codec_id.h:136
copy_region_enc
static int copy_region_enc(uint8_t *sptr, uint8_t *dptr, int dx, int dy, int h, int w, int stride, uint8_t *pfptr)
Definition: flashsvenc.c:69
ff_dlog
#define ff_dlog(a,...)
Definition: tableprint_vlc.h:28
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
AVCodecContext::gop_size
int gop_size
the number of pictures in a group of pictures, or 0 for intra_only
Definition: avcodec.h:584
codec_internal.h
flashsv_encode_init
static av_cold int flashsv_encode_init(AVCodecContext *avctx)
Definition: flashsvenc.c:101
FlashSVContext::block_height
int block_height
Definition: flashsv.c:59
AVPacket::flags
int flags
A combination of AV_PKT_FLAG values.
Definition: packet.h:380
FlashSVContext::block_width
int block_width
Definition: flashsv.c:59
i
#define i(width, name, range_min, range_max)
Definition: cbs_h2645.c:269
FlashSVContext::block_size
int block_size
Definition: flashsv.c:61
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
FlashSVContext::image_height
int image_height
Definition: flashsv.c:58
av_mallocz
void * av_mallocz(size_t size)
Allocate a memory block with alignment suitable for all memory accesses (including vectors if availab...
Definition: mem.c:264
AVCodec::name
const char * name
Name of the codec implementation.
Definition: codec.h:203
AVCodecContext::height
int height
Definition: avcodec.h:562
avcodec.h
stride
#define stride
Definition: h264pred_template.c:537
flashsv_encode_end
static av_cold int flashsv_encode_end(AVCodecContext *avctx)
Definition: flashsvenc.c:91
ret
ret
Definition: filter_design.txt:187
AVCodecContext
main external API structure.
Definition: avcodec.h:389
AV_PIX_FMT_NONE
@ AV_PIX_FMT_NONE
Definition: pixfmt.h:65
FlashSVContext::previous_frame
uint8_t * previous_frame
Definition: flashsvenc.c:60
AVMEDIA_TYPE_VIDEO
@ AVMEDIA_TYPE_VIDEO
Definition: avutil.h:201
AVCodecContext::frame_number
int frame_number
Frame counter, set by libavcodec.
Definition: avcodec.h:1037
flush_put_bits
static void flush_put_bits(PutBitContext *s)
Pad the end of the output stream with zeros.
Definition: put_bits.h:143
diff
static av_always_inline int diff(const uint32_t a, const uint32_t b)
Definition: vf_palettegen.c:139
AVPacket
This structure stores compressed data.
Definition: packet.h:351
AVCodecContext::priv_data
void * priv_data
Definition: avcodec.h:416
av_freep
#define av_freep(p)
Definition: tableprint_vlc.h:34
AVCodecContext::width
int width
picture width / height.
Definition: avcodec.h:562
bytestream.h
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
AVERROR_INVALIDDATA
#define AVERROR_INVALIDDATA
Invalid data found when processing input.
Definition: error.h:61
h
h
Definition: vp9dsp_template.c:2038
FlashSVContext::avctx
AVCodecContext * avctx
Definition: flashsv.c:56
put_bits.h
ff_alloc_packet
int ff_alloc_packet(AVCodecContext *avctx, AVPacket *avpkt, int64_t size)
Check AVPacket size and allocate data.
Definition: encode.c:35
FlashSVContext::last_key_frame
int last_key_frame
Definition: flashsvenc.c:65
encode_bitstream
static int encode_bitstream(FlashSVContext *s, const AVFrame *p, uint8_t *buf, int buf_size, int block_width, int block_height, uint8_t *previous_frame, int *I_frame)
Definition: flashsvenc.c:129