annotate ffmpeg/libavcodec/roqvideoenc.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 * RoQ Video Encoder.
yading@10 3 *
yading@10 4 * Copyright (C) 2007 Vitor Sessak <vitor1001@gmail.com>
yading@10 5 * Copyright (C) 2004-2007 Eric Lasota
yading@10 6 * Based on RoQ specs (C) 2001 Tim Ferguson
yading@10 7 *
yading@10 8 * This file is part of FFmpeg.
yading@10 9 *
yading@10 10 * FFmpeg is free software; you can redistribute it and/or
yading@10 11 * modify it under the terms of the GNU Lesser General Public
yading@10 12 * License as published by the Free Software Foundation; either
yading@10 13 * version 2.1 of the License, or (at your option) any later version.
yading@10 14 *
yading@10 15 * FFmpeg is distributed in the hope that it will be useful,
yading@10 16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
yading@10 17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
yading@10 18 * Lesser General Public License for more details.
yading@10 19 *
yading@10 20 * You should have received a copy of the GNU Lesser General Public
yading@10 21 * License along with FFmpeg; if not, write to the Free Software
yading@10 22 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
yading@10 23 */
yading@10 24
yading@10 25 /**
yading@10 26 * @file
yading@10 27 * id RoQ encoder by Vitor. Based on the Switchblade3 library and the
yading@10 28 * Switchblade3 FFmpeg glue by Eric Lasota.
yading@10 29 */
yading@10 30
yading@10 31 /*
yading@10 32 * COSTS:
yading@10 33 * Level 1:
yading@10 34 * SKIP - 2 bits
yading@10 35 * MOTION - 2 + 8 bits
yading@10 36 * CODEBOOK - 2 + 8 bits
yading@10 37 * SUBDIVIDE - 2 + combined subcel cost
yading@10 38 *
yading@10 39 * Level 2:
yading@10 40 * SKIP - 2 bits
yading@10 41 * MOTION - 2 + 8 bits
yading@10 42 * CODEBOOK - 2 + 8 bits
yading@10 43 * SUBDIVIDE - 2 + 4*8 bits
yading@10 44 *
yading@10 45 * Maximum cost: 138 bits per cel
yading@10 46 *
yading@10 47 * Proper evaluation requires LCD fraction comparison, which requires
yading@10 48 * Squared Error (SE) loss * savings increase
yading@10 49 *
yading@10 50 * Maximum savings increase: 136 bits
yading@10 51 * Maximum SE loss without overflow: 31580641
yading@10 52 * Components in 8x8 supercel: 192
yading@10 53 * Maximum SE precision per component: 164482
yading@10 54 * >65025, so no truncation is needed (phew)
yading@10 55 */
yading@10 56
yading@10 57 #include <string.h>
yading@10 58
yading@10 59 #include "roqvideo.h"
yading@10 60 #include "bytestream.h"
yading@10 61 #include "elbg.h"
yading@10 62 #include "internal.h"
yading@10 63 #include "mathops.h"
yading@10 64
yading@10 65 #define CHROMA_BIAS 1
yading@10 66
yading@10 67 /**
yading@10 68 * Maximum number of generated 4x4 codebooks. Can't be 256 to workaround a
yading@10 69 * Quake 3 bug.
yading@10 70 */
yading@10 71 #define MAX_CBS_4x4 255
yading@10 72
yading@10 73 #define MAX_CBS_2x2 256 ///< Maximum number of 2x2 codebooks.
yading@10 74
yading@10 75 /* The cast is useful when multiplying it by INT_MAX */
yading@10 76 #define ROQ_LAMBDA_SCALE ((uint64_t) FF_LAMBDA_SCALE)
yading@10 77
yading@10 78 /* Macroblock support functions */
yading@10 79 static void unpack_roq_cell(roq_cell *cell, uint8_t u[4*3])
yading@10 80 {
yading@10 81 memcpy(u , cell->y, 4);
yading@10 82 memset(u+4, cell->u, 4);
yading@10 83 memset(u+8, cell->v, 4);
yading@10 84 }
yading@10 85
yading@10 86 static void unpack_roq_qcell(uint8_t cb2[], roq_qcell *qcell, uint8_t u[4*4*3])
yading@10 87 {
yading@10 88 int i,cp;
yading@10 89 static const int offsets[4] = {0, 2, 8, 10};
yading@10 90
yading@10 91 for (cp=0; cp<3; cp++)
yading@10 92 for (i=0; i<4; i++) {
yading@10 93 u[4*4*cp + offsets[i] ] = cb2[qcell->idx[i]*2*2*3 + 4*cp ];
yading@10 94 u[4*4*cp + offsets[i]+1] = cb2[qcell->idx[i]*2*2*3 + 4*cp+1];
yading@10 95 u[4*4*cp + offsets[i]+4] = cb2[qcell->idx[i]*2*2*3 + 4*cp+2];
yading@10 96 u[4*4*cp + offsets[i]+5] = cb2[qcell->idx[i]*2*2*3 + 4*cp+3];
yading@10 97 }
yading@10 98 }
yading@10 99
yading@10 100
yading@10 101 static void enlarge_roq_mb4(uint8_t base[3*16], uint8_t u[3*64])
yading@10 102 {
yading@10 103 int x,y,cp;
yading@10 104
yading@10 105 for(cp=0; cp<3; cp++)
yading@10 106 for(y=0; y<8; y++)
yading@10 107 for(x=0; x<8; x++)
yading@10 108 *u++ = base[(y/2)*4 + (x/2) + 16*cp];
yading@10 109 }
yading@10 110
yading@10 111 static inline int square(int x)
yading@10 112 {
yading@10 113 return x*x;
yading@10 114 }
yading@10 115
yading@10 116 static inline int eval_sse(const uint8_t *a, const uint8_t *b, int count)
yading@10 117 {
yading@10 118 int diff=0;
yading@10 119
yading@10 120 while(count--)
yading@10 121 diff += square(*b++ - *a++);
yading@10 122
yading@10 123 return diff;
yading@10 124 }
yading@10 125
yading@10 126 // FIXME Could use DSPContext.sse, but it is not so speed critical (used
yading@10 127 // just for motion estimation).
yading@10 128 static int block_sse(uint8_t * const *buf1, uint8_t * const *buf2, int x1, int y1,
yading@10 129 int x2, int y2, const int *stride1, const int *stride2, int size)
yading@10 130 {
yading@10 131 int i, k;
yading@10 132 int sse=0;
yading@10 133
yading@10 134 for (k=0; k<3; k++) {
yading@10 135 int bias = (k ? CHROMA_BIAS : 4);
yading@10 136 for (i=0; i<size; i++)
yading@10 137 sse += bias*eval_sse(buf1[k] + (y1+i)*stride1[k] + x1,
yading@10 138 buf2[k] + (y2+i)*stride2[k] + x2, size);
yading@10 139 }
yading@10 140
yading@10 141 return sse;
yading@10 142 }
yading@10 143
yading@10 144 static int eval_motion_dist(RoqContext *enc, int x, int y, motion_vect vect,
yading@10 145 int size)
yading@10 146 {
yading@10 147 int mx=vect.d[0];
yading@10 148 int my=vect.d[1];
yading@10 149
yading@10 150 if (mx < -7 || mx > 7)
yading@10 151 return INT_MAX;
yading@10 152
yading@10 153 if (my < -7 || my > 7)
yading@10 154 return INT_MAX;
yading@10 155
yading@10 156 mx += x;
yading@10 157 my += y;
yading@10 158
yading@10 159 if ((unsigned) mx > enc->width-size || (unsigned) my > enc->height-size)
yading@10 160 return INT_MAX;
yading@10 161
yading@10 162 return block_sse(enc->frame_to_enc->data, enc->last_frame->data, x, y,
yading@10 163 mx, my,
yading@10 164 enc->frame_to_enc->linesize, enc->last_frame->linesize,
yading@10 165 size);
yading@10 166 }
yading@10 167
yading@10 168 /**
yading@10 169 * @return distortion between two macroblocks
yading@10 170 */
yading@10 171 static inline int squared_diff_macroblock(uint8_t a[], uint8_t b[], int size)
yading@10 172 {
yading@10 173 int cp, sdiff=0;
yading@10 174
yading@10 175 for(cp=0;cp<3;cp++) {
yading@10 176 int bias = (cp ? CHROMA_BIAS : 4);
yading@10 177 sdiff += bias*eval_sse(a, b, size*size);
yading@10 178 a += size*size;
yading@10 179 b += size*size;
yading@10 180 }
yading@10 181
yading@10 182 return sdiff;
yading@10 183 }
yading@10 184
yading@10 185 typedef struct
yading@10 186 {
yading@10 187 int eval_dist[4];
yading@10 188 int best_bit_use;
yading@10 189 int best_coding;
yading@10 190
yading@10 191 int subCels[4];
yading@10 192 motion_vect motion;
yading@10 193 int cbEntry;
yading@10 194 } SubcelEvaluation;
yading@10 195
yading@10 196 typedef struct
yading@10 197 {
yading@10 198 int eval_dist[4];
yading@10 199 int best_coding;
yading@10 200
yading@10 201 SubcelEvaluation subCels[4];
yading@10 202
yading@10 203 motion_vect motion;
yading@10 204 int cbEntry;
yading@10 205
yading@10 206 int sourceX, sourceY;
yading@10 207 } CelEvaluation;
yading@10 208
yading@10 209 typedef struct
yading@10 210 {
yading@10 211 int numCB4;
yading@10 212 int numCB2;
yading@10 213 int usedCB2[MAX_CBS_2x2];
yading@10 214 int usedCB4[MAX_CBS_4x4];
yading@10 215 uint8_t unpacked_cb2[MAX_CBS_2x2*2*2*3];
yading@10 216 uint8_t unpacked_cb4[MAX_CBS_4x4*4*4*3];
yading@10 217 uint8_t unpacked_cb4_enlarged[MAX_CBS_4x4*8*8*3];
yading@10 218 } RoqCodebooks;
yading@10 219
yading@10 220 /**
yading@10 221 * Temporary vars
yading@10 222 */
yading@10 223 typedef struct RoqTempData
yading@10 224 {
yading@10 225 CelEvaluation *cel_evals;
yading@10 226
yading@10 227 int f2i4[MAX_CBS_4x4];
yading@10 228 int i2f4[MAX_CBS_4x4];
yading@10 229 int f2i2[MAX_CBS_2x2];
yading@10 230 int i2f2[MAX_CBS_2x2];
yading@10 231
yading@10 232 int mainChunkSize;
yading@10 233
yading@10 234 int numCB4;
yading@10 235 int numCB2;
yading@10 236
yading@10 237 RoqCodebooks codebooks;
yading@10 238
yading@10 239 int *closest_cb2;
yading@10 240 int used_option[4];
yading@10 241 } RoqTempdata;
yading@10 242
yading@10 243 /**
yading@10 244 * Initialize cel evaluators and set their source coordinates
yading@10 245 */
yading@10 246 static void create_cel_evals(RoqContext *enc, RoqTempdata *tempData)
yading@10 247 {
yading@10 248 int n=0, x, y, i;
yading@10 249
yading@10 250 tempData->cel_evals = av_malloc(enc->width*enc->height/64 * sizeof(CelEvaluation));
yading@10 251
yading@10 252 /* Map to the ROQ quadtree order */
yading@10 253 for (y=0; y<enc->height; y+=16)
yading@10 254 for (x=0; x<enc->width; x+=16)
yading@10 255 for(i=0; i<4; i++) {
yading@10 256 tempData->cel_evals[n ].sourceX = x + (i&1)*8;
yading@10 257 tempData->cel_evals[n++].sourceY = y + (i&2)*4;
yading@10 258 }
yading@10 259 }
yading@10 260
yading@10 261 /**
yading@10 262 * Get macroblocks from parts of the image
yading@10 263 */
yading@10 264 static void get_frame_mb(const AVFrame *frame, int x, int y, uint8_t mb[], int dim)
yading@10 265 {
yading@10 266 int i, j, cp;
yading@10 267
yading@10 268 for (cp=0; cp<3; cp++) {
yading@10 269 int stride = frame->linesize[cp];
yading@10 270 for (i=0; i<dim; i++)
yading@10 271 for (j=0; j<dim; j++)
yading@10 272 *mb++ = frame->data[cp][(y+i)*stride + x + j];
yading@10 273 }
yading@10 274 }
yading@10 275
yading@10 276 /**
yading@10 277 * Find the codebook with the lowest distortion from an image
yading@10 278 */
yading@10 279 static int index_mb(uint8_t cluster[], uint8_t cb[], int numCB,
yading@10 280 int *outIndex, int dim)
yading@10 281 {
yading@10 282 int i, lDiff = INT_MAX, pick=0;
yading@10 283
yading@10 284 /* Diff against the others */
yading@10 285 for (i=0; i<numCB; i++) {
yading@10 286 int diff = squared_diff_macroblock(cluster, cb + i*dim*dim*3, dim);
yading@10 287 if (diff < lDiff) {
yading@10 288 lDiff = diff;
yading@10 289 pick = i;
yading@10 290 }
yading@10 291 }
yading@10 292
yading@10 293 *outIndex = pick;
yading@10 294 return lDiff;
yading@10 295 }
yading@10 296
yading@10 297 #define EVAL_MOTION(MOTION) \
yading@10 298 do { \
yading@10 299 diff = eval_motion_dist(enc, j, i, MOTION, blocksize); \
yading@10 300 \
yading@10 301 if (diff < lowestdiff) { \
yading@10 302 lowestdiff = diff; \
yading@10 303 bestpick = MOTION; \
yading@10 304 } \
yading@10 305 } while(0)
yading@10 306
yading@10 307 static void motion_search(RoqContext *enc, int blocksize)
yading@10 308 {
yading@10 309 static const motion_vect offsets[8] = {
yading@10 310 {{ 0,-1}},
yading@10 311 {{ 0, 1}},
yading@10 312 {{-1, 0}},
yading@10 313 {{ 1, 0}},
yading@10 314 {{-1, 1}},
yading@10 315 {{ 1,-1}},
yading@10 316 {{-1,-1}},
yading@10 317 {{ 1, 1}},
yading@10 318 };
yading@10 319
yading@10 320 int diff, lowestdiff, oldbest;
yading@10 321 int off[3];
yading@10 322 motion_vect bestpick = {{0,0}};
yading@10 323 int i, j, k, offset;
yading@10 324
yading@10 325 motion_vect *last_motion;
yading@10 326 motion_vect *this_motion;
yading@10 327 motion_vect vect, vect2;
yading@10 328
yading@10 329 int max=(enc->width/blocksize)*enc->height/blocksize;
yading@10 330
yading@10 331 if (blocksize == 4) {
yading@10 332 last_motion = enc->last_motion4;
yading@10 333 this_motion = enc->this_motion4;
yading@10 334 } else {
yading@10 335 last_motion = enc->last_motion8;
yading@10 336 this_motion = enc->this_motion8;
yading@10 337 }
yading@10 338
yading@10 339 for (i=0; i<enc->height; i+=blocksize)
yading@10 340 for (j=0; j<enc->width; j+=blocksize) {
yading@10 341 lowestdiff = eval_motion_dist(enc, j, i, (motion_vect) {{0,0}},
yading@10 342 blocksize);
yading@10 343 bestpick.d[0] = 0;
yading@10 344 bestpick.d[1] = 0;
yading@10 345
yading@10 346 if (blocksize == 4)
yading@10 347 EVAL_MOTION(enc->this_motion8[(i/8)*(enc->width/8) + j/8]);
yading@10 348
yading@10 349 offset = (i/blocksize)*enc->width/blocksize + j/blocksize;
yading@10 350 if (offset < max && offset >= 0)
yading@10 351 EVAL_MOTION(last_motion[offset]);
yading@10 352
yading@10 353 offset++;
yading@10 354 if (offset < max && offset >= 0)
yading@10 355 EVAL_MOTION(last_motion[offset]);
yading@10 356
yading@10 357 offset = (i/blocksize + 1)*enc->width/blocksize + j/blocksize;
yading@10 358 if (offset < max && offset >= 0)
yading@10 359 EVAL_MOTION(last_motion[offset]);
yading@10 360
yading@10 361 off[0]= (i/blocksize)*enc->width/blocksize + j/blocksize - 1;
yading@10 362 off[1]= off[0] - enc->width/blocksize + 1;
yading@10 363 off[2]= off[1] + 1;
yading@10 364
yading@10 365 if (i) {
yading@10 366
yading@10 367 for(k=0; k<2; k++)
yading@10 368 vect.d[k]= mid_pred(this_motion[off[0]].d[k],
yading@10 369 this_motion[off[1]].d[k],
yading@10 370 this_motion[off[2]].d[k]);
yading@10 371
yading@10 372 EVAL_MOTION(vect);
yading@10 373 for(k=0; k<3; k++)
yading@10 374 EVAL_MOTION(this_motion[off[k]]);
yading@10 375 } else if(j)
yading@10 376 EVAL_MOTION(this_motion[off[0]]);
yading@10 377
yading@10 378 vect = bestpick;
yading@10 379
yading@10 380 oldbest = -1;
yading@10 381 while (oldbest != lowestdiff) {
yading@10 382 oldbest = lowestdiff;
yading@10 383 for (k=0; k<8; k++) {
yading@10 384 vect2 = vect;
yading@10 385 vect2.d[0] += offsets[k].d[0];
yading@10 386 vect2.d[1] += offsets[k].d[1];
yading@10 387 EVAL_MOTION(vect2);
yading@10 388 }
yading@10 389 vect = bestpick;
yading@10 390 }
yading@10 391 offset = (i/blocksize)*enc->width/blocksize + j/blocksize;
yading@10 392 this_motion[offset] = bestpick;
yading@10 393 }
yading@10 394 }
yading@10 395
yading@10 396 /**
yading@10 397 * Get distortion for all options available to a subcel
yading@10 398 */
yading@10 399 static void gather_data_for_subcel(SubcelEvaluation *subcel, int x,
yading@10 400 int y, RoqContext *enc, RoqTempdata *tempData)
yading@10 401 {
yading@10 402 uint8_t mb4[4*4*3];
yading@10 403 uint8_t mb2[2*2*3];
yading@10 404 int cluster_index;
yading@10 405 int i, best_dist;
yading@10 406
yading@10 407 static const int bitsUsed[4] = {2, 10, 10, 34};
yading@10 408
yading@10 409 if (enc->framesSinceKeyframe >= 1) {
yading@10 410 subcel->motion = enc->this_motion4[y*enc->width/16 + x/4];
yading@10 411
yading@10 412 subcel->eval_dist[RoQ_ID_FCC] =
yading@10 413 eval_motion_dist(enc, x, y,
yading@10 414 enc->this_motion4[y*enc->width/16 + x/4], 4);
yading@10 415 } else
yading@10 416 subcel->eval_dist[RoQ_ID_FCC] = INT_MAX;
yading@10 417
yading@10 418 if (enc->framesSinceKeyframe >= 2)
yading@10 419 subcel->eval_dist[RoQ_ID_MOT] = block_sse(enc->frame_to_enc->data,
yading@10 420 enc->current_frame->data, x,
yading@10 421 y, x, y,
yading@10 422 enc->frame_to_enc->linesize,
yading@10 423 enc->current_frame->linesize,
yading@10 424 4);
yading@10 425 else
yading@10 426 subcel->eval_dist[RoQ_ID_MOT] = INT_MAX;
yading@10 427
yading@10 428 cluster_index = y*enc->width/16 + x/4;
yading@10 429
yading@10 430 get_frame_mb(enc->frame_to_enc, x, y, mb4, 4);
yading@10 431
yading@10 432 subcel->eval_dist[RoQ_ID_SLD] = index_mb(mb4,
yading@10 433 tempData->codebooks.unpacked_cb4,
yading@10 434 tempData->codebooks.numCB4,
yading@10 435 &subcel->cbEntry, 4);
yading@10 436
yading@10 437 subcel->eval_dist[RoQ_ID_CCC] = 0;
yading@10 438
yading@10 439 for(i=0;i<4;i++) {
yading@10 440 subcel->subCels[i] = tempData->closest_cb2[cluster_index*4+i];
yading@10 441
yading@10 442 get_frame_mb(enc->frame_to_enc, x+2*(i&1),
yading@10 443 y+(i&2), mb2, 2);
yading@10 444
yading@10 445 subcel->eval_dist[RoQ_ID_CCC] +=
yading@10 446 squared_diff_macroblock(tempData->codebooks.unpacked_cb2 + subcel->subCels[i]*2*2*3, mb2, 2);
yading@10 447 }
yading@10 448
yading@10 449 best_dist = INT_MAX;
yading@10 450 for (i=0; i<4; i++)
yading@10 451 if (ROQ_LAMBDA_SCALE*subcel->eval_dist[i] + enc->lambda*bitsUsed[i] <
yading@10 452 best_dist) {
yading@10 453 subcel->best_coding = i;
yading@10 454 subcel->best_bit_use = bitsUsed[i];
yading@10 455 best_dist = ROQ_LAMBDA_SCALE*subcel->eval_dist[i] +
yading@10 456 enc->lambda*bitsUsed[i];
yading@10 457 }
yading@10 458 }
yading@10 459
yading@10 460 /**
yading@10 461 * Get distortion for all options available to a cel
yading@10 462 */
yading@10 463 static void gather_data_for_cel(CelEvaluation *cel, RoqContext *enc,
yading@10 464 RoqTempdata *tempData)
yading@10 465 {
yading@10 466 uint8_t mb8[8*8*3];
yading@10 467 int index = cel->sourceY*enc->width/64 + cel->sourceX/8;
yading@10 468 int i, j, best_dist, divide_bit_use;
yading@10 469
yading@10 470 int bitsUsed[4] = {2, 10, 10, 0};
yading@10 471
yading@10 472 if (enc->framesSinceKeyframe >= 1) {
yading@10 473 cel->motion = enc->this_motion8[index];
yading@10 474
yading@10 475 cel->eval_dist[RoQ_ID_FCC] =
yading@10 476 eval_motion_dist(enc, cel->sourceX, cel->sourceY,
yading@10 477 enc->this_motion8[index], 8);
yading@10 478 } else
yading@10 479 cel->eval_dist[RoQ_ID_FCC] = INT_MAX;
yading@10 480
yading@10 481 if (enc->framesSinceKeyframe >= 2)
yading@10 482 cel->eval_dist[RoQ_ID_MOT] = block_sse(enc->frame_to_enc->data,
yading@10 483 enc->current_frame->data,
yading@10 484 cel->sourceX, cel->sourceY,
yading@10 485 cel->sourceX, cel->sourceY,
yading@10 486 enc->frame_to_enc->linesize,
yading@10 487 enc->current_frame->linesize,8);
yading@10 488 else
yading@10 489 cel->eval_dist[RoQ_ID_MOT] = INT_MAX;
yading@10 490
yading@10 491 get_frame_mb(enc->frame_to_enc, cel->sourceX, cel->sourceY, mb8, 8);
yading@10 492
yading@10 493 cel->eval_dist[RoQ_ID_SLD] =
yading@10 494 index_mb(mb8, tempData->codebooks.unpacked_cb4_enlarged,
yading@10 495 tempData->codebooks.numCB4, &cel->cbEntry, 8);
yading@10 496
yading@10 497 gather_data_for_subcel(cel->subCels + 0, cel->sourceX+0, cel->sourceY+0, enc, tempData);
yading@10 498 gather_data_for_subcel(cel->subCels + 1, cel->sourceX+4, cel->sourceY+0, enc, tempData);
yading@10 499 gather_data_for_subcel(cel->subCels + 2, cel->sourceX+0, cel->sourceY+4, enc, tempData);
yading@10 500 gather_data_for_subcel(cel->subCels + 3, cel->sourceX+4, cel->sourceY+4, enc, tempData);
yading@10 501
yading@10 502 cel->eval_dist[RoQ_ID_CCC] = 0;
yading@10 503 divide_bit_use = 0;
yading@10 504 for (i=0; i<4; i++) {
yading@10 505 cel->eval_dist[RoQ_ID_CCC] +=
yading@10 506 cel->subCels[i].eval_dist[cel->subCels[i].best_coding];
yading@10 507 divide_bit_use += cel->subCels[i].best_bit_use;
yading@10 508 }
yading@10 509
yading@10 510 best_dist = INT_MAX;
yading@10 511 bitsUsed[3] = 2 + divide_bit_use;
yading@10 512
yading@10 513 for (i=0; i<4; i++)
yading@10 514 if (ROQ_LAMBDA_SCALE*cel->eval_dist[i] + enc->lambda*bitsUsed[i] <
yading@10 515 best_dist) {
yading@10 516 cel->best_coding = i;
yading@10 517 best_dist = ROQ_LAMBDA_SCALE*cel->eval_dist[i] +
yading@10 518 enc->lambda*bitsUsed[i];
yading@10 519 }
yading@10 520
yading@10 521 tempData->used_option[cel->best_coding]++;
yading@10 522 tempData->mainChunkSize += bitsUsed[cel->best_coding];
yading@10 523
yading@10 524 if (cel->best_coding == RoQ_ID_SLD)
yading@10 525 tempData->codebooks.usedCB4[cel->cbEntry]++;
yading@10 526
yading@10 527 if (cel->best_coding == RoQ_ID_CCC)
yading@10 528 for (i=0; i<4; i++) {
yading@10 529 if (cel->subCels[i].best_coding == RoQ_ID_SLD)
yading@10 530 tempData->codebooks.usedCB4[cel->subCels[i].cbEntry]++;
yading@10 531 else if (cel->subCels[i].best_coding == RoQ_ID_CCC)
yading@10 532 for (j=0; j<4; j++)
yading@10 533 tempData->codebooks.usedCB2[cel->subCels[i].subCels[j]]++;
yading@10 534 }
yading@10 535 }
yading@10 536
yading@10 537 static void remap_codebooks(RoqContext *enc, RoqTempdata *tempData)
yading@10 538 {
yading@10 539 int i, j, idx=0;
yading@10 540
yading@10 541 /* Make remaps for the final codebook usage */
yading@10 542 for (i=0; i<MAX_CBS_4x4; i++) {
yading@10 543 if (tempData->codebooks.usedCB4[i]) {
yading@10 544 tempData->i2f4[i] = idx;
yading@10 545 tempData->f2i4[idx] = i;
yading@10 546 for (j=0; j<4; j++)
yading@10 547 tempData->codebooks.usedCB2[enc->cb4x4[i].idx[j]]++;
yading@10 548 idx++;
yading@10 549 }
yading@10 550 }
yading@10 551
yading@10 552 tempData->numCB4 = idx;
yading@10 553
yading@10 554 idx = 0;
yading@10 555 for (i=0; i<MAX_CBS_2x2; i++) {
yading@10 556 if (tempData->codebooks.usedCB2[i]) {
yading@10 557 tempData->i2f2[i] = idx;
yading@10 558 tempData->f2i2[idx] = i;
yading@10 559 idx++;
yading@10 560 }
yading@10 561 }
yading@10 562 tempData->numCB2 = idx;
yading@10 563
yading@10 564 }
yading@10 565
yading@10 566 /**
yading@10 567 * Write codebook chunk
yading@10 568 */
yading@10 569 static void write_codebooks(RoqContext *enc, RoqTempdata *tempData)
yading@10 570 {
yading@10 571 int i, j;
yading@10 572 uint8_t **outp= &enc->out_buf;
yading@10 573
yading@10 574 if (tempData->numCB2) {
yading@10 575 bytestream_put_le16(outp, RoQ_QUAD_CODEBOOK);
yading@10 576 bytestream_put_le32(outp, tempData->numCB2*6 + tempData->numCB4*4);
yading@10 577 bytestream_put_byte(outp, tempData->numCB4);
yading@10 578 bytestream_put_byte(outp, tempData->numCB2);
yading@10 579
yading@10 580 for (i=0; i<tempData->numCB2; i++) {
yading@10 581 bytestream_put_buffer(outp, enc->cb2x2[tempData->f2i2[i]].y, 4);
yading@10 582 bytestream_put_byte(outp, enc->cb2x2[tempData->f2i2[i]].u);
yading@10 583 bytestream_put_byte(outp, enc->cb2x2[tempData->f2i2[i]].v);
yading@10 584 }
yading@10 585
yading@10 586 for (i=0; i<tempData->numCB4; i++)
yading@10 587 for (j=0; j<4; j++)
yading@10 588 bytestream_put_byte(outp, tempData->i2f2[enc->cb4x4[tempData->f2i4[i]].idx[j]]);
yading@10 589
yading@10 590 }
yading@10 591 }
yading@10 592
yading@10 593 static inline uint8_t motion_arg(motion_vect mot)
yading@10 594 {
yading@10 595 uint8_t ax = 8 - ((uint8_t) mot.d[0]);
yading@10 596 uint8_t ay = 8 - ((uint8_t) mot.d[1]);
yading@10 597 return ((ax&15)<<4) | (ay&15);
yading@10 598 }
yading@10 599
yading@10 600 typedef struct
yading@10 601 {
yading@10 602 int typeSpool;
yading@10 603 int typeSpoolLength;
yading@10 604 uint8_t argumentSpool[64];
yading@10 605 uint8_t *args;
yading@10 606 uint8_t **pout;
yading@10 607 } CodingSpool;
yading@10 608
yading@10 609 /* NOTE: Typecodes must be spooled AFTER arguments!! */
yading@10 610 static void write_typecode(CodingSpool *s, uint8_t type)
yading@10 611 {
yading@10 612 s->typeSpool |= (type & 3) << (14 - s->typeSpoolLength);
yading@10 613 s->typeSpoolLength += 2;
yading@10 614 if (s->typeSpoolLength == 16) {
yading@10 615 bytestream_put_le16(s->pout, s->typeSpool);
yading@10 616 bytestream_put_buffer(s->pout, s->argumentSpool,
yading@10 617 s->args - s->argumentSpool);
yading@10 618 s->typeSpoolLength = 0;
yading@10 619 s->typeSpool = 0;
yading@10 620 s->args = s->argumentSpool;
yading@10 621 }
yading@10 622 }
yading@10 623
yading@10 624 static void reconstruct_and_encode_image(RoqContext *enc, RoqTempdata *tempData, int w, int h, int numBlocks)
yading@10 625 {
yading@10 626 int i, j, k;
yading@10 627 int x, y;
yading@10 628 int subX, subY;
yading@10 629 int dist=0;
yading@10 630
yading@10 631 roq_qcell *qcell;
yading@10 632 CelEvaluation *eval;
yading@10 633
yading@10 634 CodingSpool spool;
yading@10 635
yading@10 636 spool.typeSpool=0;
yading@10 637 spool.typeSpoolLength=0;
yading@10 638 spool.args = spool.argumentSpool;
yading@10 639 spool.pout = &enc->out_buf;
yading@10 640
yading@10 641 if (tempData->used_option[RoQ_ID_CCC]%2)
yading@10 642 tempData->mainChunkSize+=8; //FIXME
yading@10 643
yading@10 644 /* Write the video chunk header */
yading@10 645 bytestream_put_le16(&enc->out_buf, RoQ_QUAD_VQ);
yading@10 646 bytestream_put_le32(&enc->out_buf, tempData->mainChunkSize/8);
yading@10 647 bytestream_put_byte(&enc->out_buf, 0x0);
yading@10 648 bytestream_put_byte(&enc->out_buf, 0x0);
yading@10 649
yading@10 650 for (i=0; i<numBlocks; i++) {
yading@10 651 eval = tempData->cel_evals + i;
yading@10 652
yading@10 653 x = eval->sourceX;
yading@10 654 y = eval->sourceY;
yading@10 655 dist += eval->eval_dist[eval->best_coding];
yading@10 656
yading@10 657 switch (eval->best_coding) {
yading@10 658 case RoQ_ID_MOT:
yading@10 659 write_typecode(&spool, RoQ_ID_MOT);
yading@10 660 break;
yading@10 661
yading@10 662 case RoQ_ID_FCC:
yading@10 663 bytestream_put_byte(&spool.args, motion_arg(eval->motion));
yading@10 664
yading@10 665 write_typecode(&spool, RoQ_ID_FCC);
yading@10 666 ff_apply_motion_8x8(enc, x, y,
yading@10 667 eval->motion.d[0], eval->motion.d[1]);
yading@10 668 break;
yading@10 669
yading@10 670 case RoQ_ID_SLD:
yading@10 671 bytestream_put_byte(&spool.args, tempData->i2f4[eval->cbEntry]);
yading@10 672 write_typecode(&spool, RoQ_ID_SLD);
yading@10 673
yading@10 674 qcell = enc->cb4x4 + eval->cbEntry;
yading@10 675 ff_apply_vector_4x4(enc, x , y , enc->cb2x2 + qcell->idx[0]);
yading@10 676 ff_apply_vector_4x4(enc, x+4, y , enc->cb2x2 + qcell->idx[1]);
yading@10 677 ff_apply_vector_4x4(enc, x , y+4, enc->cb2x2 + qcell->idx[2]);
yading@10 678 ff_apply_vector_4x4(enc, x+4, y+4, enc->cb2x2 + qcell->idx[3]);
yading@10 679 break;
yading@10 680
yading@10 681 case RoQ_ID_CCC:
yading@10 682 write_typecode(&spool, RoQ_ID_CCC);
yading@10 683
yading@10 684 for (j=0; j<4; j++) {
yading@10 685 subX = x + 4*(j&1);
yading@10 686 subY = y + 2*(j&2);
yading@10 687
yading@10 688 switch(eval->subCels[j].best_coding) {
yading@10 689 case RoQ_ID_MOT:
yading@10 690 break;
yading@10 691
yading@10 692 case RoQ_ID_FCC:
yading@10 693 bytestream_put_byte(&spool.args,
yading@10 694 motion_arg(eval->subCels[j].motion));
yading@10 695
yading@10 696 ff_apply_motion_4x4(enc, subX, subY,
yading@10 697 eval->subCels[j].motion.d[0],
yading@10 698 eval->subCels[j].motion.d[1]);
yading@10 699 break;
yading@10 700
yading@10 701 case RoQ_ID_SLD:
yading@10 702 bytestream_put_byte(&spool.args,
yading@10 703 tempData->i2f4[eval->subCels[j].cbEntry]);
yading@10 704
yading@10 705 qcell = enc->cb4x4 + eval->subCels[j].cbEntry;
yading@10 706
yading@10 707 ff_apply_vector_2x2(enc, subX , subY ,
yading@10 708 enc->cb2x2 + qcell->idx[0]);
yading@10 709 ff_apply_vector_2x2(enc, subX+2, subY ,
yading@10 710 enc->cb2x2 + qcell->idx[1]);
yading@10 711 ff_apply_vector_2x2(enc, subX , subY+2,
yading@10 712 enc->cb2x2 + qcell->idx[2]);
yading@10 713 ff_apply_vector_2x2(enc, subX+2, subY+2,
yading@10 714 enc->cb2x2 + qcell->idx[3]);
yading@10 715 break;
yading@10 716
yading@10 717 case RoQ_ID_CCC:
yading@10 718 for (k=0; k<4; k++) {
yading@10 719 int cb_idx = eval->subCels[j].subCels[k];
yading@10 720 bytestream_put_byte(&spool.args,
yading@10 721 tempData->i2f2[cb_idx]);
yading@10 722
yading@10 723 ff_apply_vector_2x2(enc, subX + 2*(k&1), subY + (k&2),
yading@10 724 enc->cb2x2 + cb_idx);
yading@10 725 }
yading@10 726 break;
yading@10 727 }
yading@10 728 write_typecode(&spool, eval->subCels[j].best_coding);
yading@10 729 }
yading@10 730 break;
yading@10 731 }
yading@10 732 }
yading@10 733
yading@10 734 /* Flush the remainder of the argument/type spool */
yading@10 735 while (spool.typeSpoolLength)
yading@10 736 write_typecode(&spool, 0x0);
yading@10 737
yading@10 738 #if 0
yading@10 739 uint8_t *fdata[3] = {enc->frame_to_enc->data[0],
yading@10 740 enc->frame_to_enc->data[1],
yading@10 741 enc->frame_to_enc->data[2]};
yading@10 742 uint8_t *cdata[3] = {enc->current_frame->data[0],
yading@10 743 enc->current_frame->data[1],
yading@10 744 enc->current_frame->data[2]};
yading@10 745 av_log(enc->avctx, AV_LOG_ERROR, "Expected distortion: %i Actual: %i\n",
yading@10 746 dist,
yading@10 747 block_sse(fdata, cdata, 0, 0, 0, 0,
yading@10 748 enc->frame_to_enc->linesize,
yading@10 749 enc->current_frame->linesize,
yading@10 750 enc->width)); //WARNING: Square dimensions implied...
yading@10 751 #endif
yading@10 752 }
yading@10 753
yading@10 754
yading@10 755 /**
yading@10 756 * Create a single YUV cell from a 2x2 section of the image
yading@10 757 */
yading@10 758 static inline void frame_block_to_cell(uint8_t *block, uint8_t * const *data,
yading@10 759 int top, int left, const int *stride)
yading@10 760 {
yading@10 761 int i, j, u=0, v=0;
yading@10 762
yading@10 763 for (i=0; i<2; i++)
yading@10 764 for (j=0; j<2; j++) {
yading@10 765 int x = (top+i)*stride[0] + left + j;
yading@10 766 *block++ = data[0][x];
yading@10 767 x = (top+i)*stride[1] + left + j;
yading@10 768 u += data[1][x];
yading@10 769 v += data[2][x];
yading@10 770 }
yading@10 771
yading@10 772 *block++ = (u+2)/4;
yading@10 773 *block++ = (v+2)/4;
yading@10 774 }
yading@10 775
yading@10 776 /**
yading@10 777 * Create YUV clusters for the entire image
yading@10 778 */
yading@10 779 static void create_clusters(const AVFrame *frame, int w, int h, uint8_t *yuvClusters)
yading@10 780 {
yading@10 781 int i, j, k, l;
yading@10 782
yading@10 783 for (i=0; i<h; i+=4)
yading@10 784 for (j=0; j<w; j+=4) {
yading@10 785 for (k=0; k < 2; k++)
yading@10 786 for (l=0; l < 2; l++)
yading@10 787 frame_block_to_cell(yuvClusters + (l + 2*k)*6, frame->data,
yading@10 788 i+2*k, j+2*l, frame->linesize);
yading@10 789 yuvClusters += 24;
yading@10 790 }
yading@10 791 }
yading@10 792
yading@10 793 static void generate_codebook(RoqContext *enc, RoqTempdata *tempdata,
yading@10 794 int *points, int inputCount, roq_cell *results,
yading@10 795 int size, int cbsize)
yading@10 796 {
yading@10 797 int i, j, k;
yading@10 798 int c_size = size*size/4;
yading@10 799 int *buf;
yading@10 800 int *codebook = av_malloc(6*c_size*cbsize*sizeof(int));
yading@10 801 int *closest_cb;
yading@10 802
yading@10 803 if (size == 4)
yading@10 804 closest_cb = av_malloc(6*c_size*inputCount*sizeof(int));
yading@10 805 else
yading@10 806 closest_cb = tempdata->closest_cb2;
yading@10 807
yading@10 808 ff_init_elbg(points, 6*c_size, inputCount, codebook, cbsize, 1, closest_cb, &enc->randctx);
yading@10 809 ff_do_elbg(points, 6*c_size, inputCount, codebook, cbsize, 1, closest_cb, &enc->randctx);
yading@10 810
yading@10 811 if (size == 4)
yading@10 812 av_free(closest_cb);
yading@10 813
yading@10 814 buf = codebook;
yading@10 815 for (i=0; i<cbsize; i++)
yading@10 816 for (k=0; k<c_size; k++) {
yading@10 817 for(j=0; j<4; j++)
yading@10 818 results->y[j] = *buf++;
yading@10 819
yading@10 820 results->u = (*buf++ + CHROMA_BIAS/2)/CHROMA_BIAS;
yading@10 821 results->v = (*buf++ + CHROMA_BIAS/2)/CHROMA_BIAS;
yading@10 822 results++;
yading@10 823 }
yading@10 824
yading@10 825 av_free(codebook);
yading@10 826 }
yading@10 827
yading@10 828 static void generate_new_codebooks(RoqContext *enc, RoqTempdata *tempData)
yading@10 829 {
yading@10 830 int i,j;
yading@10 831 RoqCodebooks *codebooks = &tempData->codebooks;
yading@10 832 int max = enc->width*enc->height/16;
yading@10 833 uint8_t mb2[3*4];
yading@10 834 roq_cell *results4 = av_malloc(sizeof(roq_cell)*MAX_CBS_4x4*4);
yading@10 835 uint8_t *yuvClusters=av_malloc(sizeof(int)*max*6*4);
yading@10 836 int *points = av_malloc(max*6*4*sizeof(int));
yading@10 837 int bias;
yading@10 838
yading@10 839 /* Subsample YUV data */
yading@10 840 create_clusters(enc->frame_to_enc, enc->width, enc->height, yuvClusters);
yading@10 841
yading@10 842 /* Cast to integer and apply chroma bias */
yading@10 843 for (i=0; i<max*24; i++) {
yading@10 844 bias = ((i%6)<4) ? 1 : CHROMA_BIAS;
yading@10 845 points[i] = bias*yuvClusters[i];
yading@10 846 }
yading@10 847
yading@10 848 /* Create 4x4 codebooks */
yading@10 849 generate_codebook(enc, tempData, points, max, results4, 4, MAX_CBS_4x4);
yading@10 850
yading@10 851 codebooks->numCB4 = MAX_CBS_4x4;
yading@10 852
yading@10 853 tempData->closest_cb2 = av_malloc(max*4*sizeof(int));
yading@10 854
yading@10 855 /* Create 2x2 codebooks */
yading@10 856 generate_codebook(enc, tempData, points, max*4, enc->cb2x2, 2, MAX_CBS_2x2);
yading@10 857
yading@10 858 codebooks->numCB2 = MAX_CBS_2x2;
yading@10 859
yading@10 860 /* Unpack 2x2 codebook clusters */
yading@10 861 for (i=0; i<codebooks->numCB2; i++)
yading@10 862 unpack_roq_cell(enc->cb2x2 + i, codebooks->unpacked_cb2 + i*2*2*3);
yading@10 863
yading@10 864 /* Index all 4x4 entries to the 2x2 entries, unpack, and enlarge */
yading@10 865 for (i=0; i<codebooks->numCB4; i++) {
yading@10 866 for (j=0; j<4; j++) {
yading@10 867 unpack_roq_cell(&results4[4*i + j], mb2);
yading@10 868 index_mb(mb2, codebooks->unpacked_cb2, codebooks->numCB2,
yading@10 869 &enc->cb4x4[i].idx[j], 2);
yading@10 870 }
yading@10 871 unpack_roq_qcell(codebooks->unpacked_cb2, enc->cb4x4 + i,
yading@10 872 codebooks->unpacked_cb4 + i*4*4*3);
yading@10 873 enlarge_roq_mb4(codebooks->unpacked_cb4 + i*4*4*3,
yading@10 874 codebooks->unpacked_cb4_enlarged + i*8*8*3);
yading@10 875 }
yading@10 876
yading@10 877 av_free(yuvClusters);
yading@10 878 av_free(points);
yading@10 879 av_free(results4);
yading@10 880 }
yading@10 881
yading@10 882 static void roq_encode_video(RoqContext *enc)
yading@10 883 {
yading@10 884 RoqTempdata *tempData = enc->tmpData;
yading@10 885 int i;
yading@10 886
yading@10 887 memset(tempData, 0, sizeof(*tempData));
yading@10 888
yading@10 889 create_cel_evals(enc, tempData);
yading@10 890
yading@10 891 generate_new_codebooks(enc, tempData);
yading@10 892
yading@10 893 if (enc->framesSinceKeyframe >= 1) {
yading@10 894 motion_search(enc, 8);
yading@10 895 motion_search(enc, 4);
yading@10 896 }
yading@10 897
yading@10 898 retry_encode:
yading@10 899 for (i=0; i<enc->width*enc->height/64; i++)
yading@10 900 gather_data_for_cel(tempData->cel_evals + i, enc, tempData);
yading@10 901
yading@10 902 /* Quake 3 can't handle chunks bigger than 65535 bytes */
yading@10 903 if (tempData->mainChunkSize/8 > 65535) {
yading@10 904 av_log(enc->avctx, AV_LOG_ERROR,
yading@10 905 "Warning, generated a frame too big (%d > 65535), "
yading@10 906 "try using a smaller qscale value.\n",
yading@10 907 tempData->mainChunkSize/8);
yading@10 908 enc->lambda *= 1.5;
yading@10 909 tempData->mainChunkSize = 0;
yading@10 910 memset(tempData->used_option, 0, sizeof(tempData->used_option));
yading@10 911 memset(tempData->codebooks.usedCB4, 0,
yading@10 912 sizeof(tempData->codebooks.usedCB4));
yading@10 913 memset(tempData->codebooks.usedCB2, 0,
yading@10 914 sizeof(tempData->codebooks.usedCB2));
yading@10 915
yading@10 916 goto retry_encode;
yading@10 917 }
yading@10 918
yading@10 919 remap_codebooks(enc, tempData);
yading@10 920
yading@10 921 write_codebooks(enc, tempData);
yading@10 922
yading@10 923 reconstruct_and_encode_image(enc, tempData, enc->width, enc->height,
yading@10 924 enc->width*enc->height/64);
yading@10 925
yading@10 926 enc->avctx->coded_frame = enc->current_frame;
yading@10 927
yading@10 928 /* Rotate frame history */
yading@10 929 FFSWAP(AVFrame *, enc->current_frame, enc->last_frame);
yading@10 930 FFSWAP(motion_vect *, enc->last_motion4, enc->this_motion4);
yading@10 931 FFSWAP(motion_vect *, enc->last_motion8, enc->this_motion8);
yading@10 932
yading@10 933 av_free(tempData->cel_evals);
yading@10 934 av_free(tempData->closest_cb2);
yading@10 935
yading@10 936 enc->framesSinceKeyframe++;
yading@10 937 }
yading@10 938
yading@10 939 static int roq_encode_end(AVCodecContext *avctx)
yading@10 940 {
yading@10 941 RoqContext *enc = avctx->priv_data;
yading@10 942
yading@10 943 av_frame_free(&enc->current_frame);
yading@10 944 av_frame_free(&enc->last_frame);
yading@10 945
yading@10 946 av_free(enc->tmpData);
yading@10 947 av_free(enc->this_motion4);
yading@10 948 av_free(enc->last_motion4);
yading@10 949 av_free(enc->this_motion8);
yading@10 950 av_free(enc->last_motion8);
yading@10 951
yading@10 952 return 0;
yading@10 953 }
yading@10 954
yading@10 955 static int roq_encode_init(AVCodecContext *avctx)
yading@10 956 {
yading@10 957 RoqContext *enc = avctx->priv_data;
yading@10 958
yading@10 959 av_lfg_init(&enc->randctx, 1);
yading@10 960
yading@10 961 enc->framesSinceKeyframe = 0;
yading@10 962 if ((avctx->width & 0xf) || (avctx->height & 0xf)) {
yading@10 963 av_log(avctx, AV_LOG_ERROR, "Dimensions must be divisible by 16\n");
yading@10 964 return -1;
yading@10 965 }
yading@10 966
yading@10 967 if (((avctx->width)&(avctx->width-1))||((avctx->height)&(avctx->height-1)))
yading@10 968 av_log(avctx, AV_LOG_ERROR, "Warning: dimensions not power of two\n");
yading@10 969
yading@10 970 enc->width = avctx->width;
yading@10 971 enc->height = avctx->height;
yading@10 972
yading@10 973 enc->framesSinceKeyframe = 0;
yading@10 974 enc->first_frame = 1;
yading@10 975
yading@10 976 enc->last_frame = av_frame_alloc();
yading@10 977 enc->current_frame = av_frame_alloc();
yading@10 978 if (!enc->last_frame || !enc->current_frame) {
yading@10 979 roq_encode_end(avctx);
yading@10 980 return AVERROR(ENOMEM);
yading@10 981 }
yading@10 982
yading@10 983 enc->tmpData = av_malloc(sizeof(RoqTempdata));
yading@10 984
yading@10 985 enc->this_motion4 =
yading@10 986 av_mallocz((enc->width*enc->height/16)*sizeof(motion_vect));
yading@10 987
yading@10 988 enc->last_motion4 =
yading@10 989 av_malloc ((enc->width*enc->height/16)*sizeof(motion_vect));
yading@10 990
yading@10 991 enc->this_motion8 =
yading@10 992 av_mallocz((enc->width*enc->height/64)*sizeof(motion_vect));
yading@10 993
yading@10 994 enc->last_motion8 =
yading@10 995 av_malloc ((enc->width*enc->height/64)*sizeof(motion_vect));
yading@10 996
yading@10 997 return 0;
yading@10 998 }
yading@10 999
yading@10 1000 static void roq_write_video_info_chunk(RoqContext *enc)
yading@10 1001 {
yading@10 1002 /* ROQ info chunk */
yading@10 1003 bytestream_put_le16(&enc->out_buf, RoQ_INFO);
yading@10 1004
yading@10 1005 /* Size: 8 bytes */
yading@10 1006 bytestream_put_le32(&enc->out_buf, 8);
yading@10 1007
yading@10 1008 /* Unused argument */
yading@10 1009 bytestream_put_byte(&enc->out_buf, 0x00);
yading@10 1010 bytestream_put_byte(&enc->out_buf, 0x00);
yading@10 1011
yading@10 1012 /* Width */
yading@10 1013 bytestream_put_le16(&enc->out_buf, enc->width);
yading@10 1014
yading@10 1015 /* Height */
yading@10 1016 bytestream_put_le16(&enc->out_buf, enc->height);
yading@10 1017
yading@10 1018 /* Unused in Quake 3, mimics the output of the real encoder */
yading@10 1019 bytestream_put_byte(&enc->out_buf, 0x08);
yading@10 1020 bytestream_put_byte(&enc->out_buf, 0x00);
yading@10 1021 bytestream_put_byte(&enc->out_buf, 0x04);
yading@10 1022 bytestream_put_byte(&enc->out_buf, 0x00);
yading@10 1023 }
yading@10 1024
yading@10 1025 static int roq_encode_frame(AVCodecContext *avctx, AVPacket *pkt,
yading@10 1026 const AVFrame *frame, int *got_packet)
yading@10 1027 {
yading@10 1028 RoqContext *enc = avctx->priv_data;
yading@10 1029 int size, ret;
yading@10 1030
yading@10 1031 enc->avctx = avctx;
yading@10 1032
yading@10 1033 enc->frame_to_enc = frame;
yading@10 1034
yading@10 1035 if (frame->quality)
yading@10 1036 enc->lambda = frame->quality - 1;
yading@10 1037 else
yading@10 1038 enc->lambda = 2*ROQ_LAMBDA_SCALE;
yading@10 1039
yading@10 1040 /* 138 bits max per 8x8 block +
yading@10 1041 * 256 codebooks*(6 bytes 2x2 + 4 bytes 4x4) + 8 bytes frame header */
yading@10 1042 size = ((enc->width * enc->height / 64) * 138 + 7) / 8 + 256 * (6 + 4) + 8;
yading@10 1043 if ((ret = ff_alloc_packet2(avctx, pkt, size)) < 0)
yading@10 1044 return ret;
yading@10 1045 enc->out_buf = pkt->data;
yading@10 1046
yading@10 1047 /* Check for I frame */
yading@10 1048 if (enc->framesSinceKeyframe == avctx->gop_size)
yading@10 1049 enc->framesSinceKeyframe = 0;
yading@10 1050
yading@10 1051 if (enc->first_frame) {
yading@10 1052 /* Alloc memory for the reconstruction data (we must know the stride
yading@10 1053 for that) */
yading@10 1054 if ((ret = ff_get_buffer(avctx, enc->current_frame, 0)) < 0 ||
yading@10 1055 (ret = ff_get_buffer(avctx, enc->last_frame, 0)) < 0)
yading@10 1056 return ret;
yading@10 1057
yading@10 1058 /* Before the first video frame, write a "video info" chunk */
yading@10 1059 roq_write_video_info_chunk(enc);
yading@10 1060
yading@10 1061 enc->first_frame = 0;
yading@10 1062 }
yading@10 1063
yading@10 1064 /* Encode the actual frame */
yading@10 1065 roq_encode_video(enc);
yading@10 1066
yading@10 1067 pkt->size = enc->out_buf - pkt->data;
yading@10 1068 if (enc->framesSinceKeyframe == 1)
yading@10 1069 pkt->flags |= AV_PKT_FLAG_KEY;
yading@10 1070 *got_packet = 1;
yading@10 1071
yading@10 1072 return 0;
yading@10 1073 }
yading@10 1074
yading@10 1075 AVCodec ff_roq_encoder = {
yading@10 1076 .name = "roqvideo",
yading@10 1077 .type = AVMEDIA_TYPE_VIDEO,
yading@10 1078 .id = AV_CODEC_ID_ROQ,
yading@10 1079 .priv_data_size = sizeof(RoqContext),
yading@10 1080 .init = roq_encode_init,
yading@10 1081 .encode2 = roq_encode_frame,
yading@10 1082 .close = roq_encode_end,
yading@10 1083 .supported_framerates = (const AVRational[]){ {30,1}, {0,0} },
yading@10 1084 .pix_fmts = (const enum AVPixelFormat[]){ AV_PIX_FMT_YUV444P,
yading@10 1085 AV_PIX_FMT_NONE },
yading@10 1086 .long_name = NULL_IF_CONFIG_SMALL("id RoQ video"),
yading@10 1087 };