diff options
author | Øyvind Kolås <pippin@gimp.org> | 2014-03-23 02:13:26 +0100 |
---|---|---|
committer | Michael Niedermayer <michaelni@gmx.at> | 2014-03-25 13:48:06 +0100 |
commit | 3e6016622e6fc5967e55d41e8074558d43bc33c0 (patch) | |
tree | 8a6508c39c49af4f465967c3a273a597b5183ac4 /libswscale/output.c | |
parent | a490970af2f081d3c0ae279b561406cb583ac9e4 (diff) | |
download | ffmpeg-3e6016622e6fc5967e55d41e8074558d43bc33c0.tar.gz |
swscale: add two spatially stable dithering methods
Both of these dithering methods are from http://pippin.gimp.org/a_dither/ for
GIF they can be considered better than bayer (provides more gray-levels), and
spatial stability - often more than twice as good compression and less visual
flicker than error diffusion methods (the methods also avoids error-shadow
artifacts of diffusion dithers).
These methods are similar to blue/green noise type dither masks; but are
simple enough to generate their mask on the fly. They are still research work
in progress; though more expensive to generate masks (which can be used in a
LUT) like 'void and cluster' and similar methods will yield superior results
Diffstat (limited to 'libswscale/output.c')
-rw-r--r-- | libswscale/output.c | 83 |
1 files changed, 65 insertions, 18 deletions
diff --git a/libswscale/output.c b/libswscale/output.c index ddb0d0c19e..f41b32ac63 100644 --- a/libswscale/output.c +++ b/libswscale/output.c @@ -1508,24 +1508,71 @@ static av_always_inline void yuv2rgb_write_full(SwsContext *c, case AV_PIX_FMT_RGB8: { int r,g,b; - R >>= 22; - G >>= 22; - B >>= 22; - R += (7*err[0] + 1*c->dither_error[0][i] + 5*c->dither_error[0][i+1] + 3*c->dither_error[0][i+2])>>4; - G += (7*err[1] + 1*c->dither_error[1][i] + 5*c->dither_error[1][i+1] + 3*c->dither_error[1][i+2])>>4; - B += (7*err[2] + 1*c->dither_error[2][i] + 5*c->dither_error[2][i+1] + 3*c->dither_error[2][i+2])>>4; - c->dither_error[0][i] = err[0]; - c->dither_error[1][i] = err[1]; - c->dither_error[2][i] = err[2]; - r = R >> (isrgb8 ? 5 : 7); - g = G >> (isrgb8 ? 5 : 6); - b = B >> (isrgb8 ? 6 : 7); - r = av_clip(r, 0, isrgb8 ? 7 : 1); - g = av_clip(g, 0, isrgb8 ? 7 : 3); - b = av_clip(b, 0, isrgb8 ? 3 : 1); - err[0] = R - r*(isrgb8 ? 36 : 255); - err[1] = G - g*(isrgb8 ? 36 : 85); - err[2] = B - b*(isrgb8 ? 85 : 255); + + switch (c->dither) { + default: + case SWS_DITHER_AUTO: + case SWS_DITHER_ED: + R >>= 22; + G >>= 22; + B >>= 22; + R += (7*err[0] + 1*c->dither_error[0][i] + 5*c->dither_error[0][i+1] + 3*c->dither_error[0][i+2])>>4; + G += (7*err[1] + 1*c->dither_error[1][i] + 5*c->dither_error[1][i+1] + 3*c->dither_error[1][i+2])>>4; + B += (7*err[2] + 1*c->dither_error[2][i] + 5*c->dither_error[2][i+1] + 3*c->dither_error[2][i+2])>>4; + c->dither_error[0][i] = err[0]; + c->dither_error[1][i] = err[1]; + c->dither_error[2][i] = err[2]; + r = R >> (isrgb8 ? 5 : 7); + g = G >> (isrgb8 ? 5 : 6); + b = B >> (isrgb8 ? 6 : 7); + r = av_clip(r, 0, isrgb8 ? 7 : 1); + g = av_clip(g, 0, isrgb8 ? 7 : 3); + b = av_clip(b, 0, isrgb8 ? 3 : 1); + err[0] = R - r*(isrgb8 ? 36 : 255); + err[1] = G - g*(isrgb8 ? 36 : 85); + err[2] = B - b*(isrgb8 ? 85 : 255); + break; + case SWS_DITHER_A_DITHER: + if (isrgb8) { + /* see http://pippin.gimp.org/a_dither/ for details/origin */ +#define A_DITHER(u,v) (((((u)+((v)*236))*119)&0xff)) + r = (((R >> 19) + A_DITHER(i,y) -96)>>8); + g = (((G >> 19) + A_DITHER(i + 17,y) - 96)>>8); + b = (((B >> 20) + A_DITHER(i + 17*2,y) -96)>>8); + r = av_clip(r, 0, 7); + g = av_clip(g, 0, 7); + b = av_clip(b, 0, 3); + } else { + r = (((R >> 21) + A_DITHER(i,y)-256)>>8); + g = (((G >> 19) + A_DITHER(i + 17,y)-256)>>8); + b = (((B >> 21) + A_DITHER(i + 17*2,y)-256)>>8); + r = av_clip(r, 0, 1); + g = av_clip(g, 0, 3); + b = av_clip(b, 0, 1); + } + break; + case SWS_DITHER_X_DITHER: + if (isrgb8) { + /* see http://pippin.gimp.org/a_dither/ for details/origin */ +#define X_DITHER(u,v) (((((u)^((v)*237))*181)&0x1ff)/2) + r = (((R >> 19) + X_DITHER(i,y) - 96)>>8); + g = (((G >> 19) + X_DITHER(i + 17,y) - 96)>>8); + b = (((B >> 20) + X_DITHER(i + 17*2,y) - 96)>>8); + r = av_clip(r, 0, 7); + g = av_clip(g, 0, 7); + b = av_clip(b, 0, 3); + } else { + r = (((R >> 21) + X_DITHER(i,y)-256)>>8); + g = (((G >> 19) + X_DITHER(i + 17,y)-256)>>8); + b = (((B >> 21) + X_DITHER(i + 17*2,y)-256)>>8); + r = av_clip(r, 0, 1); + g = av_clip(g, 0, 3); + b = av_clip(b, 0, 1); + } + + break; + } + if(target == AV_PIX_FMT_BGR4_BYTE) { dest[0] = r + 2*g + 8*b; } else if(target == AV_PIX_FMT_RGB4_BYTE) { |