📄 subsample.c
字号:
/* * subsample.c: Routines to do chroma subsampling. ("Work In Progress") * * * Copyright (C) 2001 Matthew J. Marjanovic <maddog@mir.com> * * * 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. * */#include <config.h>#include <stdlib.h>#include <string.h>#include <assert.h>#include <mjpeg_types.h>#include "subsample.h"/************************************************************************* * Chroma Subsampling *************************************************************************//* vertical/horizontal interstitial siting * * Y Y Y Y * C C * Y Y Y Y * * Y Y Y Y * C C * Y Y Y Y * */static void ss_444_to_420jpeg(uint8_t *buffer, int width, int height){ uint8_t *in0, *in1, *out; int x, y; in0 = buffer; in1 = buffer + width; out = buffer; for (y = 0; y < height; y += 2) { for (x = 0; x < width; x += 2) { *out = (in0[0] + in0[1] + in1[0] + in1[1]) >> 2; in0 += 2; in1 += 2; out++; } in0 += width; in1 += width; }}/* vertical/horizontal interstitial siting * * Y Y Y Y * C C C inm * Y Y Y Y * * Y Y Y - Y out0 * C | C | C in0 * Y Y Y - Y out1 * * * C C C inp * * * Each iteration through the loop reconstitutes one 2x2 block of * pixels from the "surrounding" 3x3 block of samples... * Boundary conditions are handled by cheap reflection; i.e. the * center sample is simply reused. * */ #define BLANK_CRB in0[1]#if 1 /* triangle/linear filter (otherwise, use the lame box filter) */static void ss_420jpeg_to_444(uint8_t *buffer, int width, int height){ uint8_t *inm, *in0, *inp, *out0, *out1; uint8_t cmm, cm0, cmp, c0m, c00, c0p, cpm, cp0, cpp; int x, y; static uint8_t *saveme = NULL; static int saveme_size = 0; if (width > saveme_size) { free(saveme); saveme_size = width; saveme = malloc(saveme_size * sizeof(saveme[0])); assert(saveme != NULL); } memcpy(saveme, buffer, width); in0 = buffer + (width * height / 4) - 2; inm = in0 - width/2; inp = in0 + width/2; out1 = buffer + (width * height) - 1; out0 = out1 - width; for (y = height; y > 0; y -= 2) { if (y == 2) { in0 = saveme + width/2 - 2; inp = in0 + width/2; } for (x = width; x > 0; x -= 2) {#if 0 if ((x == 2) && (y == 2)) { cmm = in0[1]; cm0 = in0[1]; cmp = in0[2]; c0m = in0[1]; c0p = in0[2]; cpm = inp[1]; cp0 = inp[1]; cpp = inp[2]; } else if ((x == 2) && (y == height)) { cmm = inm[1]; cm0 = inm[1]; cmp = inm[2]; c0m = in0[1]; c0p = in0[2]; cpm = in0[1]; cp0 = in0[1]; cpp = in0[2]; } else if ((x == width) && (y == height)) { cmm = inm[0]; cm0 = inm[1]; cmp = inm[1]; c0m = in0[0]; c0p = in0[1]; cpm = in0[0]; cp0 = in0[1]; cpp = in0[1]; } else if ((x == width) && (y == 2)) { cmm = in0[0]; cm0 = (y == 2) ? BLANK_CRB : inm[1]; cmp = ((x == width) || (y == 2)) ? BLANK_CRB : inm[2]; c0m = (x == 2) ? BLANK_CRB : in0[0]; c0p = (x == width) ? BLANK_CRB : in0[2]; cpm = ((x == 2) || (y == height)) ? BLANK_CRB : inp[0]; cp0 = (y == height) ? BLANK_CRB : inp[1]; cpp = ((x == width) || (y == height)) ? BLANK_CRB : inp[2]; } else if (x == 2) { cmm = ((x == 2) || (y == 2)) ? BLANK_CRB : inm[0]; cm0 = (y == 2) ? BLANK_CRB : inm[1]; cmp = ((x == width) || (y == 2)) ? BLANK_CRB : inm[2]; c0m = (x == 2) ? BLANK_CRB : in0[0]; c0p = (x == width) ? BLANK_CRB : in0[2]; cpm = ((x == 2) || (y == height)) ? BLANK_CRB : inp[0]; cp0 = (y == height) ? BLANK_CRB : inp[1]; cpp = ((x == width) || (y == height)) ? BLANK_CRB : inp[2]; } else if (y == 2) { cmm = ((x == 2) || (y == 2)) ? BLANK_CRB : inm[0]; cm0 = (y == 2) ? BLANK_CRB : inm[1]; cmp = ((x == width) || (y == 2)) ? BLANK_CRB : inm[2]; c0m = (x == 2) ? BLANK_CRB : in0[0]; c0p = (x == width) ? BLANK_CRB : in0[2]; cpm = ((x == 2) || (y == height)) ? BLANK_CRB : inp[0]; cp0 = (y == height) ? BLANK_CRB : inp[1]; cpp = ((x == width) || (y == height)) ? BLANK_CRB : inp[2]; } else if (x == width) { cmm = ((x == 2) || (y == 2)) ? BLANK_CRB : inm[0]; cm0 = (y == 2) ? BLANK_CRB : inm[1]; cmp = ((x == width) || (y == 2)) ? BLANK_CRB : inm[2]; c0m = (x == 2) ? BLANK_CRB : in0[0]; c0p = (x == width) ? BLANK_CRB : in0[2]; cpm = ((x == 2) || (y == height)) ? BLANK_CRB : inp[0]; cp0 = (y == height) ? BLANK_CRB : inp[1]; cpp = ((x == width) || (y == height)) ? BLANK_CRB : inp[2]; } else if (y == height) { cmm = ((x == 2) || (y == 2)) ? BLANK_CRB : inm[0]; cm0 = (y == 2) ? BLANK_CRB : inm[1]; cmp = ((x == width) || (y == 2)) ? BLANK_CRB : inm[2]; c0m = (x == 2) ? BLANK_CRB : in0[0]; c0p = (x == width) ? BLANK_CRB : in0[2]; cpm = ((x == 2) || (y == height)) ? BLANK_CRB : inp[0]; cp0 = (y == height) ? BLANK_CRB : inp[1]; cpp = ((x == width) || (y == height)) ? BLANK_CRB : inp[2]; } else { cmm = ((x == 2) || (y == 2)) ? BLANK_CRB : inm[0]; cm0 = (y == 2) ? BLANK_CRB : inm[1]; cmp = ((x == width) || (y == 2)) ? BLANK_CRB : inm[2]; c0m = (x == 2) ? BLANK_CRB : in0[0]; c0p = (x == width) ? BLANK_CRB : in0[2]; cpm = ((x == 2) || (y == height)) ? BLANK_CRB : inp[0]; cp0 = (y == height) ? BLANK_CRB : inp[1]; cpp = ((x == width) || (y == height)) ? BLANK_CRB : inp[2]; } c00 = in0[1]; cmm = ((x == 2) || (y == 2)) ? BLANK_CRB : inm[0]; cm0 = (y == 2) ? BLANK_CRB : inm[1]; cmp = ((x == width) || (y == 2)) ? BLANK_CRB : inm[2]; c0m = (x == 2) ? BLANK_CRB : in0[0]; c0p = (x == width) ? BLANK_CRB : in0[2]; cpm = ((x == 2) || (y == height)) ? BLANK_CRB : inp[0]; cp0 = (y == height) ? BLANK_CRB : inp[1]; cpp = ((x == width) || (y == height)) ? BLANK_CRB : inp[2];#else cmm = ((x == 2) || (y == 2)) ? BLANK_CRB : inm[0]; cm0 = (y == 2) ? BLANK_CRB : inm[1]; cmp = ((x == width) || (y == 2)) ? BLANK_CRB : inm[2]; c0m = (x == 2) ? BLANK_CRB : in0[0]; c00 = in0[1]; c0p = (x == width) ? BLANK_CRB : in0[2]; cpm = ((x == 2) || (y == height)) ? BLANK_CRB : inp[0]; cp0 = (y == height) ? BLANK_CRB : inp[1]; cpp = ((x == width) || (y == height)) ? BLANK_CRB : inp[2];#endif inm--; in0--; inp--; *(out1--) = (1*cpp + 3*(cp0+c0p) + 9*c00 + 8) >> 4; *(out1--) = (1*cpm + 3*(cp0+c0m) + 9*c00 + 8) >> 4; *(out0--) = (1*cmp + 3*(cm0+c0p) + 9*c00 + 8) >> 4; *(out0--) = (1*cmm + 3*(cm0+c0m) + 9*c00 + 8) >> 4; } out1 -= width; out0 -= width; }}#elsestatic void ss_420jpeg_to_444(uint8_t *buffer, int width, int height){ uint8_t *in, *out0, *out1; int x, y; in = buffer + (width * height / 4) - 1; out1 = buffer + (width * height) - 1; out0 = out1 - width; for (y = height - 1; y >= 0; y -= 2) { for (x = width - 1; x >= 0; x -=2) { uint8_t val = *(in--); *(out1--) = val; *(out1--) = val; *(out0--) = val; *(out0--) = val; } out0 -= width; out1 -= width; }}#endif /* vertical intersitial siting; horizontal cositing * * Y Y Y Y * C C * Y Y Y Y * * Y Y Y Y * C C * Y Y Y Y * * [1,2,1] kernel for horizontal subsampling: * * inX[0] [1] [2] * | | | * C C C C * \ | / * \ | / * C */static void ss_444_to_420mpeg2(uint8_t *buffer, int width, int height){ uint8_t *in0, *in1, *out; int x, y; in0 = buffer; /* points to */ in1 = buffer + width; /* second of pair of lines */ out = buffer; for (y = 0; y < height; y += 2) { /* first column boundary condition -- just repeat it to right */ *out = (in0[0] + (2 * in0[0]) + in0[1] + in1[0] + (2 * in1[0]) + in1[1]) >> 3; out++; in0++; in1++; /* rest of columns just loop */ for (x = 2; x < width; x += 2) { *out = (in0[0] + (2 * in0[1]) + in0[2] + in1[0] + (2 * in1[1]) + in1[2]) >> 3; in0 += 2; in1 += 2; out++; } in0 += width + 1; in1 += width + 1; }} int chroma_sub_implemented(int mode){ switch (mode) { case Y4M_CHROMA_420JPEG: case Y4M_CHROMA_420MPEG2: case Y4M_CHROMA_444: return 1; /* yes, supported */ case Y4M_CHROMA_420PALDV: case Y4M_CHROMA_422: case Y4M_CHROMA_411: case Y4M_CHROMA_444ALPHA: case Y4M_CHROMA_MONO: default: return 0; /* no, unsupported */ }}void chroma_subsample(int mode, uint8_t *ycbcr[], int width, int height){ switch (mode) { case Y4M_CHROMA_444: case Y4M_CHROMA_444ALPHA: case Y4M_CHROMA_MONO: break; case Y4M_CHROMA_420JPEG: ss_444_to_420jpeg(ycbcr[1], width, height); ss_444_to_420jpeg(ycbcr[2], width, height); break; case Y4M_CHROMA_420MPEG2: ss_444_to_420mpeg2(ycbcr[1], width, height); ss_444_to_420mpeg2(ycbcr[2], width, height); break; default: break; }}int chroma_super_implemented(int mode){ switch (mode) { case Y4M_CHROMA_420JPEG: case Y4M_CHROMA_444: return 1; /* yes, supported */ case Y4M_CHROMA_420MPEG2: case Y4M_CHROMA_420PALDV: case Y4M_CHROMA_422: case Y4M_CHROMA_411: case Y4M_CHROMA_444ALPHA: case Y4M_CHROMA_MONO: default: return 0; /* no, unsupported */ }}void chroma_supersample(int mode, uint8_t *ycbcr[], int width, int height){ switch (mode) { case Y4M_CHROMA_444: case Y4M_CHROMA_444ALPHA: case Y4M_CHROMA_MONO: break; case Y4M_CHROMA_420JPEG: ss_420jpeg_to_444(ycbcr[1], width, height); ss_420jpeg_to_444(ycbcr[2], width, height); break; case Y4M_CHROMA_420MPEG2: // ss_420mpeg2_to_444(ycbcr[1], width, height); // ss_420mpeg2_to_444(ycbcr[2], width, height); // exit(4); // break; default: break; }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -