#include "Decoder.h" #define sign(a) ((a) < 0 ? -1 : 1) /* private prototypes*/ static int motion_decode(int vec,int pmv); static void make_edge_image(const unsigned char *src, unsigned char *dst, int width, int height, int edge); /* decode one frame or field picture */ void Decoder::getpicture(Frame decodedFrame) { int i; unsigned char *tmp; for (i=0; i<3; i++) { tmp = oldrefframe[i]; oldrefframe[i] = refframe[i]; refframe[i] = tmp; newframe[i] = refframe[i]; } if (!firstFrame) { make_edge_image(oldrefframe[0],edgeframe[0],coded_picture_width, coded_picture_height,32); make_edge_image(oldrefframe[1],edgeframe[1],chrom_width, chrom_height,16); make_edge_image(oldrefframe[2],edgeframe[2],chrom_width, chrom_height,16); } //getMBs(); get_I_P_MBs(); if (deblock) edge_filter(newframe[0], newframe[1], newframe[2], coded_picture_width, coded_picture_height); /* PostFilter(newframe[0], newframe[1], newframe[2], coded_picture_width, coded_picture_height); */ decodedFrame[0] = newframe[0]; decodedFrame[1] = newframe[1]; decodedFrame[2] = newframe[2]; firstFrame=false; } /* decode all macroblocks of the current picture */ void Decoder::clearblock(int comp) { int *bp; int i; bp = (int *)block[comp]; for (i=0; i<8; i++) { bp[0] = bp[1] = bp[2] = bp[3] = 0; bp += 4; } } /* move/add 8x8-Block from block[comp] to refframe or bframe */ void Decoder::addblock(int comp, int bx, int by, int addflag) { int cc,i, iincr; unsigned char *rfp; short *bp; bp = block[comp]; /* TODO: benski> ippiCopy8x8_8u_C1R (addflag = 0) ippiAdd8x8_16s8u_C1IRS (addflag = 1) */ cc = (comp<4) ? 0 : (comp&1)+1; /* color component index */ if (cc==0) { /* luminance */ /* frame DCT coding */ rfp = newframe[0] + coded_picture_width*(by+((comp&2)<<2)) + bx + ((comp&1)<<3); iincr = coded_picture_width; } else { /* chrominance */ /* scale coordinates */ bx >>= 1; by >>= 1; /* frame DCT coding */ rfp = newframe[cc] + chrom_width*by + bx; iincr = chrom_width; } if (addflag) { for (i=0; i<8; i++) { rfp[0] = clp[bp[0]+rfp[0]]; rfp[1] = clp[bp[1]+rfp[1]]; rfp[2] = clp[bp[2]+rfp[2]]; rfp[3] = clp[bp[3]+rfp[3]]; rfp[4] = clp[bp[4]+rfp[4]]; rfp[5] = clp[bp[5]+rfp[5]]; rfp[6] = clp[bp[6]+rfp[6]]; rfp[7] = clp[bp[7]+rfp[7]]; bp += 8; rfp+= iincr; } } else { for (i=0; i<8; i++) { rfp[0] = clp[bp[0]]; rfp[1] = clp[bp[1]]; rfp[2] = clp[bp[2]]; rfp[3] = clp[bp[3]]; rfp[4] = clp[bp[4]]; rfp[5] = clp[bp[5]]; rfp[6] = clp[bp[6]]; rfp[7] = clp[bp[7]]; bp += 8; rfp += iincr; } } } int motion_decode(int vec, int pmv) { if (vec > 31) vec -= 64; vec += pmv; if (vec > 31) vec -= 64; if (vec < -32) vec += 64; return vec; } int Decoder::find_pmv(int x, int y, int block, int comp) { int p1,p2,p3; int xin1,xin2,xin3; int yin1,yin2,yin3; int vec1,vec2,vec3; int l8,o8,or8; x++;y++; l8 = (modemap[y][x-1] == MODE_INTER4V ? 1 : 0); o8 = (modemap[y-1][x] == MODE_INTER4V ? 1 : 0); or8 = (modemap[y-1][x+1] == MODE_INTER4V ? 1 : 0); switch (block) { case 0: vec1 = (l8 ? 2 : 0) ; yin1 = y ; xin1 = x-1; vec2 = (o8 ? 3 : 0) ; yin2 = y-1; xin2 = x; vec3 = (or8? 3 : 0) ; yin3 = y-1; xin3 = x+1; break; case 1: vec1 = (l8 ? 2 : 0) ; yin1 = y ; xin1 = x-1; vec2 = (o8 ? 3 : 0) ; yin2 = y-1; xin2 = x; vec3 = (or8? 3 : 0) ; yin3 = y-1; xin3 = x+1; break; case 2: vec1 = 1 ; yin1 = y ; xin1 = x; vec2 = (o8 ? 4 : 0) ; yin2 = y-1; xin2 = x; vec3 = (or8? 3 : 0) ; yin3 = y-1; xin3 = x+1; break; case 3: vec1 = (l8 ? 4 : 0) ; yin1 = y ; xin1 = x-1; vec2 = 1 ; yin2 = y ; xin2 = x; vec3 = 2 ; yin3 = y ; xin3 = x; break; case 4: vec1 = 3 ; yin1 = y ; xin1 = x; vec2 = 1 ; yin2 = y ; xin2 = x; vec3 = 2 ; yin3 = y ; xin3 = x; break; default: exit(1); break; } p1 = MV[comp][vec1][yin1][xin1]; p2 = MV[comp][vec2][yin2][xin2]; p3 = MV[comp][vec3][yin3][xin3]; if (p2 == NO_VEC) { p2 = p3 = p1; } return p1+p2+p3 - max(p1,max(p2,p3)) - min(p1,min(p2,p3)); } void make_edge_image(const unsigned char *src,unsigned char *dst,int width,int height,int edge) { int i,j; unsigned char *p1,*p2,*p3,*p4; const unsigned char *o1,*o2,*o3,*o4; /* center image */ p1 = dst; o1 = src; for (j = 0; j < height;j++) { for (i = 0; i < width; i++) { *(p1 + i) = *(o1 + i); } p1 += width + (edge<<1); o1 += width; } /* left and right edges */ p1 = dst-1; o1 = src; for (j = 0; j < height;j++) { for (i = 0; i < edge; i++) { *(p1 - i) = *o1; *(p1 + width + i + 1) = *(o1 + width - 1); } p1 += width + (edge<<1); o1 += width; } /* top and bottom edges */ p1 = dst; p2 = dst + (width + (edge<<1))*(height-1); o1 = src; o2 = src + width*(height-1); for (j = 0; j < edge;j++) { p1 = p1 - (width + (edge<<1)); p2 = p2 + (width + (edge<<1)); for (i = 0; i < width; i++) { *(p1 + i) = *(o1 + i); *(p2 + i) = *(o2 + i); } } /* corners */ p1 = dst - (width+(edge<<1)) - 1; p2 = p1 + width + 1; p3 = dst + (width+(edge<<1))*(height)-1; p4 = p3 + width + 1; o1 = src; o2 = o1 + width - 1; o3 = src + width*(height-1); o4 = o3 + width - 1; for (j = 0; j < edge; j++) { for (i = 0; i < edge; i++) { *(p1 - i) = *o1; *(p2 + i) = *o2; *(p3 - i) = *o3; *(p4 + i) = *o4; } p1 = p1 - (width + (edge<<1)); p2 = p2 - (width + (edge<<1)); p3 = p3 + width + (edge<<1); p4 = p4 + width + (edge<<1); } } static bool Mode_IsInter(int Mode) { return (Mode == MODE_INTER || Mode == MODE_INTER_Q || Mode == MODE_INTER4V || Mode == MODE_INTER4V_Q); } static bool Mode_IsIntra(int Mode) { return (Mode == MODE_INTRA || Mode == MODE_INTRA_Q); } void Decoder::get_I_P_MBs() { int comp; int MBA, MBAmax; int COD = 0, MCBPC, CBPY, CBP = 0, CBPB = 0, MODB = 0, Mode = 0, DQUANT; int mvx = 0, mvy = 0, pmv0, pmv1, xpos, ypos, k; int startmv, stopmv, last_done = 0, pCBP = 0, pCBPB = 0, pCOD = 0, pMODB = 0; int DQ_tab[4] = {-1, -2, 1, 2}; unsigned int i; short *bp; /* number of macroblocks per picture */ MBAmax = mb_width * mb_height; MBA = 0; /* macroblock address */ xpos = ypos = 0; /* mark MV's above the picture */ for (i = 1; i < mb_width + 1; i++) { for (k = 0; k < 5; k++) { MV[0][k][0][i] = NO_VEC; MV[1][k][0][i] = NO_VEC; } modemap[0][i] = MODE_INTRA; } /* zero MV's on the sides of the picture */ for (i = 0; i < mb_height + 1; i++) { for (k = 0; k < 5; k++) { MV[0][k][i][0] = 0; MV[1][k][i][0] = 0; MV[0][k][i][mb_width + 1] = 0; MV[1][k][i][mb_width + 1] = 0; } modemap[i][0] = MODE_INTRA; modemap[i][mb_width + 1] = MODE_INTRA; } /* initialize the qcoeff used in advanced intra coding */ fault = 0; for (;;) { resync: /* This version of the decoder does not resync on every possible * error, and it does not do all possible error checks. It is not * difficult to make it much more error robust, but I do not think it * is necessary to include this in the freely available version. */ if (fault) { startcode(); /* sync on new startcode */ fault = 0; } xpos = MBA % mb_width; ypos = MBA / mb_width; if (MBA >= MBAmax) { /* all macroblocks decoded */ return; } read_cod: if (PCT_INTER == pict_type || PCT_DISPOSABLE_INTER == pict_type) { COD = buffer.showbits(1); } else { COD = 0; /* Intra picture -> not skipped */ coded_map[ypos + 1][xpos + 1] = 1; } if (!COD) { /* COD == 0 --> not skipped */ if (PCT_INTER == pict_type || PCT_DISPOSABLE_INTER == pict_type) { /* flush COD bit */ buffer.flushbits(1); } if (PCT_INTRA == pict_type) { MCBPC = getMCBPCintra(); } else { MCBPC = getMCBPC(); } if (fault) goto resync; if (MCBPC == 255) { /* stuffing - read next COD without advancing MB count. */ goto read_cod; } else { /* normal MB data */ Mode = MCBPC & 7; /* MODB and CBPB */ CBPY = getCBPY(); } /* Decode Mode and CBP */ if ((Mode == MODE_INTRA || Mode == MODE_INTRA_Q)) { /* Intra */ coded_map[ypos + 1][xpos + 1] = 1; CBPY = CBPY ^ 15; /* needed in huffman coding only */ } CBP = (CBPY << 2) | (MCBPC >> 4); if (Mode == MODE_INTER_Q || Mode == MODE_INTRA_Q || Mode == MODE_INTER4V_Q) { /* Read DQUANT if necessary */ DQUANT = buffer.getbits(2); quant += DQ_tab[DQUANT]; if (quant > 31 || quant < 1) { quant = max(1, (31, quant)); /* could set fault-flag and resync here */ fault = 1; } } /* motion vectors */ if (Mode == MODE_INTER || Mode == MODE_INTER_Q || Mode == MODE_INTER4V || Mode == MODE_INTER4V_Q) { if (Mode == MODE_INTER4V || Mode == MODE_INTER4V_Q) { startmv = 1; stopmv = 4; } else { startmv = 0; stopmv = 0; } for (k = startmv; k <= stopmv; k++) { mvx = getTMNMV(); mvy = getTMNMV(); pmv0 = find_pmv(xpos, ypos, k, 0); pmv1 = find_pmv(xpos, ypos, k, 1); mvx = motion_decode(mvx, pmv0); mvy = motion_decode(mvy, pmv1); /* store coded or not-coded */ coded_map[ypos + 1][xpos + 1] = 1; MV[0][k][ypos+1][xpos+1] = mvx; MV[1][k][ypos+1][xpos+1] = mvy; } } /* Intra. */ else { } if (fault) goto resync; } else { /* COD == 1 --> skipped MB */ if (MBA >= MBAmax) { /* all macroblocks decoded */ return; } if (PCT_INTER == pict_type || PCT_DISPOSABLE_INTER == pict_type) buffer.flushbits(1); Mode = MODE_INTER; /* Reset CBP */ CBP = CBPB = 0; coded_map[ypos + 1][xpos + 1] = 0; /* reset motion vectors */ MV[0][0][ypos + 1][xpos + 1] = 0; MV[1][0][ypos + 1][xpos + 1] = 0; } /* Store mode and prediction type */ modemap[ypos + 1][xpos + 1] = Mode; /* store defaults for advanced intra coding mode */ if (Mode == MODE_INTRA || Mode == MODE_INTRA_Q) { MV[0][0][ypos + 1][xpos + 1] = MV[1][0][ypos + 1][xpos + 1] = 0; } if (!COD) { Mode = modemap[ypos + 1][xpos + 1]; /* decode blocks */ for (comp = 0; comp < 6; comp++) { clearblock(comp); if ((Mode == MODE_INTRA || Mode == MODE_INTRA_Q)) { /* Intra (except in advanced intra coding mode) */ bp = block[comp]; bp[0] = buffer.getbits(8); if (bp[0] == 255) /* Spec. in H.26P, not in TMN4 */ bp[0] = 128; bp[0] *= 8; /* Iquant */ if ((CBP & (1 << (6 - 1 - comp)))) { getblock(comp, 0); } } else { /* Inter (or Intra in advanced intra coding mode) */ if ((CBP & (1 << (6 - 1 - comp)))) { getblock(comp, 1); } } if (fault) goto resync; } } /* decode the last MB if data is missing */ /* advance to next macroblock */ MBA++; pCBP = CBP; pCBPB = CBPB; pCOD = COD; pMODB = MODB; quant_map[ypos + 1][xpos + 1] = quant; int bx = 16 * xpos; int by = 16 * ypos; Mode = modemap[by / 16 + 1][bx / 16 + 1]; /* motion compensation for P-frame */ if (Mode == MODE_INTER || Mode == MODE_INTER_Q || Mode == MODE_INTER4V || Mode == MODE_INTER4V_Q) { reconstruct(bx, by, Mode); } /* copy or add block data into P-picture */ for (comp = 0; comp < 6; comp++) { /* inverse DCT */ if (Mode == MODE_INTRA || Mode == MODE_INTRA_Q) { idct.idct(block[comp]); addblock(comp, bx, by, 0); } else if ((pCBP & (1 << (6 - 1 - comp)))) { /* No need to to do this for blocks with no coeffs */ idct.idct(block[comp]); addblock(comp, bx, by, 1); } } } } static int STRENGTH[] = {1, 1, 2, 2, 3, 3, 4, 4, 4, 5, 5, 6, 6, 7, 7, 7, 8, 8, 8, 9, 9, 9, 10, 10, 10, 11, 11, 11, 12, 12, 12}; void Decoder::horiz_edge_filter(unsigned char *rec, int width, int height, int chr) { int i, j; int delta, d1, d2; int mbc, mbr, do_filter; int QP; int mbr_above; /* horizontal edges */ for (j = 8; j < height; j += 8) { if (!chr) { mbr = j >> 4; mbr_above = (j - 8) >> 4; } else { mbr = j >> 3; mbr_above = mbr - 1; } const int * const cur_coded_map = coded_map[mbr + 1]; for (i = 0; i < width; i++) { // TODO: replace all below with FilterDeblocking8x8HorEdge_H263(rec+i+(j+1)*width, width, QP) and i+=8 ? if (!chr) { mbc = i >> 4; } else { mbc = i >> 3; } do_filter = cur_coded_map[mbc + 1] || coded_map[mbr_above + 1][mbc + 1]; if (do_filter) { QP = cur_coded_map[mbc + 1] ? quant_map[mbr + 1][mbc + 1] : quant_map[mbr_above + 1][mbc + 1]; delta = (int)(((int)(*(rec + i + (j - 2) * width)) + (int)(*(rec + i + (j - 1) * width) * (-4)) + (int)(*(rec + i + (j) * width) * (4)) + (int)(*(rec + i + (j + 1) * width) * (-1))) / 8.0); d1 = sign(delta) * max(0, abs(delta) - max(0, 2 * (abs(delta) - STRENGTH[QP - 1]))); d2 = min(abs(d1 / 2), max(-abs(d1 / 2), (int)(((*(rec + i + (j - 2) * width) - *(rec + i + (j + 1) * width))) / 4))); *(rec + i + (j + 1) * width) += d2; /* D */ *(rec + i + (j) * width) = min(255, max(0, (int)(*(rec + i + (j) * width)) - d1)); /* C */ *(rec + i + (j - 1) * width) = min(255, max(0, (int)(*(rec + i + (j - 1) * width)) + d1)); /* B */ *(rec + i + (j - 2) * width) -= d2; /* A */ } } } return; } void Decoder::vert_edge_filter(unsigned char *rec, int width, int height, int chr) { int i, j; int delta, d1, d2; int mbc, mbr; int do_filter; int QP; int mbc_left; /* vertical edges */ for (i = 8; i < width; i += 8) { if (!chr) { mbc = i >> 4; mbc_left = (i - 8) >> 4; } else { mbc = i >> 3; mbc_left = mbc - 1; } // TODO: replace all below with FilterDeblocking8x8VerEdge_H263(rec+i +j*width, width, QP) and i+=8 ? for (j = 0; j < height; j++) { if (!chr) { mbr = j >> 4; } else { mbr = j >> 3; } do_filter = coded_map[mbr + 1][mbc + 1] || coded_map[mbr + 1][mbc_left + 1]; if (do_filter) { QP = coded_map[mbr + 1][mbc + 1] ? quant_map[mbr + 1][mbc + 1] : quant_map[mbr + 1][mbc_left + 1]; delta = (int)(((int)(*(rec + i - 2 + j * width)) + (int)(*(rec + i - 1 + j * width) * (-4)) + (int)(*(rec + i + j * width) * (4)) + (int)(*(rec + i + 1 + j * width) * (-1))) / 8.0); d1 = sign(delta) * max(0, abs(delta) - max(0, 2 * (abs(delta) - STRENGTH[QP - 1]))); d2 = min(abs(d1 / 2), max(-abs(d1 / 2), (int)((*(rec + i - 2 + j * width) - *(rec + i + 1 + j * width)) / 4))); *(rec + i + 1 + j * width) += d2; /* D */ *(rec + i + j * width) = min(255, max(0, (int)(*(rec + i + j * width)) - d1)); /* C */ *(rec + i - 1 + j * width) = min(255, max(0, (int)(*(rec + i - 1 + j * width)) + d1)); /* B */ *(rec + i - 2 + j * width) -= d2; /* A */ } } } return; } void Decoder::edge_filter(unsigned char *lum, unsigned char *Cb, unsigned char *Cr, int width, int height) { /* Luma */ horiz_edge_filter(lum, width, height, 0); vert_edge_filter(lum, width, height, 0); /* Chroma */ horiz_edge_filter(Cb, width / 2, height / 2, 1); vert_edge_filter(Cb, width / 2, height / 2, 1); horiz_edge_filter(Cr, width / 2, height / 2, 1); vert_edge_filter(Cr, width / 2, height / 2, 1); /* that's it */ return; } void Decoder::PostFilter(unsigned char *lum, unsigned char *Cb, unsigned char *Cr, int width, int height) { /* Luma */ horiz_post_filter(lum, width, height, 0); vert_post_filter(lum, width, height, 0); /* Chroma */ horiz_post_filter(Cb, width / 2, height / 2, 1); vert_post_filter(Cb, width / 2, height / 2, 1); horiz_post_filter(Cr, width / 2, height / 2, 1); vert_post_filter(Cr, width / 2, height / 2, 1); /* that's it */ return; } /***********************************************************************/ static int STRENGTH1[] = {1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4}; void Decoder::horiz_post_filter(unsigned char *rec, int width, int height, int chr) { int i, j; int delta, d1; int mbc, mbr; int QP; int mbr_above; /* horizontal edges */ for (j = 8; j < height; j += 8) { for (i = 0; i < width; i++) { if (!chr) { mbr = j >> 4; mbc = i >> 4; mbr_above = (j - 8) >> 4; } else { mbr = j >> 3; mbc = i >> 3; mbr_above = mbr - 1; } QP = coded_map[mbr + 1][mbc + 1] ? quant_map[mbr + 1][mbc + 1] : quant_map[mbr_above + 1][mbc + 1]; delta = (int)(((int)(*(rec + i + (j - 3) * width)) + (int)(*(rec + i + (j - 2) * width)) + (int)(*(rec + i + (j - 1) * width)) + (int)(*(rec + i + (j) * width) * (-6)) + (int)(*(rec + i + (j + 1) * width)) + (int)(*(rec + i + (j + 2) * width)) + (int)(*(rec + i + (j + 3) * width))) / 8.0); d1 = sign(delta) * max(0, abs(delta) - max(0, 2 * (abs(delta) - STRENGTH1[QP - 1]))); /* Filter D */ *(rec + i + (j) * width) += d1; } } return; } static int STRENGTH2[] = {1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3}; void Decoder::vert_post_filter(unsigned char *rec, int width, int height, int chr) { int i, j; int delta, d1; int mbc, mbr; int QP; int mbc_left; /* vertical edges */ for (i = 8; i < width; i += 8) { for (j = 0; j < height; j++) { if (!chr) { mbr = j >> 4; mbc = i >> 4; mbc_left = (i - 8) >> 4; } else { mbr = j >> 3; mbc = i >> 3; mbc_left = mbc - 1; } QP = coded_map[mbr + 1][mbc + 1] ? quant_map[mbr + 1][mbc + 1] : quant_map[mbr + 1][mbc_left + 1]; delta = (int)(((int)(*(rec + i - 3 + j * width)) + (int)(*(rec + i - 2 + j * width)) + (int)(*(rec + i - 1 + j * width)) + (int)(*(rec + i + j * width) * (-6)) + (int)(*(rec + i + 1 + j * width)) + (int)(*(rec + i + 2 + j * width)) + (int)(*(rec + i + 3 + j * width))) / 8.0); d1 = sign(delta) * max(0, abs(delta) - max(0, 2 * (abs(delta) - STRENGTH2[QP - 1]))); /* Post Filter D */ *(rec + i + j * width) += d1; } } return; }