FFMPEG cubic scale 过程
具体流程 ffmpeg/libswscale/swscale.c : 466
ff_rotate_slice(hout_slice, lastPosY, lastCPosY); if (posY < lastLumSrcY + 1) { //luminance Scale for (i = lumStart; i < lumEnd; ++i) desc[i].process(c, &desc[i], firstPosY, lastPosY - firstPosY + 1); } lumBufIndex += lastLumSrcY - lastInLumBuf; lastInLumBuf = lastLumSrcY; if (cPosY < lastChrSrcY + 1) {//X方向scale chroma for (i = chrStart; i < chrEnd; ++i) desc[i].process(c, &desc[i], firstCPosY, lastCPosY - firstCPosY + 1); } chrBufIndex += lastChrSrcY - lastInChrBuf; lastInChrBuf = lastChrSrcY; // wrap buf index around to stay inside the ring buffer if (lumBufIndex >= vLumFilterSize) lumBufIndex -= vLumFilterSize; if (chrBufIndex >= vChrFilterSize) chrBufIndex -= vChrFilterSize; if (!enough_lines) break; // we can't output a dstY line so let's try with the next slice #if HAVE_MMX_INLINE ff_updateMMXDitherTables(c, dstY, lumBufIndex, chrBufIndex, lastInLumBuf, lastInChrBuf); #endif if (should_dither) { c->chrDither8 = ff_dither_8x8_128[chrDstY & 7]; c->lumDither8 = ff_dither_8x8_128[dstY & 7]; } if (dstY >= dstH - 2) { /* hmm looks like we can't use MMX here without overwriting * this array's tail */ ff_sws_init_output_funcs(c, &yuv2plane1, &yuv2planeX, &yuv2nv12cX, &yuv2packed1, &yuv2packed2, &yuv2packedX, &yuv2anyX); use_mmx_vfilter= 0; ff_init_vscale_pfn(c, yuv2plane1, yuv2planeX, yuv2nv12cX, yuv2packed1, yuv2packed2, yuv2packedX, yuv2anyX, use_mmx_vfilter); } { for (i = vStart; i < vEnd; ++i)//Y方向scale desc[i].process(c, &desc[i], dstY, 1); }
hscale
// bilinear / bicubic scaling static void hScale8To15_c(SwsContext *c, int16_t *dst, int dstW, const uint8_t *src, const int16_t *filter, const int32_t *filterPos, int filterSize) { int i; for (i = 0; i < dstW; i++) { int j; int srcPos = filterPos[i]; int val = 0; for (j = 0; j < filterSize; j++) { val += ((int)src[srcPos + j]) * filter[filterSize * i + j]; } dst[i] = FFMIN(val >> 7, (1 << 15) - 1); // the cubic equation does overflow ... } }
具体卷积核为
$40 = {8192, 7314, 2220, -1092, -557, 247, 60, 0, 0, 0, 0, 0,
-1342, 2220, 7314, 7314, 2220, -1092, -557, 247, 60, 0, 0, 0, 307, -557, -1092, 2220, 7314, 7314, 2220, -1092, -557, 247, 60, 0, 60, 247, -557, -1092, 2220, 7314, 7314, 2220, -1092, -557, 247, 60, 60, 247,
-557, -1092, 2220, 7314, 7314, 2220, -1092, -557, 247, 60, 60, 247, -557, -1092, 2220, 7314, 7314, 2220, -1092, -557, 247, 60, 60, 247, -557, -1092, 2220, 7314, 7314, 2220, -1092, -557, 247, 60, 60, 247, -557, -1092, 2220, 7314, 7314, 2220, -1092, -557, 247, 60, 60,
247, -557, -1092, 2220, 7314, 7314, 2220, -1092, -557, 247, 60, 60, 247, -557, -1092, 2220, 7314, 7314, 2220, -1092, -557, 247, 60, 60, 247, -557, -1092, 2220, 7314, 7314, 2220, -1092, -557, 247, 60, 60, 247, -557, -1092, 2220, 7314, 7314, 2220, -1092, -557, 247, 60}
filterPos
(gdb) p *filterPos@960
$41 = {0, 0, 0, 1, 3, 5, 7, 9, 11, 13, 15, 17, 19, 21, 23, 25, 27, 29, 31, 33, 35, 37, 39, 41, 43, 45, 47, 49, 51, 53, 55, 57, 59, 61, 63, 65, 67, 69, 71, 73, 75, 77, 79, 81, 83, 85, 87, 89, 91, 93, 95, 97, 99, 101, 103, 105, 107, 109, 111, 113, 115, 117, 119, 121,
123, 125, 127, 129, 131, 133, 135, 137, 139, 141, 143, 145, 147, 149, 151, 153, 155, 157, 159, 161, 163, 165, 167, 169, 171, 173, 175, 177, 179, 181, 183, 185, 187, 189, 191, 193, 195, 197, 199, 201, 203, 205, 207, 209, 211, 213, 215, 217, 219, 221, 223, 225, 227,
229, 231, 233, 235, 237, 239, 241, 243, 245, 247, 249, 251, 253, 255, 257, 259, 261, 263, 265, 267, 269, 271, 273, 275, 277, 279, 281, 283, 285, 287, 289, 291, 293, 295, 297, 299, 301, 303, 305, 307, 309, 311, 313, 315, 317, 319, 321, 323, 325, 327, 329, 331, 333,
335, 337, 339, 341, 343, 345, 347, 349, 351, 353, 355, 357, 359, 361, 363, 365, 367, 369, 371, 373, 375, 377, 379, 381, 383, 385, 387, 389, 391, 393...}
Lumi hscale
static int lum_h_scale(SwsContext *c, SwsFilterDescriptor *desc, int sliceY, int sliceH) { FilterContext *instance = desc->instance; int srcW = desc->src->width; int dstW = desc->dst->width; int xInc = instance->xInc; int i; for (i = 0; i < sliceH; ++i) { uint8_t ** src = desc->src->plane[0].line; uint8_t ** dst = desc->dst->plane[0].line; int src_pos = sliceY+i - desc->src->plane[0].sliceY; int dst_pos = sliceY+i - desc->dst->plane[0].sliceY; if (c->hyscale_fast) { c->hyscale_fast(c, (int16_t*)dst[dst_pos], dstW, src[src_pos], srcW, xInc); } else { c->hyScale(c, (int16_t*)dst[dst_pos], dstW, (const uint8_t *)src[src_pos], instance->filter, instance->filter_pos, instance->filter_size); } if (c->lumConvertRange) c->lumConvertRange((int16_t*)dst[dst_pos], dstW); desc->dst->plane[0].sliceH += 1; if (desc->alpha) { src = desc->src->plane[3].line; dst = desc->dst->plane[3].line; src_pos = sliceY+i - desc->src->plane[3].sliceY; dst_pos = sliceY+i - desc->dst->plane[3].sliceY; desc->dst->plane[3].sliceH += 1; if (c->hyscale_fast) { c->hyscale_fast(c, (int16_t*)dst[dst_pos], dstW, src[src_pos], srcW, xInc); } else { c->hyScale(c, (int16_t*)dst[dst_pos], dstW, (const uint8_t *)src[src_pos], instance->filter, instance->filter_pos, instance->filter_size); } } } return sliceH; }
chr h scale
static int chr_h_scale(SwsContext *c, SwsFilterDescriptor *desc, int sliceY, int sliceH) { FilterContext *instance = desc->instance; int srcW = AV_CEIL_RSHIFT(desc->src->width, desc->src->h_chr_sub_sample); int dstW = AV_CEIL_RSHIFT(desc->dst->width, desc->dst->h_chr_sub_sample); int xInc = instance->xInc; uint8_t ** src1 = desc->src->plane[1].line; uint8_t ** dst1 = desc->dst->plane[1].line; uint8_t ** src2 = desc->src->plane[2].line; uint8_t ** dst2 = desc->dst->plane[2].line; int src_pos1 = sliceY - desc->src->plane[1].sliceY; int dst_pos1 = sliceY - desc->dst->plane[1].sliceY; int src_pos2 = sliceY - desc->src->plane[2].sliceY; int dst_pos2 = sliceY - desc->dst->plane[2].sliceY; int i; for (i = 0; i < sliceH; ++i) { if (c->hcscale_fast) { c->hcscale_fast(c, (uint16_t*)dst1[dst_pos1+i], (uint16_t*)dst2[dst_pos2+i], dstW, src1[src_pos1+i], src2[src_pos2+i], srcW, xInc); } else { c->hcScale(c, (uint16_t*)dst1[dst_pos1+i], dstW, src1[src_pos1+i], instance->filter, instance->filter_pos, instance->filter_size); c->hcScale(c, (uint16_t*)dst2[dst_pos2+i], dstW, src2[src_pos2+i], instance->filter, instance->filter_pos, instance->filter_size); } if (c->chrConvertRange) c->chrConvertRange((uint16_t*)dst1[dst_pos1+i], (uint16_t*)dst2[dst_pos2+i], dstW); desc->dst->plane[1].sliceH += 1; desc->dst->plane[2].sliceH += 1; } return sliceH; }