📄 roqvideoenc.c
字号:
EVAL_MOTION(last_motion[offset]); off[0]= (i/blocksize)*enc->width/blocksize + j/blocksize - 1; off[1]= off[0] - enc->width/blocksize + 1; off[2]= off[1] + 1; if (i) { for(k=0; k<2; k++) vect.d[k]= mid_pred(this_motion[off[0]].d[k], this_motion[off[1]].d[k], this_motion[off[2]].d[k]); EVAL_MOTION(vect); for(k=0; k<3; k++) EVAL_MOTION(this_motion[off[k]]); } else if(j) EVAL_MOTION(this_motion[off[0]]); vect = bestpick; oldbest = -1; while (oldbest != lowestdiff) { oldbest = lowestdiff; for (k=0; k<8; k++) { vect2 = vect; vect2.d[0] += offsets[k].d[0]; vect2.d[1] += offsets[k].d[1]; EVAL_MOTION(vect2); } vect = bestpick; } offset = (i/blocksize)*enc->width/blocksize + j/blocksize; this_motion[offset] = bestpick; }}/** * Gets distortion for all options available to a subcel */static void gather_data_for_subcel(subcel_evaluation_t *subcel, int x, int y, RoqContext *enc, roq_tempdata_t *tempData){ uint8_t mb4[4*4*3]; uint8_t mb2[2*2*3]; int cluster_index; int i, best_dist; static const int bitsUsed[4] = {2, 10, 10, 34}; if (enc->framesSinceKeyframe >= 1) { subcel->motion = enc->this_motion4[y*enc->width/16 + x/4]; subcel->eval_dist[RoQ_ID_FCC] = eval_motion_dist(enc, x, y, enc->this_motion4[y*enc->width/16 + x/4], 4); } else subcel->eval_dist[RoQ_ID_FCC] = INT_MAX; if (enc->framesSinceKeyframe >= 2) subcel->eval_dist[RoQ_ID_MOT] = block_sse(enc->frame_to_enc->data, enc->current_frame->data, x, y, x, y, enc->frame_to_enc->linesize, enc->current_frame->linesize, 4); else subcel->eval_dist[RoQ_ID_MOT] = INT_MAX; cluster_index = y*enc->width/16 + x/4; get_frame_mb(enc->frame_to_enc, x, y, mb4, 4); subcel->eval_dist[RoQ_ID_SLD] = index_mb(mb4, tempData->codebooks.unpacked_cb4, tempData->codebooks.numCB4, &subcel->cbEntry, 4); subcel->eval_dist[RoQ_ID_CCC] = 0; for(i=0;i<4;i++) { subcel->subCels[i] = tempData->closest_cb2[cluster_index*4+i]; get_frame_mb(enc->frame_to_enc, x+2*(i&1), y+(i&2), mb2, 2); subcel->eval_dist[RoQ_ID_CCC] += squared_diff_macroblock(tempData->codebooks.unpacked_cb2 + subcel->subCels[i]*2*2*3, mb2, 2); } best_dist = INT_MAX; for (i=0; i<4; i++) if (ROQ_LAMBDA_SCALE*subcel->eval_dist[i] + enc->lambda*bitsUsed[i] < best_dist) { subcel->best_coding = i; subcel->best_bit_use = bitsUsed[i]; best_dist = ROQ_LAMBDA_SCALE*subcel->eval_dist[i] + enc->lambda*bitsUsed[i]; }}/** * Gets distortion for all options available to a cel */static void gather_data_for_cel(cel_evaluation_t *cel, RoqContext *enc, roq_tempdata_t *tempData){ uint8_t mb8[8*8*3]; int index = cel->sourceY*enc->width/64 + cel->sourceX/8; int i, j, best_dist, divide_bit_use; int bitsUsed[4] = {2, 10, 10, 0}; if (enc->framesSinceKeyframe >= 1) { cel->motion = enc->this_motion8[index]; cel->eval_dist[RoQ_ID_FCC] = eval_motion_dist(enc, cel->sourceX, cel->sourceY, enc->this_motion8[index], 8); } else cel->eval_dist[RoQ_ID_FCC] = INT_MAX; if (enc->framesSinceKeyframe >= 2) cel->eval_dist[RoQ_ID_MOT] = block_sse(enc->frame_to_enc->data, enc->current_frame->data, cel->sourceX, cel->sourceY, cel->sourceX, cel->sourceY, enc->frame_to_enc->linesize, enc->current_frame->linesize,8); else cel->eval_dist[RoQ_ID_MOT] = INT_MAX; get_frame_mb(enc->frame_to_enc, cel->sourceX, cel->sourceY, mb8, 8); cel->eval_dist[RoQ_ID_SLD] = index_mb(mb8, tempData->codebooks.unpacked_cb4_enlarged, tempData->codebooks.numCB4, &cel->cbEntry, 8); gather_data_for_subcel(cel->subCels + 0, cel->sourceX+0, cel->sourceY+0, enc, tempData); gather_data_for_subcel(cel->subCels + 1, cel->sourceX+4, cel->sourceY+0, enc, tempData); gather_data_for_subcel(cel->subCels + 2, cel->sourceX+0, cel->sourceY+4, enc, tempData); gather_data_for_subcel(cel->subCels + 3, cel->sourceX+4, cel->sourceY+4, enc, tempData); cel->eval_dist[RoQ_ID_CCC] = 0; divide_bit_use = 0; for (i=0; i<4; i++) { cel->eval_dist[RoQ_ID_CCC] += cel->subCels[i].eval_dist[cel->subCels[i].best_coding]; divide_bit_use += cel->subCels[i].best_bit_use; } best_dist = INT_MAX; bitsUsed[3] = 2 + divide_bit_use; for (i=0; i<4; i++) if (ROQ_LAMBDA_SCALE*cel->eval_dist[i] + enc->lambda*bitsUsed[i] < best_dist) { cel->best_coding = i; best_dist = ROQ_LAMBDA_SCALE*cel->eval_dist[i] + enc->lambda*bitsUsed[i]; } tempData->used_option[cel->best_coding]++; tempData->mainChunkSize += bitsUsed[cel->best_coding]; if (cel->best_coding == RoQ_ID_SLD) tempData->codebooks.usedCB4[cel->cbEntry]++; if (cel->best_coding == RoQ_ID_CCC) for (i=0; i<4; i++) { if (cel->subCels[i].best_coding == RoQ_ID_SLD) tempData->codebooks.usedCB4[cel->subCels[i].cbEntry]++; else if (cel->subCels[i].best_coding == RoQ_ID_CCC) for (j=0; j<4; j++) tempData->codebooks.usedCB2[cel->subCels[i].subCels[j]]++; }}static void remap_codebooks(RoqContext *enc, roq_tempdata_t *tempData){ int i, j, idx=0; /* Make remaps for the final codebook usage */ for (i=0; i<MAX_CBS_4x4; i++) { if (tempData->codebooks.usedCB4[i]) { tempData->i2f4[i] = idx; tempData->f2i4[idx] = i; for (j=0; j<4; j++) tempData->codebooks.usedCB2[enc->cb4x4[i].idx[j]]++; idx++; } } tempData->numCB4 = idx; idx = 0; for (i=0; i<MAX_CBS_2x2; i++) { if (tempData->codebooks.usedCB2[i]) { tempData->i2f2[i] = idx; tempData->f2i2[idx] = i; idx++; } } tempData->numCB2 = idx;}/** * Write codebook chunk */static void write_codebooks(RoqContext *enc, roq_tempdata_t *tempData){ int i, j; uint8_t **outp= &enc->out_buf; if (tempData->numCB2) { bytestream_put_le16(outp, RoQ_QUAD_CODEBOOK); bytestream_put_le32(outp, tempData->numCB2*6 + tempData->numCB4*4); bytestream_put_byte(outp, tempData->numCB4); bytestream_put_byte(outp, tempData->numCB2); for (i=0; i<tempData->numCB2; i++) { bytestream_put_buffer(outp, enc->cb2x2[tempData->f2i2[i]].y, 4); bytestream_put_byte(outp, enc->cb2x2[tempData->f2i2[i]].u); bytestream_put_byte(outp, enc->cb2x2[tempData->f2i2[i]].v); } for (i=0; i<tempData->numCB4; i++) for (j=0; j<4; j++) bytestream_put_byte(outp, tempData->i2f2[enc->cb4x4[tempData->f2i4[i]].idx[j]]); }}static inline uint8_t motion_arg(motion_vect mot){ uint8_t ax = 8 - ((uint8_t) mot.d[0]); uint8_t ay = 8 - ((uint8_t) mot.d[1]); return ((ax&15)<<4) | (ay&15);}typedef struct{ int typeSpool; int typeSpoolLength; uint8_t argumentSpool[64]; uint8_t *args; uint8_t **pout;} CodingSpool;/* NOTE: Typecodes must be spooled AFTER arguments!! */static void write_typecode(CodingSpool *s, uint8_t type){ s->typeSpool |= (type & 3) << (14 - s->typeSpoolLength); s->typeSpoolLength += 2; if (s->typeSpoolLength == 16) { bytestream_put_le16(s->pout, s->typeSpool); bytestream_put_buffer(s->pout, s->argumentSpool, s->args - s->argumentSpool); s->typeSpoolLength = 0; s->typeSpool = 0; s->args = s->argumentSpool; }}static void reconstruct_and_encode_image(RoqContext *enc, roq_tempdata_t *tempData, int w, int h, int numBlocks){ int i, j, k; int x, y; int subX, subY; int dist=0; roq_qcell *qcell; cel_evaluation_t *eval; CodingSpool spool; spool.typeSpool=0; spool.typeSpoolLength=0; spool.args = spool.argumentSpool; spool.pout = &enc->out_buf; if (tempData->used_option[RoQ_ID_CCC]%2) tempData->mainChunkSize+=8; //FIXME /* Write the video chunk header */ bytestream_put_le16(&enc->out_buf, RoQ_QUAD_VQ); bytestream_put_le32(&enc->out_buf, tempData->mainChunkSize/8); bytestream_put_byte(&enc->out_buf, 0x0); bytestream_put_byte(&enc->out_buf, 0x0); for (i=0; i<numBlocks; i++) { eval = tempData->cel_evals + i; x = eval->sourceX; y = eval->sourceY; dist += eval->eval_dist[eval->best_coding]; switch (eval->best_coding) { case RoQ_ID_MOT: write_typecode(&spool, RoQ_ID_MOT); break; case RoQ_ID_FCC: bytestream_put_byte(&spool.args, motion_arg(eval->motion)); write_typecode(&spool, RoQ_ID_FCC); ff_apply_motion_8x8(enc, x, y, eval->motion.d[0], eval->motion.d[1]); break; case RoQ_ID_SLD: bytestream_put_byte(&spool.args, tempData->i2f4[eval->cbEntry]); write_typecode(&spool, RoQ_ID_SLD); qcell = enc->cb4x4 + eval->cbEntry; ff_apply_vector_4x4(enc, x , y , enc->cb2x2 + qcell->idx[0]); ff_apply_vector_4x4(enc, x+4, y , enc->cb2x2 + qcell->idx[1]); ff_apply_vector_4x4(enc, x , y+4, enc->cb2x2 + qcell->idx[2]); ff_apply_vector_4x4(enc, x+4, y+4, enc->cb2x2 + qcell->idx[3]); break; case RoQ_ID_CCC: write_typecode(&spool, RoQ_ID_CCC); for (j=0; j<4; j++) { subX = x + 4*(j&1); subY = y + 2*(j&2); switch(eval->subCels[j].best_coding) { case RoQ_ID_MOT: break; case RoQ_ID_FCC: bytestream_put_byte(&spool.args, motion_arg(eval->subCels[j].motion)); ff_apply_motion_4x4(enc, subX, subY, eval->subCels[j].motion.d[0], eval->subCels[j].motion.d[1]); break; case RoQ_ID_SLD: bytestream_put_byte(&spool.args, tempData->i2f4[eval->subCels[j].cbEntry]); qcell = enc->cb4x4 + eval->subCels[j].cbEntry; ff_apply_vector_2x2(enc, subX , subY , enc->cb2x2 + qcell->idx[0]); ff_apply_vector_2x2(enc, subX+2, subY , enc->cb2x2 + qcell->idx[1]); ff_apply_vector_2x2(enc, subX , subY+2, enc->cb2x2 + qcell->idx[2]); ff_apply_vector_2x2(enc, subX+2, subY+2, enc->cb2x2 + qcell->idx[3]); break;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -