static int fill(video_generator* gen, int x, int y, int w, int h, int r, int g, int b) { // Y int yc = RGB2Y(r,g,b); int uc = RGB2U(r,g,b); int vc = RGB2V(r,g,b); int j = 0; // UV int xx = x / 2; int yy = y / 2; int half_w = gen->width / 2; int half_h = gen->height / 2; int hh = h / 2; int ww = w / 2; // y for (j = y; j < (y + h); ++j) { memset(gen->y + j * gen->width + x, yc, w); } // u and v for (j = yy; j < (yy + hh); ++j) { memset(gen->u + j * half_w + xx, uc, (ww)); memset(gen->v + j * half_w + xx, vc, (ww)); } return 0; }
void subsample2(const BGR rgb[16][16], conv Y[2][2][8][8], conv cb[8][8], conv cr[8][8]) { unsigned r, c; for (r = 0; r < 16; r += 2) for (c = 0; c < 16; c += 2) { //unsigned rr, cc; unsigned i, j, k, l; unsigned sR, sG, sB; unsigned R, G, B; i = r >> 3, j = c >> 3, k = r & 7, l = c & 7; sR = R = rgb[r][c].Red, sG = G = rgb[r][c].Green, sB = B = rgb[r][c].Blue; Y[i][j][k][l] = RGB2Y(R, G, B)-128; sR += R = rgb[r][c+1].Red, sG += G = rgb[r][c+1].Green, sB += B = rgb[r][c+1].Blue; Y[i][j][k][l+1] = RGB2Y(R, G, B)-128; sR += R = rgb[r+1][c].Red, sG += G = rgb[r+1][c].Green, sB += B = rgb[r+1][c].Blue; Y[i][j][k+1][l] = RGB2Y(R, G, B)-128; sR += R = rgb[r+1][c+1].Red, sG += G = rgb[r+1][c+1].Green, sB += B = rgb[r+1][c+1].Blue; Y[i][j][k+1][l+1] = RGB2Y(R, G, B)-128; // calculating an average values R = sR >> 2, G = sG >> 2, B = sB >> 2; //rr = r >> 1, cc = c >> 1; cb[r>>1][c>>1] = (conv)RGB2Cb(R, G, B)-128; cr[r>>1][c>>1] = (conv)RGB2Cr(R, G, B)-128; } }
/* Computes the pixel value after adjusting the white balance to the current * one. The input the y, u, v channel of the pixel and the adjusted value will * be stored in place. The adjustment is done in RGB space. */ void EmulatedCameraDevice::changeWhiteBalance(uint8_t& y, uint8_t& u, uint8_t& v) const { float r_scale = mWhiteBalanceScale[0]; float b_scale = mWhiteBalanceScale[2]; int r = static_cast<float>(YUV2R(y, u, v)) / r_scale; int g = YUV2G(y, u, v); int b = static_cast<float>(YUV2B(y, u, v)) / b_scale; y = RGB2Y(r, g, b); u = RGB2U(r, g, b); v = RGB2V(r, g, b); }
void RGB2YCrCb(signed char pixelmatrix[MACRO_BLOCK_SIZE][MACRO_BLOCK_SIZE*3],signed char YMatrix[MATRIX_SIZE][MATRIX_SIZE],signed char CrMatrix[MATRIX_SIZE][MATRIX_SIZE],signed char CbMatrix[MATRIX_SIZE][MATRIX_SIZE], unsigned int sample) { unsigned int row, col, rowoffset, coloffset, xoffset, yoffset; for(row = 0;row < MATRIX_SIZE; row++) { for(col = 0; col < MATRIX_SIZE; col++) { coloffset = (sample&0x01)*8; rowoffset = (sample&0x02)*4; YMatrix[row][col] = RGB2Y(pixelmatrix[row+rowoffset][(col+coloffset)*3+2],pixelmatrix[row+rowoffset][(col+coloffset)*3+1],pixelmatrix[row+rowoffset][(col+coloffset)*3]) - 128; if (col%2==0) { yoffset = (sample&0x01)*4; xoffset = (sample&0x02)*2; if (row%2==0) { CrMatrix[xoffset+(row>>1)][yoffset+(col>>1)] = RGB2Cr(pixelmatrix[row+rowoffset][(col+coloffset)*3+2],pixelmatrix[row+rowoffset][(col+coloffset)*3+1],pixelmatrix[row+rowoffset][(col+coloffset)*3]) - 128; } else { CbMatrix[xoffset+((row)>>2)][yoffset+(col>>2)] = RGB2Cb(pixelmatrix[row+rowoffset][(col+coloffset)*3+2],pixelmatrix[row+rowoffset][(col+coloffset)*3+1],pixelmatrix[row+rowoffset][(col+coloffset)*3]) - 128; } }
static void reduceImage(uint8_t * image,uint8_t * found_colors,int row,unsigned offsetPal,Fl_Progress *progress,Fl_Window*pwin,unsigned maxCol,unsigned yuv,unsigned alg,bool isSprite=false,bool ditherBefore=true){ if(progress) progress->maximum(1.0); unsigned off2=offsetPal*2; unsigned off3=offsetPal*3; unsigned colors_found; unsigned w,h; unsigned maxPal=maxCol; unsigned msprt=curSpritemeta; if(isSprite){ w=currentProject->ms->sps[msprt].width(curSpritegroup); h=currentProject->ms->sps[msprt].height(curSpritegroup); currentProject->ms->sps[msprt].spriteGroupToImage(image,curSpritegroup,row,false); }else{ w=currentProject->tms->maps[currentProject->curPlane].mapSizeW; h=currentProject->tms->maps[currentProject->curPlane].mapSizeHA; w*=currentProject->tileC->sizew; h*=currentProject->tileC->sizeh; currentProject->tms->maps[currentProject->curPlane].truecolor_to_image(image,row,false); } if(progress){ progress->label("Dithering to colorspace"); Fl::check(); } if((!yuv)&&ditherBefore) ditherImage(image,w,h,false,true); if(progress){ progress->label("Quantizing image"); Fl::check(); } colors_found=count_colors(image,w,h,&found_colors[0],false); printf("Unique colors %d\n",colors_found); if (colors_found <= maxCol){ printf("%d colors\n",colors_found); unsigned offsetTmp=offsetPal; for (unsigned x=0;x<colors_found;x++){ uint_fast8_t r,g,b; againFun: if (currentProject->pal->palType[offsetTmp]){ ++offsetTmp; if(offsetTmp>=maxPal) goto actullyNeededReduction; goto againFun; } r=found_colors[(x*3)]; g=found_colors[(x*3)+1]; b=found_colors[(x*3)+2]; printf("R=%d G=%d B=%d\n",r,g,b); if(currentProject->pal->shouldAddCol(offsetTmp,r,g,b,isSprite)){ currentProject->pal->rgbToEntry(r,g,b,offsetTmp); currentProject->pal->updateRGBindex(offsetTmp); ++offsetTmp; } } if(currentProject->gameSystem==NES) updateEmphesis(); if(window) window->redraw(); }else{ actullyNeededReduction: printf("More than %d colors reducing to %d colors\n",maxCol,maxCol); uint8_t user_pal[3][256]; uint8_t rgb_pal2[768]; uint8_t rgb_pal3[768]; unsigned colorz=maxCol; bool can_go_again=true; uint8_t*imageuse; uint8_t*output; if(alg==1) output=(uint8_t*)malloc(w*h*3); if(yuv){ imageuse=(uint8_t*)malloc(w*h*3); uint32_t x,y; uint8_t*imageptr=image; uint8_t*outptr=imageuse; for(y=0;y<h;y++){ for(x=0;x<w;x++){ if(yuv==2){ outptr[0]=CRGB2Y(imageptr[0],imageptr[1],imageptr[2]); outptr[1]=CRGB2Cb(imageptr[0],imageptr[1],imageptr[2]); outptr[2]=CRGB2Cr(imageptr[0],imageptr[1],imageptr[2]); }else{ outptr[0]=RGB2Y(imageptr[0],imageptr[1],imageptr[2]); outptr[1]=RGB2U(imageptr[0],imageptr[1],imageptr[2]); outptr[2]=RGB2V(imageptr[0],imageptr[1],imageptr[2]); } imageptr+=3; outptr+=3; } } }else imageuse=image; try_again_color: switch(alg){ case 4: dl1quant(imageuse,w,h,colorz,user_pal); break; case 3: wu_quant(imageuse,w,h,colorz,user_pal); break; case 2: NEU_wrapper(w,h,imageuse,colorz,user_pal); break; case 1: scolorq_wrapper(imageuse,output,user_pal,w,h,colorz); break; default: dl3quant(imageuse,w,h,colorz,user_pal,true,progress);/*this uses denesis lee's v3 color quant which is found at http://www.gnu-darwin.org/www001/ports-1.5a-CURRENT/graphics/mtpaint/work/mtpaint-3.11/src/quantizer.c*/ } for (unsigned x=0;x<colorz;x++){ unsigned r,g,b; if(yuv){ if(yuv==2){ r=CYCbCr2R(user_pal[0][x],user_pal[1][x],user_pal[2][x]); g=CYCbCr2G(user_pal[0][x],user_pal[1][x],user_pal[2][x]); b=CYCbCr2B(user_pal[0][x],user_pal[1][x],user_pal[2][x]); }else{ r=YUV2R(user_pal[0][x],user_pal[1][x],user_pal[2][x]); g=YUV2G(user_pal[0][x],user_pal[1][x],user_pal[2][x]); b=YUV2B(user_pal[0][x],user_pal[1][x],user_pal[2][x]); } }else{ r=user_pal[0][x]; g=user_pal[1][x]; b=user_pal[2][x]; } switch(currentProject->gameSystem){ case segaGenesis: r=nearest_color_index(r); g=nearest_color_index(g); b=nearest_color_index(b); rgb_pal2[(x*3)]=palTab[r]; rgb_pal2[(x*3)+1]=palTab[g]; rgb_pal2[(x*3)+2]=palTab[b]; break; case NES: {uint8_t temp=currentProject->pal->to_nes_color_rgb(r,g,b); uint32_t temp_rgb = nesPalToRgb(temp); rgb_pal2[(x*3)]=(temp_rgb>>16)&255; rgb_pal2[(x*3)+1]=(temp_rgb>>8)&255; rgb_pal2[(x*3)+2]=temp_rgb&255;} break; case masterSystem: case gameGear: {const uint8_t*palUseTab=currentProject->gameSystem==gameGear?palTabGameGear:palTabMasterSystem; unsigned colsTab=currentProject->gameSystem==gameGear?16:4; r=nearestOneChannel(r,palUseTab,colsTab); g=nearestOneChannel(g,palUseTab,colsTab); b=nearestOneChannel(b,palUseTab,colsTab); rgb_pal2[(x*3)]=palUseTab[r]; rgb_pal2[(x*3)+1]=palUseTab[g]; rgb_pal2[(x*3)+2]=palUseTab[b];} break; default: show_default_error } } unsigned new_colors = count_colors(rgb_pal2,colorz,1,rgb_pal3); printf("Unique colors in palette %u\n",new_colors); if (new_colors < maxCol){ if (can_go_again == true){ if (colorz != 512) colorz++; else can_go_again=false; char tmp[1024]; snprintf(tmp,1024,"Found only %d colors trying again with %d",new_colors,colorz); tmp[sizeof(tmp)-1]=0; if(pwin){ pwin->copy_label(tmp); Fl::check(); } puts(tmp); goto try_again_color; } } if (new_colors > maxCol){ can_go_again=false; if(pwin) pwin->label("Too many colors"); colorz--; goto try_again_color; } unsigned offsetTmp=offsetPal; for (unsigned x=0;x<maxCol;x++){ againNerd: if (currentProject->pal->palType[offsetTmp]){ ++offsetTmp; if(offsetTmp>(maxPal+offsetPal)){ if(maxCol>1){ --colorz; printf("Needed to reduce colors generated due to locked colors %u\n",maxCol); }else{ fl_alert("Cannot reduce maximum colors to make this happen...aborting"); return; } goto try_again_color; } goto againNerd; } unsigned r=rgb_pal3[x*3],g=rgb_pal3[x*3+1],b=rgb_pal3[x*3+2]; if(currentProject->pal->shouldAddCol(offsetTmp,r,g,b,isSprite)){ memcpy(currentProject->pal->rgbPal+(offsetTmp*3),rgb_pal3+(x*3),3); currentProject->pal->rgbToEntry(r,g,b,offsetTmp); ++offsetTmp; } } if(currentProject->gameSystem==NES) updateEmphesis(); if(alg==1){ if(isSprite) currentProject->ms->sps[msprt].spriteImageToTiles(output,curSpritegroup,row,false); else currentProject->tms->maps[currentProject->curPlane].truecolorimageToTiles(output,row,false); free(output); } if(yuv) free(imageuse); } }
void WebMEncoder::convertFrame(unsigned char *inputImage,int inputStride) { int ii,j; //printf("IMAGE INFO: %d %d %d %d %d %d %d %d\n",raw.stride[0],raw.stride[1],raw.stride[2],raw.bps,raw.w,raw.h,raw.fmt,VPX_IMG_FMT_YV12); { unsigned char *yData = raw.planes[0]; unsigned char *uData = raw.planes[1]; unsigned char *vData = raw.planes[2]; memset(uData,0,(width*height)>>2); memset(vData,0,(width*height)>>2); int stride=3; switch(inputVideoFormat) { case IVF_RGB: stride = 3; break; case IVF_RGBA: stride = 4; break; } int fullYIndex=0; int fullRGBTLIndex=0; int fullRGBTRIndex=stride; int fullRGBBLIndex=stride*inputStride; int fullRGBBRIndex=stride*(inputStride+1); int halfIndex=0; int halfHeight = height>>1; int halfWidth = width>>1; for(ii=0;ii<halfHeight;ii++) { for(j=0;j<halfWidth;j++) { /* image[fullRGBIndex]=255; image[fullRGBIndex+1]=0; image[fullRGBIndex+2]=0; image[fullRGBIndex+stride]=255; image[fullRGBIndex+stride+1]=0; image[fullRGBIndex+stride+2]=0; image[fullRGBIndex+stride*width]=255; image[fullRGBIndex+stride*width+1]=0; image[fullRGBIndex+stride*width+2]=0; image[fullRGBIndex+stride*width+stride]=255; image[fullRGBIndex+stride*width+stride+1]=0; image[fullRGBIndex+stride*width+stride+2]=0; */ RGB2Y(yData[fullYIndex],inputImage[fullRGBTLIndex+2],inputImage[fullRGBTLIndex+1],inputImage[fullRGBTLIndex]) RGB2Y(yData[fullYIndex+1],inputImage[fullRGBTRIndex+2],inputImage[fullRGBTRIndex+1],inputImage[fullRGBTRIndex]) RGB2Y(yData[fullYIndex+width],inputImage[fullRGBBLIndex+2],inputImage[fullRGBBLIndex+1],inputImage[fullRGBBLIndex]) RGB2Y(yData[fullYIndex+width+1],inputImage[fullRGBBRIndex+2],inputImage[fullRGBBRIndex+1],inputImage[fullRGBBRIndex]) RGB2U(uData[halfIndex],\ inputImage[fullRGBTLIndex+2],inputImage[fullRGBTLIndex+1],inputImage[fullRGBTLIndex],\ inputImage[fullRGBTRIndex+2],inputImage[fullRGBTRIndex+1],inputImage[fullRGBTRIndex],\ inputImage[fullRGBBLIndex+2],inputImage[fullRGBBLIndex+1],inputImage[fullRGBBLIndex],\ inputImage[fullRGBBRIndex+2],inputImage[fullRGBBRIndex+1],inputImage[fullRGBBRIndex]\ ); RGB2V(vData[halfIndex],\ inputImage[fullRGBTLIndex+2],inputImage[fullRGBTLIndex+1],inputImage[fullRGBTLIndex],\ inputImage[fullRGBTRIndex+2],inputImage[fullRGBTRIndex+1],inputImage[fullRGBTRIndex],\ inputImage[fullRGBBLIndex+2],inputImage[fullRGBBLIndex+1],inputImage[fullRGBBLIndex],\ inputImage[fullRGBBRIndex+2],inputImage[fullRGBBRIndex+1],inputImage[fullRGBBRIndex]\ ); //yData[fullYIndex] = yData[fullYIndex+1] = yData[fullYIndex+width] = yData[fullYIndex+width+1] = 255; //uData[halfIndex] = 0; //vData[halfIndex] = 127; fullYIndex+=2; fullRGBTLIndex += stride*2; fullRGBTRIndex += stride*2; fullRGBBLIndex += stride*2; fullRGBBRIndex += stride*2; halfIndex++; } fullYIndex += width; fullRGBTLIndex += stride*((inputStride-width)+inputStride); fullRGBTRIndex += stride*((inputStride-width)+inputStride); fullRGBBLIndex += stride*((inputStride-width)+inputStride); fullRGBBRIndex += stride*((inputStride-width)+inputStride); } } }
void I3C_Converter::Pixel2YUV(Pixel *pixel, YUV *yuv) { yuv->Y = RGB2Y(pixel->red, pixel->green, pixel->blue); yuv->U = RGB2U(pixel->red, pixel->green, pixel->blue); yuv->V = RGB2V(pixel->red, pixel->green, pixel->blue); }
/* generates a new frame and stores it in the y, u and v members */ int video_generator_update(video_generator* g) { double perc; int is_bip, is_bop; int text_w, text_x, text_y, i; int32_t bar_h, time, speed, start_y, nlines, h; uint64_t days, hours, minutes, seconds; uint32_t stride, end_y; char timebuf[512] = { 0 } ; int text_r, text_g, text_b; int rc, gc, bc, yc, uc, vc, dx; int colors[] = { 255, 255, 255, // white 255, 255, 0, // yellow 0, 255, 255, // cyan 0, 255, 0, // green 255, 0, 255, // magenta 255, 0, 0, // red 0, 0, 255 // blue }; if (!g) { return -1; } if (!g->width) { return -2; } if (!g->height) { return -3; } text_r = 0; text_g = 0; text_b = 0; h = g->height - 1; bar_h = g->height / 5; start_y = -bar_h + (g->perc * (h + bar_h)); /* how many lines of the bar are visible */ if (start_y < 0) { nlines = bar_h + start_y; start_y = 0; } else if(start_y + bar_h > h) { nlines = h - start_y; } else { nlines = bar_h; } /* increment step */ g->perc += g->step; if (g->perc >= (1.0)) { g->perc = 0.0; } if (nlines + start_y > g->height || nlines < 0 || start_y < 0 || start_y >= g->height) { printf("Error: this shouldn't happen.. writing outside the buffer: %d, %d, %d\n", nlines, (nlines + start_y), start_y); return -1; } /* reset */ memset(g->y, 0x00, g->ybytes); memset(g->u, 0x00, g->ubytes); memset(g->v, 0x00, g->vbytes); for (i = 0; i < 7; ++i) { dx = i * 3; rc = colors[dx + 0]; gc = colors[dx + 1]; bc = colors[dx + 2]; fill(g, i * (g->width / 7), 0, (g->width / 7), g->height, rc, gc, bc); } rc = 255 - (g->perc * 255); gc = 30 + (g->perc * 235); bc = 150 + (g->perc * 205); yc = RGB2Y(rc, gc, bc); uc = RGB2U(rc, gc, bc); vc = RGB2V(rc, gc, bc); /* fill y channel */ for (i = start_y; i < (start_y + nlines); ++i) { memset(g->y + (i * g->width), yc, g->width); } /* fill u and v channel */ start_y = start_y / 2; stride = g->width * 0.5; end_y = start_y + nlines/ 2; for (i = start_y; i < end_y; ++i) { memset(g->u + i * stride, uc, stride); memset(g->v + i * stride, vc, stride); } /* draw blip/blop visuals. */ if (NULL != g->audio_buffer) { mutex_lock(&g->audio_mutex); { is_bop = g->audio_is_bop; is_bip = g->audio_is_bip; } mutex_unlock(&g->audio_mutex); if (is_bip == 1) { text_r = 0; text_g = 0; text_b = 255; } if (is_bop == 1) { text_r = 255; text_g = 0; text_b = 0; } } seconds = (g->frame/ g->fps_den); minutes = (seconds / 60); hours = minutes / 60; days = hours / 24; minutes %= 60; seconds %= 60; hours %= 24; text_w = 360; /* manually measured */ text_x = (g->width / 2) - (text_w / 2); text_y = (g->height / 2) - 50; fill(g, text_x, text_y, text_w, 100, text_r, text_g, text_b); sprintf(timebuf, "%03llu:%02llu:%02llu:%02llu", days, hours, minutes, seconds); add_number_string(g, timebuf, text_x + 20, text_y + 20); g->frame++; return 0; }