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