00001 
00002 
00003 
00004 
00005 
00006 
00007 
00008 
00009 
00010 
00011 
00012 
00013 
00014 
00015 
00016 
00017 
00018 
00019 
00020 
00021 
00022 
00023 
00024 
00036 
00037 
00038 
00039 
00040 
00041 
00042 
00043 
00044 
00045 
00046 
00047 #include <stdio.h>
00048 #include <stdlib.h>
00049 #include <zlib.h>
00050 
00051 #include "avcodec.h"
00052 #include "internal.h"
00053 #include "put_bits.h"
00054 #include "bytestream.h"
00055 
00056 
00057 typedef struct FlashSVContext {
00058     AVCodecContext *avctx;
00059     uint8_t        *previous_frame;
00060     AVFrame         frame;
00061     int             image_width, image_height;
00062     int             block_width, block_height;
00063     uint8_t        *tmpblock;
00064     uint8_t        *encbuffer;
00065     int             block_size;
00066     z_stream        zstream;
00067     int             last_key_frame;
00068 } FlashSVContext;
00069 
00070 static int copy_region_enc(uint8_t *sptr, uint8_t *dptr, int dx, int dy,
00071                            int h, int w, int stride, uint8_t *pfptr)
00072 {
00073     int i, j;
00074     uint8_t *nsptr;
00075     uint8_t *npfptr;
00076     int diff = 0;
00077 
00078     for (i = dx + h; i > dx; i--) {
00079         nsptr  = sptr  + i * stride + dy * 3;
00080         npfptr = pfptr + i * stride + dy * 3;
00081         for (j = 0; j < w * 3; j++) {
00082             diff    |= npfptr[j] ^ nsptr[j];
00083             dptr[j]  = nsptr[j];
00084         }
00085         dptr += w * 3;
00086     }
00087     if (diff)
00088         return 1;
00089     return 0;
00090 }
00091 
00092 static av_cold int flashsv_encode_init(AVCodecContext *avctx)
00093 {
00094     FlashSVContext *s = avctx->priv_data;
00095 
00096     s->avctx = avctx;
00097 
00098     if (avctx->width > 4095 || avctx->height > 4095) {
00099         av_log(avctx, AV_LOG_ERROR,
00100                "Input dimensions too large, input must be max 4096x4096 !\n");
00101         return AVERROR_INVALIDDATA;
00102     }
00103 
00104     
00105     memset(&s->zstream, 0, sizeof(z_stream));
00106 
00107     s->last_key_frame = 0;
00108 
00109     s->image_width  = avctx->width;
00110     s->image_height = avctx->height;
00111 
00112     s->tmpblock  = av_mallocz(3 * 256 * 256);
00113     s->encbuffer = av_mallocz(s->image_width * s->image_height * 3);
00114 
00115     if (!s->tmpblock || !s->encbuffer) {
00116         av_log(avctx, AV_LOG_ERROR, "Memory allocation failed.\n");
00117         return AVERROR(ENOMEM);
00118     }
00119 
00120     return 0;
00121 }
00122 
00123 
00124 static int encode_bitstream(FlashSVContext *s, AVFrame *p, uint8_t *buf,
00125                             int buf_size, int block_width, int block_height,
00126                             uint8_t *previous_frame, int *I_frame)
00127 {
00128 
00129     PutBitContext pb;
00130     int h_blocks, v_blocks, h_part, v_part, i, j;
00131     int buf_pos, res;
00132     int pred_blocks = 0;
00133 
00134     init_put_bits(&pb, buf, buf_size * 8);
00135 
00136     put_bits(&pb,  4, block_width / 16 - 1);
00137     put_bits(&pb, 12, s->image_width);
00138     put_bits(&pb,  4, block_height / 16 - 1);
00139     put_bits(&pb, 12, s->image_height);
00140     flush_put_bits(&pb);
00141     buf_pos = 4;
00142 
00143     h_blocks = s->image_width  / block_width;
00144     h_part   = s->image_width  % block_width;
00145     v_blocks = s->image_height / block_height;
00146     v_part   = s->image_height % block_height;
00147 
00148     
00149     for (j = 0; j < v_blocks + (v_part ? 1 : 0); j++) {
00150 
00151         int y_pos = j * block_height; 
00152         int cur_blk_height = (j < v_blocks) ? block_height : v_part;
00153 
00154         
00155         for (i = 0; i < h_blocks + (h_part ? 1 : 0); i++) {
00156             int x_pos = i * block_width; 
00157             int cur_blk_width = (i < h_blocks) ? block_width : h_part;
00158             int ret = Z_OK;
00159             uint8_t *ptr = buf + buf_pos;
00160 
00161             
00162 
00163             res = copy_region_enc(p->data[0], s->tmpblock,
00164                                   s->image_height - (y_pos + cur_blk_height + 1),
00165                                   x_pos, cur_blk_height, cur_blk_width,
00166                                   p->linesize[0], previous_frame);
00167 
00168             if (res || *I_frame) {
00169                 unsigned long zsize = 3 * block_width * block_height;
00170                 ret = compress2(ptr + 2, &zsize, s->tmpblock,
00171                                 3 * cur_blk_width * cur_blk_height, 9);
00172 
00173                 
00174                 if (ret != Z_OK)
00175                     av_log(s->avctx, AV_LOG_ERROR,
00176                            "error while compressing block %dx%d\n", i, j);
00177 
00178                 bytestream_put_be16(&ptr, zsize);
00179                 buf_pos += zsize + 2;
00180                 av_dlog(s->avctx, "buf_pos = %d\n", buf_pos);
00181             } else {
00182                 pred_blocks++;
00183                 bytestream_put_be16(&ptr, 0);
00184                 buf_pos += 2;
00185             }
00186         }
00187     }
00188 
00189     if (pred_blocks)
00190         *I_frame = 0;
00191     else
00192         *I_frame = 1;
00193 
00194     return buf_pos;
00195 }
00196 
00197 
00198 static int flashsv_encode_frame(AVCodecContext *avctx, AVPacket *pkt,
00199                                 const AVFrame *pict, int *got_packet)
00200 {
00201     FlashSVContext * const s = avctx->priv_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     
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     
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 ((res = ff_alloc_packet2(avctx, pkt, s->image_width * s->image_height * 3)) < 0)
00232         return res;
00233 
00234     pkt->size = encode_bitstream(s, p, pkt->data, pkt->size, opt_w * 16, opt_h * 16,
00235                                  pfptr, &I_frame);
00236 
00237     
00238     if (p->linesize[0] > 0)
00239         memcpy(s->previous_frame, p->data[0], s->image_height * p->linesize[0]);
00240     else
00241         memcpy(s->previous_frame,
00242                p->data[0] + p->linesize[0] * (s->image_height - 1),
00243                s->image_height * FFABS(p->linesize[0]));
00244 
00245     
00246     if (I_frame) {
00247         p->pict_type      = AV_PICTURE_TYPE_I;
00248         p->key_frame      = 1;
00249         s->last_key_frame = avctx->frame_number;
00250         av_dlog(avctx, "Inserting keyframe at frame %d\n", avctx->frame_number);
00251     } else {
00252         p->pict_type = AV_PICTURE_TYPE_P;
00253         p->key_frame = 0;
00254     }
00255 
00256     avctx->coded_frame = p;
00257 
00258     if (p->key_frame)
00259         pkt->flags |= AV_PKT_FLAG_KEY;
00260     *got_packet = 1;
00261 
00262     return 0;
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             = AV_CODEC_ID_FLASHSV,
00282     .priv_data_size = sizeof(FlashSVContext),
00283     .init           = flashsv_encode_init,
00284     .encode2        = 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 };