annotate ffmpeg/libavcodec/flashsvenc.c @ 13:844d341cf643 tip

Back up before ISMIR
author Yading Song <yading.song@eecs.qmul.ac.uk>
date Thu, 31 Oct 2013 13:17:06 +0000
parents 6840f77b83aa
children
rev   line source
yading@10 1 /*
yading@10 2 * Flash Screen Video encoder
yading@10 3 * Copyright (C) 2004 Alex Beregszaszi
yading@10 4 * Copyright (C) 2006 Benjamin Larsson
yading@10 5 *
yading@10 6 * This file is part of FFmpeg.
yading@10 7 *
yading@10 8 * FFmpeg is free software; you can redistribute it and/or
yading@10 9 * modify it under the terms of the GNU Lesser General Public
yading@10 10 * License as published by the Free Software Foundation; either
yading@10 11 * version 2.1 of the License, or (at your option) any later version.
yading@10 12 *
yading@10 13 * FFmpeg is distributed in the hope that it will be useful,
yading@10 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
yading@10 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
yading@10 16 * Lesser General Public License for more details.
yading@10 17 *
yading@10 18 * You should have received a copy of the GNU Lesser General Public
yading@10 19 * License along with FFmpeg; if not, write to the Free Software
yading@10 20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
yading@10 21 */
yading@10 22
yading@10 23 /* Encoding development sponsored by http://fh-campuswien.ac.at */
yading@10 24
yading@10 25 /**
yading@10 26 * @file
yading@10 27 * Flash Screen Video encoder
yading@10 28 * @author Alex Beregszaszi
yading@10 29 * @author Benjamin Larsson
yading@10 30 *
yading@10 31 * A description of the bitstream format for Flash Screen Video version 1/2
yading@10 32 * is part of the SWF File Format Specification (version 10), which can be
yading@10 33 * downloaded from http://www.adobe.com/devnet/swf.html.
yading@10 34 */
yading@10 35
yading@10 36 /*
yading@10 37 * Encoding ideas: A basic encoder would just use a fixed block size.
yading@10 38 * Block sizes can be multiples of 16, from 16 to 256. The blocks don't
yading@10 39 * have to be quadratic. A brute force search with a set of different
yading@10 40 * block sizes should give a better result than to just use a fixed size.
yading@10 41 *
yading@10 42 * TODO:
yading@10 43 * Don't reencode the frame in brute force mode if the frame is a dupe.
yading@10 44 * Speed up. Make the difference check faster.
yading@10 45 */
yading@10 46
yading@10 47 #include <stdio.h>
yading@10 48 #include <stdlib.h>
yading@10 49 #include <zlib.h>
yading@10 50
yading@10 51 #include "avcodec.h"
yading@10 52 #include "internal.h"
yading@10 53 #include "put_bits.h"
yading@10 54 #include "bytestream.h"
yading@10 55
yading@10 56
yading@10 57 typedef struct FlashSVContext {
yading@10 58 AVCodecContext *avctx;
yading@10 59 uint8_t *previous_frame;
yading@10 60 AVFrame frame;
yading@10 61 int image_width, image_height;
yading@10 62 int block_width, block_height;
yading@10 63 uint8_t *tmpblock;
yading@10 64 uint8_t *encbuffer;
yading@10 65 int block_size;
yading@10 66 z_stream zstream;
yading@10 67 int last_key_frame;
yading@10 68 } FlashSVContext;
yading@10 69
yading@10 70 static int copy_region_enc(uint8_t *sptr, uint8_t *dptr, int dx, int dy,
yading@10 71 int h, int w, int stride, uint8_t *pfptr)
yading@10 72 {
yading@10 73 int i, j;
yading@10 74 uint8_t *nsptr;
yading@10 75 uint8_t *npfptr;
yading@10 76 int diff = 0;
yading@10 77
yading@10 78 for (i = dx + h; i > dx; i--) {
yading@10 79 nsptr = sptr + i * stride + dy * 3;
yading@10 80 npfptr = pfptr + i * stride + dy * 3;
yading@10 81 for (j = 0; j < w * 3; j++) {
yading@10 82 diff |= npfptr[j] ^ nsptr[j];
yading@10 83 dptr[j] = nsptr[j];
yading@10 84 }
yading@10 85 dptr += w * 3;
yading@10 86 }
yading@10 87 if (diff)
yading@10 88 return 1;
yading@10 89 return 0;
yading@10 90 }
yading@10 91
yading@10 92 static av_cold int flashsv_encode_init(AVCodecContext *avctx)
yading@10 93 {
yading@10 94 FlashSVContext *s = avctx->priv_data;
yading@10 95
yading@10 96 s->avctx = avctx;
yading@10 97
yading@10 98 if (avctx->width > 4095 || avctx->height > 4095) {
yading@10 99 av_log(avctx, AV_LOG_ERROR,
yading@10 100 "Input dimensions too large, input must be max 4096x4096 !\n");
yading@10 101 return AVERROR_INVALIDDATA;
yading@10 102 }
yading@10 103
yading@10 104 // Needed if zlib unused or init aborted before deflateInit
yading@10 105 memset(&s->zstream, 0, sizeof(z_stream));
yading@10 106
yading@10 107 s->last_key_frame = 0;
yading@10 108
yading@10 109 s->image_width = avctx->width;
yading@10 110 s->image_height = avctx->height;
yading@10 111
yading@10 112 s->tmpblock = av_mallocz(3 * 256 * 256);
yading@10 113 s->encbuffer = av_mallocz(s->image_width * s->image_height * 3);
yading@10 114
yading@10 115 if (!s->tmpblock || !s->encbuffer) {
yading@10 116 av_log(avctx, AV_LOG_ERROR, "Memory allocation failed.\n");
yading@10 117 return AVERROR(ENOMEM);
yading@10 118 }
yading@10 119
yading@10 120 return 0;
yading@10 121 }
yading@10 122
yading@10 123
yading@10 124 static int encode_bitstream(FlashSVContext *s, AVFrame *p, uint8_t *buf,
yading@10 125 int buf_size, int block_width, int block_height,
yading@10 126 uint8_t *previous_frame, int *I_frame)
yading@10 127 {
yading@10 128
yading@10 129 PutBitContext pb;
yading@10 130 int h_blocks, v_blocks, h_part, v_part, i, j;
yading@10 131 int buf_pos, res;
yading@10 132 int pred_blocks = 0;
yading@10 133
yading@10 134 init_put_bits(&pb, buf, buf_size * 8);
yading@10 135
yading@10 136 put_bits(&pb, 4, block_width / 16 - 1);
yading@10 137 put_bits(&pb, 12, s->image_width);
yading@10 138 put_bits(&pb, 4, block_height / 16 - 1);
yading@10 139 put_bits(&pb, 12, s->image_height);
yading@10 140 flush_put_bits(&pb);
yading@10 141 buf_pos = 4;
yading@10 142
yading@10 143 h_blocks = s->image_width / block_width;
yading@10 144 h_part = s->image_width % block_width;
yading@10 145 v_blocks = s->image_height / block_height;
yading@10 146 v_part = s->image_height % block_height;
yading@10 147
yading@10 148 /* loop over all block columns */
yading@10 149 for (j = 0; j < v_blocks + (v_part ? 1 : 0); j++) {
yading@10 150
yading@10 151 int y_pos = j * block_height; // vertical position in frame
yading@10 152 int cur_blk_height = (j < v_blocks) ? block_height : v_part;
yading@10 153
yading@10 154 /* loop over all block rows */
yading@10 155 for (i = 0; i < h_blocks + (h_part ? 1 : 0); i++) {
yading@10 156 int x_pos = i * block_width; // horizontal position in frame
yading@10 157 int cur_blk_width = (i < h_blocks) ? block_width : h_part;
yading@10 158 int ret = Z_OK;
yading@10 159 uint8_t *ptr = buf + buf_pos;
yading@10 160
yading@10 161 /* copy the block to the temp buffer before compression
yading@10 162 * (if it differs from the previous frame's block) */
yading@10 163 res = copy_region_enc(p->data[0], s->tmpblock,
yading@10 164 s->image_height - (y_pos + cur_blk_height + 1),
yading@10 165 x_pos, cur_blk_height, cur_blk_width,
yading@10 166 p->linesize[0], previous_frame);
yading@10 167
yading@10 168 if (res || *I_frame) {
yading@10 169 unsigned long zsize = 3 * block_width * block_height;
yading@10 170 ret = compress2(ptr + 2, &zsize, s->tmpblock,
yading@10 171 3 * cur_blk_width * cur_blk_height, 9);
yading@10 172
yading@10 173 //ret = deflateReset(&s->zstream);
yading@10 174 if (ret != Z_OK)
yading@10 175 av_log(s->avctx, AV_LOG_ERROR,
yading@10 176 "error while compressing block %dx%d\n", i, j);
yading@10 177
yading@10 178 bytestream_put_be16(&ptr, zsize);
yading@10 179 buf_pos += zsize + 2;
yading@10 180 av_dlog(s->avctx, "buf_pos = %d\n", buf_pos);
yading@10 181 } else {
yading@10 182 pred_blocks++;
yading@10 183 bytestream_put_be16(&ptr, 0);
yading@10 184 buf_pos += 2;
yading@10 185 }
yading@10 186 }
yading@10 187 }
yading@10 188
yading@10 189 if (pred_blocks)
yading@10 190 *I_frame = 0;
yading@10 191 else
yading@10 192 *I_frame = 1;
yading@10 193
yading@10 194 return buf_pos;
yading@10 195 }
yading@10 196
yading@10 197
yading@10 198 static int flashsv_encode_frame(AVCodecContext *avctx, AVPacket *pkt,
yading@10 199 const AVFrame *pict, int *got_packet)
yading@10 200 {
yading@10 201 FlashSVContext * const s = avctx->priv_data;
yading@10 202 AVFrame * const p = &s->frame;
yading@10 203 uint8_t *pfptr;
yading@10 204 int res;
yading@10 205 int I_frame = 0;
yading@10 206 int opt_w = 4, opt_h = 4;
yading@10 207
yading@10 208 *p = *pict;
yading@10 209
yading@10 210 /* First frame needs to be a keyframe */
yading@10 211 if (avctx->frame_number == 0) {
yading@10 212 s->previous_frame = av_mallocz(FFABS(p->linesize[0]) * s->image_height);
yading@10 213 if (!s->previous_frame) {
yading@10 214 av_log(avctx, AV_LOG_ERROR, "Memory allocation failed.\n");
yading@10 215 return AVERROR(ENOMEM);
yading@10 216 }
yading@10 217 I_frame = 1;
yading@10 218 }
yading@10 219
yading@10 220 if (p->linesize[0] < 0)
yading@10 221 pfptr = s->previous_frame - (s->image_height - 1) * p->linesize[0];
yading@10 222 else
yading@10 223 pfptr = s->previous_frame;
yading@10 224
yading@10 225 /* Check the placement of keyframes */
yading@10 226 if (avctx->gop_size > 0 &&
yading@10 227 avctx->frame_number >= s->last_key_frame + avctx->gop_size) {
yading@10 228 I_frame = 1;
yading@10 229 }
yading@10 230
yading@10 231 if ((res = ff_alloc_packet2(avctx, pkt, s->image_width * s->image_height * 3)) < 0)
yading@10 232 return res;
yading@10 233
yading@10 234 pkt->size = encode_bitstream(s, p, pkt->data, pkt->size, opt_w * 16, opt_h * 16,
yading@10 235 pfptr, &I_frame);
yading@10 236
yading@10 237 //save the current frame
yading@10 238 if (p->linesize[0] > 0)
yading@10 239 memcpy(s->previous_frame, p->data[0], s->image_height * p->linesize[0]);
yading@10 240 else
yading@10 241 memcpy(s->previous_frame,
yading@10 242 p->data[0] + p->linesize[0] * (s->image_height - 1),
yading@10 243 s->image_height * FFABS(p->linesize[0]));
yading@10 244
yading@10 245 //mark the frame type so the muxer can mux it correctly
yading@10 246 if (I_frame) {
yading@10 247 p->pict_type = AV_PICTURE_TYPE_I;
yading@10 248 p->key_frame = 1;
yading@10 249 s->last_key_frame = avctx->frame_number;
yading@10 250 av_dlog(avctx, "Inserting keyframe at frame %d\n", avctx->frame_number);
yading@10 251 } else {
yading@10 252 p->pict_type = AV_PICTURE_TYPE_P;
yading@10 253 p->key_frame = 0;
yading@10 254 }
yading@10 255
yading@10 256 avctx->coded_frame = p;
yading@10 257
yading@10 258 if (p->key_frame)
yading@10 259 pkt->flags |= AV_PKT_FLAG_KEY;
yading@10 260 *got_packet = 1;
yading@10 261
yading@10 262 return 0;
yading@10 263 }
yading@10 264
yading@10 265 static av_cold int flashsv_encode_end(AVCodecContext *avctx)
yading@10 266 {
yading@10 267 FlashSVContext *s = avctx->priv_data;
yading@10 268
yading@10 269 deflateEnd(&s->zstream);
yading@10 270
yading@10 271 av_free(s->encbuffer);
yading@10 272 av_free(s->previous_frame);
yading@10 273 av_free(s->tmpblock);
yading@10 274
yading@10 275 return 0;
yading@10 276 }
yading@10 277
yading@10 278 AVCodec ff_flashsv_encoder = {
yading@10 279 .name = "flashsv",
yading@10 280 .type = AVMEDIA_TYPE_VIDEO,
yading@10 281 .id = AV_CODEC_ID_FLASHSV,
yading@10 282 .priv_data_size = sizeof(FlashSVContext),
yading@10 283 .init = flashsv_encode_init,
yading@10 284 .encode2 = flashsv_encode_frame,
yading@10 285 .close = flashsv_encode_end,
yading@10 286 .pix_fmts = (const enum AVPixelFormat[]){ AV_PIX_FMT_BGR24, AV_PIX_FMT_NONE },
yading@10 287 .long_name = NULL_IF_CONFIG_SMALL("Flash Screen Video"),
yading@10 288 };