📄 image.c
字号:
/************************************************************************** * * XVID MPEG-4 VIDEO CODEC * - Image management functions - * * Copyright(C) 2001-2004 Peter Ross <pross@xvid.org> * * This program is free software ; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation ; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY ; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program ; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * $Id: image.c,v 1.32 2005/09/09 12:18:10 suxen_drol Exp $ * ****************************************************************************/#include <stdlib.h>#include <string.h> /* memcpy, memset */#include <math.h>#include "../portab.h"#include "../global.h" /* XVID_CSP_XXX's */#include "../xvid.h" /* XVID_CSP_XXX's */#include "image.h"#include "colorspace.h"#include "interpolate8x8.h"#include "../utils/mem_align.h"#include "../motion/sad.h"#include "font.h" /* XXX: remove later */#define SAFETY 64#define EDGE_SIZE2 (EDGE_SIZE/2)int32_timage_create(IMAGE * image, uint32_t edged_width, uint32_t edged_height){ const uint32_t edged_width2 = edged_width / 2; const uint32_t edged_height2 = edged_height / 2; image->y = xvid_malloc(edged_width * (edged_height + 1) + SAFETY, CACHE_LINE); if (image->y == NULL) { return -1; } memset(image->y, 0, edged_width * (edged_height + 1) + SAFETY); image->u = xvid_malloc(edged_width2 * edged_height2 + SAFETY, CACHE_LINE); if (image->u == NULL) { xvid_free(image->y); image->y = NULL; return -1; } memset(image->u, 0, edged_width2 * edged_height2 + SAFETY); image->v = xvid_malloc(edged_width2 * edged_height2 + SAFETY, CACHE_LINE); if (image->v == NULL) { xvid_free(image->u); image->u = NULL; xvid_free(image->y); image->y = NULL; return -1; } memset(image->v, 0, edged_width2 * edged_height2 + SAFETY); image->y += EDGE_SIZE * edged_width + EDGE_SIZE; image->u += EDGE_SIZE2 * edged_width2 + EDGE_SIZE2; image->v += EDGE_SIZE2 * edged_width2 + EDGE_SIZE2; return 0;}voidimage_destroy(IMAGE * image, uint32_t edged_width, uint32_t edged_height){ const uint32_t edged_width2 = edged_width / 2; if (image->y) { xvid_free(image->y - (EDGE_SIZE * edged_width + EDGE_SIZE)); image->y = NULL; } if (image->u) { xvid_free(image->u - (EDGE_SIZE2 * edged_width2 + EDGE_SIZE2)); image->u = NULL; } if (image->v) { xvid_free(image->v - (EDGE_SIZE2 * edged_width2 + EDGE_SIZE2)); image->v = NULL; }}voidimage_swap(IMAGE * image1, IMAGE * image2){ SWAP(uint8_t*, image1->y, image2->y); SWAP(uint8_t*, image1->u, image2->u); SWAP(uint8_t*, image1->v, image2->v);}voidimage_copy(IMAGE * image1, IMAGE * image2, uint32_t edged_width, uint32_t height){ memcpy(image1->y, image2->y, edged_width * height); memcpy(image1->u, image2->u, edged_width * height / 4); memcpy(image1->v, image2->v, edged_width * height / 4);}/* setedges bug was fixed in this BS version */#define SETEDGES_BUG_BEFORE 18voidimage_setedges(IMAGE * image, uint32_t edged_width, uint32_t edged_height, uint32_t width, uint32_t height, int bs_version){ const uint32_t edged_width2 = edged_width / 2; uint32_t width2; uint32_t i; uint8_t *dst; uint8_t *src; dst = image->y - (EDGE_SIZE + EDGE_SIZE * edged_width); src = image->y; /* According to the Standard Clause 7.6.4, padding is done starting at 16 * pixel width and height multiples. This was not respected in old xvids */ if (bs_version == 0 || bs_version >= SETEDGES_BUG_BEFORE) { width = (width+15)&~15; height = (height+15)&~15; } width2 = width/2; for (i = 0; i < EDGE_SIZE; i++) { memset(dst, *src, EDGE_SIZE); memcpy(dst + EDGE_SIZE, src, width); memset(dst + edged_width - EDGE_SIZE, *(src + width - 1), EDGE_SIZE); dst += edged_width; } for (i = 0; i < height; i++) { memset(dst, *src, EDGE_SIZE); memset(dst + edged_width - EDGE_SIZE, src[width - 1], EDGE_SIZE); dst += edged_width; src += edged_width; } src -= edged_width; for (i = 0; i < EDGE_SIZE; i++) { memset(dst, *src, EDGE_SIZE); memcpy(dst + EDGE_SIZE, src, width); memset(dst + edged_width - EDGE_SIZE, *(src + width - 1), EDGE_SIZE); dst += edged_width; } /* U */ dst = image->u - (EDGE_SIZE2 + EDGE_SIZE2 * edged_width2); src = image->u; for (i = 0; i < EDGE_SIZE2; i++) { memset(dst, *src, EDGE_SIZE2); memcpy(dst + EDGE_SIZE2, src, width2); memset(dst + edged_width2 - EDGE_SIZE2, *(src + width2 - 1), EDGE_SIZE2); dst += edged_width2; } for (i = 0; i < height / 2; i++) { memset(dst, *src, EDGE_SIZE2); memset(dst + edged_width2 - EDGE_SIZE2, src[width2 - 1], EDGE_SIZE2); dst += edged_width2; src += edged_width2; } src -= edged_width2; for (i = 0; i < EDGE_SIZE2; i++) { memset(dst, *src, EDGE_SIZE2); memcpy(dst + EDGE_SIZE2, src, width2); memset(dst + edged_width2 - EDGE_SIZE2, *(src + width2 - 1), EDGE_SIZE2); dst += edged_width2; } /* V */ dst = image->v - (EDGE_SIZE2 + EDGE_SIZE2 * edged_width2); src = image->v; for (i = 0; i < EDGE_SIZE2; i++) { memset(dst, *src, EDGE_SIZE2); memcpy(dst + EDGE_SIZE2, src, width2); memset(dst + edged_width2 - EDGE_SIZE2, *(src + width2 - 1), EDGE_SIZE2); dst += edged_width2; } for (i = 0; i < height / 2; i++) { memset(dst, *src, EDGE_SIZE2); memset(dst + edged_width2 - EDGE_SIZE2, src[width2 - 1], EDGE_SIZE2); dst += edged_width2; src += edged_width2; } src -= edged_width2; for (i = 0; i < EDGE_SIZE2; i++) { memset(dst, *src, EDGE_SIZE2); memcpy(dst + EDGE_SIZE2, src, width2); memset(dst + edged_width2 - EDGE_SIZE2, *(src + width2 - 1), EDGE_SIZE2); dst += edged_width2; }}/* bframe encoding requires image-based u,v interpolation */voidimage_interpolate(const IMAGE * refn, IMAGE * refh, IMAGE * refv, IMAGE * refhv, uint32_t edged_width, uint32_t edged_height, uint32_t quarterpel, uint32_t rounding){ const uint32_t offset = EDGE_SIZE2 * (edged_width + 1); /* we only interpolate half of the edge area */ const uint32_t stride_add = 7 * edged_width;#if 0 const uint32_t edged_width2 = edged_width / 2; const uint32_t edged_height2 = edged_height / 2; const uint32_t offset2 = EDGE_SIZE2 * (edged_width2 + 1); const uint32_t stride_add2 = 7 * edged_width2;#endif uint8_t *n_ptr, *h_ptr, *v_ptr, *hv_ptr; uint32_t x, y; n_ptr = refn->y; h_ptr = refh->y; v_ptr = refv->y; n_ptr -= offset; h_ptr -= offset; v_ptr -= offset; /* Note we initialize the hv pointer later, as we can optimize code a bit * doing it down to up in quarterpel and up to down in halfpel */ if(quarterpel) { for (y = 0; y < (edged_height - EDGE_SIZE); y += 8) { for (x = 0; x < (edged_width - EDGE_SIZE); x += 8) { interpolate8x8_6tap_lowpass_h(h_ptr, n_ptr, edged_width, rounding); interpolate8x8_6tap_lowpass_v(v_ptr, n_ptr, edged_width, rounding); n_ptr += 8; h_ptr += 8; v_ptr += 8; } n_ptr += EDGE_SIZE; h_ptr += EDGE_SIZE; v_ptr += EDGE_SIZE; h_ptr += stride_add; v_ptr += stride_add; n_ptr += stride_add; } h_ptr = refh->y + (edged_height - EDGE_SIZE - EDGE_SIZE2)*edged_width - EDGE_SIZE2; hv_ptr = refhv->y + (edged_height - EDGE_SIZE - EDGE_SIZE2)*edged_width - EDGE_SIZE2; for (y = 0; y < (edged_height - EDGE_SIZE); y = y + 8) { hv_ptr -= stride_add; h_ptr -= stride_add; hv_ptr -= EDGE_SIZE; h_ptr -= EDGE_SIZE; for (x = 0; x < (edged_width - EDGE_SIZE); x = x + 8) { hv_ptr -= 8; h_ptr -= 8; interpolate8x8_6tap_lowpass_v(hv_ptr, h_ptr, edged_width, rounding); } } } else { hv_ptr = refhv->y; hv_ptr -= offset; for (y = 0; y < (edged_height - EDGE_SIZE); y += 8) { for (x = 0; x < (edged_width - EDGE_SIZE); x += 8) { interpolate8x8_halfpel_h(h_ptr, n_ptr, edged_width, rounding); interpolate8x8_halfpel_v(v_ptr, n_ptr, edged_width, rounding); interpolate8x8_halfpel_hv(hv_ptr, n_ptr, edged_width, rounding); n_ptr += 8; h_ptr += 8; v_ptr += 8; hv_ptr += 8; } h_ptr += EDGE_SIZE; v_ptr += EDGE_SIZE; hv_ptr += EDGE_SIZE; n_ptr += EDGE_SIZE; h_ptr += stride_add; v_ptr += stride_add; hv_ptr += stride_add; n_ptr += stride_add; } }/*#ifdef BFRAMES n_ptr = refn->u; h_ptr = refh->u; v_ptr = refv->u; hv_ptr = refhv->u; n_ptr -= offset2; h_ptr -= offset2; v_ptr -= offset2; hv_ptr -= offset2; for (y = 0; y < edged_height2; y += 8) { for (x = 0; x < edged_width2; x += 8) { interpolate8x8_halfpel_h(h_ptr, n_ptr, edged_width2, rounding); interpolate8x8_halfpel_v(v_ptr, n_ptr, edged_width2, rounding); interpolate8x8_halfpel_hv(hv_ptr, n_ptr, edged_width2, rounding); n_ptr += 8; h_ptr += 8; v_ptr += 8; hv_ptr += 8; } h_ptr += stride_add2; v_ptr += stride_add2; hv_ptr += stride_add2; n_ptr += stride_add2; } n_ptr = refn->v; h_ptr = refh->v; v_ptr = refv->v; hv_ptr = refhv->v; n_ptr -= offset2; h_ptr -= offset2; v_ptr -= offset2; hv_ptr -= offset2; for (y = 0; y < edged_height2; y = y + 8) { for (x = 0; x < edged_width2; x = x + 8) { interpolate8x8_halfpel_h(h_ptr, n_ptr, edged_width2, rounding); interpolate8x8_halfpel_v(v_ptr, n_ptr, edged_width2, rounding); interpolate8x8_halfpel_hv(hv_ptr, n_ptr, edged_width2, rounding); n_ptr += 8; h_ptr += 8; v_ptr += 8; hv_ptr += 8; } h_ptr += stride_add2; v_ptr += stride_add2; hv_ptr += stride_add2; n_ptr += stride_add2; }#endif*/ /* interpolate_halfpel_h( refh->y - offset, refn->y - offset, edged_width, edged_height, rounding); interpolate_halfpel_v( refv->y - offset, refn->y - offset, edged_width, edged_height, rounding); interpolate_halfpel_hv( refhv->y - offset, refn->y - offset, edged_width, edged_height, rounding); */ /* uv-image-based compensation offset = EDGE_SIZE2 * (edged_width / 2 + 1); interpolate_halfpel_h( refh->u - offset, refn->u - offset, edged_width / 2, edged_height / 2, rounding); interpolate_halfpel_v( refv->u - offset, refn->u - offset, edged_width / 2, edged_height / 2, rounding); interpolate_halfpel_hv( refhv->u - offset, refn->u - offset, edged_width / 2, edged_height / 2, rounding); interpolate_halfpel_h( refh->v - offset, refn->v - offset, edged_width / 2, edged_height / 2, rounding); interpolate_halfpel_v( refv->v - offset, refn->v - offset, edged_width / 2, edged_height / 2, rounding); interpolate_halfpel_hv( refhv->v - offset, refn->v - offset, edged_width / 2, edged_height / 2, rounding); */}/*chroma optimize filter, invented by mfa chroma pixel is average from the surrounding pixels, when thecorrepsonding luma pixels are pure black or white.*/voidimage_chroma_optimize(IMAGE * img, int width, int height, int edged_width){ int x,y; int pixels = 0; for (y = 1; y < height/2 - 1; y++) for (x = 1; x < width/2 - 1; x++) {#define IS_PURE(a) ((a)<=16||(a)>=235)#define IMG_Y(Y,X) img->y[(Y)*edged_width + (X)]#define IMG_U(Y,X) img->u[(Y)*edged_width/2 + (X)]#define IMG_V(Y,X) img->v[(Y)*edged_width/2 + (X)] if (IS_PURE(IMG_Y(y*2 ,x*2 )) && IS_PURE(IMG_Y(y*2 ,x*2+1)) && IS_PURE(IMG_Y(y*2+1,x*2 )) && IS_PURE(IMG_Y(y*2+1,x*2+1))) { IMG_U(y,x) = (IMG_U(y,x-1) + IMG_U(y-1, x) + IMG_U(y, x+1) + IMG_U(y+1, x)) / 4; IMG_V(y,x) = (IMG_V(y,x-1) + IMG_V(y-1, x) + IMG_V(y, x+1) + IMG_V(y+1, x)) / 4; pixels++; }#undef IS_PURE#undef IMG_Y#undef IMG_U#undef IMG_V } DPRINTF(XVID_DEBUG_DEBUG,"chroma_optimized_pixels = %i/%i\n", pixels, width*height/4);}/* perform safe packed colorspace conversion, by splitting the image up into an optimized area (pixel width divisible by 16), and two unoptimized/plain-c areas (pixel width divisible by 2)*/static voidsafe_packed_conv(uint8_t * x_ptr, int x_stride, uint8_t * y_ptr, uint8_t * u_ptr, uint8_t * v_ptr, int y_stride, int uv_stride, int width, int height, int vflip, packedFunc * func_opt, packedFunc func_c, int size){ int width_opt, width_c; if (func_opt != func_c && x_stride < size*((width+15)/16)*16) { width_opt = width & (~15); width_c = width - width_opt; } else { width_opt = width; width_c = 0; } func_opt(x_ptr, x_stride, y_ptr, u_ptr, v_ptr, y_stride, uv_stride, width_opt, height, vflip); if (width_c) { func_c(x_ptr + size*width_opt, x_stride, y_ptr + width_opt, u_ptr + width_opt/2, v_ptr + width_opt/2, y_stride, uv_stride, width_c, height, vflip); }}intimage_input(IMAGE * image, uint32_t width, int height, uint32_t edged_width, uint8_t * src[4], int src_stride[4], int csp, int interlacing){ const int edged_width2 = edged_width/2; const int width2 = width/2; const int height2 = height/2;#if 0 const int height_signed = (csp & XVID_CSP_VFLIP) ? -height : height;#endif switch (csp & ~XVID_CSP_VFLIP) { case XVID_CSP_RGB555: safe_packed_conv( src[0], src_stride[0], image->y, image->u, image->v, edged_width, edged_width2, width, height, (csp & XVID_CSP_VFLIP), interlacing?rgb555i_to_yv12 :rgb555_to_yv12, interlacing?rgb555i_to_yv12_c:rgb555_to_yv12_c, 2); break; case XVID_CSP_RGB565: safe_packed_conv( src[0], src_stride[0], image->y, image->u, image->v, edged_width, edged_width2, width, height, (csp & XVID_CSP_VFLIP), interlacing?rgb565i_to_yv12 :rgb565_to_yv12, interlacing?rgb565i_to_yv12_c:rgb565_to_yv12_c, 2);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -