Details | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
6148 | serge | 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 |
||
48 | #include |
||
49 | #include |
||
50 | |||
51 | #include "avcodec.h" |
||
52 | #include "internal.h" |
||
53 | #include "put_bits.h" |
||
54 | #include "bytestream.h" |
||
55 | |||
56 | |||
57 | typedef struct FlashSVContext { |
||
58 | AVCodecContext *avctx; |
||
59 | uint8_t *previous_frame; |
||
60 | AVFrame frame; |
||
61 | int image_width, image_height; |
||
62 | int block_width, block_height; |
||
63 | uint8_t *tmpblock; |
||
64 | uint8_t *encbuffer; |
||
65 | int block_size; |
||
66 | z_stream zstream; |
||
67 | int last_key_frame; |
||
68 | } FlashSVContext; |
||
69 | |||
70 | static int copy_region_enc(uint8_t *sptr, uint8_t *dptr, int dx, int dy, |
||
71 | int h, int w, int stride, uint8_t *pfptr) |
||
72 | { |
||
73 | int i, j; |
||
74 | uint8_t *nsptr; |
||
75 | uint8_t *npfptr; |
||
76 | int diff = 0; |
||
77 | |||
78 | for (i = dx + h; i > dx; i--) { |
||
79 | nsptr = sptr + i * stride + dy * 3; |
||
80 | npfptr = pfptr + i * stride + dy * 3; |
||
81 | for (j = 0; j < w * 3; j++) { |
||
82 | diff |= npfptr[j] ^ nsptr[j]; |
||
83 | dptr[j] = nsptr[j]; |
||
84 | } |
||
85 | dptr += w * 3; |
||
86 | } |
||
87 | if (diff) |
||
88 | return 1; |
||
89 | return 0; |
||
90 | } |
||
91 | |||
92 | static av_cold int flashsv_encode_init(AVCodecContext *avctx) |
||
93 | { |
||
94 | FlashSVContext *s = avctx->priv_data; |
||
95 | |||
96 | s->avctx = avctx; |
||
97 | |||
98 | if (avctx->width > 4095 || avctx->height > 4095) { |
||
99 | av_log(avctx, AV_LOG_ERROR, |
||
100 | "Input dimensions too large, input must be max 4096x4096 !\n"); |
||
101 | return AVERROR_INVALIDDATA; |
||
102 | } |
||
103 | |||
104 | // Needed if zlib unused or init aborted before deflateInit |
||
105 | memset(&s->zstream, 0, sizeof(z_stream)); |
||
106 | |||
107 | s->last_key_frame = 0; |
||
108 | |||
109 | s->image_width = avctx->width; |
||
110 | s->image_height = avctx->height; |
||
111 | |||
112 | s->tmpblock = av_mallocz(3 * 256 * 256); |
||
113 | s->encbuffer = av_mallocz(s->image_width * s->image_height * 3); |
||
114 | |||
115 | if (!s->tmpblock || !s->encbuffer) { |
||
116 | av_log(avctx, AV_LOG_ERROR, "Memory allocation failed.\n"); |
||
117 | return AVERROR(ENOMEM); |
||
118 | } |
||
119 | |||
120 | return 0; |
||
121 | } |
||
122 | |||
123 | |||
124 | static int encode_bitstream(FlashSVContext *s, AVFrame *p, uint8_t *buf, |
||
125 | int buf_size, int block_width, int block_height, |
||
126 | uint8_t *previous_frame, int *I_frame) |
||
127 | { |
||
128 | |||
129 | PutBitContext pb; |
||
130 | int h_blocks, v_blocks, h_part, v_part, i, j; |
||
131 | int buf_pos, res; |
||
132 | int pred_blocks = 0; |
||
133 | |||
134 | init_put_bits(&pb, buf, buf_size * 8); |
||
135 | |||
136 | put_bits(&pb, 4, block_width / 16 - 1); |
||
137 | put_bits(&pb, 12, s->image_width); |
||
138 | put_bits(&pb, 4, block_height / 16 - 1); |
||
139 | put_bits(&pb, 12, s->image_height); |
||
140 | flush_put_bits(&pb); |
||
141 | buf_pos = 4; |
||
142 | |||
143 | h_blocks = s->image_width / block_width; |
||
144 | h_part = s->image_width % block_width; |
||
145 | v_blocks = s->image_height / block_height; |
||
146 | v_part = s->image_height % block_height; |
||
147 | |||
148 | /* loop over all block columns */ |
||
149 | for (j = 0; j < v_blocks + (v_part ? 1 : 0); j++) { |
||
150 | |||
151 | int y_pos = j * block_height; // vertical position in frame |
||
152 | int cur_blk_height = (j < v_blocks) ? block_height : v_part; |
||
153 | |||
154 | /* loop over all block rows */ |
||
155 | for (i = 0; i < h_blocks + (h_part ? 1 : 0); i++) { |
||
156 | int x_pos = i * block_width; // horizontal position in frame |
||
157 | int cur_blk_width = (i < h_blocks) ? block_width : h_part; |
||
158 | int ret = Z_OK; |
||
159 | uint8_t *ptr = buf + buf_pos; |
||
160 | |||
161 | /* copy the block to the temp buffer before compression |
||
162 | * (if it differs from the previous frame's block) */ |
||
163 | res = copy_region_enc(p->data[0], s->tmpblock, |
||
164 | s->image_height - (y_pos + cur_blk_height + 1), |
||
165 | x_pos, cur_blk_height, cur_blk_width, |
||
166 | p->linesize[0], previous_frame); |
||
167 | |||
168 | if (res || *I_frame) { |
||
169 | unsigned long zsize = 3 * block_width * block_height; |
||
170 | ret = compress2(ptr + 2, &zsize, s->tmpblock, |
||
171 | 3 * cur_blk_width * cur_blk_height, 9); |
||
172 | |||
173 | //ret = deflateReset(&s->zstream); |
||
174 | if (ret != Z_OK) |
||
175 | av_log(s->avctx, AV_LOG_ERROR, |
||
176 | "error while compressing block %dx%d\n", i, j); |
||
177 | |||
178 | bytestream_put_be16(&ptr, zsize); |
||
179 | buf_pos += zsize + 2; |
||
180 | av_dlog(s->avctx, "buf_pos = %d\n", buf_pos); |
||
181 | } else { |
||
182 | pred_blocks++; |
||
183 | bytestream_put_be16(&ptr, 0); |
||
184 | buf_pos += 2; |
||
185 | } |
||
186 | } |
||
187 | } |
||
188 | |||
189 | if (pred_blocks) |
||
190 | *I_frame = 0; |
||
191 | else |
||
192 | *I_frame = 1; |
||
193 | |||
194 | return buf_pos; |
||
195 | } |
||
196 | |||
197 | |||
198 | static int flashsv_encode_frame(AVCodecContext *avctx, AVPacket *pkt, |
||
199 | const AVFrame *pict, int *got_packet) |
||
200 | { |
||
201 | FlashSVContext * const s = avctx->priv_data; |
||
202 | AVFrame * const p = &s->frame; |
||
203 | uint8_t *pfptr; |
||
204 | int res; |
||
205 | int I_frame = 0; |
||
206 | int opt_w = 4, opt_h = 4; |
||
207 | |||
208 | *p = *pict; |
||
209 | |||
210 | /* First frame needs to be a keyframe */ |
||
211 | if (avctx->frame_number == 0) { |
||
212 | s->previous_frame = av_mallocz(FFABS(p->linesize[0]) * s->image_height); |
||
213 | if (!s->previous_frame) { |
||
214 | av_log(avctx, AV_LOG_ERROR, "Memory allocation failed.\n"); |
||
215 | return AVERROR(ENOMEM); |
||
216 | } |
||
217 | I_frame = 1; |
||
218 | } |
||
219 | |||
220 | if (p->linesize[0] < 0) |
||
221 | pfptr = s->previous_frame - (s->image_height - 1) * p->linesize[0]; |
||
222 | else |
||
223 | pfptr = s->previous_frame; |
||
224 | |||
225 | /* Check the placement of keyframes */ |
||
226 | if (avctx->gop_size > 0 && |
||
227 | avctx->frame_number >= s->last_key_frame + avctx->gop_size) { |
||
228 | I_frame = 1; |
||
229 | } |
||
230 | |||
231 | if ((res = ff_alloc_packet2(avctx, pkt, s->image_width * s->image_height * 3)) < 0) |
||
232 | return res; |
||
233 | |||
234 | pkt->size = encode_bitstream(s, p, pkt->data, pkt->size, opt_w * 16, opt_h * 16, |
||
235 | pfptr, &I_frame); |
||
236 | |||
237 | //save the current frame |
||
238 | if (p->linesize[0] > 0) |
||
239 | memcpy(s->previous_frame, p->data[0], s->image_height * p->linesize[0]); |
||
240 | else |
||
241 | memcpy(s->previous_frame, |
||
242 | p->data[0] + p->linesize[0] * (s->image_height - 1), |
||
243 | s->image_height * FFABS(p->linesize[0])); |
||
244 | |||
245 | //mark the frame type so the muxer can mux it correctly |
||
246 | if (I_frame) { |
||
247 | p->pict_type = AV_PICTURE_TYPE_I; |
||
248 | p->key_frame = 1; |
||
249 | s->last_key_frame = avctx->frame_number; |
||
250 | av_dlog(avctx, "Inserting keyframe at frame %d\n", avctx->frame_number); |
||
251 | } else { |
||
252 | p->pict_type = AV_PICTURE_TYPE_P; |
||
253 | p->key_frame = 0; |
||
254 | } |
||
255 | |||
256 | avctx->coded_frame = p; |
||
257 | |||
258 | if (p->key_frame) |
||
259 | pkt->flags |= AV_PKT_FLAG_KEY; |
||
260 | *got_packet = 1; |
||
261 | |||
262 | return 0; |
||
263 | } |
||
264 | |||
265 | static av_cold int flashsv_encode_end(AVCodecContext *avctx) |
||
266 | { |
||
267 | FlashSVContext *s = avctx->priv_data; |
||
268 | |||
269 | deflateEnd(&s->zstream); |
||
270 | |||
271 | av_free(s->encbuffer); |
||
272 | av_free(s->previous_frame); |
||
273 | av_free(s->tmpblock); |
||
274 | |||
275 | return 0; |
||
276 | } |
||
277 | |||
278 | AVCodec ff_flashsv_encoder = { |
||
279 | .name = "flashsv", |
||
280 | .long_name = NULL_IF_CONFIG_SMALL("Flash Screen Video"), |
||
281 | .type = AVMEDIA_TYPE_VIDEO, |
||
282 | .id = AV_CODEC_ID_FLASHSV, |
||
283 | .priv_data_size = sizeof(FlashSVContext), |
||
284 | .init = flashsv_encode_init, |
||
285 | .encode2 = flashsv_encode_frame, |
||
286 | .close = flashsv_encode_end, |
||
287 | .pix_fmts = (const enum AVPixelFormat[]){ AV_PIX_FMT_BGR24, AV_PIX_FMT_NONE }, |
||
288 | };>>>>>>> |