一、rgb插值算法
说明:验证可用,算法效率一般;其中pDest为扩帧后内存地址,nDestWidth和nDestHeight为扩帧后分辨率,nDestBits为色深(如rgb24则为24)。
void rgbInterpolation(void* pDest, int nDestWidth, int nDestHeight, int nDestBits, void* pSrc, int nSrcWidth, int nSrcHeight, int nSrcBits)
{
//ASSERT_EXP(pDest != NULL);
//ASSERT_EXP((nDestBits == 32) || (nDestBits == 24));
//ASSERT_EXP((nDestWidth > 0) && (nDestHeight > 0));
//ASSERT_EXP(pSrc != NULL);
//ASSERT_EXP((nSrcBits == 32) || (nSrcBits == 24));
//ASSERT_EXP((nSrcWidth > 0) && (nSrcHeight > 0));
double dfAmplificationX = ((double)nDestWidth)/nSrcWidth;
double dfAmplificationY = ((double)nDestHeight)/nSrcHeight;
const int nSrcColorLen = nSrcBits/8;
const int nDestColorLen = nDestBits/8;
for(int i = 0; i0.5)
++nLine;
if(nLine >= nSrcHeight)
--nLine;
tmp = j/dfAmplificationX;
int nRow = (int)tmp;
if(tmp - nRow > 0.5)
++nRow;
if(nRow >= nSrcWidth)
--nRow;
unsigned char *pSrcPos = (unsigned char*)pSrc + (nLine*nSrcWidth + nRow)*nSrcColorLen;
unsigned char *pDestPos = (unsigned char*)pDest + (i*nDestWidth + j)*nDestColorLen;
*pDestPos++ = *pSrcPos++;
*pDestPos++ = *pSrcPos++;
*pDestPos++ = *pSrcPos++;
if(nDestColorLen == 4)
*pDestPos = 0;
}
}二、yuyv转rgb并jpeg编码的插帧算法
说明:该算法经过验证可行;效率较上边略高,是将rgb的转化省略、进而嵌套在jpeg编码中。
/* private member functions */
/*
struct params {
uint8_t* src;
int src_size;
uint8_t* dst; //需要插帧时,该buffer大小为3264*2448*3Byte
int dst_size; //需要插帧时,大小为3264*2448*3Byte
int quality;
int in_width;
int in_height;
int out_width; //需要插帧时,该位为3264
int out_height; //需要插帧时,该位为2448
const char* format;
size_t jpeg_size;
};
*/
size_t Encoder_libjpeg::encode(params* input) {
jpeg_compress_struct cinfo;
jpeg_error_mgr jerr;
jpeg_destination_mgr jdest;
uint8_t* src = NULL, *resize_src = NULL;
uint8_t* row_tmp = NULL;
uint8_t* row_src = NULL;
uint8_t* row_uv = NULL; // used only for NV12
int row_stride;
int out_width = 0, in_width = 0;
int out_height = 0, in_height = 0;
int bpp = 2; // for uyvy
Encoder_libjpeg::format informat = Encoder_libjpeg::YUV422I;
if (!input) {
return 0;
}
out_width = input->out_width;
in_width = input->in_width;
out_height = input->out_height;
in_height = input->in_height;
src = input->src;
input->jpeg_size = 0;
libjpeg_destination_mgr dest_mgr(input->dst, input->dst_size);
// param check...
if ((in_width < 2) || (out_width < 2) || (in_height < 2) || (out_height < 2) ||
(src == NULL) || (input->dst == NULL) || (input->quality < 1) || (input->src_size < 1) ||
(input->dst_size < 1) || (input->format == NULL)) {
goto exit;
}
if (strcmp(input->format, CameraParameters::PIXEL_FORMAT_YUV420SP) == 0) {
//add by tankai
if(in_width < out_height){
informat = Encoder_libjpeg::RGB24;
}
else{
//end tankai
informat = Encoder_libjpeg::YUV420SP;
bpp = 1;
if ((in_width != out_width) || (in_height != out_height)) {
resize_src = (uint8_t*) malloc(input->dst_size);
resize_nv12(input, resize_src);
if (resize_src) src = resize_src;
}
}//add by tankai
} else if (strcmp(input->format, CameraProperties::PIXEL_FORMAT_RGB24) == 0) {
informat = Encoder_libjpeg::RGB24;
bpp = 1;
if ((in_width != out_width) || (in_height != out_height)) {
resize_src = (uint8_t*) malloc(input->dst_size);
if(NULL != resize_src){
extraSmallImg(input->src, in_width, in_height,
resize_src, out_width, out_height);
src = resize_src;
}else{
CAMHAL_LOGDA("failed to malloc space to extra thumbnail\n");
goto exit;
}
}
} else if ((in_width != out_width) || (in_height != out_height)) {
CAMHAL_LOGEB("Encoder: resizing is not supported for this format: %s", input->format);
goto exit;
} else if (strcmp(input->format, CameraParameters::PIXEL_FORMAT_YUV422I)) {
// we currently only support yuv422i and yuv420sp
CAMHAL_LOGEB("Encoder: format not supported: %s", input->format);
goto exit;
}
cinfo.err = jpeg_std_error(&jerr);
jpeg_create_compress(&cinfo);
CAMHAL_LOGDB("encoding... \n\t"
"width: %d \n\t"
"height:%d \n\t"
"dest %p \n\t"
"dest size:%d \n\t"
"mSrc %p",
out_width, out_height, input->dst,
input->dst_size, src);
cinfo.dest = &dest_mgr;
cinfo.image_width = out_width;
cinfo.image_height = out_height;
cinfo.input_components = 3;
if (informat == Encoder_libjpeg::RGB24)
cinfo.in_color_space = JCS_RGB;
else
cinfo.in_color_space = JCS_YCbCr;
cinfo.input_gamma = 1;
jpeg_set_defaults(&cinfo);
jpeg_set_quality(&cinfo, input->quality, TRUE);
cinfo.dct_method = JDCT_IFAST;
jpeg_start_compress(&cinfo, TRUE);
row_tmp = (uint8_t*)malloc(out_width * 3);
row_src = src;
row_uv = src + out_width * out_height * bpp;
row_stride = out_width * 3;
//add by tankai 插帧部分
if(in_width < out_height){
int i,j,z,ratex,ratey=0; unsigned char *ptr;
while ((cinfo.next_scanline < cinfo.image_height) && !mCancelEncoding) {
JSAMPROW row_pointer[1];
if ((ratey-=10)<0){
ratey+=51;
ratex=0;
ptr=row_tmp;
z = 0;
for (j=0; j<3264; j++){
if ((ratex-=10)<0){
ratex+=51;
{
int r, g, b;
int y, u, v;
if (!z)
y = src[0] << 8;
else
y = src[2] << 8;
u = src[1] - 128;
v = src[3] - 128;
r = (y + (359 * v)) >> 8;
g = (y - (88 * u) - (183 * v)) >> 8;
b = (y + (454 * u)) >> 8;
*(ptr++) = (r > 255) ? 255 : ((r < 0) ? 0 : r);
*(ptr++) = (g > 255) ? 255 : ((g < 0) ? 0 : g);
*(ptr++) = (b > 255) ? 255 : ((b < 0) ? 0 : b);
if (z++){
z = 0;
src += 4;
}
}
}else{
register unsigned char rgbchar;
rgbchar=*(ptr-3);
*(ptr++)=rgbchar;
rgbchar=*(ptr-3);
*(ptr++)=rgbchar;
rgbchar=*(ptr-3);
*(ptr++)=rgbchar;
}
}
}
row_pointer[0] = row_tmp;
jpeg_write_scanlines (&cinfo, row_pointer, 1);
}
}
else
//end tankai 插帧部分
while ((cinfo.next_scanline < cinfo.image_height) && !mCancelEncoding) {
JSAMPROW row[1]; /* pointer to JSAMPLE row[s] */
if (informat == Encoder_libjpeg::RGB24) {
row[0] = &src[cinfo.next_scanline * row_stride];
(void) jpeg_write_scanlines(&cinfo, row, 1);
} else {
// convert input yuv format to yuv444
if (informat == Encoder_libjpeg::YUV420SP) {
nv21_to_yuv(row_tmp, row_src, row_uv, out_width);
} else if (informat == Encoder_libjpeg::YUV422I) {
//uyvy_to_yuv(row_tmp, (uint32_t*)row_src, out_width);
yuyv_to_yuv(row_tmp, (uint32_t*)row_src, out_width);
}
row[0] = row_tmp;
jpeg_write_scanlines(&cinfo, row, 1);
row_src = row_src + out_width*bpp;
// move uv row if input format needs it
if (informat == Encoder_libjpeg::YUV420SP) {
if (!(cinfo.next_scanline % 2))
row_uv = row_uv + out_width * bpp;
}
}
}
// no need to finish encoding routine if we are prematurely stopping
// we will end up crashing in dest_mgr since data is incomplete
if (!mCancelEncoding)
jpeg_finish_compress(&cinfo);
jpeg_destroy_compress(&cinfo);
if (resize_src) free(resize_src);
if (row_tmp) free(row_tmp);
exit:
input->jpeg_size = dest_mgr.jpegsize;
return dest_mgr.jpegsize;
}