00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057 #include <string.h>
00058
00059 #include "roqvideo.h"
00060 #include "bytestream.h"
00061 #include "elbg.h"
00062 #include "mathops.h"
00063
00064 #define CHROMA_BIAS 1
00065
00070 #define MAX_CBS_4x4 255
00071
00072 #define MAX_CBS_2x2 256
00073
00074
00075 #define ROQ_LAMBDA_SCALE ((uint64_t) FF_LAMBDA_SCALE)
00076
00077
00078 static void unpack_roq_cell(roq_cell *cell, uint8_t u[4*3])
00079 {
00080 memcpy(u , cell->y, 4);
00081 memset(u+4, cell->u, 4);
00082 memset(u+8, cell->v, 4);
00083 }
00084
00085 static void unpack_roq_qcell(uint8_t cb2[], roq_qcell *qcell, uint8_t u[4*4*3])
00086 {
00087 int i,cp;
00088 static const int offsets[4] = {0, 2, 8, 10};
00089
00090 for (cp=0; cp<3; cp++)
00091 for (i=0; i<4; i++) {
00092 u[4*4*cp + offsets[i] ] = cb2[qcell->idx[i]*2*2*3 + 4*cp ];
00093 u[4*4*cp + offsets[i]+1] = cb2[qcell->idx[i]*2*2*3 + 4*cp+1];
00094 u[4*4*cp + offsets[i]+4] = cb2[qcell->idx[i]*2*2*3 + 4*cp+2];
00095 u[4*4*cp + offsets[i]+5] = cb2[qcell->idx[i]*2*2*3 + 4*cp+3];
00096 }
00097 }
00098
00099
00100 static void enlarge_roq_mb4(uint8_t base[3*16], uint8_t u[3*64])
00101 {
00102 int x,y,cp;
00103
00104 for(cp=0; cp<3; cp++)
00105 for(y=0; y<8; y++)
00106 for(x=0; x<8; x++)
00107 *u++ = base[(y/2)*4 + (x/2) + 16*cp];
00108 }
00109
00110 static inline int square(int x)
00111 {
00112 return x*x;
00113 }
00114
00115 static inline int eval_sse(uint8_t *a, uint8_t *b, int count)
00116 {
00117 int diff=0;
00118
00119 while(count--)
00120 diff += square(*b++ - *a++);
00121
00122 return diff;
00123 }
00124
00125
00126
00127 static int block_sse(uint8_t **buf1, uint8_t **buf2, int x1, int y1, int x2,
00128 int y2, int *stride1, int *stride2, int size)
00129 {
00130 int i, k;
00131 int sse=0;
00132
00133 for (k=0; k<3; k++) {
00134 int bias = (k ? CHROMA_BIAS : 4);
00135 for (i=0; i<size; i++)
00136 sse += bias*eval_sse(buf1[k] + (y1+i)*stride1[k] + x1,
00137 buf2[k] + (y2+i)*stride2[k] + x2, size);
00138 }
00139
00140 return sse;
00141 }
00142
00143 static int eval_motion_dist(RoqContext *enc, int x, int y, motion_vect vect,
00144 int size)
00145 {
00146 int mx=vect.d[0];
00147 int my=vect.d[1];
00148
00149 if (mx < -7 || mx > 7)
00150 return INT_MAX;
00151
00152 if (my < -7 || my > 7)
00153 return INT_MAX;
00154
00155 mx += x;
00156 my += y;
00157
00158 if ((unsigned) mx > enc->width-size || (unsigned) my > enc->height-size)
00159 return INT_MAX;
00160
00161 return block_sse(enc->frame_to_enc->data, enc->last_frame->data, x, y,
00162 mx, my,
00163 enc->frame_to_enc->linesize, enc->last_frame->linesize,
00164 size);
00165 }
00166
00170 static inline int squared_diff_macroblock(uint8_t a[], uint8_t b[], int size)
00171 {
00172 int cp, sdiff=0;
00173
00174 for(cp=0;cp<3;cp++) {
00175 int bias = (cp ? CHROMA_BIAS : 4);
00176 sdiff += bias*eval_sse(a, b, size*size);
00177 a += size*size;
00178 b += size*size;
00179 }
00180
00181 return sdiff;
00182 }
00183
00184 typedef struct
00185 {
00186 int eval_dist[4];
00187 int best_bit_use;
00188 int best_coding;
00189
00190 int subCels[4];
00191 motion_vect motion;
00192 int cbEntry;
00193 } SubcelEvaluation;
00194
00195 typedef struct
00196 {
00197 int eval_dist[4];
00198 int best_coding;
00199
00200 SubcelEvaluation subCels[4];
00201
00202 motion_vect motion;
00203 int cbEntry;
00204
00205 int sourceX, sourceY;
00206 } CelEvaluation;
00207
00208 typedef struct
00209 {
00210 int numCB4;
00211 int numCB2;
00212 int usedCB2[MAX_CBS_2x2];
00213 int usedCB4[MAX_CBS_4x4];
00214 uint8_t unpacked_cb2[MAX_CBS_2x2*2*2*3];
00215 uint8_t unpacked_cb4[MAX_CBS_4x4*4*4*3];
00216 uint8_t unpacked_cb4_enlarged[MAX_CBS_4x4*8*8*3];
00217 } RoqCodebooks;
00218
00222 typedef struct RoqTempData
00223 {
00224 CelEvaluation *cel_evals;
00225
00226 int f2i4[MAX_CBS_4x4];
00227 int i2f4[MAX_CBS_4x4];
00228 int f2i2[MAX_CBS_2x2];
00229 int i2f2[MAX_CBS_2x2];
00230
00231 int mainChunkSize;
00232
00233 int numCB4;
00234 int numCB2;
00235
00236 RoqCodebooks codebooks;
00237
00238 int *closest_cb2;
00239 int used_option[4];
00240 } RoqTempdata;
00241
00245 static void create_cel_evals(RoqContext *enc, RoqTempdata *tempData)
00246 {
00247 int n=0, x, y, i;
00248
00249 tempData->cel_evals = av_malloc(enc->width*enc->height/64 * sizeof(CelEvaluation));
00250
00251
00252 for (y=0; y<enc->height; y+=16)
00253 for (x=0; x<enc->width; x+=16)
00254 for(i=0; i<4; i++) {
00255 tempData->cel_evals[n ].sourceX = x + (i&1)*8;
00256 tempData->cel_evals[n++].sourceY = y + (i&2)*4;
00257 }
00258 }
00259
00263 static void get_frame_mb(AVFrame *frame, int x, int y, uint8_t mb[], int dim)
00264 {
00265 int i, j, cp;
00266
00267 for (cp=0; cp<3; cp++) {
00268 int stride = frame->linesize[cp];
00269 for (i=0; i<dim; i++)
00270 for (j=0; j<dim; j++)
00271 *mb++ = frame->data[cp][(y+i)*stride + x + j];
00272 }
00273 }
00274
00278 static int index_mb(uint8_t cluster[], uint8_t cb[], int numCB,
00279 int *outIndex, int dim)
00280 {
00281 int i, lDiff = INT_MAX, pick=0;
00282
00283
00284 for (i=0; i<numCB; i++) {
00285 int diff = squared_diff_macroblock(cluster, cb + i*dim*dim*3, dim);
00286 if (diff < lDiff) {
00287 lDiff = diff;
00288 pick = i;
00289 }
00290 }
00291
00292 *outIndex = pick;
00293 return lDiff;
00294 }
00295
00296 #define EVAL_MOTION(MOTION) \
00297 do { \
00298 diff = eval_motion_dist(enc, j, i, MOTION, blocksize); \
00299 \
00300 if (diff < lowestdiff) { \
00301 lowestdiff = diff; \
00302 bestpick = MOTION; \
00303 } \
00304 } while(0)
00305
00306 static void motion_search(RoqContext *enc, int blocksize)
00307 {
00308 static const motion_vect offsets[8] = {
00309 {{ 0,-1}},
00310 {{ 0, 1}},
00311 {{-1, 0}},
00312 {{ 1, 0}},
00313 {{-1, 1}},
00314 {{ 1,-1}},
00315 {{-1,-1}},
00316 {{ 1, 1}},
00317 };
00318
00319 int diff, lowestdiff, oldbest;
00320 int off[3];
00321 motion_vect bestpick = {{0,0}};
00322 int i, j, k, offset;
00323
00324 motion_vect *last_motion;
00325 motion_vect *this_motion;
00326 motion_vect vect, vect2;
00327
00328 int max=(enc->width/blocksize)*enc->height/blocksize;
00329
00330 if (blocksize == 4) {
00331 last_motion = enc->last_motion4;
00332 this_motion = enc->this_motion4;
00333 } else {
00334 last_motion = enc->last_motion8;
00335 this_motion = enc->this_motion8;
00336 }
00337
00338 for (i=0; i<enc->height; i+=blocksize)
00339 for (j=0; j<enc->width; j+=blocksize) {
00340 lowestdiff = eval_motion_dist(enc, j, i, (motion_vect) {{0,0}},
00341 blocksize);
00342 bestpick.d[0] = 0;
00343 bestpick.d[1] = 0;
00344
00345 if (blocksize == 4)
00346 EVAL_MOTION(enc->this_motion8[(i/8)*(enc->width/8) + j/8]);
00347
00348 offset = (i/blocksize)*enc->width/blocksize + j/blocksize;
00349 if (offset < max && offset >= 0)
00350 EVAL_MOTION(last_motion[offset]);
00351
00352 offset++;
00353 if (offset < max && offset >= 0)
00354 EVAL_MOTION(last_motion[offset]);
00355
00356 offset = (i/blocksize + 1)*enc->width/blocksize + j/blocksize;
00357 if (offset < max && offset >= 0)
00358 EVAL_MOTION(last_motion[offset]);
00359
00360 off[0]= (i/blocksize)*enc->width/blocksize + j/blocksize - 1;
00361 off[1]= off[0] - enc->width/blocksize + 1;
00362 off[2]= off[1] + 1;
00363
00364 if (i) {
00365
00366 for(k=0; k<2; k++)
00367 vect.d[k]= mid_pred(this_motion[off[0]].d[k],
00368 this_motion[off[1]].d[k],
00369 this_motion[off[2]].d[k]);
00370
00371 EVAL_MOTION(vect);
00372 for(k=0; k<3; k++)
00373 EVAL_MOTION(this_motion[off[k]]);
00374 } else if(j)
00375 EVAL_MOTION(this_motion[off[0]]);
00376
00377 vect = bestpick;
00378
00379 oldbest = -1;
00380 while (oldbest != lowestdiff) {
00381 oldbest = lowestdiff;
00382 for (k=0; k<8; k++) {
00383 vect2 = vect;
00384 vect2.d[0] += offsets[k].d[0];
00385 vect2.d[1] += offsets[k].d[1];
00386 EVAL_MOTION(vect2);
00387 }
00388 vect = bestpick;
00389 }
00390 offset = (i/blocksize)*enc->width/blocksize + j/blocksize;
00391 this_motion[offset] = bestpick;
00392 }
00393 }
00394
00398 static void gather_data_for_subcel(SubcelEvaluation *subcel, int x,
00399 int y, RoqContext *enc, RoqTempdata *tempData)
00400 {
00401 uint8_t mb4[4*4*3];
00402 uint8_t mb2[2*2*3];
00403 int cluster_index;
00404 int i, best_dist;
00405
00406 static const int bitsUsed[4] = {2, 10, 10, 34};
00407
00408 if (enc->framesSinceKeyframe >= 1) {
00409 subcel->motion = enc->this_motion4[y*enc->width/16 + x/4];
00410
00411 subcel->eval_dist[RoQ_ID_FCC] =
00412 eval_motion_dist(enc, x, y,
00413 enc->this_motion4[y*enc->width/16 + x/4], 4);
00414 } else
00415 subcel->eval_dist[RoQ_ID_FCC] = INT_MAX;
00416
00417 if (enc->framesSinceKeyframe >= 2)
00418 subcel->eval_dist[RoQ_ID_MOT] = block_sse(enc->frame_to_enc->data,
00419 enc->current_frame->data, x,
00420 y, x, y,
00421 enc->frame_to_enc->linesize,
00422 enc->current_frame->linesize,
00423 4);
00424 else
00425 subcel->eval_dist[RoQ_ID_MOT] = INT_MAX;
00426
00427 cluster_index = y*enc->width/16 + x/4;
00428
00429 get_frame_mb(enc->frame_to_enc, x, y, mb4, 4);
00430
00431 subcel->eval_dist[RoQ_ID_SLD] = index_mb(mb4,
00432 tempData->codebooks.unpacked_cb4,
00433 tempData->codebooks.numCB4,
00434 &subcel->cbEntry, 4);
00435
00436 subcel->eval_dist[RoQ_ID_CCC] = 0;
00437
00438 for(i=0;i<4;i++) {
00439 subcel->subCels[i] = tempData->closest_cb2[cluster_index*4+i];
00440
00441 get_frame_mb(enc->frame_to_enc, x+2*(i&1),
00442 y+(i&2), mb2, 2);
00443
00444 subcel->eval_dist[RoQ_ID_CCC] +=
00445 squared_diff_macroblock(tempData->codebooks.unpacked_cb2 + subcel->subCels[i]*2*2*3, mb2, 2);
00446 }
00447
00448 best_dist = INT_MAX;
00449 for (i=0; i<4; i++)
00450 if (ROQ_LAMBDA_SCALE*subcel->eval_dist[i] + enc->lambda*bitsUsed[i] <
00451 best_dist) {
00452 subcel->best_coding = i;
00453 subcel->best_bit_use = bitsUsed[i];
00454 best_dist = ROQ_LAMBDA_SCALE*subcel->eval_dist[i] +
00455 enc->lambda*bitsUsed[i];
00456 }
00457 }
00458
00462 static void gather_data_for_cel(CelEvaluation *cel, RoqContext *enc,
00463 RoqTempdata *tempData)
00464 {
00465 uint8_t mb8[8*8*3];
00466 int index = cel->sourceY*enc->width/64 + cel->sourceX/8;
00467 int i, j, best_dist, divide_bit_use;
00468
00469 int bitsUsed[4] = {2, 10, 10, 0};
00470
00471 if (enc->framesSinceKeyframe >= 1) {
00472 cel->motion = enc->this_motion8[index];
00473
00474 cel->eval_dist[RoQ_ID_FCC] =
00475 eval_motion_dist(enc, cel->sourceX, cel->sourceY,
00476 enc->this_motion8[index], 8);
00477 } else
00478 cel->eval_dist[RoQ_ID_FCC] = INT_MAX;
00479
00480 if (enc->framesSinceKeyframe >= 2)
00481 cel->eval_dist[RoQ_ID_MOT] = block_sse(enc->frame_to_enc->data,
00482 enc->current_frame->data,
00483 cel->sourceX, cel->sourceY,
00484 cel->sourceX, cel->sourceY,
00485 enc->frame_to_enc->linesize,
00486 enc->current_frame->linesize,8);
00487 else
00488 cel->eval_dist[RoQ_ID_MOT] = INT_MAX;
00489
00490 get_frame_mb(enc->frame_to_enc, cel->sourceX, cel->sourceY, mb8, 8);
00491
00492 cel->eval_dist[RoQ_ID_SLD] =
00493 index_mb(mb8, tempData->codebooks.unpacked_cb4_enlarged,
00494 tempData->codebooks.numCB4, &cel->cbEntry, 8);
00495
00496 gather_data_for_subcel(cel->subCels + 0, cel->sourceX+0, cel->sourceY+0, enc, tempData);
00497 gather_data_for_subcel(cel->subCels + 1, cel->sourceX+4, cel->sourceY+0, enc, tempData);
00498 gather_data_for_subcel(cel->subCels + 2, cel->sourceX+0, cel->sourceY+4, enc, tempData);
00499 gather_data_for_subcel(cel->subCels + 3, cel->sourceX+4, cel->sourceY+4, enc, tempData);
00500
00501 cel->eval_dist[RoQ_ID_CCC] = 0;
00502 divide_bit_use = 0;
00503 for (i=0; i<4; i++) {
00504 cel->eval_dist[RoQ_ID_CCC] +=
00505 cel->subCels[i].eval_dist[cel->subCels[i].best_coding];
00506 divide_bit_use += cel->subCels[i].best_bit_use;
00507 }
00508
00509 best_dist = INT_MAX;
00510 bitsUsed[3] = 2 + divide_bit_use;
00511
00512 for (i=0; i<4; i++)
00513 if (ROQ_LAMBDA_SCALE*cel->eval_dist[i] + enc->lambda*bitsUsed[i] <
00514 best_dist) {
00515 cel->best_coding = i;
00516 best_dist = ROQ_LAMBDA_SCALE*cel->eval_dist[i] +
00517 enc->lambda*bitsUsed[i];
00518 }
00519
00520 tempData->used_option[cel->best_coding]++;
00521 tempData->mainChunkSize += bitsUsed[cel->best_coding];
00522
00523 if (cel->best_coding == RoQ_ID_SLD)
00524 tempData->codebooks.usedCB4[cel->cbEntry]++;
00525
00526 if (cel->best_coding == RoQ_ID_CCC)
00527 for (i=0; i<4; i++) {
00528 if (cel->subCels[i].best_coding == RoQ_ID_SLD)
00529 tempData->codebooks.usedCB4[cel->subCels[i].cbEntry]++;
00530 else if (cel->subCels[i].best_coding == RoQ_ID_CCC)
00531 for (j=0; j<4; j++)
00532 tempData->codebooks.usedCB2[cel->subCels[i].subCels[j]]++;
00533 }
00534 }
00535
00536 static void remap_codebooks(RoqContext *enc, RoqTempdata *tempData)
00537 {
00538 int i, j, idx=0;
00539
00540
00541 for (i=0; i<MAX_CBS_4x4; i++) {
00542 if (tempData->codebooks.usedCB4[i]) {
00543 tempData->i2f4[i] = idx;
00544 tempData->f2i4[idx] = i;
00545 for (j=0; j<4; j++)
00546 tempData->codebooks.usedCB2[enc->cb4x4[i].idx[j]]++;
00547 idx++;
00548 }
00549 }
00550
00551 tempData->numCB4 = idx;
00552
00553 idx = 0;
00554 for (i=0; i<MAX_CBS_2x2; i++) {
00555 if (tempData->codebooks.usedCB2[i]) {
00556 tempData->i2f2[i] = idx;
00557 tempData->f2i2[idx] = i;
00558 idx++;
00559 }
00560 }
00561 tempData->numCB2 = idx;
00562
00563 }
00564
00568 static void write_codebooks(RoqContext *enc, RoqTempdata *tempData)
00569 {
00570 int i, j;
00571 uint8_t **outp= &enc->out_buf;
00572
00573 if (tempData->numCB2) {
00574 bytestream_put_le16(outp, RoQ_QUAD_CODEBOOK);
00575 bytestream_put_le32(outp, tempData->numCB2*6 + tempData->numCB4*4);
00576 bytestream_put_byte(outp, tempData->numCB4);
00577 bytestream_put_byte(outp, tempData->numCB2);
00578
00579 for (i=0; i<tempData->numCB2; i++) {
00580 bytestream_put_buffer(outp, enc->cb2x2[tempData->f2i2[i]].y, 4);
00581 bytestream_put_byte(outp, enc->cb2x2[tempData->f2i2[i]].u);
00582 bytestream_put_byte(outp, enc->cb2x2[tempData->f2i2[i]].v);
00583 }
00584
00585 for (i=0; i<tempData->numCB4; i++)
00586 for (j=0; j<4; j++)
00587 bytestream_put_byte(outp, tempData->i2f2[enc->cb4x4[tempData->f2i4[i]].idx[j]]);
00588
00589 }
00590 }
00591
00592 static inline uint8_t motion_arg(motion_vect mot)
00593 {
00594 uint8_t ax = 8 - ((uint8_t) mot.d[0]);
00595 uint8_t ay = 8 - ((uint8_t) mot.d[1]);
00596 return ((ax&15)<<4) | (ay&15);
00597 }
00598
00599 typedef struct
00600 {
00601 int typeSpool;
00602 int typeSpoolLength;
00603 uint8_t argumentSpool[64];
00604 uint8_t *args;
00605 uint8_t **pout;
00606 } CodingSpool;
00607
00608
00609 static void write_typecode(CodingSpool *s, uint8_t type)
00610 {
00611 s->typeSpool |= (type & 3) << (14 - s->typeSpoolLength);
00612 s->typeSpoolLength += 2;
00613 if (s->typeSpoolLength == 16) {
00614 bytestream_put_le16(s->pout, s->typeSpool);
00615 bytestream_put_buffer(s->pout, s->argumentSpool,
00616 s->args - s->argumentSpool);
00617 s->typeSpoolLength = 0;
00618 s->typeSpool = 0;
00619 s->args = s->argumentSpool;
00620 }
00621 }
00622
00623 static void reconstruct_and_encode_image(RoqContext *enc, RoqTempdata *tempData, int w, int h, int numBlocks)
00624 {
00625 int i, j, k;
00626 int x, y;
00627 int subX, subY;
00628 int dist=0;
00629
00630 roq_qcell *qcell;
00631 CelEvaluation *eval;
00632
00633 CodingSpool spool;
00634
00635 spool.typeSpool=0;
00636 spool.typeSpoolLength=0;
00637 spool.args = spool.argumentSpool;
00638 spool.pout = &enc->out_buf;
00639
00640 if (tempData->used_option[RoQ_ID_CCC]%2)
00641 tempData->mainChunkSize+=8;
00642
00643
00644 bytestream_put_le16(&enc->out_buf, RoQ_QUAD_VQ);
00645 bytestream_put_le32(&enc->out_buf, tempData->mainChunkSize/8);
00646 bytestream_put_byte(&enc->out_buf, 0x0);
00647 bytestream_put_byte(&enc->out_buf, 0x0);
00648
00649 for (i=0; i<numBlocks; i++) {
00650 eval = tempData->cel_evals + i;
00651
00652 x = eval->sourceX;
00653 y = eval->sourceY;
00654 dist += eval->eval_dist[eval->best_coding];
00655
00656 switch (eval->best_coding) {
00657 case RoQ_ID_MOT:
00658 write_typecode(&spool, RoQ_ID_MOT);
00659 break;
00660
00661 case RoQ_ID_FCC:
00662 bytestream_put_byte(&spool.args, motion_arg(eval->motion));
00663
00664 write_typecode(&spool, RoQ_ID_FCC);
00665 ff_apply_motion_8x8(enc, x, y,
00666 eval->motion.d[0], eval->motion.d[1]);
00667 break;
00668
00669 case RoQ_ID_SLD:
00670 bytestream_put_byte(&spool.args, tempData->i2f4[eval->cbEntry]);
00671 write_typecode(&spool, RoQ_ID_SLD);
00672
00673 qcell = enc->cb4x4 + eval->cbEntry;
00674 ff_apply_vector_4x4(enc, x , y , enc->cb2x2 + qcell->idx[0]);
00675 ff_apply_vector_4x4(enc, x+4, y , enc->cb2x2 + qcell->idx[1]);
00676 ff_apply_vector_4x4(enc, x , y+4, enc->cb2x2 + qcell->idx[2]);
00677 ff_apply_vector_4x4(enc, x+4, y+4, enc->cb2x2 + qcell->idx[3]);
00678 break;
00679
00680 case RoQ_ID_CCC:
00681 write_typecode(&spool, RoQ_ID_CCC);
00682
00683 for (j=0; j<4; j++) {
00684 subX = x + 4*(j&1);
00685 subY = y + 2*(j&2);
00686
00687 switch(eval->subCels[j].best_coding) {
00688 case RoQ_ID_MOT:
00689 break;
00690
00691 case RoQ_ID_FCC:
00692 bytestream_put_byte(&spool.args,
00693 motion_arg(eval->subCels[j].motion));
00694
00695 ff_apply_motion_4x4(enc, subX, subY,
00696 eval->subCels[j].motion.d[0],
00697 eval->subCels[j].motion.d[1]);
00698 break;
00699
00700 case RoQ_ID_SLD:
00701 bytestream_put_byte(&spool.args,
00702 tempData->i2f4[eval->subCels[j].cbEntry]);
00703
00704 qcell = enc->cb4x4 + eval->subCels[j].cbEntry;
00705
00706 ff_apply_vector_2x2(enc, subX , subY ,
00707 enc->cb2x2 + qcell->idx[0]);
00708 ff_apply_vector_2x2(enc, subX+2, subY ,
00709 enc->cb2x2 + qcell->idx[1]);
00710 ff_apply_vector_2x2(enc, subX , subY+2,
00711 enc->cb2x2 + qcell->idx[2]);
00712 ff_apply_vector_2x2(enc, subX+2, subY+2,
00713 enc->cb2x2 + qcell->idx[3]);
00714 break;
00715
00716 case RoQ_ID_CCC:
00717 for (k=0; k<4; k++) {
00718 int cb_idx = eval->subCels[j].subCels[k];
00719 bytestream_put_byte(&spool.args,
00720 tempData->i2f2[cb_idx]);
00721
00722 ff_apply_vector_2x2(enc, subX + 2*(k&1), subY + (k&2),
00723 enc->cb2x2 + cb_idx);
00724 }
00725 break;
00726 }
00727 write_typecode(&spool, eval->subCels[j].best_coding);
00728 }
00729 break;
00730 }
00731 }
00732
00733
00734 while (spool.typeSpoolLength)
00735 write_typecode(&spool, 0x0);
00736
00737 #if 0
00738 uint8_t *fdata[3] = {enc->frame_to_enc->data[0],
00739 enc->frame_to_enc->data[1],
00740 enc->frame_to_enc->data[2]};
00741 uint8_t *cdata[3] = {enc->current_frame->data[0],
00742 enc->current_frame->data[1],
00743 enc->current_frame->data[2]};
00744 av_log(enc->avctx, AV_LOG_ERROR, "Expected distortion: %i Actual: %i\n",
00745 dist,
00746 block_sse(fdata, cdata, 0, 0, 0, 0,
00747 enc->frame_to_enc->linesize,
00748 enc->current_frame->linesize,
00749 enc->width));
00750 #endif
00751 }
00752
00753
00757 static inline void frame_block_to_cell(uint8_t *block, uint8_t **data,
00758 int top, int left, int *stride)
00759 {
00760 int i, j, u=0, v=0;
00761
00762 for (i=0; i<2; i++)
00763 for (j=0; j<2; j++) {
00764 int x = (top+i)*stride[0] + left + j;
00765 *block++ = data[0][x];
00766 x = (top+i)*stride[1] + left + j;
00767 u += data[1][x];
00768 v += data[2][x];
00769 }
00770
00771 *block++ = (u+2)/4;
00772 *block++ = (v+2)/4;
00773 }
00774
00778 static void create_clusters(AVFrame *frame, int w, int h, uint8_t *yuvClusters)
00779 {
00780 int i, j, k, l;
00781
00782 for (i=0; i<h; i+=4)
00783 for (j=0; j<w; j+=4) {
00784 for (k=0; k < 2; k++)
00785 for (l=0; l < 2; l++)
00786 frame_block_to_cell(yuvClusters + (l + 2*k)*6, frame->data,
00787 i+2*k, j+2*l, frame->linesize);
00788 yuvClusters += 24;
00789 }
00790 }
00791
00792 static void generate_codebook(RoqContext *enc, RoqTempdata *tempdata,
00793 int *points, int inputCount, roq_cell *results,
00794 int size, int cbsize)
00795 {
00796 int i, j, k;
00797 int c_size = size*size/4;
00798 int *buf;
00799 int *codebook = av_malloc(6*c_size*cbsize*sizeof(int));
00800 int *closest_cb;
00801
00802 if (size == 4)
00803 closest_cb = av_malloc(6*c_size*inputCount*sizeof(int));
00804 else
00805 closest_cb = tempdata->closest_cb2;
00806
00807 ff_init_elbg(points, 6*c_size, inputCount, codebook, cbsize, 1, closest_cb, &enc->randctx);
00808 ff_do_elbg(points, 6*c_size, inputCount, codebook, cbsize, 1, closest_cb, &enc->randctx);
00809
00810 if (size == 4)
00811 av_free(closest_cb);
00812
00813 buf = codebook;
00814 for (i=0; i<cbsize; i++)
00815 for (k=0; k<c_size; k++) {
00816 for(j=0; j<4; j++)
00817 results->y[j] = *buf++;
00818
00819 results->u = (*buf++ + CHROMA_BIAS/2)/CHROMA_BIAS;
00820 results->v = (*buf++ + CHROMA_BIAS/2)/CHROMA_BIAS;
00821 results++;
00822 }
00823
00824 av_free(codebook);
00825 }
00826
00827 static void generate_new_codebooks(RoqContext *enc, RoqTempdata *tempData)
00828 {
00829 int i,j;
00830 RoqCodebooks *codebooks = &tempData->codebooks;
00831 int max = enc->width*enc->height/16;
00832 uint8_t mb2[3*4];
00833 roq_cell *results4 = av_malloc(sizeof(roq_cell)*MAX_CBS_4x4*4);
00834 uint8_t *yuvClusters=av_malloc(sizeof(int)*max*6*4);
00835 int *points = av_malloc(max*6*4*sizeof(int));
00836 int bias;
00837
00838
00839 create_clusters(enc->frame_to_enc, enc->width, enc->height, yuvClusters);
00840
00841
00842 for (i=0; i<max*24; i++) {
00843 bias = ((i%6)<4) ? 1 : CHROMA_BIAS;
00844 points[i] = bias*yuvClusters[i];
00845 }
00846
00847
00848 generate_codebook(enc, tempData, points, max, results4, 4, MAX_CBS_4x4);
00849
00850 codebooks->numCB4 = MAX_CBS_4x4;
00851
00852 tempData->closest_cb2 = av_malloc(max*4*sizeof(int));
00853
00854
00855 generate_codebook(enc, tempData, points, max*4, enc->cb2x2, 2, MAX_CBS_2x2);
00856
00857 codebooks->numCB2 = MAX_CBS_2x2;
00858
00859
00860 for (i=0; i<codebooks->numCB2; i++)
00861 unpack_roq_cell(enc->cb2x2 + i, codebooks->unpacked_cb2 + i*2*2*3);
00862
00863
00864 for (i=0; i<codebooks->numCB4; i++) {
00865 for (j=0; j<4; j++) {
00866 unpack_roq_cell(&results4[4*i + j], mb2);
00867 index_mb(mb2, codebooks->unpacked_cb2, codebooks->numCB2,
00868 &enc->cb4x4[i].idx[j], 2);
00869 }
00870 unpack_roq_qcell(codebooks->unpacked_cb2, enc->cb4x4 + i,
00871 codebooks->unpacked_cb4 + i*4*4*3);
00872 enlarge_roq_mb4(codebooks->unpacked_cb4 + i*4*4*3,
00873 codebooks->unpacked_cb4_enlarged + i*8*8*3);
00874 }
00875
00876 av_free(yuvClusters);
00877 av_free(points);
00878 av_free(results4);
00879 }
00880
00881 static void roq_encode_video(RoqContext *enc)
00882 {
00883 RoqTempdata *tempData = enc->tmpData;
00884 int i;
00885
00886 memset(tempData, 0, sizeof(*tempData));
00887
00888 create_cel_evals(enc, tempData);
00889
00890 generate_new_codebooks(enc, tempData);
00891
00892 if (enc->framesSinceKeyframe >= 1) {
00893 motion_search(enc, 8);
00894 motion_search(enc, 4);
00895 }
00896
00897 retry_encode:
00898 for (i=0; i<enc->width*enc->height/64; i++)
00899 gather_data_for_cel(tempData->cel_evals + i, enc, tempData);
00900
00901
00902 if (tempData->mainChunkSize/8 > 65535) {
00903 av_log(enc->avctx, AV_LOG_ERROR,
00904 "Warning, generated a frame too big (%d > 65535), "
00905 "try using a smaller qscale value.\n",
00906 tempData->mainChunkSize/8);
00907 enc->lambda *= 1.5;
00908 tempData->mainChunkSize = 0;
00909 memset(tempData->used_option, 0, sizeof(tempData->used_option));
00910 memset(tempData->codebooks.usedCB4, 0,
00911 sizeof(tempData->codebooks.usedCB4));
00912 memset(tempData->codebooks.usedCB2, 0,
00913 sizeof(tempData->codebooks.usedCB2));
00914
00915 goto retry_encode;
00916 }
00917
00918 remap_codebooks(enc, tempData);
00919
00920 write_codebooks(enc, tempData);
00921
00922 reconstruct_and_encode_image(enc, tempData, enc->width, enc->height,
00923 enc->width*enc->height/64);
00924
00925 enc->avctx->coded_frame = enc->current_frame;
00926
00927
00928 FFSWAP(AVFrame *, enc->current_frame, enc->last_frame);
00929 FFSWAP(motion_vect *, enc->last_motion4, enc->this_motion4);
00930 FFSWAP(motion_vect *, enc->last_motion8, enc->this_motion8);
00931
00932 av_free(tempData->cel_evals);
00933 av_free(tempData->closest_cb2);
00934
00935 enc->framesSinceKeyframe++;
00936 }
00937
00938 static int roq_encode_init(AVCodecContext *avctx)
00939 {
00940 RoqContext *enc = avctx->priv_data;
00941
00942 av_lfg_init(&enc->randctx, 1);
00943
00944 enc->framesSinceKeyframe = 0;
00945 if ((avctx->width & 0xf) || (avctx->height & 0xf)) {
00946 av_log(avctx, AV_LOG_ERROR, "Dimensions must be divisible by 16\n");
00947 return -1;
00948 }
00949
00950 if (((avctx->width)&(avctx->width-1))||((avctx->height)&(avctx->height-1)))
00951 av_log(avctx, AV_LOG_ERROR, "Warning: dimensions not power of two\n");
00952
00953 enc->width = avctx->width;
00954 enc->height = avctx->height;
00955
00956 enc->framesSinceKeyframe = 0;
00957 enc->first_frame = 1;
00958
00959 enc->last_frame = &enc->frames[0];
00960 enc->current_frame = &enc->frames[1];
00961
00962 enc->tmpData = av_malloc(sizeof(RoqTempdata));
00963
00964 enc->this_motion4 =
00965 av_mallocz((enc->width*enc->height/16)*sizeof(motion_vect));
00966
00967 enc->last_motion4 =
00968 av_malloc ((enc->width*enc->height/16)*sizeof(motion_vect));
00969
00970 enc->this_motion8 =
00971 av_mallocz((enc->width*enc->height/64)*sizeof(motion_vect));
00972
00973 enc->last_motion8 =
00974 av_malloc ((enc->width*enc->height/64)*sizeof(motion_vect));
00975
00976 return 0;
00977 }
00978
00979 static void roq_write_video_info_chunk(RoqContext *enc)
00980 {
00981
00982 bytestream_put_le16(&enc->out_buf, RoQ_INFO);
00983
00984
00985 bytestream_put_le32(&enc->out_buf, 8);
00986
00987
00988 bytestream_put_byte(&enc->out_buf, 0x00);
00989 bytestream_put_byte(&enc->out_buf, 0x00);
00990
00991
00992 bytestream_put_le16(&enc->out_buf, enc->width);
00993
00994
00995 bytestream_put_le16(&enc->out_buf, enc->height);
00996
00997
00998 bytestream_put_byte(&enc->out_buf, 0x08);
00999 bytestream_put_byte(&enc->out_buf, 0x00);
01000 bytestream_put_byte(&enc->out_buf, 0x04);
01001 bytestream_put_byte(&enc->out_buf, 0x00);
01002 }
01003
01004 static int roq_encode_frame(AVCodecContext *avctx, unsigned char *buf, int buf_size, void *data)
01005 {
01006 RoqContext *enc = avctx->priv_data;
01007 AVFrame *frame= data;
01008 uint8_t *buf_start = buf;
01009
01010 enc->out_buf = buf;
01011 enc->avctx = avctx;
01012
01013 enc->frame_to_enc = frame;
01014
01015 if (frame->quality)
01016 enc->lambda = frame->quality - 1;
01017 else
01018 enc->lambda = 2*ROQ_LAMBDA_SCALE;
01019
01020
01021
01022 if (((enc->width*enc->height/64)*138+7)/8 + 256*(6+4) + 8 > buf_size) {
01023 av_log(avctx, AV_LOG_ERROR, " RoQ: Output buffer too small!\n");
01024 return -1;
01025 }
01026
01027
01028 if (enc->framesSinceKeyframe == avctx->gop_size)
01029 enc->framesSinceKeyframe = 0;
01030
01031 if (enc->first_frame) {
01032
01033
01034 if (avctx->get_buffer(avctx, enc->current_frame) ||
01035 avctx->get_buffer(avctx, enc->last_frame)) {
01036 av_log(avctx, AV_LOG_ERROR, " RoQ: get_buffer() failed\n");
01037 return -1;
01038 }
01039
01040
01041 roq_write_video_info_chunk(enc);
01042
01043 enc->first_frame = 0;
01044 }
01045
01046
01047 roq_encode_video(enc);
01048
01049 return enc->out_buf - buf_start;
01050 }
01051
01052 static int roq_encode_end(AVCodecContext *avctx)
01053 {
01054 RoqContext *enc = avctx->priv_data;
01055
01056 avctx->release_buffer(avctx, enc->last_frame);
01057 avctx->release_buffer(avctx, enc->current_frame);
01058
01059 av_free(enc->tmpData);
01060 av_free(enc->this_motion4);
01061 av_free(enc->last_motion4);
01062 av_free(enc->this_motion8);
01063 av_free(enc->last_motion8);
01064
01065 return 0;
01066 }
01067
01068 AVCodec ff_roq_encoder =
01069 {
01070 "roqvideo",
01071 AVMEDIA_TYPE_VIDEO,
01072 CODEC_ID_ROQ,
01073 sizeof(RoqContext),
01074 roq_encode_init,
01075 roq_encode_frame,
01076 roq_encode_end,
01077 .supported_framerates = (const AVRational[]){{30,1}, {0,0}},
01078 .pix_fmts = (const enum PixelFormat[]){PIX_FMT_YUV444P, PIX_FMT_NONE},
01079 .long_name = NULL_IF_CONFIG_SMALL("id RoQ video"),
01080 };