• Main Page
  • Related Pages
  • Modules
  • Data Structures
  • Files
  • File List
  • Globals

libavcodec/roqvideoenc.c

Go to the documentation of this file.
00001 /*
00002  * RoQ Video Encoder.
00003  *
00004  * Copyright (C) 2007 Vitor Sessak <vitor1001@gmail.com>
00005  * Copyright (C) 2004-2007 Eric Lasota
00006  *    Based on RoQ specs (C) 2001 Tim Ferguson
00007  *
00008  * This file is part of FFmpeg.
00009  *
00010  * FFmpeg is free software; you can redistribute it and/or
00011  * modify it under the terms of the GNU Lesser General Public
00012  * License as published by the Free Software Foundation; either
00013  * version 2.1 of the License, or (at your option) any later version.
00014  *
00015  * FFmpeg is distributed in the hope that it will be useful,
00016  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00017  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00018  * Lesser General Public License for more details.
00019  *
00020  * You should have received a copy of the GNU Lesser General Public
00021  * License along with FFmpeg; if not, write to the Free Software
00022  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
00023  */
00024 
00031 /*
00032  * COSTS:
00033  * Level 1:
00034  *  SKIP - 2 bits
00035  *  MOTION - 2 + 8 bits
00036  *  CODEBOOK - 2 + 8 bits
00037  *  SUBDIVIDE - 2 + combined subcel cost
00038  *
00039  * Level 2:
00040  *  SKIP - 2 bits
00041  *  MOTION - 2 + 8 bits
00042  *  CODEBOOK - 2 + 8 bits
00043  *  SUBDIVIDE - 2 + 4*8 bits
00044  *
00045  * Maximum cost: 138 bits per cel
00046  *
00047  * Proper evaluation requires LCD fraction comparison, which requires
00048  * Squared Error (SE) loss * savings increase
00049  *
00050  * Maximum savings increase: 136 bits
00051  * Maximum SE loss without overflow: 31580641
00052  * Components in 8x8 supercel: 192
00053  * Maximum SE precision per component: 164482
00054  *    >65025, so no truncation is needed (phew)
00055  */
00056 
00057 #include <string.h>
00058 #include <unistd.h>
00059 
00060 #include "roqvideo.h"
00061 #include "bytestream.h"
00062 #include "elbg.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 ///< Maximum number of 2x2 codebooks.
00074 
00075 /* The cast is useful when multiplying it by INT_MAX */
00076 #define ROQ_LAMBDA_SCALE ((uint64_t) FF_LAMBDA_SCALE)
00077 
00078 /* Macroblock support functions */
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(uint8_t *a, 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 // FIXME Could use DSPContext.sse, but it is not so speed critical (used
00127 // just for motion estimation).
00128 static int block_sse(uint8_t **buf1, uint8_t **buf2, int x1, int y1, int x2,
00129                      int y2, int *stride1, 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     /* Map to the ROQ quadtree order */
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(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     /* Diff against the others */
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     /* Make remaps for the final codebook usage */
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 /* NOTE: Typecodes must be spooled AFTER arguments!! */
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; //FIXME
00643 
00644     /* Write the video chunk header */
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     /* Flush the remainder of the argument/type spool */
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));  //WARNING: Square dimensions implied...
00751 #endif
00752 }
00753 
00754 
00758 static inline void frame_block_to_cell(uint8_t *block, uint8_t **data,
00759                                        int top, int left, 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(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 = points;
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     /* Subsample YUV data */
00840     create_clusters(enc->frame_to_enc, enc->width, enc->height, yuvClusters);
00841 
00842     /* Cast to integer and apply chroma bias */
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     /* Create 4x4 codebooks */
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     /* Create 2x2 codebooks */
00856     generate_codebook(enc, tempData, points, max*4, enc->cb2x2, 2, MAX_CBS_2x2);
00857 
00858     codebooks->numCB2 = MAX_CBS_2x2;
00859 
00860     /* Unpack 2x2 codebook clusters */
00861     for (i=0; i<codebooks->numCB2; i++)
00862         unpack_roq_cell(enc->cb2x2 + i, codebooks->unpacked_cb2 + i*2*2*3);
00863 
00864     /* Index all 4x4 entries to the 2x2 entries, unpack, and enlarge */
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     /* Quake 3 can't handle chunks bigger than 65536 bytes */
00903     if (tempData->mainChunkSize/8 > 65536) {
00904         enc->lambda *= .8;
00905         goto retry_encode;
00906     }
00907 
00908     remap_codebooks(enc, tempData);
00909 
00910     write_codebooks(enc, tempData);
00911 
00912     reconstruct_and_encode_image(enc, tempData, enc->width, enc->height,
00913                                  enc->width*enc->height/64);
00914 
00915     enc->avctx->coded_frame = enc->current_frame;
00916 
00917     /* Rotate frame history */
00918     FFSWAP(AVFrame *, enc->current_frame, enc->last_frame);
00919     FFSWAP(motion_vect *, enc->last_motion4, enc->this_motion4);
00920     FFSWAP(motion_vect *, enc->last_motion8, enc->this_motion8);
00921 
00922     av_free(tempData->cel_evals);
00923     av_free(tempData->closest_cb2);
00924 
00925     enc->framesSinceKeyframe++;
00926 }
00927 
00928 static int roq_encode_init(AVCodecContext *avctx)
00929 {
00930     RoqContext *enc = avctx->priv_data;
00931 
00932     av_random_init(&enc->randctx, 1);
00933 
00934     enc->framesSinceKeyframe = 0;
00935     if ((avctx->width & 0xf) || (avctx->height & 0xf)) {
00936         av_log(avctx, AV_LOG_ERROR, "Dimensions must be divisible by 16\n");
00937         return -1;
00938     }
00939 
00940     if (((avctx->width)&(avctx->width-1))||((avctx->height)&(avctx->height-1)))
00941         av_log(avctx, AV_LOG_ERROR, "Warning: dimensions not power of two\n");
00942 
00943     if (avcodec_check_dimensions(avctx, avctx->width, avctx->height)) {
00944         av_log(avctx, AV_LOG_ERROR, "Invalid dimensions (%dx%d)\n",
00945                avctx->width, avctx->height);
00946         return -1;
00947     }
00948 
00949     enc->width = avctx->width;
00950     enc->height = avctx->height;
00951 
00952     enc->framesSinceKeyframe = 0;
00953     enc->first_frame = 1;
00954 
00955     enc->last_frame    = &enc->frames[0];
00956     enc->current_frame = &enc->frames[1];
00957 
00958     enc->tmpData      = av_malloc(sizeof(RoqTempdata));
00959 
00960     enc->this_motion4 =
00961         av_mallocz((enc->width*enc->height/16)*sizeof(motion_vect));
00962 
00963     enc->last_motion4 =
00964         av_malloc ((enc->width*enc->height/16)*sizeof(motion_vect));
00965 
00966     enc->this_motion8 =
00967         av_mallocz((enc->width*enc->height/64)*sizeof(motion_vect));
00968 
00969     enc->last_motion8 =
00970         av_malloc ((enc->width*enc->height/64)*sizeof(motion_vect));
00971 
00972     return 0;
00973 }
00974 
00975 static void roq_write_video_info_chunk(RoqContext *enc)
00976 {
00977     /* ROQ info chunk */
00978     bytestream_put_le16(&enc->out_buf, RoQ_INFO);
00979 
00980     /* Size: 8 bytes */
00981     bytestream_put_le32(&enc->out_buf, 8);
00982 
00983     /* Unused argument */
00984     bytestream_put_byte(&enc->out_buf, 0x00);
00985     bytestream_put_byte(&enc->out_buf, 0x00);
00986 
00987     /* Width */
00988     bytestream_put_le16(&enc->out_buf, enc->width);
00989 
00990     /* Height */
00991     bytestream_put_le16(&enc->out_buf, enc->height);
00992 
00993     /* Unused in Quake 3, mimics the output of the real encoder */
00994     bytestream_put_byte(&enc->out_buf, 0x08);
00995     bytestream_put_byte(&enc->out_buf, 0x00);
00996     bytestream_put_byte(&enc->out_buf, 0x04);
00997     bytestream_put_byte(&enc->out_buf, 0x00);
00998 }
00999 
01000 static int roq_encode_frame(AVCodecContext *avctx, unsigned char *buf, int buf_size, void *data)
01001 {
01002     RoqContext *enc = avctx->priv_data;
01003     AVFrame *frame= data;
01004     uint8_t *buf_start = buf;
01005 
01006     enc->out_buf = buf;
01007     enc->avctx = avctx;
01008 
01009     enc->frame_to_enc = frame;
01010 
01011     if (frame->quality)
01012         enc->lambda = frame->quality - 1;
01013     else
01014         enc->lambda = 2*ROQ_LAMBDA_SCALE;
01015 
01016     /* 138 bits max per 8x8 block +
01017      *     256 codebooks*(6 bytes 2x2 + 4 bytes 4x4) + 8 bytes frame header */
01018     if (((enc->width*enc->height/64)*138+7)/8 + 256*(6+4) + 8 > buf_size) {
01019         av_log(avctx, AV_LOG_ERROR, "  RoQ: Output buffer too small!\n");
01020         return -1;
01021     }
01022 
01023     /* Check for I frame */
01024     if (enc->framesSinceKeyframe == avctx->gop_size)
01025         enc->framesSinceKeyframe = 0;
01026 
01027     if (enc->first_frame) {
01028         /* Alloc memory for the reconstruction data (we must know the stride
01029          for that) */
01030         if (avctx->get_buffer(avctx, enc->current_frame) ||
01031             avctx->get_buffer(avctx, enc->last_frame)) {
01032             av_log(avctx, AV_LOG_ERROR, "  RoQ: get_buffer() failed\n");
01033             return -1;
01034         }
01035 
01036         /* Before the first video frame, write a "video info" chunk */
01037         roq_write_video_info_chunk(enc);
01038 
01039         enc->first_frame = 0;
01040     }
01041 
01042     /* Encode the actual frame */
01043     roq_encode_video(enc);
01044 
01045     return enc->out_buf - buf_start;
01046 }
01047 
01048 static int roq_encode_end(AVCodecContext *avctx)
01049 {
01050     RoqContext *enc = avctx->priv_data;
01051 
01052     avctx->release_buffer(avctx, enc->last_frame);
01053     avctx->release_buffer(avctx, enc->current_frame);
01054 
01055     av_free(enc->tmpData);
01056     av_free(enc->this_motion4);
01057     av_free(enc->last_motion4);
01058     av_free(enc->this_motion8);
01059     av_free(enc->last_motion8);
01060 
01061     return 0;
01062 }
01063 
01064 AVCodec roq_encoder =
01065 {
01066     "roqvideo",
01067     CODEC_TYPE_VIDEO,
01068     CODEC_ID_ROQ,
01069     sizeof(RoqContext),
01070     roq_encode_init,
01071     roq_encode_frame,
01072     roq_encode_end,
01073     .supported_framerates = (AVRational[]){{30,1}, {0,0}},
01074     .pix_fmts = (enum PixelFormat[]){PIX_FMT_YUV444P, PIX_FMT_NONE},
01075     .long_name = NULL_IF_CONFIG_SMALL("id RoQ video"),
01076 };

Generated on Tue Nov 4 2014 12:59:22 for ffmpeg by  doxygen 1.7.1