00001 /* 00002 * Flash Screen Video encoder 00003 * Copyright (C) 2004 Alex Beregszaszi 00004 * Copyright (C) 2006 Benjamin Larsson 00005 * 00006 * This file is part of FFmpeg. 00007 * 00008 * FFmpeg is free software; you can redistribute it and/or 00009 * modify it under the terms of the GNU Lesser General Public 00010 * License as published by the Free Software Foundation; either 00011 * version 2.1 of the License, or (at your option) any later version. 00012 * 00013 * FFmpeg is distributed in the hope that it will be useful, 00014 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00015 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00016 * Lesser General Public License for more details. 00017 * 00018 * You should have received a copy of the GNU Lesser General Public 00019 * License along with FFmpeg; if not, write to the Free Software 00020 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 00021 */ 00022 00023 /* Encoding development sponsored by http://fh-campuswien.ac.at */ 00024 00036 /* 00037 * Encoding ideas: A basic encoder would just use a fixed block size. 00038 * Block sizes can be multiples of 16, from 16 to 256. The blocks don't 00039 * have to be quadratic. A brute force search with a set of different 00040 * block sizes should give a better result than to just use a fixed size. 00041 * 00042 * TODO: 00043 * Don't reencode the frame in brute force mode if the frame is a dupe. 00044 * Speed up. Make the difference check faster. 00045 */ 00046 00047 #include <stdio.h> 00048 #include <stdlib.h> 00049 #include <zlib.h> 00050 00051 #include "avcodec.h" 00052 #include "put_bits.h" 00053 #include "bytestream.h" 00054 00055 00056 typedef struct FlashSVContext { 00057 AVCodecContext *avctx; 00058 uint8_t *previous_frame; 00059 AVFrame frame; 00060 int image_width, image_height; 00061 int block_width, block_height; 00062 uint8_t *tmpblock; 00063 uint8_t *encbuffer; 00064 int block_size; 00065 z_stream zstream; 00066 int last_key_frame; 00067 } FlashSVContext; 00068 00069 static int copy_region_enc(uint8_t *sptr, uint8_t *dptr, int dx, int dy, 00070 int h, int w, int stride, uint8_t *pfptr) 00071 { 00072 int i, j; 00073 uint8_t *nsptr; 00074 uint8_t *npfptr; 00075 int diff = 0; 00076 00077 for (i = dx + h; i > dx; i--) { 00078 nsptr = sptr + i * stride + dy * 3; 00079 npfptr = pfptr + i * stride + dy * 3; 00080 for (j = 0; j < w * 3; j++) { 00081 diff |= npfptr[j] ^ nsptr[j]; 00082 dptr[j] = nsptr[j]; 00083 } 00084 dptr += w * 3; 00085 } 00086 if (diff) 00087 return 1; 00088 return 0; 00089 } 00090 00091 static av_cold int flashsv_encode_init(AVCodecContext *avctx) 00092 { 00093 FlashSVContext *s = avctx->priv_data; 00094 00095 s->avctx = avctx; 00096 00097 if (avctx->width > 4095 || avctx->height > 4095) { 00098 av_log(avctx, AV_LOG_ERROR, 00099 "Input dimensions too large, input must be max 4096x4096 !\n"); 00100 return AVERROR_INVALIDDATA; 00101 } 00102 00103 // Needed if zlib unused or init aborted before deflateInit 00104 memset(&s->zstream, 0, sizeof(z_stream)); 00105 00106 s->last_key_frame = 0; 00107 00108 s->image_width = avctx->width; 00109 s->image_height = avctx->height; 00110 00111 s->tmpblock = av_mallocz(3 * 256 * 256); 00112 s->encbuffer = av_mallocz(s->image_width * s->image_height * 3); 00113 00114 if (!s->tmpblock || !s->encbuffer) { 00115 av_log(avctx, AV_LOG_ERROR, "Memory allocation failed.\n"); 00116 return AVERROR(ENOMEM); 00117 } 00118 00119 return 0; 00120 } 00121 00122 00123 static int encode_bitstream(FlashSVContext *s, AVFrame *p, uint8_t *buf, 00124 int buf_size, int block_width, int block_height, 00125 uint8_t *previous_frame, int *I_frame) 00126 { 00127 00128 PutBitContext pb; 00129 int h_blocks, v_blocks, h_part, v_part, i, j; 00130 int buf_pos, res; 00131 int pred_blocks = 0; 00132 00133 init_put_bits(&pb, buf, buf_size * 8); 00134 00135 put_bits(&pb, 4, block_width / 16 - 1); 00136 put_bits(&pb, 12, s->image_width); 00137 put_bits(&pb, 4, block_height / 16 - 1); 00138 put_bits(&pb, 12, s->image_height); 00139 flush_put_bits(&pb); 00140 buf_pos = 4; 00141 00142 h_blocks = s->image_width / block_width; 00143 h_part = s->image_width % block_width; 00144 v_blocks = s->image_height / block_height; 00145 v_part = s->image_height % block_height; 00146 00147 /* loop over all block columns */ 00148 for (j = 0; j < v_blocks + (v_part ? 1 : 0); j++) { 00149 00150 int y_pos = j * block_height; // vertical position in frame 00151 int cur_blk_height = (j < v_blocks) ? block_height : v_part; 00152 00153 /* loop over all block rows */ 00154 for (i = 0; i < h_blocks + (h_part ? 1 : 0); i++) { 00155 int x_pos = i * block_width; // horizontal position in frame 00156 int cur_blk_width = (i < h_blocks) ? block_width : h_part; 00157 int ret = Z_OK; 00158 uint8_t *ptr = buf + buf_pos; 00159 00160 /* copy the block to the temp buffer before compression 00161 * (if it differs from the previous frame's block) */ 00162 res = copy_region_enc(p->data[0], s->tmpblock, 00163 s->image_height - (y_pos + cur_blk_height + 1), 00164 x_pos, cur_blk_height, cur_blk_width, 00165 p->linesize[0], previous_frame); 00166 00167 if (res || *I_frame) { 00168 unsigned long zsize = 3 * block_width * block_height; 00169 ret = compress2(ptr + 2, &zsize, s->tmpblock, 00170 3 * cur_blk_width * cur_blk_height, 9); 00171 00172 //ret = deflateReset(&s->zstream); 00173 if (ret != Z_OK) 00174 av_log(s->avctx, AV_LOG_ERROR, 00175 "error while compressing block %dx%d\n", i, j); 00176 00177 bytestream_put_be16(&ptr, zsize); 00178 buf_pos += zsize + 2; 00179 av_dlog(s->avctx, "buf_pos = %d\n", buf_pos); 00180 } else { 00181 pred_blocks++; 00182 bytestream_put_be16(&ptr, 0); 00183 buf_pos += 2; 00184 } 00185 } 00186 } 00187 00188 if (pred_blocks) 00189 *I_frame = 0; 00190 else 00191 *I_frame = 1; 00192 00193 return buf_pos; 00194 } 00195 00196 00197 static int flashsv_encode_frame(AVCodecContext *avctx, uint8_t *buf, 00198 int buf_size, void *data) 00199 { 00200 FlashSVContext * const s = avctx->priv_data; 00201 AVFrame *pict = data; 00202 AVFrame * const p = &s->frame; 00203 uint8_t *pfptr; 00204 int res; 00205 int I_frame = 0; 00206 int opt_w = 4, opt_h = 4; 00207 00208 *p = *pict; 00209 00210 /* First frame needs to be a keyframe */ 00211 if (avctx->frame_number == 0) { 00212 s->previous_frame = av_mallocz(FFABS(p->linesize[0]) * s->image_height); 00213 if (!s->previous_frame) { 00214 av_log(avctx, AV_LOG_ERROR, "Memory allocation failed.\n"); 00215 return AVERROR(ENOMEM); 00216 } 00217 I_frame = 1; 00218 } 00219 00220 if (p->linesize[0] < 0) 00221 pfptr = s->previous_frame - (s->image_height - 1) * p->linesize[0]; 00222 else 00223 pfptr = s->previous_frame; 00224 00225 /* Check the placement of keyframes */ 00226 if (avctx->gop_size > 0 && 00227 avctx->frame_number >= s->last_key_frame + avctx->gop_size) { 00228 I_frame = 1; 00229 } 00230 00231 if (buf_size < s->image_width * s->image_height * 3) { 00232 //Conservative upper bound check for compressed data 00233 av_log(avctx, AV_LOG_ERROR, "buf_size %d < %d\n", 00234 buf_size, s->image_width * s->image_height * 3); 00235 return -1; 00236 } 00237 00238 res = encode_bitstream(s, p, buf, buf_size, opt_w * 16, opt_h * 16, 00239 pfptr, &I_frame); 00240 00241 //save the current frame 00242 if (p->linesize[0] > 0) 00243 memcpy(s->previous_frame, p->data[0], s->image_height * p->linesize[0]); 00244 else 00245 memcpy(s->previous_frame, 00246 p->data[0] + p->linesize[0] * (s->image_height - 1), 00247 s->image_height * FFABS(p->linesize[0])); 00248 00249 //mark the frame type so the muxer can mux it correctly 00250 if (I_frame) { 00251 p->pict_type = AV_PICTURE_TYPE_I; 00252 p->key_frame = 1; 00253 s->last_key_frame = avctx->frame_number; 00254 av_dlog(avctx, "Inserting keyframe at frame %d\n", avctx->frame_number); 00255 } else { 00256 p->pict_type = AV_PICTURE_TYPE_P; 00257 p->key_frame = 0; 00258 } 00259 00260 avctx->coded_frame = p; 00261 00262 return res; 00263 } 00264 00265 static av_cold int flashsv_encode_end(AVCodecContext *avctx) 00266 { 00267 FlashSVContext *s = avctx->priv_data; 00268 00269 deflateEnd(&s->zstream); 00270 00271 av_free(s->encbuffer); 00272 av_free(s->previous_frame); 00273 av_free(s->tmpblock); 00274 00275 return 0; 00276 } 00277 00278 AVCodec ff_flashsv_encoder = { 00279 .name = "flashsv", 00280 .type = AVMEDIA_TYPE_VIDEO, 00281 .id = CODEC_ID_FLASHSV, 00282 .priv_data_size = sizeof(FlashSVContext), 00283 .init = flashsv_encode_init, 00284 .encode = flashsv_encode_frame, 00285 .close = flashsv_encode_end, 00286 .pix_fmts = (const enum PixelFormat[]){PIX_FMT_BGR24, PIX_FMT_NONE}, 00287 .long_name = NULL_IF_CONFIG_SMALL("Flash Screen Video"), 00288 }; 00289