X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=libavcodec%2Froqvideoenc.c;h=192f1eb6a39c3749458b0c873b83c150c3f3762e;hb=0e02b381b4850bbc5b8e1ce6e17447968a2ae8b5;hp=a5622cd6fee2058be9f8e463818d1a0e0759fcf8;hpb=199436b952c198e14d53a389438e232ef60f1982;p=ffmpeg diff --git a/libavcodec/roqvideoenc.c b/libavcodec/roqvideoenc.c index a5622cd6fee..192f1eb6a39 100644 --- a/libavcodec/roqvideoenc.c +++ b/libavcodec/roqvideoenc.c @@ -5,27 +5,27 @@ * Copyright (C) 2004-2007 Eric Lasota * Based on RoQ specs (C) 2001 Tim Ferguson * - * This file is part of FFmpeg. + * This file is part of Libav. * - * FFmpeg is free software; you can redistribute it and/or + * Libav is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * - * FFmpeg is distributed in the hope that it will be useful, + * Libav is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public - * License along with FFmpeg; if not, write to the Free Software + * License along with Libav; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /** - * @file roqvideoenc.c + * @file * id RoQ encoder by Vitor. Based on the Switchblade3 library and the - * Switchblade3 FFmpeg glue by Eric Lasota. + * Switchblade3 Libav glue by Eric Lasota. */ /* @@ -55,11 +55,11 @@ */ #include -#include #include "roqvideo.h" #include "bytestream.h" #include "elbg.h" +#include "internal.h" #include "mathops.h" #define CHROMA_BIAS 1 @@ -113,7 +113,7 @@ static inline int square(int x) return x*x; } -static inline int eval_sse(uint8_t *a, uint8_t *b, int count) +static inline int eval_sse(const uint8_t *a, const uint8_t *b, int count) { int diff=0; @@ -125,8 +125,8 @@ static inline int eval_sse(uint8_t *a, uint8_t *b, int count) // FIXME Could use DSPContext.sse, but it is not so speed critical (used // just for motion estimation). -static int block_sse(uint8_t **buf1, uint8_t **buf2, int x1, int y1, int x2, - int y2, int *stride1, int *stride2, int size) +static int block_sse(uint8_t * const *buf1, uint8_t * const *buf2, int x1, int y1, + int x2, int y2, const int *stride1, const int *stride2, int size) { int i, k; int sse=0; @@ -166,7 +166,7 @@ static int eval_motion_dist(RoqContext *enc, int x, int y, motion_vect vect, } /** - * Returns distortion between two macroblocks + * @return distortion between two macroblocks */ static inline int squared_diff_macroblock(uint8_t a[], uint8_t b[], int size) { @@ -220,7 +220,7 @@ typedef struct /** * Temporary vars */ -typedef struct +typedef struct RoqTempData { CelEvaluation *cel_evals; @@ -241,7 +241,7 @@ typedef struct } RoqTempdata; /** - * Initializes cel evaluators and sets their source coordinates + * Initialize cel evaluators and set their source coordinates */ static void create_cel_evals(RoqContext *enc, RoqTempdata *tempData) { @@ -261,7 +261,7 @@ static void create_cel_evals(RoqContext *enc, RoqTempdata *tempData) /** * Get macroblocks from parts of the image */ -static void get_frame_mb(AVFrame *frame, int x, int y, uint8_t mb[], int dim) +static void get_frame_mb(const AVFrame *frame, int x, int y, uint8_t mb[], int dim) { int i, j, cp; @@ -394,7 +394,7 @@ static void motion_search(RoqContext *enc, int blocksize) } /** - * Gets distortion for all options available to a subcel + * Get distortion for all options available to a subcel */ static void gather_data_for_subcel(SubcelEvaluation *subcel, int x, int y, RoqContext *enc, RoqTempdata *tempData) @@ -458,7 +458,7 @@ static void gather_data_for_subcel(SubcelEvaluation *subcel, int x, } /** - * Gets distortion for all options available to a cel + * Get distortion for all options available to a cel */ static void gather_data_for_cel(CelEvaluation *cel, RoqContext *enc, RoqTempdata *tempData) @@ -755,8 +755,8 @@ static void reconstruct_and_encode_image(RoqContext *enc, RoqTempdata *tempData, /** * Create a single YUV cell from a 2x2 section of the image */ -static inline void frame_block_to_cell(uint8_t *block, uint8_t **data, - int top, int left, int *stride) +static inline void frame_block_to_cell(uint8_t *block, uint8_t * const *data, + int top, int left, const int *stride) { int i, j, u=0, v=0; @@ -774,9 +774,9 @@ static inline void frame_block_to_cell(uint8_t *block, uint8_t **data, } /** - * Creates YUV clusters for the entire image + * Create YUV clusters for the entire image */ -static void create_clusters(AVFrame *frame, int w, int h, uint8_t *yuvClusters) +static void create_clusters(const AVFrame *frame, int w, int h, uint8_t *yuvClusters) { int i, j, k, l; @@ -796,7 +796,7 @@ static void generate_codebook(RoqContext *enc, RoqTempdata *tempdata, { int i, j, k; int c_size = size*size/4; - int *buf = points; + int *buf; int *codebook = av_malloc(6*c_size*cbsize*sizeof(int)); int *closest_cb; @@ -881,14 +881,14 @@ static void generate_new_codebooks(RoqContext *enc, RoqTempdata *tempData) static void roq_encode_video(RoqContext *enc) { - RoqTempdata tempData; + RoqTempdata *tempData = enc->tmpData; int i; - memset(&tempData, 0, sizeof(tempData)); + memset(tempData, 0, sizeof(*tempData)); - create_cel_evals(enc, &tempData); + create_cel_evals(enc, tempData); - generate_new_codebooks(enc, &tempData); + generate_new_codebooks(enc, tempData); if (enc->framesSinceKeyframe >= 1) { motion_search(enc, 8); @@ -897,19 +897,30 @@ static void roq_encode_video(RoqContext *enc) retry_encode: for (i=0; iwidth*enc->height/64; i++) - gather_data_for_cel(tempData.cel_evals + i, enc, &tempData); + gather_data_for_cel(tempData->cel_evals + i, enc, tempData); + + /* Quake 3 can't handle chunks bigger than 65535 bytes */ + if (tempData->mainChunkSize/8 > 65535) { + av_log(enc->avctx, AV_LOG_ERROR, + "Warning, generated a frame too big (%d > 65535), " + "try using a smaller qscale value.\n", + tempData->mainChunkSize/8); + enc->lambda *= 1.5; + tempData->mainChunkSize = 0; + memset(tempData->used_option, 0, sizeof(tempData->used_option)); + memset(tempData->codebooks.usedCB4, 0, + sizeof(tempData->codebooks.usedCB4)); + memset(tempData->codebooks.usedCB2, 0, + sizeof(tempData->codebooks.usedCB2)); - /* Quake 3 can't handle chunks bigger than 65536 bytes */ - if (tempData.mainChunkSize/8 > 65536) { - enc->lambda *= .8; goto retry_encode; } - remap_codebooks(enc, &tempData); + remap_codebooks(enc, tempData); - write_codebooks(enc, &tempData); + write_codebooks(enc, tempData); - reconstruct_and_encode_image(enc, &tempData, enc->width, enc->height, + reconstruct_and_encode_image(enc, tempData, enc->width, enc->height, enc->width*enc->height/64); enc->avctx->coded_frame = enc->current_frame; @@ -919,8 +930,8 @@ static void roq_encode_video(RoqContext *enc) FFSWAP(motion_vect *, enc->last_motion4, enc->this_motion4); FFSWAP(motion_vect *, enc->last_motion8, enc->this_motion8); - av_free(tempData.cel_evals); - av_free(tempData.closest_cb2); + av_free(tempData->cel_evals); + av_free(tempData->closest_cb2); enc->framesSinceKeyframe++; } @@ -929,7 +940,7 @@ static int roq_encode_init(AVCodecContext *avctx) { RoqContext *enc = avctx->priv_data; - av_init_random(1, &enc->randctx); + av_lfg_init(&enc->randctx, 1); enc->framesSinceKeyframe = 0; if ((avctx->width & 0xf) || (avctx->height & 0xf)) { @@ -940,12 +951,6 @@ static int roq_encode_init(AVCodecContext *avctx) if (((avctx->width)&(avctx->width-1))||((avctx->height)&(avctx->height-1))) av_log(avctx, AV_LOG_ERROR, "Warning: dimensions not power of two\n"); - if (avcodec_check_dimensions(avctx, avctx->width, avctx->height)) { - av_log(avctx, AV_LOG_ERROR, "Invalid dimensions (%dx%d)\n", - avctx->width, avctx->height); - return -1; - } - enc->width = avctx->width; enc->height = avctx->height; @@ -955,6 +960,8 @@ static int roq_encode_init(AVCodecContext *avctx) enc->last_frame = &enc->frames[0]; enc->current_frame = &enc->frames[1]; + enc->tmpData = av_malloc(sizeof(RoqTempdata)); + enc->this_motion4 = av_mallocz((enc->width*enc->height/16)*sizeof(motion_vect)); @@ -995,13 +1002,12 @@ static void roq_write_video_info_chunk(RoqContext *enc) bytestream_put_byte(&enc->out_buf, 0x00); } -static int roq_encode_frame(AVCodecContext *avctx, unsigned char *buf, int buf_size, void *data) +static int roq_encode_frame(AVCodecContext *avctx, AVPacket *pkt, + const AVFrame *frame, int *got_packet) { RoqContext *enc = avctx->priv_data; - AVFrame *frame= data; - uint8_t *buf_start = buf; + int size, ret; - enc->out_buf = buf; enc->avctx = avctx; enc->frame_to_enc = frame; @@ -1013,10 +1019,12 @@ static int roq_encode_frame(AVCodecContext *avctx, unsigned char *buf, int buf_s /* 138 bits max per 8x8 block + * 256 codebooks*(6 bytes 2x2 + 4 bytes 4x4) + 8 bytes frame header */ - if (((enc->width*enc->height/64)*138+7)/8 + 256*(6+4) + 8 > buf_size) { - av_log(avctx, AV_LOG_ERROR, " RoQ: Output buffer too small!\n"); - return -1; + size = ((enc->width * enc->height / 64) * 138 + 7) / 8 + 256 * (6 + 4) + 8; + if ((ret = ff_alloc_packet(pkt, size)) < 0) { + av_log(avctx, AV_LOG_ERROR, "Error getting output packet with size %d.\n", size); + return ret; } + enc->out_buf = pkt->data; /* Check for I frame */ if (enc->framesSinceKeyframe == avctx->gop_size) @@ -1025,8 +1033,8 @@ static int roq_encode_frame(AVCodecContext *avctx, unsigned char *buf, int buf_s if (enc->first_frame) { /* Alloc memory for the reconstruction data (we must know the stride for that) */ - if (avctx->get_buffer(avctx, enc->current_frame) || - avctx->get_buffer(avctx, enc->last_frame)) { + if (ff_get_buffer(avctx, enc->current_frame) || + ff_get_buffer(avctx, enc->last_frame)) { av_log(avctx, AV_LOG_ERROR, " RoQ: get_buffer() failed\n"); return -1; } @@ -1040,7 +1048,12 @@ static int roq_encode_frame(AVCodecContext *avctx, unsigned char *buf, int buf_s /* Encode the actual frame */ roq_encode_video(enc); - return enc->out_buf - buf_start; + pkt->size = enc->out_buf - pkt->data; + if (enc->framesSinceKeyframe == 1) + pkt->flags |= AV_PKT_FLAG_KEY; + *got_packet = 1; + + return 0; } static int roq_encode_end(AVCodecContext *avctx) @@ -1050,6 +1063,7 @@ static int roq_encode_end(AVCodecContext *avctx) avctx->release_buffer(avctx, enc->last_frame); avctx->release_buffer(avctx, enc->current_frame); + av_free(enc->tmpData); av_free(enc->this_motion4); av_free(enc->last_motion4); av_free(enc->this_motion8); @@ -1058,16 +1072,16 @@ static int roq_encode_end(AVCodecContext *avctx) return 0; } -AVCodec roq_encoder = -{ - "roqvideo", - CODEC_TYPE_VIDEO, - CODEC_ID_ROQ, - sizeof(RoqContext), - roq_encode_init, - roq_encode_frame, - roq_encode_end, - .supported_framerates = (AVRational[]){{30,1}, {0,0}}, - .pix_fmts = (enum PixelFormat[]){PIX_FMT_YUV444P, PIX_FMT_NONE}, - .long_name = NULL_IF_CONFIG_SMALL("id RoQ video"), +AVCodec ff_roq_encoder = { + .name = "roqvideo", + .type = AVMEDIA_TYPE_VIDEO, + .id = AV_CODEC_ID_ROQ, + .priv_data_size = sizeof(RoqContext), + .init = roq_encode_init, + .encode2 = roq_encode_frame, + .close = roq_encode_end, + .supported_framerates = (const AVRational[]){ {30,1}, {0,0} }, + .pix_fmts = (const enum AVPixelFormat[]){ AV_PIX_FMT_YUV444P, + AV_PIX_FMT_NONE }, + .long_name = NULL_IF_CONFIG_SMALL("id RoQ video"), };