| @@ -0,0 +1,59 @@ | |||
| /* | |||
| * This file is part of MPlayer. | |||
| * | |||
| * MPlayer 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. | |||
| * | |||
| * MPlayer 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 MPlayer; if not, write to the Free Software Foundation, Inc., | |||
| * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | |||
| */ | |||
| #ifndef MPLAYER_CPUDETECT_H | |||
| #define MPLAYER_CPUDETECT_H | |||
| //#include "config.h" | |||
| #define CPUTYPE_I386 3 | |||
| #define CPUTYPE_I486 4 | |||
| #define CPUTYPE_I586 5 | |||
| #define CPUTYPE_I686 6 | |||
| #include "libavutil/x86_cpu.h" | |||
| typedef struct cpucaps_s { | |||
| int cpuType; | |||
| int cpuModel; | |||
| int cpuStepping; | |||
| int hasMMX; | |||
| int hasMMX2; | |||
| int has3DNow; | |||
| int has3DNowExt; | |||
| int hasSSE; | |||
| int hasSSE2; | |||
| int hasSSE3; | |||
| int hasSSSE3; | |||
| int hasSSE4a; | |||
| int isX86; | |||
| unsigned cl_size; /* size of cache line */ | |||
| int hasAltiVec; | |||
| int hasTSC; | |||
| } CpuCaps; | |||
| extern CpuCaps gCpuCaps; | |||
| void do_cpuid(unsigned int ax, unsigned int *p); | |||
| void GetCpuCaps(CpuCaps *caps); | |||
| /* returned value is malloc()'ed so free() it after use */ | |||
| char *GetCpuFriendlyName(unsigned int regs[], unsigned int regs2[]); | |||
| #endif /* MPLAYER_CPUDETECT_H */ | |||
| @@ -0,0 +1,170 @@ | |||
| /* | |||
| * This file is part of MPlayer. | |||
| * | |||
| * MPlayer 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. | |||
| * | |||
| * MPlayer 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 MPlayer; if not, write to the Free Software Foundation, Inc., | |||
| * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | |||
| */ | |||
| #include "config.h" | |||
| #include "img_format.h" | |||
| #include "stdio.h" | |||
| const char *vo_format_name(int format) | |||
| { | |||
| static char unknown_format[20]; | |||
| switch(format) | |||
| { | |||
| case IMGFMT_RGB1: return "RGB 1-bit"; | |||
| case IMGFMT_RGB4: return "RGB 4-bit"; | |||
| case IMGFMT_RG4B: return "RGB 4-bit per byte"; | |||
| case IMGFMT_RGB8: return "RGB 8-bit"; | |||
| case IMGFMT_RGB12: return "RGB 12-bit"; | |||
| case IMGFMT_RGB15: return "RGB 15-bit"; | |||
| case IMGFMT_RGB16: return "RGB 16-bit"; | |||
| case IMGFMT_RGB24: return "RGB 24-bit"; | |||
| // case IMGFMT_RGB32: return "RGB 32-bit"; | |||
| case IMGFMT_RGB48LE: return "RGB 48-bit LE"; | |||
| case IMGFMT_RGB48BE: return "RGB 48-bit BE"; | |||
| case IMGFMT_BGR1: return "BGR 1-bit"; | |||
| case IMGFMT_BGR4: return "BGR 4-bit"; | |||
| case IMGFMT_BG4B: return "BGR 4-bit per byte"; | |||
| case IMGFMT_BGR8: return "BGR 8-bit"; | |||
| case IMGFMT_BGR12: return "BGR 12-bit"; | |||
| case IMGFMT_BGR15: return "BGR 15-bit"; | |||
| case IMGFMT_BGR16: return "BGR 16-bit"; | |||
| case IMGFMT_BGR24: return "BGR 24-bit"; | |||
| // case IMGFMT_BGR32: return "BGR 32-bit"; | |||
| case IMGFMT_ABGR: return "ABGR"; | |||
| case IMGFMT_BGRA: return "BGRA"; | |||
| case IMGFMT_ARGB: return "ARGB"; | |||
| case IMGFMT_RGBA: return "RGBA"; | |||
| case IMGFMT_YVU9: return "Planar YVU9"; | |||
| case IMGFMT_IF09: return "Planar IF09"; | |||
| case IMGFMT_YV12: return "Planar YV12"; | |||
| case IMGFMT_I420: return "Planar I420"; | |||
| case IMGFMT_IYUV: return "Planar IYUV"; | |||
| case IMGFMT_CLPL: return "Planar CLPL"; | |||
| case IMGFMT_Y800: return "Planar Y800"; | |||
| case IMGFMT_Y8: return "Planar Y8"; | |||
| case IMGFMT_420P16_LE: return "Planar 420P 16-bit little-endian"; | |||
| case IMGFMT_420P16_BE: return "Planar 420P 16-bit big-endian"; | |||
| case IMGFMT_422P16_LE: return "Planar 422P 16-bit little-endian"; | |||
| case IMGFMT_422P16_BE: return "Planar 422P 16-bit big-endian"; | |||
| case IMGFMT_444P16_LE: return "Planar 444P 16-bit little-endian"; | |||
| case IMGFMT_444P16_BE: return "Planar 444P 16-bit big-endian"; | |||
| case IMGFMT_420A: return "Planar 420P with alpha"; | |||
| case IMGFMT_444P: return "Planar 444P"; | |||
| case IMGFMT_422P: return "Planar 422P"; | |||
| case IMGFMT_411P: return "Planar 411P"; | |||
| case IMGFMT_NV12: return "Planar NV12"; | |||
| case IMGFMT_NV21: return "Planar NV21"; | |||
| case IMGFMT_HM12: return "Planar NV12 Macroblock"; | |||
| case IMGFMT_IUYV: return "Packed IUYV"; | |||
| case IMGFMT_IY41: return "Packed IY41"; | |||
| case IMGFMT_IYU1: return "Packed IYU1"; | |||
| case IMGFMT_IYU2: return "Packed IYU2"; | |||
| case IMGFMT_UYVY: return "Packed UYVY"; | |||
| case IMGFMT_UYNV: return "Packed UYNV"; | |||
| case IMGFMT_cyuv: return "Packed CYUV"; | |||
| case IMGFMT_Y422: return "Packed Y422"; | |||
| case IMGFMT_YUY2: return "Packed YUY2"; | |||
| case IMGFMT_YUNV: return "Packed YUNV"; | |||
| case IMGFMT_YVYU: return "Packed YVYU"; | |||
| case IMGFMT_Y41P: return "Packed Y41P"; | |||
| case IMGFMT_Y211: return "Packed Y211"; | |||
| case IMGFMT_Y41T: return "Packed Y41T"; | |||
| case IMGFMT_Y42T: return "Packed Y42T"; | |||
| case IMGFMT_V422: return "Packed V422"; | |||
| case IMGFMT_V655: return "Packed V655"; | |||
| case IMGFMT_CLJR: return "Packed CLJR"; | |||
| case IMGFMT_YUVP: return "Packed YUVP"; | |||
| case IMGFMT_UYVP: return "Packed UYVP"; | |||
| case IMGFMT_MPEGPES: return "Mpeg PES"; | |||
| case IMGFMT_ZRMJPEGNI: return "Zoran MJPEG non-interlaced"; | |||
| case IMGFMT_ZRMJPEGIT: return "Zoran MJPEG top field first"; | |||
| case IMGFMT_ZRMJPEGIB: return "Zoran MJPEG bottom field first"; | |||
| case IMGFMT_XVMC_MOCO_MPEG2: return "MPEG1/2 Motion Compensation"; | |||
| case IMGFMT_XVMC_IDCT_MPEG2: return "MPEG1/2 Motion Compensation and IDCT"; | |||
| case IMGFMT_VDPAU_MPEG1: return "MPEG1 VDPAU acceleration"; | |||
| case IMGFMT_VDPAU_MPEG2: return "MPEG2 VDPAU acceleration"; | |||
| case IMGFMT_VDPAU_H264: return "H.264 VDPAU acceleration"; | |||
| case IMGFMT_VDPAU_MPEG4: return "MPEG-4 Part 2 VDPAU acceleration"; | |||
| case IMGFMT_VDPAU_WMV3: return "WMV3 VDPAU acceleration"; | |||
| case IMGFMT_VDPAU_VC1: return "VC1 VDPAU acceleration"; | |||
| } | |||
| snprintf(unknown_format,20,"Unknown 0x%04x",format); | |||
| return unknown_format; | |||
| } | |||
| int mp_get_chroma_shift(int format, int *x_shift, int *y_shift) | |||
| { | |||
| int xs = 0, ys = 0; | |||
| int bpp; | |||
| int bpp_factor = 1; | |||
| int err = 0; | |||
| switch (format) { | |||
| case IMGFMT_420P16_LE: | |||
| case IMGFMT_420P16_BE: | |||
| bpp_factor = 2; | |||
| case IMGFMT_420A: | |||
| case IMGFMT_I420: | |||
| case IMGFMT_IYUV: | |||
| case IMGFMT_YV12: | |||
| xs = 1; | |||
| ys = 1; | |||
| break; | |||
| case IMGFMT_IF09: | |||
| case IMGFMT_YVU9: | |||
| xs = 2; | |||
| ys = 2; | |||
| break; | |||
| case IMGFMT_444P16_LE: | |||
| case IMGFMT_444P16_BE: | |||
| bpp_factor = 2; | |||
| case IMGFMT_444P: | |||
| xs = 0; | |||
| ys = 0; | |||
| break; | |||
| case IMGFMT_422P16_LE: | |||
| case IMGFMT_422P16_BE: | |||
| bpp_factor = 2; | |||
| case IMGFMT_422P: | |||
| xs = 1; | |||
| ys = 0; | |||
| break; | |||
| case IMGFMT_411P: | |||
| xs = 2; | |||
| ys = 0; | |||
| break; | |||
| case IMGFMT_440P: | |||
| xs = 0; | |||
| ys = 1; | |||
| break; | |||
| case IMGFMT_Y8: | |||
| case IMGFMT_Y800: | |||
| xs = 31; | |||
| ys = 31; | |||
| break; | |||
| default: | |||
| err = 1; | |||
| break; | |||
| } | |||
| if (x_shift) *x_shift = xs; | |||
| if (y_shift) *y_shift = ys; | |||
| bpp = 8 + ((16 >> xs) >> ys); | |||
| if (format == IMGFMT_420A) | |||
| bpp += 8; | |||
| bpp *= bpp_factor; | |||
| return err ? 0 : bpp; | |||
| } | |||
| @@ -0,0 +1,214 @@ | |||
| /* | |||
| * This file is part of MPlayer. | |||
| * | |||
| * MPlayer 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. | |||
| * | |||
| * MPlayer 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 MPlayer; if not, write to the Free Software Foundation, Inc., | |||
| * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | |||
| */ | |||
| #ifndef MPLAYER_IMG_FORMAT_H | |||
| #define MPLAYER_IMG_FORMAT_H | |||
| #include "config.h" | |||
| /* RGB/BGR Formats */ | |||
| #define IMGFMT_RGB_MASK 0xFFFFFF00 | |||
| #define IMGFMT_RGB (('R'<<24)|('G'<<16)|('B'<<8)) | |||
| #define IMGFMT_RGB1 (IMGFMT_RGB|1) | |||
| #define IMGFMT_RGB4 (IMGFMT_RGB|4) | |||
| #define IMGFMT_RGB4_CHAR (IMGFMT_RGB|4|128) // RGB4 with 1 pixel per byte | |||
| #define IMGFMT_RGB8 (IMGFMT_RGB|8) | |||
| #define IMGFMT_RGB12 (IMGFMT_RGB|12) | |||
| #define IMGFMT_RGB15 (IMGFMT_RGB|15) | |||
| #define IMGFMT_RGB16 (IMGFMT_RGB|16) | |||
| #define IMGFMT_RGB24 (IMGFMT_RGB|24) | |||
| #define IMGFMT_RGB32 (IMGFMT_RGB|32) | |||
| #define IMGFMT_RGB48LE (IMGFMT_RGB|48) | |||
| #define IMGFMT_RGB48BE (IMGFMT_RGB|48|128) | |||
| #define IMGFMT_BGR_MASK 0xFFFFFF00 | |||
| #define IMGFMT_BGR (('B'<<24)|('G'<<16)|('R'<<8)) | |||
| #define IMGFMT_BGR1 (IMGFMT_BGR|1) | |||
| #define IMGFMT_BGR4 (IMGFMT_BGR|4) | |||
| #define IMGFMT_BGR4_CHAR (IMGFMT_BGR|4|128) // BGR4 with 1 pixel per byte | |||
| #define IMGFMT_BGR8 (IMGFMT_BGR|8) | |||
| #define IMGFMT_BGR12 (IMGFMT_BGR|12) | |||
| #define IMGFMT_BGR15 (IMGFMT_BGR|15) | |||
| #define IMGFMT_BGR16 (IMGFMT_BGR|16) | |||
| #define IMGFMT_BGR24 (IMGFMT_BGR|24) | |||
| #define IMGFMT_BGR32 (IMGFMT_BGR|32) | |||
| #if HAVE_BIGENDIAN | |||
| #define IMGFMT_ABGR IMGFMT_RGB32 | |||
| #define IMGFMT_BGRA (IMGFMT_RGB32|64) | |||
| #define IMGFMT_ARGB IMGFMT_BGR32 | |||
| #define IMGFMT_RGBA (IMGFMT_BGR32|64) | |||
| #define IMGFMT_RGB48NE IMGFMT_RGB48BE | |||
| #define IMGFMT_RGB12BE IMGFMT_RGB12 | |||
| #define IMGFMT_RGB12LE (IMGFMT_RGB12|64) | |||
| #define IMGFMT_RGB15BE IMGFMT_RGB15 | |||
| #define IMGFMT_RGB15LE (IMGFMT_RGB15|64) | |||
| #define IMGFMT_RGB16BE IMGFMT_RGB16 | |||
| #define IMGFMT_RGB16LE (IMGFMT_RGB16|64) | |||
| #define IMGFMT_BGR12BE IMGFMT_BGR12 | |||
| #define IMGFMT_BGR12LE (IMGFMT_BGR12|64) | |||
| #define IMGFMT_BGR15BE IMGFMT_BGR15 | |||
| #define IMGFMT_BGR15LE (IMGFMT_BGR15|64) | |||
| #define IMGFMT_BGR16BE IMGFMT_BGR16 | |||
| #define IMGFMT_BGR16LE (IMGFMT_BGR16|64) | |||
| #else | |||
| #define IMGFMT_ABGR (IMGFMT_BGR32|64) | |||
| #define IMGFMT_BGRA IMGFMT_BGR32 | |||
| #define IMGFMT_ARGB (IMGFMT_RGB32|64) | |||
| #define IMGFMT_RGBA IMGFMT_RGB32 | |||
| #define IMGFMT_RGB48NE IMGFMT_RGB48LE | |||
| #define IMGFMT_RGB12BE (IMGFMT_RGB12|64) | |||
| #define IMGFMT_RGB12LE IMGFMT_RGB12 | |||
| #define IMGFMT_RGB15BE (IMGFMT_RGB15|64) | |||
| #define IMGFMT_RGB15LE IMGFMT_RGB15 | |||
| #define IMGFMT_RGB16BE (IMGFMT_RGB16|64) | |||
| #define IMGFMT_RGB16LE IMGFMT_RGB16 | |||
| #define IMGFMT_BGR12BE (IMGFMT_BGR12|64) | |||
| #define IMGFMT_BGR12LE IMGFMT_BGR12 | |||
| #define IMGFMT_BGR15BE (IMGFMT_BGR15|64) | |||
| #define IMGFMT_BGR15LE IMGFMT_BGR15 | |||
| #define IMGFMT_BGR16BE (IMGFMT_BGR16|64) | |||
| #define IMGFMT_BGR16LE IMGFMT_BGR16 | |||
| #endif | |||
| /* old names for compatibility */ | |||
| #define IMGFMT_RG4B IMGFMT_RGB4_CHAR | |||
| #define IMGFMT_BG4B IMGFMT_BGR4_CHAR | |||
| #define IMGFMT_IS_RGB(fmt) (((fmt)&IMGFMT_RGB_MASK)==IMGFMT_RGB) | |||
| #define IMGFMT_IS_BGR(fmt) (((fmt)&IMGFMT_BGR_MASK)==IMGFMT_BGR) | |||
| #define IMGFMT_RGB_DEPTH(fmt) ((fmt)&0x3F) | |||
| #define IMGFMT_BGR_DEPTH(fmt) ((fmt)&0x3F) | |||
| /* Planar YUV Formats */ | |||
| #define IMGFMT_YVU9 0x39555659 | |||
| #define IMGFMT_IF09 0x39304649 | |||
| #define IMGFMT_YV12 0x32315659 | |||
| #define IMGFMT_I420 0x30323449 | |||
| #define IMGFMT_IYUV 0x56555949 | |||
| #define IMGFMT_CLPL 0x4C504C43 | |||
| #define IMGFMT_Y800 0x30303859 | |||
| #define IMGFMT_Y8 0x20203859 | |||
| #define IMGFMT_NV12 0x3231564E | |||
| #define IMGFMT_NV21 0x3132564E | |||
| /* unofficial Planar Formats, FIXME if official 4CC exists */ | |||
| #define IMGFMT_444P 0x50343434 | |||
| #define IMGFMT_422P 0x50323234 | |||
| #define IMGFMT_411P 0x50313134 | |||
| #define IMGFMT_440P 0x50303434 | |||
| #define IMGFMT_HM12 0x32314D48 | |||
| // 4:2:0 planar with alpha | |||
| #define IMGFMT_420A 0x41303234 | |||
| #define IMGFMT_444P16_LE 0x51343434 | |||
| #define IMGFMT_444P16_BE 0x34343451 | |||
| #define IMGFMT_422P16_LE 0x51323234 | |||
| #define IMGFMT_422P16_BE 0x34323251 | |||
| #define IMGFMT_420P16_LE 0x51303234 | |||
| #define IMGFMT_420P16_BE 0x34323051 | |||
| #if HAVE_BIGENDIAN | |||
| #define IMGFMT_444P16 IMGFMT_444P16_BE | |||
| #define IMGFMT_422P16 IMGFMT_422P16_BE | |||
| #define IMGFMT_420P16 IMGFMT_420P16_BE | |||
| #else | |||
| #define IMGFMT_444P16 IMGFMT_444P16_LE | |||
| #define IMGFMT_422P16 IMGFMT_422P16_LE | |||
| #define IMGFMT_420P16 IMGFMT_420P16_LE | |||
| #endif | |||
| #define IMGFMT_IS_YUVP16_LE(fmt) (((fmt ^ IMGFMT_420P16_LE) & 0xff0000ff) == 0) | |||
| #define IMGFMT_IS_YUVP16_BE(fmt) (((fmt ^ IMGFMT_420P16_BE) & 0xff0000ff) == 0) | |||
| #define IMGFMT_IS_YUVP16_NE(fmt) (((fmt ^ IMGFMT_420P16 ) & 0xff0000ff) == 0) | |||
| #define IMGFMT_IS_YUVP16(fmt) (IMGFMT_IS_YUVP16_LE(fmt) || IMGFMT_IS_YUVP16_BE(fmt)) | |||
| /* Packed YUV Formats */ | |||
| #define IMGFMT_IUYV 0x56595549 | |||
| #define IMGFMT_IY41 0x31435949 | |||
| #define IMGFMT_IYU1 0x31555949 | |||
| #define IMGFMT_IYU2 0x32555949 | |||
| #define IMGFMT_UYVY 0x59565955 | |||
| #define IMGFMT_UYNV 0x564E5955 | |||
| #define IMGFMT_cyuv 0x76757963 | |||
| #define IMGFMT_Y422 0x32323459 | |||
| #define IMGFMT_YUY2 0x32595559 | |||
| #define IMGFMT_YUNV 0x564E5559 | |||
| #define IMGFMT_YVYU 0x55595659 | |||
| #define IMGFMT_Y41P 0x50313459 | |||
| #define IMGFMT_Y211 0x31313259 | |||
| #define IMGFMT_Y41T 0x54313459 | |||
| #define IMGFMT_Y42T 0x54323459 | |||
| #define IMGFMT_V422 0x32323456 | |||
| #define IMGFMT_V655 0x35353656 | |||
| #define IMGFMT_CLJR 0x524A4C43 | |||
| #define IMGFMT_YUVP 0x50565559 | |||
| #define IMGFMT_UYVP 0x50565955 | |||
| /* Compressed Formats */ | |||
| #define IMGFMT_MPEGPES (('M'<<24)|('P'<<16)|('E'<<8)|('S')) | |||
| #define IMGFMT_MJPEG (('M')|('J'<<8)|('P'<<16)|('G'<<24)) | |||
| /* Formats that are understood by zoran chips, we include | |||
| * non-interlaced, interlaced top-first, interlaced bottom-first */ | |||
| #define IMGFMT_ZRMJPEGNI (('Z'<<24)|('R'<<16)|('N'<<8)|('I')) | |||
| #define IMGFMT_ZRMJPEGIT (('Z'<<24)|('R'<<16)|('I'<<8)|('T')) | |||
| #define IMGFMT_ZRMJPEGIB (('Z'<<24)|('R'<<16)|('I'<<8)|('B')) | |||
| // I think that this code could not be used by any other codec/format | |||
| #define IMGFMT_XVMC 0x1DC70000 | |||
| #define IMGFMT_XVMC_MASK 0xFFFF0000 | |||
| #define IMGFMT_IS_XVMC(fmt) (((fmt)&IMGFMT_XVMC_MASK)==IMGFMT_XVMC) | |||
| //these are chroma420 | |||
| #define IMGFMT_XVMC_MOCO_MPEG2 (IMGFMT_XVMC|0x02) | |||
| #define IMGFMT_XVMC_IDCT_MPEG2 (IMGFMT_XVMC|0x82) | |||
| // VDPAU specific format. | |||
| #define IMGFMT_VDPAU 0x1DC80000 | |||
| #define IMGFMT_VDPAU_MASK 0xFFFF0000 | |||
| #define IMGFMT_IS_VDPAU(fmt) (((fmt)&IMGFMT_VDPAU_MASK)==IMGFMT_VDPAU) | |||
| #define IMGFMT_VDPAU_MPEG1 (IMGFMT_VDPAU|0x01) | |||
| #define IMGFMT_VDPAU_MPEG2 (IMGFMT_VDPAU|0x02) | |||
| #define IMGFMT_VDPAU_H264 (IMGFMT_VDPAU|0x03) | |||
| #define IMGFMT_VDPAU_WMV3 (IMGFMT_VDPAU|0x04) | |||
| #define IMGFMT_VDPAU_VC1 (IMGFMT_VDPAU|0x05) | |||
| #define IMGFMT_VDPAU_MPEG4 (IMGFMT_VDPAU|0x06) | |||
| #define IMGFMT_IS_HWACCEL(fmt) (IMGFMT_IS_VDPAU(fmt) || IMGFMT_IS_XVMC(fmt)) | |||
| typedef struct { | |||
| void* data; | |||
| int size; | |||
| int id; // stream id. usually 0x1E0 | |||
| int timestamp; // pts, 90000 Hz counter based | |||
| } vo_mpegpes_t; | |||
| const char *vo_format_name(int format); | |||
| /** | |||
| * Calculates the scale shifts for the chroma planes for planar YUV | |||
| * | |||
| * \return bits-per-pixel for format if successful (i.e. format is 3 or 4-planes planar YUV), 0 otherwise | |||
| */ | |||
| int mp_get_chroma_shift(int format, int *x_shift, int *y_shift); | |||
| #endif /* MPLAYER_IMG_FORMAT_H */ | |||
| @@ -0,0 +1,99 @@ | |||
| /* | |||
| * This file is part of MPlayer. | |||
| * | |||
| * MPlayer is free software; you can redistribute it and/or | |||
| * modify it under the terms of the GNU Lesser General Public | |||
| * License as published by the Free Software Foundation; either | |||
| * version 2.1 of the License, or (at your option) any later version. | |||
| * | |||
| * MPlayer 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 | |||
| * Lesser General Public License for more details. | |||
| * | |||
| * You should have received a copy of the GNU Lesser General Public | |||
| * License along with MPlayer; if not, write to the Free Software | |||
| * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | |||
| */ | |||
| #ifndef MPLAYER_FASTMEMCPY_H | |||
| #define MPLAYER_FASTMEMCPY_H | |||
| #include <inttypes.h> | |||
| #include <string.h> | |||
| #include <stddef.h> | |||
| void * fast_memcpy(void * to, const void * from, size_t len); | |||
| void * mem2agpcpy(void * to, const void * from, size_t len); | |||
| #if ! defined(CONFIG_FASTMEMCPY) || ! (HAVE_MMX || HAVE_MMX2 || HAVE_AMD3DNOW /* || HAVE_SSE || HAVE_SSE2 */) | |||
| #define mem2agpcpy(a,b,c) memcpy(a,b,c) | |||
| #define fast_memcpy(a,b,c) memcpy(a,b,c) | |||
| #endif | |||
| static inline void * mem2agpcpy_pic(void * dst, const void * src, int bytesPerLine, int height, int dstStride, int srcStride) | |||
| { | |||
| int i; | |||
| void *retval=dst; | |||
| if(dstStride == srcStride) | |||
| { | |||
| if (srcStride < 0) { | |||
| src = (uint8_t*)src + (height-1)*srcStride; | |||
| dst = (uint8_t*)dst + (height-1)*dstStride; | |||
| srcStride = -srcStride; | |||
| } | |||
| mem2agpcpy(dst, src, srcStride*height); | |||
| } | |||
| else | |||
| { | |||
| for(i=0; i<height; i++) | |||
| { | |||
| mem2agpcpy(dst, src, bytesPerLine); | |||
| src = (uint8_t*)src + srcStride; | |||
| dst = (uint8_t*)dst + dstStride; | |||
| } | |||
| } | |||
| return retval; | |||
| } | |||
| #define memcpy_pic(d, s, b, h, ds, ss) memcpy_pic2(d, s, b, h, ds, ss, 0) | |||
| #define my_memcpy_pic(d, s, b, h, ds, ss) memcpy_pic2(d, s, b, h, ds, ss, 1) | |||
| /** | |||
| * \param limit2width always skip data between end of line and start of next | |||
| * instead of copying the full block when strides are the same | |||
| */ | |||
| static inline void * memcpy_pic2(void * dst, const void * src, | |||
| int bytesPerLine, int height, | |||
| int dstStride, int srcStride, int limit2width) | |||
| { | |||
| int i; | |||
| void *retval=dst; | |||
| if(!limit2width && dstStride == srcStride) | |||
| { | |||
| if (srcStride < 0) { | |||
| src = (uint8_t*)src + (height-1)*srcStride; | |||
| dst = (uint8_t*)dst + (height-1)*dstStride; | |||
| srcStride = -srcStride; | |||
| } | |||
| fast_memcpy(dst, src, srcStride*height); | |||
| } | |||
| else | |||
| { | |||
| for(i=0; i<height; i++) | |||
| { | |||
| fast_memcpy(dst, src, bytesPerLine); | |||
| src = (uint8_t*)src + srcStride; | |||
| dst = (uint8_t*)dst + dstStride; | |||
| } | |||
| } | |||
| return retval; | |||
| } | |||
| #endif /* MPLAYER_FASTMEMCPY_H */ | |||
| @@ -0,0 +1,287 @@ | |||
| /* | |||
| * Copyright (C) Aaron Holtzman - Aug 1999 | |||
| * Strongly modified, most parts rewritten: A'rpi/ESP-team - 2000-2001 | |||
| * (C) MPlayer developers | |||
| * | |||
| * This file is part of MPlayer. | |||
| * | |||
| * MPlayer 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. | |||
| * | |||
| * MPlayer 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 MPlayer; if not, write to the Free Software Foundation, Inc., | |||
| * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | |||
| */ | |||
| #ifndef MPLAYER_VIDEO_OUT_H | |||
| #define MPLAYER_VIDEO_OUT_H | |||
| #include <inttypes.h> | |||
| #include <stdarg.h> | |||
| //#include "sub/font_load.h" | |||
| #include "libmpcodecs/img_format.h" | |||
| //#include "vidix/vidix.h" | |||
| #define VO_EVENT_EXPOSE 1 | |||
| #define VO_EVENT_RESIZE 2 | |||
| #define VO_EVENT_KEYPRESS 4 | |||
| #define VO_EVENT_REINIT 8 | |||
| #define VO_EVENT_MOVE 16 | |||
| /* Obsolete: VOCTRL_QUERY_VAA 1 */ | |||
| /* does the device support the required format */ | |||
| #define VOCTRL_QUERY_FORMAT 2 | |||
| /* signal a device reset seek */ | |||
| #define VOCTRL_RESET 3 | |||
| /* true if vo driver can use GUI created windows */ | |||
| #define VOCTRL_GUISUPPORT 4 | |||
| #define VOCTRL_GUI_NOWINDOW 19 | |||
| /* used to switch to fullscreen */ | |||
| #define VOCTRL_FULLSCREEN 5 | |||
| /* signal a device pause */ | |||
| #define VOCTRL_PAUSE 7 | |||
| /* start/resume playback */ | |||
| #define VOCTRL_RESUME 8 | |||
| /* libmpcodecs direct rendering: */ | |||
| #define VOCTRL_GET_IMAGE 9 | |||
| #define VOCTRL_DRAW_IMAGE 13 | |||
| #define VOCTRL_SET_SPU_PALETTE 14 | |||
| /* decoding ahead: */ | |||
| #define VOCTRL_GET_NUM_FRAMES 10 | |||
| #define VOCTRL_GET_FRAME_NUM 11 | |||
| #define VOCTRL_SET_FRAME_NUM 12 | |||
| #define VOCTRL_GET_PANSCAN 15 | |||
| #define VOCTRL_SET_PANSCAN 16 | |||
| /* equalizer controls */ | |||
| #define VOCTRL_SET_EQUALIZER 17 | |||
| #define VOCTRL_GET_EQUALIZER 18 | |||
| //#define VOCTRL_GUI_NOWINDOW 19 | |||
| /* Frame duplication */ | |||
| #define VOCTRL_DUPLICATE_FRAME 20 | |||
| // ... 21 | |||
| #define VOCTRL_START_SLICE 21 | |||
| #define VOCTRL_ONTOP 25 | |||
| #define VOCTRL_ROOTWIN 26 | |||
| #define VOCTRL_BORDER 27 | |||
| #define VOCTRL_DRAW_EOSD 28 | |||
| #define VOCTRL_GET_EOSD_RES 29 | |||
| #define VOCTRL_SET_DEINTERLACE 30 | |||
| #define VOCTRL_GET_DEINTERLACE 31 | |||
| #define VOCTRL_UPDATE_SCREENINFO 32 | |||
| // Vo can be used by xover | |||
| #define VOCTRL_XOVERLAY_SUPPORT 22 | |||
| #define VOCTRL_XOVERLAY_SET_COLORKEY 24 | |||
| typedef struct { | |||
| uint32_t x11; // The raw x11 color | |||
| uint16_t r,g,b; | |||
| } mp_colorkey_t; | |||
| #define VOCTRL_XOVERLAY_SET_WIN 23 | |||
| typedef struct { | |||
| int x,y; | |||
| int w,h; | |||
| } mp_win_t; | |||
| #define VO_TRUE 1 | |||
| #define VO_FALSE 0 | |||
| #define VO_ERROR -1 | |||
| #define VO_NOTAVAIL -2 | |||
| #define VO_NOTIMPL -3 | |||
| #define VOFLAG_FULLSCREEN 0x01 | |||
| #define VOFLAG_MODESWITCHING 0x02 | |||
| #define VOFLAG_SWSCALE 0x04 | |||
| #define VOFLAG_FLIPPING 0x08 | |||
| #define VOFLAG_HIDDEN 0x10 //< Use to create a hidden window | |||
| #define VOFLAG_STEREO 0x20 //< Use to create a stereo-capable window | |||
| #define VOFLAG_XOVERLAY_SUB_VO 0x10000 | |||
| typedef struct vo_info_s | |||
| { | |||
| /* driver name ("Matrox Millennium G200/G400" */ | |||
| const char *name; | |||
| /* short name (for config strings) ("mga") */ | |||
| const char *short_name; | |||
| /* author ("Aaron Holtzman <aholtzma@ess.engr.uvic.ca>") */ | |||
| const char *author; | |||
| /* any additional comments */ | |||
| const char *comment; | |||
| } vo_info_t; | |||
| typedef struct vo_functions_s | |||
| { | |||
| const vo_info_t *info; | |||
| /* | |||
| * Preinitializes driver (real INITIALIZATION) | |||
| * arg - currently it's vo_subdevice | |||
| * returns: zero on successful initialization, non-zero on error. | |||
| */ | |||
| int (*preinit)(const char *arg); | |||
| /* | |||
| * Initialize (means CONFIGURE) the display driver. | |||
| * params: | |||
| * width,height: image source size | |||
| * d_width,d_height: size of the requested window size, just a hint | |||
| * fullscreen: flag, 0=windowd 1=fullscreen, just a hint | |||
| * title: window title, if available | |||
| * format: fourcc of pixel format | |||
| * returns : zero on successful initialization, non-zero on error. | |||
| */ | |||
| int (*config)(uint32_t width, uint32_t height, uint32_t d_width, | |||
| uint32_t d_height, uint32_t fullscreen, char *title, | |||
| uint32_t format); | |||
| /* | |||
| * Control interface | |||
| */ | |||
| int (*control)(uint32_t request, void *data, ...); | |||
| /* | |||
| * Display a new RGB/BGR frame of the video to the screen. | |||
| * params: | |||
| * src[0] - pointer to the image | |||
| */ | |||
| int (*draw_frame)(uint8_t *src[]); | |||
| /* | |||
| * Draw a planar YUV slice to the buffer: | |||
| * params: | |||
| * src[3] = source image planes (Y,U,V) | |||
| * stride[3] = source image planes line widths (in bytes) | |||
| * w,h = width*height of area to be copied (in Y pixels) | |||
| * x,y = position at the destination image (in Y pixels) | |||
| */ | |||
| int (*draw_slice)(uint8_t *src[], int stride[], int w,int h, int x,int y); | |||
| /* | |||
| * Draws OSD to the screen buffer | |||
| */ | |||
| void (*draw_osd)(void); | |||
| /* | |||
| * Blit/Flip buffer to the screen. Must be called after each frame! | |||
| */ | |||
| void (*flip_page)(void); | |||
| /* | |||
| * This func is called after every frames to handle keyboard and | |||
| * other events. It's called in PAUSE mode too! | |||
| */ | |||
| void (*check_events)(void); | |||
| /* | |||
| * Closes driver. Should restore the original state of the system. | |||
| */ | |||
| void (*uninit)(void); | |||
| } vo_functions_t; | |||
| const vo_functions_t* init_best_video_out(char** vo_list); | |||
| int config_video_out(const vo_functions_t *vo, uint32_t width, uint32_t height, | |||
| uint32_t d_width, uint32_t d_height, uint32_t flags, | |||
| char *title, uint32_t format); | |||
| void list_video_out(void); | |||
| // NULL terminated array of all drivers | |||
| extern const vo_functions_t* const video_out_drivers[]; | |||
| extern int vo_flags; | |||
| extern int vo_config_count; | |||
| extern int xinerama_screen; | |||
| extern int xinerama_x; | |||
| extern int xinerama_y; | |||
| // correct resolution/bpp on screen: (should be autodetected by vo_init()) | |||
| extern int vo_depthonscreen; | |||
| extern int vo_screenwidth; | |||
| extern int vo_screenheight; | |||
| // requested resolution/bpp: (-x -y -bpp options) | |||
| extern int vo_dx; | |||
| extern int vo_dy; | |||
| extern int vo_dwidth; | |||
| extern int vo_dheight; | |||
| extern int vo_dbpp; | |||
| extern int vo_grabpointer; | |||
| extern int vo_doublebuffering; | |||
| extern int vo_directrendering; | |||
| extern int vo_vsync; | |||
| extern int vo_fs; | |||
| extern int vo_fsmode; | |||
| extern float vo_panscan; | |||
| extern int vo_adapter_num; | |||
| extern int vo_refresh_rate; | |||
| extern int vo_keepaspect; | |||
| extern int vo_rootwin; | |||
| extern int vo_ontop; | |||
| extern int vo_border; | |||
| extern int vo_gamma_gamma; | |||
| extern int vo_gamma_brightness; | |||
| extern int vo_gamma_saturation; | |||
| extern int vo_gamma_contrast; | |||
| extern int vo_gamma_hue; | |||
| extern int vo_gamma_red_intensity; | |||
| extern int vo_gamma_green_intensity; | |||
| extern int vo_gamma_blue_intensity; | |||
| extern int vo_nomouse_input; | |||
| extern int enable_mouse_movements; | |||
| extern int vo_pts; | |||
| extern float vo_fps; | |||
| extern char *vo_subdevice; | |||
| extern int vo_colorkey; | |||
| extern char *vo_winname; | |||
| extern char *vo_wintitle; | |||
| extern int64_t WinID; | |||
| typedef struct { | |||
| float min; | |||
| float max; | |||
| } range_t; | |||
| float range_max(range_t *r); | |||
| int in_range(range_t *r, float f); | |||
| range_t *str2range(char *s); | |||
| extern char *monitor_hfreq_str; | |||
| extern char *monitor_vfreq_str; | |||
| extern char *monitor_dotclock_str; | |||
| struct mp_keymap { | |||
| int from; | |||
| int to; | |||
| }; | |||
| int lookup_keymap_table(const struct mp_keymap *map, int key); | |||
| struct vo_rect { | |||
| int left, right, top, bottom, width, height; | |||
| }; | |||
| void calc_src_dst_rects(int src_width, int src_height, struct vo_rect *src, struct vo_rect *dst, | |||
| struct vo_rect *borders, const struct vo_rect *crop); | |||
| void vo_mouse_movement(int posx, int posy); | |||
| static inline int aspect_scaling(void) | |||
| { | |||
| return vo_fs; | |||
| } | |||
| #endif /* MPLAYER_VIDEO_OUT_H */ | |||
| @@ -0,0 +1,200 @@ | |||
| /* | |||
| * This file is part of MPlayer. | |||
| * | |||
| * MPlayer 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. | |||
| * | |||
| * MPlayer 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 MPlayer; if not, write to the Free Software Foundation, Inc., | |||
| * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | |||
| */ | |||
| #include "config.h" | |||
| #include <stdio.h> | |||
| #include <stdlib.h> | |||
| #include <string.h> | |||
| #if HAVE_MALLOC_H | |||
| #include <malloc.h> | |||
| #endif | |||
| #include "libmpcodecs/img_format.h" | |||
| #include "libmpcodecs/mp_image.h" | |||
| #include "libvo/fastmemcpy.h" | |||
| #include "libavutil/mem.h" | |||
| void mp_image_alloc_planes(mp_image_t *mpi) { | |||
| // IF09 - allocate space for 4. plane delta info - unused | |||
| if (mpi->imgfmt == IMGFMT_IF09) { | |||
| mpi->planes[0]=av_malloc(mpi->bpp*mpi->width*(mpi->height+2)/8+ | |||
| mpi->chroma_width*mpi->chroma_height); | |||
| } else | |||
| mpi->planes[0]=av_malloc(mpi->bpp*mpi->width*(mpi->height+2)/8); | |||
| if (mpi->flags&MP_IMGFLAG_PLANAR) { | |||
| int bpp = IMGFMT_IS_YUVP16(mpi->imgfmt)? 2 : 1; | |||
| // YV12/I420/YVU9/IF09. feel free to add other planar formats here... | |||
| mpi->stride[0]=mpi->stride[3]=bpp*mpi->width; | |||
| if(mpi->num_planes > 2){ | |||
| mpi->stride[1]=mpi->stride[2]=bpp*mpi->chroma_width; | |||
| if(mpi->flags&MP_IMGFLAG_SWAPPED){ | |||
| // I420/IYUV (Y,U,V) | |||
| mpi->planes[1]=mpi->planes[0]+mpi->stride[0]*mpi->height; | |||
| mpi->planes[2]=mpi->planes[1]+mpi->stride[1]*mpi->chroma_height; | |||
| if (mpi->num_planes > 3) | |||
| mpi->planes[3]=mpi->planes[2]+mpi->stride[2]*mpi->chroma_height; | |||
| } else { | |||
| // YV12,YVU9,IF09 (Y,V,U) | |||
| mpi->planes[2]=mpi->planes[0]+mpi->stride[0]*mpi->height; | |||
| mpi->planes[1]=mpi->planes[2]+mpi->stride[1]*mpi->chroma_height; | |||
| if (mpi->num_planes > 3) | |||
| mpi->planes[3]=mpi->planes[1]+mpi->stride[1]*mpi->chroma_height; | |||
| } | |||
| } else { | |||
| // NV12/NV21 | |||
| mpi->stride[1]=mpi->chroma_width; | |||
| mpi->planes[1]=mpi->planes[0]+mpi->stride[0]*mpi->height; | |||
| } | |||
| } else { | |||
| mpi->stride[0]=mpi->width*mpi->bpp/8; | |||
| if (mpi->flags & MP_IMGFLAG_RGB_PALETTE) | |||
| mpi->planes[1] = av_malloc(1024); | |||
| } | |||
| mpi->flags|=MP_IMGFLAG_ALLOCATED; | |||
| } | |||
| mp_image_t* alloc_mpi(int w, int h, unsigned long int fmt) { | |||
| mp_image_t* mpi = new_mp_image(w,h); | |||
| mp_image_setfmt(mpi,fmt); | |||
| mp_image_alloc_planes(mpi); | |||
| return mpi; | |||
| } | |||
| void copy_mpi(mp_image_t *dmpi, mp_image_t *mpi) { | |||
| if(mpi->flags&MP_IMGFLAG_PLANAR){ | |||
| memcpy_pic(dmpi->planes[0],mpi->planes[0], mpi->w, mpi->h, | |||
| dmpi->stride[0],mpi->stride[0]); | |||
| memcpy_pic(dmpi->planes[1],mpi->planes[1], mpi->chroma_width, mpi->chroma_height, | |||
| dmpi->stride[1],mpi->stride[1]); | |||
| memcpy_pic(dmpi->planes[2], mpi->planes[2], mpi->chroma_width, mpi->chroma_height, | |||
| dmpi->stride[2],mpi->stride[2]); | |||
| } else { | |||
| memcpy_pic(dmpi->planes[0],mpi->planes[0], | |||
| mpi->w*(dmpi->bpp/8), mpi->h, | |||
| dmpi->stride[0],mpi->stride[0]); | |||
| } | |||
| } | |||
| void mp_image_setfmt(mp_image_t* mpi,unsigned int out_fmt){ | |||
| mpi->flags&=~(MP_IMGFLAG_PLANAR|MP_IMGFLAG_YUV|MP_IMGFLAG_SWAPPED); | |||
| mpi->imgfmt=out_fmt; | |||
| // compressed formats | |||
| if(out_fmt == IMGFMT_MPEGPES || | |||
| out_fmt == IMGFMT_ZRMJPEGNI || out_fmt == IMGFMT_ZRMJPEGIT || out_fmt == IMGFMT_ZRMJPEGIB || | |||
| IMGFMT_IS_HWACCEL(out_fmt)){ | |||
| mpi->bpp=0; | |||
| return; | |||
| } | |||
| mpi->num_planes=1; | |||
| if (IMGFMT_IS_RGB(out_fmt)) { | |||
| if (IMGFMT_RGB_DEPTH(out_fmt) < 8 && !(out_fmt&128)) | |||
| mpi->bpp = IMGFMT_RGB_DEPTH(out_fmt); | |||
| else | |||
| mpi->bpp=(IMGFMT_RGB_DEPTH(out_fmt)+7)&(~7); | |||
| return; | |||
| } | |||
| if (IMGFMT_IS_BGR(out_fmt)) { | |||
| if (IMGFMT_BGR_DEPTH(out_fmt) < 8 && !(out_fmt&128)) | |||
| mpi->bpp = IMGFMT_BGR_DEPTH(out_fmt); | |||
| else | |||
| mpi->bpp=(IMGFMT_BGR_DEPTH(out_fmt)+7)&(~7); | |||
| mpi->flags|=MP_IMGFLAG_SWAPPED; | |||
| return; | |||
| } | |||
| mpi->flags|=MP_IMGFLAG_YUV; | |||
| mpi->num_planes=3; | |||
| if (mp_get_chroma_shift(out_fmt, NULL, NULL)) { | |||
| mpi->flags|=MP_IMGFLAG_PLANAR; | |||
| mpi->bpp = mp_get_chroma_shift(out_fmt, &mpi->chroma_x_shift, &mpi->chroma_y_shift); | |||
| mpi->chroma_width = mpi->width >> mpi->chroma_x_shift; | |||
| mpi->chroma_height = mpi->height >> mpi->chroma_y_shift; | |||
| } | |||
| switch(out_fmt){ | |||
| case IMGFMT_I420: | |||
| case IMGFMT_IYUV: | |||
| mpi->flags|=MP_IMGFLAG_SWAPPED; | |||
| case IMGFMT_YV12: | |||
| return; | |||
| case IMGFMT_420A: | |||
| case IMGFMT_IF09: | |||
| mpi->num_planes=4; | |||
| case IMGFMT_YVU9: | |||
| case IMGFMT_444P: | |||
| case IMGFMT_422P: | |||
| case IMGFMT_411P: | |||
| case IMGFMT_440P: | |||
| case IMGFMT_444P16_LE: | |||
| case IMGFMT_444P16_BE: | |||
| case IMGFMT_422P16_LE: | |||
| case IMGFMT_422P16_BE: | |||
| case IMGFMT_420P16_LE: | |||
| case IMGFMT_420P16_BE: | |||
| return; | |||
| case IMGFMT_Y800: | |||
| case IMGFMT_Y8: | |||
| /* they're planar ones, but for easier handling use them as packed */ | |||
| mpi->flags&=~MP_IMGFLAG_PLANAR; | |||
| mpi->num_planes=1; | |||
| return; | |||
| case IMGFMT_UYVY: | |||
| mpi->flags|=MP_IMGFLAG_SWAPPED; | |||
| case IMGFMT_YUY2: | |||
| mpi->bpp=16; | |||
| mpi->num_planes=1; | |||
| return; | |||
| case IMGFMT_NV12: | |||
| mpi->flags|=MP_IMGFLAG_SWAPPED; | |||
| case IMGFMT_NV21: | |||
| mpi->flags|=MP_IMGFLAG_PLANAR; | |||
| mpi->bpp=12; | |||
| mpi->num_planes=2; | |||
| mpi->chroma_width=(mpi->width>>0); | |||
| mpi->chroma_height=(mpi->height>>1); | |||
| mpi->chroma_x_shift=0; | |||
| mpi->chroma_y_shift=1; | |||
| return; | |||
| } | |||
| mp_msg(MSGT_DECVIDEO,MSGL_WARN,"mp_image: unknown out_fmt: 0x%X\n",out_fmt); | |||
| mpi->bpp=0; | |||
| } | |||
| mp_image_t* new_mp_image(int w,int h){ | |||
| mp_image_t* mpi = malloc(sizeof(mp_image_t)); | |||
| if(!mpi) return NULL; // error! | |||
| memset(mpi,0,sizeof(mp_image_t)); | |||
| mpi->width=mpi->w=w; | |||
| mpi->height=mpi->h=h; | |||
| return mpi; | |||
| } | |||
| void free_mp_image(mp_image_t* mpi){ | |||
| if(!mpi) return; | |||
| if(mpi->flags&MP_IMGFLAG_ALLOCATED){ | |||
| /* becouse we allocate the whole image in once */ | |||
| av_free(mpi->planes[0]); | |||
| if (mpi->flags & MP_IMGFLAG_RGB_PALETTE) | |||
| av_free(mpi->planes[1]); | |||
| } | |||
| free(mpi); | |||
| } | |||
| @@ -0,0 +1,137 @@ | |||
| /* | |||
| * This file is part of MPlayer. | |||
| * | |||
| * MPlayer 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. | |||
| * | |||
| * MPlayer 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 MPlayer; if not, write to the Free Software Foundation, Inc., | |||
| * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | |||
| */ | |||
| #ifndef MPLAYER_MP_IMAGE_H | |||
| #define MPLAYER_MP_IMAGE_H | |||
| #include <stdio.h> | |||
| #include <stdlib.h> | |||
| #include <string.h> | |||
| #include "mp_msg.h" | |||
| //--------- codec's requirements (filled by the codec/vf) --------- | |||
| //--- buffer content restrictions: | |||
| // set if buffer content shouldn't be modified: | |||
| #define MP_IMGFLAG_PRESERVE 0x01 | |||
| // set if buffer content will be READ for next frame's MC: (I/P mpeg frames) | |||
| #define MP_IMGFLAG_READABLE 0x02 | |||
| //--- buffer width/stride/plane restrictions: (used for direct rendering) | |||
| // stride _have_to_ be aligned to MB boundary: [for DR restrictions] | |||
| #define MP_IMGFLAG_ACCEPT_ALIGNED_STRIDE 0x4 | |||
| // stride should be aligned to MB boundary: [for buffer allocation] | |||
| #define MP_IMGFLAG_PREFER_ALIGNED_STRIDE 0x8 | |||
| // codec accept any stride (>=width): | |||
| #define MP_IMGFLAG_ACCEPT_STRIDE 0x10 | |||
| // codec accept any width (width*bpp=stride -> stride%bpp==0) (>=width): | |||
| #define MP_IMGFLAG_ACCEPT_WIDTH 0x20 | |||
| //--- for planar formats only: | |||
| // uses only stride[0], and stride[1]=stride[2]=stride[0]>>mpi->chroma_x_shift | |||
| #define MP_IMGFLAG_COMMON_STRIDE 0x40 | |||
| // uses only planes[0], and calculates planes[1,2] from width,height,imgfmt | |||
| #define MP_IMGFLAG_COMMON_PLANE 0x80 | |||
| #define MP_IMGFLAGMASK_RESTRICTIONS 0xFF | |||
| //--------- color info (filled by mp_image_setfmt() ) ----------- | |||
| // set if number of planes > 1 | |||
| #define MP_IMGFLAG_PLANAR 0x100 | |||
| // set if it's YUV colorspace | |||
| #define MP_IMGFLAG_YUV 0x200 | |||
| // set if it's swapped (BGR or YVU) plane/byteorder | |||
| #define MP_IMGFLAG_SWAPPED 0x400 | |||
| // set if you want memory for palette allocated and managed by vf_get_image etc. | |||
| #define MP_IMGFLAG_RGB_PALETTE 0x800 | |||
| #define MP_IMGFLAGMASK_COLORS 0xF00 | |||
| // codec uses drawing/rendering callbacks (draw_slice()-like thing, DR method 2) | |||
| // [the codec will set this flag if it supports callbacks, and the vo _may_ | |||
| // clear it in get_image() if draw_slice() not implemented] | |||
| #define MP_IMGFLAG_DRAW_CALLBACK 0x1000 | |||
| // set if it's in video buffer/memory: [set by vo/vf's get_image() !!!] | |||
| #define MP_IMGFLAG_DIRECT 0x2000 | |||
| // set if buffer is allocated (used in destination images): | |||
| #define MP_IMGFLAG_ALLOCATED 0x4000 | |||
| // buffer type was printed (do NOT set this flag - it's for INTERNAL USE!!!) | |||
| #define MP_IMGFLAG_TYPE_DISPLAYED 0x8000 | |||
| // codec doesn't support any form of direct rendering - it has own buffer | |||
| // allocation. so we just export its buffer pointers: | |||
| #define MP_IMGTYPE_EXPORT 0 | |||
| // codec requires a static WO buffer, but it does only partial updates later: | |||
| #define MP_IMGTYPE_STATIC 1 | |||
| // codec just needs some WO memory, where it writes/copies the whole frame to: | |||
| #define MP_IMGTYPE_TEMP 2 | |||
| // I+P type, requires 2+ independent static R/W buffers | |||
| #define MP_IMGTYPE_IP 3 | |||
| // I+P+B type, requires 2+ independent static R/W and 1+ temp WO buffers | |||
| #define MP_IMGTYPE_IPB 4 | |||
| // Upper 16 bits give desired buffer number, -1 means get next available | |||
| #define MP_IMGTYPE_NUMBERED 5 | |||
| // Doesn't need any buffer, incomplete image (probably a first field only) | |||
| // we need this type to be able to differentiate between half frames and | |||
| // all other cases | |||
| #define MP_IMGTYPE_INCOMPLETE 6 | |||
| #define MP_MAX_PLANES 4 | |||
| #define MP_IMGFIELD_ORDERED 0x01 | |||
| #define MP_IMGFIELD_TOP_FIRST 0x02 | |||
| #define MP_IMGFIELD_REPEAT_FIRST 0x04 | |||
| #define MP_IMGFIELD_TOP 0x08 | |||
| #define MP_IMGFIELD_BOTTOM 0x10 | |||
| #define MP_IMGFIELD_INTERLACED 0x20 | |||
| typedef struct mp_image { | |||
| unsigned int flags; | |||
| unsigned char type; | |||
| int number; | |||
| unsigned char bpp; // bits/pixel. NOT depth! for RGB it will be n*8 | |||
| unsigned int imgfmt; | |||
| int width,height; // stored dimensions | |||
| int x,y,w,h; // visible dimensions | |||
| unsigned char* planes[MP_MAX_PLANES]; | |||
| int stride[MP_MAX_PLANES]; | |||
| char * qscale; | |||
| int qstride; | |||
| int pict_type; // 0->unknown, 1->I, 2->P, 3->B | |||
| int fields; | |||
| int qscale_type; // 0->mpeg1/4/h263, 1->mpeg2 | |||
| int num_planes; | |||
| /* these are only used by planar formats Y,U(Cb),V(Cr) */ | |||
| int chroma_width; | |||
| int chroma_height; | |||
| int chroma_x_shift; // horizontal | |||
| int chroma_y_shift; // vertical | |||
| int usage_count; | |||
| /* for private use by filter or vo driver (to store buffer id or dmpi) */ | |||
| void* priv; | |||
| } mp_image_t; | |||
| void mp_image_setfmt(mp_image_t* mpi,unsigned int out_fmt); | |||
| mp_image_t* new_mp_image(int w,int h); | |||
| void free_mp_image(mp_image_t* mpi); | |||
| mp_image_t* alloc_mpi(int w, int h, unsigned long int fmt); | |||
| void mp_image_alloc_planes(mp_image_t *mpi); | |||
| void copy_mpi(mp_image_t *dmpi, mp_image_t *mpi); | |||
| #endif /* MPLAYER_MP_IMAGE_H */ | |||
| @@ -0,0 +1,164 @@ | |||
| /* | |||
| * This file is part of MPlayer. | |||
| * | |||
| * MPlayer 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. | |||
| * | |||
| * MPlayer 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 MPlayer; if not, write to the Free Software Foundation, Inc., | |||
| * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | |||
| */ | |||
| #ifndef MPLAYER_MP_MSG_H | |||
| #define MPLAYER_MP_MSG_H | |||
| #include <stdarg.h> | |||
| // defined in mplayer.c and mencoder.c | |||
| extern int verbose; | |||
| // verbosity elevel: | |||
| /* Only messages level MSGL_FATAL-MSGL_STATUS should be translated, | |||
| * messages level MSGL_V and above should not be translated. */ | |||
| #define MSGL_FATAL 0 // will exit/abort | |||
| #define MSGL_ERR 1 // continues | |||
| #define MSGL_WARN 2 // only warning | |||
| #define MSGL_HINT 3 // short help message | |||
| #define MSGL_INFO 4 // -quiet | |||
| #define MSGL_STATUS 5 // v=0 | |||
| #define MSGL_V 6 // v=1 | |||
| #define MSGL_DBG2 7 // v=2 | |||
| #define MSGL_DBG3 8 // v=3 | |||
| #define MSGL_DBG4 9 // v=4 | |||
| #define MSGL_DBG5 10 // v=5 | |||
| #define MSGL_FIXME 1 // for conversions from printf where the appropriate MSGL is not known; set equal to ERR for obtrusiveness | |||
| #define MSGT_FIXME 0 // for conversions from printf where the appropriate MSGT is not known; set equal to GLOBAL for obtrusiveness | |||
| // code/module: | |||
| #define MSGT_GLOBAL 0 // common player stuff errors | |||
| #define MSGT_CPLAYER 1 // console player (mplayer.c) | |||
| #define MSGT_GPLAYER 2 // gui player | |||
| #define MSGT_VO 3 // libvo | |||
| #define MSGT_AO 4 // libao | |||
| #define MSGT_DEMUXER 5 // demuxer.c (general stuff) | |||
| #define MSGT_DS 6 // demux stream (add/read packet etc) | |||
| #define MSGT_DEMUX 7 // fileformat-specific stuff (demux_*.c) | |||
| #define MSGT_HEADER 8 // fileformat-specific header (*header.c) | |||
| #define MSGT_AVSYNC 9 // mplayer.c timer stuff | |||
| #define MSGT_AUTOQ 10 // mplayer.c auto-quality stuff | |||
| #define MSGT_CFGPARSER 11 // cfgparser.c | |||
| #define MSGT_DECAUDIO 12 // av decoder | |||
| #define MSGT_DECVIDEO 13 | |||
| #define MSGT_SEEK 14 // seeking code | |||
| #define MSGT_WIN32 15 // win32 dll stuff | |||
| #define MSGT_OPEN 16 // open.c (stream opening) | |||
| #define MSGT_DVD 17 // open.c (DVD init/read/seek) | |||
| #define MSGT_PARSEES 18 // parse_es.c (mpeg stream parser) | |||
| #define MSGT_LIRC 19 // lirc_mp.c and input lirc driver | |||
| #define MSGT_STREAM 20 // stream.c | |||
| #define MSGT_CACHE 21 // cache2.c | |||
| #define MSGT_MENCODER 22 | |||
| #define MSGT_XACODEC 23 // XAnim codecs | |||
| #define MSGT_TV 24 // TV input subsystem | |||
| #define MSGT_OSDEP 25 // OS-dependent parts | |||
| #define MSGT_SPUDEC 26 // spudec.c | |||
| #define MSGT_PLAYTREE 27 // Playtree handeling (playtree.c, playtreeparser.c) | |||
| #define MSGT_INPUT 28 | |||
| #define MSGT_VFILTER 29 | |||
| #define MSGT_OSD 30 | |||
| #define MSGT_NETWORK 31 | |||
| #define MSGT_CPUDETECT 32 | |||
| #define MSGT_CODECCFG 33 | |||
| #define MSGT_SWS 34 | |||
| #define MSGT_VOBSUB 35 | |||
| #define MSGT_SUBREADER 36 | |||
| #define MSGT_AFILTER 37 // Audio filter messages | |||
| #define MSGT_NETST 38 // Netstream | |||
| #define MSGT_MUXER 39 // muxer layer | |||
| #define MSGT_OSD_MENU 40 | |||
| #define MSGT_IDENTIFY 41 // -identify output | |||
| #define MSGT_RADIO 42 | |||
| #define MSGT_ASS 43 // libass messages | |||
| #define MSGT_LOADER 44 // dll loader messages | |||
| #define MSGT_STATUSLINE 45 // playback/encoding status line | |||
| #define MSGT_TELETEXT 46 // Teletext decoder | |||
| #define MSGT_MAX 64 | |||
| extern char *mp_msg_charset; | |||
| extern int mp_msg_color; | |||
| extern int mp_msg_module; | |||
| extern int mp_msg_levels[MSGT_MAX]; | |||
| extern int mp_msg_level_all; | |||
| void mp_msg_init(void); | |||
| int mp_msg_test(int mod, int lev); | |||
| #include "config.h" | |||
| void mp_msg_va(int mod, int lev, const char *format, va_list va); | |||
| #ifdef __GNUC__ | |||
| void mp_msg(int mod, int lev, const char *format, ... ) __attribute__ ((format (printf, 3, 4))); | |||
| # ifdef MP_DEBUG | |||
| # define mp_dbg(mod,lev, args... ) mp_msg(mod, lev, ## args ) | |||
| # else | |||
| # define mp_dbg(mod,lev, args... ) /* only useful for developers */ | |||
| # endif | |||
| #else // not GNU C | |||
| void mp_msg(int mod, int lev, const char *format, ... ); | |||
| # ifdef MP_DEBUG | |||
| # define mp_dbg(mod,lev, ... ) mp_msg(mod, lev, __VA_ARGS__) | |||
| # else | |||
| # define mp_dbg(mod,lev, ... ) /* only useful for developers */ | |||
| # endif | |||
| #endif /* __GNUC__ */ | |||
| const char* filename_recode(const char* filename); | |||
| #endif /* MPLAYER_MP_MSG_H */ | |||
| @@ -0,0 +1,38 @@ | |||
| /* | |||
| * This file is part of MPlayer. | |||
| * | |||
| * MPlayer 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. | |||
| * | |||
| * MPlayer 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 MPlayer; if not, write to the Free Software Foundation, Inc., | |||
| * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | |||
| */ | |||
| #ifndef MPLAYER_MPBSWAP_H | |||
| #define MPLAYER_MPBSWAP_H | |||
| #include <sys/types.h> | |||
| #include "config.h" | |||
| #include "libavutil/bswap.h" | |||
| #define bswap_16(v) av_bswap16(v) | |||
| #define bswap_32(v) av_bswap32(v) | |||
| #define le2me_16(v) av_le2ne16(v) | |||
| #define le2me_32(v) av_le2ne32(v) | |||
| #define le2me_64(v) av_le2ne64(v) | |||
| #define be2me_16(v) av_be2ne16(v) | |||
| #define be2me_32(v) av_be2ne32(v) | |||
| #ifndef HAVE_SWAB | |||
| void swab(const void *from, void *to, ssize_t n); | |||
| #endif | |||
| #endif /* MPLAYER_MPBSWAP_H */ | |||
| @@ -0,0 +1,43 @@ | |||
| /* | |||
| * This file is part of MPlayer. | |||
| * | |||
| * MPlayer 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. | |||
| * | |||
| * MPlayer 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 MPlayer; if not, write to the Free Software Foundation, Inc., | |||
| * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | |||
| */ | |||
| #ifndef MPLAYER_MPC_INFO_H | |||
| #define MPLAYER_MPC_INFO_H | |||
| typedef struct mp_codec_info_s | |||
| { | |||
| /* codec long name ("Autodesk FLI/FLC Animation decoder" */ | |||
| const char *name; | |||
| /* short name (same as driver name in codecs.conf) ("dshow") */ | |||
| const char *short_name; | |||
| /* interface author/maintainer */ | |||
| const char *maintainer; | |||
| /* codec author ("Aaron Holtzman <aholtzma@ess.engr.uvic.ca>") */ | |||
| const char *author; | |||
| /* any additional comments */ | |||
| const char *comment; | |||
| } mp_codec_info_t; | |||
| #define CONTROL_OK 1 | |||
| #define CONTROL_TRUE 1 | |||
| #define CONTROL_FALSE 0 | |||
| #define CONTROL_UNKNOWN -1 | |||
| #define CONTROL_ERROR -2 | |||
| #define CONTROL_NA -3 | |||
| #endif /* MPLAYER_MPC_INFO_H */ | |||
| @@ -0,0 +1,822 @@ | |||
| /* | |||
| * This file is part of MPlayer. | |||
| * | |||
| * MPlayer 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. | |||
| * | |||
| * MPlayer 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 MPlayer; if not, write to the Free Software Foundation, Inc., | |||
| * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | |||
| */ | |||
| #include <stdio.h> | |||
| #include <stdlib.h> | |||
| #include <string.h> | |||
| #include "config.h" | |||
| #include "pullup.h" | |||
| #include "cpudetect.h" | |||
| #if ARCH_X86 | |||
| #if HAVE_MMX | |||
| static int diff_y_mmx(unsigned char *a, unsigned char *b, int s) | |||
| { | |||
| int ret; | |||
| __asm__ volatile ( | |||
| "movl $4, %%ecx \n\t" | |||
| "pxor %%mm4, %%mm4 \n\t" | |||
| "pxor %%mm7, %%mm7 \n\t" | |||
| "1: \n\t" | |||
| "movq (%%"REG_S"), %%mm0 \n\t" | |||
| "movq (%%"REG_S"), %%mm2 \n\t" | |||
| "add %%"REG_a", %%"REG_S" \n\t" | |||
| "movq (%%"REG_D"), %%mm1 \n\t" | |||
| "add %%"REG_a", %%"REG_D" \n\t" | |||
| "psubusb %%mm1, %%mm2 \n\t" | |||
| "psubusb %%mm0, %%mm1 \n\t" | |||
| "movq %%mm2, %%mm0 \n\t" | |||
| "movq %%mm1, %%mm3 \n\t" | |||
| "punpcklbw %%mm7, %%mm0 \n\t" | |||
| "punpcklbw %%mm7, %%mm1 \n\t" | |||
| "punpckhbw %%mm7, %%mm2 \n\t" | |||
| "punpckhbw %%mm7, %%mm3 \n\t" | |||
| "paddw %%mm0, %%mm4 \n\t" | |||
| "paddw %%mm1, %%mm4 \n\t" | |||
| "paddw %%mm2, %%mm4 \n\t" | |||
| "paddw %%mm3, %%mm4 \n\t" | |||
| "decl %%ecx \n\t" | |||
| "jnz 1b \n\t" | |||
| "movq %%mm4, %%mm3 \n\t" | |||
| "punpcklwd %%mm7, %%mm4 \n\t" | |||
| "punpckhwd %%mm7, %%mm3 \n\t" | |||
| "paddd %%mm4, %%mm3 \n\t" | |||
| "movd %%mm3, %%eax \n\t" | |||
| "psrlq $32, %%mm3 \n\t" | |||
| "movd %%mm3, %%edx \n\t" | |||
| "addl %%edx, %%eax \n\t" | |||
| "emms \n\t" | |||
| : "=a" (ret) | |||
| : "S" (a), "D" (b), "a" (s) | |||
| : "%ecx", "%edx" | |||
| ); | |||
| return ret; | |||
| } | |||
| static int licomb_y_mmx(unsigned char *a, unsigned char *b, int s) | |||
| { | |||
| int ret; | |||
| __asm__ volatile ( | |||
| "movl $4, %%ecx \n\t" | |||
| "pxor %%mm6, %%mm6 \n\t" | |||
| "pxor %%mm7, %%mm7 \n\t" | |||
| "sub %%"REG_a", %%"REG_D" \n\t" | |||
| "2: \n\t" | |||
| "movq (%%"REG_D"), %%mm0 \n\t" | |||
| "movq (%%"REG_D"), %%mm1 \n\t" | |||
| "punpcklbw %%mm7, %%mm0 \n\t" | |||
| "movq (%%"REG_D",%%"REG_a"), %%mm2 \n\t" | |||
| "punpcklbw %%mm7, %%mm1 \n\t" | |||
| "punpcklbw %%mm7, %%mm2 \n\t" | |||
| "paddw %%mm0, %%mm0 \n\t" | |||
| "paddw %%mm2, %%mm1 \n\t" | |||
| "movq %%mm0, %%mm2 \n\t" | |||
| "psubusw %%mm1, %%mm0 \n\t" | |||
| "psubusw %%mm2, %%mm1 \n\t" | |||
| "paddw %%mm0, %%mm6 \n\t" | |||
| "paddw %%mm1, %%mm6 \n\t" | |||
| "movq (%%"REG_S"), %%mm0 \n\t" | |||
| "movq (%%"REG_D"), %%mm1 \n\t" | |||
| "punpckhbw %%mm7, %%mm0 \n\t" | |||
| "movq (%%"REG_D",%%"REG_a"), %%mm2 \n\t" | |||
| "punpckhbw %%mm7, %%mm1 \n\t" | |||
| "punpckhbw %%mm7, %%mm2 \n\t" | |||
| "paddw %%mm0, %%mm0 \n\t" | |||
| "paddw %%mm2, %%mm1 \n\t" | |||
| "movq %%mm0, %%mm2 \n\t" | |||
| "psubusw %%mm1, %%mm0 \n\t" | |||
| "psubusw %%mm2, %%mm1 \n\t" | |||
| "paddw %%mm0, %%mm6 \n\t" | |||
| "paddw %%mm1, %%mm6 \n\t" | |||
| "movq (%%"REG_D",%%"REG_a"), %%mm0 \n\t" | |||
| "movq (%%"REG_S"), %%mm1 \n\t" | |||
| "punpcklbw %%mm7, %%mm0 \n\t" | |||
| "movq (%%"REG_S",%%"REG_a"), %%mm2 \n\t" | |||
| "punpcklbw %%mm7, %%mm1 \n\t" | |||
| "punpcklbw %%mm7, %%mm2 \n\t" | |||
| "paddw %%mm0, %%mm0 \n\t" | |||
| "paddw %%mm2, %%mm1 \n\t" | |||
| "movq %%mm0, %%mm2 \n\t" | |||
| "psubusw %%mm1, %%mm0 \n\t" | |||
| "psubusw %%mm2, %%mm1 \n\t" | |||
| "paddw %%mm0, %%mm6 \n\t" | |||
| "paddw %%mm1, %%mm6 \n\t" | |||
| "movq (%%"REG_D",%%"REG_a"), %%mm0 \n\t" | |||
| "movq (%%"REG_S"), %%mm1 \n\t" | |||
| "punpckhbw %%mm7, %%mm0 \n\t" | |||
| "movq (%%"REG_S",%%"REG_a"), %%mm2 \n\t" | |||
| "punpckhbw %%mm7, %%mm1 \n\t" | |||
| "punpckhbw %%mm7, %%mm2 \n\t" | |||
| "paddw %%mm0, %%mm0 \n\t" | |||
| "paddw %%mm2, %%mm1 \n\t" | |||
| "movq %%mm0, %%mm2 \n\t" | |||
| "psubusw %%mm1, %%mm0 \n\t" | |||
| "psubusw %%mm2, %%mm1 \n\t" | |||
| "paddw %%mm0, %%mm6 \n\t" | |||
| "paddw %%mm1, %%mm6 \n\t" | |||
| "add %%"REG_a", %%"REG_S" \n\t" | |||
| "add %%"REG_a", %%"REG_D" \n\t" | |||
| "decl %%ecx \n\t" | |||
| "jnz 2b \n\t" | |||
| "movq %%mm6, %%mm5 \n\t" | |||
| "punpcklwd %%mm7, %%mm6 \n\t" | |||
| "punpckhwd %%mm7, %%mm5 \n\t" | |||
| "paddd %%mm6, %%mm5 \n\t" | |||
| "movd %%mm5, %%eax \n\t" | |||
| "psrlq $32, %%mm5 \n\t" | |||
| "movd %%mm5, %%edx \n\t" | |||
| "addl %%edx, %%eax \n\t" | |||
| "emms \n\t" | |||
| : "=a" (ret) | |||
| : "S" (a), "D" (b), "a" (s) | |||
| : "%ecx", "%edx" | |||
| ); | |||
| return ret; | |||
| } | |||
| static int var_y_mmx(unsigned char *a, unsigned char *b, int s) | |||
| { | |||
| int ret; | |||
| __asm__ volatile ( | |||
| "movl $3, %%ecx \n\t" | |||
| "pxor %%mm4, %%mm4 \n\t" | |||
| "pxor %%mm7, %%mm7 \n\t" | |||
| "1: \n\t" | |||
| "movq (%%"REG_S"), %%mm0 \n\t" | |||
| "movq (%%"REG_S"), %%mm2 \n\t" | |||
| "movq (%%"REG_S",%%"REG_a"), %%mm1 \n\t" | |||
| "add %%"REG_a", %%"REG_S" \n\t" | |||
| "psubusb %%mm1, %%mm2 \n\t" | |||
| "psubusb %%mm0, %%mm1 \n\t" | |||
| "movq %%mm2, %%mm0 \n\t" | |||
| "movq %%mm1, %%mm3 \n\t" | |||
| "punpcklbw %%mm7, %%mm0 \n\t" | |||
| "punpcklbw %%mm7, %%mm1 \n\t" | |||
| "punpckhbw %%mm7, %%mm2 \n\t" | |||
| "punpckhbw %%mm7, %%mm3 \n\t" | |||
| "paddw %%mm0, %%mm4 \n\t" | |||
| "paddw %%mm1, %%mm4 \n\t" | |||
| "paddw %%mm2, %%mm4 \n\t" | |||
| "paddw %%mm3, %%mm4 \n\t" | |||
| "decl %%ecx \n\t" | |||
| "jnz 1b \n\t" | |||
| "movq %%mm4, %%mm3 \n\t" | |||
| "punpcklwd %%mm7, %%mm4 \n\t" | |||
| "punpckhwd %%mm7, %%mm3 \n\t" | |||
| "paddd %%mm4, %%mm3 \n\t" | |||
| "movd %%mm3, %%eax \n\t" | |||
| "psrlq $32, %%mm3 \n\t" | |||
| "movd %%mm3, %%edx \n\t" | |||
| "addl %%edx, %%eax \n\t" | |||
| "emms \n\t" | |||
| : "=a" (ret) | |||
| : "S" (a), "a" (s) | |||
| : "%ecx", "%edx" | |||
| ); | |||
| return 4*ret; | |||
| } | |||
| #endif | |||
| #endif | |||
| #define ABS(a) (((a)^((a)>>31))-((a)>>31)) | |||
| static int diff_y(unsigned char *a, unsigned char *b, int s) | |||
| { | |||
| int i, j, diff=0; | |||
| for (i=4; i; i--) { | |||
| for (j=0; j<8; j++) diff += ABS(a[j]-b[j]); | |||
| a+=s; b+=s; | |||
| } | |||
| return diff; | |||
| } | |||
| static int licomb_y(unsigned char *a, unsigned char *b, int s) | |||
| { | |||
| int i, j, diff=0; | |||
| for (i=4; i; i--) { | |||
| for (j=0; j<8; j++) | |||
| diff += ABS((a[j]<<1) - b[j-s] - b[j]) | |||
| + ABS((b[j]<<1) - a[j] - a[j+s]); | |||
| a+=s; b+=s; | |||
| } | |||
| return diff; | |||
| } | |||
| #if 0 | |||
| static int qpcomb_y(unsigned char *a, unsigned char *b, int s) | |||
| { | |||
| int i, j, diff=0; | |||
| for (i=4; i; i--) { | |||
| for (j=0; j<8; j++) | |||
| diff += ABS(a[j] - 3*b[j-s] + 3*a[j+s] - b[j]); | |||
| a+=s; b+=s; | |||
| } | |||
| return diff; | |||
| } | |||
| static int licomb_y_test(unsigned char *a, unsigned char *b, int s) | |||
| { | |||
| int c = licomb_y(a,b,s); | |||
| int m = licomb_y_mmx(a,b,s); | |||
| if (c != m) printf("%d != %d\n", c, m); | |||
| return m; | |||
| } | |||
| #endif | |||
| static int var_y(unsigned char *a, unsigned char *b, int s) | |||
| { | |||
| int i, j, var=0; | |||
| for (i=3; i; i--) { | |||
| for (j=0; j<8; j++) { | |||
| var += ABS(a[j]-a[j+s]); | |||
| } | |||
| a+=s; b+=s; | |||
| } | |||
| return 4*var; /* match comb scaling */ | |||
| } | |||
| static void alloc_buffer(struct pullup_context *c, struct pullup_buffer *b) | |||
| { | |||
| int i; | |||
| if (b->planes) return; | |||
| b->planes = calloc(c->nplanes, sizeof(unsigned char *)); | |||
| for (i = 0; i < c->nplanes; i++) { | |||
| b->planes[i] = malloc(c->h[i]*c->stride[i]); | |||
| /* Deal with idiotic 128=0 for chroma: */ | |||
| memset(b->planes[i], c->background[i], c->h[i]*c->stride[i]); | |||
| } | |||
| } | |||
| struct pullup_buffer *pullup_lock_buffer(struct pullup_buffer *b, int parity) | |||
| { | |||
| if (!b) return 0; | |||
| if ((parity+1) & 1) b->lock[0]++; | |||
| if ((parity+1) & 2) b->lock[1]++; | |||
| return b; | |||
| } | |||
| void pullup_release_buffer(struct pullup_buffer *b, int parity) | |||
| { | |||
| if (!b) return; | |||
| if ((parity+1) & 1) b->lock[0]--; | |||
| if ((parity+1) & 2) b->lock[1]--; | |||
| } | |||
| struct pullup_buffer *pullup_get_buffer(struct pullup_context *c, int parity) | |||
| { | |||
| int i; | |||
| /* Try first to get the sister buffer for the previous field */ | |||
| if (parity < 2 && c->last && parity != c->last->parity | |||
| && !c->last->buffer->lock[parity]) { | |||
| alloc_buffer(c, c->last->buffer); | |||
| return pullup_lock_buffer(c->last->buffer, parity); | |||
| } | |||
| /* Prefer a buffer with both fields open */ | |||
| for (i = 0; i < c->nbuffers; i++) { | |||
| if (c->buffers[i].lock[0]) continue; | |||
| if (c->buffers[i].lock[1]) continue; | |||
| alloc_buffer(c, &c->buffers[i]); | |||
| return pullup_lock_buffer(&c->buffers[i], parity); | |||
| } | |||
| if (parity == 2) return 0; | |||
| /* Search for any half-free buffer */ | |||
| for (i = 0; i < c->nbuffers; i++) { | |||
| if (((parity+1) & 1) && c->buffers[i].lock[0]) continue; | |||
| if (((parity+1) & 2) && c->buffers[i].lock[1]) continue; | |||
| alloc_buffer(c, &c->buffers[i]); | |||
| return pullup_lock_buffer(&c->buffers[i], parity); | |||
| } | |||
| return 0; | |||
| } | |||
| static void compute_metric(struct pullup_context *c, | |||
| struct pullup_field *fa, int pa, | |||
| struct pullup_field *fb, int pb, | |||
| int (*func)(unsigned char *, unsigned char *, int), int *dest) | |||
| { | |||
| unsigned char *a, *b; | |||
| int x, y; | |||
| int mp = c->metric_plane; | |||
| int xstep = c->bpp[mp]; | |||
| int ystep = c->stride[mp]<<3; | |||
| int s = c->stride[mp]<<1; /* field stride */ | |||
| int w = c->metric_w*xstep; | |||
| if (!fa->buffer || !fb->buffer) return; | |||
| /* Shortcut for duplicate fields (e.g. from RFF flag) */ | |||
| if (fa->buffer == fb->buffer && pa == pb) { | |||
| memset(dest, 0, c->metric_len * sizeof(int)); | |||
| return; | |||
| } | |||
| a = fa->buffer->planes[mp] + pa * c->stride[mp] + c->metric_offset; | |||
| b = fb->buffer->planes[mp] + pb * c->stride[mp] + c->metric_offset; | |||
| for (y = c->metric_h; y; y--) { | |||
| for (x = 0; x < w; x += xstep) { | |||
| *dest++ = func(a + x, b + x, s); | |||
| } | |||
| a += ystep; b += ystep; | |||
| } | |||
| } | |||
| static void alloc_metrics(struct pullup_context *c, struct pullup_field *f) | |||
| { | |||
| f->diffs = calloc(c->metric_len, sizeof(int)); | |||
| f->comb = calloc(c->metric_len, sizeof(int)); | |||
| f->var = calloc(c->metric_len, sizeof(int)); | |||
| /* add more metrics here as needed */ | |||
| } | |||
| static struct pullup_field *make_field_queue(struct pullup_context *c, int len) | |||
| { | |||
| struct pullup_field *head, *f; | |||
| f = head = calloc(1, sizeof(struct pullup_field)); | |||
| alloc_metrics(c, f); | |||
| for (; len > 0; len--) { | |||
| f->next = calloc(1, sizeof(struct pullup_field)); | |||
| f->next->prev = f; | |||
| f = f->next; | |||
| alloc_metrics(c, f); | |||
| } | |||
| f->next = head; | |||
| head->prev = f; | |||
| return head; | |||
| } | |||
| static void check_field_queue(struct pullup_context *c) | |||
| { | |||
| if (c->head->next == c->first) { | |||
| struct pullup_field *f = calloc(1, sizeof(struct pullup_field)); | |||
| alloc_metrics(c, f); | |||
| f->prev = c->head; | |||
| f->next = c->first; | |||
| c->head->next = f; | |||
| c->first->prev = f; | |||
| } | |||
| } | |||
| void pullup_submit_field(struct pullup_context *c, struct pullup_buffer *b, int parity) | |||
| { | |||
| struct pullup_field *f; | |||
| /* Grow the circular list if needed */ | |||
| check_field_queue(c); | |||
| /* Cannot have two fields of same parity in a row; drop the new one */ | |||
| if (c->last && c->last->parity == parity) return; | |||
| f = c->head; | |||
| f->parity = parity; | |||
| f->buffer = pullup_lock_buffer(b, parity); | |||
| f->flags = 0; | |||
| f->breaks = 0; | |||
| f->affinity = 0; | |||
| compute_metric(c, f, parity, f->prev->prev, parity, c->diff, f->diffs); | |||
| compute_metric(c, parity?f->prev:f, 0, parity?f:f->prev, 1, c->comb, f->comb); | |||
| compute_metric(c, f, parity, f, -1, c->var, f->var); | |||
| /* Advance the circular list */ | |||
| if (!c->first) c->first = c->head; | |||
| c->last = c->head; | |||
| c->head = c->head->next; | |||
| } | |||
| void pullup_flush_fields(struct pullup_context *c) | |||
| { | |||
| struct pullup_field *f; | |||
| for (f = c->first; f && f != c->head; f = f->next) { | |||
| pullup_release_buffer(f->buffer, f->parity); | |||
| f->buffer = 0; | |||
| } | |||
| c->first = c->last = 0; | |||
| } | |||
| #define F_HAVE_BREAKS 1 | |||
| #define F_HAVE_AFFINITY 2 | |||
| #define BREAK_LEFT 1 | |||
| #define BREAK_RIGHT 2 | |||
| static int queue_length(struct pullup_field *begin, struct pullup_field *end) | |||
| { | |||
| int count = 1; | |||
| struct pullup_field *f; | |||
| if (!begin || !end) return 0; | |||
| for (f = begin; f != end; f = f->next) count++; | |||
| return count; | |||
| } | |||
| static int find_first_break(struct pullup_field *f, int max) | |||
| { | |||
| int i; | |||
| for (i = 0; i < max; i++) { | |||
| if (f->breaks & BREAK_RIGHT || f->next->breaks & BREAK_LEFT) | |||
| return i+1; | |||
| f = f->next; | |||
| } | |||
| return 0; | |||
| } | |||
| static void compute_breaks(struct pullup_context *c, struct pullup_field *f0) | |||
| { | |||
| int i; | |||
| struct pullup_field *f1 = f0->next; | |||
| struct pullup_field *f2 = f1->next; | |||
| struct pullup_field *f3 = f2->next; | |||
| int l, max_l=0, max_r=0; | |||
| //struct pullup_field *ff; | |||
| //for (i=0, ff=c->first; ff != f0; i++, ff=ff->next); | |||
| if (f0->flags & F_HAVE_BREAKS) return; | |||
| //printf("\n%d: ", i); | |||
| f0->flags |= F_HAVE_BREAKS; | |||
| /* Special case when fields are 100% identical */ | |||
| if (f0->buffer == f2->buffer && f1->buffer != f3->buffer) { | |||
| f2->breaks |= BREAK_RIGHT; | |||
| return; | |||
| } | |||
| if (f0->buffer != f2->buffer && f1->buffer == f3->buffer) { | |||
| f1->breaks |= BREAK_LEFT; | |||
| return; | |||
| } | |||
| for (i = 0; i < c->metric_len; i++) { | |||
| l = f2->diffs[i] - f3->diffs[i]; | |||
| if (l > max_l) max_l = l; | |||
| if (-l > max_r) max_r = -l; | |||
| } | |||
| /* Don't get tripped up when differences are mostly quant error */ | |||
| //printf("%d %d\n", max_l, max_r); | |||
| if (max_l + max_r < 128) return; | |||
| if (max_l > 4*max_r) f1->breaks |= BREAK_LEFT; | |||
| if (max_r > 4*max_l) f2->breaks |= BREAK_RIGHT; | |||
| } | |||
| static void compute_affinity(struct pullup_context *c, struct pullup_field *f) | |||
| { | |||
| int i; | |||
| int max_l=0, max_r=0, l; | |||
| if (f->flags & F_HAVE_AFFINITY) return; | |||
| f->flags |= F_HAVE_AFFINITY; | |||
| if (f->buffer == f->next->next->buffer) { | |||
| f->affinity = 1; | |||
| f->next->affinity = 0; | |||
| f->next->next->affinity = -1; | |||
| f->next->flags |= F_HAVE_AFFINITY; | |||
| f->next->next->flags |= F_HAVE_AFFINITY; | |||
| return; | |||
| } | |||
| if (1) { | |||
| for (i = 0; i < c->metric_len; i++) { | |||
| int lv = f->prev->var[i]; | |||
| int rv = f->next->var[i]; | |||
| int v = f->var[i]; | |||
| int lc = f->comb[i] - (v+lv) + ABS(v-lv); | |||
| int rc = f->next->comb[i] - (v+rv) + ABS(v-rv); | |||
| lc = lc>0 ? lc : 0; | |||
| rc = rc>0 ? rc : 0; | |||
| l = lc - rc; | |||
| if (l > max_l) max_l = l; | |||
| if (-l > max_r) max_r = -l; | |||
| } | |||
| if (max_l + max_r < 64) return; | |||
| if (max_r > 6*max_l) f->affinity = -1; | |||
| else if (max_l > 6*max_r) f->affinity = 1; | |||
| } else { | |||
| for (i = 0; i < c->metric_len; i++) { | |||
| l = f->comb[i] - f->next->comb[i]; | |||
| if (l > max_l) max_l = l; | |||
| if (-l > max_r) max_r = -l; | |||
| } | |||
| if (max_l + max_r < 64) return; | |||
| if (max_r > 2*max_l) f->affinity = -1; | |||
| else if (max_l > 2*max_r) f->affinity = 1; | |||
| } | |||
| } | |||
| static void foo(struct pullup_context *c) | |||
| { | |||
| struct pullup_field *f = c->first; | |||
| int i, n = queue_length(f, c->last); | |||
| for (i = 0; i < n-1; i++) { | |||
| if (i < n-3) compute_breaks(c, f); | |||
| compute_affinity(c, f); | |||
| f = f->next; | |||
| } | |||
| } | |||
| static int decide_frame_length(struct pullup_context *c) | |||
| { | |||
| struct pullup_field *f0 = c->first; | |||
| struct pullup_field *f1 = f0->next; | |||
| struct pullup_field *f2 = f1->next; | |||
| int l; | |||
| if (queue_length(c->first, c->last) < 4) return 0; | |||
| foo(c); | |||
| if (f0->affinity == -1) return 1; | |||
| l = find_first_break(f0, 3); | |||
| if (l == 1 && c->strict_breaks < 0) l = 0; | |||
| switch (l) { | |||
| case 1: | |||
| if (c->strict_breaks < 1 && f0->affinity == 1 && f1->affinity == -1) | |||
| return 2; | |||
| else return 1; | |||
| case 2: | |||
| /* FIXME: strictly speaking, f0->prev is no longer valid... :) */ | |||
| if (c->strict_pairs | |||
| && (f0->prev->breaks & BREAK_RIGHT) && (f2->breaks & BREAK_LEFT) | |||
| && (f0->affinity != 1 || f1->affinity != -1) ) | |||
| return 1; | |||
| if (f1->affinity == 1) return 1; | |||
| else return 2; | |||
| case 3: | |||
| if (f2->affinity == 1) return 2; | |||
| else return 3; | |||
| default: | |||
| /* 9 possibilities covered before switch */ | |||
| if (f1->affinity == 1) return 1; /* covers 6 */ | |||
| else if (f1->affinity == -1) return 2; /* covers 6 */ | |||
| else if (f2->affinity == -1) { /* covers 2 */ | |||
| if (f0->affinity == 1) return 3; | |||
| else return 1; | |||
| } | |||
| else return 2; /* the remaining 6 */ | |||
| } | |||
| } | |||
| static void print_aff_and_breaks(struct pullup_context *c, struct pullup_field *f) | |||
| { | |||
| int i; | |||
| struct pullup_field *f0 = f; | |||
| const char aff_l[] = "+..", aff_r[] = "..+"; | |||
| printf("\naffinity: "); | |||
| for (i = 0; i < 4; i++) { | |||
| printf("%c%d%c", aff_l[1+f->affinity], i, aff_r[1+f->affinity]); | |||
| f = f->next; | |||
| } | |||
| f = f0; | |||
| printf("\nbreaks: "); | |||
| for (i=0; i<4; i++) { | |||
| printf("%c%d%c", f->breaks & BREAK_LEFT ? '|' : '.', i, f->breaks & BREAK_RIGHT ? '|' : '.'); | |||
| f = f->next; | |||
| } | |||
| printf("\n"); | |||
| } | |||
| struct pullup_frame *pullup_get_frame(struct pullup_context *c) | |||
| { | |||
| int i; | |||
| struct pullup_frame *fr = c->frame; | |||
| int n = decide_frame_length(c); | |||
| int aff = c->first->next->affinity; | |||
| if (!n) return 0; | |||
| if (fr->lock) return 0; | |||
| if (c->verbose) { | |||
| print_aff_and_breaks(c, c->first); | |||
| printf("duration: %d \n", n); | |||
| } | |||
| fr->lock++; | |||
| fr->length = n; | |||
| fr->parity = c->first->parity; | |||
| fr->buffer = 0; | |||
| for (i = 0; i < n; i++) { | |||
| /* We cheat and steal the buffer without release+relock */ | |||
| fr->ifields[i] = c->first->buffer; | |||
| c->first->buffer = 0; | |||
| c->first = c->first->next; | |||
| } | |||
| if (n == 1) { | |||
| fr->ofields[fr->parity] = fr->ifields[0]; | |||
| fr->ofields[fr->parity^1] = 0; | |||
| } else if (n == 2) { | |||
| fr->ofields[fr->parity] = fr->ifields[0]; | |||
| fr->ofields[fr->parity^1] = fr->ifields[1]; | |||
| } else if (n == 3) { | |||
| if (aff == 0) | |||
| aff = (fr->ifields[0] == fr->ifields[1]) ? -1 : 1; | |||
| /* else if (c->verbose) printf("forced aff: %d \n", aff); */ | |||
| fr->ofields[fr->parity] = fr->ifields[1+aff]; | |||
| fr->ofields[fr->parity^1] = fr->ifields[1]; | |||
| } | |||
| pullup_lock_buffer(fr->ofields[0], 0); | |||
| pullup_lock_buffer(fr->ofields[1], 1); | |||
| if (fr->ofields[0] == fr->ofields[1]) { | |||
| fr->buffer = fr->ofields[0]; | |||
| pullup_lock_buffer(fr->buffer, 2); | |||
| return fr; | |||
| } | |||
| return fr; | |||
| } | |||
| static void copy_field(struct pullup_context *c, struct pullup_buffer *dest, | |||
| struct pullup_buffer *src, int parity) | |||
| { | |||
| int i, j; | |||
| unsigned char *d, *s; | |||
| for (i = 0; i < c->nplanes; i++) { | |||
| s = src->planes[i] + parity*c->stride[i]; | |||
| d = dest->planes[i] + parity*c->stride[i]; | |||
| for (j = c->h[i]>>1; j; j--) { | |||
| memcpy(d, s, c->stride[i]); | |||
| s += c->stride[i]<<1; | |||
| d += c->stride[i]<<1; | |||
| } | |||
| } | |||
| } | |||
| void pullup_pack_frame(struct pullup_context *c, struct pullup_frame *fr) | |||
| { | |||
| int i; | |||
| if (fr->buffer) return; | |||
| if (fr->length < 2) return; /* FIXME: deal with this */ | |||
| for (i = 0; i < 2; i++) | |||
| { | |||
| if (fr->ofields[i]->lock[i^1]) continue; | |||
| fr->buffer = fr->ofields[i]; | |||
| pullup_lock_buffer(fr->buffer, 2); | |||
| copy_field(c, fr->buffer, fr->ofields[i^1], i^1); | |||
| return; | |||
| } | |||
| fr->buffer = pullup_get_buffer(c, 2); | |||
| copy_field(c, fr->buffer, fr->ofields[0], 0); | |||
| copy_field(c, fr->buffer, fr->ofields[1], 1); | |||
| } | |||
| void pullup_release_frame(struct pullup_frame *fr) | |||
| { | |||
| int i; | |||
| for (i = 0; i < fr->length; i++) | |||
| pullup_release_buffer(fr->ifields[i], fr->parity ^ (i&1)); | |||
| pullup_release_buffer(fr->ofields[0], 0); | |||
| pullup_release_buffer(fr->ofields[1], 1); | |||
| if (fr->buffer) pullup_release_buffer(fr->buffer, 2); | |||
| fr->lock--; | |||
| } | |||
| struct pullup_context *pullup_alloc_context(void) | |||
| { | |||
| struct pullup_context *c; | |||
| c = calloc(1, sizeof(struct pullup_context)); | |||
| return c; | |||
| } | |||
| void pullup_preinit_context(struct pullup_context *c) | |||
| { | |||
| c->bpp = calloc(c->nplanes, sizeof(int)); | |||
| c->w = calloc(c->nplanes, sizeof(int)); | |||
| c->h = calloc(c->nplanes, sizeof(int)); | |||
| c->stride = calloc(c->nplanes, sizeof(int)); | |||
| c->background = calloc(c->nplanes, sizeof(int)); | |||
| } | |||
| void pullup_init_context(struct pullup_context *c) | |||
| { | |||
| int mp = c->metric_plane; | |||
| if (c->nbuffers < 10) c->nbuffers = 10; | |||
| c->buffers = calloc(c->nbuffers, sizeof (struct pullup_buffer)); | |||
| c->metric_w = (c->w[mp] - ((c->junk_left + c->junk_right) << 3)) >> 3; | |||
| c->metric_h = (c->h[mp] - ((c->junk_top + c->junk_bottom) << 1)) >> 3; | |||
| c->metric_offset = c->junk_left*c->bpp[mp] + (c->junk_top<<1)*c->stride[mp]; | |||
| c->metric_len = c->metric_w * c->metric_h; | |||
| c->head = make_field_queue(c, 8); | |||
| c->frame = calloc(1, sizeof (struct pullup_frame)); | |||
| c->frame->ifields = calloc(3, sizeof (struct pullup_buffer *)); | |||
| switch(c->format) { | |||
| case PULLUP_FMT_Y: | |||
| c->diff = diff_y; | |||
| c->comb = licomb_y; | |||
| c->var = var_y; | |||
| #if ARCH_X86 | |||
| #if HAVE_MMX | |||
| if (c->cpu & PULLUP_CPU_MMX) { | |||
| c->diff = diff_y_mmx; | |||
| c->comb = licomb_y_mmx; | |||
| c->var = var_y_mmx; | |||
| } | |||
| #endif | |||
| #endif | |||
| /* c->comb = qpcomb_y; */ | |||
| break; | |||
| #if 0 | |||
| case PULLUP_FMT_YUY2: | |||
| c->diff = diff_yuy2; | |||
| break; | |||
| case PULLUP_FMT_RGB32: | |||
| c->diff = diff_rgb32; | |||
| break; | |||
| #endif | |||
| } | |||
| } | |||
| void pullup_free_context(struct pullup_context *c) | |||
| { | |||
| struct pullup_field *f; | |||
| free(c->buffers); | |||
| f = c->head; | |||
| do { | |||
| if (!f) break; | |||
| free(f->diffs); | |||
| free(f->comb); | |||
| f = f->next; | |||
| free(f->prev); | |||
| } while (f != c->head); | |||
| free(c->frame); | |||
| free(c); | |||
| } | |||
| @@ -0,0 +1,102 @@ | |||
| /* | |||
| * This file is part of MPlayer. | |||
| * | |||
| * MPlayer 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. | |||
| * | |||
| * MPlayer 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 MPlayer; if not, write to the Free Software Foundation, Inc., | |||
| * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | |||
| */ | |||
| #ifndef MPLAYER_PULLUP_H | |||
| #define MPLAYER_PULLUP_H | |||
| #define PULLUP_CPU_MMX 1 | |||
| #define PULLUP_CPU_MMX2 2 | |||
| #define PULLUP_CPU_3DNOW 4 | |||
| #define PULLUP_CPU_3DNOWEXT 8 | |||
| #define PULLUP_CPU_SSE 16 | |||
| #define PULLUP_CPU_SSE2 32 | |||
| #define PULLUP_FMT_Y 1 | |||
| #define PULLUP_FMT_YUY2 2 | |||
| #define PULLUP_FMT_UYVY 3 | |||
| #define PULLUP_FMT_RGB32 4 | |||
| struct pullup_buffer | |||
| { | |||
| int lock[2]; | |||
| unsigned char **planes; | |||
| }; | |||
| struct pullup_field | |||
| { | |||
| int parity; | |||
| struct pullup_buffer *buffer; | |||
| unsigned int flags; | |||
| int breaks; | |||
| int affinity; | |||
| int *diffs; | |||
| int *comb; | |||
| int *var; | |||
| struct pullup_field *prev, *next; | |||
| }; | |||
| struct pullup_frame | |||
| { | |||
| int lock; | |||
| int length; | |||
| int parity; | |||
| struct pullup_buffer **ifields, *ofields[2]; | |||
| struct pullup_buffer *buffer; | |||
| }; | |||
| struct pullup_context | |||
| { | |||
| /* Public interface */ | |||
| int format; | |||
| int nplanes; | |||
| int *bpp, *w, *h, *stride, *background; | |||
| unsigned int cpu; | |||
| int junk_left, junk_right, junk_top, junk_bottom; | |||
| int verbose; | |||
| int metric_plane; | |||
| int strict_breaks; | |||
| int strict_pairs; | |||
| /* Internal data */ | |||
| struct pullup_field *first, *last, *head; | |||
| struct pullup_buffer *buffers; | |||
| int nbuffers; | |||
| int (*diff)(unsigned char *, unsigned char *, int); | |||
| int (*comb)(unsigned char *, unsigned char *, int); | |||
| int (*var)(unsigned char *, unsigned char *, int); | |||
| int metric_w, metric_h, metric_len, metric_offset; | |||
| struct pullup_frame *frame; | |||
| }; | |||
| struct pullup_buffer *pullup_lock_buffer(struct pullup_buffer *b, int parity); | |||
| void pullup_release_buffer(struct pullup_buffer *b, int parity); | |||
| struct pullup_buffer *pullup_get_buffer(struct pullup_context *c, int parity); | |||
| void pullup_submit_field(struct pullup_context *c, struct pullup_buffer *b, int parity); | |||
| void pullup_flush_fields(struct pullup_context *c); | |||
| struct pullup_frame *pullup_get_frame(struct pullup_context *c); | |||
| void pullup_pack_frame(struct pullup_context *c, struct pullup_frame *fr); | |||
| void pullup_release_frame(struct pullup_frame *fr); | |||
| struct pullup_context *pullup_alloc_context(void); | |||
| void pullup_preinit_context(struct pullup_context *c); | |||
| void pullup_init_context(struct pullup_context *c); | |||
| void pullup_free_context(struct pullup_context *c); | |||
| #endif /* MPLAYER_PULLUP_H */ | |||
| @@ -0,0 +1,24 @@ | |||
| /* | |||
| * This file is part of MPlayer. | |||
| * | |||
| * MPlayer 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. | |||
| * | |||
| * MPlayer 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 MPlayer; if not, write to the Free Software Foundation, Inc., | |||
| * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | |||
| */ | |||
| #ifndef MPLAYER_VD_FFMPEG_H | |||
| #define MPLAYER_VD_FFMPEG_H | |||
| void init_avcodec(void); | |||
| #endif /* MPLAYER_VD_FFMPEG_H */ | |||
| @@ -0,0 +1,169 @@ | |||
| /* | |||
| * This file is part of MPlayer. | |||
| * | |||
| * MPlayer 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. | |||
| * | |||
| * MPlayer 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 MPlayer; if not, write to the Free Software Foundation, Inc., | |||
| * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | |||
| */ | |||
| #ifndef MPLAYER_VF_H | |||
| #define MPLAYER_VF_H | |||
| #include "m_option.h" | |||
| #include "mp_image.h" | |||
| extern m_obj_settings_t* vf_settings; | |||
| extern const m_obj_list_t vf_obj_list; | |||
| struct vf_instance; | |||
| struct vf_priv_s; | |||
| typedef struct vf_info_s { | |||
| const char *info; | |||
| const char *name; | |||
| const char *author; | |||
| const char *comment; | |||
| int (*vf_open)(struct vf_instance *vf,char* args); | |||
| // Ptr to a struct dscribing the options | |||
| const void* opts; | |||
| } vf_info_t; | |||
| #define NUM_NUMBERED_MPI 50 | |||
| typedef struct vf_image_context_s { | |||
| mp_image_t* static_images[2]; | |||
| mp_image_t* temp_images[1]; | |||
| mp_image_t* export_images[1]; | |||
| mp_image_t* numbered_images[NUM_NUMBERED_MPI]; | |||
| int static_idx; | |||
| } vf_image_context_t; | |||
| typedef struct vf_format_context_t { | |||
| int have_configured; | |||
| int orig_width, orig_height, orig_fmt; | |||
| } vf_format_context_t; | |||
| typedef struct vf_instance { | |||
| const vf_info_t* info; | |||
| // funcs: | |||
| int (*config)(struct vf_instance *vf, | |||
| int width, int height, int d_width, int d_height, | |||
| unsigned int flags, unsigned int outfmt); | |||
| int (*control)(struct vf_instance *vf, | |||
| int request, void* data); | |||
| int (*query_format)(struct vf_instance *vf, | |||
| unsigned int fmt); | |||
| void (*get_image)(struct vf_instance *vf, | |||
| mp_image_t *mpi); | |||
| int (*put_image)(struct vf_instance *vf, | |||
| mp_image_t *mpi, double pts); | |||
| void (*start_slice)(struct vf_instance *vf, | |||
| mp_image_t *mpi); | |||
| void (*draw_slice)(struct vf_instance *vf, | |||
| unsigned char** src, int* stride, int w,int h, int x, int y); | |||
| void (*uninit)(struct vf_instance *vf); | |||
| int (*continue_buffered_image)(struct vf_instance *vf); | |||
| // caps: | |||
| unsigned int default_caps; // used by default query_format() | |||
| unsigned int default_reqs; // used by default config() | |||
| // data: | |||
| int w, h; | |||
| vf_image_context_t imgctx; | |||
| vf_format_context_t fmt; | |||
| struct vf_instance *next; | |||
| mp_image_t *dmpi; | |||
| struct vf_priv_s* priv; | |||
| } vf_instance_t; | |||
| // control codes: | |||
| #include "mpc_info.h" | |||
| typedef struct vf_seteq_s | |||
| { | |||
| const char *item; | |||
| int value; | |||
| } vf_equalizer_t; | |||
| #define VFCTRL_QUERY_MAX_PP_LEVEL 4 /* test for postprocessing support (max level) */ | |||
| #define VFCTRL_SET_PP_LEVEL 5 /* set postprocessing level */ | |||
| #define VFCTRL_SET_EQUALIZER 6 /* set color options (brightness,contrast etc) */ | |||
| #define VFCTRL_GET_EQUALIZER 8 /* gset color options (brightness,contrast etc) */ | |||
| #define VFCTRL_DRAW_OSD 7 | |||
| #define VFCTRL_CHANGE_RECTANGLE 9 /* Change the rectangle boundaries */ | |||
| #define VFCTRL_FLIP_PAGE 10 /* Tell the vo to flip pages */ | |||
| #define VFCTRL_DUPLICATE_FRAME 11 /* For encoding - encode zero-change frame */ | |||
| #define VFCTRL_SKIP_NEXT_FRAME 12 /* For encoding - drop the next frame that passes thru */ | |||
| #define VFCTRL_FLUSH_FRAMES 13 /* For encoding - flush delayed frames */ | |||
| #define VFCTRL_SCREENSHOT 14 /* Make a screenshot */ | |||
| #define VFCTRL_INIT_EOSD 15 /* Select EOSD renderer */ | |||
| #define VFCTRL_DRAW_EOSD 16 /* Render EOSD */ | |||
| #define VFCTRL_GET_PTS 17 /* Return last pts value that reached vf_vo*/ | |||
| #define VFCTRL_SET_DEINTERLACE 18 /* Set deinterlacing status */ | |||
| #define VFCTRL_GET_DEINTERLACE 19 /* Get deinterlacing status */ | |||
| #include "vfcap.h" | |||
| //FIXME this should be in a common header, but i dunno which | |||
| #define MP_NOPTS_VALUE (-1LL<<63) //both int64_t and double should be able to represent this exactly | |||
| // functions: | |||
| void vf_mpi_clear(mp_image_t* mpi,int x0,int y0,int w,int h); | |||
| mp_image_t* vf_get_image(vf_instance_t* vf, unsigned int outfmt, int mp_imgtype, int mp_imgflag, int w, int h); | |||
| vf_instance_t* vf_open_plugin(const vf_info_t* const* filter_list, vf_instance_t* next, const char *name, char **args); | |||
| vf_instance_t* vf_open_filter(vf_instance_t* next, const char *name, char **args); | |||
| vf_instance_t* vf_add_before_vo(vf_instance_t **vf, char *name, char **args); | |||
| vf_instance_t* vf_open_encoder(vf_instance_t* next, const char *name, char *args); | |||
| unsigned int vf_match_csp(vf_instance_t** vfp,const unsigned int* list,unsigned int preferred); | |||
| void vf_clone_mpi_attributes(mp_image_t* dst, mp_image_t* src); | |||
| void vf_queue_frame(vf_instance_t *vf, int (*)(vf_instance_t *)); | |||
| int vf_output_queued_frame(vf_instance_t *vf); | |||
| // default wrappers: | |||
| int vf_next_config(struct vf_instance *vf, | |||
| int width, int height, int d_width, int d_height, | |||
| unsigned int flags, unsigned int outfmt); | |||
| int vf_next_control(struct vf_instance *vf, int request, void* data); | |||
| void vf_extra_flip(struct vf_instance *vf); | |||
| int vf_next_query_format(struct vf_instance *vf, unsigned int fmt); | |||
| int vf_next_put_image(struct vf_instance *vf,mp_image_t *mpi, double pts); | |||
| void vf_next_draw_slice (struct vf_instance *vf, unsigned char** src, int* stride, int w,int h, int x, int y); | |||
| vf_instance_t* append_filters(vf_instance_t* last); | |||
| void vf_uninit_filter(vf_instance_t* vf); | |||
| void vf_uninit_filter_chain(vf_instance_t* vf); | |||
| int vf_config_wrapper(struct vf_instance *vf, | |||
| int width, int height, int d_width, int d_height, | |||
| unsigned int flags, unsigned int outfmt); | |||
| static inline int norm_qscale(int qscale, int type) | |||
| { | |||
| switch (type) { | |||
| case 0: // MPEG-1 | |||
| return qscale; | |||
| case 1: // MPEG-2 | |||
| return qscale >> 1; | |||
| case 2: // H264 | |||
| return qscale >> 2; | |||
| case 3: // VP56 | |||
| return (63 - qscale + 2) >> 2; | |||
| } | |||
| return qscale; | |||
| } | |||
| #endif /* MPLAYER_VF_H */ | |||
| @@ -0,0 +1,336 @@ | |||
| /* | |||
| * This file is part of MPlayer. | |||
| * | |||
| * MPlayer 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. | |||
| * | |||
| * MPlayer 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 MPlayer; if not, write to the Free Software Foundation, Inc., | |||
| * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | |||
| */ | |||
| #include <stdio.h> | |||
| #include <stdlib.h> | |||
| #include <string.h> | |||
| #include <inttypes.h> | |||
| #include "config.h" | |||
| #include "mp_msg.h" | |||
| #include "img_format.h" | |||
| #include "mp_image.h" | |||
| #include "vf.h" | |||
| //===========================================================================// | |||
| /* FIXME: these all belong in the context, not as globals! */ | |||
| static uint32_t colorMask = 0xF7DEF7DE; | |||
| static uint32_t lowPixelMask = 0x08210821; | |||
| static uint32_t qcolorMask = 0xE79CE79C; | |||
| static uint32_t qlowpixelMask = 0x18631863; | |||
| static uint32_t redblueMask = 0xF81F; | |||
| static uint32_t greenMask = 0x7E0; | |||
| static int PixelsPerMask = 2; | |||
| #define makecol(r,g,b) (r+(g<<8)+(b<<16)) | |||
| #define makecol_depth(d,r,g,b) (r+(g<<8)+(b<<16)) | |||
| static int Init_2xSaI(int d) | |||
| { | |||
| int minr = 0, ming = 0, minb = 0; | |||
| int i; | |||
| // if (d != 15 && d != 16 && d != 24 && d != 32) | |||
| // return -1; | |||
| /* Get lowest color bit */ | |||
| for (i = 0; i < 255; i++) { | |||
| if (!minr) | |||
| minr = makecol(i, 0, 0); | |||
| if (!ming) | |||
| ming = makecol(0, i, 0); | |||
| if (!minb) | |||
| minb = makecol(0, 0, i); | |||
| } | |||
| colorMask = (makecol_depth(d, 255, 0, 0) - minr) | (makecol_depth(d, 0, 255, 0) - ming) | (makecol_depth(d, 0, 0, 255) - minb); | |||
| lowPixelMask = minr | ming | minb; | |||
| qcolorMask = (makecol_depth(d, 255, 0, 0) - 3 * minr) | (makecol_depth(d, 0, 255, 0) - 3 * ming) | (makecol_depth(d, 0, 0, 255) - 3 * minb); | |||
| qlowpixelMask = (minr * 3) | (ming * 3) | (minb * 3); | |||
| redblueMask = makecol_depth(d, 255, 0, 255); | |||
| greenMask = makecol_depth(d, 0, 255, 0); | |||
| PixelsPerMask = (d <= 16) ? 2 : 1; | |||
| if (PixelsPerMask == 2) { | |||
| colorMask |= (colorMask << 16); | |||
| qcolorMask |= (qcolorMask << 16); | |||
| lowPixelMask |= (lowPixelMask << 16); | |||
| qlowpixelMask |= (qlowpixelMask << 16); | |||
| } | |||
| // TRACE("Color Mask: 0x%lX\n", colorMask); | |||
| // TRACE("Low Pixel Mask: 0x%lX\n", lowPixelMask); | |||
| // TRACE("QColor Mask: 0x%lX\n", qcolorMask); | |||
| // TRACE("QLow Pixel Mask: 0x%lX\n", qlowpixelMask); | |||
| return 0; | |||
| } | |||
| #define GET_RESULT(A, B, C, D) ((A != C || A != D) - (B != C || B != D)) | |||
| #define INTERPOLATE(A, B) (((A & colorMask) >> 1) + ((B & colorMask) >> 1) + (A & B & lowPixelMask)) | |||
| #define Q_INTERPOLATE(A, B, C, D) ((A & qcolorMask) >> 2) + ((B & qcolorMask) >> 2) + ((C & qcolorMask) >> 2) + ((D & qcolorMask) >> 2) \ | |||
| + ((((A & qlowpixelMask) + (B & qlowpixelMask) + (C & qlowpixelMask) + (D & qlowpixelMask)) >> 2) & qlowpixelMask) | |||
| static void Super2xSaI_ex(uint8_t *src, uint32_t src_pitch, | |||
| uint8_t *dst, uint32_t dst_pitch, | |||
| uint32_t width, uint32_t height, int sbpp) | |||
| { | |||
| unsigned int x, y; | |||
| uint32_t color[16]; | |||
| unsigned char *src_line[4]; | |||
| /* Point to the first 3 lines. */ | |||
| src_line[0] = src; | |||
| src_line[1] = src; | |||
| src_line[2] = src + src_pitch; | |||
| src_line[3] = src + src_pitch * 2; | |||
| x = 0, y = 0; | |||
| if (PixelsPerMask == 2) { | |||
| unsigned short *sbp; | |||
| sbp = (unsigned short*)src_line[0]; | |||
| color[0] = *sbp; color[1] = color[0]; color[2] = color[0]; color[3] = color[0]; | |||
| color[4] = color[0]; color[5] = color[0]; color[6] = *(sbp + 1); color[7] = *(sbp + 2); | |||
| sbp = (unsigned short*)src_line[2]; | |||
| color[8] = *sbp; color[9] = color[8]; color[10] = *(sbp + 1); color[11] = *(sbp + 2); | |||
| sbp = (unsigned short*)src_line[3]; | |||
| color[12] = *sbp; color[13] = color[12]; color[14] = *(sbp + 1); color[15] = *(sbp + 2); | |||
| } | |||
| else { | |||
| uint32_t *lbp; | |||
| lbp = (uint32_t*)src_line[0]; | |||
| color[0] = *lbp; color[1] = color[0]; color[2] = color[0]; color[3] = color[0]; | |||
| color[4] = color[0]; color[5] = color[0]; color[6] = *(lbp + 1); color[7] = *(lbp + 2); | |||
| lbp = (uint32_t*)src_line[2]; | |||
| color[8] = *lbp; color[9] = color[8]; color[10] = *(lbp + 1); color[11] = *(lbp + 2); | |||
| lbp = (uint32_t*)src_line[3]; | |||
| color[12] = *lbp; color[13] = color[12]; color[14] = *(lbp + 1); color[15] = *(lbp + 2); | |||
| } | |||
| for (y = 0; y < height; y++) { | |||
| unsigned char *dst_line[2]; | |||
| dst_line[0] = dst + dst_pitch*2*y; | |||
| dst_line[1] = dst + dst_pitch*(2*y+1); | |||
| /* Todo: x = width - 2, x = width - 1 */ | |||
| for (x = 0; x < width; x++) { | |||
| uint32_t product1a, product1b, product2a, product2b; | |||
| //--------------------------------------- B0 B1 B2 B3 0 1 2 3 | |||
| // 4 5* 6 S2 -> 4 5* 6 7 | |||
| // 1 2 3 S1 8 9 10 11 | |||
| // A0 A1 A2 A3 12 13 14 15 | |||
| //-------------------------------------- | |||
| if (color[9] == color[6] && color[5] != color[10]) { | |||
| product2b = color[9]; | |||
| product1b = product2b; | |||
| } | |||
| else if (color[5] == color[10] && color[9] != color[6]) { | |||
| product2b = color[5]; | |||
| product1b = product2b; | |||
| } | |||
| else if (color[5] == color[10] && color[9] == color[6]) { | |||
| int r = 0; | |||
| r += GET_RESULT(color[6], color[5], color[8], color[13]); | |||
| r += GET_RESULT(color[6], color[5], color[4], color[1]); | |||
| r += GET_RESULT(color[6], color[5], color[14], color[11]); | |||
| r += GET_RESULT(color[6], color[5], color[2], color[7]); | |||
| if (r > 0) | |||
| product1b = color[6]; | |||
| else if (r < 0) | |||
| product1b = color[5]; | |||
| else | |||
| product1b = INTERPOLATE(color[5], color[6]); | |||
| product2b = product1b; | |||
| } | |||
| else { | |||
| if (color[6] == color[10] && color[10] == color[13] && color[9] != color[14] && color[10] != color[12]) | |||
| product2b = Q_INTERPOLATE(color[10], color[10], color[10], color[9]); | |||
| else if (color[5] == color[9] && color[9] == color[14] && color[13] != color[10] && color[9] != color[15]) | |||
| product2b = Q_INTERPOLATE(color[9], color[9], color[9], color[10]); | |||
| else | |||
| product2b = INTERPOLATE(color[9], color[10]); | |||
| if (color[6] == color[10] && color[6] == color[1] && color[5] != color[2] && color[6] != color[0]) | |||
| product1b = Q_INTERPOLATE(color[6], color[6], color[6], color[5]); | |||
| else if (color[5] == color[9] && color[5] == color[2] && color[1] != color[6] && color[5] != color[3]) | |||
| product1b = Q_INTERPOLATE(color[6], color[5], color[5], color[5]); | |||
| else | |||
| product1b = INTERPOLATE(color[5], color[6]); | |||
| } | |||
| if (color[5] == color[10] && color[9] != color[6] && color[4] == color[5] && color[5] != color[14]) | |||
| product2a = INTERPOLATE(color[9], color[5]); | |||
| else if (color[5] == color[8] && color[6] == color[5] && color[4] != color[9] && color[5] != color[12]) | |||
| product2a = INTERPOLATE(color[9], color[5]); | |||
| else | |||
| product2a = color[9]; | |||
| if (color[9] == color[6] && color[5] != color[10] && color[8] == color[9] && color[9] != color[2]) | |||
| product1a = INTERPOLATE(color[9], color[5]); | |||
| else if (color[4] == color[9] && color[10] == color[9] && color[8] != color[5] && color[9] != color[0]) | |||
| product1a = INTERPOLATE(color[9], color[5]); | |||
| else | |||
| product1a = color[5]; | |||
| if (PixelsPerMask == 2) { | |||
| *((uint32_t *) (&dst_line[0][x * 4])) = product1a | (product1b << 16); | |||
| *((uint32_t *) (&dst_line[1][x * 4])) = product2a | (product2b << 16); | |||
| } | |||
| else { | |||
| *((uint32_t *) (&dst_line[0][x * 8])) = product1a; | |||
| *((uint32_t *) (&dst_line[0][x * 8 + 4])) = product1b; | |||
| *((uint32_t *) (&dst_line[1][x * 8])) = product2a; | |||
| *((uint32_t *) (&dst_line[1][x * 8 + 4])) = product2b; | |||
| } | |||
| /* Move color matrix forward */ | |||
| color[0] = color[1]; color[4] = color[5]; color[8] = color[9]; color[12] = color[13]; | |||
| color[1] = color[2]; color[5] = color[6]; color[9] = color[10]; color[13] = color[14]; | |||
| color[2] = color[3]; color[6] = color[7]; color[10] = color[11]; color[14] = color[15]; | |||
| if (x < width - 3) { | |||
| x += 3; | |||
| if (PixelsPerMask == 2) { | |||
| color[3] = *(((unsigned short*)src_line[0]) + x); | |||
| color[7] = *(((unsigned short*)src_line[1]) + x); | |||
| color[11] = *(((unsigned short*)src_line[2]) + x); | |||
| color[15] = *(((unsigned short*)src_line[3]) + x); | |||
| } | |||
| else { | |||
| color[3] = *(((uint32_t*)src_line[0]) + x); | |||
| color[7] = *(((uint32_t*)src_line[1]) + x); | |||
| color[11] = *(((uint32_t*)src_line[2]) + x); | |||
| color[15] = *(((uint32_t*)src_line[3]) + x); | |||
| } | |||
| x -= 3; | |||
| } | |||
| } | |||
| /* We're done with one line, so we shift the source lines up */ | |||
| src_line[0] = src_line[1]; | |||
| src_line[1] = src_line[2]; | |||
| src_line[2] = src_line[3]; | |||
| /* Read next line */ | |||
| if (y + 3 >= height) | |||
| src_line[3] = src_line[2]; | |||
| else | |||
| src_line[3] = src_line[2] + src_pitch; | |||
| /* Then shift the color matrix up */ | |||
| if (PixelsPerMask == 2) { | |||
| unsigned short *sbp; | |||
| sbp = (unsigned short*)src_line[0]; | |||
| color[0] = *sbp; color[1] = color[0]; color[2] = *(sbp + 1); color[3] = *(sbp + 2); | |||
| sbp = (unsigned short*)src_line[1]; | |||
| color[4] = *sbp; color[5] = color[4]; color[6] = *(sbp + 1); color[7] = *(sbp + 2); | |||
| sbp = (unsigned short*)src_line[2]; | |||
| color[8] = *sbp; color[9] = color[9]; color[10] = *(sbp + 1); color[11] = *(sbp + 2); | |||
| sbp = (unsigned short*)src_line[3]; | |||
| color[12] = *sbp; color[13] = color[12]; color[14] = *(sbp + 1); color[15] = *(sbp + 2); | |||
| } | |||
| else { | |||
| uint32_t *lbp; | |||
| lbp = (uint32_t*)src_line[0]; | |||
| color[0] = *lbp; color[1] = color[0]; color[2] = *(lbp + 1); color[3] = *(lbp + 2); | |||
| lbp = (uint32_t*)src_line[1]; | |||
| color[4] = *lbp; color[5] = color[4]; color[6] = *(lbp + 1); color[7] = *(lbp + 2); | |||
| lbp = (uint32_t*)src_line[2]; | |||
| color[8] = *lbp; color[9] = color[9]; color[10] = *(lbp + 1); color[11] = *(lbp + 2); | |||
| lbp = (uint32_t*)src_line[3]; | |||
| color[12] = *lbp; color[13] = color[12]; color[14] = *(lbp + 1); color[15] = *(lbp + 2); | |||
| } | |||
| } // y loop | |||
| } | |||
| //===========================================================================// | |||
| static int config(struct vf_instance *vf, | |||
| int width, int height, int d_width, int d_height, | |||
| unsigned int flags, unsigned int outfmt){ | |||
| Init_2xSaI(outfmt&255); | |||
| return vf_next_config(vf,2*width,2*height,2*d_width,2*d_height,flags,outfmt); | |||
| } | |||
| static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts){ | |||
| mp_image_t *dmpi; | |||
| // hope we'll get DR buffer: | |||
| dmpi=vf_get_image(vf->next,mpi->imgfmt, | |||
| MP_IMGTYPE_TEMP, MP_IMGFLAG_ACCEPT_STRIDE, | |||
| 2*mpi->w, 2*mpi->h); | |||
| Super2xSaI_ex(mpi->planes[0], mpi->stride[0], | |||
| dmpi->planes[0], dmpi->stride[0], | |||
| mpi->w, mpi->h, mpi->bpp/8); | |||
| return vf_next_put_image(vf,dmpi, pts); | |||
| } | |||
| //===========================================================================// | |||
| static int query_format(struct vf_instance *vf, unsigned int fmt){ | |||
| switch(fmt){ | |||
| // case IMGFMT_BGR15: | |||
| // case IMGFMT_BGR16: | |||
| case IMGFMT_BGR32: | |||
| return vf_next_query_format(vf,fmt); | |||
| } | |||
| return 0; | |||
| } | |||
| static int vf_open(vf_instance_t *vf, char *args){ | |||
| vf->config=config; | |||
| vf->put_image=put_image; | |||
| vf->query_format=query_format; | |||
| return 1; | |||
| } | |||
| const vf_info_t vf_info_2xsai = { | |||
| "2xSai BGR bitmap 2x scaler", | |||
| "2xsai", | |||
| "A'rpi", | |||
| "http://elektron.its.tudelft.nl/~dalikifa/", | |||
| vf_open, | |||
| NULL | |||
| }; | |||
| //===========================================================================// | |||
| @@ -0,0 +1,148 @@ | |||
| /* | |||
| * detect frames that are (almost) black | |||
| * search for black frames to detect scene transitions | |||
| * (c) 2006 Julian Hall | |||
| * | |||
| * based on code designed for skipping commercials | |||
| * (c) 2002-2003 Brian J. Murrell | |||
| * | |||
| * cleanup, simplify, speedup (c) 2006 by Ivo van Poorten | |||
| * | |||
| * This file is part of MPlayer. | |||
| * | |||
| * MPlayer 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. | |||
| * | |||
| * MPlayer 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 MPlayer; if not, write to the Free Software Foundation, Inc., | |||
| * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | |||
| */ | |||
| #include <stdio.h> | |||
| #include <stdlib.h> | |||
| #include <string.h> | |||
| #include "config.h" | |||
| #include "mp_msg.h" | |||
| #include "img_format.h" | |||
| #include "mp_image.h" | |||
| #include "vf.h" | |||
| struct vf_priv_s { | |||
| unsigned int bamount, bthresh, frame, lastkeyframe; | |||
| }; | |||
| static int config(struct vf_instance *vf, int width, int height, int d_width, | |||
| int d_height, unsigned int flags, unsigned int outfmt) { | |||
| return vf_next_config(vf,width,height,d_width,d_height,flags,outfmt); | |||
| } | |||
| static int query_format(struct vf_instance *vf, unsigned fmt) { | |||
| switch(fmt) { | |||
| case IMGFMT_YVU9: | |||
| case IMGFMT_IF09: | |||
| case IMGFMT_YV12: | |||
| case IMGFMT_I420: | |||
| case IMGFMT_IYUV: | |||
| case IMGFMT_CLPL: | |||
| case IMGFMT_Y800: | |||
| case IMGFMT_Y8: | |||
| case IMGFMT_NV12: | |||
| case IMGFMT_NV21: | |||
| case IMGFMT_444P: | |||
| case IMGFMT_422P: | |||
| case IMGFMT_411P: | |||
| case IMGFMT_HM12: | |||
| return vf_next_query_format(vf, fmt); | |||
| } | |||
| return 0; | |||
| } | |||
| static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts){ | |||
| mp_image_t *dmpi; | |||
| int x, y; | |||
| int nblack=0, pblack=0; | |||
| unsigned char *yplane = mpi->planes[0]; | |||
| unsigned int ystride = mpi->stride[0]; | |||
| int pict_type = mpi->pict_type; | |||
| int w = mpi->w, h = mpi->h; | |||
| int bthresh = vf->priv->bthresh; | |||
| int bamount = vf->priv->bamount; | |||
| static const char *const picttypes[4] = { "unknown", "I", "P", "B" }; | |||
| for (y=1; y<=h; y++) { | |||
| for (x=0; x<w; x++) | |||
| nblack += yplane[x] < bthresh; | |||
| pblack = nblack*100/(w*y); | |||
| if (pblack < bamount) break; | |||
| yplane += ystride; | |||
| } | |||
| if (pict_type > 3 || pict_type < 0) pict_type = 0; | |||
| if (pict_type == 1) vf->priv->lastkeyframe = vf->priv->frame; | |||
| if (pblack >= bamount) | |||
| mp_msg(MSGT_VFILTER, MSGL_INFO,"vf_blackframe: %u, %i%%, %s (I:%u)\n", | |||
| vf->priv->frame, pblack, picttypes[pict_type], | |||
| vf->priv->lastkeyframe); | |||
| vf->priv->frame++; | |||
| dmpi = vf_get_image(vf->next, mpi->imgfmt, MP_IMGTYPE_EXPORT, 0, | |||
| mpi->width, mpi->height); | |||
| dmpi->planes[0] = mpi->planes[0]; | |||
| dmpi->stride[0] = mpi->stride[0]; | |||
| dmpi->planes[1] = mpi->planes[1]; | |||
| dmpi->stride[1] = mpi->stride[1]; | |||
| dmpi->planes[2] = mpi->planes[2]; | |||
| dmpi->stride[2] = mpi->stride[2]; | |||
| vf_clone_mpi_attributes(dmpi, mpi); | |||
| return vf_next_put_image(vf, dmpi, pts); | |||
| } | |||
| static int control(struct vf_instance *vf, int request, void* data){ | |||
| return vf_next_control(vf,request,data); | |||
| } | |||
| static void uninit(struct vf_instance *vf) { | |||
| free(vf->priv); | |||
| } | |||
| static int vf_open(vf_instance_t *vf, char *args){ | |||
| vf->priv = malloc(sizeof(struct vf_priv_s)); | |||
| if (!vf->priv) return 0; | |||
| vf->config = config; | |||
| vf->put_image = put_image; | |||
| vf->control = control; | |||
| vf->uninit = uninit; | |||
| vf->query_format = query_format; | |||
| vf->priv->bamount = 98; | |||
| vf->priv->bthresh = 0x20; | |||
| vf->priv->frame = 0; | |||
| vf->priv->lastkeyframe = 0; | |||
| if (args) | |||
| sscanf(args, "%u:%u", &vf->priv->bamount, &vf->priv->bthresh); | |||
| return 1; | |||
| } | |||
| const vf_info_t vf_info_blackframe = { | |||
| "detects black frames", | |||
| "blackframe", | |||
| "Brian J. Murrell, Julian Hall, Ivo van Poorten", | |||
| "Useful for detecting scene transitions", | |||
| vf_open, | |||
| NULL | |||
| }; | |||
| @@ -0,0 +1,214 @@ | |||
| /* | |||
| * Copyright (C) 2002 Michael Niedermayer <michaelni@gmx.at> | |||
| * | |||
| * This file is part of MPlayer. | |||
| * | |||
| * MPlayer 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. | |||
| * | |||
| * MPlayer 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 MPlayer; if not, write to the Free Software Foundation, Inc., | |||
| * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | |||
| */ | |||
| #include <stdio.h> | |||
| #include <stdlib.h> | |||
| #include <string.h> | |||
| #include <inttypes.h> | |||
| #include <assert.h> | |||
| #include "mp_msg.h" | |||
| #include "img_format.h" | |||
| #include "mp_image.h" | |||
| #include "vf.h" | |||
| //===========================================================================// | |||
| typedef struct FilterParam{ | |||
| int radius; | |||
| int power; | |||
| }FilterParam; | |||
| struct vf_priv_s { | |||
| FilterParam lumaParam; | |||
| FilterParam chromaParam; | |||
| }; | |||
| /***************************************************************************/ | |||
| static int config(struct vf_instance *vf, | |||
| int width, int height, int d_width, int d_height, | |||
| unsigned int flags, unsigned int outfmt){ | |||
| return vf_next_config(vf,width,height,d_width,d_height,flags,outfmt); | |||
| } | |||
| static inline void blur(uint8_t *dst, uint8_t *src, int w, int radius, int dstStep, int srcStep){ | |||
| int x; | |||
| const int length= radius*2 + 1; | |||
| const int inv= ((1<<16) + length/2)/length; | |||
| int sum= 0; | |||
| for(x=0; x<radius; x++){ | |||
| sum+= src[x*srcStep]<<1; | |||
| } | |||
| sum+= src[radius*srcStep]; | |||
| for(x=0; x<=radius; x++){ | |||
| sum+= src[(radius+x)*srcStep] - src[(radius-x)*srcStep]; | |||
| dst[x*dstStep]= (sum*inv + (1<<15))>>16; | |||
| } | |||
| for(; x<w-radius; x++){ | |||
| sum+= src[(radius+x)*srcStep] - src[(x-radius-1)*srcStep]; | |||
| dst[x*dstStep]= (sum*inv + (1<<15))>>16; | |||
| } | |||
| for(; x<w; x++){ | |||
| sum+= src[(2*w-radius-x-1)*srcStep] - src[(x-radius-1)*srcStep]; | |||
| dst[x*dstStep]= (sum*inv + (1<<15))>>16; | |||
| } | |||
| } | |||
| static inline void blur2(uint8_t *dst, uint8_t *src, int w, int radius, int power, int dstStep, int srcStep){ | |||
| uint8_t temp[2][4096]; | |||
| uint8_t *a= temp[0], *b=temp[1]; | |||
| if(radius){ | |||
| blur(a, src, w, radius, 1, srcStep); | |||
| for(; power>2; power--){ | |||
| uint8_t *c; | |||
| blur(b, a, w, radius, 1, 1); | |||
| c=a; a=b; b=c; | |||
| } | |||
| if(power>1) | |||
| blur(dst, a, w, radius, dstStep, 1); | |||
| else{ | |||
| int i; | |||
| for(i=0; i<w; i++) | |||
| dst[i*dstStep]= a[i]; | |||
| } | |||
| }else{ | |||
| int i; | |||
| for(i=0; i<w; i++) | |||
| dst[i*dstStep]= src[i*srcStep]; | |||
| } | |||
| } | |||
| static void hBlur(uint8_t *dst, uint8_t *src, int w, int h, int dstStride, int srcStride, int radius, int power){ | |||
| int y; | |||
| if(radius==0 && dst==src) return; | |||
| for(y=0; y<h; y++){ | |||
| blur2(dst + y*dstStride, src + y*srcStride, w, radius, power, 1, 1); | |||
| } | |||
| } | |||
| //FIXME optimize (x before y !!!) | |||
| static void vBlur(uint8_t *dst, uint8_t *src, int w, int h, int dstStride, int srcStride, int radius, int power){ | |||
| int x; | |||
| if(radius==0 && dst==src) return; | |||
| for(x=0; x<w; x++){ | |||
| blur2(dst + x, src + x, h, radius, power, dstStride, srcStride); | |||
| } | |||
| } | |||
| static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts){ | |||
| int cw= mpi->w >> mpi->chroma_x_shift; | |||
| int ch= mpi->h >> mpi->chroma_y_shift; | |||
| mp_image_t *dmpi=vf_get_image(vf->next,mpi->imgfmt, | |||
| MP_IMGTYPE_TEMP, MP_IMGFLAG_ACCEPT_STRIDE | MP_IMGFLAG_READABLE, | |||
| mpi->w,mpi->h); | |||
| assert(mpi->flags&MP_IMGFLAG_PLANAR); | |||
| hBlur(dmpi->planes[0], mpi->planes[0], mpi->w,mpi->h, | |||
| dmpi->stride[0], mpi->stride[0], vf->priv->lumaParam.radius, vf->priv->lumaParam.power); | |||
| hBlur(dmpi->planes[1], mpi->planes[1], cw,ch, | |||
| dmpi->stride[1], mpi->stride[1], vf->priv->chromaParam.radius, vf->priv->chromaParam.power); | |||
| hBlur(dmpi->planes[2], mpi->planes[2], cw,ch, | |||
| dmpi->stride[2], mpi->stride[2], vf->priv->chromaParam.radius, vf->priv->chromaParam.power); | |||
| vBlur(dmpi->planes[0], dmpi->planes[0], mpi->w,mpi->h, | |||
| dmpi->stride[0], dmpi->stride[0], vf->priv->lumaParam.radius, vf->priv->lumaParam.power); | |||
| vBlur(dmpi->planes[1], dmpi->planes[1], cw,ch, | |||
| dmpi->stride[1], dmpi->stride[1], vf->priv->chromaParam.radius, vf->priv->chromaParam.power); | |||
| vBlur(dmpi->planes[2], dmpi->planes[2], cw,ch, | |||
| dmpi->stride[2], dmpi->stride[2], vf->priv->chromaParam.radius, vf->priv->chromaParam.power); | |||
| return vf_next_put_image(vf,dmpi, pts); | |||
| } | |||
| //===========================================================================// | |||
| static int query_format(struct vf_instance *vf, unsigned int fmt){ | |||
| switch(fmt) | |||
| { | |||
| case IMGFMT_YV12: | |||
| case IMGFMT_I420: | |||
| case IMGFMT_IYUV: | |||
| case IMGFMT_YVU9: | |||
| case IMGFMT_444P: | |||
| case IMGFMT_422P: | |||
| case IMGFMT_411P: | |||
| return vf_next_query_format(vf, fmt); | |||
| } | |||
| return 0; | |||
| } | |||
| static int vf_open(vf_instance_t *vf, char *args){ | |||
| int e; | |||
| vf->config=config; | |||
| vf->put_image=put_image; | |||
| // vf->get_image=get_image; | |||
| vf->query_format=query_format; | |||
| vf->priv=malloc(sizeof(struct vf_priv_s)); | |||
| memset(vf->priv, 0, sizeof(struct vf_priv_s)); | |||
| if(args==NULL) return 0; | |||
| e=sscanf(args, "%d:%d:%d:%d", | |||
| &vf->priv->lumaParam.radius, | |||
| &vf->priv->lumaParam.power, | |||
| &vf->priv->chromaParam.radius, | |||
| &vf->priv->chromaParam.power | |||
| ); | |||
| if(e==2){ | |||
| vf->priv->chromaParam.radius= vf->priv->lumaParam.radius; | |||
| vf->priv->chromaParam.power = vf->priv->lumaParam.power; | |||
| }else if(e!=4) | |||
| return 0; | |||
| if(vf->priv->lumaParam.radius < 0) return 0; | |||
| if(vf->priv->chromaParam.radius < 0) return 0; | |||
| return 1; | |||
| } | |||
| const vf_info_t vf_info_boxblur = { | |||
| "box blur", | |||
| "boxblur", | |||
| "Michael Niedermayer", | |||
| "", | |||
| vf_open, | |||
| NULL | |||
| }; | |||
| //===========================================================================// | |||
| @@ -0,0 +1,201 @@ | |||
| /* | |||
| * This file is part of MPlayer. | |||
| * | |||
| * MPlayer 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. | |||
| * | |||
| * MPlayer 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 MPlayer; if not, write to the Free Software Foundation, Inc., | |||
| * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | |||
| */ | |||
| #include <stdio.h> | |||
| #include <stdlib.h> | |||
| #include <string.h> | |||
| #include <inttypes.h> | |||
| #include "config.h" | |||
| #include "mp_msg.h" | |||
| #include "help_mp.h" | |||
| #include "img_format.h" | |||
| #include "mp_image.h" | |||
| #include "vf.h" | |||
| struct vf_priv_s { | |||
| int x1,y1,x2,y2; | |||
| int limit; | |||
| int round; | |||
| int reset_count; | |||
| int fno; | |||
| }; | |||
| static int checkline(unsigned char* src,int stride,int len,int bpp){ | |||
| int total=0; | |||
| int div=len; | |||
| switch(bpp){ | |||
| case 1: | |||
| while(--len>=0){ | |||
| total+=src[0]; src+=stride; | |||
| } | |||
| break; | |||
| case 3: | |||
| case 4: | |||
| while(--len>=0){ | |||
| total+=src[0]+src[1]+src[2]; src+=stride; | |||
| } | |||
| div*=3; | |||
| break; | |||
| } | |||
| total/=div; | |||
| // printf("total=%d\n",total); | |||
| return total; | |||
| } | |||
| //===========================================================================// | |||
| static int config(struct vf_instance *vf, | |||
| int width, int height, int d_width, int d_height, | |||
| unsigned int flags, unsigned int outfmt){ | |||
| vf->priv->x1=width - 1; | |||
| vf->priv->y1=height - 1; | |||
| vf->priv->x2=0; | |||
| vf->priv->y2=0; | |||
| vf->priv->fno=-2; | |||
| return vf_next_config(vf,width,height,d_width,d_height,flags,outfmt); | |||
| } | |||
| static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts){ | |||
| mp_image_t *dmpi; | |||
| int bpp=mpi->bpp/8; | |||
| int w,h,x,y,shrink_by; | |||
| // hope we'll get DR buffer: | |||
| dmpi=vf_get_image(vf->next,mpi->imgfmt, | |||
| MP_IMGTYPE_EXPORT, 0, | |||
| mpi->w, mpi->h); | |||
| dmpi->planes[0]=mpi->planes[0]; | |||
| dmpi->planes[1]=mpi->planes[1]; | |||
| dmpi->planes[2]=mpi->planes[2]; | |||
| dmpi->stride[0]=mpi->stride[0]; | |||
| dmpi->stride[1]=mpi->stride[1]; | |||
| dmpi->stride[2]=mpi->stride[2]; | |||
| dmpi->width=mpi->width; | |||
| dmpi->height=mpi->height; | |||
| if(++vf->priv->fno>0){ // ignore first 2 frames - they may be empty | |||
| // Reset the crop area every reset_count frames, if reset_count is > 0 | |||
| if(vf->priv->reset_count > 0 && vf->priv->fno > vf->priv->reset_count){ | |||
| vf->priv->x1=mpi->w-1; | |||
| vf->priv->y1=mpi->h-1; | |||
| vf->priv->x2=0; | |||
| vf->priv->y2=0; | |||
| vf->priv->fno=1; | |||
| } | |||
| for(y=0;y<vf->priv->y1;y++){ | |||
| if(checkline(mpi->planes[0]+mpi->stride[0]*y,bpp,mpi->w,bpp)>vf->priv->limit){ | |||
| vf->priv->y1=y; | |||
| break; | |||
| } | |||
| } | |||
| for(y=mpi->h-1;y>vf->priv->y2;y--){ | |||
| if(checkline(mpi->planes[0]+mpi->stride[0]*y,bpp,mpi->w,bpp)>vf->priv->limit){ | |||
| vf->priv->y2=y; | |||
| break; | |||
| } | |||
| } | |||
| for(y=0;y<vf->priv->x1;y++){ | |||
| if(checkline(mpi->planes[0]+bpp*y,mpi->stride[0],mpi->h,bpp)>vf->priv->limit){ | |||
| vf->priv->x1=y; | |||
| break; | |||
| } | |||
| } | |||
| for(y=mpi->w-1;y>vf->priv->x2;y--){ | |||
| if(checkline(mpi->planes[0]+bpp*y,mpi->stride[0],mpi->h,bpp)>vf->priv->limit){ | |||
| vf->priv->x2=y; | |||
| break; | |||
| } | |||
| } | |||
| // round x and y (up), important for yuv colorspaces | |||
| // make sure they stay rounded! | |||
| x=(vf->priv->x1+1)&(~1); | |||
| y=(vf->priv->y1+1)&(~1); | |||
| w = vf->priv->x2 - x + 1; | |||
| h = vf->priv->y2 - y + 1; | |||
| // w and h must be divisible by 2 as well because of yuv | |||
| // colorspace problems. | |||
| if (vf->priv->round <= 1) | |||
| vf->priv->round = 16; | |||
| if (vf->priv->round % 2) | |||
| vf->priv->round *= 2; | |||
| shrink_by = w % vf->priv->round; | |||
| w -= shrink_by; | |||
| x += (shrink_by / 2 + 1) & ~1; | |||
| shrink_by = h % vf->priv->round; | |||
| h -= shrink_by; | |||
| y += (shrink_by / 2 + 1) & ~1; | |||
| mp_msg(MSGT_VFILTER, MSGL_INFO, MSGTR_MPCODECS_CropArea, | |||
| vf->priv->x1,vf->priv->x2, | |||
| vf->priv->y1,vf->priv->y2, | |||
| w,h,x,y); | |||
| } | |||
| return vf_next_put_image(vf,dmpi, pts); | |||
| } | |||
| static int query_format(struct vf_instance *vf, unsigned int fmt) { | |||
| switch(fmt) { | |||
| // the default limit value works only right with YV12 right now. | |||
| case IMGFMT_YV12: | |||
| return vf_next_query_format(vf, fmt); | |||
| } | |||
| return 0; | |||
| } | |||
| //===========================================================================// | |||
| static int vf_open(vf_instance_t *vf, char *args){ | |||
| vf->config=config; | |||
| vf->put_image=put_image; | |||
| vf->query_format=query_format; | |||
| vf->priv=malloc(sizeof(struct vf_priv_s)); | |||
| vf->priv->limit=24; // should be option | |||
| vf->priv->round = 0; | |||
| vf->priv->reset_count = 0; | |||
| if(args) sscanf(args, "%d:%d:%d", | |||
| &vf->priv->limit, | |||
| &vf->priv->round, | |||
| &vf->priv->reset_count); | |||
| return 1; | |||
| } | |||
| const vf_info_t vf_info_cropdetect = { | |||
| "autodetect crop size", | |||
| "cropdetect", | |||
| "A'rpi", | |||
| "", | |||
| vf_open, | |||
| NULL | |||
| }; | |||
| //===========================================================================// | |||
| @@ -0,0 +1,198 @@ | |||
| /* | |||
| * This file is part of MPlayer. | |||
| * | |||
| * MPlayer 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. | |||
| * | |||
| * MPlayer 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 MPlayer; if not, write to the Free Software Foundation, Inc., | |||
| * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | |||
| */ | |||
| #include <stdio.h> | |||
| #include <stdlib.h> | |||
| #include <string.h> | |||
| #include "config.h" | |||
| #include "mp_msg.h" | |||
| #include "cpudetect.h" | |||
| #include "img_format.h" | |||
| #include "mp_image.h" | |||
| #include "vf.h" | |||
| #include "libvo/fastmemcpy.h" | |||
| struct vf_priv_s { | |||
| int hi, lo; | |||
| float frac; | |||
| int max, last, cnt; | |||
| }; | |||
| #if HAVE_MMX && HAVE_EBX_AVAILABLE | |||
| static int diff_MMX(unsigned char *old, unsigned char *new, int os, int ns) | |||
| { | |||
| volatile short out[4]; | |||
| __asm__ ( | |||
| "movl $8, %%ecx \n\t" | |||
| "pxor %%mm4, %%mm4 \n\t" | |||
| "pxor %%mm7, %%mm7 \n\t" | |||
| ASMALIGN(4) | |||
| "1: \n\t" | |||
| "movq (%%"REG_S"), %%mm0 \n\t" | |||
| "movq (%%"REG_S"), %%mm2 \n\t" | |||
| "add %%"REG_a", %%"REG_S" \n\t" | |||
| "movq (%%"REG_D"), %%mm1 \n\t" | |||
| "add %%"REG_b", %%"REG_D" \n\t" | |||
| "psubusb %%mm1, %%mm2 \n\t" | |||
| "psubusb %%mm0, %%mm1 \n\t" | |||
| "movq %%mm2, %%mm0 \n\t" | |||
| "movq %%mm1, %%mm3 \n\t" | |||
| "punpcklbw %%mm7, %%mm0 \n\t" | |||
| "punpcklbw %%mm7, %%mm1 \n\t" | |||
| "punpckhbw %%mm7, %%mm2 \n\t" | |||
| "punpckhbw %%mm7, %%mm3 \n\t" | |||
| "paddw %%mm0, %%mm4 \n\t" | |||
| "paddw %%mm1, %%mm4 \n\t" | |||
| "paddw %%mm2, %%mm4 \n\t" | |||
| "paddw %%mm3, %%mm4 \n\t" | |||
| "decl %%ecx \n\t" | |||
| "jnz 1b \n\t" | |||
| "movq %%mm4, (%%"REG_d") \n\t" | |||
| "emms \n\t" | |||
| : | |||
| : "S" (old), "D" (new), "a" ((long)os), "b" ((long)ns), "d" (out) | |||
| : "%ecx", "memory" | |||
| ); | |||
| return out[0]+out[1]+out[2]+out[3]; | |||
| } | |||
| #endif | |||
| static int diff_C(unsigned char *old, unsigned char *new, int os, int ns) | |||
| { | |||
| int x, y, d=0; | |||
| for (y = 8; y; y--) { | |||
| for (x = 8; x; x--) { | |||
| d += abs(new[x] - old[x]); | |||
| } | |||
| new += ns; | |||
| old += os; | |||
| } | |||
| return d; | |||
| } | |||
| static int (*diff)(unsigned char *, unsigned char *, int, int); | |||
| static int diff_to_drop_plane(int hi, int lo, float frac, unsigned char *old, unsigned char *new, int w, int h, int os, int ns) | |||
| { | |||
| int x, y; | |||
| int d, c=0; | |||
| int t = (w/16)*(h/16)*frac; | |||
| for (y = 0; y < h-7; y += 4) { | |||
| for (x = 8; x < w-7; x += 4) { | |||
| d = diff(old+x+y*os, new+x+y*ns, os, ns); | |||
| if (d > hi) return 0; | |||
| if (d > lo) { | |||
| c++; | |||
| if (c > t) return 0; | |||
| } | |||
| } | |||
| } | |||
| return 1; | |||
| } | |||
| static int diff_to_drop(int hi, int lo, float frac, mp_image_t *old, mp_image_t *new) | |||
| { | |||
| if (new->flags & MP_IMGFLAG_PLANAR) { | |||
| return diff_to_drop_plane(hi,lo,frac, old->planes[0], new->planes[0], | |||
| new->w, new->h, old->stride[0], new->stride[0]) | |||
| && diff_to_drop_plane(hi,lo,frac, old->planes[1], new->planes[1], | |||
| new->chroma_width, new->chroma_height, | |||
| old->stride[1], new->stride[1]) | |||
| && diff_to_drop_plane(hi,lo,frac, old->planes[2], new->planes[2], | |||
| new->chroma_width, new->chroma_height, | |||
| old->stride[2], new->stride[2]); | |||
| } | |||
| return diff_to_drop_plane(hi,lo,frac, old->planes[0], new->planes[0], | |||
| new->w*(new->bpp/8), new->h, old->stride[0], new->stride[0]); | |||
| } | |||
| static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts) | |||
| { | |||
| mp_image_t *dmpi; | |||
| dmpi = vf_get_image(vf->next, mpi->imgfmt, | |||
| MP_IMGTYPE_STATIC, MP_IMGFLAG_ACCEPT_STRIDE | | |||
| MP_IMGFLAG_PRESERVE | MP_IMGFLAG_READABLE, | |||
| mpi->width, mpi->height); | |||
| dmpi->qscale = mpi->qscale; | |||
| dmpi->qstride = mpi->qstride; | |||
| dmpi->qscale_type = mpi->qscale_type; | |||
| if (diff_to_drop(vf->priv->hi, vf->priv->lo, vf->priv->frac, dmpi, mpi)) { | |||
| if (vf->priv->max == 0) | |||
| return 0; | |||
| else if ((vf->priv->max > 0) && (vf->priv->cnt++ < vf->priv->max)) | |||
| return 0; | |||
| else if ((vf->priv->max < 0) && (vf->priv->last+1 >= -vf->priv->max)) | |||
| return vf->priv->last=0; | |||
| } | |||
| vf->priv->last++; | |||
| vf->priv->cnt=0; | |||
| memcpy_pic(dmpi->planes[0], mpi->planes[0], mpi->w, mpi->h, | |||
| dmpi->stride[0], mpi->stride[0]); | |||
| if (mpi->flags & MP_IMGFLAG_PLANAR) { | |||
| memcpy_pic(dmpi->planes[1], mpi->planes[1], | |||
| mpi->chroma_width, mpi->chroma_height, | |||
| dmpi->stride[1], mpi->stride[1]); | |||
| memcpy_pic(dmpi->planes[2], mpi->planes[2], | |||
| mpi->chroma_width, mpi->chroma_height, | |||
| dmpi->stride[2], mpi->stride[2]); | |||
| } | |||
| return vf_next_put_image(vf, dmpi, pts); | |||
| } | |||
| static void uninit(struct vf_instance *vf) | |||
| { | |||
| free(vf->priv); | |||
| } | |||
| static int vf_open(vf_instance_t *vf, char *args) | |||
| { | |||
| struct vf_priv_s *p; | |||
| vf->put_image = put_image; | |||
| vf->uninit = uninit; | |||
| vf->default_reqs = VFCAP_ACCEPT_STRIDE; | |||
| vf->priv = p = calloc(1, sizeof(struct vf_priv_s)); | |||
| p->max = 0; | |||
| p->hi = 64*12; | |||
| p->lo = 64*5; | |||
| p->frac = 0.33; | |||
| if (args) sscanf(args, "%d:%d:%d:%f", &p->max, &p->hi, &p->lo, &p->frac); | |||
| diff = diff_C; | |||
| #if HAVE_MMX && HAVE_EBX_AVAILABLE | |||
| if(gCpuCaps.hasMMX) diff = diff_MMX; | |||
| #endif | |||
| return 1; | |||
| } | |||
| const vf_info_t vf_info_decimate = { | |||
| "near-duplicate frame remover", | |||
| "decimate", | |||
| "Rich Felker", | |||
| "", | |||
| vf_open, | |||
| NULL | |||
| }; | |||
| @@ -0,0 +1,262 @@ | |||
| /* | |||
| * Copyright (C) 2002 Jindrich Makovicka <makovick@gmail.com> | |||
| * | |||
| * This file is part of MPlayer. | |||
| * | |||
| * MPlayer 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. | |||
| * | |||
| * MPlayer 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 MPlayer; if not, write to the Free Software Foundation, Inc., | |||
| * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | |||
| */ | |||
| /* A very simple tv station logo remover */ | |||
| #include <stdio.h> | |||
| #include <stdlib.h> | |||
| #include <string.h> | |||
| #include <inttypes.h> | |||
| #include <math.h> | |||
| #include "mp_msg.h" | |||
| #include "cpudetect.h" | |||
| #include "img_format.h" | |||
| #include "mp_image.h" | |||
| #include "vf.h" | |||
| #include "libvo/fastmemcpy.h" | |||
| #include "m_option.h" | |||
| #include "m_struct.h" | |||
| //===========================================================================// | |||
| static struct vf_priv_s { | |||
| unsigned int outfmt; | |||
| int xoff, yoff, lw, lh, band, show; | |||
| } const vf_priv_dflt = { | |||
| 0, | |||
| 0, 0, 0, 0, 0, 0 | |||
| }; | |||
| #define MIN(a,b) (((a) < (b)) ? (a) : (b)) | |||
| #define MAX(a,b) (((a) > (b)) ? (a) : (b)) | |||
| static void delogo(uint8_t *dst, uint8_t *src, int dstStride, int srcStride, int width, int height, | |||
| int logo_x, int logo_y, int logo_w, int logo_h, int band, int show, int direct) { | |||
| int y, x; | |||
| int interp, dist; | |||
| uint8_t *xdst, *xsrc; | |||
| uint8_t *topleft, *botleft, *topright; | |||
| int xclipl, xclipr, yclipt, yclipb; | |||
| int logo_x1, logo_x2, logo_y1, logo_y2; | |||
| xclipl = MAX(-logo_x, 0); | |||
| xclipr = MAX(logo_x+logo_w-width, 0); | |||
| yclipt = MAX(-logo_y, 0); | |||
| yclipb = MAX(logo_y+logo_h-height, 0); | |||
| logo_x1 = logo_x + xclipl; | |||
| logo_x2 = logo_x + logo_w - xclipr; | |||
| logo_y1 = logo_y + yclipt; | |||
| logo_y2 = logo_y + logo_h - yclipb; | |||
| topleft = src+logo_y1*srcStride+logo_x1; | |||
| topright = src+logo_y1*srcStride+logo_x2-1; | |||
| botleft = src+(logo_y2-1)*srcStride+logo_x1; | |||
| if (!direct) memcpy_pic(dst, src, width, height, dstStride, srcStride); | |||
| dst += (logo_y1+1)*dstStride; | |||
| src += (logo_y1+1)*srcStride; | |||
| for(y = logo_y1+1; y < logo_y2-1; y++) | |||
| { | |||
| for (x = logo_x1+1, xdst = dst+logo_x1+1, xsrc = src+logo_x1+1; x < logo_x2-1; x++, xdst++, xsrc++) { | |||
| interp = ((topleft[srcStride*(y-logo_y-yclipt)] | |||
| + topleft[srcStride*(y-logo_y-1-yclipt)] | |||
| + topleft[srcStride*(y-logo_y+1-yclipt)])*(logo_w-(x-logo_x))/logo_w | |||
| + (topright[srcStride*(y-logo_y-yclipt)] | |||
| + topright[srcStride*(y-logo_y-1-yclipt)] | |||
| + topright[srcStride*(y-logo_y+1-yclipt)])*(x-logo_x)/logo_w | |||
| + (topleft[x-logo_x-xclipl] | |||
| + topleft[x-logo_x-1-xclipl] | |||
| + topleft[x-logo_x+1-xclipl])*(logo_h-(y-logo_y))/logo_h | |||
| + (botleft[x-logo_x-xclipl] | |||
| + botleft[x-logo_x-1-xclipl] | |||
| + botleft[x-logo_x+1-xclipl])*(y-logo_y)/logo_h | |||
| )/6; | |||
| /* interp = (topleft[srcStride*(y-logo_y)]*(logo_w-(x-logo_x))/logo_w | |||
| + topright[srcStride*(y-logo_y)]*(x-logo_x)/logo_w | |||
| + topleft[x-logo_x]*(logo_h-(y-logo_y))/logo_h | |||
| + botleft[x-logo_x]*(y-logo_y)/logo_h | |||
| )/2;*/ | |||
| if (y >= logo_y+band && y < logo_y+logo_h-band && x >= logo_x+band && x < logo_x+logo_w-band) { | |||
| *xdst = interp; | |||
| } else { | |||
| dist = 0; | |||
| if (x < logo_x+band) dist = MAX(dist, logo_x-x+band); | |||
| else if (x >= logo_x+logo_w-band) dist = MAX(dist, x-(logo_x+logo_w-1-band)); | |||
| if (y < logo_y+band) dist = MAX(dist, logo_y-y+band); | |||
| else if (y >= logo_y+logo_h-band) dist = MAX(dist, y-(logo_y+logo_h-1-band)); | |||
| *xdst = (*xsrc*dist + interp*(band-dist))/band; | |||
| if (show && (dist == band-1)) *xdst = 0; | |||
| } | |||
| } | |||
| dst+= dstStride; | |||
| src+= srcStride; | |||
| } | |||
| } | |||
| static int config(struct vf_instance *vf, | |||
| int width, int height, int d_width, int d_height, | |||
| unsigned int flags, unsigned int outfmt){ | |||
| return vf_next_config(vf,width,height,d_width,d_height,flags,outfmt); | |||
| } | |||
| static void get_image(struct vf_instance *vf, mp_image_t *mpi){ | |||
| if(mpi->flags&MP_IMGFLAG_PRESERVE) return; // don't change | |||
| if(mpi->imgfmt!=vf->priv->outfmt) return; // colorspace differ | |||
| // ok, we can do pp in-place (or pp disabled): | |||
| vf->dmpi=vf_get_image(vf->next,mpi->imgfmt, | |||
| mpi->type, mpi->flags, mpi->w, mpi->h); | |||
| mpi->planes[0]=vf->dmpi->planes[0]; | |||
| mpi->stride[0]=vf->dmpi->stride[0]; | |||
| mpi->width=vf->dmpi->width; | |||
| if(mpi->flags&MP_IMGFLAG_PLANAR){ | |||
| mpi->planes[1]=vf->dmpi->planes[1]; | |||
| mpi->planes[2]=vf->dmpi->planes[2]; | |||
| mpi->stride[1]=vf->dmpi->stride[1]; | |||
| mpi->stride[2]=vf->dmpi->stride[2]; | |||
| } | |||
| mpi->flags|=MP_IMGFLAG_DIRECT; | |||
| } | |||
| static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts){ | |||
| mp_image_t *dmpi; | |||
| if(!(mpi->flags&MP_IMGFLAG_DIRECT)){ | |||
| // no DR, so get a new image! hope we'll get DR buffer: | |||
| vf->dmpi=vf_get_image(vf->next,vf->priv->outfmt, | |||
| MP_IMGTYPE_TEMP, MP_IMGFLAG_ACCEPT_STRIDE, | |||
| mpi->w,mpi->h); | |||
| } | |||
| dmpi= vf->dmpi; | |||
| delogo(dmpi->planes[0], mpi->planes[0], dmpi->stride[0], mpi->stride[0], mpi->w, mpi->h, | |||
| vf->priv->xoff, vf->priv->yoff, vf->priv->lw, vf->priv->lh, vf->priv->band, vf->priv->show, | |||
| mpi->flags&MP_IMGFLAG_DIRECT); | |||
| delogo(dmpi->planes[1], mpi->planes[1], dmpi->stride[1], mpi->stride[1], mpi->w/2, mpi->h/2, | |||
| vf->priv->xoff/2, vf->priv->yoff/2, vf->priv->lw/2, vf->priv->lh/2, vf->priv->band/2, vf->priv->show, | |||
| mpi->flags&MP_IMGFLAG_DIRECT); | |||
| delogo(dmpi->planes[2], mpi->planes[2], dmpi->stride[2], mpi->stride[2], mpi->w/2, mpi->h/2, | |||
| vf->priv->xoff/2, vf->priv->yoff/2, vf->priv->lw/2, vf->priv->lh/2, vf->priv->band/2, vf->priv->show, | |||
| mpi->flags&MP_IMGFLAG_DIRECT); | |||
| vf_clone_mpi_attributes(dmpi, mpi); | |||
| return vf_next_put_image(vf,dmpi, pts); | |||
| } | |||
| static void uninit(struct vf_instance *vf){ | |||
| if(!vf->priv) return; | |||
| free(vf->priv); | |||
| vf->priv=NULL; | |||
| } | |||
| //===========================================================================// | |||
| static int query_format(struct vf_instance *vf, unsigned int fmt){ | |||
| switch(fmt) | |||
| { | |||
| case IMGFMT_YV12: | |||
| case IMGFMT_I420: | |||
| case IMGFMT_IYUV: | |||
| return vf_next_query_format(vf,vf->priv->outfmt); | |||
| } | |||
| return 0; | |||
| } | |||
| static const unsigned int fmt_list[]={ | |||
| IMGFMT_YV12, | |||
| IMGFMT_I420, | |||
| IMGFMT_IYUV, | |||
| 0 | |||
| }; | |||
| static int vf_open(vf_instance_t *vf, char *args){ | |||
| vf->config=config; | |||
| vf->put_image=put_image; | |||
| vf->get_image=get_image; | |||
| vf->query_format=query_format; | |||
| vf->uninit=uninit; | |||
| mp_msg(MSGT_VFILTER, MSGL_V, "delogo: %d x %d, %d x %d, band = %d\n", | |||
| vf->priv->xoff, vf->priv->yoff, | |||
| vf->priv->lw, vf->priv->lh, | |||
| vf->priv->band); | |||
| vf->priv->show = 0; | |||
| if (vf->priv->band < 0) { | |||
| vf->priv->band = 4; | |||
| vf->priv->show = 1; | |||
| } | |||
| vf->priv->lw += vf->priv->band*2; | |||
| vf->priv->lh += vf->priv->band*2; | |||
| vf->priv->xoff -= vf->priv->band; | |||
| vf->priv->yoff -= vf->priv->band; | |||
| // check csp: | |||
| vf->priv->outfmt=vf_match_csp(&vf->next,fmt_list,IMGFMT_YV12); | |||
| if(!vf->priv->outfmt) | |||
| { | |||
| uninit(vf); | |||
| return 0; // no csp match :( | |||
| } | |||
| return 1; | |||
| } | |||
| #define ST_OFF(f) M_ST_OFF(struct vf_priv_s,f) | |||
| static const m_option_t vf_opts_fields[] = { | |||
| { "x", ST_OFF(xoff), CONF_TYPE_INT, 0, 0, 0, NULL }, | |||
| { "y", ST_OFF(yoff), CONF_TYPE_INT, 0, 0, 0, NULL }, | |||
| { "w", ST_OFF(lw), CONF_TYPE_INT, 0, 0, 0, NULL }, | |||
| { "h", ST_OFF(lh), CONF_TYPE_INT, 0, 0, 0, NULL }, | |||
| { "t", ST_OFF(band), CONF_TYPE_INT, 0, 0, 0, NULL }, | |||
| { "band", ST_OFF(band), CONF_TYPE_INT, 0, 0, 0, NULL }, // alias | |||
| { NULL, NULL, 0, 0, 0, 0, NULL } | |||
| }; | |||
| static const m_struct_t vf_opts = { | |||
| "delogo", | |||
| sizeof(struct vf_priv_s), | |||
| &vf_priv_dflt, | |||
| vf_opts_fields | |||
| }; | |||
| const vf_info_t vf_info_delogo = { | |||
| "simple logo remover", | |||
| "delogo", | |||
| "Jindrich Makovicka, Alex Beregszaszi", | |||
| "", | |||
| vf_open, | |||
| &vf_opts | |||
| }; | |||
| //===========================================================================// | |||
| @@ -0,0 +1,268 @@ | |||
| /* | |||
| * Copyright (C) 2003 Daniel Moreno <comac@comac.darktech.org> | |||
| * | |||
| * This file is part of MPlayer. | |||
| * | |||
| * MPlayer 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. | |||
| * | |||
| * MPlayer 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 MPlayer; if not, write to the Free Software Foundation, Inc., | |||
| * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | |||
| */ | |||
| #include <stdio.h> | |||
| #include <stdlib.h> | |||
| #include <string.h> | |||
| #include <inttypes.h> | |||
| #include <math.h> | |||
| #include "mp_msg.h" | |||
| #include "img_format.h" | |||
| #include "mp_image.h" | |||
| #include "vf.h" | |||
| #define PARAM1_DEFAULT 4.0 | |||
| #define PARAM2_DEFAULT 3.0 | |||
| #define PARAM3_DEFAULT 6.0 | |||
| //===========================================================================// | |||
| struct vf_priv_s { | |||
| int Coefs[4][512]; | |||
| unsigned char *Line; | |||
| mp_image_t *pmpi; | |||
| }; | |||
| /***************************************************************************/ | |||
| static int config(struct vf_instance *vf, | |||
| int width, int height, int d_width, int d_height, | |||
| unsigned int flags, unsigned int outfmt){ | |||
| free(vf->priv->Line); | |||
| vf->priv->Line = malloc(width); | |||
| vf->priv->pmpi=NULL; | |||
| // vf->default_caps &= !VFCAP_ACCEPT_STRIDE; | |||
| return vf_next_config(vf,width,height,d_width,d_height,flags,outfmt); | |||
| } | |||
| static void uninit(struct vf_instance *vf) | |||
| { | |||
| free(vf->priv->Line); | |||
| } | |||
| #define LowPass(Prev, Curr, Coef) (Curr + Coef[Prev - Curr]) | |||
| static void deNoise(unsigned char *Frame, // mpi->planes[x] | |||
| unsigned char *FramePrev, // pmpi->planes[x] | |||
| unsigned char *FrameDest, // dmpi->planes[x] | |||
| unsigned char *LineAnt, // vf->priv->Line (width bytes) | |||
| int W, int H, int sStride, int pStride, int dStride, | |||
| int *Horizontal, int *Vertical, int *Temporal) | |||
| { | |||
| int X, Y; | |||
| int sLineOffs = 0, pLineOffs = 0, dLineOffs = 0; | |||
| unsigned char PixelAnt; | |||
| /* First pixel has no left nor top neighbor. Only previous frame */ | |||
| LineAnt[0] = PixelAnt = Frame[0]; | |||
| FrameDest[0] = LowPass(FramePrev[0], LineAnt[0], Temporal); | |||
| /* Fist line has no top neighbor. Only left one for each pixel and | |||
| * last frame */ | |||
| for (X = 1; X < W; X++) | |||
| { | |||
| PixelAnt = LowPass(PixelAnt, Frame[X], Horizontal); | |||
| LineAnt[X] = PixelAnt; | |||
| FrameDest[X] = LowPass(FramePrev[X], LineAnt[X], Temporal); | |||
| } | |||
| for (Y = 1; Y < H; Y++) | |||
| { | |||
| sLineOffs += sStride, pLineOffs += pStride, dLineOffs += dStride; | |||
| /* First pixel on each line doesn't have previous pixel */ | |||
| PixelAnt = Frame[sLineOffs]; | |||
| LineAnt[0] = LowPass(LineAnt[0], PixelAnt, Vertical); | |||
| FrameDest[dLineOffs] = LowPass(FramePrev[pLineOffs], LineAnt[0], Temporal); | |||
| for (X = 1; X < W; X++) | |||
| { | |||
| /* The rest are normal */ | |||
| PixelAnt = LowPass(PixelAnt, Frame[sLineOffs+X], Horizontal); | |||
| LineAnt[X] = LowPass(LineAnt[X], PixelAnt, Vertical); | |||
| FrameDest[dLineOffs+X] = LowPass(FramePrev[pLineOffs+X], LineAnt[X], Temporal); | |||
| } | |||
| } | |||
| } | |||
| static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts){ | |||
| int cw= mpi->w >> mpi->chroma_x_shift; | |||
| int ch= mpi->h >> mpi->chroma_y_shift; | |||
| int W = mpi->w, H = mpi->h; | |||
| mp_image_t *dmpi=vf_get_image(vf->next,mpi->imgfmt, | |||
| MP_IMGTYPE_IP, MP_IMGFLAG_ACCEPT_STRIDE | | |||
| MP_IMGFLAG_PRESERVE | MP_IMGFLAG_READABLE, | |||
| mpi->w,mpi->h); | |||
| if(!dmpi) return 0; | |||
| if (!vf->priv->pmpi) vf->priv->pmpi=mpi; | |||
| deNoise(mpi->planes[0], vf->priv->pmpi->planes[0], dmpi->planes[0], | |||
| vf->priv->Line, W, H, | |||
| mpi->stride[0], vf->priv->pmpi->stride[0], dmpi->stride[0], | |||
| vf->priv->Coefs[0] + 256, | |||
| vf->priv->Coefs[0] + 256, | |||
| vf->priv->Coefs[1] + 256); | |||
| deNoise(mpi->planes[1], vf->priv->pmpi->planes[1], dmpi->planes[1], | |||
| vf->priv->Line, cw, ch, | |||
| mpi->stride[1], vf->priv->pmpi->stride[1], dmpi->stride[1], | |||
| vf->priv->Coefs[2] + 256, | |||
| vf->priv->Coefs[2] + 256, | |||
| vf->priv->Coefs[3] + 256); | |||
| deNoise(mpi->planes[2], vf->priv->pmpi->planes[2], dmpi->planes[2], | |||
| vf->priv->Line, cw, ch, | |||
| mpi->stride[2], vf->priv->pmpi->stride[2], dmpi->stride[2], | |||
| vf->priv->Coefs[2] + 256, | |||
| vf->priv->Coefs[2] + 256, | |||
| vf->priv->Coefs[3] + 256); | |||
| vf->priv->pmpi=dmpi; // save reference image | |||
| return vf_next_put_image(vf,dmpi, pts); | |||
| } | |||
| //===========================================================================// | |||
| static int query_format(struct vf_instance *vf, unsigned int fmt){ | |||
| switch(fmt) | |||
| { | |||
| case IMGFMT_YV12: | |||
| case IMGFMT_I420: | |||
| case IMGFMT_IYUV: | |||
| case IMGFMT_YVU9: | |||
| case IMGFMT_444P: | |||
| case IMGFMT_422P: | |||
| case IMGFMT_411P: | |||
| return vf_next_query_format(vf, fmt); | |||
| } | |||
| return 0; | |||
| } | |||
| #define ABS(A) ( (A) > 0 ? (A) : -(A) ) | |||
| static void PrecalcCoefs(int *Ct, double Dist25) | |||
| { | |||
| int i; | |||
| double Gamma, Simil, C; | |||
| Gamma = log(0.25) / log(1.0 - Dist25/255.0); | |||
| for (i = -256; i <= 255; i++) | |||
| { | |||
| Simil = 1.0 - ABS(i) / 255.0; | |||
| // Ct[256+i] = lround(pow(Simil, Gamma) * (double)i); | |||
| C = pow(Simil, Gamma) * (double)i; | |||
| Ct[256+i] = (C<0) ? (C-0.5) : (C+0.5); | |||
| } | |||
| } | |||
| static int vf_open(vf_instance_t *vf, char *args){ | |||
| double LumSpac, LumTmp, ChromSpac, ChromTmp; | |||
| double Param1, Param2, Param3; | |||
| vf->config=config; | |||
| vf->put_image=put_image; | |||
| vf->query_format=query_format; | |||
| vf->uninit=uninit; | |||
| vf->priv=malloc(sizeof(struct vf_priv_s)); | |||
| memset(vf->priv, 0, sizeof(struct vf_priv_s)); | |||
| if (args) | |||
| { | |||
| switch(sscanf(args, "%lf:%lf:%lf", | |||
| &Param1, &Param2, &Param3 | |||
| )) | |||
| { | |||
| case 0: | |||
| LumSpac = PARAM1_DEFAULT; | |||
| LumTmp = PARAM3_DEFAULT; | |||
| ChromSpac = PARAM2_DEFAULT; | |||
| ChromTmp = LumTmp * ChromSpac / LumSpac; | |||
| break; | |||
| case 1: | |||
| LumSpac = Param1; | |||
| LumTmp = PARAM3_DEFAULT * Param1 / PARAM1_DEFAULT; | |||
| ChromSpac = PARAM2_DEFAULT * Param1 / PARAM1_DEFAULT; | |||
| ChromTmp = LumTmp * ChromSpac / LumSpac; | |||
| break; | |||
| case 2: | |||
| LumSpac = Param1; | |||
| LumTmp = PARAM3_DEFAULT * Param1 / PARAM1_DEFAULT; | |||
| ChromSpac = Param2; | |||
| ChromTmp = LumTmp * ChromSpac / LumSpac; | |||
| break; | |||
| case 3: | |||
| LumSpac = Param1; | |||
| LumTmp = Param3; | |||
| ChromSpac = Param2; | |||
| ChromTmp = LumTmp * ChromSpac / LumSpac; | |||
| break; | |||
| default: | |||
| LumSpac = PARAM1_DEFAULT; | |||
| LumTmp = PARAM3_DEFAULT; | |||
| ChromSpac = PARAM2_DEFAULT; | |||
| ChromTmp = LumTmp * ChromSpac / LumSpac; | |||
| } | |||
| } | |||
| else | |||
| { | |||
| LumSpac = PARAM1_DEFAULT; | |||
| LumTmp = PARAM3_DEFAULT; | |||
| ChromSpac = PARAM2_DEFAULT; | |||
| ChromTmp = LumTmp * ChromSpac / LumSpac; | |||
| } | |||
| PrecalcCoefs(vf->priv->Coefs[0], LumSpac); | |||
| PrecalcCoefs(vf->priv->Coefs[1], LumTmp); | |||
| PrecalcCoefs(vf->priv->Coefs[2], ChromSpac); | |||
| PrecalcCoefs(vf->priv->Coefs[3], ChromTmp); | |||
| return 1; | |||
| } | |||
| const vf_info_t vf_info_denoise3d = { | |||
| "3D Denoiser (variable lowpass filter)", | |||
| "denoise3d", | |||
| "Daniel Moreno", | |||
| "", | |||
| vf_open, | |||
| NULL | |||
| }; | |||
| //===========================================================================// | |||
| @@ -0,0 +1,453 @@ | |||
| /* | |||
| * This file is part of MPlayer. | |||
| * | |||
| * MPlayer 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. | |||
| * | |||
| * MPlayer 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 MPlayer; if not, write to the Free Software Foundation, Inc., | |||
| * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | |||
| */ | |||
| #include <stdio.h> | |||
| #include <stdlib.h> | |||
| #include <string.h> | |||
| #include "config.h" | |||
| #include "mp_msg.h" | |||
| #include "img_format.h" | |||
| #include "mp_image.h" | |||
| #include "vf.h" | |||
| #include "libvo/fastmemcpy.h" | |||
| struct metrics { | |||
| int even; | |||
| int odd; | |||
| int noise; | |||
| int temp; | |||
| }; | |||
| struct vf_priv_s { | |||
| int frame; | |||
| int drop, lastdrop; | |||
| struct metrics pm; | |||
| int thres[5]; | |||
| int inframes, outframes; | |||
| int mode; | |||
| int (*analyze)(struct vf_priv_s *, mp_image_t *, mp_image_t *); | |||
| int needread; | |||
| }; | |||
| #define COMPE(a,b,e) (abs((a)-(b)) < (((a)+(b))>>(e))) | |||
| #define COMPARABLE(a,b) COMPE((a),(b),2) | |||
| #define VERYCLOSE(a,b) COMPE((a),(b),3) | |||
| #define OUTER_TC_NBHD(s) ( \ | |||
| COMPARABLE((s)[-1].m.even,(s)[-1].m.odd) && \ | |||
| COMPARABLE((s)[1].m.even,(s)[0].m.odd) && \ | |||
| COMPARABLE((s)[2].m.even,(s)[1].m.odd) && \ | |||
| COMPARABLE((s)[-1].m.noise,(s)[0].m.temp) && \ | |||
| COMPARABLE((s)[2].m.noise,(s)[2].m.temp) ) | |||
| #define INNER_TC_NBHD(s,l,h) ( \ | |||
| COMPARABLE((s)[0].m.even,(l)) && \ | |||
| COMPARABLE((s)[2].m.odd,(l)) && ( \ | |||
| COMPARABLE((s)[0].m.noise,(h)) || \ | |||
| COMPARABLE((s)[1].m.noise,(h)) ) ) | |||
| enum { | |||
| TC_DROP, | |||
| TC_PROG, | |||
| TC_IL1, | |||
| TC_IL2 | |||
| }; | |||
| static void block_diffs(struct metrics *m, unsigned char *old, unsigned char *new, int os, int ns) | |||
| { | |||
| int x, y, even=0, odd=0, noise, temp; | |||
| unsigned char *oldp, *newp; | |||
| m->noise = m->temp = 0; | |||
| for (x = 8; x; x--) { | |||
| oldp = old++; | |||
| newp = new++; | |||
| noise = temp = 0; | |||
| for (y = 4; y; y--) { | |||
| even += abs(newp[0]-oldp[0]); | |||
| odd += abs(newp[ns]-oldp[os]); | |||
| noise += newp[ns]-newp[0]; | |||
| temp += oldp[os]-newp[0]; | |||
| oldp += os<<1; | |||
| newp += ns<<1; | |||
| } | |||
| m->noise += abs(noise); | |||
| m->temp += abs(temp); | |||
| } | |||
| m->even = even; | |||
| m->odd = odd; | |||
| } | |||
| static void diff_planes(struct metrics *m, unsigned char *old, unsigned char *new, int w, int h, int os, int ns) | |||
| { | |||
| int x, y, me=0, mo=0, mn=0, mt=0; | |||
| struct metrics l; | |||
| for (y = 0; y < h-7; y += 8) { | |||
| for (x = 0; x < w-7; x += 8) { | |||
| block_diffs(&l, old+x+y*os, new+x+y*ns, os, ns); | |||
| if (l.even > me) me = l.even; | |||
| if (l.odd > mo) mo = l.odd; | |||
| if (l.noise > mn) mn = l.noise; | |||
| if (l.temp > mt) mt = l.temp; | |||
| } | |||
| } | |||
| m->even = me; | |||
| m->odd = mo; | |||
| m->noise = mn; | |||
| m->temp = mt; | |||
| } | |||
| static void diff_fields(struct metrics *metr, mp_image_t *old, mp_image_t *new) | |||
| { | |||
| struct metrics m, mu, mv; | |||
| diff_planes(&m, old->planes[0], new->planes[0], | |||
| new->w, new->h, old->stride[0], new->stride[0]); | |||
| if (new->flags & MP_IMGFLAG_PLANAR) { | |||
| diff_planes(&mu, old->planes[1], new->planes[1], | |||
| new->chroma_width, new->chroma_height, | |||
| old->stride[1], new->stride[1]); | |||
| diff_planes(&mv, old->planes[2], new->planes[2], | |||
| new->chroma_width, new->chroma_height, | |||
| old->stride[2], new->stride[2]); | |||
| if (mu.even > m.even) m.even = mu.even; | |||
| if (mu.odd > m.odd) m.odd = mu.odd; | |||
| if (mu.noise > m.noise) m.noise = mu.noise; | |||
| if (mu.temp > m.temp) m.temp = mu.temp; | |||
| if (mv.even > m.even) m.even = mv.even; | |||
| if (mv.odd > m.odd) m.odd = mv.odd; | |||
| if (mv.noise > m.noise) m.noise = mv.noise; | |||
| if (mv.temp > m.temp) m.temp = mv.temp; | |||
| } | |||
| *metr = m; | |||
| } | |||
| static void status(int f, struct metrics *m) | |||
| { | |||
| mp_msg(MSGT_VFILTER, MSGL_V, "frame %d: e=%d o=%d n=%d t=%d\n", | |||
| f, m->even, m->odd, m->noise, m->temp); | |||
| } | |||
| static int analyze_fixed_pattern(struct vf_priv_s *p, mp_image_t *new, mp_image_t *old) | |||
| { | |||
| if (p->frame >= 0) p->frame = (p->frame+1)%5; | |||
| mp_msg(MSGT_VFILTER, MSGL_V, "frame %d\n", p->frame); | |||
| switch (p->frame) { | |||
| case -1: case 0: case 1: case 2: | |||
| return TC_PROG; | |||
| case 3: | |||
| return TC_IL1; | |||
| case 4: | |||
| return TC_IL2; | |||
| } | |||
| return 0; | |||
| } | |||
| static int analyze_aggressive(struct vf_priv_s *p, mp_image_t *new, mp_image_t *old) | |||
| { | |||
| struct metrics m, pm; | |||
| if (p->frame >= 0) p->frame = (p->frame+1)%5; | |||
| diff_fields(&m, old, new); | |||
| status(p->frame, &m); | |||
| pm = p->pm; | |||
| p->pm = m; | |||
| if (p->frame == 4) { | |||
| /* We need to break at scene changes, but is this a valid test? */ | |||
| if ((m.even > p->thres[2]) && (m.odd > p->thres[2]) && (m.temp > p->thres[3]) | |||
| && (m.temp > 5*pm.temp) && (m.temp*2 > m.noise)) { | |||
| mp_msg(MSGT_VFILTER, MSGL_V, "scene change breaking telecine!\n"); | |||
| p->frame = -1; | |||
| return TC_DROP; | |||
| } | |||
| /* Thres. is to compensate for quantization errors when noise is low */ | |||
| if (m.noise - m.temp > -p->thres[4]) { | |||
| if (COMPARABLE(m.even, pm.odd)) { | |||
| //mp_msg(MSGT_VFILTER, MSGL_V, "confirmed field match!\n"); | |||
| return TC_IL2; | |||
| } else if ((m.even < p->thres[0]) && (m.odd < p->thres[0]) && VERYCLOSE(m.even, m.odd) | |||
| && VERYCLOSE(m.noise,m.temp) && VERYCLOSE(m.noise,pm.noise)) { | |||
| mp_msg(MSGT_VFILTER, MSGL_V, "interlaced frame appears in duplicate!!!\n"); | |||
| p->pm = pm; /* hack :) */ | |||
| p->frame = 3; | |||
| return TC_IL1; | |||
| } | |||
| } else { | |||
| mp_msg(MSGT_VFILTER, MSGL_V, "mismatched telecine fields!\n"); | |||
| p->frame = -1; | |||
| } | |||
| } | |||
| if (2*m.even*m.temp < m.odd*m.noise) { | |||
| mp_msg(MSGT_VFILTER, MSGL_V, "caught telecine sync!\n"); | |||
| p->frame = 3; | |||
| return TC_IL1; | |||
| } | |||
| if (p->frame < 3) { | |||
| if (m.noise > p->thres[3]) { | |||
| if (m.noise > 2*m.temp) { | |||
| mp_msg(MSGT_VFILTER, MSGL_V, "merging fields out of sequence!\n"); | |||
| return TC_IL2; | |||
| } | |||
| if ((m.noise > 2*pm.noise) && (m.even > p->thres[2]) && (m.odd > p->thres[2])) { | |||
| mp_msg(MSGT_VFILTER, MSGL_V, "dropping horrible interlaced frame!\n"); | |||
| return TC_DROP; | |||
| } | |||
| } | |||
| } | |||
| switch (p->frame) { | |||
| case -1: | |||
| if (4*m.noise > 5*m.temp) { | |||
| mp_msg(MSGT_VFILTER, MSGL_V, "merging fields out of sequence!\n"); | |||
| return TC_IL2; | |||
| } | |||
| case 0: | |||
| case 1: | |||
| case 2: | |||
| return TC_PROG; | |||
| case 3: | |||
| if ((m.even > p->thres[1]) && (m.even > m.odd) && (m.temp > m.noise)) { | |||
| mp_msg(MSGT_VFILTER, MSGL_V, "lost telecine tracking!\n"); | |||
| p->frame = -1; | |||
| return TC_PROG; | |||
| } | |||
| return TC_IL1; | |||
| case 4: | |||
| return TC_IL2; | |||
| } | |||
| return 0; | |||
| } | |||
| static void copy_image(mp_image_t *dmpi, mp_image_t *mpi, int field) | |||
| { | |||
| switch (field) { | |||
| case 0: | |||
| my_memcpy_pic(dmpi->planes[0], mpi->planes[0], mpi->w, mpi->h/2, | |||
| dmpi->stride[0]*2, mpi->stride[0]*2); | |||
| if (mpi->flags & MP_IMGFLAG_PLANAR) { | |||
| my_memcpy_pic(dmpi->planes[1], mpi->planes[1], | |||
| mpi->chroma_width, mpi->chroma_height/2, | |||
| dmpi->stride[1]*2, mpi->stride[1]*2); | |||
| my_memcpy_pic(dmpi->planes[2], mpi->planes[2], | |||
| mpi->chroma_width, mpi->chroma_height/2, | |||
| dmpi->stride[2]*2, mpi->stride[2]*2); | |||
| } | |||
| break; | |||
| case 1: | |||
| my_memcpy_pic(dmpi->planes[0]+dmpi->stride[0], | |||
| mpi->planes[0]+mpi->stride[0], mpi->w, mpi->h/2, | |||
| dmpi->stride[0]*2, mpi->stride[0]*2); | |||
| if (mpi->flags & MP_IMGFLAG_PLANAR) { | |||
| my_memcpy_pic(dmpi->planes[1]+dmpi->stride[1], | |||
| mpi->planes[1]+mpi->stride[1], | |||
| mpi->chroma_width, mpi->chroma_height/2, | |||
| dmpi->stride[1]*2, mpi->stride[1]*2); | |||
| my_memcpy_pic(dmpi->planes[2]+dmpi->stride[2], | |||
| mpi->planes[2]+mpi->stride[2], | |||
| mpi->chroma_width, mpi->chroma_height/2, | |||
| dmpi->stride[2]*2, mpi->stride[2]*2); | |||
| } | |||
| break; | |||
| case 2: | |||
| memcpy_pic(dmpi->planes[0], mpi->planes[0], mpi->w, mpi->h, | |||
| dmpi->stride[0], mpi->stride[0]); | |||
| if (mpi->flags & MP_IMGFLAG_PLANAR) { | |||
| memcpy_pic(dmpi->planes[1], mpi->planes[1], | |||
| mpi->chroma_width, mpi->chroma_height, | |||
| dmpi->stride[1], mpi->stride[1]); | |||
| memcpy_pic(dmpi->planes[2], mpi->planes[2], | |||
| mpi->chroma_width, mpi->chroma_height, | |||
| dmpi->stride[2], mpi->stride[2]); | |||
| } | |||
| break; | |||
| } | |||
| } | |||
| static int do_put_image(struct vf_instance *vf, mp_image_t *dmpi) | |||
| { | |||
| struct vf_priv_s *p = vf->priv; | |||
| int dropflag; | |||
| switch (p->drop) { | |||
| default: | |||
| dropflag = 0; | |||
| break; | |||
| case 1: | |||
| dropflag = (++p->lastdrop >= 5); | |||
| break; | |||
| case 2: | |||
| dropflag = (++p->lastdrop >= 5) && (4*p->inframes <= 5*p->outframes); | |||
| break; | |||
| } | |||
| if (dropflag) { | |||
| mp_msg(MSGT_VFILTER, MSGL_V, "drop! [%d/%d=%g]\n", | |||
| p->outframes, p->inframes, (float)p->outframes/p->inframes); | |||
| p->lastdrop = 0; | |||
| return 0; | |||
| } | |||
| p->outframes++; | |||
| return vf_next_put_image(vf, dmpi, MP_NOPTS_VALUE); | |||
| } | |||
| static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts) | |||
| { | |||
| int ret=0; | |||
| mp_image_t *dmpi; | |||
| struct vf_priv_s *p = vf->priv; | |||
| p->inframes++; | |||
| if (p->needread) dmpi = vf_get_image(vf->next, mpi->imgfmt, | |||
| MP_IMGTYPE_STATIC, MP_IMGFLAG_ACCEPT_STRIDE | | |||
| MP_IMGFLAG_PRESERVE | MP_IMGFLAG_READABLE, | |||
| mpi->width, mpi->height); | |||
| /* FIXME: is there a good way to get rid of static type? */ | |||
| else dmpi = vf_get_image(vf->next, mpi->imgfmt, | |||
| MP_IMGTYPE_STATIC, MP_IMGFLAG_ACCEPT_STRIDE | | |||
| MP_IMGFLAG_PRESERVE, mpi->width, mpi->height); | |||
| switch (p->analyze(p, mpi, dmpi)) { | |||
| case TC_DROP: | |||
| /* Don't copy anything unless we'll need to read it. */ | |||
| if (p->needread) copy_image(dmpi, mpi, 2); | |||
| p->lastdrop = 0; | |||
| break; | |||
| case TC_PROG: | |||
| /* Copy and display the whole frame. */ | |||
| copy_image(dmpi, mpi, 2); | |||
| ret = do_put_image(vf, dmpi); | |||
| break; | |||
| case TC_IL1: | |||
| /* Only copy bottom field unless we need to read. */ | |||
| if (p->needread) copy_image(dmpi, mpi, 2); | |||
| else copy_image(dmpi, mpi, 1); | |||
| p->lastdrop = 0; | |||
| break; | |||
| case TC_IL2: | |||
| /* Copy top field and show frame, then copy bottom if needed. */ | |||
| copy_image(dmpi, mpi, 0); | |||
| ret = do_put_image(vf, dmpi); | |||
| if (p->needread) copy_image(dmpi, mpi, 1); | |||
| break; | |||
| } | |||
| return ret; | |||
| } | |||
| static int query_format(struct vf_instance *vf, unsigned int fmt) | |||
| { | |||
| /* FIXME - figure out which other formats work */ | |||
| switch (fmt) { | |||
| case IMGFMT_YV12: | |||
| case IMGFMT_IYUV: | |||
| case IMGFMT_I420: | |||
| return vf_next_query_format(vf, fmt); | |||
| } | |||
| return 0; | |||
| } | |||
| static int config(struct vf_instance *vf, | |||
| int width, int height, int d_width, int d_height, | |||
| unsigned int flags, unsigned int outfmt) | |||
| { | |||
| return vf_next_config(vf,width,height,d_width,d_height,flags,outfmt); | |||
| } | |||
| static void uninit(struct vf_instance *vf) | |||
| { | |||
| free(vf->priv); | |||
| } | |||
| static struct { | |||
| char *name; | |||
| int (*func)(struct vf_priv_s *p, mp_image_t *new, mp_image_t *old); | |||
| int needread; | |||
| } anal_funcs[] = { | |||
| { "fixed", analyze_fixed_pattern, 0 }, | |||
| { "aggressive", analyze_aggressive, 1 }, | |||
| { NULL, NULL, 0 } | |||
| }; | |||
| #define STARTVARS if (0) | |||
| #define GETVAR(str, name, out, func) \ | |||
| else if (!strncmp((str), name "=", sizeof(name))) \ | |||
| (out) = (func)((str) + sizeof(name)) | |||
| static void parse_var(struct vf_priv_s *p, char *var) | |||
| { | |||
| STARTVARS; | |||
| GETVAR(var, "dr", p->drop, atoi); | |||
| GETVAR(var, "t0", p->thres[0], atoi); | |||
| GETVAR(var, "t1", p->thres[1], atoi); | |||
| GETVAR(var, "t2", p->thres[2], atoi); | |||
| GETVAR(var, "t3", p->thres[3], atoi); | |||
| GETVAR(var, "t4", p->thres[4], atoi); | |||
| GETVAR(var, "fr", p->frame, atoi); | |||
| GETVAR(var, "am", p->mode, atoi); | |||
| } | |||
| static void parse_args(struct vf_priv_s *p, char *args) | |||
| { | |||
| char *next, *orig; | |||
| for (args=orig=strdup(args); args; args=next) { | |||
| next = strchr(args, ':'); | |||
| if (next) *next++ = 0; | |||
| parse_var(p, args); | |||
| } | |||
| free(orig); | |||
| } | |||
| static int vf_open(vf_instance_t *vf, char *args) | |||
| { | |||
| struct vf_priv_s *p; | |||
| vf->config = config; | |||
| vf->put_image = put_image; | |||
| vf->query_format = query_format; | |||
| vf->uninit = uninit; | |||
| vf->default_reqs = VFCAP_ACCEPT_STRIDE; | |||
| vf->priv = p = calloc(1, sizeof(struct vf_priv_s)); | |||
| p->frame = -1; | |||
| p->thres[0] = 440; | |||
| p->thres[1] = 720; | |||
| p->thres[2] = 2500; | |||
| p->thres[3] = 2500; | |||
| p->thres[4] = 800; | |||
| p->drop = 0; | |||
| p->mode = 1; | |||
| if (args) parse_args(p, args); | |||
| p->analyze = anal_funcs[p->mode].func; | |||
| p->needread = anal_funcs[p->mode].needread; | |||
| return 1; | |||
| } | |||
| const vf_info_t vf_info_detc = { | |||
| "de-telecine filter", | |||
| "detc", | |||
| "Rich Felker", | |||
| "", | |||
| vf_open, | |||
| NULL | |||
| }; | |||
| @@ -0,0 +1,214 @@ | |||
| /* | |||
| * This file is part of MPlayer. | |||
| * | |||
| * MPlayer 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. | |||
| * | |||
| * MPlayer 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 MPlayer; if not, write to the Free Software Foundation, Inc., | |||
| * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | |||
| */ | |||
| #include <stdio.h> | |||
| #include <stdlib.h> | |||
| #include <string.h> | |||
| #include <inttypes.h> | |||
| #include "config.h" | |||
| #include "mp_msg.h" | |||
| #include "mp_image.h" | |||
| #include "img_format.h" | |||
| #include "vf.h" | |||
| struct vf_priv_s { | |||
| float sense; // first parameter | |||
| float level; // second parameter | |||
| unsigned int imgfmt; | |||
| char diff; | |||
| uint32_t max; | |||
| // int dfr; | |||
| // int rdfr; | |||
| int was_dint; | |||
| mp_image_t *pmpi; // previous mpi | |||
| }; | |||
| #define MAXROWSIZE 1200 | |||
| static int config (struct vf_instance *vf, | |||
| int width, int height, int d_width, int d_height, | |||
| unsigned int flags, unsigned int outfmt) | |||
| { | |||
| int rowsize; | |||
| vf->priv->pmpi = vf_get_image (vf->next, outfmt, MP_IMGTYPE_TEMP, | |||
| 0, width, height); | |||
| if (!(vf->priv->pmpi->flags & MP_IMGFLAG_PLANAR) && | |||
| outfmt != IMGFMT_RGB32 && outfmt != IMGFMT_BGR32 && | |||
| outfmt != IMGFMT_RGB24 && outfmt != IMGFMT_BGR24 && | |||
| outfmt != IMGFMT_RGB16 && outfmt != IMGFMT_BGR16) | |||
| { | |||
| mp_msg (MSGT_VFILTER, MSGL_WARN, "Drop-interlaced filter doesn't support this outfmt :(\n"); | |||
| return 0; | |||
| } | |||
| vf->priv->imgfmt = outfmt; | |||
| // recalculate internal values | |||
| rowsize = vf->priv->pmpi->width; | |||
| if (rowsize > MAXROWSIZE) rowsize = MAXROWSIZE; | |||
| vf->priv->max = vf->priv->level * vf->priv->pmpi->height * rowsize / 2; | |||
| if (vf->priv->pmpi->flags & MP_IMGFLAG_PLANAR) // planar YUV | |||
| vf->priv->diff = vf->priv->sense * 256; | |||
| else | |||
| vf->priv->diff = vf->priv->sense * (1 << (vf->priv->pmpi->bpp/3)); | |||
| if (vf->priv->diff < 0) vf->priv->diff = 0; | |||
| if (!(vf->priv->pmpi->flags & MP_IMGFLAG_PLANAR) && | |||
| vf->priv->pmpi->bpp < 24 && vf->priv->diff > 31) | |||
| vf->priv->diff = 31; | |||
| mp_msg (MSGT_VFILTER, MSGL_INFO, "Drop-interlaced: %dx%d diff %d / level %u\n", | |||
| vf->priv->pmpi->width, vf->priv->pmpi->height, | |||
| (int)vf->priv->diff, (unsigned int)vf->priv->max); | |||
| // vf->priv->rdfr = vf->priv->dfr = 0; | |||
| vf->priv->was_dint = 0; | |||
| return vf_next_config(vf,width,height,d_width,d_height,flags,outfmt); | |||
| } | |||
| static int put_image (struct vf_instance *vf, mp_image_t *mpi, double pts) | |||
| { | |||
| char rrow0[MAXROWSIZE]; | |||
| char rrow1[MAXROWSIZE]; | |||
| char rrow2[MAXROWSIZE]; | |||
| char *row0 = rrow0, *row1 = rrow1, *row2 = rrow2/*, *row3 = rrow3*/; | |||
| int rowsize = mpi->width; | |||
| uint32_t nok = 0, max = vf->priv->max; | |||
| int diff = vf->priv->diff; | |||
| int i, j; | |||
| register int n1, n2; | |||
| unsigned char *cur0, *prv0; | |||
| register unsigned char *cur, *prv; | |||
| if (rowsize > MAXROWSIZE) rowsize = MAXROWSIZE; | |||
| // check if nothing to do | |||
| if (mpi->imgfmt == vf->priv->imgfmt) | |||
| { | |||
| cur0 = mpi->planes[0] + mpi->stride[0]; | |||
| prv0 = mpi->planes[0]; | |||
| for (j = 1; j < mpi->height && nok <= max; j++) | |||
| { | |||
| cur = cur0; | |||
| prv = prv0; | |||
| // analyse row (row0) | |||
| if (mpi->flags & MP_IMGFLAG_PLANAR) // planar YUV - check luminance | |||
| for (i = 0; i < rowsize; i++) | |||
| { | |||
| if (cur[0] - prv[0] > diff) | |||
| row0[i] = 1; | |||
| else if (cur[0] - prv[0] < -diff) | |||
| row0[i] = -1; | |||
| else | |||
| row0[i] = 0; | |||
| cur++; | |||
| prv++; | |||
| // check if row0 is 1 but row1 is 0, and row2 is 1 or row2 is 0 | |||
| // but row3 is 1 so it's interlaced ptr (nok++) | |||
| if (j > 2 && row0[i] > 0 && (row1[i] < 0 || (!row1[i] && row2[i] < 0)) && | |||
| (++nok) > max) | |||
| break; | |||
| } | |||
| else if (mpi->bpp < 24) // RGB/BGR 16 - check all colors | |||
| for (i = 0; i < rowsize; i++) | |||
| { | |||
| n1 = cur[0] + (cur[1]<<8); | |||
| n2 = prv[0] + (prv[1]<<8); | |||
| if ((n1&0x1f) - (n2&0x1f) > diff || | |||
| ((n1>>5)&0x3f) - ((n2>>5)&0x3f) > diff || | |||
| ((n1>>11)&0x1f) - ((n2>>11)&0x1f) > diff) | |||
| row0[i] = 1; | |||
| else if ((n1&0x1f) - (n2&0x1f) < -diff || | |||
| ((n1>>5)&0x3f) - ((n2>>5)&0x3f) < -diff || | |||
| ((n1>>11)&0x1f) - ((n2>>11)&0x1f) < -diff) | |||
| row0[i] = -1; | |||
| else | |||
| row0[i] = 0; | |||
| cur += 2; | |||
| prv += 2; | |||
| // check if row0 is 1 but row1 is 0, and row2 is 1 or row2 is 0 | |||
| // but row3 is 1 so it's interlaced ptr (nok++) | |||
| if (j > 2 && row0[i] > 0 && (row1[i] < 0 || (!row1[i] && row2[i] < 0)) && | |||
| (++nok) > max) | |||
| break; | |||
| } | |||
| else // RGB/BGR 24/32 | |||
| for (i = 0; i < rowsize; i++) | |||
| { | |||
| if (cur[0] - prv[0] > diff || | |||
| cur[1] - prv[1] > diff || | |||
| cur[2] - prv[2] > diff) | |||
| row0[i] = 1; | |||
| else if (prv[0] - cur[0] > diff || | |||
| prv[1] - cur[1] > diff || | |||
| prv[2] - cur[2] > diff) | |||
| row0[i] = -1; | |||
| else | |||
| row0[i] = 0; | |||
| cur += mpi->bpp/8; | |||
| prv += mpi->bpp/8; | |||
| // check if row0 is 1 but row1 is 0, and row2 is 1 or row2 is 0 | |||
| // but row3 is 1 so it's interlaced ptr (nok++) | |||
| if (j > 2 && row0[i] > 0 && (row1[i] < 0 || (!row1[i] && row2[i] < 0)) && | |||
| (++nok) > max) | |||
| break; | |||
| } | |||
| cur0 += mpi->stride[0]; | |||
| prv0 += mpi->stride[0]; | |||
| // rotate rows | |||
| cur = row2; | |||
| row2 = row1; | |||
| row1 = row0; | |||
| row0 = cur; | |||
| } | |||
| } | |||
| // check if number of interlaced is above of max | |||
| if (nok > max) | |||
| { | |||
| // vf->priv->dfr++; | |||
| if (vf->priv->was_dint < 1) // can skip at most one frame! | |||
| { | |||
| vf->priv->was_dint++; | |||
| // vf->priv->rdfr++; | |||
| // mp_msg (MSGT_VFILTER, MSGL_INFO, "DI:%d/%d ", vf->priv->rdfr, vf->priv->dfr); | |||
| return 0; | |||
| } | |||
| } | |||
| vf->priv->was_dint = 0; | |||
| // mp_msg (MSGT_VFILTER, MSGL_INFO, "DI:%d/%d ", vf->priv->rdfr, vf->priv->dfr); | |||
| return vf_next_put_image (vf, mpi, pts); | |||
| } | |||
| static int vf_open(vf_instance_t *vf, char *args){ | |||
| vf->config = config; | |||
| vf->put_image = put_image; | |||
| // vf->default_reqs=VFCAP_ACCEPT_STRIDE; | |||
| vf->priv = malloc (sizeof(struct vf_priv_s)); | |||
| vf->priv->sense = 0.1; | |||
| vf->priv->level = 0.15; | |||
| vf->priv->pmpi = NULL; | |||
| if (args) | |||
| sscanf (args, "%f:%f", &vf->priv->sense, &vf->priv->level); | |||
| return 1; | |||
| } | |||
| const vf_info_t vf_info_dint = { | |||
| "drop interlaced frames", | |||
| "dint", | |||
| "A.G.", | |||
| "", | |||
| vf_open, | |||
| NULL | |||
| }; | |||
| @@ -0,0 +1,720 @@ | |||
| /* | |||
| * This file is part of MPlayer. | |||
| * | |||
| * MPlayer 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. | |||
| * | |||
| * MPlayer 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 MPlayer; if not, write to the Free Software Foundation, Inc., | |||
| * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | |||
| */ | |||
| #include <stdio.h> | |||
| #include <stdlib.h> | |||
| #include <string.h> | |||
| #include <limits.h> | |||
| #include <math.h> | |||
| #include "config.h" | |||
| #include "mp_msg.h" | |||
| #include "cpudetect.h" | |||
| #include "libavutil/common.h" | |||
| #include "mpbswap.h" | |||
| #include "img_format.h" | |||
| #include "mp_image.h" | |||
| #include "vf.h" | |||
| #include "libvo/fastmemcpy.h" | |||
| const vf_info_t vf_info_divtc; | |||
| struct vf_priv_s | |||
| { | |||
| int deghost, pass, phase, window, fcount, bcount, frameno, misscount, | |||
| ocount, sum[5]; | |||
| double threshold; | |||
| FILE *file; | |||
| char *bdata; | |||
| unsigned int *csdata; | |||
| int *history; | |||
| }; | |||
| /* | |||
| * diff_MMX and diff_C stolen from vf_decimate.c | |||
| */ | |||
| #if HAVE_MMX && HAVE_EBX_AVAILABLE | |||
| static int diff_MMX(unsigned char *old, unsigned char *new, int os, int ns) | |||
| { | |||
| volatile short out[4]; | |||
| __asm__ ( | |||
| "movl $8, %%ecx \n\t" | |||
| "pxor %%mm4, %%mm4 \n\t" | |||
| "pxor %%mm7, %%mm7 \n\t" | |||
| ASMALIGN(4) | |||
| "1: \n\t" | |||
| "movq (%%"REG_S"), %%mm0 \n\t" | |||
| "movq (%%"REG_S"), %%mm2 \n\t" | |||
| "add %%"REG_a", %%"REG_S" \n\t" | |||
| "movq (%%"REG_D"), %%mm1 \n\t" | |||
| "add %%"REG_b", %%"REG_D" \n\t" | |||
| "psubusb %%mm1, %%mm2 \n\t" | |||
| "psubusb %%mm0, %%mm1 \n\t" | |||
| "movq %%mm2, %%mm0 \n\t" | |||
| "movq %%mm1, %%mm3 \n\t" | |||
| "punpcklbw %%mm7, %%mm0 \n\t" | |||
| "punpcklbw %%mm7, %%mm1 \n\t" | |||
| "punpckhbw %%mm7, %%mm2 \n\t" | |||
| "punpckhbw %%mm7, %%mm3 \n\t" | |||
| "paddw %%mm0, %%mm4 \n\t" | |||
| "paddw %%mm1, %%mm4 \n\t" | |||
| "paddw %%mm2, %%mm4 \n\t" | |||
| "paddw %%mm3, %%mm4 \n\t" | |||
| "decl %%ecx \n\t" | |||
| "jnz 1b \n\t" | |||
| "movq %%mm4, (%%"REG_d") \n\t" | |||
| "emms \n\t" | |||
| : | |||
| : "S" (old), "D" (new), "a" ((long)os), "b" ((long)ns), "d" (out) | |||
| : "%ecx", "memory" | |||
| ); | |||
| return out[0]+out[1]+out[2]+out[3]; | |||
| } | |||
| #endif | |||
| static int diff_C(unsigned char *old, unsigned char *new, int os, int ns) | |||
| { | |||
| int x, y, d=0; | |||
| for(y=8; y; y--, new+=ns, old+=os) | |||
| for(x=8; x; x--) | |||
| d+=abs(new[x]-old[x]); | |||
| return d; | |||
| } | |||
| static int (*diff)(unsigned char *, unsigned char *, int, int); | |||
| static int diff_plane(unsigned char *old, unsigned char *new, | |||
| int w, int h, int os, int ns, int arg) | |||
| { | |||
| int x, y, d, max=0, sum=0, n=0; | |||
| for(y=0; y<h-7; y+=8) | |||
| { | |||
| for(x=0; x<w-7; x+=8) | |||
| { | |||
| d=diff(old+x+y*os, new+x+y*ns, os, ns); | |||
| if(d>max) max=d; | |||
| sum+=d; | |||
| n++; | |||
| } | |||
| } | |||
| return (sum+n*max)/2; | |||
| } | |||
| /* | |||
| static unsigned int checksum_plane(unsigned char *p, unsigned char *z, | |||
| int w, int h, int s, int zs, int arg) | |||
| { | |||
| unsigned int shift, sum; | |||
| unsigned char *e; | |||
| for(sum=0; h; h--, p+=s-w) | |||
| for(e=p+w, shift=32; p<e;) | |||
| sum^=(*p++)<<(shift=(shift-8)&31); | |||
| return sum; | |||
| } | |||
| */ | |||
| static unsigned int checksum_plane(unsigned char *p, unsigned char *z, | |||
| int w, int h, int s, int zs, int arg) | |||
| { | |||
| unsigned int shift; | |||
| uint32_t sum, t; | |||
| unsigned char *e, *e2; | |||
| #if HAVE_FAST_64BIT | |||
| typedef uint64_t wsum_t; | |||
| #else | |||
| typedef uint32_t wsum_t; | |||
| #endif | |||
| wsum_t wsum; | |||
| for(sum=0; h; h--, p+=s-w) | |||
| { | |||
| for(shift=0, e=p+w; (int)p&(sizeof(wsum_t)-1) && p<e;) | |||
| sum^=*p++<<(shift=(shift-8)&31); | |||
| for(wsum=0, e2=e-sizeof(wsum_t)+1; p<e2; p+=sizeof(wsum_t)) | |||
| wsum^=*(wsum_t *)p; | |||
| #if HAVE_FAST_64BIT | |||
| t=be2me_32((uint32_t)(wsum>>32^wsum)); | |||
| #else | |||
| t=be2me_32(wsum); | |||
| #endif | |||
| for(sum^=(t<<shift|t>>(32-shift)); p<e;) | |||
| sum^=*p++<<(shift=(shift-8)&31); | |||
| } | |||
| return sum; | |||
| } | |||
| static int deghost_plane(unsigned char *d, unsigned char *s, | |||
| int w, int h, int ds, int ss, int threshold) | |||
| { | |||
| int t; | |||
| unsigned char *e; | |||
| for(; h; h--, s+=ss-w, d+=ds-w) | |||
| for(e=d+w; d<e; d++, s++) | |||
| if(abs(*d-*s)>=threshold) | |||
| *d=(t=(*d<<1)-*s)<0?0:t>255?255:t; | |||
| return 0; | |||
| } | |||
| static int copyop(unsigned char *d, unsigned char *s, int bpl, int h, int dstride, int sstride, int dummy) { | |||
| memcpy_pic(d, s, bpl, h, dstride, sstride); | |||
| return 0; | |||
| } | |||
| static int imgop(int(*planeop)(unsigned char *, unsigned char *, | |||
| int, int, int, int, int), | |||
| mp_image_t *dst, mp_image_t *src, int arg) | |||
| { | |||
| if(dst->flags&MP_IMGFLAG_PLANAR) | |||
| return planeop(dst->planes[0], src?src->planes[0]:0, | |||
| dst->w, dst->h, | |||
| dst->stride[0], src?src->stride[0]:0, arg)+ | |||
| planeop(dst->planes[1], src?src->planes[1]:0, | |||
| dst->chroma_width, dst->chroma_height, | |||
| dst->stride[1], src?src->stride[1]:0, arg)+ | |||
| planeop(dst->planes[2], src?src->planes[2]:0, | |||
| dst->chroma_width, dst->chroma_height, | |||
| dst->stride[2], src?src->stride[2]:0, arg); | |||
| return planeop(dst->planes[0], src?src->planes[0]:0, | |||
| dst->w*(dst->bpp/8), dst->h, | |||
| dst->stride[0], src?src->stride[0]:0, arg); | |||
| } | |||
| /* | |||
| * Find the phase in which the telecine pattern fits best to the | |||
| * given 5 frame slice of frame difference measurements. | |||
| * | |||
| * If phase1 and phase2 are not negative, only the two specified | |||
| * phases are tested. | |||
| */ | |||
| static int match(struct vf_priv_s *p, int *diffs, | |||
| int phase1, int phase2, double *strength) | |||
| { | |||
| static const int pattern1[]={ -4, 1, 1, 1, 1 }, | |||
| pattern2[]={ -2, -3, 4, 4, -3 }, *pattern; | |||
| int f, m, n, t[5]; | |||
| pattern=p->deghost>0?pattern2:pattern1; | |||
| for(f=0; f<5; f++) | |||
| { | |||
| if(phase1<0 || phase2<0 || f==phase1 || f==phase2) | |||
| { | |||
| for(n=t[f]=0; n<5; n++) | |||
| t[f]+=diffs[n]*pattern[(n-f+5)%5]; | |||
| } | |||
| else | |||
| t[f]=INT_MIN; | |||
| } | |||
| /* find the best match */ | |||
| for(m=0, n=1; n<5; n++) | |||
| if(t[n]>t[m]) m=n; | |||
| if(strength) | |||
| { | |||
| /* the second best match */ | |||
| for(f=m?0:1, n=f+1; n<5; n++) | |||
| if(n!=m && t[n]>t[f]) f=n; | |||
| *strength=(t[m]>0?(double)(t[m]-t[f])/t[m]:0.0); | |||
| } | |||
| return m; | |||
| } | |||
| static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts) | |||
| { | |||
| mp_image_t *dmpi, *tmpi=0; | |||
| int n, m, f, newphase; | |||
| struct vf_priv_s *p=vf->priv; | |||
| unsigned int checksum; | |||
| double d; | |||
| dmpi=vf_get_image(vf->next, mpi->imgfmt, | |||
| MP_IMGTYPE_STATIC, MP_IMGFLAG_ACCEPT_STRIDE | | |||
| MP_IMGFLAG_PRESERVE | MP_IMGFLAG_READABLE, | |||
| mpi->width, mpi->height); | |||
| vf_clone_mpi_attributes(dmpi, mpi); | |||
| newphase=p->phase; | |||
| switch(p->pass) | |||
| { | |||
| case 1: | |||
| fprintf(p->file, "%08x %d\n", | |||
| (unsigned int)imgop((void *)checksum_plane, mpi, 0, 0), | |||
| p->frameno?imgop(diff_plane, dmpi, mpi, 0):0); | |||
| break; | |||
| case 2: | |||
| if(p->frameno/5>p->bcount) | |||
| { | |||
| mp_msg(MSGT_VFILTER, MSGL_ERR, | |||
| "\n%s: Log file ends prematurely! " | |||
| "Switching to one pass mode.\n", vf->info->name); | |||
| p->pass=0; | |||
| break; | |||
| } | |||
| checksum=(unsigned int)imgop((void *)checksum_plane, mpi, 0, 0); | |||
| if(checksum!=p->csdata[p->frameno]) | |||
| { | |||
| for(f=0; f<100; f++) | |||
| if(p->frameno+f<p->fcount && p->csdata[p->frameno+f]==checksum) | |||
| break; | |||
| else if(p->frameno-f>=0 && p->csdata[p->frameno-f]==checksum) | |||
| { | |||
| f=-f; | |||
| break; | |||
| } | |||
| if(f<100) | |||
| { | |||
| mp_msg(MSGT_VFILTER, MSGL_INFO, | |||
| "\n%s: Mismatch with pass-1: %+d frame(s).\n", | |||
| vf->info->name, f); | |||
| p->frameno+=f; | |||
| p->misscount=0; | |||
| } | |||
| else if(p->misscount++>=30) | |||
| { | |||
| mp_msg(MSGT_VFILTER, MSGL_ERR, | |||
| "\n%s: Sync with pass-1 lost! " | |||
| "Switching to one pass mode.\n", vf->info->name); | |||
| p->pass=0; | |||
| break; | |||
| } | |||
| } | |||
| n=(p->frameno)/5; | |||
| if(n>=p->bcount) n=p->bcount-1; | |||
| newphase=p->bdata[n]; | |||
| break; | |||
| default: | |||
| if(p->frameno) | |||
| { | |||
| int *sump=p->sum+p->frameno%5, | |||
| *histp=p->history+p->frameno%p->window; | |||
| *sump-=*histp; | |||
| *sump+=(*histp=imgop(diff_plane, dmpi, mpi, 0)); | |||
| } | |||
| m=match(p, p->sum, -1, -1, &d); | |||
| if(d>=p->threshold) | |||
| newphase=m; | |||
| } | |||
| n=p->ocount++%5; | |||
| if(newphase!=p->phase && ((p->phase+4)%5<n)==((newphase+4)%5<n)) | |||
| { | |||
| p->phase=newphase; | |||
| mp_msg(MSGT_VFILTER, MSGL_STATUS, | |||
| "\n%s: Telecine phase %d.\n", vf->info->name, p->phase); | |||
| } | |||
| switch((p->frameno++-p->phase+10)%5) | |||
| { | |||
| case 0: | |||
| imgop(copyop, dmpi, mpi, 0); | |||
| return 0; | |||
| case 4: | |||
| if(p->deghost>0) | |||
| { | |||
| tmpi=vf_get_image(vf->next, mpi->imgfmt, | |||
| MP_IMGTYPE_TEMP, MP_IMGFLAG_ACCEPT_STRIDE | | |||
| MP_IMGFLAG_READABLE, | |||
| mpi->width, mpi->height); | |||
| vf_clone_mpi_attributes(tmpi, mpi); | |||
| imgop(copyop, tmpi, mpi, 0); | |||
| imgop(deghost_plane, tmpi, dmpi, p->deghost); | |||
| imgop(copyop, dmpi, mpi, 0); | |||
| return vf_next_put_image(vf, tmpi, MP_NOPTS_VALUE); | |||
| } | |||
| } | |||
| imgop(copyop, dmpi, mpi, 0); | |||
| return vf_next_put_image(vf, dmpi, MP_NOPTS_VALUE); | |||
| } | |||
| static int analyze(struct vf_priv_s *p) | |||
| { | |||
| int *buf=0, *bp, bufsize=0, n, b, f, i, j, m, s; | |||
| unsigned int *cbuf=0, *cp; | |||
| char *pbuf; | |||
| char lbuf[256]; | |||
| int sum[5]; | |||
| double d; | |||
| /* read the file */ | |||
| n=15; | |||
| while(fgets(lbuf, 256, p->file)) | |||
| { | |||
| if(n>=bufsize-19) | |||
| { | |||
| bufsize=bufsize?bufsize*2:30000; | |||
| if((bp=realloc(buf, bufsize*sizeof *buf))) buf=bp; | |||
| if((cp=realloc(cbuf, bufsize*sizeof *cbuf))) cbuf=cp; | |||
| if(!bp || !cp) | |||
| { | |||
| mp_msg(MSGT_VFILTER, MSGL_FATAL, "%s: Not enough memory.\n", | |||
| vf_info_divtc.name); | |||
| free(buf); | |||
| free(cbuf); | |||
| return 0; | |||
| } | |||
| } | |||
| sscanf(lbuf, "%x %d", cbuf+n, buf+n); | |||
| n++; | |||
| } | |||
| if(!n) | |||
| { | |||
| mp_msg(MSGT_VFILTER, MSGL_FATAL, "%s: Empty 2-pass log file.\n", | |||
| vf_info_divtc.name); | |||
| free(buf); | |||
| free(cbuf); | |||
| return 0; | |||
| } | |||
| /* generate some dummy data past the beginning and end of the array */ | |||
| buf+=15, cbuf+=15; | |||
| n-=15; | |||
| memcpy(buf-15, buf, 15*sizeof *buf); | |||
| memset(cbuf-15, 0, 15*sizeof *cbuf); | |||
| while(n%5) | |||
| buf[n]=buf[n-5], cbuf[n]=0, n++; | |||
| memcpy(buf+n, buf+n-15, 15*sizeof *buf); | |||
| memset(cbuf+n, 0, 15*sizeof *cbuf); | |||
| p->csdata=cbuf; | |||
| p->fcount=n; | |||
| /* array with one slot for each slice of 5 frames */ | |||
| p->bdata=pbuf=malloc(p->bcount=b=(n/5)); | |||
| memset(pbuf, 255, b); | |||
| /* resolve the automatic mode */ | |||
| if(p->deghost<0) | |||
| { | |||
| int deghost=-p->deghost; | |||
| double s0=0.0, s1=0.0; | |||
| for(f=0; f<n; f+=5) | |||
| { | |||
| p->deghost=0; match(p, buf+f, -1, -1, &d); s0+=d; | |||
| p->deghost=1; match(p, buf+f, -1, -1, &d); s1+=d; | |||
| } | |||
| p->deghost=s1>s0?deghost:0; | |||
| mp_msg(MSGT_VFILTER, MSGL_INFO, | |||
| "%s: Deghosting %-3s (relative pattern strength %+.2fdB).\n", | |||
| vf_info_divtc.name, | |||
| p->deghost?"ON":"OFF", | |||
| 10.0*log10(s1/s0)); | |||
| } | |||
| /* analyze the data */ | |||
| for(f=0; f<5; f++) | |||
| for(sum[f]=0, n=-15; n<20; n+=5) | |||
| sum[f]+=buf[n+f]; | |||
| for(f=0; f<b; f++) | |||
| { | |||
| m=match(p, sum, -1, -1, &d); | |||
| if(d>=p->threshold) | |||
| pbuf[f]=m; | |||
| if(f<b-1) | |||
| for(n=0; n<5; n++) | |||
| sum[n]=sum[n]-buf[5*(f-3)+n]+buf[5*(f+4)+n]; | |||
| } | |||
| /* fill in the gaps */ | |||
| /* the beginning */ | |||
| for(f=0; f<b && pbuf[f]==-1; f++); | |||
| if(f==b) | |||
| { | |||
| free(buf-15); | |||
| mp_msg(MSGT_VFILTER, MSGL_FATAL, "%s: No telecine pattern found!\n", | |||
| vf_info_divtc.name); | |||
| return 0; | |||
| } | |||
| for(n=0; n<f; pbuf[n++]=pbuf[f]); | |||
| /* the end */ | |||
| for(f=b-1; pbuf[f]==-1; f--); | |||
| for(n=f+1; n<b; pbuf[n++]=pbuf[f]); | |||
| /* the rest */ | |||
| for(f=0;;) | |||
| { | |||
| while(f<b && pbuf[f]!=-1) f++; | |||
| if(f==b) break; | |||
| for(n=f; pbuf[n]==-1; n++); | |||
| if(pbuf[f-1]==pbuf[n]) | |||
| { | |||
| /* just a gap */ | |||
| while(f<n) pbuf[f++]=pbuf[n]; | |||
| } | |||
| else | |||
| { | |||
| /* phase change, reanalyze the original data in the gap with zero | |||
| threshold for only the two phases that appear at the ends */ | |||
| for(i=0; i<5; i++) | |||
| for(sum[i]=0, j=5*f-15; j<5*f; j+=5) | |||
| sum[i]+=buf[i+j]; | |||
| for(i=f; i<n; i++) | |||
| { | |||
| pbuf[i]=match(p, sum, pbuf[f-1], pbuf[n], 0); | |||
| for(j=0; j<5; j++) | |||
| sum[j]=sum[j]-buf[5*(i-3)+j]+buf[5*(i+4)+j]; | |||
| } | |||
| /* estimate the transition point by dividing the gap | |||
| in the same proportion as the number of matches of each kind */ | |||
| for(i=f, m=f; i<n; i++) | |||
| if(pbuf[i]==pbuf[f-1]) m++; | |||
| /* find the transition of the right direction nearest to the | |||
| estimated point */ | |||
| if(m>f && m<n) | |||
| { | |||
| for(j=m; j>f; j--) | |||
| if(pbuf[j-1]==pbuf[f-1] && pbuf[j]==pbuf[n]) break; | |||
| for(s=m; s<n; s++) | |||
| if(pbuf[s-1]==pbuf[f-1] && pbuf[s]==pbuf[n]) break; | |||
| m=(s-m<m-j)?s:j; | |||
| } | |||
| /* and rewrite the data to allow only this one transition */ | |||
| for(i=f; i<m; i++) | |||
| pbuf[i]=pbuf[f-1]; | |||
| for(; i<n; i++) | |||
| pbuf[i]=pbuf[n]; | |||
| f=n; | |||
| } | |||
| } | |||
| free(buf-15); | |||
| return 1; | |||
| } | |||
| static int query_format(struct vf_instance *vf, unsigned int fmt) | |||
| { | |||
| switch(fmt) | |||
| { | |||
| case IMGFMT_444P: case IMGFMT_IYUV: case IMGFMT_RGB24: | |||
| case IMGFMT_422P: case IMGFMT_UYVY: case IMGFMT_BGR24: | |||
| case IMGFMT_411P: case IMGFMT_YUY2: case IMGFMT_IF09: | |||
| case IMGFMT_YV12: case IMGFMT_I420: case IMGFMT_YVU9: | |||
| case IMGFMT_IUYV: case IMGFMT_Y800: case IMGFMT_Y8: | |||
| return vf_next_query_format(vf,fmt); | |||
| } | |||
| return 0; | |||
| } | |||
| static void uninit(struct vf_instance *vf) | |||
| { | |||
| if(vf->priv) | |||
| { | |||
| if(vf->priv->file) fclose(vf->priv->file); | |||
| if(vf->priv->csdata) free(vf->priv->csdata-15); | |||
| free(vf->priv->bdata); | |||
| free(vf->priv->history); | |||
| free(vf->priv); | |||
| } | |||
| } | |||
| static int vf_open(vf_instance_t *vf, char *args) | |||
| { | |||
| struct vf_priv_s *p; | |||
| char *filename="framediff.log", *ap, *q, *a; | |||
| if(args && !(args=strdup(args))) | |||
| { | |||
| nomem: | |||
| mp_msg(MSGT_VFILTER, MSGL_FATAL, | |||
| "%s: Not enough memory.\n", vf->info->name); | |||
| fail: | |||
| uninit(vf); | |||
| free(args); | |||
| return 0; | |||
| } | |||
| vf->put_image=put_image; | |||
| vf->uninit=uninit; | |||
| vf->query_format=query_format; | |||
| vf->default_reqs=VFCAP_ACCEPT_STRIDE; | |||
| if(!(vf->priv=p=calloc(1, sizeof(struct vf_priv_s)))) | |||
| goto nomem; | |||
| p->phase=5; | |||
| p->threshold=0.5; | |||
| p->window=30; | |||
| if((ap=args)) | |||
| while(*ap) | |||
| { | |||
| q=ap; | |||
| if((ap=strchr(q, ':'))) *ap++=0; else ap=q+strlen(q); | |||
| if((a=strchr(q, '='))) *a++=0; else a=q+strlen(q); | |||
| switch(*q) | |||
| { | |||
| case 0: break; | |||
| case 'f': filename=a; break; | |||
| case 't': p->threshold=atof(a); break; | |||
| case 'w': p->window=5*(atoi(a)+4)/5; break; | |||
| case 'd': p->deghost=atoi(a); break; | |||
| case 'p': | |||
| if(q[1]=='h') p->phase=atoi(a); | |||
| else p->pass=atoi(a); | |||
| break; | |||
| case 'h': | |||
| mp_msg(MSGT_VFILTER, MSGL_INFO, | |||
| "\n%s options:\n\n" | |||
| "pass=1|2 - Use 2-pass mode.\n" | |||
| "file=filename - Set the 2-pass log file name " | |||
| "(default %s).\n" | |||
| "threshold=value - Set the pattern recognition " | |||
| "sensitivity (default %g).\n" | |||
| "deghost=value - Select deghosting threshold " | |||
| "(default %d).\n" | |||
| "window=numframes - Set the statistics window " | |||
| "for 1-pass mode (default %d).\n" | |||
| "phase=0|1|2|3|4 - Set the initial phase " | |||
| "for 1-pass mode (default %d).\n\n" | |||
| "The option names can be abbreviated to the shortest " | |||
| "unique prefix.\n\n", | |||
| vf->info->name, filename, p->threshold, p->deghost, | |||
| p->window, p->phase%5); | |||
| break; | |||
| default: | |||
| mp_msg(MSGT_VFILTER, MSGL_FATAL, | |||
| "%s: Unknown argument %s.\n", vf->info->name, q); | |||
| goto fail; | |||
| } | |||
| } | |||
| switch(p->pass) | |||
| { | |||
| case 1: | |||
| if(!(p->file=fopen(filename, "w"))) | |||
| { | |||
| mp_msg(MSGT_VFILTER, MSGL_FATAL, | |||
| "%s: Can't create file %s.\n", vf->info->name, filename); | |||
| goto fail; | |||
| } | |||
| break; | |||
| case 2: | |||
| if(!(p->file=fopen(filename, "r"))) | |||
| { | |||
| mp_msg(MSGT_VFILTER, MSGL_FATAL, | |||
| "%s: Can't open file %s.\n", vf->info->name, filename); | |||
| goto fail; | |||
| } | |||
| if(!analyze(p)) | |||
| goto fail; | |||
| fclose(p->file); | |||
| p->file=0; | |||
| break; | |||
| } | |||
| if(p->window<5) p->window=5; | |||
| if(!(p->history=calloc(sizeof *p->history, p->window))) | |||
| goto nomem; | |||
| diff = diff_C; | |||
| #if HAVE_MMX && HAVE_EBX_AVAILABLE | |||
| if(gCpuCaps.hasMMX) diff = diff_MMX; | |||
| #endif | |||
| free(args); | |||
| return 1; | |||
| } | |||
| const vf_info_t vf_info_divtc = | |||
| { | |||
| "inverse telecine for deinterlaced video", | |||
| "divtc", | |||
| "Ville Saari", | |||
| "", | |||
| vf_open, | |||
| NULL | |||
| }; | |||
| @@ -0,0 +1,166 @@ | |||
| /* | |||
| * This file is part of MPlayer. | |||
| * | |||
| * MPlayer 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. | |||
| * | |||
| * MPlayer 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 MPlayer; if not, write to the Free Software Foundation, Inc., | |||
| * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | |||
| */ | |||
| #include <stdio.h> | |||
| #include <stdlib.h> | |||
| #include <string.h> | |||
| #include <inttypes.h> | |||
| #include "config.h" | |||
| #include "mp_msg.h" | |||
| #include "cpudetect.h" | |||
| #include "img_format.h" | |||
| #include "mp_image.h" | |||
| #include "vf.h" | |||
| #include "libvo/fastmemcpy.h" | |||
| struct vf_priv_s { | |||
| int skipline; | |||
| int scalew; | |||
| int scaleh; | |||
| }; | |||
| static void toright(unsigned char *dst[3], unsigned char *src[3], | |||
| int dststride[3], int srcstride[3], | |||
| int w, int h, struct vf_priv_s* p) | |||
| { | |||
| int k; | |||
| for (k = 0; k < 3; k++) { | |||
| unsigned char* fromL = src[k]; | |||
| unsigned char* fromR = src[k]; | |||
| unsigned char* to = dst[k]; | |||
| int src = srcstride[k]; | |||
| int dst = dststride[k]; | |||
| int ss; | |||
| unsigned int dd; | |||
| int i; | |||
| if (k > 0) { | |||
| i = h / 4 - p->skipline / 2; | |||
| ss = src * (h / 4 + p->skipline / 2); | |||
| dd = w / 4; | |||
| } else { | |||
| i = h / 2 - p->skipline; | |||
| ss = src * (h / 2 + p->skipline); | |||
| dd = w / 2; | |||
| } | |||
| fromR += ss; | |||
| for ( ; i > 0; i--) { | |||
| int j; | |||
| unsigned char* t = to; | |||
| unsigned char* sL = fromL; | |||
| unsigned char* sR = fromR; | |||
| if (p->scalew == 1) { | |||
| for (j = dd; j > 0; j--) { | |||
| *t++ = (sL[0] + sL[1]) / 2; | |||
| sL+=2; | |||
| } | |||
| for (j = dd ; j > 0; j--) { | |||
| *t++ = (sR[0] + sR[1]) / 2; | |||
| sR+=2; | |||
| } | |||
| } else { | |||
| for (j = dd * 2 ; j > 0; j--) | |||
| *t++ = *sL++; | |||
| for (j = dd * 2 ; j > 0; j--) | |||
| *t++ = *sR++; | |||
| } | |||
| if (p->scaleh == 1) { | |||
| fast_memcpy(to + dst, to, dst); | |||
| to += dst; | |||
| } | |||
| to += dst; | |||
| fromL += src; | |||
| fromR += src; | |||
| } | |||
| //printf("K %d %d %d %d %d \n", k, w, h, src, dst); | |||
| } | |||
| } | |||
| static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts) | |||
| { | |||
| mp_image_t *dmpi; | |||
| // hope we'll get DR buffer: | |||
| dmpi=vf_get_image(vf->next, IMGFMT_YV12, | |||
| MP_IMGTYPE_TEMP, MP_IMGFLAG_ACCEPT_STRIDE | | |||
| (vf->priv->scaleh == 1) ? MP_IMGFLAG_READABLE : 0, | |||
| mpi->w * vf->priv->scalew, | |||
| mpi->h / vf->priv->scaleh - vf->priv->skipline); | |||
| toright(dmpi->planes, mpi->planes, dmpi->stride, | |||
| mpi->stride, mpi->w, mpi->h, vf->priv); | |||
| return vf_next_put_image(vf,dmpi, pts); | |||
| } | |||
| static int config(struct vf_instance *vf, | |||
| int width, int height, int d_width, int d_height, | |||
| unsigned int flags, unsigned int outfmt) | |||
| { | |||
| /* FIXME - also support UYVY output? */ | |||
| return vf_next_config(vf, width * vf->priv->scalew, | |||
| height / vf->priv->scaleh - vf->priv->skipline, d_width, d_height, flags, IMGFMT_YV12); | |||
| } | |||
| static int query_format(struct vf_instance *vf, unsigned int fmt) | |||
| { | |||
| /* FIXME - really any YUV 4:2:0 input format should work */ | |||
| switch (fmt) { | |||
| case IMGFMT_YV12: | |||
| case IMGFMT_IYUV: | |||
| case IMGFMT_I420: | |||
| return vf_next_query_format(vf, IMGFMT_YV12); | |||
| } | |||
| return 0; | |||
| } | |||
| static void uninit(struct vf_instance *vf) | |||
| { | |||
| free(vf->priv); | |||
| } | |||
| static int vf_open(vf_instance_t *vf, char *args) | |||
| { | |||
| vf->config=config; | |||
| vf->query_format=query_format; | |||
| vf->put_image=put_image; | |||
| vf->uninit=uninit; | |||
| vf->priv = calloc(1, sizeof (struct vf_priv_s)); | |||
| vf->priv->skipline = 0; | |||
| vf->priv->scalew = 1; | |||
| vf->priv->scaleh = 2; | |||
| if (args) sscanf(args, "%d:%d:%d", &vf->priv->skipline, &vf->priv->scalew, &vf->priv->scaleh); | |||
| return 1; | |||
| } | |||
| const vf_info_t vf_info_down3dright = { | |||
| "convert stereo movie from top-bottom to left-right field", | |||
| "down3dright", | |||
| "Zdenek Kabelac", | |||
| "", | |||
| vf_open, | |||
| NULL | |||
| }; | |||
| @@ -0,0 +1,123 @@ | |||
| /* | |||
| * This file is part of MPlayer. | |||
| * | |||
| * MPlayer 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. | |||
| * | |||
| * MPlayer 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 MPlayer; if not, write to the Free Software Foundation, Inc., | |||
| * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | |||
| */ | |||
| #include <stdio.h> | |||
| #include <stdlib.h> | |||
| #include <string.h> | |||
| #include <inttypes.h> | |||
| #include "config.h" | |||
| #include "mp_msg.h" | |||
| #include "img_format.h" | |||
| #include "mp_image.h" | |||
| #include "vf.h" | |||
| struct vf_priv_s { | |||
| int w, h; | |||
| int method; // aspect method, 0 -> downscale, 1-> upscale. +2 -> original aspect. | |||
| int round; | |||
| float aspect; | |||
| }; | |||
| static int config(struct vf_instance *vf, | |||
| int width, int height, int d_width, int d_height, | |||
| unsigned int flags, unsigned int outfmt) | |||
| { | |||
| if (vf->priv->aspect < 0.001) { // did the user input aspect or w,h params | |||
| if (vf->priv->w == 0) vf->priv->w = d_width; | |||
| if (vf->priv->h == 0) vf->priv->h = d_height; | |||
| if (vf->priv->w == -1) vf->priv->w = width; | |||
| if (vf->priv->h == -1) vf->priv->h = height; | |||
| if (vf->priv->w == -2) vf->priv->w = vf->priv->h * (double)d_width / d_height; | |||
| if (vf->priv->w == -3) vf->priv->w = vf->priv->h * (double)width / height; | |||
| if (vf->priv->h == -2) vf->priv->h = vf->priv->w * (double)d_height / d_width; | |||
| if (vf->priv->h == -3) vf->priv->h = vf->priv->w * (double)height / width; | |||
| if (vf->priv->method > -1) { | |||
| double aspect = (vf->priv->method & 2) ? ((double)height / width) : ((double)d_height / d_width); | |||
| if ((vf->priv->h > vf->priv->w * aspect) ^ (vf->priv->method & 1)) { | |||
| vf->priv->h = vf->priv->w * aspect; | |||
| } else { | |||
| vf->priv->w = vf->priv->h / aspect; | |||
| } | |||
| } | |||
| if (vf->priv->round > 1) { // round up | |||
| vf->priv->w += (vf->priv->round - 1 - (vf->priv->w - 1) % vf->priv->round); | |||
| vf->priv->h += (vf->priv->round - 1 - (vf->priv->h - 1) % vf->priv->round); | |||
| } | |||
| d_width = vf->priv->w; | |||
| d_height = vf->priv->h; | |||
| } else { | |||
| if (vf->priv->aspect * height > width) { | |||
| d_width = height * vf->priv->aspect + .5; | |||
| d_height = height; | |||
| } else { | |||
| d_height = width / vf->priv->aspect + .5; | |||
| d_width = width; | |||
| } | |||
| } | |||
| return vf_next_config(vf, width, height, d_width, d_height, flags, outfmt); | |||
| } | |||
| static void uninit(vf_instance_t *vf) { | |||
| free(vf->priv); | |||
| vf->priv = NULL; | |||
| } | |||
| static int vf_open(vf_instance_t *vf, char *args) | |||
| { | |||
| vf->config = config; | |||
| vf->draw_slice = vf_next_draw_slice; | |||
| vf->uninit = uninit; | |||
| //vf->default_caps = 0; | |||
| vf->priv = calloc(sizeof(struct vf_priv_s), 1); | |||
| vf->priv->aspect = 0.; | |||
| vf->priv->w = -1; | |||
| vf->priv->h = -1; | |||
| vf->priv->method = -1; | |||
| vf->priv->round = 1; | |||
| if (args) { | |||
| if (strchr(args, '/')) { | |||
| int w, h; | |||
| sscanf(args, "%d/%d", &w, &h); | |||
| vf->priv->aspect = (float)w/h; | |||
| } else if (strchr(args, '.')) { | |||
| sscanf(args, "%f", &vf->priv->aspect); | |||
| } else { | |||
| sscanf(args, "%d:%d:%d:%d", &vf->priv->w, &vf->priv->h, &vf->priv->method, &vf->priv->round); | |||
| } | |||
| } | |||
| if ((vf->priv->aspect < 0.) || (vf->priv->w < -3) || (vf->priv->h < -3) || | |||
| ((vf->priv->w < -1) && (vf->priv->h < -1)) || | |||
| (vf->priv->method < -1) || (vf->priv->method > 3) || | |||
| (vf->priv->round < 0)) { | |||
| mp_msg(MSGT_VFILTER, MSGL_ERR, "[dsize] Illegal value(s): aspect: %f w: %d h: %d aspect_method: %d round: %d\n", vf->priv->aspect, vf->priv->w, vf->priv->h, vf->priv->method, vf->priv->round); | |||
| free(vf->priv); vf->priv = NULL; | |||
| return -1; | |||
| } | |||
| return 1; | |||
| } | |||
| const vf_info_t vf_info_dsize = { | |||
| "reset displaysize/aspect", | |||
| "dsize", | |||
| "Rich Felker", | |||
| "", | |||
| vf_open, | |||
| NULL | |||
| }; | |||
| @@ -0,0 +1,258 @@ | |||
| /* | |||
| * This file is part of MPlayer. | |||
| * | |||
| * MPlayer 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. | |||
| * | |||
| * MPlayer 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 MPlayer; if not, write to the Free Software Foundation, Inc., | |||
| * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | |||
| */ | |||
| #include <stdio.h> | |||
| #include <stdlib.h> | |||
| #include <string.h> | |||
| #include <inttypes.h> | |||
| #include "config.h" | |||
| #include "mp_msg.h" | |||
| #include "cpudetect.h" | |||
| #include "img_format.h" | |||
| #include "mp_image.h" | |||
| #include "vf.h" | |||
| #include "libvo/video_out.h" | |||
| #include "m_option.h" | |||
| #include "m_struct.h" | |||
| static struct vf_priv_s { | |||
| unsigned char *buf; | |||
| int brightness; | |||
| int contrast; | |||
| } const vf_priv_dflt = { | |||
| NULL, | |||
| 0, | |||
| 0 | |||
| }; | |||
| #if HAVE_MMX | |||
| static void process_MMX(unsigned char *dest, int dstride, unsigned char *src, int sstride, | |||
| int w, int h, int brightness, int contrast) | |||
| { | |||
| int i; | |||
| int pel; | |||
| int dstep = dstride-w; | |||
| int sstep = sstride-w; | |||
| short brvec[4]; | |||
| short contvec[4]; | |||
| contrast = ((contrast+100)*256*16)/100; | |||
| brightness = ((brightness+100)*511)/200-128 - contrast/32; | |||
| brvec[0] = brvec[1] = brvec[2] = brvec[3] = brightness; | |||
| contvec[0] = contvec[1] = contvec[2] = contvec[3] = contrast; | |||
| while (h--) { | |||
| __asm__ volatile ( | |||
| "movq (%5), %%mm3 \n\t" | |||
| "movq (%6), %%mm4 \n\t" | |||
| "pxor %%mm0, %%mm0 \n\t" | |||
| "movl %4, %%eax\n\t" | |||
| ASMALIGN(4) | |||
| "1: \n\t" | |||
| "movq (%0), %%mm1 \n\t" | |||
| "movq (%0), %%mm2 \n\t" | |||
| "punpcklbw %%mm0, %%mm1 \n\t" | |||
| "punpckhbw %%mm0, %%mm2 \n\t" | |||
| "psllw $4, %%mm1 \n\t" | |||
| "psllw $4, %%mm2 \n\t" | |||
| "pmulhw %%mm4, %%mm1 \n\t" | |||
| "pmulhw %%mm4, %%mm2 \n\t" | |||
| "paddw %%mm3, %%mm1 \n\t" | |||
| "paddw %%mm3, %%mm2 \n\t" | |||
| "packuswb %%mm2, %%mm1 \n\t" | |||
| "add $8, %0 \n\t" | |||
| "movq %%mm1, (%1) \n\t" | |||
| "add $8, %1 \n\t" | |||
| "decl %%eax \n\t" | |||
| "jnz 1b \n\t" | |||
| : "=r" (src), "=r" (dest) | |||
| : "0" (src), "1" (dest), "r" (w>>3), "r" (brvec), "r" (contvec) | |||
| : "%eax" | |||
| ); | |||
| for (i = w&7; i; i--) | |||
| { | |||
| pel = ((*src++* contrast)>>12) + brightness; | |||
| if(pel&768) pel = (-pel)>>31; | |||
| *dest++ = pel; | |||
| } | |||
| src += sstep; | |||
| dest += dstep; | |||
| } | |||
| __asm__ volatile ( "emms \n\t" ::: "memory" ); | |||
| } | |||
| #endif | |||
| static void process_C(unsigned char *dest, int dstride, unsigned char *src, int sstride, | |||
| int w, int h, int brightness, int contrast) | |||
| { | |||
| int i; | |||
| int pel; | |||
| int dstep = dstride-w; | |||
| int sstep = sstride-w; | |||
| contrast = ((contrast+100)*256*256)/100; | |||
| brightness = ((brightness+100)*511)/200-128 - contrast/512; | |||
| while (h--) { | |||
| for (i = w; i; i--) | |||
| { | |||
| pel = ((*src++* contrast)>>16) + brightness; | |||
| if(pel&768) pel = (-pel)>>31; | |||
| *dest++ = pel; | |||
| } | |||
| src += sstep; | |||
| dest += dstep; | |||
| } | |||
| } | |||
| static void (*process)(unsigned char *dest, int dstride, unsigned char *src, int sstride, | |||
| int w, int h, int brightness, int contrast); | |||
| /* FIXME: add packed yuv version of process */ | |||
| static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts) | |||
| { | |||
| mp_image_t *dmpi; | |||
| dmpi=vf_get_image(vf->next, mpi->imgfmt, | |||
| MP_IMGTYPE_EXPORT, 0, | |||
| mpi->w, mpi->h); | |||
| dmpi->stride[0] = mpi->stride[0]; | |||
| dmpi->planes[1] = mpi->planes[1]; | |||
| dmpi->planes[2] = mpi->planes[2]; | |||
| dmpi->stride[1] = mpi->stride[1]; | |||
| dmpi->stride[2] = mpi->stride[2]; | |||
| if (!vf->priv->buf) vf->priv->buf = malloc(mpi->stride[0]*mpi->h); | |||
| if ((vf->priv->brightness == 0) && (vf->priv->contrast == 0)) | |||
| dmpi->planes[0] = mpi->planes[0]; | |||
| else { | |||
| dmpi->planes[0] = vf->priv->buf; | |||
| process(dmpi->planes[0], dmpi->stride[0], | |||
| mpi->planes[0], mpi->stride[0], | |||
| mpi->w, mpi->h, vf->priv->brightness, | |||
| vf->priv->contrast); | |||
| } | |||
| return vf_next_put_image(vf,dmpi, pts); | |||
| } | |||
| static int control(struct vf_instance *vf, int request, void* data) | |||
| { | |||
| vf_equalizer_t *eq; | |||
| switch (request) { | |||
| case VFCTRL_SET_EQUALIZER: | |||
| eq = data; | |||
| if (!strcmp(eq->item,"brightness")) { | |||
| vf->priv->brightness = eq->value; | |||
| return CONTROL_TRUE; | |||
| } | |||
| else if (!strcmp(eq->item,"contrast")) { | |||
| vf->priv->contrast = eq->value; | |||
| return CONTROL_TRUE; | |||
| } | |||
| break; | |||
| case VFCTRL_GET_EQUALIZER: | |||
| eq = data; | |||
| if (!strcmp(eq->item,"brightness")) { | |||
| eq->value = vf->priv->brightness; | |||
| return CONTROL_TRUE; | |||
| } | |||
| else if (!strcmp(eq->item,"contrast")) { | |||
| eq->value = vf->priv->contrast; | |||
| return CONTROL_TRUE; | |||
| } | |||
| break; | |||
| } | |||
| return vf_next_control(vf, request, data); | |||
| } | |||
| static int query_format(struct vf_instance *vf, unsigned int fmt) | |||
| { | |||
| switch (fmt) { | |||
| case IMGFMT_YVU9: | |||
| case IMGFMT_IF09: | |||
| case IMGFMT_YV12: | |||
| case IMGFMT_I420: | |||
| case IMGFMT_IYUV: | |||
| case IMGFMT_CLPL: | |||
| case IMGFMT_Y800: | |||
| case IMGFMT_Y8: | |||
| case IMGFMT_NV12: | |||
| case IMGFMT_NV21: | |||
| case IMGFMT_444P: | |||
| case IMGFMT_422P: | |||
| case IMGFMT_411P: | |||
| return vf_next_query_format(vf, fmt); | |||
| } | |||
| return 0; | |||
| } | |||
| static void uninit(struct vf_instance *vf) | |||
| { | |||
| free(vf->priv->buf); | |||
| free(vf->priv); | |||
| } | |||
| static int vf_open(vf_instance_t *vf, char *args) | |||
| { | |||
| vf->control=control; | |||
| vf->query_format=query_format; | |||
| vf->put_image=put_image; | |||
| vf->uninit=uninit; | |||
| process = process_C; | |||
| #if HAVE_MMX | |||
| if(gCpuCaps.hasMMX) process = process_MMX; | |||
| #endif | |||
| return 1; | |||
| } | |||
| #define ST_OFF(f) M_ST_OFF(struct vf_priv_s,f) | |||
| static const m_option_t vf_opts_fields[] = { | |||
| {"brightness", ST_OFF(brightness), CONF_TYPE_INT, M_OPT_RANGE,-100 ,100, NULL}, | |||
| {"contrast", ST_OFF(contrast), CONF_TYPE_INT, M_OPT_RANGE,-100 ,100, NULL}, | |||
| { NULL, NULL, 0, 0, 0, 0, NULL } | |||
| }; | |||
| static const m_struct_t vf_opts = { | |||
| "eq", | |||
| sizeof(struct vf_priv_s), | |||
| &vf_priv_dflt, | |||
| vf_opts_fields | |||
| }; | |||
| const vf_info_t vf_info_eq = { | |||
| "soft video equalizer", | |||
| "eq", | |||
| "Richard Felker", | |||
| "", | |||
| vf_open, | |||
| &vf_opts | |||
| }; | |||
| @@ -0,0 +1,519 @@ | |||
| /* | |||
| * Software equalizer (brightness, contrast, gamma, saturation) | |||
| * | |||
| * Hampa Hug <hampa@hampa.ch> (original LUT gamma/contrast/brightness filter) | |||
| * Daniel Moreno <comac@comac.darktech.org> (saturation, R/G/B gamma support) | |||
| * Richard Felker (original MMX contrast/brightness code (vf_eq.c)) | |||
| * Michael Niedermayer <michalni@gmx.at> (LUT16) | |||
| * | |||
| * This file is part of MPlayer. | |||
| * | |||
| * MPlayer 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. | |||
| * | |||
| * MPlayer 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 MPlayer; if not, write to the Free Software Foundation, Inc., | |||
| * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | |||
| */ | |||
| #include <stdio.h> | |||
| #include <stdlib.h> | |||
| #include <string.h> | |||
| #include <math.h> | |||
| #include <inttypes.h> | |||
| #include "config.h" | |||
| #include "mp_msg.h" | |||
| #include "cpudetect.h" | |||
| #include "img_format.h" | |||
| #include "mp_image.h" | |||
| #include "vf.h" | |||
| #define LUT16 | |||
| /* Per channel parameters */ | |||
| typedef struct eq2_param_t { | |||
| unsigned char lut[256]; | |||
| #ifdef LUT16 | |||
| uint16_t lut16[256*256]; | |||
| #endif | |||
| int lut_clean; | |||
| void (*adjust) (struct eq2_param_t *par, unsigned char *dst, unsigned char *src, | |||
| unsigned w, unsigned h, unsigned dstride, unsigned sstride); | |||
| double c; | |||
| double b; | |||
| double g; | |||
| double w; | |||
| } eq2_param_t; | |||
| typedef struct vf_priv_s { | |||
| eq2_param_t param[3]; | |||
| double contrast; | |||
| double brightness; | |||
| double saturation; | |||
| double gamma; | |||
| double gamma_weight; | |||
| double rgamma; | |||
| double ggamma; | |||
| double bgamma; | |||
| unsigned buf_w[3]; | |||
| unsigned buf_h[3]; | |||
| unsigned char *buf[3]; | |||
| } vf_eq2_t; | |||
| static | |||
| void create_lut (eq2_param_t *par) | |||
| { | |||
| unsigned i; | |||
| double g, v; | |||
| double lw, gw; | |||
| g = par->g; | |||
| gw = par->w; | |||
| lw = 1.0 - gw; | |||
| if ((g < 0.001) || (g > 1000.0)) { | |||
| g = 1.0; | |||
| } | |||
| g = 1.0 / g; | |||
| for (i = 0; i < 256; i++) { | |||
| v = (double) i / 255.0; | |||
| v = par->c * (v - 0.5) + 0.5 + par->b; | |||
| if (v <= 0.0) { | |||
| par->lut[i] = 0; | |||
| } | |||
| else { | |||
| v = v*lw + pow(v, g)*gw; | |||
| if (v >= 1.0) { | |||
| par->lut[i] = 255; | |||
| } | |||
| else { | |||
| par->lut[i] = (unsigned char) (256.0 * v); | |||
| } | |||
| } | |||
| } | |||
| #ifdef LUT16 | |||
| for(i=0; i<256*256; i++){ | |||
| par->lut16[i]= par->lut[i&0xFF] + (par->lut[i>>8]<<8); | |||
| } | |||
| #endif | |||
| par->lut_clean = 1; | |||
| } | |||
| #if HAVE_MMX | |||
| static | |||
| void affine_1d_MMX (eq2_param_t *par, unsigned char *dst, unsigned char *src, | |||
| unsigned w, unsigned h, unsigned dstride, unsigned sstride) | |||
| { | |||
| unsigned i; | |||
| int contrast, brightness; | |||
| unsigned dstep, sstep; | |||
| int pel; | |||
| short brvec[4]; | |||
| short contvec[4]; | |||
| // printf("\nmmx: src=%p dst=%p w=%d h=%d ds=%d ss=%d\n",src,dst,w,h,dstride,sstride); | |||
| contrast = (int) (par->c * 256 * 16); | |||
| brightness = ((int) (100.0 * par->b + 100.0) * 511) / 200 - 128 - contrast / 32; | |||
| brvec[0] = brvec[1] = brvec[2] = brvec[3] = brightness; | |||
| contvec[0] = contvec[1] = contvec[2] = contvec[3] = contrast; | |||
| sstep = sstride - w; | |||
| dstep = dstride - w; | |||
| while (h-- > 0) { | |||
| __asm__ volatile ( | |||
| "movq (%5), %%mm3 \n\t" | |||
| "movq (%6), %%mm4 \n\t" | |||
| "pxor %%mm0, %%mm0 \n\t" | |||
| "movl %4, %%eax\n\t" | |||
| ASMALIGN(4) | |||
| "1: \n\t" | |||
| "movq (%0), %%mm1 \n\t" | |||
| "movq (%0), %%mm2 \n\t" | |||
| "punpcklbw %%mm0, %%mm1 \n\t" | |||
| "punpckhbw %%mm0, %%mm2 \n\t" | |||
| "psllw $4, %%mm1 \n\t" | |||
| "psllw $4, %%mm2 \n\t" | |||
| "pmulhw %%mm4, %%mm1 \n\t" | |||
| "pmulhw %%mm4, %%mm2 \n\t" | |||
| "paddw %%mm3, %%mm1 \n\t" | |||
| "paddw %%mm3, %%mm2 \n\t" | |||
| "packuswb %%mm2, %%mm1 \n\t" | |||
| "add $8, %0 \n\t" | |||
| "movq %%mm1, (%1) \n\t" | |||
| "add $8, %1 \n\t" | |||
| "decl %%eax \n\t" | |||
| "jnz 1b \n\t" | |||
| : "=r" (src), "=r" (dst) | |||
| : "0" (src), "1" (dst), "r" (w >> 3), "r" (brvec), "r" (contvec) | |||
| : "%eax" | |||
| ); | |||
| for (i = w & 7; i > 0; i--) { | |||
| pel = ((*src++ * contrast) >> 12) + brightness; | |||
| if (pel & 768) { | |||
| pel = (-pel) >> 31; | |||
| } | |||
| *dst++ = pel; | |||
| } | |||
| src += sstep; | |||
| dst += dstep; | |||
| } | |||
| __asm__ volatile ( "emms \n\t" ::: "memory" ); | |||
| } | |||
| #endif | |||
| static | |||
| void apply_lut (eq2_param_t *par, unsigned char *dst, unsigned char *src, | |||
| unsigned w, unsigned h, unsigned dstride, unsigned sstride) | |||
| { | |||
| unsigned i, j, w2; | |||
| unsigned char *lut; | |||
| uint16_t *lut16; | |||
| if (!par->lut_clean) { | |||
| create_lut (par); | |||
| } | |||
| lut = par->lut; | |||
| #ifdef LUT16 | |||
| lut16 = par->lut16; | |||
| w2= (w>>3)<<2; | |||
| for (j = 0; j < h; j++) { | |||
| uint16_t *src16= (uint16_t*)src; | |||
| uint16_t *dst16= (uint16_t*)dst; | |||
| for (i = 0; i < w2; i+=4) { | |||
| dst16[i+0] = lut16[src16[i+0]]; | |||
| dst16[i+1] = lut16[src16[i+1]]; | |||
| dst16[i+2] = lut16[src16[i+2]]; | |||
| dst16[i+3] = lut16[src16[i+3]]; | |||
| } | |||
| i <<= 1; | |||
| #else | |||
| w2= (w>>3)<<3; | |||
| for (j = 0; j < h; j++) { | |||
| for (i = 0; i < w2; i+=8) { | |||
| dst[i+0] = lut[src[i+0]]; | |||
| dst[i+1] = lut[src[i+1]]; | |||
| dst[i+2] = lut[src[i+2]]; | |||
| dst[i+3] = lut[src[i+3]]; | |||
| dst[i+4] = lut[src[i+4]]; | |||
| dst[i+5] = lut[src[i+5]]; | |||
| dst[i+6] = lut[src[i+6]]; | |||
| dst[i+7] = lut[src[i+7]]; | |||
| } | |||
| #endif | |||
| for (; i < w; i++) { | |||
| dst[i] = lut[src[i]]; | |||
| } | |||
| src += sstride; | |||
| dst += dstride; | |||
| } | |||
| } | |||
| static | |||
| int put_image (vf_instance_t *vf, mp_image_t *src, double pts) | |||
| { | |||
| unsigned i; | |||
| vf_eq2_t *eq2; | |||
| mp_image_t *dst; | |||
| unsigned long img_n,img_c; | |||
| eq2 = vf->priv; | |||
| if ((eq2->buf_w[0] != src->w) || (eq2->buf_h[0] != src->h)) { | |||
| eq2->buf_w[0] = src->w; | |||
| eq2->buf_h[0] = src->h; | |||
| eq2->buf_w[1] = eq2->buf_w[2] = src->w >> src->chroma_x_shift; | |||
| eq2->buf_h[1] = eq2->buf_h[2] = src->h >> src->chroma_y_shift; | |||
| img_n = eq2->buf_w[0]*eq2->buf_h[0]; | |||
| if(src->num_planes>1){ | |||
| img_c = eq2->buf_w[1]*eq2->buf_h[1]; | |||
| eq2->buf[0] = realloc (eq2->buf[0], img_n + 2*img_c); | |||
| eq2->buf[1] = eq2->buf[0] + img_n; | |||
| eq2->buf[2] = eq2->buf[1] + img_c; | |||
| } else | |||
| eq2->buf[0] = realloc (eq2->buf[0], img_n); | |||
| } | |||
| dst = vf_get_image (vf->next, src->imgfmt, MP_IMGTYPE_EXPORT, 0, src->w, src->h); | |||
| for (i = 0; i < ((src->num_planes>1)?3:1); i++) { | |||
| if (eq2->param[i].adjust != NULL) { | |||
| dst->planes[i] = eq2->buf[i]; | |||
| dst->stride[i] = eq2->buf_w[i]; | |||
| eq2->param[i].adjust (&eq2->param[i], dst->planes[i], src->planes[i], | |||
| eq2->buf_w[i], eq2->buf_h[i], dst->stride[i], src->stride[i]); | |||
| } | |||
| else { | |||
| dst->planes[i] = src->planes[i]; | |||
| dst->stride[i] = src->stride[i]; | |||
| } | |||
| } | |||
| return vf_next_put_image (vf, dst, pts); | |||
| } | |||
| static | |||
| void check_values (eq2_param_t *par) | |||
| { | |||
| /* yuck! floating point comparisons... */ | |||
| if ((par->c == 1.0) && (par->b == 0.0) && (par->g == 1.0)) { | |||
| par->adjust = NULL; | |||
| } | |||
| #if HAVE_MMX | |||
| else if (par->g == 1.0 && gCpuCaps.hasMMX) { | |||
| par->adjust = &affine_1d_MMX; | |||
| } | |||
| #endif | |||
| else { | |||
| par->adjust = &apply_lut; | |||
| } | |||
| } | |||
| static | |||
| void print_values (vf_eq2_t *eq2) | |||
| { | |||
| mp_msg (MSGT_VFILTER, MSGL_V, "vf_eq2: c=%.2f b=%.2f g=%.4f s=%.2f \n", | |||
| eq2->contrast, eq2->brightness, eq2->gamma, eq2->saturation | |||
| ); | |||
| } | |||
| static | |||
| void set_contrast (vf_eq2_t *eq2, double c) | |||
| { | |||
| eq2->contrast = c; | |||
| eq2->param[0].c = c; | |||
| eq2->param[0].lut_clean = 0; | |||
| check_values (&eq2->param[0]); | |||
| print_values (eq2); | |||
| } | |||
| static | |||
| void set_brightness (vf_eq2_t *eq2, double b) | |||
| { | |||
| eq2->brightness = b; | |||
| eq2->param[0].b = b; | |||
| eq2->param[0].lut_clean = 0; | |||
| check_values (&eq2->param[0]); | |||
| print_values (eq2); | |||
| } | |||
| static | |||
| void set_gamma (vf_eq2_t *eq2, double g) | |||
| { | |||
| eq2->gamma = g; | |||
| eq2->param[0].g = eq2->gamma * eq2->ggamma; | |||
| eq2->param[1].g = sqrt (eq2->bgamma / eq2->ggamma); | |||
| eq2->param[2].g = sqrt (eq2->rgamma / eq2->ggamma); | |||
| eq2->param[0].w = eq2->param[1].w = eq2->param[2].w = eq2->gamma_weight; | |||
| eq2->param[0].lut_clean = 0; | |||
| eq2->param[1].lut_clean = 0; | |||
| eq2->param[2].lut_clean = 0; | |||
| check_values (&eq2->param[0]); | |||
| check_values (&eq2->param[1]); | |||
| check_values (&eq2->param[2]); | |||
| print_values (eq2); | |||
| } | |||
| static | |||
| void set_saturation (vf_eq2_t *eq2, double s) | |||
| { | |||
| eq2->saturation = s; | |||
| eq2->param[1].c = s; | |||
| eq2->param[2].c = s; | |||
| eq2->param[1].lut_clean = 0; | |||
| eq2->param[2].lut_clean = 0; | |||
| check_values (&eq2->param[1]); | |||
| check_values (&eq2->param[2]); | |||
| print_values (eq2); | |||
| } | |||
| static | |||
| int control (vf_instance_t *vf, int request, void *data) | |||
| { | |||
| vf_equalizer_t *eq; | |||
| switch (request) { | |||
| case VFCTRL_SET_EQUALIZER: | |||
| eq = (vf_equalizer_t *) data; | |||
| if (strcmp (eq->item, "gamma") == 0) { | |||
| set_gamma (vf->priv, exp (log (8.0) * eq->value / 100.0)); | |||
| return CONTROL_TRUE; | |||
| } | |||
| else if (strcmp (eq->item, "contrast") == 0) { | |||
| set_contrast (vf->priv, (1.0 / 100.0) * (eq->value + 100)); | |||
| return CONTROL_TRUE; | |||
| } | |||
| else if (strcmp (eq->item, "brightness") == 0) { | |||
| set_brightness (vf->priv, (1.0 / 100.0) * eq->value); | |||
| return CONTROL_TRUE; | |||
| } | |||
| else if (strcmp (eq->item, "saturation") == 0) { | |||
| set_saturation (vf->priv, (double) (eq->value + 100) / 100.0); | |||
| return CONTROL_TRUE; | |||
| } | |||
| break; | |||
| case VFCTRL_GET_EQUALIZER: | |||
| eq = (vf_equalizer_t *) data; | |||
| if (strcmp (eq->item, "gamma") == 0) { | |||
| eq->value = (int) (100.0 * log (vf->priv->gamma) / log (8.0)); | |||
| return CONTROL_TRUE; | |||
| } | |||
| else if (strcmp (eq->item, "contrast") == 0) { | |||
| eq->value = (int) (100.0 * vf->priv->contrast) - 100; | |||
| return CONTROL_TRUE; | |||
| } | |||
| else if (strcmp (eq->item, "brightness") == 0) { | |||
| eq->value = (int) (100.0 * vf->priv->brightness); | |||
| return CONTROL_TRUE; | |||
| } | |||
| else if (strcmp (eq->item, "saturation") == 0) { | |||
| eq->value = (int) (100.0 * vf->priv->saturation) - 100; | |||
| return CONTROL_TRUE; | |||
| } | |||
| break; | |||
| } | |||
| return vf_next_control (vf, request, data); | |||
| } | |||
| static | |||
| int query_format (vf_instance_t *vf, unsigned fmt) | |||
| { | |||
| switch (fmt) { | |||
| case IMGFMT_YVU9: | |||
| case IMGFMT_IF09: | |||
| case IMGFMT_YV12: | |||
| case IMGFMT_I420: | |||
| case IMGFMT_IYUV: | |||
| case IMGFMT_Y800: | |||
| case IMGFMT_Y8: | |||
| case IMGFMT_444P: | |||
| case IMGFMT_422P: | |||
| case IMGFMT_411P: | |||
| return vf_next_query_format (vf, fmt); | |||
| } | |||
| return 0; | |||
| } | |||
| static | |||
| void uninit (vf_instance_t *vf) | |||
| { | |||
| if (vf->priv != NULL) { | |||
| free (vf->priv->buf[0]); | |||
| free (vf->priv); | |||
| } | |||
| } | |||
| static | |||
| int vf_open(vf_instance_t *vf, char *args) | |||
| { | |||
| unsigned i; | |||
| vf_eq2_t *eq2; | |||
| double par[8]; | |||
| vf->control = control; | |||
| vf->query_format = query_format; | |||
| vf->put_image = put_image; | |||
| vf->uninit = uninit; | |||
| vf->priv = malloc (sizeof (vf_eq2_t)); | |||
| eq2 = vf->priv; | |||
| for (i = 0; i < 3; i++) { | |||
| eq2->buf[i] = NULL; | |||
| eq2->buf_w[i] = 0; | |||
| eq2->buf_h[i] = 0; | |||
| eq2->param[i].adjust = NULL; | |||
| eq2->param[i].c = 1.0; | |||
| eq2->param[i].b = 0.0; | |||
| eq2->param[i].g = 1.0; | |||
| eq2->param[i].lut_clean = 0; | |||
| } | |||
| eq2->contrast = 1.0; | |||
| eq2->brightness = 0.0; | |||
| eq2->saturation = 1.0; | |||
| eq2->gamma = 1.0; | |||
| eq2->gamma_weight = 1.0; | |||
| eq2->rgamma = 1.0; | |||
| eq2->ggamma = 1.0; | |||
| eq2->bgamma = 1.0; | |||
| if (args != NULL) { | |||
| par[0] = 1.0; | |||
| par[1] = 1.0; | |||
| par[2] = 0.0; | |||
| par[3] = 1.0; | |||
| par[4] = 1.0; | |||
| par[5] = 1.0; | |||
| par[6] = 1.0; | |||
| par[7] = 1.0; | |||
| sscanf (args, "%lf:%lf:%lf:%lf:%lf:%lf:%lf:%lf", | |||
| par, par + 1, par + 2, par + 3, par + 4, par + 5, par + 6, par + 7 | |||
| ); | |||
| eq2->rgamma = par[4]; | |||
| eq2->ggamma = par[5]; | |||
| eq2->bgamma = par[6]; | |||
| eq2->gamma_weight = par[7]; | |||
| set_gamma (eq2, par[0]); | |||
| set_contrast (eq2, par[1]); | |||
| set_brightness (eq2, par[2]); | |||
| set_saturation (eq2, par[3]); | |||
| } | |||
| return 1; | |||
| } | |||
| const vf_info_t vf_info_eq2 = { | |||
| "Software equalizer", | |||
| "eq2", | |||
| "Hampa Hug, Daniel Moreno, Richard Felker", | |||
| "", | |||
| &vf_open, | |||
| NULL | |||
| }; | |||
| @@ -0,0 +1,89 @@ | |||
| /* | |||
| * This file is part of MPlayer. | |||
| * | |||
| * MPlayer 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. | |||
| * | |||
| * MPlayer 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 MPlayer; if not, write to the Free Software Foundation, Inc., | |||
| * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | |||
| */ | |||
| #include <stdio.h> | |||
| #include <stdlib.h> | |||
| #include <string.h> | |||
| #include "config.h" | |||
| #include "mp_msg.h" | |||
| #include "mp_image.h" | |||
| #include "vf.h" | |||
| struct vf_priv_s { | |||
| int field; | |||
| }; | |||
| //===========================================================================// | |||
| static int config(struct vf_instance *vf, | |||
| int width, int height, int d_width, int d_height, | |||
| unsigned int flags, unsigned int outfmt){ | |||
| return vf_next_config(vf,width,height/2,d_width,d_height,flags,outfmt); | |||
| } | |||
| static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts){ | |||
| vf->dmpi=vf_get_image(vf->next,mpi->imgfmt, | |||
| MP_IMGTYPE_EXPORT, MP_IMGFLAG_ACCEPT_STRIDE, | |||
| mpi->width, mpi->height/2); | |||
| // set up mpi as a double-stride image of dmpi: | |||
| vf->dmpi->planes[0]=mpi->planes[0]+mpi->stride[0]*vf->priv->field; | |||
| vf->dmpi->stride[0]=2*mpi->stride[0]; | |||
| if(vf->dmpi->flags&MP_IMGFLAG_PLANAR){ | |||
| vf->dmpi->planes[1]=mpi->planes[1]+ | |||
| mpi->stride[1]*vf->priv->field; | |||
| vf->dmpi->stride[1]=2*mpi->stride[1]; | |||
| vf->dmpi->planes[2]=mpi->planes[2]+ | |||
| mpi->stride[2]*vf->priv->field; | |||
| vf->dmpi->stride[2]=2*mpi->stride[2]; | |||
| } else | |||
| vf->dmpi->planes[1]=mpi->planes[1]; // passthru bgr8 palette!!! | |||
| return vf_next_put_image(vf,vf->dmpi, pts); | |||
| } | |||
| //===========================================================================// | |||
| static void uninit(struct vf_instance *vf) | |||
| { | |||
| free(vf->priv); | |||
| } | |||
| static int vf_open(vf_instance_t *vf, char *args){ | |||
| vf->config=config; | |||
| vf->put_image=put_image; | |||
| vf->uninit=uninit; | |||
| vf->default_reqs=VFCAP_ACCEPT_STRIDE; | |||
| vf->priv=calloc(1, sizeof(struct vf_priv_s)); | |||
| if (args) sscanf(args, "%d", &vf->priv->field); | |||
| vf->priv->field &= 1; | |||
| return 1; | |||
| } | |||
| const vf_info_t vf_info_field = { | |||
| "extract single field", | |||
| "field", | |||
| "Rich Felker", | |||
| "", | |||
| vf_open, | |||
| NULL | |||
| }; | |||
| //===========================================================================// | |||
| @@ -0,0 +1,116 @@ | |||
| /* | |||
| * This file is part of MPlayer. | |||
| * | |||
| * MPlayer 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. | |||
| * | |||
| * MPlayer 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 MPlayer; if not, write to the Free Software Foundation, Inc., | |||
| * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | |||
| */ | |||
| #include <stdio.h> | |||
| #include <stdlib.h> | |||
| #include <string.h> | |||
| #include "config.h" | |||
| #include "mp_msg.h" | |||
| #include "mp_image.h" | |||
| #include "vf.h" | |||
| struct vf_priv_s { | |||
| int interleave; | |||
| int height; | |||
| int width; | |||
| int stridefactor; | |||
| }; | |||
| //===========================================================================// | |||
| static int config(struct vf_instance *vf, | |||
| int width, int height, int d_width, int d_height, | |||
| unsigned int flags, unsigned int outfmt){ | |||
| int pixel_stride= (width+15)&~15; //FIXME this is ust a guess ... especially for non planar its somewhat bad one | |||
| #if 0 | |||
| if(mpi->flags&MP_IMGFLAG_PLANAR) | |||
| pixel_stride= mpi->stride[0]; | |||
| else | |||
| pixel_stride= 8*mpi->stride[0] / mpi->bpp; | |||
| #endif | |||
| if(vf->priv->interleave){ | |||
| vf->priv->height= 2*height; | |||
| vf->priv->width= width - (pixel_stride/2); | |||
| vf->priv->stridefactor=1; | |||
| }else{ | |||
| vf->priv->height= height/2; | |||
| vf->priv->width= width + pixel_stride; | |||
| vf->priv->stridefactor=4; | |||
| } | |||
| //printf("hX %d %d %d\n", vf->priv->width,vf->priv->height,vf->priv->stridefactor); | |||
| return vf_next_config(vf, vf->priv->width, vf->priv->height, | |||
| (d_width*vf->priv->stridefactor)>>1, 2*d_height/vf->priv->stridefactor, flags, outfmt); | |||
| } | |||
| static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts){ | |||
| if(mpi->flags&MP_IMGFLAG_DIRECT){ | |||
| // we've used DR, so we're ready... | |||
| return vf_next_put_image(vf,(mp_image_t*)mpi->priv, pts); | |||
| } | |||
| vf->dmpi=vf_get_image(vf->next,mpi->imgfmt, | |||
| MP_IMGTYPE_EXPORT, MP_IMGFLAG_ACCEPT_STRIDE, | |||
| vf->priv->width, vf->priv->height); | |||
| // set up mpi as a double-stride image of dmpi: | |||
| vf->dmpi->planes[0]=mpi->planes[0]; | |||
| vf->dmpi->stride[0]=(mpi->stride[0]*vf->priv->stridefactor)>>1; | |||
| if(vf->dmpi->flags&MP_IMGFLAG_PLANAR){ | |||
| vf->dmpi->planes[1]=mpi->planes[1]; | |||
| vf->dmpi->stride[1]=(mpi->stride[1]*vf->priv->stridefactor)>>1; | |||
| vf->dmpi->planes[2]=mpi->planes[2]; | |||
| vf->dmpi->stride[2]=(mpi->stride[2]*vf->priv->stridefactor)>>1; | |||
| } else | |||
| vf->dmpi->planes[1]=mpi->planes[1]; // passthru bgr8 palette!!! | |||
| return vf_next_put_image(vf,vf->dmpi, pts); | |||
| } | |||
| //===========================================================================// | |||
| static void uninit(struct vf_instance *vf) | |||
| { | |||
| free(vf->priv); | |||
| } | |||
| static int vf_open(vf_instance_t *vf, char *args){ | |||
| vf->config=config; | |||
| vf->put_image=put_image; | |||
| vf->uninit=uninit; | |||
| vf->default_reqs=VFCAP_ACCEPT_STRIDE; | |||
| vf->priv=calloc(1, sizeof(struct vf_priv_s)); | |||
| vf->priv->interleave= args && (*args == 'i'); | |||
| return 1; | |||
| } | |||
| const vf_info_t vf_info_fil = { | |||
| "fast (de)interleaver", | |||
| "fil", | |||
| "Michael Niedermayer", | |||
| "", | |||
| vf_open, | |||
| NULL | |||
| }; | |||
| //===========================================================================// | |||
| @@ -0,0 +1,137 @@ | |||
| /* | |||
| * This file is part of MPlayer. | |||
| * | |||
| * MPlayer 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. | |||
| * | |||
| * MPlayer 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 MPlayer; if not, write to the Free Software Foundation, Inc., | |||
| * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | |||
| */ | |||
| #include <stdio.h> | |||
| #include <stdlib.h> | |||
| #include <string.h> | |||
| #include <inttypes.h> | |||
| #include "config.h" | |||
| #include "mp_msg.h" | |||
| #include "help_mp.h" | |||
| #include "img_format.h" | |||
| #include "mp_image.h" | |||
| #include "vf.h" | |||
| struct vf_priv_s { | |||
| double current; | |||
| double step; | |||
| int autostart; | |||
| int autostep; | |||
| unsigned have_step:1; | |||
| unsigned print:1; | |||
| }; | |||
| static int put_image(vf_instance_t *vf, mp_image_t *src, double pts) | |||
| { | |||
| struct vf_priv_s *p = vf->priv; | |||
| if (p->print) { | |||
| if (pts == MP_NOPTS_VALUE) | |||
| mp_msg(MSGT_VFILTER, MSGL_INFO, "PTS: undef\n"); | |||
| else | |||
| mp_msg(MSGT_VFILTER, MSGL_INFO, "PTS: %f\n", pts); | |||
| } | |||
| if (pts != MP_NOPTS_VALUE && p->autostart != 0) { | |||
| p->current = pts; | |||
| if (p->autostart > 0) | |||
| p->autostart--; | |||
| } else if (pts != MP_NOPTS_VALUE && p->autostep > 0) { | |||
| p->step = pts - p->current; | |||
| p->current = pts; | |||
| p->autostep--; | |||
| p->have_step = 1; | |||
| } else if (p->have_step) { | |||
| p->current += p->step; | |||
| pts = p->current; | |||
| } else { | |||
| pts = MP_NOPTS_VALUE; | |||
| } | |||
| return vf_next_put_image(vf, src, pts); | |||
| } | |||
| static void uninit(vf_instance_t *vf) | |||
| { | |||
| free(vf->priv); | |||
| } | |||
| static int parse_args(struct vf_priv_s *p, const char *args) | |||
| { | |||
| int pos; | |||
| double num, denom = 1; | |||
| int iarg; | |||
| while (*args != 0) { | |||
| pos = 0; | |||
| if (sscanf(args, "print%n", &pos) == 0 && pos > 0) { | |||
| p->print = 1; | |||
| } else if (sscanf(args, "fps=%lf%n/%lf%n", &num, &pos, &denom, &pos) >= | |||
| 1 && pos > 0) { | |||
| p->step = denom / num; | |||
| p->have_step = 1; | |||
| } else if (sscanf(args, "start=%lf%n", &num, &pos) >= 1 && pos > 0) { | |||
| p->current = num; | |||
| } else if (sscanf(args, "autostart=%d%n", &iarg, &pos) == 1 && pos > 0) { | |||
| p->autostart = iarg; | |||
| } else if (sscanf(args, "autofps=%d%n", &iarg, &pos) == 1 && pos > 0) { | |||
| p->autostep = iarg; | |||
| } else { | |||
| mp_msg(MSGT_VFILTER, MSGL_FATAL, | |||
| "fixpts: unknown suboption: %s\n", args); | |||
| return 0; | |||
| } | |||
| args += pos; | |||
| if (*args == ':') | |||
| args++; | |||
| } | |||
| return 1; | |||
| } | |||
| static int open(vf_instance_t *vf, char *args) | |||
| { | |||
| struct vf_priv_s *p; | |||
| struct vf_priv_s ptmp = { | |||
| .current = 0, | |||
| .step = 0, | |||
| .autostart = 0, | |||
| .autostep = 0, | |||
| .have_step = 0, | |||
| .print = 0, | |||
| }; | |||
| if (!parse_args(&ptmp, args == NULL ? "" : args)) | |||
| return 0; | |||
| vf->put_image = put_image; | |||
| vf->uninit = uninit; | |||
| vf->priv = p = malloc(sizeof(struct vf_priv_s)); | |||
| *p = ptmp; | |||
| p->current = -p->step; | |||
| return 1; | |||
| } | |||
| const vf_info_t vf_info_fixpts = { | |||
| "Fix presentation timestamps", | |||
| "fixpts", | |||
| "Nicolas George", | |||
| "", | |||
| &open, | |||
| NULL | |||
| }; | |||
| @@ -0,0 +1,205 @@ | |||
| /* | |||
| * filter to ouput only 1 every n frame, or only the I (key)frame | |||
| * | |||
| * The parameters are: | |||
| * | |||
| * [I] | [i]num | |||
| * | |||
| * if you call the filter with I (uppercase) as the parameter | |||
| * ... -vf framestep=I ... | |||
| * then ONLY the keyframes are outputted. | |||
| * For DVD it means, generally, one every 15 frames (IBBPBBPBBPBBPBB), for avi it means | |||
| * every scene change or every keyint value (see -lavcopts). | |||
| * | |||
| * if you call the filter with the i (lowercase) | |||
| * ... -vf framestep=i ... | |||
| * then a I! followed by a cr is printed when a key frame (eg Intra frame) is | |||
| * found, leaving the current line of mplayer/mencoder, where you got the | |||
| * time, in seconds, and frame of the key. Use this information to split the | |||
| * AVI. | |||
| * | |||
| * After the i or alone you can put a positive number and only one frame every | |||
| * x (the number you set) is passed on the filter chain, limiting the output | |||
| * of the frame. | |||
| * | |||
| * Example | |||
| * ... -vf framestep=i20 ... | |||
| * Dump one every 20 frames, printing on the console when a I-Frame is encounter. | |||
| * | |||
| * ... -vf framestep=25 | |||
| * Dump one every 25 frames. | |||
| * | |||
| * If you call the filter without parameter it does nothing (except using memory | |||
| * and resource of your system,. of course). | |||
| * | |||
| * This filter doesn' t work like the option -sstep seconds. | |||
| * | |||
| * The -sstep seek to the new position, without decoding all frames but, | |||
| * expecially on avi file coded whith mpeg4 (lavc or xvid or divx), the | |||
| * seek is not always too much precise. | |||
| * | |||
| * This filter simply discard the unwanted frames, so you are very precise in | |||
| * counting the frame but sometime you use a lot of CPU for nothing. | |||
| * | |||
| * As usual it depends on what you're doing. | |||
| * | |||
| * copyright (c) 2003 Daniele Forghieri ( guru@digitalfantasy.it ) | |||
| * | |||
| * This file is part of MPlayer. | |||
| * | |||
| * MPlayer 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. | |||
| * | |||
| * MPlayer 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 MPlayer; if not, write to the Free Software Foundation, Inc., | |||
| * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | |||
| */ | |||
| #include <stdio.h> | |||
| #include <stdlib.h> | |||
| #include <string.h> | |||
| #include "config.h" | |||
| #include "mp_msg.h" | |||
| #include "help_mp.h" | |||
| #include "cpudetect.h" | |||
| #include "img_format.h" | |||
| #include "mp_image.h" | |||
| #include "vf.h" | |||
| /* Uncomment if you want to print some info on the format */ | |||
| // #define DUMP_FORMAT_DATA | |||
| /* Private data */ | |||
| struct vf_priv_s { | |||
| /* Current frame */ | |||
| int frame_cur; | |||
| /* Frame output step, 0 = all */ | |||
| int frame_step; | |||
| /* Only I-Frame (2), print on I-Frame (1) */ | |||
| int dump_iframe; | |||
| }; | |||
| /* Filter handler */ | |||
| static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts) | |||
| { | |||
| mp_image_t *dmpi; | |||
| struct vf_priv_s *priv; | |||
| int skip; | |||
| priv = vf->priv; | |||
| /* Print the 'I' if is a intra frame. The \n advance the current line so you got the | |||
| * current file time (in second) and the frame number on the console ;-) | |||
| */ | |||
| if (priv->dump_iframe) { | |||
| if (mpi->pict_type == 1) { | |||
| mp_msg(MSGT_VFILTER, MSGL_INFO, "I!\n"); | |||
| } | |||
| } | |||
| /* decide if frame must be shown */ | |||
| if (priv->dump_iframe == 2) { | |||
| /* Only key frame */ | |||
| skip = mpi->pict_type == 1 ? 0 : 1; | |||
| } | |||
| else { | |||
| /* Only 1 every frame_step */ | |||
| skip = 0; | |||
| if ((priv->frame_step != 0) && ((priv->frame_cur % priv->frame_step) != 0)) { | |||
| skip = 1; | |||
| } | |||
| } | |||
| /* Increment current frame */ | |||
| ++priv->frame_cur; | |||
| if (skip == 0) { | |||
| /* Get image, export type (we don't modify tghe image) */ | |||
| dmpi=vf_get_image(vf->next, mpi->imgfmt, | |||
| MP_IMGTYPE_EXPORT, 0, | |||
| mpi->w, mpi->h); | |||
| /* Copy only the pointer ( MP_IMGTYPE_EXPORT ! ) */ | |||
| dmpi->planes[0] = mpi->planes[0]; | |||
| dmpi->planes[1] = mpi->planes[1]; | |||
| dmpi->planes[2] = mpi->planes[2]; | |||
| dmpi->stride[0] = mpi->stride[0]; | |||
| dmpi->stride[1] = mpi->stride[1]; | |||
| dmpi->stride[2] = mpi->stride[2]; | |||
| dmpi->width = mpi->width; | |||
| dmpi->height = mpi->height; | |||
| /* Chain to next filter / output ... */ | |||
| return vf_next_put_image(vf, dmpi, pts); | |||
| } | |||
| /* Skip the frame */ | |||
| return 0; | |||
| } | |||
| static void uninit(struct vf_instance *vf) | |||
| { | |||
| /* Free private data */ | |||
| free(vf->priv); | |||
| } | |||
| /* Main entry funct for the filter */ | |||
| static int vf_open(vf_instance_t *vf, char *args) | |||
| { | |||
| struct vf_priv_s *p; | |||
| vf->put_image = put_image; | |||
| vf->uninit = uninit; | |||
| vf->default_reqs = VFCAP_ACCEPT_STRIDE; | |||
| vf->priv = p = calloc(1, sizeof(struct vf_priv_s)); | |||
| if (p == NULL) { | |||
| return 0; | |||
| } | |||
| if (args != NULL) { | |||
| #ifdef DUMP_FORMAT_DATA | |||
| if (*args == 'd') { | |||
| p->dump_iframe = 3; | |||
| } | |||
| else | |||
| #endif | |||
| if (*args == 'I') { | |||
| /* Dump only KEY (ie INTRA) frame */ | |||
| p->dump_iframe = 2; | |||
| } | |||
| else { | |||
| if (*args == 'i') { | |||
| /* Print a 'I!' when a i-frame is encounter */ | |||
| p->dump_iframe = 1; | |||
| ++args; | |||
| } | |||
| if (*args != '\0') { | |||
| p->frame_step = atoi(args); | |||
| if (p->frame_step <= 0) { | |||
| mp_msg(MSGT_VFILTER, MSGL_WARN, MSGTR_MPCODECS_ErrorParsingArgument); | |||
| return 0; | |||
| } | |||
| } | |||
| } | |||
| } | |||
| return 1; | |||
| } | |||
| const vf_info_t vf_info_framestep = { | |||
| "Dump one every n / key frames", | |||
| "framestep", | |||
| "Daniele Forghieri", | |||
| "", | |||
| vf_open, | |||
| NULL | |||
| }; | |||
| @@ -0,0 +1,197 @@ | |||
| /* | |||
| * Copyright (C) 2006 Michael Niedermayer <michaelni@gmx.at> | |||
| * | |||
| * This file is part of MPlayer. | |||
| * | |||
| * MPlayer 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. | |||
| * | |||
| * MPlayer 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 MPlayer; if not, write to the Free Software Foundation, Inc., | |||
| * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | |||
| */ | |||
| #include <stdio.h> | |||
| #include <stdlib.h> | |||
| #include <string.h> | |||
| #include <math.h> | |||
| #include <inttypes.h> | |||
| #include "config.h" | |||
| #include "mp_msg.h" | |||
| #include "cpudetect.h" | |||
| #include "img_format.h" | |||
| #include "mp_image.h" | |||
| #include "vf.h" | |||
| #include "libavcodec/avcodec.h" | |||
| #include "libavutil/eval.h" | |||
| struct vf_priv_s { | |||
| AVExpr * e[3]; | |||
| int framenum; | |||
| mp_image_t *mpi; | |||
| }; | |||
| static int config(struct vf_instance *vf, | |||
| int width, int height, int d_width, int d_height, | |||
| unsigned int flags, unsigned int outfmt){ | |||
| return vf_next_config(vf,width,height,d_width,d_height,flags,outfmt); | |||
| } | |||
| static inline double getpix(struct vf_instance *vf, double x, double y, int plane){ | |||
| int xi, yi; | |||
| mp_image_t *mpi= vf->priv->mpi; | |||
| int stride= mpi->stride[plane]; | |||
| uint8_t *src= mpi->planes[plane]; | |||
| xi=x= FFMIN(FFMAX(x, 0), (mpi->w >> (plane ? mpi->chroma_x_shift : 0))-1); | |||
| yi=y= FFMIN(FFMAX(y, 0), (mpi->h >> (plane ? mpi->chroma_y_shift : 0))-1); | |||
| x-=xi; | |||
| y-=yi; | |||
| return | |||
| (1-y)*((1-x)*src[xi + yi * stride] + x*src[xi + 1 + yi * stride]) | |||
| + y *((1-x)*src[xi + (yi+1) * stride] + x*src[xi + 1 + (yi+1) * stride]); | |||
| } | |||
| //FIXME cubic interpolate | |||
| //FIXME keep the last few frames | |||
| static double lum(void *vf, double x, double y){ | |||
| return getpix(vf, x, y, 0); | |||
| } | |||
| static double cb(void *vf, double x, double y){ | |||
| return getpix(vf, x, y, 1); | |||
| } | |||
| static double cr(void *vf, double x, double y){ | |||
| return getpix(vf, x, y, 2); | |||
| } | |||
| static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts){ | |||
| mp_image_t *dmpi; | |||
| int x,y, plane; | |||
| if(!(mpi->flags&MP_IMGFLAG_DIRECT)){ | |||
| // no DR, so get a new image! hope we'll get DR buffer: | |||
| vf->dmpi=vf_get_image(vf->next,mpi->imgfmt, MP_IMGTYPE_TEMP, | |||
| MP_IMGFLAG_ACCEPT_STRIDE|MP_IMGFLAG_PREFER_ALIGNED_STRIDE, | |||
| mpi->w,mpi->h); | |||
| } | |||
| dmpi= vf->dmpi; | |||
| vf->priv->mpi= mpi; | |||
| vf_clone_mpi_attributes(dmpi, mpi); | |||
| for(plane=0; plane<3; plane++){ | |||
| int w= mpi->w >> (plane ? mpi->chroma_x_shift : 0); | |||
| int h= mpi->h >> (plane ? mpi->chroma_y_shift : 0); | |||
| uint8_t *dst = dmpi->planes[plane]; | |||
| int dst_stride= dmpi->stride[plane]; | |||
| double const_values[]={ | |||
| M_PI, | |||
| M_E, | |||
| 0, | |||
| 0, | |||
| w, | |||
| h, | |||
| vf->priv->framenum, | |||
| w/(double)mpi->w, | |||
| h/(double)mpi->h, | |||
| 0 | |||
| }; | |||
| if (!vf->priv->e[plane]) continue; | |||
| for(y=0; y<h; y++){ | |||
| const_values[3]=y; | |||
| for(x=0; x<w; x++){ | |||
| const_values[2]=x; | |||
| dst[x + y * dst_stride] = av_eval_expr(vf->priv->e[plane], | |||
| const_values, vf); | |||
| } | |||
| } | |||
| } | |||
| vf->priv->framenum++; | |||
| return vf_next_put_image(vf,dmpi, pts); | |||
| } | |||
| static void uninit(struct vf_instance *vf){ | |||
| av_free(vf->priv); | |||
| vf->priv=NULL; | |||
| } | |||
| //===========================================================================// | |||
| static int vf_open(vf_instance_t *vf, char *args){ | |||
| char eq[3][2000] = { { 0 }, { 0 }, { 0 } }; | |||
| int plane, res; | |||
| vf->config=config; | |||
| vf->put_image=put_image; | |||
| // vf->get_image=get_image; | |||
| vf->uninit=uninit; | |||
| vf->priv=av_malloc(sizeof(struct vf_priv_s)); | |||
| memset(vf->priv, 0, sizeof(struct vf_priv_s)); | |||
| if (args) sscanf(args, "%1999[^:]:%1999[^:]:%1999[^:]", eq[0], eq[1], eq[2]); | |||
| if (!eq[1][0]) strncpy(eq[1], eq[0], sizeof(eq[0])-1); | |||
| if (!eq[2][0]) strncpy(eq[2], eq[1], sizeof(eq[0])-1); | |||
| for(plane=0; plane<3; plane++){ | |||
| static const char *const_names[]={ | |||
| "PI", | |||
| "E", | |||
| "X", | |||
| "Y", | |||
| "W", | |||
| "H", | |||
| "N", | |||
| "SW", | |||
| "SH", | |||
| NULL | |||
| }; | |||
| static const char *func2_names[]={ | |||
| "lum", | |||
| "cb", | |||
| "cr", | |||
| "p", | |||
| NULL | |||
| }; | |||
| double (*func2[])(void *, double, double)={ | |||
| lum, | |||
| cb, | |||
| cr, | |||
| plane==0 ? lum : (plane==1 ? cb : cr), | |||
| NULL | |||
| }; | |||
| res = av_parse_expr(&vf->priv->e[plane], eq[plane], const_names, NULL, NULL, func2_names, func2, 0, NULL); | |||
| if (res < 0) { | |||
| mp_msg(MSGT_VFILTER, MSGL_ERR, "geq: error loading equation `%s'\n", eq[plane]); | |||
| return 0; | |||
| } | |||
| } | |||
| return 1; | |||
| } | |||
| const vf_info_t vf_info_geq = { | |||
| "generic equation filter", | |||
| "geq", | |||
| "Michael Niedermayer", | |||
| "", | |||
| vf_open, | |||
| NULL | |||
| }; | |||
| @@ -0,0 +1,411 @@ | |||
| /* | |||
| * Copyright (C) 2009 Loren Merritt <lorenm@u.washignton.edu> | |||
| * | |||
| * This file is part of MPlayer. | |||
| * | |||
| * MPlayer 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. | |||
| * | |||
| * MPlayer 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 MPlayer; if not, write to the Free Software Foundation, Inc., | |||
| * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | |||
| */ | |||
| /* | |||
| * Debanding algorithm (from gradfun2db by prunedtree): | |||
| * Boxblur. | |||
| * Foreach pixel, if it's within threshold of the blurred value, make it closer. | |||
| * So now we have a smoothed and higher bitdepth version of all the shallow | |||
| * gradients, while leaving detailed areas untouched. | |||
| * Dither it back to 8bit. | |||
| */ | |||
| #include <stdio.h> | |||
| #include <stdlib.h> | |||
| #include <string.h> | |||
| #include <inttypes.h> | |||
| #include "config.h" | |||
| #include "cpudetect.h" | |||
| #include "img_format.h" | |||
| #include "mp_image.h" | |||
| #include "vf.h" | |||
| #include "libvo/fastmemcpy.h" | |||
| #include "libavutil/avutil.h" | |||
| #include "libavutil/x86_cpu.h" | |||
| struct vf_priv_s { | |||
| int thresh; | |||
| int radius; | |||
| uint16_t *buf; | |||
| void (*filter_line)(uint8_t *dst, uint8_t *src, uint16_t *dc, | |||
| int width, int thresh, const uint16_t *dithers); | |||
| void (*blur_line)(uint16_t *dc, uint16_t *buf, uint16_t *buf1, | |||
| uint8_t *src, int sstride, int width); | |||
| }; | |||
| static const uint16_t __attribute__((aligned(16))) pw_7f[8] = {127,127,127,127,127,127,127,127}; | |||
| static const uint16_t __attribute__((aligned(16))) pw_ff[8] = {255,255,255,255,255,255,255,255}; | |||
| static const uint16_t __attribute__((aligned(16))) dither[8][8] = { | |||
| { 0, 96, 24,120, 6,102, 30,126 }, | |||
| { 64, 32, 88, 56, 70, 38, 94, 62 }, | |||
| { 16,112, 8,104, 22,118, 14,110 }, | |||
| { 80, 48, 72, 40, 86, 54, 78, 46 }, | |||
| { 4,100, 28,124, 2, 98, 26,122 }, | |||
| { 68, 36, 92, 60, 66, 34, 90, 58 }, | |||
| { 20,116, 12,108, 18,114, 10,106 }, | |||
| { 84, 52, 76, 44, 82, 50, 74, 42 }, | |||
| }; | |||
| static void filter_line_c(uint8_t *dst, uint8_t *src, uint16_t *dc, | |||
| int width, int thresh, const uint16_t *dithers) | |||
| { | |||
| int x; | |||
| for (x=0; x<width; x++, dc+=x&1) { | |||
| int pix = src[x]<<7; | |||
| int delta = dc[0] - pix; | |||
| int m = abs(delta) * thresh >> 16; | |||
| m = FFMAX(0, 127-m); | |||
| m = m*m*delta >> 14; | |||
| pix += m + dithers[x&7]; | |||
| dst[x] = av_clip_uint8(pix>>7); | |||
| } | |||
| } | |||
| static void blur_line_c(uint16_t *dc, uint16_t *buf, uint16_t *buf1, | |||
| uint8_t *src, int sstride, int width) | |||
| { | |||
| int x, v, old; | |||
| for (x=0; x<width; x++) { | |||
| v = buf1[x] + src[2*x] + src[2*x+1] + src[2*x+sstride] + src[2*x+1+sstride]; | |||
| old = buf[x]; | |||
| buf[x] = v; | |||
| dc[x] = v - old; | |||
| } | |||
| } | |||
| #if HAVE_MMX2 | |||
| static void filter_line_mmx2(uint8_t *dst, uint8_t *src, uint16_t *dc, | |||
| int width, int thresh, const uint16_t *dithers) | |||
| { | |||
| intptr_t x; | |||
| if (width&3) { | |||
| x = width&~3; | |||
| filter_line_c(dst+x, src+x, dc+x/2, width-x, thresh, dithers); | |||
| width = x; | |||
| } | |||
| x = -width; | |||
| __asm__ volatile( | |||
| "movd %4, %%mm5 \n" | |||
| "pxor %%mm7, %%mm7 \n" | |||
| "pshufw $0, %%mm5, %%mm5 \n" | |||
| "movq %6, %%mm6 \n" | |||
| "movq %5, %%mm4 \n" | |||
| "1: \n" | |||
| "movd (%2,%0), %%mm0 \n" | |||
| "movd (%3,%0), %%mm1 \n" | |||
| "punpcklbw %%mm7, %%mm0 \n" | |||
| "punpcklwd %%mm1, %%mm1 \n" | |||
| "psllw $7, %%mm0 \n" | |||
| "pxor %%mm2, %%mm2 \n" | |||
| "psubw %%mm0, %%mm1 \n" // delta = dc - pix | |||
| "psubw %%mm1, %%mm2 \n" | |||
| "pmaxsw %%mm1, %%mm2 \n" | |||
| "pmulhuw %%mm5, %%mm2 \n" // m = abs(delta) * thresh >> 16 | |||
| "psubw %%mm6, %%mm2 \n" | |||
| "pminsw %%mm7, %%mm2 \n" // m = -max(0, 127-m) | |||
| "pmullw %%mm2, %%mm2 \n" | |||
| "paddw %%mm4, %%mm0 \n" // pix += dither | |||
| "pmulhw %%mm2, %%mm1 \n" | |||
| "psllw $2, %%mm1 \n" // m = m*m*delta >> 14 | |||
| "paddw %%mm1, %%mm0 \n" // pix += m | |||
| "psraw $7, %%mm0 \n" | |||
| "packuswb %%mm0, %%mm0 \n" | |||
| "movd %%mm0, (%1,%0) \n" // dst = clip(pix>>7) | |||
| "add $4, %0 \n" | |||
| "jl 1b \n" | |||
| "emms \n" | |||
| :"+r"(x) | |||
| :"r"(dst+width), "r"(src+width), "r"(dc+width/2), | |||
| "rm"(thresh), "m"(*dithers), "m"(*pw_7f) | |||
| :"memory" | |||
| ); | |||
| } | |||
| #endif | |||
| #if HAVE_SSSE3 | |||
| static void filter_line_ssse3(uint8_t *dst, uint8_t *src, uint16_t *dc, | |||
| int width, int thresh, const uint16_t *dithers) | |||
| { | |||
| intptr_t x; | |||
| if (width&7) { | |||
| // could be 10% faster if I somehow eliminated this | |||
| x = width&~7; | |||
| filter_line_c(dst+x, src+x, dc+x/2, width-x, thresh, dithers); | |||
| width = x; | |||
| } | |||
| x = -width; | |||
| __asm__ volatile( | |||
| "movd %4, %%xmm5 \n" | |||
| "pxor %%xmm7, %%xmm7 \n" | |||
| "pshuflw $0,%%xmm5, %%xmm5 \n" | |||
| "movdqa %6, %%xmm6 \n" | |||
| "punpcklqdq %%xmm5, %%xmm5 \n" | |||
| "movdqa %5, %%xmm4 \n" | |||
| "1: \n" | |||
| "movq (%2,%0), %%xmm0 \n" | |||
| "movq (%3,%0), %%xmm1 \n" | |||
| "punpcklbw %%xmm7, %%xmm0 \n" | |||
| "punpcklwd %%xmm1, %%xmm1 \n" | |||
| "psllw $7, %%xmm0 \n" | |||
| "psubw %%xmm0, %%xmm1 \n" // delta = dc - pix | |||
| "pabsw %%xmm1, %%xmm2 \n" | |||
| "pmulhuw %%xmm5, %%xmm2 \n" // m = abs(delta) * thresh >> 16 | |||
| "psubw %%xmm6, %%xmm2 \n" | |||
| "pminsw %%xmm7, %%xmm2 \n" // m = -max(0, 127-m) | |||
| "pmullw %%xmm2, %%xmm2 \n" | |||
| "psllw $1, %%xmm2 \n" | |||
| "paddw %%xmm4, %%xmm0 \n" // pix += dither | |||
| "pmulhrsw %%xmm2, %%xmm1 \n" // m = m*m*delta >> 14 | |||
| "paddw %%xmm1, %%xmm0 \n" // pix += m | |||
| "psraw $7, %%xmm0 \n" | |||
| "packuswb %%xmm0, %%xmm0 \n" | |||
| "movq %%xmm0, (%1,%0) \n" // dst = clip(pix>>7) | |||
| "add $8, %0 \n" | |||
| "jl 1b \n" | |||
| :"+&r"(x) | |||
| :"r"(dst+width), "r"(src+width), "r"(dc+width/2), | |||
| "rm"(thresh), "m"(*dithers), "m"(*pw_7f) | |||
| :"memory" | |||
| ); | |||
| } | |||
| #endif // HAVE_SSSE3 | |||
| #if HAVE_SSE2 && HAVE_6REGS | |||
| #define BLURV(load)\ | |||
| intptr_t x = -2*width;\ | |||
| __asm__ volatile(\ | |||
| "movdqa %6, %%xmm7 \n"\ | |||
| "1: \n"\ | |||
| load" (%4,%0), %%xmm0 \n"\ | |||
| load" (%5,%0), %%xmm1 \n"\ | |||
| "movdqa %%xmm0, %%xmm2 \n"\ | |||
| "movdqa %%xmm1, %%xmm3 \n"\ | |||
| "psrlw $8, %%xmm0 \n"\ | |||
| "psrlw $8, %%xmm1 \n"\ | |||
| "pand %%xmm7, %%xmm2 \n"\ | |||
| "pand %%xmm7, %%xmm3 \n"\ | |||
| "paddw %%xmm1, %%xmm0 \n"\ | |||
| "paddw %%xmm3, %%xmm2 \n"\ | |||
| "paddw %%xmm2, %%xmm0 \n"\ | |||
| "paddw (%2,%0), %%xmm0 \n"\ | |||
| "movdqa (%1,%0), %%xmm1 \n"\ | |||
| "movdqa %%xmm0, (%1,%0) \n"\ | |||
| "psubw %%xmm1, %%xmm0 \n"\ | |||
| "movdqa %%xmm0, (%3,%0) \n"\ | |||
| "add $16, %0 \n"\ | |||
| "jl 1b \n"\ | |||
| :"+&r"(x)\ | |||
| :"r"(buf+width),\ | |||
| "r"(buf1+width),\ | |||
| "r"(dc+width),\ | |||
| "r"(src+width*2),\ | |||
| "r"(src+width*2+sstride),\ | |||
| "m"(*pw_ff)\ | |||
| :"memory"\ | |||
| ); | |||
| static void blur_line_sse2(uint16_t *dc, uint16_t *buf, uint16_t *buf1, | |||
| uint8_t *src, int sstride, int width) | |||
| { | |||
| if (((intptr_t)src|sstride)&15) { | |||
| BLURV("movdqu"); | |||
| } else { | |||
| BLURV("movdqa"); | |||
| } | |||
| } | |||
| #endif // HAVE_6REGS && HAVE_SSE2 | |||
| static void filter(struct vf_priv_s *ctx, uint8_t *dst, uint8_t *src, | |||
| int width, int height, int dstride, int sstride, int r) | |||
| { | |||
| int bstride = ((width+15)&~15)/2; | |||
| int y; | |||
| uint32_t dc_factor = (1<<21)/(r*r); | |||
| uint16_t *dc = ctx->buf+16; | |||
| uint16_t *buf = ctx->buf+bstride+32; | |||
| int thresh = ctx->thresh; | |||
| memset(dc, 0, (bstride+16)*sizeof(*buf)); | |||
| for (y=0; y<r; y++) | |||
| ctx->blur_line(dc, buf+y*bstride, buf+(y-1)*bstride, src+2*y*sstride, sstride, width/2); | |||
| for (;;) { | |||
| if (y < height-r) { | |||
| int mod = ((y+r)/2)%r; | |||
| uint16_t *buf0 = buf+mod*bstride; | |||
| uint16_t *buf1 = buf+(mod?mod-1:r-1)*bstride; | |||
| int x, v; | |||
| ctx->blur_line(dc, buf0, buf1, src+(y+r)*sstride, sstride, width/2); | |||
| for (x=v=0; x<r; x++) | |||
| v += dc[x]; | |||
| for (; x<width/2; x++) { | |||
| v += dc[x] - dc[x-r]; | |||
| dc[x-r] = v * dc_factor >> 16; | |||
| } | |||
| for (; x<(width+r+1)/2; x++) | |||
| dc[x-r] = v * dc_factor >> 16; | |||
| for (x=-r/2; x<0; x++) | |||
| dc[x] = dc[0]; | |||
| } | |||
| if (y == r) { | |||
| for (y=0; y<r; y++) | |||
| ctx->filter_line(dst+y*dstride, src+y*sstride, dc-r/2, width, thresh, dither[y&7]); | |||
| } | |||
| ctx->filter_line(dst+y*dstride, src+y*sstride, dc-r/2, width, thresh, dither[y&7]); | |||
| if (++y >= height) break; | |||
| ctx->filter_line(dst+y*dstride, src+y*sstride, dc-r/2, width, thresh, dither[y&7]); | |||
| if (++y >= height) break; | |||
| } | |||
| } | |||
| static void get_image(struct vf_instance *vf, mp_image_t *mpi) | |||
| { | |||
| if (mpi->flags&MP_IMGFLAG_PRESERVE) return; // don't change | |||
| // ok, we can do pp in-place: | |||
| vf->dmpi = vf_get_image(vf->next, mpi->imgfmt, | |||
| mpi->type, mpi->flags, mpi->width, mpi->height); | |||
| mpi->planes[0] = vf->dmpi->planes[0]; | |||
| mpi->stride[0] = vf->dmpi->stride[0]; | |||
| mpi->width = vf->dmpi->width; | |||
| if (mpi->flags&MP_IMGFLAG_PLANAR){ | |||
| mpi->planes[1] = vf->dmpi->planes[1]; | |||
| mpi->planes[2] = vf->dmpi->planes[2]; | |||
| mpi->stride[1] = vf->dmpi->stride[1]; | |||
| mpi->stride[2] = vf->dmpi->stride[2]; | |||
| } | |||
| mpi->flags |= MP_IMGFLAG_DIRECT; | |||
| } | |||
| static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts) | |||
| { | |||
| mp_image_t *dmpi = vf->dmpi; | |||
| int p; | |||
| if (!(mpi->flags&MP_IMGFLAG_DIRECT)) { | |||
| // no DR, so get a new image. hope we'll get DR buffer: | |||
| dmpi = vf_get_image(vf->next,mpi->imgfmt, MP_IMGTYPE_TEMP, | |||
| MP_IMGFLAG_ACCEPT_STRIDE|MP_IMGFLAG_PREFER_ALIGNED_STRIDE, | |||
| mpi->w, mpi->h); | |||
| } | |||
| vf_clone_mpi_attributes(dmpi, mpi); | |||
| for (p=0; p<mpi->num_planes; p++) { | |||
| int w = mpi->w; | |||
| int h = mpi->h; | |||
| int r = vf->priv->radius; | |||
| if (p) { | |||
| w >>= mpi->chroma_x_shift; | |||
| h >>= mpi->chroma_y_shift; | |||
| r = ((r>>mpi->chroma_x_shift) + (r>>mpi->chroma_y_shift)) / 2; | |||
| r = av_clip((r+1)&~1,4,32); | |||
| } | |||
| if (FFMIN(w,h) > 2*r) | |||
| filter(vf->priv, dmpi->planes[p], mpi->planes[p], w, h, | |||
| dmpi->stride[p], mpi->stride[p], r); | |||
| else if (dmpi->planes[p] != mpi->planes[p]) | |||
| memcpy_pic(dmpi->planes[p], mpi->planes[p], w, h, | |||
| dmpi->stride[p], mpi->stride[p]); | |||
| } | |||
| return vf_next_put_image(vf, dmpi, pts); | |||
| } | |||
| static int query_format(struct vf_instance *vf, unsigned int fmt) | |||
| { | |||
| switch (fmt){ | |||
| case IMGFMT_YVU9: | |||
| case IMGFMT_IF09: | |||
| case IMGFMT_YV12: | |||
| case IMGFMT_I420: | |||
| case IMGFMT_IYUV: | |||
| case IMGFMT_CLPL: | |||
| case IMGFMT_Y800: | |||
| case IMGFMT_Y8: | |||
| case IMGFMT_NV12: | |||
| case IMGFMT_NV21: | |||
| case IMGFMT_444P: | |||
| case IMGFMT_422P: | |||
| case IMGFMT_411P: | |||
| case IMGFMT_HM12: | |||
| return vf_next_query_format(vf,fmt); | |||
| } | |||
| return 0; | |||
| } | |||
| static int config(struct vf_instance *vf, | |||
| int width, int height, int d_width, int d_height, | |||
| unsigned int flags, unsigned int outfmt) | |||
| { | |||
| free(vf->priv->buf); | |||
| vf->priv->buf = av_mallocz((((width+15)&~15)*(vf->priv->radius+1)/2+32)*sizeof(uint16_t)); | |||
| return vf_next_config(vf,width,height,d_width,d_height,flags,outfmt); | |||
| } | |||
| static void uninit(struct vf_instance *vf) | |||
| { | |||
| if (!vf->priv) return; | |||
| av_free(vf->priv->buf); | |||
| free(vf->priv); | |||
| vf->priv = NULL; | |||
| } | |||
| static int vf_open(vf_instance_t *vf, char *args) | |||
| { | |||
| float thresh = 1.2; | |||
| int radius = 16; | |||
| vf->get_image=get_image; | |||
| vf->put_image=put_image; | |||
| vf->query_format=query_format; | |||
| vf->config=config; | |||
| vf->uninit=uninit; | |||
| vf->priv=malloc(sizeof(struct vf_priv_s)); | |||
| memset(vf->priv, 0, sizeof(struct vf_priv_s)); | |||
| if (args) sscanf(args, "%f:%d", &thresh, &radius); | |||
| vf->priv->thresh = (1<<15)/av_clipf(thresh,0.51,255); | |||
| vf->priv->radius = av_clip((radius+1)&~1,4,32); | |||
| vf->priv->blur_line = blur_line_c; | |||
| vf->priv->filter_line = filter_line_c; | |||
| #if HAVE_SSE2 && HAVE_6REGS | |||
| if (gCpuCaps.hasSSE2) | |||
| vf->priv->blur_line = blur_line_sse2; | |||
| #endif | |||
| #if HAVE_MMX2 | |||
| if (gCpuCaps.hasMMX2) | |||
| vf->priv->filter_line = filter_line_mmx2; | |||
| #endif | |||
| #if HAVE_SSSE3 | |||
| if (gCpuCaps.hasSSSE3) | |||
| vf->priv->filter_line = filter_line_ssse3; | |||
| #endif | |||
| return 1; | |||
| } | |||
| const vf_info_t vf_info_gradfun = { | |||
| "gradient deband", | |||
| "gradfun", | |||
| "Loren Merritt", | |||
| "", | |||
| vf_open, | |||
| NULL | |||
| }; | |||
| @@ -0,0 +1,92 @@ | |||
| /* | |||
| * This file is part of MPlayer. | |||
| * | |||
| * MPlayer 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. | |||
| * | |||
| * MPlayer 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 MPlayer; if not, write to the Free Software Foundation, Inc., | |||
| * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | |||
| */ | |||
| #include <stdio.h> | |||
| #include <stdlib.h> | |||
| #include <string.h> | |||
| #include "config.h" | |||
| #include "mp_msg.h" | |||
| #include "img_format.h" | |||
| #include "mp_image.h" | |||
| #include "vf.h" | |||
| struct vf_priv_s { | |||
| mp_image_t *last_mpi; | |||
| }; | |||
| static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts) | |||
| { | |||
| mp_image_t *dmpi; | |||
| vf->priv->last_mpi = mpi; | |||
| dmpi = vf_get_image(vf->next, mpi->imgfmt, | |||
| MP_IMGTYPE_EXPORT, 0, mpi->width, mpi->height); | |||
| dmpi->planes[0] = mpi->planes[0]; | |||
| dmpi->stride[0] = mpi->stride[0]; | |||
| if (dmpi->flags&MP_IMGFLAG_PLANAR) { | |||
| dmpi->planes[1] = mpi->planes[1]; | |||
| dmpi->stride[1] = mpi->stride[1]; | |||
| dmpi->planes[2] = mpi->planes[2]; | |||
| dmpi->stride[2] = mpi->stride[2]; | |||
| } | |||
| return vf_next_put_image(vf, dmpi, pts); | |||
| } | |||
| static int control(struct vf_instance *vf, int request, void* data) | |||
| { | |||
| switch (request) { | |||
| case VFCTRL_DUPLICATE_FRAME: | |||
| if (!vf->priv->last_mpi) break; | |||
| // This is a huge hack. We assume nothing | |||
| // has been called earlier in the filter chain | |||
| // since the last put_image. This is reasonable | |||
| // because we're handling a duplicate frame! | |||
| if (put_image(vf, vf->priv->last_mpi, MP_NOPTS_VALUE)) | |||
| return CONTROL_TRUE; | |||
| break; | |||
| } | |||
| return vf_next_control(vf, request, data); | |||
| } | |||
| static void uninit(struct vf_instance *vf) | |||
| { | |||
| free(vf->priv); | |||
| } | |||
| static int vf_open(vf_instance_t *vf, char *args) | |||
| { | |||
| vf->put_image = put_image; | |||
| vf->control = control; | |||
| vf->uninit = uninit; | |||
| vf->priv = calloc(1, sizeof(struct vf_priv_s)); | |||
| return 1; | |||
| } | |||
| const vf_info_t vf_info_harddup = { | |||
| "resubmit duplicate frames for encoding", | |||
| "harddup", | |||
| "Rich Felker", | |||
| "", | |||
| vf_open, | |||
| NULL | |||
| }; | |||
| @@ -0,0 +1,373 @@ | |||
| /* | |||
| * Copyright (C) 2003 Daniel Moreno <comac@comac.darktech.org> | |||
| * | |||
| * This file is part of MPlayer. | |||
| * | |||
| * MPlayer 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. | |||
| * | |||
| * MPlayer 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 MPlayer; if not, write to the Free Software Foundation, Inc., | |||
| * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | |||
| */ | |||
| #include <stdio.h> | |||
| #include <stdlib.h> | |||
| #include <string.h> | |||
| #include <inttypes.h> | |||
| #include <math.h> | |||
| #include "mp_msg.h" | |||
| #include "img_format.h" | |||
| #include "mp_image.h" | |||
| #include "vf.h" | |||
| #define PARAM1_DEFAULT 4.0 | |||
| #define PARAM2_DEFAULT 3.0 | |||
| #define PARAM3_DEFAULT 6.0 | |||
| //===========================================================================// | |||
| struct vf_priv_s { | |||
| int Coefs[4][512*16]; | |||
| unsigned int *Line; | |||
| unsigned short *Frame[3]; | |||
| }; | |||
| /***************************************************************************/ | |||
| static void uninit(struct vf_instance *vf) | |||
| { | |||
| free(vf->priv->Line); | |||
| free(vf->priv->Frame[0]); | |||
| free(vf->priv->Frame[1]); | |||
| free(vf->priv->Frame[2]); | |||
| vf->priv->Line = NULL; | |||
| vf->priv->Frame[0] = NULL; | |||
| vf->priv->Frame[1] = NULL; | |||
| vf->priv->Frame[2] = NULL; | |||
| } | |||
| static int config(struct vf_instance *vf, | |||
| int width, int height, int d_width, int d_height, | |||
| unsigned int flags, unsigned int outfmt){ | |||
| uninit(vf); | |||
| vf->priv->Line = malloc(width*sizeof(int)); | |||
| return vf_next_config(vf,width,height,d_width,d_height,flags,outfmt); | |||
| } | |||
| static inline unsigned int LowPassMul(unsigned int PrevMul, unsigned int CurrMul, int* Coef){ | |||
| // int dMul= (PrevMul&0xFFFFFF)-(CurrMul&0xFFFFFF); | |||
| int dMul= PrevMul-CurrMul; | |||
| unsigned int d=((dMul+0x10007FF)>>12); | |||
| return CurrMul + Coef[d]; | |||
| } | |||
| static void deNoiseTemporal( | |||
| unsigned char *Frame, // mpi->planes[x] | |||
| unsigned char *FrameDest, // dmpi->planes[x] | |||
| unsigned short *FrameAnt, | |||
| int W, int H, int sStride, int dStride, | |||
| int *Temporal) | |||
| { | |||
| long X, Y; | |||
| unsigned int PixelDst; | |||
| for (Y = 0; Y < H; Y++){ | |||
| for (X = 0; X < W; X++){ | |||
| PixelDst = LowPassMul(FrameAnt[X]<<8, Frame[X]<<16, Temporal); | |||
| FrameAnt[X] = ((PixelDst+0x1000007F)>>8); | |||
| FrameDest[X]= ((PixelDst+0x10007FFF)>>16); | |||
| } | |||
| Frame += sStride; | |||
| FrameDest += dStride; | |||
| FrameAnt += W; | |||
| } | |||
| } | |||
| static void deNoiseSpacial( | |||
| unsigned char *Frame, // mpi->planes[x] | |||
| unsigned char *FrameDest, // dmpi->planes[x] | |||
| unsigned int *LineAnt, // vf->priv->Line (width bytes) | |||
| int W, int H, int sStride, int dStride, | |||
| int *Horizontal, int *Vertical) | |||
| { | |||
| long X, Y; | |||
| long sLineOffs = 0, dLineOffs = 0; | |||
| unsigned int PixelAnt; | |||
| unsigned int PixelDst; | |||
| /* First pixel has no left nor top neighbor. */ | |||
| PixelDst = LineAnt[0] = PixelAnt = Frame[0]<<16; | |||
| FrameDest[0]= ((PixelDst+0x10007FFF)>>16); | |||
| /* First line has no top neighbor, only left. */ | |||
| for (X = 1; X < W; X++){ | |||
| PixelDst = LineAnt[X] = LowPassMul(PixelAnt, Frame[X]<<16, Horizontal); | |||
| FrameDest[X]= ((PixelDst+0x10007FFF)>>16); | |||
| } | |||
| for (Y = 1; Y < H; Y++){ | |||
| unsigned int PixelAnt; | |||
| sLineOffs += sStride, dLineOffs += dStride; | |||
| /* First pixel on each line doesn't have previous pixel */ | |||
| PixelAnt = Frame[sLineOffs]<<16; | |||
| PixelDst = LineAnt[0] = LowPassMul(LineAnt[0], PixelAnt, Vertical); | |||
| FrameDest[dLineOffs]= ((PixelDst+0x10007FFF)>>16); | |||
| for (X = 1; X < W; X++){ | |||
| unsigned int PixelDst; | |||
| /* The rest are normal */ | |||
| PixelAnt = LowPassMul(PixelAnt, Frame[sLineOffs+X]<<16, Horizontal); | |||
| PixelDst = LineAnt[X] = LowPassMul(LineAnt[X], PixelAnt, Vertical); | |||
| FrameDest[dLineOffs+X]= ((PixelDst+0x10007FFF)>>16); | |||
| } | |||
| } | |||
| } | |||
| static void deNoise(unsigned char *Frame, // mpi->planes[x] | |||
| unsigned char *FrameDest, // dmpi->planes[x] | |||
| unsigned int *LineAnt, // vf->priv->Line (width bytes) | |||
| unsigned short **FrameAntPtr, | |||
| int W, int H, int sStride, int dStride, | |||
| int *Horizontal, int *Vertical, int *Temporal) | |||
| { | |||
| long X, Y; | |||
| long sLineOffs = 0, dLineOffs = 0; | |||
| unsigned int PixelAnt; | |||
| unsigned int PixelDst; | |||
| unsigned short* FrameAnt=(*FrameAntPtr); | |||
| if(!FrameAnt){ | |||
| (*FrameAntPtr)=FrameAnt=malloc(W*H*sizeof(unsigned short)); | |||
| for (Y = 0; Y < H; Y++){ | |||
| unsigned short* dst=&FrameAnt[Y*W]; | |||
| unsigned char* src=Frame+Y*sStride; | |||
| for (X = 0; X < W; X++) dst[X]=src[X]<<8; | |||
| } | |||
| } | |||
| if(!Horizontal[0] && !Vertical[0]){ | |||
| deNoiseTemporal(Frame, FrameDest, FrameAnt, | |||
| W, H, sStride, dStride, Temporal); | |||
| return; | |||
| } | |||
| if(!Temporal[0]){ | |||
| deNoiseSpacial(Frame, FrameDest, LineAnt, | |||
| W, H, sStride, dStride, Horizontal, Vertical); | |||
| return; | |||
| } | |||
| /* First pixel has no left nor top neighbor. Only previous frame */ | |||
| LineAnt[0] = PixelAnt = Frame[0]<<16; | |||
| PixelDst = LowPassMul(FrameAnt[0]<<8, PixelAnt, Temporal); | |||
| FrameAnt[0] = ((PixelDst+0x1000007F)>>8); | |||
| FrameDest[0]= ((PixelDst+0x10007FFF)>>16); | |||
| /* First line has no top neighbor. Only left one for each pixel and | |||
| * last frame */ | |||
| for (X = 1; X < W; X++){ | |||
| LineAnt[X] = PixelAnt = LowPassMul(PixelAnt, Frame[X]<<16, Horizontal); | |||
| PixelDst = LowPassMul(FrameAnt[X]<<8, PixelAnt, Temporal); | |||
| FrameAnt[X] = ((PixelDst+0x1000007F)>>8); | |||
| FrameDest[X]= ((PixelDst+0x10007FFF)>>16); | |||
| } | |||
| for (Y = 1; Y < H; Y++){ | |||
| unsigned int PixelAnt; | |||
| unsigned short* LinePrev=&FrameAnt[Y*W]; | |||
| sLineOffs += sStride, dLineOffs += dStride; | |||
| /* First pixel on each line doesn't have previous pixel */ | |||
| PixelAnt = Frame[sLineOffs]<<16; | |||
| LineAnt[0] = LowPassMul(LineAnt[0], PixelAnt, Vertical); | |||
| PixelDst = LowPassMul(LinePrev[0]<<8, LineAnt[0], Temporal); | |||
| LinePrev[0] = ((PixelDst+0x1000007F)>>8); | |||
| FrameDest[dLineOffs]= ((PixelDst+0x10007FFF)>>16); | |||
| for (X = 1; X < W; X++){ | |||
| unsigned int PixelDst; | |||
| /* The rest are normal */ | |||
| PixelAnt = LowPassMul(PixelAnt, Frame[sLineOffs+X]<<16, Horizontal); | |||
| LineAnt[X] = LowPassMul(LineAnt[X], PixelAnt, Vertical); | |||
| PixelDst = LowPassMul(LinePrev[X]<<8, LineAnt[X], Temporal); | |||
| LinePrev[X] = ((PixelDst+0x1000007F)>>8); | |||
| FrameDest[dLineOffs+X]= ((PixelDst+0x10007FFF)>>16); | |||
| } | |||
| } | |||
| } | |||
| static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts){ | |||
| int cw= mpi->w >> mpi->chroma_x_shift; | |||
| int ch= mpi->h >> mpi->chroma_y_shift; | |||
| int W = mpi->w, H = mpi->h; | |||
| mp_image_t *dmpi=vf_get_image(vf->next,mpi->imgfmt, | |||
| MP_IMGTYPE_TEMP, MP_IMGFLAG_ACCEPT_STRIDE, | |||
| mpi->w,mpi->h); | |||
| if(!dmpi) return 0; | |||
| deNoise(mpi->planes[0], dmpi->planes[0], | |||
| vf->priv->Line, &vf->priv->Frame[0], W, H, | |||
| mpi->stride[0], dmpi->stride[0], | |||
| vf->priv->Coefs[0], | |||
| vf->priv->Coefs[0], | |||
| vf->priv->Coefs[1]); | |||
| deNoise(mpi->planes[1], dmpi->planes[1], | |||
| vf->priv->Line, &vf->priv->Frame[1], cw, ch, | |||
| mpi->stride[1], dmpi->stride[1], | |||
| vf->priv->Coefs[2], | |||
| vf->priv->Coefs[2], | |||
| vf->priv->Coefs[3]); | |||
| deNoise(mpi->planes[2], dmpi->planes[2], | |||
| vf->priv->Line, &vf->priv->Frame[2], cw, ch, | |||
| mpi->stride[2], dmpi->stride[2], | |||
| vf->priv->Coefs[2], | |||
| vf->priv->Coefs[2], | |||
| vf->priv->Coefs[3]); | |||
| return vf_next_put_image(vf,dmpi, pts); | |||
| } | |||
| //===========================================================================// | |||
| static int query_format(struct vf_instance *vf, unsigned int fmt){ | |||
| switch(fmt) | |||
| { | |||
| case IMGFMT_YV12: | |||
| case IMGFMT_I420: | |||
| case IMGFMT_IYUV: | |||
| case IMGFMT_YVU9: | |||
| case IMGFMT_444P: | |||
| case IMGFMT_422P: | |||
| case IMGFMT_411P: | |||
| return vf_next_query_format(vf, fmt); | |||
| } | |||
| return 0; | |||
| } | |||
| #define ABS(A) ( (A) > 0 ? (A) : -(A) ) | |||
| static void PrecalcCoefs(int *Ct, double Dist25) | |||
| { | |||
| int i; | |||
| double Gamma, Simil, C; | |||
| Gamma = log(0.25) / log(1.0 - Dist25/255.0 - 0.00001); | |||
| for (i = -255*16; i <= 255*16; i++) | |||
| { | |||
| Simil = 1.0 - ABS(i) / (16*255.0); | |||
| C = pow(Simil, Gamma) * 65536.0 * (double)i / 16.0; | |||
| Ct[16*256+i] = (C<0) ? (C-0.5) : (C+0.5); | |||
| } | |||
| Ct[0] = (Dist25 != 0); | |||
| } | |||
| static int vf_open(vf_instance_t *vf, char *args){ | |||
| double LumSpac, LumTmp, ChromSpac, ChromTmp; | |||
| double Param1, Param2, Param3, Param4; | |||
| vf->config=config; | |||
| vf->put_image=put_image; | |||
| vf->query_format=query_format; | |||
| vf->uninit=uninit; | |||
| vf->priv=malloc(sizeof(struct vf_priv_s)); | |||
| memset(vf->priv, 0, sizeof(struct vf_priv_s)); | |||
| if (args) | |||
| { | |||
| switch(sscanf(args, "%lf:%lf:%lf:%lf", | |||
| &Param1, &Param2, &Param3, &Param4 | |||
| )) | |||
| { | |||
| case 0: | |||
| LumSpac = PARAM1_DEFAULT; | |||
| LumTmp = PARAM3_DEFAULT; | |||
| ChromSpac = PARAM2_DEFAULT; | |||
| ChromTmp = LumTmp * ChromSpac / LumSpac; | |||
| break; | |||
| case 1: | |||
| LumSpac = Param1; | |||
| LumTmp = PARAM3_DEFAULT * Param1 / PARAM1_DEFAULT; | |||
| ChromSpac = PARAM2_DEFAULT * Param1 / PARAM1_DEFAULT; | |||
| ChromTmp = LumTmp * ChromSpac / LumSpac; | |||
| break; | |||
| case 2: | |||
| LumSpac = Param1; | |||
| LumTmp = PARAM3_DEFAULT * Param1 / PARAM1_DEFAULT; | |||
| ChromSpac = Param2; | |||
| ChromTmp = LumTmp * ChromSpac / LumSpac; | |||
| break; | |||
| case 3: | |||
| LumSpac = Param1; | |||
| LumTmp = Param3; | |||
| ChromSpac = Param2; | |||
| ChromTmp = LumTmp * ChromSpac / LumSpac; | |||
| break; | |||
| case 4: | |||
| LumSpac = Param1; | |||
| LumTmp = Param3; | |||
| ChromSpac = Param2; | |||
| ChromTmp = Param4; | |||
| break; | |||
| default: | |||
| LumSpac = PARAM1_DEFAULT; | |||
| LumTmp = PARAM3_DEFAULT; | |||
| ChromSpac = PARAM2_DEFAULT; | |||
| ChromTmp = LumTmp * ChromSpac / LumSpac; | |||
| } | |||
| } | |||
| else | |||
| { | |||
| LumSpac = PARAM1_DEFAULT; | |||
| LumTmp = PARAM3_DEFAULT; | |||
| ChromSpac = PARAM2_DEFAULT; | |||
| ChromTmp = LumTmp * ChromSpac / LumSpac; | |||
| } | |||
| PrecalcCoefs(vf->priv->Coefs[0], LumSpac); | |||
| PrecalcCoefs(vf->priv->Coefs[1], LumTmp); | |||
| PrecalcCoefs(vf->priv->Coefs[2], ChromSpac); | |||
| PrecalcCoefs(vf->priv->Coefs[3], ChromTmp); | |||
| return 1; | |||
| } | |||
| const vf_info_t vf_info_hqdn3d = { | |||
| "High Quality 3D Denoiser", | |||
| "hqdn3d", | |||
| "Daniel Moreno & A'rpi", | |||
| "", | |||
| vf_open, | |||
| NULL | |||
| }; | |||
| //===========================================================================// | |||
| @@ -0,0 +1,200 @@ | |||
| /* | |||
| * This file is part of MPlayer. | |||
| * | |||
| * MPlayer 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. | |||
| * | |||
| * MPlayer 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 MPlayer; if not, write to the Free Software Foundation, Inc., | |||
| * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | |||
| */ | |||
| #include <stdio.h> | |||
| #include <stdlib.h> | |||
| #include <string.h> | |||
| #include <inttypes.h> | |||
| #include <math.h> | |||
| #include "config.h" | |||
| #include "mp_msg.h" | |||
| #include "cpudetect.h" | |||
| #include "img_format.h" | |||
| #include "mp_image.h" | |||
| #include "vf.h" | |||
| #include "libvo/video_out.h" | |||
| #include "m_option.h" | |||
| #include "m_struct.h" | |||
| static struct vf_priv_s { | |||
| uint8_t *buf[2]; | |||
| float hue; | |||
| float saturation; | |||
| } const vf_priv_dflt = { | |||
| {NULL, NULL}, | |||
| 0.0, | |||
| 1.0, | |||
| }; | |||
| static void process_C(uint8_t *udst, uint8_t *vdst, uint8_t *usrc, uint8_t *vsrc, int dststride, int srcstride, | |||
| int w, int h, float hue, float sat) | |||
| { | |||
| int i; | |||
| const int s= rint(sin(hue) * (1<<16) * sat); | |||
| const int c= rint(cos(hue) * (1<<16) * sat); | |||
| while (h--) { | |||
| for (i = 0; i<w; i++) | |||
| { | |||
| const int u= usrc[i] - 128; | |||
| const int v= vsrc[i] - 128; | |||
| int new_u= (c*u - s*v + (1<<15) + (128<<16))>>16; | |||
| int new_v= (s*u + c*v + (1<<15) + (128<<16))>>16; | |||
| if(new_u & 768) new_u= (-new_u)>>31; | |||
| if(new_v & 768) new_v= (-new_v)>>31; | |||
| udst[i]= new_u; | |||
| vdst[i]= new_v; | |||
| } | |||
| usrc += srcstride; | |||
| vsrc += srcstride; | |||
| udst += dststride; | |||
| vdst += dststride; | |||
| } | |||
| } | |||
| static void (*process)(uint8_t *udst, uint8_t *vdst, uint8_t *usrc, uint8_t *vsrc, int dststride, int srcstride, | |||
| int w, int h, float hue, float sat); | |||
| /* FIXME: add packed yuv version of process */ | |||
| static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts) | |||
| { | |||
| mp_image_t *dmpi; | |||
| dmpi=vf_get_image(vf->next, mpi->imgfmt, | |||
| MP_IMGTYPE_EXPORT, 0, | |||
| mpi->w, mpi->h); | |||
| dmpi->planes[0] = mpi->planes[0]; | |||
| dmpi->stride[0] = mpi->stride[0]; | |||
| dmpi->stride[1] = mpi->stride[1]; | |||
| dmpi->stride[2] = mpi->stride[2]; | |||
| if (!vf->priv->buf[0]){ | |||
| vf->priv->buf[0] = malloc(mpi->stride[1]*mpi->h >> mpi->chroma_y_shift); | |||
| vf->priv->buf[1] = malloc(mpi->stride[2]*mpi->h >> mpi->chroma_y_shift); | |||
| } | |||
| if (vf->priv->hue == 0 && vf->priv->saturation == 1){ | |||
| dmpi->planes[1] = mpi->planes[1]; | |||
| dmpi->planes[2] = mpi->planes[2]; | |||
| }else { | |||
| dmpi->planes[1] = vf->priv->buf[0]; | |||
| dmpi->planes[2] = vf->priv->buf[1]; | |||
| process(dmpi->planes[1], dmpi->planes[2], | |||
| mpi->planes[1], mpi->planes[2], | |||
| dmpi->stride[1],mpi->stride[1], | |||
| mpi->w>> mpi->chroma_x_shift, mpi->h>> mpi->chroma_y_shift, | |||
| vf->priv->hue, vf->priv->saturation); | |||
| } | |||
| return vf_next_put_image(vf,dmpi, pts); | |||
| } | |||
| static int control(struct vf_instance *vf, int request, void* data) | |||
| { | |||
| vf_equalizer_t *eq; | |||
| switch (request) { | |||
| case VFCTRL_SET_EQUALIZER: | |||
| eq = data; | |||
| if (!strcmp(eq->item,"hue")) { | |||
| vf->priv->hue = eq->value * M_PI / 100; | |||
| return CONTROL_TRUE; | |||
| } else if (!strcmp(eq->item,"saturation")) { | |||
| vf->priv->saturation = (eq->value + 100)/100.0; | |||
| return CONTROL_TRUE; | |||
| } | |||
| break; | |||
| case VFCTRL_GET_EQUALIZER: | |||
| eq = data; | |||
| if (!strcmp(eq->item,"hue")) { | |||
| eq->value = rint(vf->priv->hue *100 / M_PI); | |||
| return CONTROL_TRUE; | |||
| }else if (!strcmp(eq->item,"saturation")) { | |||
| eq->value = rint(vf->priv->saturation*100 - 100); | |||
| return CONTROL_TRUE; | |||
| } | |||
| break; | |||
| } | |||
| return vf_next_control(vf, request, data); | |||
| } | |||
| static int query_format(struct vf_instance *vf, unsigned int fmt) | |||
| { | |||
| switch (fmt) { | |||
| case IMGFMT_YVU9: | |||
| case IMGFMT_IF09: | |||
| case IMGFMT_YV12: | |||
| case IMGFMT_I420: | |||
| case IMGFMT_IYUV: | |||
| case IMGFMT_CLPL: | |||
| case IMGFMT_444P: | |||
| case IMGFMT_422P: | |||
| case IMGFMT_411P: | |||
| return vf_next_query_format(vf, fmt); | |||
| } | |||
| return 0; | |||
| } | |||
| static void uninit(struct vf_instance *vf) | |||
| { | |||
| free(vf->priv->buf[0]); | |||
| free(vf->priv->buf[1]); | |||
| free(vf->priv); | |||
| } | |||
| static int vf_open(vf_instance_t *vf, char *args) | |||
| { | |||
| vf->control=control; | |||
| vf->query_format=query_format; | |||
| vf->put_image=put_image; | |||
| vf->uninit=uninit; | |||
| vf->priv->hue *= M_PI / 180.0; | |||
| process = process_C; | |||
| return 1; | |||
| } | |||
| #define ST_OFF(f) M_ST_OFF(struct vf_priv_s,f) | |||
| static const m_option_t vf_opts_fields[] = { | |||
| {"hue", ST_OFF(hue), CONF_TYPE_FLOAT, M_OPT_RANGE,-180.0 ,180.0, NULL}, | |||
| {"saturation", ST_OFF(saturation), CONF_TYPE_FLOAT, M_OPT_RANGE,-10.0 ,10.0, NULL}, | |||
| { NULL, NULL, 0, 0, 0, 0, NULL } | |||
| }; | |||
| static const m_struct_t vf_opts = { | |||
| "hue", | |||
| sizeof(struct vf_priv_s), | |||
| &vf_priv_dflt, | |||
| vf_opts_fields | |||
| }; | |||
| const vf_info_t vf_info_hue = { | |||
| "hue changer", | |||
| "hue", | |||
| "Michael Niedermayer", | |||
| "", | |||
| vf_open, | |||
| &vf_opts | |||
| }; | |||
| @@ -0,0 +1,148 @@ | |||
| /* | |||
| * Copyright (C) 2002 Michael Niedermayer <michaelni@gmx.at> | |||
| * | |||
| * This file is part of MPlayer. | |||
| * | |||
| * MPlayer 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. | |||
| * | |||
| * MPlayer 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 MPlayer; if not, write to the Free Software Foundation, Inc., | |||
| * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | |||
| */ | |||
| #include <stdio.h> | |||
| #include <stdlib.h> | |||
| #include <string.h> | |||
| #include <inttypes.h> | |||
| #include <assert.h> | |||
| #include "mp_msg.h" | |||
| #include "img_format.h" | |||
| #include "mp_image.h" | |||
| #include "vf.h" | |||
| #include "libvo/fastmemcpy.h" | |||
| //===========================================================================// | |||
| typedef struct FilterParam{ | |||
| int interleave; | |||
| int swap; | |||
| }FilterParam; | |||
| struct vf_priv_s { | |||
| FilterParam lumaParam; | |||
| FilterParam chromaParam; | |||
| }; | |||
| /***************************************************************************/ | |||
| static void interleave(uint8_t *dst, uint8_t *src, int w, int h, int dstStride, int srcStride, int interleave, int swap){ | |||
| const int a= swap; | |||
| const int b= 1-a; | |||
| const int m= h>>1; | |||
| int y; | |||
| switch(interleave){ | |||
| case -1: | |||
| for(y=0; y < m; y++){ | |||
| fast_memcpy(dst + dstStride* y , src + srcStride*(y*2 + a), w); | |||
| fast_memcpy(dst + dstStride*(y + m), src + srcStride*(y*2 + b), w); | |||
| } | |||
| break; | |||
| case 0: | |||
| for(y=0; y < m; y++){ | |||
| fast_memcpy(dst + dstStride* y*2 , src + srcStride*(y*2 + a), w); | |||
| fast_memcpy(dst + dstStride*(y*2+1), src + srcStride*(y*2 + b), w); | |||
| } | |||
| break; | |||
| case 1: | |||
| for(y=0; y < m; y++){ | |||
| fast_memcpy(dst + dstStride*(y*2+a), src + srcStride* y , w); | |||
| fast_memcpy(dst + dstStride*(y*2+b), src + srcStride*(y + m), w); | |||
| } | |||
| break; | |||
| } | |||
| } | |||
| static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts){ | |||
| int w; | |||
| FilterParam *luma = &vf->priv->lumaParam; | |||
| FilterParam *chroma= &vf->priv->chromaParam; | |||
| mp_image_t *dmpi=vf_get_image(vf->next,mpi->imgfmt, | |||
| MP_IMGTYPE_TEMP, MP_IMGFLAG_ACCEPT_STRIDE, | |||
| mpi->w,mpi->h); | |||
| if(mpi->flags&MP_IMGFLAG_PLANAR) | |||
| w= mpi->w; | |||
| else | |||
| w= mpi->w * mpi->bpp/8; | |||
| interleave(dmpi->planes[0], mpi->planes[0], | |||
| w, mpi->h, dmpi->stride[0], mpi->stride[0], luma->interleave, luma->swap); | |||
| if(mpi->flags&MP_IMGFLAG_PLANAR){ | |||
| int cw= mpi->w >> mpi->chroma_x_shift; | |||
| int ch= mpi->h >> mpi->chroma_y_shift; | |||
| interleave(dmpi->planes[1], mpi->planes[1], cw,ch, | |||
| dmpi->stride[1], mpi->stride[1], chroma->interleave, luma->swap); | |||
| interleave(dmpi->planes[2], mpi->planes[2], cw,ch, | |||
| dmpi->stride[2], mpi->stride[2], chroma->interleave, luma->swap); | |||
| } | |||
| return vf_next_put_image(vf,dmpi, pts); | |||
| } | |||
| //===========================================================================// | |||
| static void parse(FilterParam *fp, char* args){ | |||
| char *pos; | |||
| char *max= strchr(args, ':'); | |||
| if(!max) max= args + strlen(args); | |||
| pos= strchr(args, 's'); | |||
| if(pos && pos<max) fp->swap=1; | |||
| pos= strchr(args, 'i'); | |||
| if(pos && pos<max) fp->interleave=1; | |||
| pos= strchr(args, 'd'); | |||
| if(pos && pos<max) fp->interleave=-1; | |||
| } | |||
| static int vf_open(vf_instance_t *vf, char *args){ | |||
| vf->put_image=put_image; | |||
| // vf->get_image=get_image; | |||
| vf->priv=malloc(sizeof(struct vf_priv_s)); | |||
| memset(vf->priv, 0, sizeof(struct vf_priv_s)); | |||
| if(args) | |||
| { | |||
| char *arg2= strchr(args,':'); | |||
| if(arg2) parse(&vf->priv->chromaParam, arg2+1); | |||
| parse(&vf->priv->lumaParam, args); | |||
| } | |||
| return 1; | |||
| } | |||
| const vf_info_t vf_info_il = { | |||
| "(de)interleave", | |||
| "il", | |||
| "Michael Niedermayer", | |||
| "", | |||
| vf_open, | |||
| NULL | |||
| }; | |||
| //===========================================================================// | |||
| @@ -0,0 +1,453 @@ | |||
| /* | |||
| * This file is part of MPlayer. | |||
| * | |||
| * MPlayer 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. | |||
| * | |||
| * MPlayer 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 MPlayer; if not, write to the Free Software Foundation, Inc., | |||
| * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | |||
| */ | |||
| #include <stdio.h> | |||
| #include <stdlib.h> | |||
| #include <string.h> | |||
| #include <inttypes.h> | |||
| #include "config.h" | |||
| #include "mp_msg.h" | |||
| #include "cpudetect.h" | |||
| #include "img_format.h" | |||
| #include "mp_image.h" | |||
| #include "vf.h" | |||
| typedef void (pack_func_t)(unsigned char *dst, unsigned char *y, | |||
| unsigned char *u, unsigned char *v, int w, int us, int vs); | |||
| struct vf_priv_s { | |||
| int mode; | |||
| pack_func_t *pack[2]; | |||
| }; | |||
| static void pack_nn_C(unsigned char *dst, unsigned char *y, | |||
| unsigned char *u, unsigned char *v, int w) | |||
| { | |||
| int j; | |||
| for (j = w/2; j; j--) { | |||
| *dst++ = *y++; | |||
| *dst++ = *u++; | |||
| *dst++ = *y++; | |||
| *dst++ = *v++; | |||
| } | |||
| } | |||
| static void pack_li_0_C(unsigned char *dst, unsigned char *y, | |||
| unsigned char *u, unsigned char *v, int w, int us, int vs) | |||
| { | |||
| int j; | |||
| for (j = w/2; j; j--) { | |||
| *dst++ = *y++; | |||
| *dst++ = (u[us+us] + 7*u[0])>>3; | |||
| *dst++ = *y++; | |||
| *dst++ = (v[vs+vs] + 7*v[0])>>3; | |||
| u++; v++; | |||
| } | |||
| } | |||
| static void pack_li_1_C(unsigned char *dst, unsigned char *y, | |||
| unsigned char *u, unsigned char *v, int w, int us, int vs) | |||
| { | |||
| int j; | |||
| for (j = w/2; j; j--) { | |||
| *dst++ = *y++; | |||
| *dst++ = (3*u[us+us] + 5*u[0])>>3; | |||
| *dst++ = *y++; | |||
| *dst++ = (3*v[vs+vs] + 5*v[0])>>3; | |||
| u++; v++; | |||
| } | |||
| } | |||
| #if HAVE_MMX | |||
| static void pack_nn_MMX(unsigned char *dst, unsigned char *y, | |||
| unsigned char *u, unsigned char *v, int w) | |||
| { | |||
| __asm__ volatile ("" | |||
| ASMALIGN(4) | |||
| "1: \n\t" | |||
| "movq (%0), %%mm1 \n\t" | |||
| "movq (%0), %%mm2 \n\t" | |||
| "movq (%1), %%mm4 \n\t" | |||
| "movq (%2), %%mm6 \n\t" | |||
| "punpcklbw %%mm6, %%mm4 \n\t" | |||
| "punpcklbw %%mm4, %%mm1 \n\t" | |||
| "punpckhbw %%mm4, %%mm2 \n\t" | |||
| "add $8, %0 \n\t" | |||
| "add $4, %1 \n\t" | |||
| "add $4, %2 \n\t" | |||
| "movq %%mm1, (%3) \n\t" | |||
| "movq %%mm2, 8(%3) \n\t" | |||
| "add $16, %3 \n\t" | |||
| "decl %4 \n\t" | |||
| "jnz 1b \n\t" | |||
| "emms \n\t" | |||
| : | |||
| : "r" (y), "r" (u), "r" (v), "r" (dst), "r" (w/8) | |||
| : "memory" | |||
| ); | |||
| pack_nn_C(dst, y, u, v, (w&7)); | |||
| } | |||
| #if HAVE_EBX_AVAILABLE | |||
| static void pack_li_0_MMX(unsigned char *dst, unsigned char *y, | |||
| unsigned char *u, unsigned char *v, int w, int us, int vs) | |||
| { | |||
| __asm__ volatile ("" | |||
| "push %%"REG_BP" \n\t" | |||
| #if ARCH_X86_64 | |||
| "mov %6, %%"REG_BP" \n\t" | |||
| #else | |||
| "movl 4(%%"REG_d"), %%"REG_BP" \n\t" | |||
| "movl (%%"REG_d"), %%"REG_d" \n\t" | |||
| #endif | |||
| "pxor %%mm0, %%mm0 \n\t" | |||
| ASMALIGN(4) | |||
| ".Lli0: \n\t" | |||
| "movq (%%"REG_S"), %%mm1 \n\t" | |||
| "movq (%%"REG_S"), %%mm2 \n\t" | |||
| "movq (%%"REG_a",%%"REG_d",2), %%mm4 \n\t" | |||
| "movq (%%"REG_b",%%"REG_BP",2), %%mm6 \n\t" | |||
| "punpcklbw %%mm0, %%mm4 \n\t" | |||
| "punpcklbw %%mm0, %%mm6 \n\t" | |||
| "movq (%%"REG_a"), %%mm3 \n\t" | |||
| "movq (%%"REG_b"), %%mm5 \n\t" | |||
| "punpcklbw %%mm0, %%mm3 \n\t" | |||
| "punpcklbw %%mm0, %%mm5 \n\t" | |||
| "paddw %%mm3, %%mm4 \n\t" | |||
| "paddw %%mm5, %%mm6 \n\t" | |||
| "paddw %%mm3, %%mm4 \n\t" | |||
| "paddw %%mm5, %%mm6 \n\t" | |||
| "paddw %%mm3, %%mm4 \n\t" | |||
| "paddw %%mm5, %%mm6 \n\t" | |||
| "paddw %%mm3, %%mm4 \n\t" | |||
| "paddw %%mm5, %%mm6 \n\t" | |||
| "paddw %%mm3, %%mm4 \n\t" | |||
| "paddw %%mm5, %%mm6 \n\t" | |||
| "paddw %%mm3, %%mm4 \n\t" | |||
| "paddw %%mm5, %%mm6 \n\t" | |||
| "paddw %%mm3, %%mm4 \n\t" | |||
| "paddw %%mm5, %%mm6 \n\t" | |||
| "psrlw $3, %%mm4 \n\t" | |||
| "psrlw $3, %%mm6 \n\t" | |||
| "packuswb %%mm4, %%mm4 \n\t" | |||
| "packuswb %%mm6, %%mm6 \n\t" | |||
| "punpcklbw %%mm6, %%mm4 \n\t" | |||
| "punpcklbw %%mm4, %%mm1 \n\t" | |||
| "punpckhbw %%mm4, %%mm2 \n\t" | |||
| "movq %%mm1, (%%"REG_D") \n\t" | |||
| "movq %%mm2, 8(%%"REG_D") \n\t" | |||
| "movq 8(%%"REG_S"), %%mm1 \n\t" | |||
| "movq 8(%%"REG_S"), %%mm2 \n\t" | |||
| "movq (%%"REG_a",%%"REG_d",2), %%mm4 \n\t" | |||
| "movq (%%"REG_b",%%"REG_BP",2), %%mm6 \n\t" | |||
| "punpckhbw %%mm0, %%mm4 \n\t" | |||
| "punpckhbw %%mm0, %%mm6 \n\t" | |||
| "movq (%%"REG_a"), %%mm3 \n\t" | |||
| "movq (%%"REG_b"), %%mm5 \n\t" | |||
| "punpckhbw %%mm0, %%mm3 \n\t" | |||
| "punpckhbw %%mm0, %%mm5 \n\t" | |||
| "paddw %%mm3, %%mm4 \n\t" | |||
| "paddw %%mm5, %%mm6 \n\t" | |||
| "paddw %%mm3, %%mm4 \n\t" | |||
| "paddw %%mm5, %%mm6 \n\t" | |||
| "paddw %%mm3, %%mm4 \n\t" | |||
| "paddw %%mm5, %%mm6 \n\t" | |||
| "paddw %%mm3, %%mm4 \n\t" | |||
| "paddw %%mm5, %%mm6 \n\t" | |||
| "paddw %%mm3, %%mm4 \n\t" | |||
| "paddw %%mm5, %%mm6 \n\t" | |||
| "paddw %%mm3, %%mm4 \n\t" | |||
| "paddw %%mm5, %%mm6 \n\t" | |||
| "paddw %%mm3, %%mm4 \n\t" | |||
| "paddw %%mm5, %%mm6 \n\t" | |||
| "psrlw $3, %%mm4 \n\t" | |||
| "psrlw $3, %%mm6 \n\t" | |||
| "packuswb %%mm4, %%mm4 \n\t" | |||
| "packuswb %%mm6, %%mm6 \n\t" | |||
| "punpcklbw %%mm6, %%mm4 \n\t" | |||
| "punpcklbw %%mm4, %%mm1 \n\t" | |||
| "punpckhbw %%mm4, %%mm2 \n\t" | |||
| "add $16, %%"REG_S" \n\t" | |||
| "add $8, %%"REG_a" \n\t" | |||
| "add $8, %%"REG_b" \n\t" | |||
| "movq %%mm1, 16(%%"REG_D") \n\t" | |||
| "movq %%mm2, 24(%%"REG_D") \n\t" | |||
| "add $32, %%"REG_D" \n\t" | |||
| "decl %%ecx \n\t" | |||
| "jnz .Lli0 \n\t" | |||
| "emms \n\t" | |||
| "pop %%"REG_BP" \n\t" | |||
| : | |||
| : "S" (y), "D" (dst), "a" (u), "b" (v), "c" (w/16), | |||
| #if ARCH_X86_64 | |||
| "d" ((x86_reg)us), "r" ((x86_reg)vs) | |||
| #else | |||
| "d" (&us) | |||
| #endif | |||
| : "memory" | |||
| ); | |||
| pack_li_0_C(dst, y, u, v, (w&15), us, vs); | |||
| } | |||
| static void pack_li_1_MMX(unsigned char *dst, unsigned char *y, | |||
| unsigned char *u, unsigned char *v, int w, int us, int vs) | |||
| { | |||
| __asm__ volatile ("" | |||
| "push %%"REG_BP" \n\t" | |||
| #if ARCH_X86_64 | |||
| "mov %6, %%"REG_BP" \n\t" | |||
| #else | |||
| "movl 4(%%"REG_d"), %%"REG_BP" \n\t" | |||
| "movl (%%"REG_d"), %%"REG_d" \n\t" | |||
| #endif | |||
| "pxor %%mm0, %%mm0 \n\t" | |||
| ASMALIGN(4) | |||
| ".Lli1: \n\t" | |||
| "movq (%%"REG_S"), %%mm1 \n\t" | |||
| "movq (%%"REG_S"), %%mm2 \n\t" | |||
| "movq (%%"REG_a",%%"REG_d",2), %%mm4 \n\t" | |||
| "movq (%%"REG_b",%%"REG_BP",2), %%mm6 \n\t" | |||
| "punpcklbw %%mm0, %%mm4 \n\t" | |||
| "punpcklbw %%mm0, %%mm6 \n\t" | |||
| "movq (%%"REG_a"), %%mm3 \n\t" | |||
| "movq (%%"REG_b"), %%mm5 \n\t" | |||
| "punpcklbw %%mm0, %%mm3 \n\t" | |||
| "punpcklbw %%mm0, %%mm5 \n\t" | |||
| "movq %%mm4, %%mm7 \n\t" | |||
| "paddw %%mm4, %%mm4 \n\t" | |||
| "paddw %%mm7, %%mm4 \n\t" | |||
| "movq %%mm6, %%mm7 \n\t" | |||
| "paddw %%mm6, %%mm6 \n\t" | |||
| "paddw %%mm7, %%mm6 \n\t" | |||
| "paddw %%mm3, %%mm4 \n\t" | |||
| "paddw %%mm5, %%mm6 \n\t" | |||
| "paddw %%mm3, %%mm4 \n\t" | |||
| "paddw %%mm5, %%mm6 \n\t" | |||
| "paddw %%mm3, %%mm4 \n\t" | |||
| "paddw %%mm5, %%mm6 \n\t" | |||
| "paddw %%mm3, %%mm4 \n\t" | |||
| "paddw %%mm5, %%mm6 \n\t" | |||
| "paddw %%mm3, %%mm4 \n\t" | |||
| "paddw %%mm5, %%mm6 \n\t" | |||
| "psrlw $3, %%mm4 \n\t" | |||
| "psrlw $3, %%mm6 \n\t" | |||
| "packuswb %%mm4, %%mm4 \n\t" | |||
| "packuswb %%mm6, %%mm6 \n\t" | |||
| "punpcklbw %%mm6, %%mm4 \n\t" | |||
| "punpcklbw %%mm4, %%mm1 \n\t" | |||
| "punpckhbw %%mm4, %%mm2 \n\t" | |||
| "movq %%mm1, (%%"REG_D") \n\t" | |||
| "movq %%mm2, 8(%%"REG_D") \n\t" | |||
| "movq 8(%%"REG_S"), %%mm1 \n\t" | |||
| "movq 8(%%"REG_S"), %%mm2 \n\t" | |||
| "movq (%%"REG_a",%%"REG_d",2), %%mm4 \n\t" | |||
| "movq (%%"REG_b",%%"REG_BP",2), %%mm6 \n\t" | |||
| "punpckhbw %%mm0, %%mm4 \n\t" | |||
| "punpckhbw %%mm0, %%mm6 \n\t" | |||
| "movq (%%"REG_a"), %%mm3 \n\t" | |||
| "movq (%%"REG_b"), %%mm5 \n\t" | |||
| "punpckhbw %%mm0, %%mm3 \n\t" | |||
| "punpckhbw %%mm0, %%mm5 \n\t" | |||
| "movq %%mm4, %%mm7 \n\t" | |||
| "paddw %%mm4, %%mm4 \n\t" | |||
| "paddw %%mm7, %%mm4 \n\t" | |||
| "movq %%mm6, %%mm7 \n\t" | |||
| "paddw %%mm6, %%mm6 \n\t" | |||
| "paddw %%mm7, %%mm6 \n\t" | |||
| "paddw %%mm3, %%mm4 \n\t" | |||
| "paddw %%mm5, %%mm6 \n\t" | |||
| "paddw %%mm3, %%mm4 \n\t" | |||
| "paddw %%mm5, %%mm6 \n\t" | |||
| "paddw %%mm3, %%mm4 \n\t" | |||
| "paddw %%mm5, %%mm6 \n\t" | |||
| "paddw %%mm3, %%mm4 \n\t" | |||
| "paddw %%mm5, %%mm6 \n\t" | |||
| "paddw %%mm3, %%mm4 \n\t" | |||
| "paddw %%mm5, %%mm6 \n\t" | |||
| "psrlw $3, %%mm4 \n\t" | |||
| "psrlw $3, %%mm6 \n\t" | |||
| "packuswb %%mm4, %%mm4 \n\t" | |||
| "packuswb %%mm6, %%mm6 \n\t" | |||
| "punpcklbw %%mm6, %%mm4 \n\t" | |||
| "punpcklbw %%mm4, %%mm1 \n\t" | |||
| "punpckhbw %%mm4, %%mm2 \n\t" | |||
| "add $16, %%"REG_S" \n\t" | |||
| "add $8, %%"REG_a" \n\t" | |||
| "add $8, %%"REG_b" \n\t" | |||
| "movq %%mm1, 16(%%"REG_D") \n\t" | |||
| "movq %%mm2, 24(%%"REG_D") \n\t" | |||
| "add $32, %%"REG_D" \n\t" | |||
| "decl %%ecx \n\t" | |||
| "jnz .Lli1 \n\t" | |||
| "emms \n\t" | |||
| "pop %%"REG_BP" \n\t" | |||
| : | |||
| : "S" (y), "D" (dst), "a" (u), "b" (v), "c" (w/16), | |||
| #if ARCH_X86_64 | |||
| "d" ((x86_reg)us), "r" ((x86_reg)vs) | |||
| #else | |||
| "d" (&us) | |||
| #endif | |||
| : "memory" | |||
| ); | |||
| pack_li_1_C(dst, y, u, v, (w&15), us, vs); | |||
| } | |||
| #endif /* HAVE_EBX_AVAILABLE */ | |||
| #endif | |||
| static pack_func_t *pack_nn; | |||
| static pack_func_t *pack_li_0; | |||
| static pack_func_t *pack_li_1; | |||
| static void ilpack(unsigned char *dst, unsigned char *src[3], | |||
| int dststride, int srcstride[3], int w, int h, pack_func_t *pack[2]) | |||
| { | |||
| int i; | |||
| unsigned char *y, *u, *v; | |||
| int ys = srcstride[0], us = srcstride[1], vs = srcstride[2]; | |||
| int a, b; | |||
| y = src[0]; | |||
| u = src[1]; | |||
| v = src[2]; | |||
| pack_nn(dst, y, u, v, w, 0, 0); | |||
| y += ys; dst += dststride; | |||
| pack_nn(dst, y, u+us, v+vs, w, 0, 0); | |||
| y += ys; dst += dststride; | |||
| for (i=2; i<h-2; i++) { | |||
| a = (i&2) ? 1 : -1; | |||
| b = (i&1) ^ ((i&2)>>1); | |||
| pack[b](dst, y, u, v, w, us*a, vs*a); | |||
| y += ys; | |||
| if ((i&3) == 1) { | |||
| u -= us; | |||
| v -= vs; | |||
| } else { | |||
| u += us; | |||
| v += vs; | |||
| } | |||
| dst += dststride; | |||
| } | |||
| pack_nn(dst, y, u, v, w, 0, 0); | |||
| y += ys; dst += dststride; u += us; v += vs; | |||
| pack_nn(dst, y, u, v, w, 0, 0); | |||
| } | |||
| static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts) | |||
| { | |||
| mp_image_t *dmpi; | |||
| // hope we'll get DR buffer: | |||
| dmpi=vf_get_image(vf->next, IMGFMT_YUY2, | |||
| MP_IMGTYPE_TEMP, MP_IMGFLAG_ACCEPT_STRIDE, | |||
| mpi->w, mpi->h); | |||
| ilpack(dmpi->planes[0], mpi->planes, dmpi->stride[0], mpi->stride, mpi->w, mpi->h, vf->priv->pack); | |||
| return vf_next_put_image(vf,dmpi, pts); | |||
| } | |||
| static int config(struct vf_instance *vf, | |||
| int width, int height, int d_width, int d_height, | |||
| unsigned int flags, unsigned int outfmt) | |||
| { | |||
| /* FIXME - also support UYVY output? */ | |||
| return vf_next_config(vf, width, height, d_width, d_height, flags, IMGFMT_YUY2); | |||
| } | |||
| static int query_format(struct vf_instance *vf, unsigned int fmt) | |||
| { | |||
| /* FIXME - really any YUV 4:2:0 input format should work */ | |||
| switch (fmt) { | |||
| case IMGFMT_YV12: | |||
| case IMGFMT_IYUV: | |||
| case IMGFMT_I420: | |||
| return vf_next_query_format(vf,IMGFMT_YUY2); | |||
| } | |||
| return 0; | |||
| } | |||
| static int vf_open(vf_instance_t *vf, char *args) | |||
| { | |||
| vf->config=config; | |||
| vf->query_format=query_format; | |||
| vf->put_image=put_image; | |||
| vf->priv = calloc(1, sizeof(struct vf_priv_s)); | |||
| vf->priv->mode = 1; | |||
| if (args) sscanf(args, "%d", &vf->priv->mode); | |||
| pack_nn = (pack_func_t *)pack_nn_C; | |||
| pack_li_0 = pack_li_0_C; | |||
| pack_li_1 = pack_li_1_C; | |||
| #if HAVE_MMX | |||
| if(gCpuCaps.hasMMX) { | |||
| pack_nn = (pack_func_t *)pack_nn_MMX; | |||
| #if HAVE_EBX_AVAILABLE | |||
| pack_li_0 = pack_li_0_MMX; | |||
| pack_li_1 = pack_li_1_MMX; | |||
| #endif | |||
| } | |||
| #endif | |||
| switch(vf->priv->mode) { | |||
| case 0: | |||
| vf->priv->pack[0] = vf->priv->pack[1] = pack_nn; | |||
| break; | |||
| default: | |||
| mp_msg(MSGT_VFILTER, MSGL_WARN, | |||
| "ilpack: unknown mode %d (fallback to linear)\n", | |||
| vf->priv->mode); | |||
| case 1: | |||
| vf->priv->pack[0] = pack_li_0; | |||
| vf->priv->pack[1] = pack_li_1; | |||
| break; | |||
| } | |||
| return 1; | |||
| } | |||
| const vf_info_t vf_info_ilpack = { | |||
| "4:2:0 planar -> 4:2:2 packed reinterlacer", | |||
| "ilpack", | |||
| "Richard Felker", | |||
| "", | |||
| vf_open, | |||
| NULL | |||
| }; | |||
| @@ -0,0 +1,550 @@ | |||
| /* | |||
| * This file is part of MPlayer. | |||
| * | |||
| * MPlayer 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. | |||
| * | |||
| * MPlayer 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 MPlayer; if not, write to the Free Software Foundation, Inc., | |||
| * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | |||
| */ | |||
| #include <stdio.h> | |||
| #include <stdlib.h> | |||
| #include <string.h> | |||
| #include "config.h" | |||
| #include "mp_msg.h" | |||
| #include "cpudetect.h" | |||
| #include "img_format.h" | |||
| #include "mp_image.h" | |||
| #include "vf.h" | |||
| #include "libvo/fastmemcpy.h" | |||
| struct metrics { | |||
| /* difference: total, even lines, odd lines */ | |||
| int d, e, o; | |||
| /* noise: temporal, spacial (current), spacial (past) */ | |||
| int t, s, p; | |||
| }; | |||
| struct frameinfo { | |||
| /* peak, relative, mean */ | |||
| struct metrics p, r, m; | |||
| }; | |||
| struct vf_priv_s { | |||
| struct frameinfo fi[2]; | |||
| mp_image_t *dmpi; | |||
| int first; | |||
| int drop, lastdrop, dropnext; | |||
| int inframes, outframes; | |||
| }; | |||
| enum { | |||
| F_DROP, | |||
| F_MERGE, | |||
| F_NEXT, | |||
| F_SHOW | |||
| }; | |||
| #if HAVE_MMX && HAVE_EBX_AVAILABLE | |||
| static void block_diffs_MMX(struct metrics *m, unsigned char *old, unsigned char *new, int os, int ns) | |||
| { | |||
| int i; | |||
| short out[24]; // output buffer for the partial metrics from the mmx code | |||
| __asm__ ( | |||
| "movl $4, %%ecx \n\t" | |||
| "pxor %%mm4, %%mm4 \n\t" // 4 even difference sums | |||
| "pxor %%mm5, %%mm5 \n\t" // 4 odd difference sums | |||
| "pxor %%mm7, %%mm7 \n\t" // all zeros | |||
| ASMALIGN(4) | |||
| "1: \n\t" | |||
| // Even difference | |||
| "movq (%%"REG_S"), %%mm0 \n\t" | |||
| "movq (%%"REG_S"), %%mm2 \n\t" | |||
| "add %%"REG_a", %%"REG_S" \n\t" | |||
| "movq (%%"REG_D"), %%mm1 \n\t" | |||
| "add %%"REG_b", %%"REG_D" \n\t" | |||
| "psubusb %%mm1, %%mm2 \n\t" | |||
| "psubusb %%mm0, %%mm1 \n\t" | |||
| "movq %%mm2, %%mm0 \n\t" | |||
| "movq %%mm1, %%mm3 \n\t" | |||
| "punpcklbw %%mm7, %%mm0 \n\t" | |||
| "punpcklbw %%mm7, %%mm1 \n\t" | |||
| "punpckhbw %%mm7, %%mm2 \n\t" | |||
| "punpckhbw %%mm7, %%mm3 \n\t" | |||
| "paddw %%mm0, %%mm4 \n\t" | |||
| "paddw %%mm1, %%mm4 \n\t" | |||
| "paddw %%mm2, %%mm4 \n\t" | |||
| "paddw %%mm3, %%mm4 \n\t" | |||
| // Odd difference | |||
| "movq (%%"REG_S"), %%mm0 \n\t" | |||
| "movq (%%"REG_S"), %%mm2 \n\t" | |||
| "add %%"REG_a", %%"REG_S" \n\t" | |||
| "movq (%%"REG_D"), %%mm1 \n\t" | |||
| "add %%"REG_b", %%"REG_D" \n\t" | |||
| "psubusb %%mm1, %%mm2 \n\t" | |||
| "psubusb %%mm0, %%mm1 \n\t" | |||
| "movq %%mm2, %%mm0 \n\t" | |||
| "movq %%mm1, %%mm3 \n\t" | |||
| "punpcklbw %%mm7, %%mm0 \n\t" | |||
| "punpcklbw %%mm7, %%mm1 \n\t" | |||
| "punpckhbw %%mm7, %%mm2 \n\t" | |||
| "punpckhbw %%mm7, %%mm3 \n\t" | |||
| "paddw %%mm0, %%mm5 \n\t" | |||
| "paddw %%mm1, %%mm5 \n\t" | |||
| "paddw %%mm2, %%mm5 \n\t" | |||
| "paddw %%mm3, %%mm5 \n\t" | |||
| "decl %%ecx \n\t" | |||
| "jnz 1b \n\t" | |||
| "movq %%mm4, (%%"REG_d") \n\t" | |||
| "movq %%mm5, 8(%%"REG_d") \n\t" | |||
| : | |||
| : "S" (old), "D" (new), "a" (os), "b" (ns), "d" (out) | |||
| : "memory" | |||
| ); | |||
| m->e = out[0]+out[1]+out[2]+out[3]; | |||
| m->o = out[4]+out[5]+out[6]+out[7]; | |||
| m->d = m->e + m->o; | |||
| __asm__ ( | |||
| // First loop to measure first four columns | |||
| "movl $4, %%ecx \n\t" | |||
| "pxor %%mm4, %%mm4 \n\t" // Past spacial noise | |||
| "pxor %%mm5, %%mm5 \n\t" // Temporal noise | |||
| "pxor %%mm6, %%mm6 \n\t" // Current spacial noise | |||
| ASMALIGN(4) | |||
| "2: \n\t" | |||
| "movq (%%"REG_S"), %%mm0 \n\t" | |||
| "movq (%%"REG_S",%%"REG_a"), %%mm1 \n\t" | |||
| "add %%"REG_a", %%"REG_S" \n\t" | |||
| "add %%"REG_a", %%"REG_S" \n\t" | |||
| "movq (%%"REG_D"), %%mm2 \n\t" | |||
| "movq (%%"REG_D",%%"REG_b"), %%mm3 \n\t" | |||
| "add %%"REG_b", %%"REG_D" \n\t" | |||
| "add %%"REG_b", %%"REG_D" \n\t" | |||
| "punpcklbw %%mm7, %%mm0 \n\t" | |||
| "punpcklbw %%mm7, %%mm1 \n\t" | |||
| "punpcklbw %%mm7, %%mm2 \n\t" | |||
| "punpcklbw %%mm7, %%mm3 \n\t" | |||
| "paddw %%mm1, %%mm4 \n\t" | |||
| "paddw %%mm1, %%mm5 \n\t" | |||
| "paddw %%mm3, %%mm6 \n\t" | |||
| "psubw %%mm0, %%mm4 \n\t" | |||
| "psubw %%mm2, %%mm5 \n\t" | |||
| "psubw %%mm2, %%mm6 \n\t" | |||
| "decl %%ecx \n\t" | |||
| "jnz 2b \n\t" | |||
| "movq %%mm0, %%mm1 \n\t" | |||
| "movq %%mm0, %%mm2 \n\t" | |||
| "movq %%mm0, %%mm3 \n\t" | |||
| "pcmpgtw %%mm4, %%mm1 \n\t" | |||
| "pcmpgtw %%mm5, %%mm2 \n\t" | |||
| "pcmpgtw %%mm6, %%mm3 \n\t" | |||
| "pxor %%mm1, %%mm4 \n\t" | |||
| "pxor %%mm2, %%mm5 \n\t" | |||
| "pxor %%mm3, %%mm6 \n\t" | |||
| "psubw %%mm1, %%mm4 \n\t" | |||
| "psubw %%mm2, %%mm5 \n\t" | |||
| "psubw %%mm3, %%mm6 \n\t" | |||
| "movq %%mm4, (%%"REG_d") \n\t" | |||
| "movq %%mm5, 16(%%"REG_d") \n\t" | |||
| "movq %%mm6, 32(%%"REG_d") \n\t" | |||
| "mov %%"REG_a", %%"REG_c" \n\t" | |||
| "shl $3, %%"REG_c" \n\t" | |||
| "sub %%"REG_c", %%"REG_S" \n\t" | |||
| "mov %%"REG_b", %%"REG_c" \n\t" | |||
| "shl $3, %%"REG_c" \n\t" | |||
| "sub %%"REG_c", %%"REG_D" \n\t" | |||
| // Second loop for the last four columns | |||
| "movl $4, %%ecx \n\t" | |||
| "pxor %%mm4, %%mm4 \n\t" | |||
| "pxor %%mm5, %%mm5 \n\t" | |||
| "pxor %%mm6, %%mm6 \n\t" | |||
| ASMALIGN(4) | |||
| "3: \n\t" | |||
| "movq (%%"REG_S"), %%mm0 \n\t" | |||
| "movq (%%"REG_S",%%"REG_a"), %%mm1 \n\t" | |||
| "add %%"REG_a", %%"REG_S" \n\t" | |||
| "add %%"REG_a", %%"REG_S" \n\t" | |||
| "movq (%%"REG_D"), %%mm2 \n\t" | |||
| "movq (%%"REG_D",%%"REG_b"), %%mm3 \n\t" | |||
| "add %%"REG_b", %%"REG_D" \n\t" | |||
| "add %%"REG_b", %%"REG_D" \n\t" | |||
| "punpckhbw %%mm7, %%mm0 \n\t" | |||
| "punpckhbw %%mm7, %%mm1 \n\t" | |||
| "punpckhbw %%mm7, %%mm2 \n\t" | |||
| "punpckhbw %%mm7, %%mm3 \n\t" | |||
| "paddw %%mm1, %%mm4 \n\t" | |||
| "paddw %%mm1, %%mm5 \n\t" | |||
| "paddw %%mm3, %%mm6 \n\t" | |||
| "psubw %%mm0, %%mm4 \n\t" | |||
| "psubw %%mm2, %%mm5 \n\t" | |||
| "psubw %%mm2, %%mm6 \n\t" | |||
| "decl %%ecx \n\t" | |||
| "jnz 3b \n\t" | |||
| "movq %%mm0, %%mm1 \n\t" | |||
| "movq %%mm0, %%mm2 \n\t" | |||
| "movq %%mm0, %%mm3 \n\t" | |||
| "pcmpgtw %%mm4, %%mm1 \n\t" | |||
| "pcmpgtw %%mm5, %%mm2 \n\t" | |||
| "pcmpgtw %%mm6, %%mm3 \n\t" | |||
| "pxor %%mm1, %%mm4 \n\t" | |||
| "pxor %%mm2, %%mm5 \n\t" | |||
| "pxor %%mm3, %%mm6 \n\t" | |||
| "psubw %%mm1, %%mm4 \n\t" | |||
| "psubw %%mm2, %%mm5 \n\t" | |||
| "psubw %%mm3, %%mm6 \n\t" | |||
| "movq %%mm4, 8(%%"REG_d") \n\t" | |||
| "movq %%mm5, 24(%%"REG_d") \n\t" | |||
| "movq %%mm6, 40(%%"REG_d") \n\t" | |||
| "emms \n\t" | |||
| : | |||
| : "S" (old), "D" (new), "a" ((long)os), "b" ((long)ns), "d" (out) | |||
| : "memory" | |||
| ); | |||
| m->p = m->t = m->s = 0; | |||
| for (i=0; i<8; i++) { | |||
| m->p += out[i]; | |||
| m->t += out[8+i]; | |||
| m->s += out[16+i]; | |||
| } | |||
| //printf("e=%d o=%d d=%d p=%d t=%d s=%d\n", m->e, m->o, m->d, m->p, m->t, m->s); | |||
| } | |||
| #endif | |||
| //#define MAG(a) ((a)*(a)) | |||
| //#define MAG(a) (abs(a)) | |||
| #define MAG(a) (((a)^((a)>>31))-((a)>>31)) | |||
| //#define LOWPASS(s) (((s)[-2] + 4*(s)[-1] + 6*(s)[0] + 4*(s)[1] + (s)[2])>>4) | |||
| //#define LOWPASS(s) (((s)[-1] + 2*(s)[0] + (s)[1])>>2) | |||
| #define LOWPASS(s) ((s)[0]) | |||
| static void block_diffs_C(struct metrics *m, unsigned char *old, unsigned char *new, int os, int ns) | |||
| { | |||
| int x, y, e=0, o=0, s=0, p=0, t=0; | |||
| unsigned char *oldp, *newp; | |||
| m->s = m->p = m->t = 0; | |||
| for (x = 8; x; x--) { | |||
| oldp = old++; | |||
| newp = new++; | |||
| s = p = t = 0; | |||
| for (y = 4; y; y--) { | |||
| e += MAG(newp[0]-oldp[0]); | |||
| o += MAG(newp[ns]-oldp[os]); | |||
| s += newp[ns]-newp[0]; | |||
| p += oldp[os]-oldp[0]; | |||
| t += oldp[os]-newp[0]; | |||
| oldp += os<<1; | |||
| newp += ns<<1; | |||
| } | |||
| m->s += MAG(s); | |||
| m->p += MAG(p); | |||
| m->t += MAG(t); | |||
| } | |||
| m->e = e; | |||
| m->o = o; | |||
| m->d = e+o; | |||
| } | |||
| static void (*block_diffs)(struct metrics *, unsigned char *, unsigned char *, int, int); | |||
| #define MAXUP(a,b) ((a) = ((a)>(b)) ? (a) : (b)) | |||
| static void diff_planes(struct frameinfo *fi, | |||
| unsigned char *old, unsigned char *new, int w, int h, int os, int ns) | |||
| { | |||
| int x, y; | |||
| struct metrics l; | |||
| struct metrics *peak=&fi->p, *rel=&fi->r, *mean=&fi->m; | |||
| memset(peak, 0, sizeof(struct metrics)); | |||
| memset(rel, 0, sizeof(struct metrics)); | |||
| memset(mean, 0, sizeof(struct metrics)); | |||
| for (y = 0; y < h-7; y += 8) { | |||
| for (x = 8; x < w-8-7; x += 8) { | |||
| block_diffs(&l, old+x+y*os, new+x+y*ns, os, ns); | |||
| mean->d += l.d; | |||
| mean->e += l.e; | |||
| mean->o += l.o; | |||
| mean->s += l.s; | |||
| mean->p += l.p; | |||
| mean->t += l.t; | |||
| MAXUP(peak->d, l.d); | |||
| MAXUP(peak->e, l.e); | |||
| MAXUP(peak->o, l.o); | |||
| MAXUP(peak->s, l.s); | |||
| MAXUP(peak->p, l.p); | |||
| MAXUP(peak->t, l.t); | |||
| MAXUP(rel->e, l.e-l.o); | |||
| MAXUP(rel->o, l.o-l.e); | |||
| MAXUP(rel->s, l.s-l.t); | |||
| MAXUP(rel->p, l.p-l.t); | |||
| MAXUP(rel->t, l.t-l.p); | |||
| MAXUP(rel->d, l.t-l.s); /* hack */ | |||
| } | |||
| } | |||
| x = (w/8-2)*(h/8); | |||
| mean->d /= x; | |||
| mean->e /= x; | |||
| mean->o /= x; | |||
| mean->s /= x; | |||
| mean->p /= x; | |||
| mean->t /= x; | |||
| } | |||
| static void diff_fields(struct frameinfo *fi, mp_image_t *old, mp_image_t *new) | |||
| { | |||
| diff_planes(fi, old->planes[0], new->planes[0], | |||
| new->w, new->h, old->stride[0], new->stride[0]); | |||
| } | |||
| static void stats(struct frameinfo *f) | |||
| { | |||
| mp_msg(MSGT_VFILTER, MSGL_V, " pd=%d re=%d ro=%d rp=%d rt=%d rs=%d rd=%d pp=%d pt=%d ps=%d\r", | |||
| f->p.d, f->r.e, f->r.o, f->r.p, f->r.t, f->r.s, f->r.d, f->p.p, f->p.t, f->p.s); | |||
| } | |||
| static int foo(struct vf_priv_s *p, mp_image_t *new, mp_image_t *cur) | |||
| { | |||
| struct frameinfo *f = p->fi; | |||
| f[0] = f[1]; | |||
| diff_fields(&f[1], cur, new); | |||
| stats(&f[1]); | |||
| // Immediately drop this frame if it's already been used. | |||
| if (p->dropnext) { | |||
| p->dropnext = 0; | |||
| return F_DROP; | |||
| } | |||
| // Sometimes a pulldown frame comes all by itself, so both | |||
| // its top and bottom field are duplicates from the adjacent | |||
| // two frames. We can just drop such a frame, but we | |||
| // immediately show the next frame instead to keep the frame | |||
| // drops evenly spaced during normal 3:2 pulldown sequences. | |||
| if ((3*f[1].r.o < f[1].r.e) && (f[1].r.s < f[1].r.d)) { | |||
| p->dropnext = 1; | |||
| return F_NEXT; | |||
| } | |||
| // If none of these conditions hold, we will consider the frame | |||
| // progressive and just show it as-is. | |||
| if (!( (3*f[0].r.e < f[0].r.o) || | |||
| ((2*f[0].r.d < f[0].r.s) && (f[0].r.s > 1200)) || | |||
| ((2*f[1].r.t < f[1].r.p) && (f[1].r.p > 1200)) )) | |||
| return F_SHOW; | |||
| // Otherwise, we have to decide whether to merge or drop. | |||
| // If the noise metric only increases minimally, we're off | |||
| // to a good start... | |||
| if (((2*f[1].r.t < 3*f[1].r.p) && (f[1].r.t < 3600)) || | |||
| (f[1].r.t < 900) || (f[1].r.d < 900)) { | |||
| // ...and if noise decreases or the duplicate even field | |||
| // is detected, we go ahead with the merge. | |||
| if ((3*f[0].r.e < f[0].r.o) || (2*f[1].r.t < f[1].r.p)) { | |||
| p->dropnext = 1; | |||
| return F_MERGE; | |||
| } | |||
| } | |||
| return F_DROP; | |||
| } | |||
| static void copy_image(mp_image_t *dmpi, mp_image_t *mpi, int field) | |||
| { | |||
| switch (field) { | |||
| case 0: | |||
| my_memcpy_pic(dmpi->planes[0], mpi->planes[0], mpi->w, mpi->h/2, | |||
| dmpi->stride[0]*2, mpi->stride[0]*2); | |||
| if (mpi->flags & MP_IMGFLAG_PLANAR) { | |||
| my_memcpy_pic(dmpi->planes[1], mpi->planes[1], | |||
| mpi->chroma_width, mpi->chroma_height/2, | |||
| dmpi->stride[1]*2, mpi->stride[1]*2); | |||
| my_memcpy_pic(dmpi->planes[2], mpi->planes[2], | |||
| mpi->chroma_width, mpi->chroma_height/2, | |||
| dmpi->stride[2]*2, mpi->stride[2]*2); | |||
| } | |||
| break; | |||
| case 1: | |||
| my_memcpy_pic(dmpi->planes[0]+dmpi->stride[0], | |||
| mpi->planes[0]+mpi->stride[0], mpi->w, mpi->h/2, | |||
| dmpi->stride[0]*2, mpi->stride[0]*2); | |||
| if (mpi->flags & MP_IMGFLAG_PLANAR) { | |||
| my_memcpy_pic(dmpi->planes[1]+dmpi->stride[1], | |||
| mpi->planes[1]+mpi->stride[1], | |||
| mpi->chroma_width, mpi->chroma_height/2, | |||
| dmpi->stride[1]*2, mpi->stride[1]*2); | |||
| my_memcpy_pic(dmpi->planes[2]+dmpi->stride[2], | |||
| mpi->planes[2]+mpi->stride[2], | |||
| mpi->chroma_width, mpi->chroma_height/2, | |||
| dmpi->stride[2]*2, mpi->stride[2]*2); | |||
| } | |||
| break; | |||
| case 2: | |||
| memcpy_pic(dmpi->planes[0], mpi->planes[0], mpi->w, mpi->h, | |||
| dmpi->stride[0], mpi->stride[0]); | |||
| if (mpi->flags & MP_IMGFLAG_PLANAR) { | |||
| memcpy_pic(dmpi->planes[1], mpi->planes[1], | |||
| mpi->chroma_width, mpi->chroma_height, | |||
| dmpi->stride[1], mpi->stride[1]); | |||
| memcpy_pic(dmpi->planes[2], mpi->planes[2], | |||
| mpi->chroma_width, mpi->chroma_height, | |||
| dmpi->stride[2], mpi->stride[2]); | |||
| } | |||
| break; | |||
| } | |||
| } | |||
| static int do_put_image(struct vf_instance *vf, mp_image_t *dmpi) | |||
| { | |||
| struct vf_priv_s *p = vf->priv; | |||
| int dropflag=0; | |||
| if (!p->dropnext) switch (p->drop) { | |||
| case 0: | |||
| dropflag = 0; | |||
| break; | |||
| case 1: | |||
| dropflag = (++p->lastdrop >= 5); | |||
| break; | |||
| case 2: | |||
| dropflag = (++p->lastdrop >= 5) && (4*p->inframes <= 5*p->outframes); | |||
| break; | |||
| } | |||
| if (dropflag) { | |||
| //mp_msg(MSGT_VFILTER, MSGL_V, "drop! [%d/%d=%g]\n", | |||
| // p->outframes, p->inframes, (float)p->outframes/p->inframes); | |||
| mp_msg(MSGT_VFILTER, MSGL_V, "!"); | |||
| p->lastdrop = 0; | |||
| return 0; | |||
| } | |||
| p->outframes++; | |||
| return vf_next_put_image(vf, dmpi, MP_NOPTS_VALUE); | |||
| } | |||
| static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts) | |||
| { | |||
| int ret=0; | |||
| struct vf_priv_s *p = vf->priv; | |||
| p->inframes++; | |||
| if (p->first) { /* hack */ | |||
| p->first = 0; | |||
| return 1; | |||
| } | |||
| if (!p->dmpi) p->dmpi = vf_get_image(vf->next, mpi->imgfmt, | |||
| MP_IMGTYPE_STATIC, MP_IMGFLAG_ACCEPT_STRIDE | | |||
| MP_IMGFLAG_PRESERVE | MP_IMGFLAG_READABLE, | |||
| mpi->width, mpi->height); | |||
| /* FIXME -- not correct, off by one frame! */ | |||
| p->dmpi->qscale = mpi->qscale; | |||
| p->dmpi->qstride = mpi->qstride; | |||
| p->dmpi->qscale_type = mpi->qscale_type; | |||
| switch (foo(p, mpi, p->dmpi)) { | |||
| case F_DROP: | |||
| copy_image(p->dmpi, mpi, 2); | |||
| ret = 0; | |||
| p->lastdrop = 0; | |||
| mp_msg(MSGT_VFILTER, MSGL_V, "DROP\n"); | |||
| break; | |||
| case F_MERGE: | |||
| copy_image(p->dmpi, mpi, 0); | |||
| ret = do_put_image(vf, p->dmpi); | |||
| copy_image(p->dmpi, mpi, 1); | |||
| mp_msg(MSGT_VFILTER, MSGL_V, "MERGE\n"); | |||
| p->dmpi = NULL; | |||
| break; | |||
| case F_NEXT: | |||
| copy_image(p->dmpi, mpi, 2); | |||
| ret = do_put_image(vf, p->dmpi); | |||
| mp_msg(MSGT_VFILTER, MSGL_V, "NEXT\n"); | |||
| p->dmpi = NULL; | |||
| break; | |||
| case F_SHOW: | |||
| ret = do_put_image(vf, p->dmpi); | |||
| copy_image(p->dmpi, mpi, 2); | |||
| mp_msg(MSGT_VFILTER, MSGL_V, "OK\n"); | |||
| p->dmpi = NULL; | |||
| break; | |||
| } | |||
| return ret; | |||
| } | |||
| static int query_format(struct vf_instance *vf, unsigned int fmt) | |||
| { | |||
| switch (fmt) { | |||
| case IMGFMT_YV12: | |||
| case IMGFMT_IYUV: | |||
| case IMGFMT_I420: | |||
| return vf_next_query_format(vf, fmt); | |||
| } | |||
| return 0; | |||
| } | |||
| static void uninit(struct vf_instance *vf) | |||
| { | |||
| free(vf->priv); | |||
| } | |||
| static int vf_open(vf_instance_t *vf, char *args) | |||
| { | |||
| struct vf_priv_s *p; | |||
| vf->put_image = put_image; | |||
| vf->query_format = query_format; | |||
| vf->uninit = uninit; | |||
| vf->default_reqs = VFCAP_ACCEPT_STRIDE; | |||
| vf->priv = p = calloc(1, sizeof(struct vf_priv_s)); | |||
| p->drop = 0; | |||
| p->first = 1; | |||
| if (args) sscanf(args, "%d", &p->drop); | |||
| block_diffs = block_diffs_C; | |||
| #if HAVE_MMX && HAVE_EBX_AVAILABLE | |||
| if(gCpuCaps.hasMMX) block_diffs = block_diffs_MMX; | |||
| #endif | |||
| return 1; | |||
| } | |||
| const vf_info_t vf_info_ivtc = { | |||
| "inverse telecine, take 2", | |||
| "ivtc", | |||
| "Rich Felker", | |||
| "", | |||
| vf_open, | |||
| NULL | |||
| }; | |||
| @@ -0,0 +1,345 @@ | |||
| /* | |||
| * Original AVISynth Filter Copyright (C) 2003 Donald A. Graft | |||
| * Adapted to MPlayer by Tobias Diedrich | |||
| * | |||
| * This file is part of MPlayer. | |||
| * | |||
| * MPlayer 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. | |||
| * | |||
| * MPlayer 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 MPlayer; if not, write to the Free Software Foundation, Inc., | |||
| * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | |||
| */ | |||
| #include <stdio.h> | |||
| #include <stdlib.h> | |||
| #include <string.h> | |||
| #include <inttypes.h> | |||
| #include <math.h> | |||
| #include "mp_msg.h" | |||
| #include "img_format.h" | |||
| #include "mp_image.h" | |||
| #include "vf.h" | |||
| #include "libvo/fastmemcpy.h" | |||
| //===========================================================================// | |||
| struct vf_priv_s { | |||
| int frame; | |||
| int map; | |||
| int order; | |||
| int thresh; | |||
| int sharp; | |||
| int twoway; | |||
| int do_deinterlace; | |||
| }; | |||
| /***************************************************************************/ | |||
| static int config(struct vf_instance *vf, | |||
| int width, int height, int d_width, int d_height, | |||
| unsigned int flags, unsigned int outfmt){ | |||
| return vf_next_config(vf,width,height,d_width,d_height,flags,outfmt); | |||
| } | |||
| static void uninit(struct vf_instance *vf) | |||
| { | |||
| free(vf->priv); | |||
| } | |||
| static inline int IsRGB(mp_image_t *mpi) | |||
| { | |||
| return mpi->imgfmt == IMGFMT_RGB; | |||
| } | |||
| static inline int IsYUY2(mp_image_t *mpi) | |||
| { | |||
| return mpi->imgfmt == IMGFMT_YUY2; | |||
| } | |||
| #define PLANAR_Y 0 | |||
| #define PLANAR_U 1 | |||
| #define PLANAR_V 2 | |||
| static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts){ | |||
| int cw= mpi->w >> mpi->chroma_x_shift; | |||
| int ch= mpi->h >> mpi->chroma_y_shift; | |||
| int W = mpi->w, H = mpi->h; | |||
| const unsigned char *prvp, *prvpp, *prvpn, *prvpnn, *prvppp, *prvp4p, *prvp4n; | |||
| const unsigned char *srcp_saved; | |||
| const unsigned char *srcp, *srcpp, *srcpn, *srcpnn, *srcppp, *srcp3p, *srcp3n, *srcp4p, *srcp4n; | |||
| unsigned char *dstp, *dstp_saved; | |||
| int src_pitch; | |||
| int psrc_pitch; | |||
| int dst_pitch; | |||
| int x, y, z; | |||
| int n = vf->priv->frame++; | |||
| int val, hi, lo, w, h; | |||
| double valf; | |||
| int plane; | |||
| int threshold = vf->priv->thresh; | |||
| int order = vf->priv->order; | |||
| int map = vf->priv->map; | |||
| int sharp = vf->priv->sharp; | |||
| int twoway = vf->priv->twoway; | |||
| mp_image_t *dmpi, *pmpi; | |||
| if(!vf->priv->do_deinterlace) | |||
| return vf_next_put_image(vf, mpi, pts); | |||
| dmpi=vf_get_image(vf->next,mpi->imgfmt, | |||
| MP_IMGTYPE_IP, MP_IMGFLAG_ACCEPT_STRIDE, | |||
| mpi->w,mpi->h); | |||
| pmpi=vf_get_image(vf->next,mpi->imgfmt, | |||
| MP_IMGTYPE_TEMP, MP_IMGFLAG_ACCEPT_STRIDE, | |||
| mpi->w,mpi->h); | |||
| if(!dmpi) return 0; | |||
| for (z=0; z<mpi->num_planes; z++) { | |||
| if (z == 0) plane = PLANAR_Y; | |||
| else if (z == 1) plane = PLANAR_U; | |||
| else plane = PLANAR_V; | |||
| h = plane == PLANAR_Y ? H : ch; | |||
| w = plane == PLANAR_Y ? W : cw; | |||
| srcp = srcp_saved = mpi->planes[z]; | |||
| src_pitch = mpi->stride[z]; | |||
| psrc_pitch = pmpi->stride[z]; | |||
| dstp = dstp_saved = dmpi->planes[z]; | |||
| dst_pitch = dmpi->stride[z]; | |||
| srcp = srcp_saved + (1-order) * src_pitch; | |||
| dstp = dstp_saved + (1-order) * dst_pitch; | |||
| for (y=0; y<h; y+=2) { | |||
| fast_memcpy(dstp, srcp, w); | |||
| srcp += 2*src_pitch; | |||
| dstp += 2*dst_pitch; | |||
| } | |||
| // Copy through the lines that will be missed below. | |||
| fast_memcpy(dstp_saved + order*dst_pitch, srcp_saved + (1-order)*src_pitch, w); | |||
| fast_memcpy(dstp_saved + (2+order)*dst_pitch, srcp_saved + (3-order)*src_pitch, w); | |||
| fast_memcpy(dstp_saved + (h-2+order)*dst_pitch, srcp_saved + (h-1-order)*src_pitch, w); | |||
| fast_memcpy(dstp_saved + (h-4+order)*dst_pitch, srcp_saved + (h-3-order)*src_pitch, w); | |||
| /* For the other field choose adaptively between using the previous field | |||
| or the interpolant from the current field. */ | |||
| prvp = pmpi->planes[z] + 5*psrc_pitch - (1-order)*psrc_pitch; | |||
| prvpp = prvp - psrc_pitch; | |||
| prvppp = prvp - 2*psrc_pitch; | |||
| prvp4p = prvp - 4*psrc_pitch; | |||
| prvpn = prvp + psrc_pitch; | |||
| prvpnn = prvp + 2*psrc_pitch; | |||
| prvp4n = prvp + 4*psrc_pitch; | |||
| srcp = srcp_saved + 5*src_pitch - (1-order)*src_pitch; | |||
| srcpp = srcp - src_pitch; | |||
| srcppp = srcp - 2*src_pitch; | |||
| srcp3p = srcp - 3*src_pitch; | |||
| srcp4p = srcp - 4*src_pitch; | |||
| srcpn = srcp + src_pitch; | |||
| srcpnn = srcp + 2*src_pitch; | |||
| srcp3n = srcp + 3*src_pitch; | |||
| srcp4n = srcp + 4*src_pitch; | |||
| dstp = dstp_saved + 5*dst_pitch - (1-order)*dst_pitch; | |||
| for (y = 5 - (1-order); y <= h - 5 - (1-order); y+=2) | |||
| { | |||
| for (x = 0; x < w; x++) | |||
| { | |||
| if ((threshold == 0) || (n == 0) || | |||
| (abs((int)prvp[x] - (int)srcp[x]) > threshold) || | |||
| (abs((int)prvpp[x] - (int)srcpp[x]) > threshold) || | |||
| (abs((int)prvpn[x] - (int)srcpn[x]) > threshold)) | |||
| { | |||
| if (map == 1) | |||
| { | |||
| int g = x & ~3; | |||
| if (IsRGB(mpi) == 1) | |||
| { | |||
| dstp[g++] = 255; | |||
| dstp[g++] = 255; | |||
| dstp[g++] = 255; | |||
| dstp[g] = 255; | |||
| x = g; | |||
| } | |||
| else if (IsYUY2(mpi) == 1) | |||
| { | |||
| dstp[g++] = 235; | |||
| dstp[g++] = 128; | |||
| dstp[g++] = 235; | |||
| dstp[g] = 128; | |||
| x = g; | |||
| } | |||
| else | |||
| { | |||
| if (plane == PLANAR_Y) dstp[x] = 235; | |||
| else dstp[x] = 128; | |||
| } | |||
| } | |||
| else | |||
| { | |||
| if (IsRGB(mpi)) | |||
| { | |||
| hi = 255; | |||
| lo = 0; | |||
| } | |||
| else if (IsYUY2(mpi)) | |||
| { | |||
| hi = (x & 1) ? 240 : 235; | |||
| lo = 16; | |||
| } | |||
| else | |||
| { | |||
| hi = (plane == PLANAR_Y) ? 235 : 240; | |||
| lo = 16; | |||
| } | |||
| if (sharp == 1) | |||
| { | |||
| if (twoway == 1) | |||
| valf = + 0.526*((int)srcpp[x] + (int)srcpn[x]) | |||
| + 0.170*((int)srcp[x] + (int)prvp[x]) | |||
| - 0.116*((int)srcppp[x] + (int)srcpnn[x] + (int)prvppp[x] + (int)prvpnn[x]) | |||
| - 0.026*((int)srcp3p[x] + (int)srcp3n[x]) | |||
| + 0.031*((int)srcp4p[x] + (int)srcp4n[x] + (int)prvp4p[x] + (int)prvp4n[x]); | |||
| else | |||
| valf = + 0.526*((int)srcpp[x] + (int)srcpn[x]) | |||
| + 0.170*((int)prvp[x]) | |||
| - 0.116*((int)prvppp[x] + (int)prvpnn[x]) | |||
| - 0.026*((int)srcp3p[x] + (int)srcp3n[x]) | |||
| + 0.031*((int)prvp4p[x] + (int)prvp4p[x]); | |||
| if (valf > hi) valf = hi; | |||
| else if (valf < lo) valf = lo; | |||
| dstp[x] = (int) valf; | |||
| } | |||
| else | |||
| { | |||
| if (twoway == 1) | |||
| val = (8*((int)srcpp[x] + (int)srcpn[x]) + 2*((int)srcp[x] + (int)prvp[x]) - | |||
| (int)(srcppp[x]) - (int)(srcpnn[x]) - | |||
| (int)(prvppp[x]) - (int)(prvpnn[x])) >> 4; | |||
| else | |||
| val = (8*((int)srcpp[x] + (int)srcpn[x]) + 2*((int)prvp[x]) - | |||
| (int)(prvppp[x]) - (int)(prvpnn[x])) >> 4; | |||
| if (val > hi) val = hi; | |||
| else if (val < lo) val = lo; | |||
| dstp[x] = (int) val; | |||
| } | |||
| } | |||
| } | |||
| else | |||
| { | |||
| dstp[x] = srcp[x]; | |||
| } | |||
| } | |||
| prvp += 2*psrc_pitch; | |||
| prvpp += 2*psrc_pitch; | |||
| prvppp += 2*psrc_pitch; | |||
| prvpn += 2*psrc_pitch; | |||
| prvpnn += 2*psrc_pitch; | |||
| prvp4p += 2*psrc_pitch; | |||
| prvp4n += 2*psrc_pitch; | |||
| srcp += 2*src_pitch; | |||
| srcpp += 2*src_pitch; | |||
| srcppp += 2*src_pitch; | |||
| srcp3p += 2*src_pitch; | |||
| srcp4p += 2*src_pitch; | |||
| srcpn += 2*src_pitch; | |||
| srcpnn += 2*src_pitch; | |||
| srcp3n += 2*src_pitch; | |||
| srcp4n += 2*src_pitch; | |||
| dstp += 2*dst_pitch; | |||
| } | |||
| srcp = mpi->planes[z]; | |||
| dstp = pmpi->planes[z]; | |||
| for (y=0; y<h; y++) { | |||
| fast_memcpy(dstp, srcp, w); | |||
| srcp += src_pitch; | |||
| dstp += psrc_pitch; | |||
| } | |||
| } | |||
| return vf_next_put_image(vf,dmpi, pts); | |||
| } | |||
| //===========================================================================// | |||
| static int query_format(struct vf_instance *vf, unsigned int fmt){ | |||
| switch(fmt) | |||
| { | |||
| case IMGFMT_YV12: | |||
| case IMGFMT_RGB: | |||
| case IMGFMT_YUY2: | |||
| return vf_next_query_format(vf, fmt); | |||
| } | |||
| return 0; | |||
| } | |||
| static int control(struct vf_instance *vf, int request, void* data){ | |||
| switch (request) | |||
| { | |||
| case VFCTRL_GET_DEINTERLACE: | |||
| *(int*)data = vf->priv->do_deinterlace; | |||
| return CONTROL_OK; | |||
| case VFCTRL_SET_DEINTERLACE: | |||
| vf->priv->do_deinterlace = *(int*)data; | |||
| return CONTROL_OK; | |||
| } | |||
| return vf_next_control (vf, request, data); | |||
| } | |||
| static int vf_open(vf_instance_t *vf, char *args){ | |||
| vf->control=control; | |||
| vf->config=config; | |||
| vf->put_image=put_image; | |||
| vf->query_format=query_format; | |||
| vf->uninit=uninit; | |||
| vf->priv=malloc(sizeof(struct vf_priv_s)); | |||
| memset(vf->priv, 0, sizeof(struct vf_priv_s)); | |||
| vf->priv->frame = 0; | |||
| vf->priv->map = 0; | |||
| vf->priv->order = 0; | |||
| vf->priv->thresh = 10; | |||
| vf->priv->sharp = 0; | |||
| vf->priv->twoway = 0; | |||
| vf->priv->do_deinterlace=1; | |||
| if (args) | |||
| { | |||
| sscanf(args, "%d:%d:%d:%d:%d", | |||
| &vf->priv->thresh, &vf->priv->map, | |||
| &vf->priv->order, &vf->priv->sharp, | |||
| &vf->priv->twoway); | |||
| } | |||
| if (vf->priv->order > 1) vf->priv->order = 1; | |||
| return 1; | |||
| } | |||
| const vf_info_t vf_info_kerndeint = { | |||
| "Kernel Deinterlacer", | |||
| "kerndeint", | |||
| "Donald Graft", | |||
| "", | |||
| vf_open, | |||
| NULL | |||
| }; | |||
| //===========================================================================// | |||
| @@ -0,0 +1,338 @@ | |||
| /* | |||
| * Copyright (C) 2006 Michael Niedermayer <michaelni@gmx.at> | |||
| * | |||
| * This file is part of MPlayer. | |||
| * | |||
| * MPlayer 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. | |||
| * | |||
| * MPlayer 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 MPlayer; if not, write to the Free Software Foundation, Inc., | |||
| * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | |||
| */ | |||
| /* | |||
| Known Issues: | |||
| * The motion estimation is somewhat at the mercy of the input, if the input | |||
| frames are created purely based on spatial interpolation then for example | |||
| a thin black line or another random and not interpolateable pattern | |||
| will cause problems | |||
| Note: completly ignoring the "unavailable" lines during motion estimation | |||
| didnt look any better, so the most obvious solution would be to improve | |||
| tfields or penalize problematic motion vectors ... | |||
| * If non iterative ME is used then snow currently ignores the OBMC window | |||
| and as a result sometimes creates artifacts | |||
| * only past frames are used, we should ideally use future frames too, something | |||
| like filtering the whole movie in forward and then backward direction seems | |||
| like a interresting idea but the current filter framework is FAR from | |||
| supporting such things | |||
| * combining the motion compensated image with the input image also isnt | |||
| as trivial as it seems, simple blindly taking even lines from one and | |||
| odd ones from the other doesnt work at all as ME/MC sometimes simple | |||
| has nothing in the previous frames which matches the current, the current | |||
| algo has been found by trial and error and almost certainly can be | |||
| improved ... | |||
| */ | |||
| #include <stdio.h> | |||
| #include <stdlib.h> | |||
| #include <string.h> | |||
| #include <inttypes.h> | |||
| #include <math.h> | |||
| #include "mp_msg.h" | |||
| #include "cpudetect.h" | |||
| #include "libavutil/internal.h" | |||
| #include "libavutil/intreadwrite.h" | |||
| #include "libavcodec/avcodec.h" | |||
| #include "libavcodec/dsputil.h" | |||
| #undef fprintf | |||
| #undef free | |||
| #undef malloc | |||
| #include "img_format.h" | |||
| #include "mp_image.h" | |||
| #include "vf.h" | |||
| #include "vd_ffmpeg.h" | |||
| #define MIN(a,b) ((a) > (b) ? (b) : (a)) | |||
| #define MAX(a,b) ((a) < (b) ? (b) : (a)) | |||
| #define ABS(a) ((a) > 0 ? (a) : (-(a))) | |||
| //===========================================================================// | |||
| struct vf_priv_s { | |||
| int mode; | |||
| int qp; | |||
| int parity; | |||
| #if 0 | |||
| int temp_stride[3]; | |||
| uint8_t *src[3]; | |||
| int16_t *temp[3]; | |||
| #endif | |||
| int outbuf_size; | |||
| uint8_t *outbuf; | |||
| AVCodecContext *avctx_enc; | |||
| AVFrame *frame; | |||
| AVFrame *frame_dec; | |||
| }; | |||
| static void filter(struct vf_priv_s *p, uint8_t *dst[3], uint8_t *src[3], int dst_stride[3], int src_stride[3], int width, int height){ | |||
| int x, y, i; | |||
| int out_size; | |||
| for(i=0; i<3; i++){ | |||
| p->frame->data[i]= src[i]; | |||
| p->frame->linesize[i]= src_stride[i]; | |||
| } | |||
| p->avctx_enc->me_cmp= | |||
| p->avctx_enc->me_sub_cmp= FF_CMP_SAD /*| (p->parity ? FF_CMP_ODD : FF_CMP_EVEN)*/; | |||
| p->frame->quality= p->qp*FF_QP2LAMBDA; | |||
| out_size = avcodec_encode_video(p->avctx_enc, p->outbuf, p->outbuf_size, p->frame); | |||
| p->frame_dec = p->avctx_enc->coded_frame; | |||
| for(i=0; i<3; i++){ | |||
| int is_chroma= !!i; | |||
| int w= width >>is_chroma; | |||
| int h= height>>is_chroma; | |||
| int fils= p->frame_dec->linesize[i]; | |||
| int srcs= src_stride[i]; | |||
| for(y=0; y<h; y++){ | |||
| if((y ^ p->parity) & 1){ | |||
| for(x=0; x<w; x++){ | |||
| if((x-2)+(y-1)*w>=0 && (x+2)+(y+1)*w<w*h){ //FIXME either alloc larger images or optimize this | |||
| uint8_t *filp= &p->frame_dec->data[i][x + y*fils]; | |||
| uint8_t *srcp= &src[i][x + y*srcs]; | |||
| int diff0= filp[-fils] - srcp[-srcs]; | |||
| int diff1= filp[+fils] - srcp[+srcs]; | |||
| int spatial_score= ABS(srcp[-srcs-1] - srcp[+srcs-1]) | |||
| +ABS(srcp[-srcs ] - srcp[+srcs ]) | |||
| +ABS(srcp[-srcs+1] - srcp[+srcs+1]) - 1; | |||
| int temp= filp[0]; | |||
| #define CHECK(j)\ | |||
| { int score= ABS(srcp[-srcs-1+j] - srcp[+srcs-1-j])\ | |||
| + ABS(srcp[-srcs +j] - srcp[+srcs -j])\ | |||
| + ABS(srcp[-srcs+1+j] - srcp[+srcs+1-j]);\ | |||
| if(score < spatial_score){\ | |||
| spatial_score= score;\ | |||
| diff0= filp[-fils+j] - srcp[-srcs+j];\ | |||
| diff1= filp[+fils-j] - srcp[+srcs-j]; | |||
| CHECK(-1) CHECK(-2) }} }} | |||
| CHECK( 1) CHECK( 2) }} }} | |||
| #if 0 | |||
| if((diff0 ^ diff1) > 0){ | |||
| int mindiff= ABS(diff0) > ABS(diff1) ? diff1 : diff0; | |||
| temp-= mindiff; | |||
| } | |||
| #elif 1 | |||
| if(diff0 + diff1 > 0) | |||
| temp-= (diff0 + diff1 - ABS( ABS(diff0) - ABS(diff1) )/2)/2; | |||
| else | |||
| temp-= (diff0 + diff1 + ABS( ABS(diff0) - ABS(diff1) )/2)/2; | |||
| #else | |||
| temp-= (diff0 + diff1)/2; | |||
| #endif | |||
| #if 1 | |||
| filp[0]= | |||
| dst[i][x + y*dst_stride[i]]= temp > 255U ? ~(temp>>31) : temp; | |||
| #else | |||
| dst[i][x + y*dst_stride[i]]= filp[0]; | |||
| filp[0]= temp > 255U ? ~(temp>>31) : temp; | |||
| #endif | |||
| }else | |||
| dst[i][x + y*dst_stride[i]]= p->frame_dec->data[i][x + y*fils]; | |||
| } | |||
| } | |||
| } | |||
| for(y=0; y<h; y++){ | |||
| if(!((y ^ p->parity) & 1)){ | |||
| for(x=0; x<w; x++){ | |||
| #if 1 | |||
| p->frame_dec->data[i][x + y*fils]= | |||
| dst[i][x + y*dst_stride[i]]= src[i][x + y*srcs]; | |||
| #else | |||
| dst[i][x + y*dst_stride[i]]= p->frame_dec->data[i][x + y*fils]; | |||
| p->frame_dec->data[i][x + y*fils]= src[i][x + y*srcs]; | |||
| #endif | |||
| } | |||
| } | |||
| } | |||
| } | |||
| p->parity ^= 1; | |||
| } | |||
| static int config(struct vf_instance *vf, | |||
| int width, int height, int d_width, int d_height, | |||
| unsigned int flags, unsigned int outfmt){ | |||
| int i; | |||
| AVCodec *enc= avcodec_find_encoder(CODEC_ID_SNOW); | |||
| for(i=0; i<3; i++){ | |||
| AVCodecContext *avctx_enc; | |||
| #if 0 | |||
| int is_chroma= !!i; | |||
| int w= ((width + 31) & (~31))>>is_chroma; | |||
| int h= ((height + 31) & (~31))>>is_chroma; | |||
| vf->priv->temp_stride[i]= w; | |||
| vf->priv->temp[i]= malloc(vf->priv->temp_stride[i]*h*sizeof(int16_t)); | |||
| vf->priv->src [i]= malloc(vf->priv->temp_stride[i]*h*sizeof(uint8_t)); | |||
| #endif | |||
| avctx_enc= | |||
| vf->priv->avctx_enc= avcodec_alloc_context(); | |||
| avctx_enc->width = width; | |||
| avctx_enc->height = height; | |||
| avctx_enc->time_base= (AVRational){1,25}; // meaningless | |||
| avctx_enc->gop_size = 300; | |||
| avctx_enc->max_b_frames= 0; | |||
| avctx_enc->pix_fmt = PIX_FMT_YUV420P; | |||
| avctx_enc->flags = CODEC_FLAG_QSCALE | CODEC_FLAG_LOW_DELAY; | |||
| avctx_enc->strict_std_compliance = FF_COMPLIANCE_EXPERIMENTAL; | |||
| avctx_enc->global_quality= 1; | |||
| avctx_enc->flags2= CODEC_FLAG2_MEMC_ONLY; | |||
| avctx_enc->me_cmp= | |||
| avctx_enc->me_sub_cmp= FF_CMP_SAD; //SSE; | |||
| avctx_enc->mb_cmp= FF_CMP_SSE; | |||
| switch(vf->priv->mode){ | |||
| case 3: | |||
| avctx_enc->refs= 3; | |||
| case 2: | |||
| avctx_enc->me_method= ME_ITER; | |||
| case 1: | |||
| avctx_enc->flags |= CODEC_FLAG_4MV; | |||
| avctx_enc->dia_size=2; | |||
| // avctx_enc->mb_decision = MB_DECISION_RD; | |||
| case 0: | |||
| avctx_enc->flags |= CODEC_FLAG_QPEL; | |||
| } | |||
| avcodec_open(avctx_enc, enc); | |||
| } | |||
| vf->priv->frame= avcodec_alloc_frame(); | |||
| vf->priv->outbuf_size= width*height*10; | |||
| vf->priv->outbuf= malloc(vf->priv->outbuf_size); | |||
| return vf_next_config(vf,width,height,d_width,d_height,flags,outfmt); | |||
| } | |||
| static void get_image(struct vf_instance *vf, mp_image_t *mpi){ | |||
| if(mpi->flags&MP_IMGFLAG_PRESERVE) return; // don't change | |||
| return; //caused problems, dunno why | |||
| // ok, we can do pp in-place (or pp disabled): | |||
| vf->dmpi=vf_get_image(vf->next,mpi->imgfmt, | |||
| mpi->type, mpi->flags | MP_IMGFLAG_READABLE, mpi->width, mpi->height); | |||
| mpi->planes[0]=vf->dmpi->planes[0]; | |||
| mpi->stride[0]=vf->dmpi->stride[0]; | |||
| mpi->width=vf->dmpi->width; | |||
| if(mpi->flags&MP_IMGFLAG_PLANAR){ | |||
| mpi->planes[1]=vf->dmpi->planes[1]; | |||
| mpi->planes[2]=vf->dmpi->planes[2]; | |||
| mpi->stride[1]=vf->dmpi->stride[1]; | |||
| mpi->stride[2]=vf->dmpi->stride[2]; | |||
| } | |||
| mpi->flags|=MP_IMGFLAG_DIRECT; | |||
| } | |||
| static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts){ | |||
| mp_image_t *dmpi; | |||
| if(!(mpi->flags&MP_IMGFLAG_DIRECT)){ | |||
| // no DR, so get a new image! hope we'll get DR buffer: | |||
| dmpi=vf_get_image(vf->next,mpi->imgfmt, | |||
| MP_IMGTYPE_TEMP, | |||
| MP_IMGFLAG_ACCEPT_STRIDE|MP_IMGFLAG_PREFER_ALIGNED_STRIDE, | |||
| mpi->width,mpi->height); | |||
| vf_clone_mpi_attributes(dmpi, mpi); | |||
| }else{ | |||
| dmpi=vf->dmpi; | |||
| } | |||
| filter(vf->priv, dmpi->planes, mpi->planes, dmpi->stride, mpi->stride, mpi->w, mpi->h); | |||
| return vf_next_put_image(vf,dmpi, pts); | |||
| } | |||
| static void uninit(struct vf_instance *vf){ | |||
| if(!vf->priv) return; | |||
| #if 0 | |||
| for(i=0; i<3; i++){ | |||
| free(vf->priv->temp[i]); | |||
| vf->priv->temp[i]= NULL; | |||
| free(vf->priv->src[i]); | |||
| vf->priv->src[i]= NULL; | |||
| } | |||
| #endif | |||
| if (vf->priv->avctx_enc) { | |||
| avcodec_close(vf->priv->avctx_enc); | |||
| av_freep(&vf->priv->avctx_enc); | |||
| } | |||
| free(vf->priv->outbuf); | |||
| free(vf->priv); | |||
| vf->priv=NULL; | |||
| } | |||
| //===========================================================================// | |||
| static int query_format(struct vf_instance *vf, unsigned int fmt){ | |||
| switch(fmt){ | |||
| case IMGFMT_YV12: | |||
| case IMGFMT_I420: | |||
| case IMGFMT_IYUV: | |||
| case IMGFMT_Y800: | |||
| case IMGFMT_Y8: | |||
| return vf_next_query_format(vf,fmt); | |||
| } | |||
| return 0; | |||
| } | |||
| static int vf_open(vf_instance_t *vf, char *args){ | |||
| vf->config=config; | |||
| vf->put_image=put_image; | |||
| vf->get_image=get_image; | |||
| vf->query_format=query_format; | |||
| vf->uninit=uninit; | |||
| vf->priv=malloc(sizeof(struct vf_priv_s)); | |||
| memset(vf->priv, 0, sizeof(struct vf_priv_s)); | |||
| init_avcodec(); | |||
| vf->priv->mode=0; | |||
| vf->priv->parity= -1; | |||
| vf->priv->qp=1; | |||
| if (args) sscanf(args, "%d:%d:%d", &vf->priv->mode, &vf->priv->parity, &vf->priv->qp); | |||
| return 1; | |||
| } | |||
| const vf_info_t vf_info_mcdeint = { | |||
| "motion compensating deinterlacer", | |||
| "mcdeint", | |||
| "Michael Niedermayer", | |||
| "", | |||
| vf_open, | |||
| NULL | |||
| }; | |||
| @@ -0,0 +1,131 @@ | |||
| /* | |||
| * This file is part of MPlayer. | |||
| * | |||
| * MPlayer 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. | |||
| * | |||
| * MPlayer 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 MPlayer; if not, write to the Free Software Foundation, Inc., | |||
| * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | |||
| */ | |||
| #include <stdio.h> | |||
| #include <stdlib.h> | |||
| #include <string.h> | |||
| #include <inttypes.h> | |||
| #include "config.h" | |||
| #include "mp_msg.h" | |||
| #include "img_format.h" | |||
| #include "mp_image.h" | |||
| #include "vf.h" | |||
| static void mirror(unsigned char* dst,unsigned char* src,int dststride,int srcstride,int w,int h,int bpp,unsigned int fmt){ | |||
| int y; | |||
| for(y=0;y<h;y++){ | |||
| int x; | |||
| switch(bpp){ | |||
| case 1: | |||
| for(x=0;x<w;x++) dst[x]=src[w-x-1]; | |||
| break; | |||
| case 2: | |||
| switch(fmt){ | |||
| case IMGFMT_UYVY: { | |||
| // packed YUV is tricky. U,V are 32bpp while Y is 16bpp: | |||
| int w2=w>>1; | |||
| for(x=0;x<w2;x++){ | |||
| // TODO: optimize this... | |||
| dst[x*4+0]=src[0+(w2-x-1)*4]; | |||
| dst[x*4+1]=src[3+(w2-x-1)*4]; | |||
| dst[x*4+2]=src[2+(w2-x-1)*4]; | |||
| dst[x*4+3]=src[1+(w2-x-1)*4]; | |||
| } | |||
| break; } | |||
| case IMGFMT_YUY2: | |||
| case IMGFMT_YVYU: { | |||
| // packed YUV is tricky. U,V are 32bpp while Y is 16bpp: | |||
| int w2=w>>1; | |||
| for(x=0;x<w2;x++){ | |||
| // TODO: optimize this... | |||
| dst[x*4+0]=src[2+(w2-x-1)*4]; | |||
| dst[x*4+1]=src[1+(w2-x-1)*4]; | |||
| dst[x*4+2]=src[0+(w2-x-1)*4]; | |||
| dst[x*4+3]=src[3+(w2-x-1)*4]; | |||
| } | |||
| break; } | |||
| default: | |||
| for(x=0;x<w;x++) *((short*)(dst+x*2))=*((short*)(src+(w-x-1)*2)); | |||
| } | |||
| break; | |||
| case 3: | |||
| for(x=0;x<w;x++){ | |||
| dst[x*3+0]=src[0+(w-x-1)*3]; | |||
| dst[x*3+1]=src[1+(w-x-1)*3]; | |||
| dst[x*3+2]=src[2+(w-x-1)*3]; | |||
| } | |||
| break; | |||
| case 4: | |||
| for(x=0;x<w;x++) *((int*)(dst+x*4))=*((int*)(src+(w-x-1)*4)); | |||
| } | |||
| src+=srcstride; | |||
| dst+=dststride; | |||
| } | |||
| } | |||
| //===========================================================================// | |||
| static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts){ | |||
| mp_image_t *dmpi; | |||
| // hope we'll get DR buffer: | |||
| dmpi=vf_get_image(vf->next,mpi->imgfmt, | |||
| MP_IMGTYPE_TEMP, MP_IMGFLAG_ACCEPT_STRIDE, | |||
| mpi->w, mpi->h); | |||
| if(mpi->flags&MP_IMGFLAG_PLANAR){ | |||
| mirror(dmpi->planes[0],mpi->planes[0], | |||
| dmpi->stride[0],mpi->stride[0], | |||
| dmpi->w,dmpi->h,1,mpi->imgfmt); | |||
| mirror(dmpi->planes[1],mpi->planes[1], | |||
| dmpi->stride[1],mpi->stride[1], | |||
| dmpi->w>>mpi->chroma_x_shift,dmpi->h>>mpi->chroma_y_shift,1,mpi->imgfmt); | |||
| mirror(dmpi->planes[2],mpi->planes[2], | |||
| dmpi->stride[2],mpi->stride[2], | |||
| dmpi->w>>mpi->chroma_x_shift,dmpi->h>>mpi->chroma_y_shift,1,mpi->imgfmt); | |||
| } else { | |||
| mirror(dmpi->planes[0],mpi->planes[0], | |||
| dmpi->stride[0],mpi->stride[0], | |||
| dmpi->w,dmpi->h,dmpi->bpp>>3,mpi->imgfmt); | |||
| dmpi->planes[1]=mpi->planes[1]; // passthrough rgb8 palette | |||
| } | |||
| return vf_next_put_image(vf,dmpi, pts); | |||
| } | |||
| //===========================================================================// | |||
| static int vf_open(vf_instance_t *vf, char *args){ | |||
| //vf->config=config; | |||
| vf->put_image=put_image; | |||
| return 1; | |||
| } | |||
| const vf_info_t vf_info_mirror = { | |||
| "horizontal mirror", | |||
| "mirror", | |||
| "Eyck", | |||
| "", | |||
| vf_open, | |||
| NULL | |||
| }; | |||
| //===========================================================================// | |||
| @@ -0,0 +1,474 @@ | |||
| /* | |||
| * Copyright (C) 2002 Michael Niedermayer <michaelni@gmx.at> | |||
| * | |||
| * This file is part of MPlayer. | |||
| * | |||
| * MPlayer 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. | |||
| * | |||
| * MPlayer 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 MPlayer; if not, write to the Free Software Foundation, Inc., | |||
| * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | |||
| */ | |||
| #include <stdio.h> | |||
| #include <stdlib.h> | |||
| #include <string.h> | |||
| #include <inttypes.h> | |||
| #include <math.h> | |||
| #include "config.h" | |||
| #include "mp_msg.h" | |||
| #include "cpudetect.h" | |||
| #if HAVE_MALLOC_H | |||
| #include <malloc.h> | |||
| #endif | |||
| #include "img_format.h" | |||
| #include "mp_image.h" | |||
| #include "vf.h" | |||
| #include "libvo/fastmemcpy.h" | |||
| #include "libavutil/mem.h" | |||
| #define MAX_NOISE 4096 | |||
| #define MAX_SHIFT 1024 | |||
| #define MAX_RES (MAX_NOISE-MAX_SHIFT) | |||
| //===========================================================================// | |||
| static inline void lineNoise_C(uint8_t *dst, uint8_t *src, int8_t *noise, int len, int shift); | |||
| static inline void lineNoiseAvg_C(uint8_t *dst, uint8_t *src, int len, int8_t **shift); | |||
| static void (*lineNoise)(uint8_t *dst, uint8_t *src, int8_t *noise, int len, int shift)= lineNoise_C; | |||
| static void (*lineNoiseAvg)(uint8_t *dst, uint8_t *src, int len, int8_t **shift)= lineNoiseAvg_C; | |||
| typedef struct FilterParam{ | |||
| int strength; | |||
| int uniform; | |||
| int temporal; | |||
| int quality; | |||
| int averaged; | |||
| int pattern; | |||
| int shiftptr; | |||
| int8_t *noise; | |||
| int8_t *prev_shift[MAX_RES][3]; | |||
| }FilterParam; | |||
| struct vf_priv_s { | |||
| FilterParam lumaParam; | |||
| FilterParam chromaParam; | |||
| unsigned int outfmt; | |||
| }; | |||
| static int nonTempRandShift_init; | |||
| static int nonTempRandShift[MAX_RES]; | |||
| static int patt[4] = { | |||
| -1,0,1,0 | |||
| }; | |||
| #define RAND_N(range) ((int) ((double)range*rand()/(RAND_MAX+1.0))) | |||
| static int8_t *initNoise(FilterParam *fp){ | |||
| int strength= fp->strength; | |||
| int uniform= fp->uniform; | |||
| int averaged= fp->averaged; | |||
| int pattern= fp->pattern; | |||
| int8_t *noise= av_malloc(MAX_NOISE*sizeof(int8_t)); | |||
| int i, j; | |||
| srand(123457); | |||
| for(i=0,j=0; i<MAX_NOISE; i++,j++) | |||
| { | |||
| if(uniform) { | |||
| if (averaged) { | |||
| if (pattern) { | |||
| noise[i]= (RAND_N(strength) - strength/2)/6 | |||
| +patt[j%4]*strength*0.25/3; | |||
| } else { | |||
| noise[i]= (RAND_N(strength) - strength/2)/3; | |||
| } | |||
| } else { | |||
| if (pattern) { | |||
| noise[i]= (RAND_N(strength) - strength/2)/2 | |||
| + patt[j%4]*strength*0.25; | |||
| } else { | |||
| noise[i]= RAND_N(strength) - strength/2; | |||
| } | |||
| } | |||
| } else { | |||
| double x1, x2, w, y1; | |||
| do { | |||
| x1 = 2.0 * rand()/(float)RAND_MAX - 1.0; | |||
| x2 = 2.0 * rand()/(float)RAND_MAX - 1.0; | |||
| w = x1 * x1 + x2 * x2; | |||
| } while ( w >= 1.0 ); | |||
| w = sqrt( (-2.0 * log( w ) ) / w ); | |||
| y1= x1 * w; | |||
| y1*= strength / sqrt(3.0); | |||
| if (pattern) { | |||
| y1 /= 2; | |||
| y1 += patt[j%4]*strength*0.35; | |||
| } | |||
| if (y1<-128) y1=-128; | |||
| else if(y1> 127) y1= 127; | |||
| if (averaged) y1 /= 3.0; | |||
| noise[i]= (int)y1; | |||
| } | |||
| if (RAND_N(6) == 0) j--; | |||
| } | |||
| for (i = 0; i < MAX_RES; i++) | |||
| for (j = 0; j < 3; j++) | |||
| fp->prev_shift[i][j] = noise + (rand()&(MAX_SHIFT-1)); | |||
| if(!nonTempRandShift_init){ | |||
| for(i=0; i<MAX_RES; i++){ | |||
| nonTempRandShift[i]= rand()&(MAX_SHIFT-1); | |||
| } | |||
| nonTempRandShift_init = 1; | |||
| } | |||
| fp->noise= noise; | |||
| fp->shiftptr= 0; | |||
| return noise; | |||
| } | |||
| /***************************************************************************/ | |||
| #if HAVE_MMX | |||
| static inline void lineNoise_MMX(uint8_t *dst, uint8_t *src, int8_t *noise, int len, int shift){ | |||
| x86_reg mmx_len= len&(~7); | |||
| noise+=shift; | |||
| __asm__ volatile( | |||
| "mov %3, %%"REG_a" \n\t" | |||
| "pcmpeqb %%mm7, %%mm7 \n\t" | |||
| "psllw $15, %%mm7 \n\t" | |||
| "packsswb %%mm7, %%mm7 \n\t" | |||
| ASMALIGN(4) | |||
| "1: \n\t" | |||
| "movq (%0, %%"REG_a"), %%mm0 \n\t" | |||
| "movq (%1, %%"REG_a"), %%mm1 \n\t" | |||
| "pxor %%mm7, %%mm0 \n\t" | |||
| "paddsb %%mm1, %%mm0 \n\t" | |||
| "pxor %%mm7, %%mm0 \n\t" | |||
| "movq %%mm0, (%2, %%"REG_a") \n\t" | |||
| "add $8, %%"REG_a" \n\t" | |||
| " js 1b \n\t" | |||
| :: "r" (src+mmx_len), "r" (noise+mmx_len), "r" (dst+mmx_len), "g" (-mmx_len) | |||
| : "%"REG_a | |||
| ); | |||
| if(mmx_len!=len) | |||
| lineNoise_C(dst+mmx_len, src+mmx_len, noise+mmx_len, len-mmx_len, 0); | |||
| } | |||
| #endif | |||
| //duplicate of previous except movntq | |||
| #if HAVE_MMX2 | |||
| static inline void lineNoise_MMX2(uint8_t *dst, uint8_t *src, int8_t *noise, int len, int shift){ | |||
| x86_reg mmx_len= len&(~7); | |||
| noise+=shift; | |||
| __asm__ volatile( | |||
| "mov %3, %%"REG_a" \n\t" | |||
| "pcmpeqb %%mm7, %%mm7 \n\t" | |||
| "psllw $15, %%mm7 \n\t" | |||
| "packsswb %%mm7, %%mm7 \n\t" | |||
| ASMALIGN(4) | |||
| "1: \n\t" | |||
| "movq (%0, %%"REG_a"), %%mm0 \n\t" | |||
| "movq (%1, %%"REG_a"), %%mm1 \n\t" | |||
| "pxor %%mm7, %%mm0 \n\t" | |||
| "paddsb %%mm1, %%mm0 \n\t" | |||
| "pxor %%mm7, %%mm0 \n\t" | |||
| "movntq %%mm0, (%2, %%"REG_a") \n\t" | |||
| "add $8, %%"REG_a" \n\t" | |||
| " js 1b \n\t" | |||
| :: "r" (src+mmx_len), "r" (noise+mmx_len), "r" (dst+mmx_len), "g" (-mmx_len) | |||
| : "%"REG_a | |||
| ); | |||
| if(mmx_len!=len) | |||
| lineNoise_C(dst+mmx_len, src+mmx_len, noise+mmx_len, len-mmx_len, 0); | |||
| } | |||
| #endif | |||
| static inline void lineNoise_C(uint8_t *dst, uint8_t *src, int8_t *noise, int len, int shift){ | |||
| int i; | |||
| noise+= shift; | |||
| for(i=0; i<len; i++) | |||
| { | |||
| int v= src[i]+ noise[i]; | |||
| if(v>255) dst[i]=255; //FIXME optimize | |||
| else if(v<0) dst[i]=0; | |||
| else dst[i]=v; | |||
| } | |||
| } | |||
| /***************************************************************************/ | |||
| #if HAVE_MMX | |||
| static inline void lineNoiseAvg_MMX(uint8_t *dst, uint8_t *src, int len, int8_t **shift){ | |||
| x86_reg mmx_len= len&(~7); | |||
| __asm__ volatile( | |||
| "mov %5, %%"REG_a" \n\t" | |||
| ASMALIGN(4) | |||
| "1: \n\t" | |||
| "movq (%1, %%"REG_a"), %%mm1 \n\t" | |||
| "movq (%0, %%"REG_a"), %%mm0 \n\t" | |||
| "paddb (%2, %%"REG_a"), %%mm1 \n\t" | |||
| "paddb (%3, %%"REG_a"), %%mm1 \n\t" | |||
| "movq %%mm0, %%mm2 \n\t" | |||
| "movq %%mm1, %%mm3 \n\t" | |||
| "punpcklbw %%mm0, %%mm0 \n\t" | |||
| "punpckhbw %%mm2, %%mm2 \n\t" | |||
| "punpcklbw %%mm1, %%mm1 \n\t" | |||
| "punpckhbw %%mm3, %%mm3 \n\t" | |||
| "pmulhw %%mm0, %%mm1 \n\t" | |||
| "pmulhw %%mm2, %%mm3 \n\t" | |||
| "paddw %%mm1, %%mm1 \n\t" | |||
| "paddw %%mm3, %%mm3 \n\t" | |||
| "paddw %%mm0, %%mm1 \n\t" | |||
| "paddw %%mm2, %%mm3 \n\t" | |||
| "psrlw $8, %%mm1 \n\t" | |||
| "psrlw $8, %%mm3 \n\t" | |||
| "packuswb %%mm3, %%mm1 \n\t" | |||
| "movq %%mm1, (%4, %%"REG_a") \n\t" | |||
| "add $8, %%"REG_a" \n\t" | |||
| " js 1b \n\t" | |||
| :: "r" (src+mmx_len), "r" (shift[0]+mmx_len), "r" (shift[1]+mmx_len), "r" (shift[2]+mmx_len), | |||
| "r" (dst+mmx_len), "g" (-mmx_len) | |||
| : "%"REG_a | |||
| ); | |||
| if(mmx_len!=len){ | |||
| int8_t *shift2[3]={shift[0]+mmx_len, shift[1]+mmx_len, shift[2]+mmx_len}; | |||
| lineNoiseAvg_C(dst+mmx_len, src+mmx_len, len-mmx_len, shift2); | |||
| } | |||
| } | |||
| #endif | |||
| static inline void lineNoiseAvg_C(uint8_t *dst, uint8_t *src, int len, int8_t **shift){ | |||
| int i; | |||
| int8_t *src2= (int8_t*)src; | |||
| for(i=0; i<len; i++) | |||
| { | |||
| const int n= shift[0][i] + shift[1][i] + shift[2][i]; | |||
| dst[i]= src2[i]+((n*src2[i])>>7); | |||
| } | |||
| } | |||
| /***************************************************************************/ | |||
| static void noise(uint8_t *dst, uint8_t *src, int dstStride, int srcStride, int width, int height, FilterParam *fp){ | |||
| int8_t *noise= fp->noise; | |||
| int y; | |||
| int shift=0; | |||
| if(!noise) | |||
| { | |||
| if(src==dst) return; | |||
| if(dstStride==srcStride) fast_memcpy(dst, src, srcStride*height); | |||
| else | |||
| { | |||
| for(y=0; y<height; y++) | |||
| { | |||
| fast_memcpy(dst, src, width); | |||
| dst+= dstStride; | |||
| src+= srcStride; | |||
| } | |||
| } | |||
| return; | |||
| } | |||
| for(y=0; y<height; y++) | |||
| { | |||
| if(fp->temporal) shift= rand()&(MAX_SHIFT -1); | |||
| else shift= nonTempRandShift[y]; | |||
| if(fp->quality==0) shift&= ~7; | |||
| if (fp->averaged) { | |||
| lineNoiseAvg(dst, src, width, fp->prev_shift[y]); | |||
| fp->prev_shift[y][fp->shiftptr] = noise + shift; | |||
| } else { | |||
| lineNoise(dst, src, noise, width, shift); | |||
| } | |||
| dst+= dstStride; | |||
| src+= srcStride; | |||
| } | |||
| fp->shiftptr++; | |||
| if (fp->shiftptr == 3) fp->shiftptr = 0; | |||
| } | |||
| static int config(struct vf_instance *vf, | |||
| int width, int height, int d_width, int d_height, | |||
| unsigned int flags, unsigned int outfmt){ | |||
| return vf_next_config(vf,width,height,d_width,d_height,flags,outfmt); | |||
| } | |||
| static void get_image(struct vf_instance *vf, mp_image_t *mpi){ | |||
| if(mpi->flags&MP_IMGFLAG_PRESERVE) return; // don't change | |||
| if(mpi->imgfmt!=vf->priv->outfmt) return; // colorspace differ | |||
| // ok, we can do pp in-place (or pp disabled): | |||
| vf->dmpi=vf_get_image(vf->next,mpi->imgfmt, | |||
| mpi->type, mpi->flags, mpi->w, mpi->h); | |||
| mpi->planes[0]=vf->dmpi->planes[0]; | |||
| mpi->stride[0]=vf->dmpi->stride[0]; | |||
| mpi->width=vf->dmpi->width; | |||
| if(mpi->flags&MP_IMGFLAG_PLANAR){ | |||
| mpi->planes[1]=vf->dmpi->planes[1]; | |||
| mpi->planes[2]=vf->dmpi->planes[2]; | |||
| mpi->stride[1]=vf->dmpi->stride[1]; | |||
| mpi->stride[2]=vf->dmpi->stride[2]; | |||
| } | |||
| mpi->flags|=MP_IMGFLAG_DIRECT; | |||
| } | |||
| static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts){ | |||
| mp_image_t *dmpi; | |||
| if(!(mpi->flags&MP_IMGFLAG_DIRECT)){ | |||
| // no DR, so get a new image! hope we'll get DR buffer: | |||
| vf->dmpi=vf_get_image(vf->next,vf->priv->outfmt, | |||
| MP_IMGTYPE_TEMP, MP_IMGFLAG_ACCEPT_STRIDE, | |||
| mpi->w,mpi->h); | |||
| //printf("nodr\n"); | |||
| } | |||
| //else printf("dr\n"); | |||
| dmpi= vf->dmpi; | |||
| noise(dmpi->planes[0], mpi->planes[0], dmpi->stride[0], mpi->stride[0], mpi->w, mpi->h, &vf->priv->lumaParam); | |||
| noise(dmpi->planes[1], mpi->planes[1], dmpi->stride[1], mpi->stride[1], mpi->w/2, mpi->h/2, &vf->priv->chromaParam); | |||
| noise(dmpi->planes[2], mpi->planes[2], dmpi->stride[2], mpi->stride[2], mpi->w/2, mpi->h/2, &vf->priv->chromaParam); | |||
| vf_clone_mpi_attributes(dmpi, mpi); | |||
| #if HAVE_MMX | |||
| if(gCpuCaps.hasMMX) __asm__ volatile ("emms\n\t"); | |||
| #endif | |||
| #if HAVE_MMX2 | |||
| if(gCpuCaps.hasMMX2) __asm__ volatile ("sfence\n\t"); | |||
| #endif | |||
| return vf_next_put_image(vf,dmpi, pts); | |||
| } | |||
| static void uninit(struct vf_instance *vf){ | |||
| if(!vf->priv) return; | |||
| av_free(vf->priv->chromaParam.noise); | |||
| vf->priv->chromaParam.noise= NULL; | |||
| av_free(vf->priv->lumaParam.noise); | |||
| vf->priv->lumaParam.noise= NULL; | |||
| free(vf->priv); | |||
| vf->priv=NULL; | |||
| } | |||
| //===========================================================================// | |||
| static int query_format(struct vf_instance *vf, unsigned int fmt){ | |||
| switch(fmt) | |||
| { | |||
| case IMGFMT_YV12: | |||
| case IMGFMT_I420: | |||
| case IMGFMT_IYUV: | |||
| return vf_next_query_format(vf,vf->priv->outfmt); | |||
| } | |||
| return 0; | |||
| } | |||
| static void parse(FilterParam *fp, char* args){ | |||
| char *pos; | |||
| char *max= strchr(args, ':'); | |||
| if(!max) max= args + strlen(args); | |||
| fp->strength= atoi(args); | |||
| pos= strchr(args, 'u'); | |||
| if(pos && pos<max) fp->uniform=1; | |||
| pos= strchr(args, 't'); | |||
| if(pos && pos<max) fp->temporal=1; | |||
| pos= strchr(args, 'h'); | |||
| if(pos && pos<max) fp->quality=1; | |||
| pos= strchr(args, 'p'); | |||
| if(pos && pos<max) fp->pattern=1; | |||
| pos= strchr(args, 'a'); | |||
| if(pos && pos<max) { | |||
| fp->temporal=1; | |||
| fp->averaged=1; | |||
| } | |||
| if(fp->strength) initNoise(fp); | |||
| } | |||
| static const unsigned int fmt_list[]={ | |||
| IMGFMT_YV12, | |||
| IMGFMT_I420, | |||
| IMGFMT_IYUV, | |||
| 0 | |||
| }; | |||
| static int vf_open(vf_instance_t *vf, char *args){ | |||
| vf->config=config; | |||
| vf->put_image=put_image; | |||
| vf->get_image=get_image; | |||
| vf->query_format=query_format; | |||
| vf->uninit=uninit; | |||
| vf->priv=malloc(sizeof(struct vf_priv_s)); | |||
| memset(vf->priv, 0, sizeof(struct vf_priv_s)); | |||
| if(args) | |||
| { | |||
| char *arg2= strchr(args,':'); | |||
| if(arg2) parse(&vf->priv->chromaParam, arg2+1); | |||
| parse(&vf->priv->lumaParam, args); | |||
| } | |||
| // check csp: | |||
| vf->priv->outfmt=vf_match_csp(&vf->next,fmt_list,IMGFMT_YV12); | |||
| if(!vf->priv->outfmt) | |||
| { | |||
| uninit(vf); | |||
| return 0; // no csp match :( | |||
| } | |||
| #if HAVE_MMX | |||
| if(gCpuCaps.hasMMX){ | |||
| lineNoise= lineNoise_MMX; | |||
| lineNoiseAvg= lineNoiseAvg_MMX; | |||
| } | |||
| #endif | |||
| #if HAVE_MMX2 | |||
| if(gCpuCaps.hasMMX2) lineNoise= lineNoise_MMX2; | |||
| // if(gCpuCaps.hasMMX) lineNoiseAvg= lineNoiseAvg_MMX2; | |||
| #endif | |||
| return 1; | |||
| } | |||
| const vf_info_t vf_info_noise = { | |||
| "noise generator", | |||
| "noise", | |||
| "Michael Niedermayer", | |||
| "", | |||
| vf_open, | |||
| NULL | |||
| }; | |||
| //===========================================================================// | |||
| @@ -0,0 +1,322 @@ | |||
| /* | |||
| * Copyright (C) 2007 Michael Niedermayer <michaelni@gmx.at> | |||
| * | |||
| * This file is part of MPlayer. | |||
| * | |||
| * MPlayer 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. | |||
| * | |||
| * MPlayer 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 MPlayer; if not, write to the Free Software Foundation, Inc., | |||
| * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | |||
| */ | |||
| /** | |||
| * @todo try to change to int | |||
| * @todo try lifting based implementation | |||
| * @todo optimize optimize optimize | |||
| * @todo hard tresholding | |||
| * @todo use QP to decide filter strength | |||
| * @todo wavelet normalization / least squares optimal signal vs. noise thresholds | |||
| */ | |||
| #include <stdio.h> | |||
| #include <string.h> | |||
| #include <inttypes.h> | |||
| #include <math.h> | |||
| #include "mp_msg.h" | |||
| #include "img_format.h" | |||
| #include "mp_image.h" | |||
| #include "vf.h" | |||
| //===========================================================================// | |||
| static const uint8_t __attribute__((aligned(8))) dither[8][8]={ | |||
| { 0, 48, 12, 60, 3, 51, 15, 63, }, | |||
| { 32, 16, 44, 28, 35, 19, 47, 31, }, | |||
| { 8, 56, 4, 52, 11, 59, 7, 55, }, | |||
| { 40, 24, 36, 20, 43, 27, 39, 23, }, | |||
| { 2, 50, 14, 62, 1, 49, 13, 61, }, | |||
| { 34, 18, 46, 30, 33, 17, 45, 29, }, | |||
| { 10, 58, 6, 54, 9, 57, 5, 53, }, | |||
| { 42, 26, 38, 22, 41, 25, 37, 21, }, | |||
| }; | |||
| //FIXME the above is duplicated in many filters | |||
| struct vf_priv_s { | |||
| float strength[2]; | |||
| float delta; | |||
| int mode; | |||
| int depth; | |||
| float *plane[16][4]; | |||
| int stride; | |||
| }; | |||
| #define S 1.41421356237 //sqrt(2) | |||
| static const double coeff[2][5]={ | |||
| { | |||
| 0.6029490182363579 *S, | |||
| 0.2668641184428723 *S, | |||
| -0.07822326652898785 *S, | |||
| -0.01686411844287495 *S, | |||
| 0.02674875741080976 *S | |||
| },{ | |||
| 1.115087052456994 /S, | |||
| -0.5912717631142470 /S, | |||
| -0.05754352622849957 /S, | |||
| 0.09127176311424948 /S | |||
| } | |||
| }; | |||
| static const double icoeff[2][5]={ | |||
| { | |||
| 1.115087052456994 /S, | |||
| 0.5912717631142470 /S, | |||
| -0.05754352622849957 /S, | |||
| -0.09127176311424948 /S | |||
| },{ | |||
| 0.6029490182363579 *S, | |||
| -0.2668641184428723 *S, | |||
| -0.07822326652898785 *S, | |||
| 0.01686411844287495 *S, | |||
| 0.02674875741080976 *S | |||
| } | |||
| }; | |||
| #undef S | |||
| static inline int mirror(int x, int w){ | |||
| while((unsigned)x > (unsigned)w){ | |||
| x=-x; | |||
| if(x<0) x+= 2*w; | |||
| } | |||
| return x; | |||
| } | |||
| static inline void decompose(float *dstL, float *dstH, float *src, int stride, int w){ | |||
| int x, i; | |||
| for(x=0; x<w; x++){ | |||
| double sumL= src[x*stride] * coeff[0][0]; | |||
| double sumH= src[x*stride] * coeff[1][0]; | |||
| for(i=1; i<=4; i++){ | |||
| double s= (src[mirror(x-i, w-1)*stride] + src[mirror(x+i, w-1)*stride]); | |||
| sumL+= coeff[0][i]*s; | |||
| sumH+= coeff[1][i]*s; | |||
| } | |||
| dstL[x*stride]= sumL; | |||
| dstH[x*stride]= sumH; | |||
| } | |||
| } | |||
| static inline void compose(float *dst, float *srcL, float *srcH, int stride, int w){ | |||
| int x, i; | |||
| for(x=0; x<w; x++){ | |||
| double sumL= srcL[x*stride] * icoeff[0][0]; | |||
| double sumH= srcH[x*stride] * icoeff[1][0]; | |||
| for(i=1; i<=4; i++){ | |||
| int x0= mirror(x-i, w-1)*stride; | |||
| int x1= mirror(x+i, w-1)*stride; | |||
| sumL+= icoeff[0][i]*(srcL[x0] + srcL[x1]); | |||
| sumH+= icoeff[1][i]*(srcH[x0] + srcH[x1]); | |||
| } | |||
| dst[x*stride]= (sumL + sumH)*0.5; | |||
| } | |||
| } | |||
| static inline void decompose2D(float *dstL, float *dstH, float *src, int xstride, int ystride, int step, int w, int h){ | |||
| int y, x; | |||
| for(y=0; y<h; y++) | |||
| for(x=0; x<step; x++) | |||
| decompose(dstL + ystride*y + xstride*x, dstH + ystride*y + xstride*x, src + ystride*y + xstride*x, step*xstride, (w-x+step-1)/step); | |||
| } | |||
| static inline void compose2D(float *dst, float *srcL, float *srcH, int xstride, int ystride, int step, int w, int h){ | |||
| int y, x; | |||
| for(y=0; y<h; y++) | |||
| for(x=0; x<step; x++) | |||
| compose(dst + ystride*y + xstride*x, srcL + ystride*y + xstride*x, srcH + ystride*y + xstride*x, step*xstride, (w-x+step-1)/step); | |||
| } | |||
| static void decompose2D2(float *dst[4], float *src, float *temp[2], int stride, int step, int w, int h){ | |||
| decompose2D(temp[0], temp[1], src , 1, stride, step , w, h); | |||
| decompose2D( dst[0], dst[1], temp[0], stride, 1, step , h, w); | |||
| decompose2D( dst[2], dst[3], temp[1], stride, 1, step , h, w); | |||
| } | |||
| static void compose2D2(float *dst, float *src[4], float *temp[2], int stride, int step, int w, int h){ | |||
| compose2D(temp[0], src[0], src[1], stride, 1, step , h, w); | |||
| compose2D(temp[1], src[2], src[3], stride, 1, step , h, w); | |||
| compose2D(dst , temp[0], temp[1], 1, stride, step , w, h); | |||
| } | |||
| static void filter(struct vf_priv_s *p, uint8_t *dst, uint8_t *src, int dst_stride, int src_stride, int width, int height, int is_luma){ | |||
| int x,y, i, j; | |||
| // double sum=0; | |||
| double s= p->strength[!is_luma]; | |||
| int depth= p->depth; | |||
| while(1<<depth > width || 1<<depth > height) | |||
| depth--; | |||
| for(y=0; y<height; y++) | |||
| for(x=0; x<width; x++) | |||
| p->plane[0][0][x + y*p->stride]= src[x + y*src_stride]; | |||
| for(i=0; i<depth; i++){ | |||
| decompose2D2(p->plane[i+1], p->plane[i][0], p->plane[0]+1,p->stride, 1<<i, width, height); | |||
| } | |||
| for(i=0; i<depth; i++){ | |||
| for(j=1; j<4; j++){ | |||
| for(y=0; y<height; y++){ | |||
| for(x=0; x<width; x++){ | |||
| double v= p->plane[i+1][j][x + y*p->stride]; | |||
| if (v> s) v-=s; | |||
| else if(v<-s) v+=s; | |||
| else v =0; | |||
| p->plane[i+1][j][x + y*p->stride]= v; | |||
| } | |||
| } | |||
| } | |||
| } | |||
| for(i=depth-1; i>=0; i--){ | |||
| compose2D2(p->plane[i][0], p->plane[i+1], p->plane[0]+1, p->stride, 1<<i, width, height); | |||
| } | |||
| for(y=0; y<height; y++) | |||
| for(x=0; x<width; x++){ | |||
| i= p->plane[0][0][x + y*p->stride] + dither[x&7][y&7]*(1.0/64) + 1.0/128; //yes the rounding is insane but optimal :) | |||
| // double e= i - src[x + y*src_stride]; | |||
| // sum += e*e; | |||
| if((unsigned)i > 255U) i= ~(i>>31); | |||
| dst[x + y*dst_stride]= i; | |||
| } | |||
| // printf("%f\n", sum/height/width); | |||
| } | |||
| static int config(struct vf_instance *vf, int width, int height, int d_width, int d_height, unsigned int flags, unsigned int outfmt){ | |||
| int h= (height+15)&(~15); | |||
| int i,j; | |||
| vf->priv->stride= (width+15)&(~15); | |||
| for(j=0; j<4; j++){ | |||
| for(i=0; i<=vf->priv->depth; i++) | |||
| vf->priv->plane[i][j]= malloc(vf->priv->stride*h*sizeof(vf->priv->plane[0][0][0])); | |||
| } | |||
| return vf_next_config(vf,width,height,d_width,d_height,flags,outfmt); | |||
| } | |||
| static void get_image(struct vf_instance *vf, mp_image_t *mpi){ | |||
| if(mpi->flags&MP_IMGFLAG_PRESERVE) return; // don't change | |||
| // ok, we can do pp in-place (or pp disabled): | |||
| vf->dmpi=vf_get_image(vf->next,mpi->imgfmt, | |||
| mpi->type, mpi->flags | MP_IMGFLAG_READABLE, mpi->width, mpi->height); | |||
| mpi->planes[0]=vf->dmpi->planes[0]; | |||
| mpi->stride[0]=vf->dmpi->stride[0]; | |||
| mpi->width=vf->dmpi->width; | |||
| if(mpi->flags&MP_IMGFLAG_PLANAR){ | |||
| mpi->planes[1]=vf->dmpi->planes[1]; | |||
| mpi->planes[2]=vf->dmpi->planes[2]; | |||
| mpi->stride[1]=vf->dmpi->stride[1]; | |||
| mpi->stride[2]=vf->dmpi->stride[2]; | |||
| } | |||
| mpi->flags|=MP_IMGFLAG_DIRECT; | |||
| } | |||
| static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts){ | |||
| mp_image_t *dmpi; | |||
| if(!(mpi->flags&MP_IMGFLAG_DIRECT)){ | |||
| // no DR, so get a new image! hope we'll get DR buffer: | |||
| dmpi=vf_get_image(vf->next,mpi->imgfmt, | |||
| MP_IMGTYPE_TEMP, | |||
| MP_IMGFLAG_ACCEPT_STRIDE|MP_IMGFLAG_PREFER_ALIGNED_STRIDE, | |||
| mpi->width,mpi->height); | |||
| vf_clone_mpi_attributes(dmpi, mpi); | |||
| }else{ | |||
| dmpi=vf->dmpi; | |||
| } | |||
| filter(vf->priv, dmpi->planes[0], mpi->planes[0], dmpi->stride[0], mpi->stride[0], mpi->w, mpi->h, 1); | |||
| filter(vf->priv, dmpi->planes[1], mpi->planes[1], dmpi->stride[1], mpi->stride[1], mpi->w>>mpi->chroma_x_shift, mpi->h>>mpi->chroma_y_shift, 0); | |||
| filter(vf->priv, dmpi->planes[2], mpi->planes[2], dmpi->stride[2], mpi->stride[2], mpi->w>>mpi->chroma_x_shift, mpi->h>>mpi->chroma_y_shift, 0); | |||
| return vf_next_put_image(vf,dmpi, pts); | |||
| } | |||
| static void uninit(struct vf_instance *vf){ | |||
| int i,j; | |||
| if(!vf->priv) return; | |||
| for(j=0; j<4; j++){ | |||
| for(i=0; i<16; i++){ | |||
| free(vf->priv->plane[i][j]); | |||
| vf->priv->plane[i][j]= NULL; | |||
| } | |||
| } | |||
| free(vf->priv); | |||
| vf->priv=NULL; | |||
| } | |||
| //===========================================================================// | |||
| static int query_format(struct vf_instance *vf, unsigned int fmt){ | |||
| switch(fmt){ | |||
| case IMGFMT_YVU9: | |||
| case IMGFMT_IF09: | |||
| case IMGFMT_YV12: | |||
| case IMGFMT_I420: | |||
| case IMGFMT_IYUV: | |||
| case IMGFMT_CLPL: | |||
| case IMGFMT_Y800: | |||
| case IMGFMT_Y8: | |||
| case IMGFMT_444P: | |||
| case IMGFMT_422P: | |||
| case IMGFMT_411P: | |||
| return vf_next_query_format(vf,fmt); | |||
| } | |||
| return 0; | |||
| } | |||
| static int vf_open(vf_instance_t *vf, char *args){ | |||
| vf->config=config; | |||
| vf->put_image=put_image; | |||
| vf->get_image=get_image; | |||
| vf->query_format=query_format; | |||
| vf->uninit=uninit; | |||
| vf->priv=malloc(sizeof(struct vf_priv_s)); | |||
| memset(vf->priv, 0, sizeof(struct vf_priv_s)); | |||
| vf->priv->depth= 8; | |||
| vf->priv->strength[0]= 1.0; | |||
| vf->priv->strength[1]= 1.0; | |||
| vf->priv->delta= 1.0; | |||
| if (args) sscanf(args, "%d:%f:%f:%d:%f", &vf->priv->depth, | |||
| &vf->priv->strength[0], | |||
| &vf->priv->strength[1], | |||
| &vf->priv->mode, | |||
| &vf->priv->delta); | |||
| return 1; | |||
| } | |||
| const vf_info_t vf_info_ow = { | |||
| "overcomplete wavelet denoiser", | |||
| "ow", | |||
| "Michael Niedermayer", | |||
| "", | |||
| vf_open, | |||
| NULL | |||
| }; | |||
| @@ -0,0 +1,235 @@ | |||
| /* | |||
| * This file is part of MPlayer. | |||
| * | |||
| * MPlayer 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. | |||
| * | |||
| * MPlayer 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 MPlayer; if not, write to the Free Software Foundation, Inc., | |||
| * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | |||
| */ | |||
| #include <stdio.h> | |||
| #include <stdlib.h> | |||
| #include <string.h> | |||
| #include <inttypes.h> | |||
| #include "config.h" | |||
| #include "mp_msg.h" | |||
| #include "help_mp.h" | |||
| #include "img_format.h" | |||
| #include "mp_image.h" | |||
| #include "vf.h" | |||
| #include "mpbswap.h" | |||
| #include "libswscale/swscale.h" | |||
| //===========================================================================// | |||
| // commented out 16 and 15 bit output support, because the conversion | |||
| // routines are incorrrect. they assume the palette to be of the same | |||
| // depth as the output, which is incorrect. --Joey | |||
| static const unsigned int bgr_list[]={ | |||
| IMGFMT_BGR32, | |||
| IMGFMT_BGR24, | |||
| // IMGFMT_BGR16, | |||
| // IMGFMT_BGR15, | |||
| 0 | |||
| }; | |||
| static const unsigned int rgb_list[]={ | |||
| IMGFMT_RGB32, | |||
| IMGFMT_RGB24, | |||
| // IMGFMT_RGB16, | |||
| // IMGFMT_RGB15, | |||
| 0 | |||
| }; | |||
| /** | |||
| * Palette is assumed to contain BGR16, see rgb32to16 to convert the palette. | |||
| */ | |||
| static void palette8torgb16(const uint8_t *src, uint8_t *dst, long num_pixels, const uint8_t *palette) | |||
| { | |||
| long i; | |||
| for (i=0; i<num_pixels; i++) | |||
| ((uint16_t *)dst)[i] = ((const uint16_t *)palette)[src[i]]; | |||
| } | |||
| static void palette8tobgr16(const uint8_t *src, uint8_t *dst, long num_pixels, const uint8_t *palette) | |||
| { | |||
| long i; | |||
| for (i=0; i<num_pixels; i++) | |||
| ((uint16_t *)dst)[i] = bswap_16(((const uint16_t *)palette)[src[i]]); | |||
| } | |||
| static unsigned int gray_pal[256]; | |||
| static unsigned int find_best(struct vf_instance *vf, unsigned int fmt){ | |||
| unsigned int best=0; | |||
| int ret; | |||
| const unsigned int* p; | |||
| if(fmt==IMGFMT_BGR8) p=bgr_list; | |||
| else if(fmt==IMGFMT_RGB8) p=rgb_list; | |||
| else return 0; | |||
| while(*p){ | |||
| ret=vf->next->query_format(vf->next,*p); | |||
| mp_msg(MSGT_VFILTER,MSGL_DBG2,"[%s] query(%s) -> %d\n",vf->info->name,vo_format_name(*p),ret&3); | |||
| if(ret&VFCAP_CSP_SUPPORTED_BY_HW){ best=*p; break;} // no conversion -> bingo! | |||
| if(ret&VFCAP_CSP_SUPPORTED && !best) best=*p; // best with conversion | |||
| ++p; | |||
| } | |||
| return best; | |||
| } | |||
| //===========================================================================// | |||
| struct vf_priv_s { | |||
| unsigned int fmt; | |||
| int pal_msg; | |||
| }; | |||
| static int config(struct vf_instance *vf, | |||
| int width, int height, int d_width, int d_height, | |||
| unsigned int flags, unsigned int outfmt){ | |||
| if (!vf->priv->fmt) | |||
| vf->priv->fmt=find_best(vf,outfmt); | |||
| if(!vf->priv->fmt){ | |||
| // no matching fmt, so force one... | |||
| if(outfmt==IMGFMT_RGB8) vf->priv->fmt=IMGFMT_RGB32; | |||
| else if(outfmt==IMGFMT_BGR8) vf->priv->fmt=IMGFMT_BGR32; | |||
| else return 0; | |||
| } | |||
| return vf_next_config(vf,width,height,d_width,d_height,flags,vf->priv->fmt); | |||
| } | |||
| static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts){ | |||
| mp_image_t *dmpi; | |||
| uint8_t *old_palette = mpi->planes[1]; | |||
| // hope we'll get DR buffer: | |||
| dmpi=vf_get_image(vf->next,vf->priv->fmt, | |||
| MP_IMGTYPE_TEMP, MP_IMGFLAG_ACCEPT_STRIDE, | |||
| mpi->w, mpi->h); | |||
| if (!mpi->planes[1]) | |||
| { | |||
| if(!vf->priv->pal_msg){ | |||
| mp_msg(MSGT_VFILTER,MSGL_V,"[%s] no palette given, assuming builtin grayscale one\n",vf->info->name); | |||
| vf->priv->pal_msg=1; | |||
| } | |||
| mpi->planes[1] = (unsigned char*)gray_pal; | |||
| } | |||
| if(mpi->w==mpi->stride[0] && dmpi->w*(dmpi->bpp>>3)==dmpi->stride[0]){ | |||
| // no stride conversion needed | |||
| switch(IMGFMT_RGB_DEPTH(dmpi->imgfmt)){ | |||
| case 15: | |||
| case 16: | |||
| if (IMGFMT_IS_BGR(dmpi->imgfmt)) | |||
| palette8tobgr16(mpi->planes[0],dmpi->planes[0],mpi->h*mpi->w,mpi->planes[1]); | |||
| else | |||
| palette8torgb16(mpi->planes[0],dmpi->planes[0],mpi->h*mpi->w,mpi->planes[1]); | |||
| break; | |||
| case 24: | |||
| if (IMGFMT_IS_BGR(dmpi->imgfmt)) | |||
| sws_convertPalette8ToPacked24(mpi->planes[0],dmpi->planes[0],mpi->h*mpi->w,mpi->planes[1]); | |||
| else | |||
| sws_convertPalette8ToPacked24(mpi->planes[0],dmpi->planes[0],mpi->h*mpi->w,mpi->planes[1]); | |||
| break; | |||
| case 32: | |||
| if (IMGFMT_IS_BGR(dmpi->imgfmt)) | |||
| sws_convertPalette8ToPacked32(mpi->planes[0],dmpi->planes[0],mpi->h*mpi->w,mpi->planes[1]); | |||
| else | |||
| sws_convertPalette8ToPacked32(mpi->planes[0],dmpi->planes[0],mpi->h*mpi->w,mpi->planes[1]); | |||
| break; | |||
| } | |||
| } else { | |||
| int y; | |||
| for(y=0;y<mpi->h;y++){ | |||
| unsigned char* src=mpi->planes[0]+y*mpi->stride[0]; | |||
| unsigned char* dst=dmpi->planes[0]+y*dmpi->stride[0]; | |||
| switch(IMGFMT_RGB_DEPTH(dmpi->imgfmt)){ | |||
| case 15: | |||
| case 16: | |||
| if (IMGFMT_IS_BGR(dmpi->imgfmt)) | |||
| palette8tobgr16(src,dst,mpi->w,mpi->planes[1]); | |||
| else | |||
| palette8torgb16(src,dst,mpi->w,mpi->planes[1]); | |||
| break; | |||
| case 24: | |||
| if (IMGFMT_IS_BGR(dmpi->imgfmt)) | |||
| sws_convertPalette8ToPacked24(src,dst,mpi->w,mpi->planes[1]); | |||
| else | |||
| sws_convertPalette8ToPacked24(src,dst,mpi->w,mpi->planes[1]); | |||
| break; | |||
| case 32: | |||
| if (IMGFMT_IS_BGR(dmpi->imgfmt)) | |||
| sws_convertPalette8ToPacked32(src,dst,mpi->w,mpi->planes[1]); | |||
| else | |||
| sws_convertPalette8ToPacked32(src,dst,mpi->w,mpi->planes[1]); | |||
| break; | |||
| } | |||
| } | |||
| } | |||
| mpi->planes[1] = old_palette; | |||
| return vf_next_put_image(vf,dmpi, pts); | |||
| } | |||
| //===========================================================================// | |||
| static int query_format(struct vf_instance *vf, unsigned int fmt){ | |||
| int best=find_best(vf,fmt); | |||
| if(!best) return 0; // no match | |||
| return vf->next->query_format(vf->next,best); | |||
| } | |||
| static void uninit(vf_instance_t *vf) { | |||
| free(vf->priv); | |||
| } | |||
| static int vf_open(vf_instance_t *vf, char *args){ | |||
| unsigned int i; | |||
| vf->config=config; | |||
| vf->uninit=uninit; | |||
| vf->put_image=put_image; | |||
| vf->query_format=query_format; | |||
| vf->priv=malloc(sizeof(struct vf_priv_s)); | |||
| memset(vf->priv, 0, sizeof(struct vf_priv_s)); | |||
| for(i=0;i<256;i++) gray_pal[i]=0x01010101*i; | |||
| if (args) | |||
| { | |||
| if (!strcasecmp(args,"rgb15")) vf->priv->fmt=IMGFMT_RGB15; else | |||
| if (!strcasecmp(args,"rgb16")) vf->priv->fmt=IMGFMT_RGB16; else | |||
| if (!strcasecmp(args,"rgb24")) vf->priv->fmt=IMGFMT_RGB24; else | |||
| if (!strcasecmp(args,"rgb32")) vf->priv->fmt=IMGFMT_RGB32; else | |||
| if (!strcasecmp(args,"bgr15")) vf->priv->fmt=IMGFMT_BGR15; else | |||
| if (!strcasecmp(args,"bgr16")) vf->priv->fmt=IMGFMT_BGR16; else | |||
| if (!strcasecmp(args,"bgr24")) vf->priv->fmt=IMGFMT_BGR24; else | |||
| if (!strcasecmp(args,"bgr32")) vf->priv->fmt=IMGFMT_BGR32; else | |||
| { | |||
| mp_msg(MSGT_VFILTER, MSGL_WARN, MSGTR_MPCODECS_UnknownFormatName, args); | |||
| return 0; | |||
| } | |||
| } | |||
| return 1; | |||
| } | |||
| const vf_info_t vf_info_palette = { | |||
| "8bpp indexed (using palette) -> BGR 15/16/24/32 conversion", | |||
| "palette", | |||
| "A'rpi & Alex", | |||
| "", | |||
| vf_open, | |||
| NULL | |||
| }; | |||
| //===========================================================================// | |||
| @@ -0,0 +1,343 @@ | |||
| /* | |||
| * Copyright (C) 2002 Michael Niedermayer <michaelni@gmx.at> | |||
| * | |||
| * This file is part of MPlayer. | |||
| * | |||
| * MPlayer 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. | |||
| * | |||
| * MPlayer 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 MPlayer; if not, write to the Free Software Foundation, Inc., | |||
| * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | |||
| */ | |||
| #include <stdio.h> | |||
| #include <stdlib.h> | |||
| #include <string.h> | |||
| #include <inttypes.h> | |||
| #include <assert.h> | |||
| #include <math.h> | |||
| #include "config.h" | |||
| #include "mp_msg.h" | |||
| #if HAVE_MALLOC_H | |||
| #include <malloc.h> | |||
| #endif | |||
| #include "img_format.h" | |||
| #include "mp_image.h" | |||
| #include "vf.h" | |||
| #define SUB_PIXEL_BITS 8 | |||
| #define SUB_PIXELS (1<<SUB_PIXEL_BITS) | |||
| #define COEFF_BITS 11 | |||
| //===========================================================================// | |||
| struct vf_priv_s { | |||
| double ref[4][2]; | |||
| int32_t coeff[1<<SUB_PIXEL_BITS][4]; | |||
| int32_t (*pv)[2]; | |||
| int pvStride; | |||
| int cubic; | |||
| }; | |||
| /***************************************************************************/ | |||
| static void initPv(struct vf_priv_s *priv, int W, int H){ | |||
| double a,b,c,d,e,f,g,h,D; | |||
| double (*ref)[2]= priv->ref; | |||
| int x,y; | |||
| g= ( (ref[0][0] - ref[1][0] - ref[2][0] + ref[3][0])*(ref[2][1] - ref[3][1]) | |||
| - (ref[0][1] - ref[1][1] - ref[2][1] + ref[3][1])*(ref[2][0] - ref[3][0]))*H; | |||
| h= ( (ref[0][1] - ref[1][1] - ref[2][1] + ref[3][1])*(ref[1][0] - ref[3][0]) | |||
| - (ref[0][0] - ref[1][0] - ref[2][0] + ref[3][0])*(ref[1][1] - ref[3][1]))*W; | |||
| D= (ref[1][0] - ref[3][0])*(ref[2][1] - ref[3][1]) | |||
| - (ref[2][0] - ref[3][0])*(ref[1][1] - ref[3][1]); | |||
| a= D*(ref[1][0] - ref[0][0])*H + g*ref[1][0]; | |||
| b= D*(ref[2][0] - ref[0][0])*W + h*ref[2][0]; | |||
| c= D*ref[0][0]*W*H; | |||
| d= D*(ref[1][1] - ref[0][1])*H + g*ref[1][1]; | |||
| e= D*(ref[2][1] - ref[0][1])*W + h*ref[2][1]; | |||
| f= D*ref[0][1]*W*H; | |||
| for(y=0; y<H; y++){ | |||
| for(x=0; x<W; x++){ | |||
| int u, v; | |||
| u= (int)floor( SUB_PIXELS*(a*x + b*y + c)/(g*x + h*y + D*W*H) + 0.5); | |||
| v= (int)floor( SUB_PIXELS*(d*x + e*y + f)/(g*x + h*y + D*W*H) + 0.5); | |||
| priv->pv[x + y*W][0]= u; | |||
| priv->pv[x + y*W][1]= v; | |||
| } | |||
| } | |||
| } | |||
| static double getCoeff(double d){ | |||
| double A= -0.60; | |||
| double coeff; | |||
| d= fabs(d); | |||
| // Equation is from VirtualDub | |||
| if(d<1.0) | |||
| coeff = (1.0 - (A+3.0)*d*d + (A+2.0)*d*d*d); | |||
| else if(d<2.0) | |||
| coeff = (-4.0*A + 8.0*A*d - 5.0*A*d*d + A*d*d*d); | |||
| else | |||
| coeff=0.0; | |||
| return coeff; | |||
| } | |||
| static int config(struct vf_instance *vf, | |||
| int width, int height, int d_width, int d_height, | |||
| unsigned int flags, unsigned int outfmt){ | |||
| int i, j; | |||
| vf->priv->pvStride= width; | |||
| vf->priv->pv= (void*)memalign(8, width*height*2*sizeof(int32_t)); | |||
| initPv(vf->priv, width, height); | |||
| for(i=0; i<SUB_PIXELS; i++){ | |||
| double d= i/(double)SUB_PIXELS; | |||
| double temp[4]; | |||
| double sum=0; | |||
| for(j=0; j<4; j++) | |||
| temp[j]= getCoeff(j - d - 1); | |||
| for(j=0; j<4; j++) | |||
| sum+= temp[j]; | |||
| for(j=0; j<4; j++) | |||
| vf->priv->coeff[i][j]= (int)floor((1<<COEFF_BITS)*temp[j]/sum + 0.5); | |||
| } | |||
| return vf_next_config(vf,width,height,d_width,d_height,flags,outfmt); | |||
| } | |||
| static void uninit(struct vf_instance *vf){ | |||
| if(!vf->priv) return; | |||
| free(vf->priv->pv); | |||
| vf->priv->pv= NULL; | |||
| free(vf->priv); | |||
| vf->priv=NULL; | |||
| } | |||
| static inline void resampleCubic(uint8_t *dst, uint8_t *src, int w, int h, int dstStride, int srcStride, struct vf_priv_s *privParam, int xShift, int yShift){ | |||
| int x, y; | |||
| struct vf_priv_s priv= *privParam; | |||
| for(y=0; y<h; y++){ | |||
| for(x=0; x<w; x++){ | |||
| int u, v, subU, subV, sum, sx, sy; | |||
| sx= x << xShift; | |||
| sy= y << yShift; | |||
| u= priv.pv[sx + sy*priv.pvStride][0]>>xShift; | |||
| v= priv.pv[sx + sy*priv.pvStride][1]>>yShift; | |||
| subU= u & (SUB_PIXELS-1); | |||
| subV= v & (SUB_PIXELS-1); | |||
| u >>= SUB_PIXEL_BITS; | |||
| v >>= SUB_PIXEL_BITS; | |||
| if(u>0 && v>0 && u<w-2 && v<h-2){ | |||
| const int index= u + v*srcStride; | |||
| const int a= priv.coeff[subU][0]; | |||
| const int b= priv.coeff[subU][1]; | |||
| const int c= priv.coeff[subU][2]; | |||
| const int d= priv.coeff[subU][3]; | |||
| sum= | |||
| priv.coeff[subV][0]*( a*src[index - 1 - srcStride] + b*src[index - 0 - srcStride] | |||
| + c*src[index + 1 - srcStride] + d*src[index + 2 - srcStride]) | |||
| +priv.coeff[subV][1]*( a*src[index - 1 ] + b*src[index - 0 ] | |||
| + c*src[index + 1 ] + d*src[index + 2 ]) | |||
| +priv.coeff[subV][2]*( a*src[index - 1 + srcStride] + b*src[index - 0 + srcStride] | |||
| + c*src[index + 1 + srcStride] + d*src[index + 2 + srcStride]) | |||
| +priv.coeff[subV][3]*( a*src[index - 1+2*srcStride] + b*src[index - 0+2*srcStride] | |||
| + c*src[index + 1+2*srcStride] + d*src[index + 2+2*srcStride]); | |||
| }else{ | |||
| int dx, dy; | |||
| sum=0; | |||
| for(dy=0; dy<4; dy++){ | |||
| int iy= v + dy - 1; | |||
| if (iy< 0) iy=0; | |||
| else if(iy>=h) iy=h-1; | |||
| for(dx=0; dx<4; dx++){ | |||
| int ix= u + dx - 1; | |||
| if (ix< 0) ix=0; | |||
| else if(ix>=w) ix=w-1; | |||
| sum+= priv.coeff[subU][dx]*priv.coeff[subV][dy] | |||
| *src[ ix + iy*srcStride]; | |||
| } | |||
| } | |||
| } | |||
| sum= (sum + (1<<(COEFF_BITS*2-1)) ) >> (COEFF_BITS*2); | |||
| if(sum&~255){ | |||
| if(sum<0) sum=0; | |||
| else sum=255; | |||
| } | |||
| dst[ x + y*dstStride]= sum; | |||
| } | |||
| } | |||
| } | |||
| static inline void resampleLinear(uint8_t *dst, uint8_t *src, int w, int h, int dstStride, int srcStride, | |||
| struct vf_priv_s *privParam, int xShift, int yShift){ | |||
| int x, y; | |||
| struct vf_priv_s priv= *privParam; | |||
| for(y=0; y<h; y++){ | |||
| for(x=0; x<w; x++){ | |||
| int u, v, subU, subV, sum, sx, sy, index, subUI, subVI; | |||
| sx= x << xShift; | |||
| sy= y << yShift; | |||
| u= priv.pv[sx + sy*priv.pvStride][0]>>xShift; | |||
| v= priv.pv[sx + sy*priv.pvStride][1]>>yShift; | |||
| subU= u & (SUB_PIXELS-1); | |||
| subV= v & (SUB_PIXELS-1); | |||
| u >>= SUB_PIXEL_BITS; | |||
| v >>= SUB_PIXEL_BITS; | |||
| index= u + v*srcStride; | |||
| subUI= SUB_PIXELS - subU; | |||
| subVI= SUB_PIXELS - subV; | |||
| if((unsigned)u < (unsigned)(w - 1)){ | |||
| if((unsigned)v < (unsigned)(h - 1)){ | |||
| sum= subVI*(subUI*src[index ] + subU*src[index +1]) | |||
| +subV *(subUI*src[index+srcStride] + subU*src[index+srcStride+1]); | |||
| sum= (sum + (1<<(SUB_PIXEL_BITS*2-1)) ) >> (SUB_PIXEL_BITS*2); | |||
| }else{ | |||
| if(v<0) v= 0; | |||
| else v= h-1; | |||
| index= u + v*srcStride; | |||
| sum= subUI*src[index] + subU*src[index+1]; | |||
| sum= (sum + (1<<(SUB_PIXEL_BITS-1)) ) >> SUB_PIXEL_BITS; | |||
| } | |||
| }else{ | |||
| if((unsigned)v < (unsigned)(h - 1)){ | |||
| if(u<0) u= 0; | |||
| else u= w-1; | |||
| index= u + v*srcStride; | |||
| sum= subVI*src[index] + subV*src[index+srcStride]; | |||
| sum= (sum + (1<<(SUB_PIXEL_BITS-1)) ) >> SUB_PIXEL_BITS; | |||
| }else{ | |||
| if(u<0) u= 0; | |||
| else u= w-1; | |||
| if(v<0) v= 0; | |||
| else v= h-1; | |||
| index= u + v*srcStride; | |||
| sum= src[index]; | |||
| } | |||
| } | |||
| if(sum&~255){ | |||
| if(sum<0) sum=0; | |||
| else sum=255; | |||
| } | |||
| dst[ x + y*dstStride]= sum; | |||
| } | |||
| } | |||
| } | |||
| static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts){ | |||
| int cw= mpi->w >> mpi->chroma_x_shift; | |||
| int ch= mpi->h >> mpi->chroma_y_shift; | |||
| mp_image_t *dmpi=vf_get_image(vf->next,mpi->imgfmt, | |||
| MP_IMGTYPE_TEMP, MP_IMGFLAG_ACCEPT_STRIDE, | |||
| mpi->w,mpi->h); | |||
| assert(mpi->flags&MP_IMGFLAG_PLANAR); | |||
| if(vf->priv->cubic){ | |||
| resampleCubic(dmpi->planes[0], mpi->planes[0], mpi->w,mpi->h, dmpi->stride[0], mpi->stride[0], | |||
| vf->priv, 0, 0); | |||
| resampleCubic(dmpi->planes[1], mpi->planes[1], cw , ch , dmpi->stride[1], mpi->stride[1], | |||
| vf->priv, mpi->chroma_x_shift, mpi->chroma_y_shift); | |||
| resampleCubic(dmpi->planes[2], mpi->planes[2], cw , ch , dmpi->stride[2], mpi->stride[2], | |||
| vf->priv, mpi->chroma_x_shift, mpi->chroma_y_shift); | |||
| }else{ | |||
| resampleLinear(dmpi->planes[0], mpi->planes[0], mpi->w,mpi->h, dmpi->stride[0], mpi->stride[0], | |||
| vf->priv, 0, 0); | |||
| resampleLinear(dmpi->planes[1], mpi->planes[1], cw , ch , dmpi->stride[1], mpi->stride[1], | |||
| vf->priv, mpi->chroma_x_shift, mpi->chroma_y_shift); | |||
| resampleLinear(dmpi->planes[2], mpi->planes[2], cw , ch , dmpi->stride[2], mpi->stride[2], | |||
| vf->priv, mpi->chroma_x_shift, mpi->chroma_y_shift); | |||
| } | |||
| return vf_next_put_image(vf,dmpi, pts); | |||
| } | |||
| //===========================================================================// | |||
| static int query_format(struct vf_instance *vf, unsigned int fmt){ | |||
| switch(fmt) | |||
| { | |||
| case IMGFMT_YV12: | |||
| case IMGFMT_I420: | |||
| case IMGFMT_IYUV: | |||
| case IMGFMT_YVU9: | |||
| case IMGFMT_444P: | |||
| case IMGFMT_422P: | |||
| case IMGFMT_411P: | |||
| return vf_next_query_format(vf, fmt); | |||
| } | |||
| return 0; | |||
| } | |||
| static int vf_open(vf_instance_t *vf, char *args){ | |||
| int e; | |||
| vf->config=config; | |||
| vf->put_image=put_image; | |||
| // vf->get_image=get_image; | |||
| vf->query_format=query_format; | |||
| vf->uninit=uninit; | |||
| vf->priv=malloc(sizeof(struct vf_priv_s)); | |||
| memset(vf->priv, 0, sizeof(struct vf_priv_s)); | |||
| if(args==NULL) return 0; | |||
| e=sscanf(args, "%lf:%lf:%lf:%lf:%lf:%lf:%lf:%lf:%d", | |||
| &vf->priv->ref[0][0], &vf->priv->ref[0][1], | |||
| &vf->priv->ref[1][0], &vf->priv->ref[1][1], | |||
| &vf->priv->ref[2][0], &vf->priv->ref[2][1], | |||
| &vf->priv->ref[3][0], &vf->priv->ref[3][1], | |||
| &vf->priv->cubic | |||
| ); | |||
| if(e!=9) | |||
| return 0; | |||
| return 1; | |||
| } | |||
| const vf_info_t vf_info_perspective = { | |||
| "perspective correcture", | |||
| "perspective", | |||
| "Michael Niedermayer", | |||
| "", | |||
| vf_open, | |||
| NULL | |||
| }; | |||
| //===========================================================================// | |||
| @@ -0,0 +1,301 @@ | |||
| /* | |||
| * This file is part of MPlayer. | |||
| * | |||
| * MPlayer 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. | |||
| * | |||
| * MPlayer 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 MPlayer; if not, write to the Free Software Foundation, Inc., | |||
| * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | |||
| */ | |||
| #include <stdio.h> | |||
| #include <stdlib.h> | |||
| #include <string.h> | |||
| #include <limits.h> | |||
| #include "config.h" | |||
| #include "mp_msg.h" | |||
| #include "img_format.h" | |||
| #include "mp_image.h" | |||
| #include "vf.h" | |||
| #include "libvo/fastmemcpy.h" | |||
| enum mode { PROGRESSIVE, TOP_FIRST, BOTTOM_FIRST, | |||
| TOP_FIRST_ANALYZE, BOTTOM_FIRST_ANALYZE, | |||
| ANALYZE, FULL_ANALYZE, AUTO, AUTO_ANALYZE }; | |||
| #define fixed_mode(p) ((p)<=BOTTOM_FIRST) | |||
| struct vf_priv_s | |||
| { | |||
| enum mode mode; | |||
| int verbose; | |||
| unsigned char *buf[3]; | |||
| }; | |||
| /* | |||
| * Copy fields from either current or buffered previous frame to the | |||
| * output and store the current frame unmodified to the buffer. | |||
| */ | |||
| static void do_plane(unsigned char *to, unsigned char *from, | |||
| int w, int h, int ts, int fs, | |||
| unsigned char **bufp, enum mode mode) | |||
| { | |||
| unsigned char *buf, *end; | |||
| int top; | |||
| if(!*bufp) | |||
| { | |||
| mode=PROGRESSIVE; | |||
| if(!(*bufp=malloc(h*w))) return; | |||
| } | |||
| for(end=to+h*ts, buf=*bufp, top=1; to<end; from+=fs, to+=ts, buf+=w, top^=1) | |||
| { | |||
| fast_memcpy(to, mode==(top?BOTTOM_FIRST:TOP_FIRST)?buf:from, w); | |||
| fast_memcpy(buf, from, w); | |||
| } | |||
| } | |||
| /* | |||
| * This macro interpolates the value of both fields at a point halfway | |||
| * between lines and takes the squared difference. In field resolution | |||
| * the point is a quarter pixel below a line in one field and a quarter | |||
| * pixel above a line in other. | |||
| * | |||
| * (the result is actually multiplied by 25) | |||
| */ | |||
| #define diff(a, as, b, bs) (t=((*a-b[bs])<<2)+a[as<<1]-b[-bs], t*t) | |||
| /* | |||
| * Find which field combination has the smallest average squared difference | |||
| * between the fields. | |||
| */ | |||
| static enum mode analyze_plane(unsigned char *old, unsigned char *new, | |||
| int w, int h, int os, int ns, enum mode mode, | |||
| int verbose, int fields) | |||
| { | |||
| double bdiff, pdiff, tdiff, scale; | |||
| int bdif, tdif, pdif; | |||
| int top, t; | |||
| unsigned char *end, *rend; | |||
| if(mode==AUTO) | |||
| mode=fields&MP_IMGFIELD_ORDERED?fields&MP_IMGFIELD_TOP_FIRST? | |||
| TOP_FIRST:BOTTOM_FIRST:PROGRESSIVE; | |||
| else if(mode==AUTO_ANALYZE) | |||
| mode=fields&MP_IMGFIELD_ORDERED?fields&MP_IMGFIELD_TOP_FIRST? | |||
| TOP_FIRST_ANALYZE:BOTTOM_FIRST_ANALYZE:FULL_ANALYZE; | |||
| if(fixed_mode(mode)) | |||
| bdiff=pdiff=tdiff=65536.0; | |||
| else | |||
| { | |||
| bdiff=pdiff=tdiff=0.0; | |||
| for(end=new+(h-2)*ns, new+=ns, old+=os, top=0; | |||
| new<end; new+=ns-w, old+=os-w, top^=1) | |||
| { | |||
| pdif=tdif=bdif=0; | |||
| switch(mode) | |||
| { | |||
| case TOP_FIRST_ANALYZE: | |||
| if(top) | |||
| for(rend=new+w; new<rend; new++, old++) | |||
| pdif+=diff(new, ns, new, ns), | |||
| tdif+=diff(new, ns, old, os); | |||
| else | |||
| for(rend=new+w; new<rend; new++, old++) | |||
| pdif+=diff(new, ns, new, ns), | |||
| tdif+=diff(old, os, new, ns); | |||
| break; | |||
| case BOTTOM_FIRST_ANALYZE: | |||
| if(top) | |||
| for(rend=new+w; new<rend; new++, old++) | |||
| pdif+=diff(new, ns, new, ns), | |||
| bdif+=diff(old, os, new, ns); | |||
| else | |||
| for(rend=new+w; new<rend; new++, old++) | |||
| pdif+=diff(new, ns, new, ns), | |||
| bdif+=diff(new, ns, old, os); | |||
| break; | |||
| case ANALYZE: | |||
| if(top) | |||
| for(rend=new+w; new<rend; new++, old++) | |||
| tdif+=diff(new, ns, old, os), | |||
| bdif+=diff(old, os, new, ns); | |||
| else | |||
| for(rend=new+w; new<rend; new++, old++) | |||
| bdif+=diff(new, ns, old, os), | |||
| tdif+=diff(old, os, new, ns); | |||
| break; | |||
| default: /* FULL_ANALYZE */ | |||
| if(top) | |||
| for(rend=new+w; new<rend; new++, old++) | |||
| pdif+=diff(new, ns, new, ns), | |||
| tdif+=diff(new, ns, old, os), | |||
| bdif+=diff(old, os, new, ns); | |||
| else | |||
| for(rend=new+w; new<rend; new++, old++) | |||
| pdif+=diff(new, ns, new, ns), | |||
| bdif+=diff(new, ns, old, os), | |||
| tdif+=diff(old, os, new, ns); | |||
| } | |||
| pdiff+=(double)pdif; | |||
| tdiff+=(double)tdif; | |||
| bdiff+=(double)bdif; | |||
| } | |||
| scale=1.0/(w*(h-3))/25.0; | |||
| pdiff*=scale; | |||
| tdiff*=scale; | |||
| bdiff*=scale; | |||
| if(mode==TOP_FIRST_ANALYZE) | |||
| bdiff=65536.0; | |||
| else if(mode==BOTTOM_FIRST_ANALYZE) | |||
| tdiff=65536.0; | |||
| else if(mode==ANALYZE) | |||
| pdiff=65536.0; | |||
| if(bdiff<pdiff && bdiff<tdiff) | |||
| mode=BOTTOM_FIRST; | |||
| else if(tdiff<pdiff && tdiff<bdiff) | |||
| mode=TOP_FIRST; | |||
| else | |||
| mode=PROGRESSIVE; | |||
| } | |||
| if( mp_msg_test(MSGT_VFILTER,MSGL_V) ) | |||
| { | |||
| mp_msg(MSGT_VFILTER, MSGL_INFO, "%c", mode==BOTTOM_FIRST?'b':mode==TOP_FIRST?'t':'p'); | |||
| if(tdiff==65536.0) mp_msg(MSGT_VFILTER, MSGL_INFO," N/A "); else mp_msg(MSGT_VFILTER, MSGL_INFO," %8.2f", tdiff); | |||
| if(bdiff==65536.0) mp_msg(MSGT_VFILTER, MSGL_INFO," N/A "); else mp_msg(MSGT_VFILTER, MSGL_INFO," %8.2f", bdiff); | |||
| if(pdiff==65536.0) mp_msg(MSGT_VFILTER, MSGL_INFO," N/A "); else mp_msg(MSGT_VFILTER, MSGL_INFO," %8.2f", pdiff); | |||
| mp_msg(MSGT_VFILTER, MSGL_INFO," \n"); | |||
| } | |||
| return mode; | |||
| } | |||
| static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts) | |||
| { | |||
| mp_image_t *dmpi; | |||
| int w; | |||
| enum mode mode; | |||
| if(!(dmpi=vf_get_image(vf->next, mpi->imgfmt, | |||
| MP_IMGTYPE_TEMP, MP_IMGFLAG_ACCEPT_STRIDE, | |||
| mpi->w, mpi->h))) | |||
| return 0; | |||
| w=dmpi->w; | |||
| if(!(dmpi->flags&MP_IMGFLAG_PLANAR)) | |||
| w*=dmpi->bpp/8; | |||
| mode=vf->priv->mode; | |||
| if(!vf->priv->buf[0]) | |||
| mode=PROGRESSIVE; | |||
| else | |||
| mode=analyze_plane(vf->priv->buf[0], mpi->planes[0], | |||
| w, dmpi->h, w, mpi->stride[0], mode, | |||
| vf->priv->verbose, mpi->fields); | |||
| do_plane(dmpi->planes[0], mpi->planes[0], | |||
| w, dmpi->h, | |||
| dmpi->stride[0], mpi->stride[0], | |||
| &vf->priv->buf[0], mode); | |||
| if(dmpi->flags&MP_IMGFLAG_PLANAR) | |||
| { | |||
| do_plane(dmpi->planes[1], mpi->planes[1], | |||
| dmpi->chroma_width, dmpi->chroma_height, | |||
| dmpi->stride[1], mpi->stride[1], | |||
| &vf->priv->buf[1], mode); | |||
| do_plane(dmpi->planes[2], mpi->planes[2], | |||
| dmpi->chroma_width, dmpi->chroma_height, | |||
| dmpi->stride[2], mpi->stride[2], | |||
| &vf->priv->buf[2], mode); | |||
| } | |||
| return vf_next_put_image(vf, dmpi, MP_NOPTS_VALUE); | |||
| } | |||
| static void uninit(struct vf_instance *vf) | |||
| { | |||
| free(vf->priv->buf[0]); | |||
| free(vf->priv->buf[1]); | |||
| free(vf->priv->buf[2]); | |||
| free(vf->priv); | |||
| } | |||
| static int vf_open(vf_instance_t *vf, char *args) | |||
| { | |||
| vf->put_image = put_image; | |||
| vf->uninit = uninit; | |||
| vf->default_reqs = VFCAP_ACCEPT_STRIDE; | |||
| if(!(vf->priv = calloc(1, sizeof(struct vf_priv_s)))) | |||
| { | |||
| uninit(vf); | |||
| return 0; | |||
| } | |||
| vf->priv->mode=AUTO_ANALYZE; | |||
| vf->priv->verbose=0; | |||
| while(args && *args) | |||
| { | |||
| switch(*args) | |||
| { | |||
| case 't': vf->priv->mode=TOP_FIRST; break; | |||
| case 'a': vf->priv->mode=AUTO; break; | |||
| case 'b': vf->priv->mode=BOTTOM_FIRST; break; | |||
| case 'u': vf->priv->mode=ANALYZE; break; | |||
| case 'T': vf->priv->mode=TOP_FIRST_ANALYZE; break; | |||
| case 'A': vf->priv->mode=AUTO_ANALYZE; break; | |||
| case 'B': vf->priv->mode=BOTTOM_FIRST_ANALYZE; break; | |||
| case 'U': vf->priv->mode=FULL_ANALYZE; break; | |||
| case 'p': vf->priv->mode=PROGRESSIVE; break; | |||
| case 'v': vf->priv->verbose=1; break; | |||
| case ':': break; | |||
| default: | |||
| uninit(vf); | |||
| return 0; /* bad args */ | |||
| } | |||
| if( (args=strchr(args, ':')) ) args++; | |||
| } | |||
| return 1; | |||
| } | |||
| const vf_info_t vf_info_phase = | |||
| { | |||
| "phase shift fields", | |||
| "phase", | |||
| "Ville Saari", | |||
| "", | |||
| vf_open, | |||
| NULL | |||
| }; | |||
| @@ -0,0 +1,491 @@ | |||
| /* | |||
| * Copyright (C) 2005 Michael Niedermayer <michaelni@gmx.at> | |||
| * | |||
| * This file is part of MPlayer. | |||
| * | |||
| * MPlayer 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. | |||
| * | |||
| * MPlayer 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 MPlayer; if not, write to the Free Software Foundation, Inc., | |||
| * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | |||
| */ | |||
| #include <stdio.h> | |||
| #include <stdlib.h> | |||
| #include <string.h> | |||
| #include <inttypes.h> | |||
| #include <math.h> | |||
| #include "config.h" | |||
| #include "mp_msg.h" | |||
| #include "cpudetect.h" | |||
| #if HAVE_MALLOC_H | |||
| #include <malloc.h> | |||
| #endif | |||
| #include "img_format.h" | |||
| #include "mp_image.h" | |||
| #include "vf.h" | |||
| #include "libvo/fastmemcpy.h" | |||
| #define XMIN(a,b) ((a) < (b) ? (a) : (b)) | |||
| #define XMAX(a,b) ((a) > (b) ? (a) : (b)) | |||
| typedef short DCTELEM; | |||
| //===========================================================================// | |||
| static const uint8_t __attribute__((aligned(8))) dither[8][8]={ | |||
| { 0, 48, 12, 60, 3, 51, 15, 63, }, | |||
| { 32, 16, 44, 28, 35, 19, 47, 31, }, | |||
| { 8, 56, 4, 52, 11, 59, 7, 55, }, | |||
| { 40, 24, 36, 20, 43, 27, 39, 23, }, | |||
| { 2, 50, 14, 62, 1, 49, 13, 61, }, | |||
| { 34, 18, 46, 30, 33, 17, 45, 29, }, | |||
| { 10, 58, 6, 54, 9, 57, 5, 53, }, | |||
| { 42, 26, 38, 22, 41, 25, 37, 21, }, | |||
| }; | |||
| struct vf_priv_s { | |||
| int qp; | |||
| int mode; | |||
| int mpeg2; | |||
| int temp_stride; | |||
| uint8_t *src; | |||
| }; | |||
| #if 0 | |||
| static inline void dct7_c(DCTELEM *dst, int s0, int s1, int s2, int s3, int step){ | |||
| int s, d; | |||
| int dst2[64]; | |||
| //#define S0 (1024/0.37796447300922719759) | |||
| #define C0 ((int)(1024*0.37796447300922719759+0.5)) //sqrt(1/7) | |||
| #define C1 ((int)(1024*0.53452248382484879308/6+0.5)) //sqrt(2/7)/6 | |||
| #define C2 ((int)(1024*0.45221175985034745004/2+0.5)) | |||
| #define C3 ((int)(1024*0.36264567479870879474/2+0.5)) | |||
| //0.1962505182412941918 0.0149276808419397944-0.2111781990832339584 | |||
| #define C4 ((int)(1024*0.1962505182412941918+0.5)) | |||
| #define C5 ((int)(1024*0.0149276808419397944+0.5)) | |||
| //#define C6 ((int)(1024*0.2111781990832339584+0.5)) | |||
| #if 0 | |||
| s= s0 + s1 + s2; | |||
| dst[0*step] = ((s + s3)*C0 + 512) >> 10; | |||
| s= (s - 6*s3)*C1 + 512; | |||
| d= (s0-s2)*C4 + (s1-s2)*C5; | |||
| dst[1*step] = (s + 2*d)>>10; | |||
| s -= d; | |||
| d= (s1-s0)*C2 + (s1-s2)*C3; | |||
| dst[2*step] = (s + d)>>10; | |||
| dst[3*step] = (s - d)>>10; | |||
| #elif 1 | |||
| s = s3+s3; | |||
| s3= s-s0; | |||
| s0= s+s0; | |||
| s = s2+s1; | |||
| s2= s2-s1; | |||
| dst[0*step]= s0 + s; | |||
| dst[2*step]= s0 - s; | |||
| dst[1*step]= 2*s3 + s2; | |||
| dst[3*step]= s3 - 2*s2; | |||
| #else | |||
| int i,j,n=7; | |||
| for(i=0; i<7; i+=2){ | |||
| dst2[i*step/2]= 0; | |||
| for(j=0; j<4; j++) | |||
| dst2[i*step/2] += src[j*step] * cos(i*M_PI/n*(j+0.5)) * sqrt((i?2.0:1.0)/n); | |||
| if(fabs(dst2[i*step/2] - dst[i*step/2]) > 20) | |||
| printf("%d %d %d (%d %d %d %d) -> (%d %d %d %d)\n", i,dst2[i*step/2], dst[i*step/2],src[0*step], src[1*step], src[2*step], src[3*step], dst[0*step], dst[1*step],dst[2*step],dst[3*step]); | |||
| } | |||
| #endif | |||
| } | |||
| #endif | |||
| static inline void dctA_c(DCTELEM *dst, uint8_t *src, int stride){ | |||
| int i; | |||
| for(i=0; i<4; i++){ | |||
| int s0= src[0*stride] + src[6*stride]; | |||
| int s1= src[1*stride] + src[5*stride]; | |||
| int s2= src[2*stride] + src[4*stride]; | |||
| int s3= src[3*stride]; | |||
| int s= s3+s3; | |||
| s3= s-s0; | |||
| s0= s+s0; | |||
| s = s2+s1; | |||
| s2= s2-s1; | |||
| dst[0]= s0 + s; | |||
| dst[2]= s0 - s; | |||
| dst[1]= 2*s3 + s2; | |||
| dst[3]= s3 - 2*s2; | |||
| src++; | |||
| dst+=4; | |||
| } | |||
| } | |||
| static void dctB_c(DCTELEM *dst, DCTELEM *src){ | |||
| int i; | |||
| for(i=0; i<4; i++){ | |||
| int s0= src[0*4] + src[6*4]; | |||
| int s1= src[1*4] + src[5*4]; | |||
| int s2= src[2*4] + src[4*4]; | |||
| int s3= src[3*4]; | |||
| int s= s3+s3; | |||
| s3= s-s0; | |||
| s0= s+s0; | |||
| s = s2+s1; | |||
| s2= s2-s1; | |||
| dst[0*4]= s0 + s; | |||
| dst[2*4]= s0 - s; | |||
| dst[1*4]= 2*s3 + s2; | |||
| dst[3*4]= s3 - 2*s2; | |||
| src++; | |||
| dst++; | |||
| } | |||
| } | |||
| #if HAVE_MMX | |||
| static void dctB_mmx(DCTELEM *dst, DCTELEM *src){ | |||
| __asm__ volatile ( | |||
| "movq (%0), %%mm0 \n\t" | |||
| "movq 1*4*2(%0), %%mm1 \n\t" | |||
| "paddw 6*4*2(%0), %%mm0 \n\t" | |||
| "paddw 5*4*2(%0), %%mm1 \n\t" | |||
| "movq 2*4*2(%0), %%mm2 \n\t" | |||
| "movq 3*4*2(%0), %%mm3 \n\t" | |||
| "paddw 4*4*2(%0), %%mm2 \n\t" | |||
| "paddw %%mm3, %%mm3 \n\t" //s | |||
| "movq %%mm3, %%mm4 \n\t" //s | |||
| "psubw %%mm0, %%mm3 \n\t" //s-s0 | |||
| "paddw %%mm0, %%mm4 \n\t" //s+s0 | |||
| "movq %%mm2, %%mm0 \n\t" //s2 | |||
| "psubw %%mm1, %%mm2 \n\t" //s2-s1 | |||
| "paddw %%mm1, %%mm0 \n\t" //s2+s1 | |||
| "movq %%mm4, %%mm1 \n\t" //s0' | |||
| "psubw %%mm0, %%mm4 \n\t" //s0'-s' | |||
| "paddw %%mm0, %%mm1 \n\t" //s0'+s' | |||
| "movq %%mm3, %%mm0 \n\t" //s3' | |||
| "psubw %%mm2, %%mm3 \n\t" | |||
| "psubw %%mm2, %%mm3 \n\t" | |||
| "paddw %%mm0, %%mm2 \n\t" | |||
| "paddw %%mm0, %%mm2 \n\t" | |||
| "movq %%mm1, (%1) \n\t" | |||
| "movq %%mm4, 2*4*2(%1) \n\t" | |||
| "movq %%mm2, 1*4*2(%1) \n\t" | |||
| "movq %%mm3, 3*4*2(%1) \n\t" | |||
| :: "r" (src), "r"(dst) | |||
| ); | |||
| } | |||
| #endif | |||
| static void (*dctB)(DCTELEM *dst, DCTELEM *src)= dctB_c; | |||
| #define N0 4 | |||
| #define N1 5 | |||
| #define N2 10 | |||
| #define SN0 2 | |||
| #define SN1 2.2360679775 | |||
| #define SN2 3.16227766017 | |||
| #define N (1<<16) | |||
| static const int factor[16]={ | |||
| N/(N0*N0), N/(N0*N1), N/(N0*N0),N/(N0*N2), | |||
| N/(N1*N0), N/(N1*N1), N/(N1*N0),N/(N1*N2), | |||
| N/(N0*N0), N/(N0*N1), N/(N0*N0),N/(N0*N2), | |||
| N/(N2*N0), N/(N2*N1), N/(N2*N0),N/(N2*N2), | |||
| }; | |||
| static const int thres[16]={ | |||
| N/(SN0*SN0), N/(SN0*SN2), N/(SN0*SN0),N/(SN0*SN2), | |||
| N/(SN2*SN0), N/(SN2*SN2), N/(SN2*SN0),N/(SN2*SN2), | |||
| N/(SN0*SN0), N/(SN0*SN2), N/(SN0*SN0),N/(SN0*SN2), | |||
| N/(SN2*SN0), N/(SN2*SN2), N/(SN2*SN0),N/(SN2*SN2), | |||
| }; | |||
| static int thres2[99][16]; | |||
| static void init_thres2(void){ | |||
| int qp, i; | |||
| int bias= 0; //FIXME | |||
| for(qp=0; qp<99; qp++){ | |||
| for(i=0; i<16; i++){ | |||
| thres2[qp][i]= ((i&1)?SN2:SN0) * ((i&4)?SN2:SN0) * XMAX(1,qp) * (1<<2) - 1 - bias; | |||
| } | |||
| } | |||
| } | |||
| static int hardthresh_c(DCTELEM *src, int qp){ | |||
| int i; | |||
| int a; | |||
| a= src[0] * factor[0]; | |||
| for(i=1; i<16; i++){ | |||
| unsigned int threshold1= thres2[qp][i]; | |||
| unsigned int threshold2= (threshold1<<1); | |||
| int level= src[i]; | |||
| if(((unsigned)(level+threshold1))>threshold2){ | |||
| a += level * factor[i]; | |||
| } | |||
| } | |||
| return (a + (1<<11))>>12; | |||
| } | |||
| static int mediumthresh_c(DCTELEM *src, int qp){ | |||
| int i; | |||
| int a; | |||
| a= src[0] * factor[0]; | |||
| for(i=1; i<16; i++){ | |||
| unsigned int threshold1= thres2[qp][i]; | |||
| unsigned int threshold2= (threshold1<<1); | |||
| int level= src[i]; | |||
| if(((unsigned)(level+threshold1))>threshold2){ | |||
| if(((unsigned)(level+2*threshold1))>2*threshold2){ | |||
| a += level * factor[i]; | |||
| }else{ | |||
| if(level>0) a+= 2*(level - (int)threshold1)*factor[i]; | |||
| else a+= 2*(level + (int)threshold1)*factor[i]; | |||
| } | |||
| } | |||
| } | |||
| return (a + (1<<11))>>12; | |||
| } | |||
| static int softthresh_c(DCTELEM *src, int qp){ | |||
| int i; | |||
| int a; | |||
| a= src[0] * factor[0]; | |||
| for(i=1; i<16; i++){ | |||
| unsigned int threshold1= thres2[qp][i]; | |||
| unsigned int threshold2= (threshold1<<1); | |||
| int level= src[i]; | |||
| if(((unsigned)(level+threshold1))>threshold2){ | |||
| if(level>0) a+= (level - (int)threshold1)*factor[i]; | |||
| else a+= (level + (int)threshold1)*factor[i]; | |||
| } | |||
| } | |||
| return (a + (1<<11))>>12; | |||
| } | |||
| static int (*requantize)(DCTELEM *src, int qp)= hardthresh_c; | |||
| static void filter(struct vf_priv_s *p, uint8_t *dst, uint8_t *src, int dst_stride, int src_stride, int width, int height, uint8_t *qp_store, int qp_stride, int is_luma){ | |||
| int x, y; | |||
| const int stride= is_luma ? p->temp_stride : ((width+16+15)&(~15)); | |||
| uint8_t *p_src= p->src + 8*stride; | |||
| DCTELEM *block= p->src; | |||
| DCTELEM *temp= p->src + 32; | |||
| if (!src || !dst) return; // HACK avoid crash for Y8 colourspace | |||
| for(y=0; y<height; y++){ | |||
| int index= 8 + 8*stride + y*stride; | |||
| fast_memcpy(p_src + index, src + y*src_stride, width); | |||
| for(x=0; x<8; x++){ | |||
| p_src[index - x - 1]= p_src[index + x ]; | |||
| p_src[index + width + x ]= p_src[index + width - x - 1]; | |||
| } | |||
| } | |||
| for(y=0; y<8; y++){ | |||
| fast_memcpy(p_src + ( 7-y)*stride, p_src + ( y+8)*stride, stride); | |||
| fast_memcpy(p_src + (height+8+y)*stride, p_src + (height-y+7)*stride, stride); | |||
| } | |||
| //FIXME (try edge emu) | |||
| for(y=0; y<height; y++){ | |||
| for(x=-8; x<0; x+=4){ | |||
| const int index= x + y*stride + (8-3)*(1+stride) + 8; //FIXME silly offset | |||
| uint8_t *src = p_src + index; | |||
| DCTELEM *tp= temp+4*x; | |||
| dctA_c(tp+4*8, src, stride); | |||
| } | |||
| for(x=0; x<width; ){ | |||
| const int qps= 3 + is_luma; | |||
| int qp; | |||
| int end= XMIN(x+8, width); | |||
| if(p->qp) | |||
| qp= p->qp; | |||
| else{ | |||
| qp= qp_store[ (XMIN(x, width-1)>>qps) + (XMIN(y, height-1)>>qps) * qp_stride]; | |||
| qp=norm_qscale(qp, p->mpeg2); | |||
| } | |||
| for(; x<end; x++){ | |||
| const int index= x + y*stride + (8-3)*(1+stride) + 8; //FIXME silly offset | |||
| uint8_t *src = p_src + index; | |||
| DCTELEM *tp= temp+4*x; | |||
| int v; | |||
| if((x&3)==0) | |||
| dctA_c(tp+4*8, src, stride); | |||
| dctB(block, tp); | |||
| v= requantize(block, qp); | |||
| v= (v + dither[y&7][x&7])>>6; | |||
| if((unsigned)v > 255) | |||
| v= (-v)>>31; | |||
| dst[x + y*dst_stride]= v; | |||
| } | |||
| } | |||
| } | |||
| } | |||
| static int config(struct vf_instance *vf, | |||
| int width, int height, int d_width, int d_height, | |||
| unsigned int flags, unsigned int outfmt){ | |||
| int h= (height+16+15)&(~15); | |||
| vf->priv->temp_stride= (width+16+15)&(~15); | |||
| vf->priv->src = memalign(8, vf->priv->temp_stride*(h+8)*sizeof(uint8_t)); | |||
| return vf_next_config(vf,width,height,d_width,d_height,flags,outfmt); | |||
| } | |||
| static void get_image(struct vf_instance *vf, mp_image_t *mpi){ | |||
| if(mpi->flags&MP_IMGFLAG_PRESERVE) return; // don't change | |||
| // ok, we can do pp in-place (or pp disabled): | |||
| vf->dmpi=vf_get_image(vf->next,mpi->imgfmt, | |||
| mpi->type, mpi->flags | MP_IMGFLAG_READABLE, mpi->width, mpi->height); | |||
| mpi->planes[0]=vf->dmpi->planes[0]; | |||
| mpi->stride[0]=vf->dmpi->stride[0]; | |||
| mpi->width=vf->dmpi->width; | |||
| if(mpi->flags&MP_IMGFLAG_PLANAR){ | |||
| mpi->planes[1]=vf->dmpi->planes[1]; | |||
| mpi->planes[2]=vf->dmpi->planes[2]; | |||
| mpi->stride[1]=vf->dmpi->stride[1]; | |||
| mpi->stride[2]=vf->dmpi->stride[2]; | |||
| } | |||
| mpi->flags|=MP_IMGFLAG_DIRECT; | |||
| } | |||
| static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts){ | |||
| mp_image_t *dmpi; | |||
| if(mpi->flags&MP_IMGFLAG_DIRECT){ | |||
| dmpi=vf->dmpi; | |||
| }else{ | |||
| // no DR, so get a new image! hope we'll get DR buffer: | |||
| dmpi=vf_get_image(vf->next,mpi->imgfmt, | |||
| MP_IMGTYPE_TEMP, | |||
| MP_IMGFLAG_ACCEPT_STRIDE|MP_IMGFLAG_PREFER_ALIGNED_STRIDE, | |||
| mpi->width,mpi->height); | |||
| vf_clone_mpi_attributes(dmpi, mpi); | |||
| } | |||
| vf->priv->mpeg2= mpi->qscale_type; | |||
| if(mpi->qscale || vf->priv->qp){ | |||
| filter(vf->priv, dmpi->planes[0], mpi->planes[0], dmpi->stride[0], mpi->stride[0], mpi->w, mpi->h, mpi->qscale, mpi->qstride, 1); | |||
| filter(vf->priv, dmpi->planes[1], mpi->planes[1], dmpi->stride[1], mpi->stride[1], mpi->w>>mpi->chroma_x_shift, mpi->h>>mpi->chroma_y_shift, mpi->qscale, mpi->qstride, 0); | |||
| filter(vf->priv, dmpi->planes[2], mpi->planes[2], dmpi->stride[2], mpi->stride[2], mpi->w>>mpi->chroma_x_shift, mpi->h>>mpi->chroma_y_shift, mpi->qscale, mpi->qstride, 0); | |||
| }else{ | |||
| memcpy_pic(dmpi->planes[0], mpi->planes[0], mpi->w, mpi->h, dmpi->stride[0], mpi->stride[0]); | |||
| memcpy_pic(dmpi->planes[1], mpi->planes[1], mpi->w>>mpi->chroma_x_shift, mpi->h>>mpi->chroma_y_shift, dmpi->stride[1], mpi->stride[1]); | |||
| memcpy_pic(dmpi->planes[2], mpi->planes[2], mpi->w>>mpi->chroma_x_shift, mpi->h>>mpi->chroma_y_shift, dmpi->stride[2], mpi->stride[2]); | |||
| } | |||
| #if HAVE_MMX | |||
| if(gCpuCaps.hasMMX) __asm__ volatile ("emms\n\t"); | |||
| #endif | |||
| #if HAVE_MMX2 | |||
| if(gCpuCaps.hasMMX2) __asm__ volatile ("sfence\n\t"); | |||
| #endif | |||
| return vf_next_put_image(vf,dmpi, pts); | |||
| } | |||
| static void uninit(struct vf_instance *vf){ | |||
| if(!vf->priv) return; | |||
| free(vf->priv->src); | |||
| vf->priv->src= NULL; | |||
| free(vf->priv); | |||
| vf->priv=NULL; | |||
| } | |||
| //===========================================================================// | |||
| static int query_format(struct vf_instance *vf, unsigned int fmt){ | |||
| switch(fmt){ | |||
| case IMGFMT_YVU9: | |||
| case IMGFMT_IF09: | |||
| case IMGFMT_YV12: | |||
| case IMGFMT_I420: | |||
| case IMGFMT_IYUV: | |||
| case IMGFMT_CLPL: | |||
| case IMGFMT_Y800: | |||
| case IMGFMT_Y8: | |||
| case IMGFMT_444P: | |||
| case IMGFMT_422P: | |||
| case IMGFMT_411P: | |||
| return vf_next_query_format(vf,fmt); | |||
| } | |||
| return 0; | |||
| } | |||
| static int control(struct vf_instance *vf, int request, void* data){ | |||
| return vf_next_control(vf,request,data); | |||
| } | |||
| static int vf_open(vf_instance_t *vf, char *args){ | |||
| vf->config=config; | |||
| vf->put_image=put_image; | |||
| vf->get_image=get_image; | |||
| vf->query_format=query_format; | |||
| vf->uninit=uninit; | |||
| vf->control= control; | |||
| vf->priv=malloc(sizeof(struct vf_priv_s)); | |||
| memset(vf->priv, 0, sizeof(struct vf_priv_s)); | |||
| if (args) sscanf(args, "%d:%d", &vf->priv->qp, &vf->priv->mode); | |||
| if(vf->priv->qp < 0) | |||
| vf->priv->qp = 0; | |||
| init_thres2(); | |||
| switch(vf->priv->mode){ | |||
| case 0: requantize= hardthresh_c; break; | |||
| case 1: requantize= softthresh_c; break; | |||
| default: | |||
| case 2: requantize= mediumthresh_c; break; | |||
| } | |||
| #if HAVE_MMX | |||
| if(gCpuCaps.hasMMX){ | |||
| dctB= dctB_mmx; | |||
| } | |||
| #endif | |||
| #if 0 | |||
| if(gCpuCaps.hasMMX){ | |||
| switch(vf->priv->mode){ | |||
| case 0: requantize= hardthresh_mmx; break; | |||
| case 1: requantize= softthresh_mmx; break; | |||
| } | |||
| } | |||
| #endif | |||
| return 1; | |||
| } | |||
| const vf_info_t vf_info_pp7 = { | |||
| "postprocess 7", | |||
| "pp7", | |||
| "Michael Niedermayer", | |||
| "", | |||
| vf_open, | |||
| NULL | |||
| }; | |||
| @@ -0,0 +1,314 @@ | |||
| /* | |||
| * This file is part of MPlayer. | |||
| * | |||
| * MPlayer 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. | |||
| * | |||
| * MPlayer 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 MPlayer; if not, write to the Free Software Foundation, Inc., | |||
| * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | |||
| */ | |||
| #include <stdio.h> | |||
| #include <stdlib.h> | |||
| #include <string.h> | |||
| #include "config.h" | |||
| #include "mp_msg.h" | |||
| #include "cpudetect.h" | |||
| #include "img_format.h" | |||
| #include "mp_image.h" | |||
| #include "vf.h" | |||
| #include "libvo/fastmemcpy.h" | |||
| #include "pullup.h" | |||
| #undef MAX | |||
| #define MAX(a,b) ((a)>(b)?(a):(b)) | |||
| struct vf_priv_s { | |||
| struct pullup_context *ctx; | |||
| int init; | |||
| int fakecount; | |||
| char *qbuf; | |||
| }; | |||
| static void init_pullup(struct vf_instance *vf, mp_image_t *mpi) | |||
| { | |||
| struct pullup_context *c = vf->priv->ctx; | |||
| if (mpi->flags & MP_IMGFLAG_PLANAR) { | |||
| c->format = PULLUP_FMT_Y; | |||
| c->nplanes = 4; | |||
| pullup_preinit_context(c); | |||
| c->bpp[0] = c->bpp[1] = c->bpp[2] = 8; | |||
| c->w[0] = mpi->w; | |||
| c->h[0] = mpi->h; | |||
| c->w[1] = c->w[2] = mpi->chroma_width; | |||
| c->h[1] = c->h[2] = mpi->chroma_height; | |||
| c->w[3] = ((mpi->w+15)/16) * ((mpi->h+15)/16); | |||
| c->h[3] = 2; | |||
| c->stride[0] = mpi->width; | |||
| c->stride[1] = c->stride[2] = mpi->chroma_width; | |||
| c->stride[3] = c->w[3]; | |||
| c->background[1] = c->background[2] = 128; | |||
| } | |||
| if (gCpuCaps.hasMMX) c->cpu |= PULLUP_CPU_MMX; | |||
| if (gCpuCaps.hasMMX2) c->cpu |= PULLUP_CPU_MMX2; | |||
| if (gCpuCaps.has3DNow) c->cpu |= PULLUP_CPU_3DNOW; | |||
| if (gCpuCaps.has3DNowExt) c->cpu |= PULLUP_CPU_3DNOWEXT; | |||
| if (gCpuCaps.hasSSE) c->cpu |= PULLUP_CPU_SSE; | |||
| if (gCpuCaps.hasSSE2) c->cpu |= PULLUP_CPU_SSE2; | |||
| pullup_init_context(c); | |||
| vf->priv->init = 1; | |||
| vf->priv->qbuf = malloc(c->w[3]); | |||
| } | |||
| #if 0 | |||
| static void get_image(struct vf_instance *vf, mp_image_t *mpi) | |||
| { | |||
| struct pullup_context *c = vf->priv->ctx; | |||
| struct pullup_buffer *b; | |||
| if (mpi->type == MP_IMGTYPE_STATIC) return; | |||
| if (!vf->priv->init) init_pullup(vf, mpi); | |||
| b = pullup_get_buffer(c, 2); | |||
| if (!b) return; /* shouldn't happen... */ | |||
| mpi->priv = b; | |||
| mpi->planes[0] = b->planes[0]; | |||
| mpi->planes[1] = b->planes[1]; | |||
| mpi->planes[2] = b->planes[2]; | |||
| mpi->stride[0] = c->stride[0]; | |||
| mpi->stride[1] = c->stride[1]; | |||
| mpi->stride[2] = c->stride[2]; | |||
| mpi->flags |= MP_IMGFLAG_DIRECT; | |||
| mpi->flags &= ~MP_IMGFLAG_DRAW_CALLBACK; | |||
| } | |||
| #endif | |||
| static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts) | |||
| { | |||
| struct pullup_context *c = vf->priv->ctx; | |||
| struct pullup_buffer *b; | |||
| struct pullup_frame *f; | |||
| mp_image_t *dmpi; | |||
| int ret; | |||
| int p; | |||
| int i; | |||
| if (!vf->priv->init) init_pullup(vf, mpi); | |||
| if (mpi->flags & MP_IMGFLAG_DIRECT) { | |||
| b = mpi->priv; | |||
| mpi->priv = 0; | |||
| } else { | |||
| b = pullup_get_buffer(c, 2); | |||
| if (!b) { | |||
| mp_msg(MSGT_VFILTER,MSGL_ERR,"Could not get buffer from pullup!\n"); | |||
| f = pullup_get_frame(c); | |||
| pullup_release_frame(f); | |||
| return 0; | |||
| } | |||
| memcpy_pic(b->planes[0], mpi->planes[0], mpi->w, mpi->h, | |||
| c->stride[0], mpi->stride[0]); | |||
| if (mpi->flags & MP_IMGFLAG_PLANAR) { | |||
| memcpy_pic(b->planes[1], mpi->planes[1], | |||
| mpi->chroma_width, mpi->chroma_height, | |||
| c->stride[1], mpi->stride[1]); | |||
| memcpy_pic(b->planes[2], mpi->planes[2], | |||
| mpi->chroma_width, mpi->chroma_height, | |||
| c->stride[2], mpi->stride[2]); | |||
| } | |||
| } | |||
| if (mpi->qscale) { | |||
| fast_memcpy(b->planes[3], mpi->qscale, c->w[3]); | |||
| fast_memcpy(b->planes[3]+c->w[3], mpi->qscale, c->w[3]); | |||
| } | |||
| p = mpi->fields & MP_IMGFIELD_TOP_FIRST ? 0 : | |||
| (mpi->fields & MP_IMGFIELD_ORDERED ? 1 : 0); | |||
| pullup_submit_field(c, b, p); | |||
| pullup_submit_field(c, b, p^1); | |||
| if (mpi->fields & MP_IMGFIELD_REPEAT_FIRST) | |||
| pullup_submit_field(c, b, p); | |||
| pullup_release_buffer(b, 2); | |||
| f = pullup_get_frame(c); | |||
| /* Fake yes for first few frames (buffer depth) to keep from | |||
| * breaking A/V sync with G1's bad architecture... */ | |||
| if (!f) return vf->priv->fakecount ? (--vf->priv->fakecount,1) : 0; | |||
| if (f->length < 2) { | |||
| pullup_release_frame(f); | |||
| f = pullup_get_frame(c); | |||
| if (!f) return 0; | |||
| if (f->length < 2) { | |||
| pullup_release_frame(f); | |||
| if (!(mpi->fields & MP_IMGFIELD_REPEAT_FIRST)) | |||
| return 0; | |||
| f = pullup_get_frame(c); | |||
| if (!f) return 0; | |||
| if (f->length < 2) { | |||
| pullup_release_frame(f); | |||
| return 0; | |||
| } | |||
| } | |||
| } | |||
| #if 0 | |||
| /* Average qscale tables from both frames. */ | |||
| if (mpi->qscale) { | |||
| for (i=0; i<c->w[3]; i++) { | |||
| vf->priv->qbuf[i] = (f->ofields[0]->planes[3][i] | |||
| + f->ofields[1]->planes[3][i+c->w[3]])>>1; | |||
| } | |||
| } | |||
| #else | |||
| /* Take worst of qscale tables from both frames. */ | |||
| if (mpi->qscale) { | |||
| for (i=0; i<c->w[3]; i++) { | |||
| vf->priv->qbuf[i] = MAX(f->ofields[0]->planes[3][i], f->ofields[1]->planes[3][i+c->w[3]]); | |||
| } | |||
| } | |||
| #endif | |||
| /* If the frame isn't already exportable... */ | |||
| while (!f->buffer) { | |||
| dmpi = vf_get_image(vf->next, mpi->imgfmt, | |||
| MP_IMGTYPE_TEMP, MP_IMGFLAG_ACCEPT_STRIDE, | |||
| mpi->width, mpi->height); | |||
| /* FIXME: Is it ok to discard dmpi if it's not direct? */ | |||
| if (!(dmpi->flags & MP_IMGFLAG_DIRECT)) { | |||
| pullup_pack_frame(c, f); | |||
| break; | |||
| } | |||
| /* Direct render fields into output buffer */ | |||
| my_memcpy_pic(dmpi->planes[0], f->ofields[0]->planes[0], | |||
| mpi->w, mpi->h/2, dmpi->stride[0]*2, c->stride[0]*2); | |||
| my_memcpy_pic(dmpi->planes[0] + dmpi->stride[0], | |||
| f->ofields[1]->planes[0] + c->stride[0], | |||
| mpi->w, mpi->h/2, dmpi->stride[0]*2, c->stride[0]*2); | |||
| if (mpi->flags & MP_IMGFLAG_PLANAR) { | |||
| my_memcpy_pic(dmpi->planes[1], f->ofields[0]->planes[1], | |||
| mpi->chroma_width, mpi->chroma_height/2, | |||
| dmpi->stride[1]*2, c->stride[1]*2); | |||
| my_memcpy_pic(dmpi->planes[1] + dmpi->stride[1], | |||
| f->ofields[1]->planes[1] + c->stride[1], | |||
| mpi->chroma_width, mpi->chroma_height/2, | |||
| dmpi->stride[1]*2, c->stride[1]*2); | |||
| my_memcpy_pic(dmpi->planes[2], f->ofields[0]->planes[2], | |||
| mpi->chroma_width, mpi->chroma_height/2, | |||
| dmpi->stride[2]*2, c->stride[2]*2); | |||
| my_memcpy_pic(dmpi->planes[2] + dmpi->stride[2], | |||
| f->ofields[1]->planes[2] + c->stride[2], | |||
| mpi->chroma_width, mpi->chroma_height/2, | |||
| dmpi->stride[2]*2, c->stride[2]*2); | |||
| } | |||
| pullup_release_frame(f); | |||
| if (mpi->qscale) { | |||
| dmpi->qscale = vf->priv->qbuf; | |||
| dmpi->qstride = mpi->qstride; | |||
| dmpi->qscale_type = mpi->qscale_type; | |||
| } | |||
| return vf_next_put_image(vf, dmpi, MP_NOPTS_VALUE); | |||
| } | |||
| dmpi = vf_get_image(vf->next, mpi->imgfmt, | |||
| MP_IMGTYPE_EXPORT, MP_IMGFLAG_ACCEPT_STRIDE, | |||
| mpi->width, mpi->height); | |||
| dmpi->planes[0] = f->buffer->planes[0]; | |||
| dmpi->planes[1] = f->buffer->planes[1]; | |||
| dmpi->planes[2] = f->buffer->planes[2]; | |||
| dmpi->stride[0] = c->stride[0]; | |||
| dmpi->stride[1] = c->stride[1]; | |||
| dmpi->stride[2] = c->stride[2]; | |||
| if (mpi->qscale) { | |||
| dmpi->qscale = vf->priv->qbuf; | |||
| dmpi->qstride = mpi->qstride; | |||
| dmpi->qscale_type = mpi->qscale_type; | |||
| } | |||
| ret = vf_next_put_image(vf, dmpi, MP_NOPTS_VALUE); | |||
| pullup_release_frame(f); | |||
| return ret; | |||
| } | |||
| static int query_format(struct vf_instance *vf, unsigned int fmt) | |||
| { | |||
| /* FIXME - support more formats */ | |||
| switch (fmt) { | |||
| case IMGFMT_YV12: | |||
| case IMGFMT_IYUV: | |||
| case IMGFMT_I420: | |||
| return vf_next_query_format(vf, fmt); | |||
| } | |||
| return 0; | |||
| } | |||
| static int config(struct vf_instance *vf, | |||
| int width, int height, int d_width, int d_height, | |||
| unsigned int flags, unsigned int outfmt) | |||
| { | |||
| if (height&3) return 0; | |||
| return vf_next_config(vf, width, height, d_width, d_height, flags, outfmt); | |||
| } | |||
| static void uninit(struct vf_instance *vf) | |||
| { | |||
| pullup_free_context(vf->priv->ctx); | |||
| free(vf->priv); | |||
| } | |||
| static int vf_open(vf_instance_t *vf, char *args) | |||
| { | |||
| struct vf_priv_s *p; | |||
| struct pullup_context *c; | |||
| //vf->get_image = get_image; | |||
| vf->put_image = put_image; | |||
| vf->config = config; | |||
| vf->query_format = query_format; | |||
| vf->uninit = uninit; | |||
| vf->default_reqs = VFCAP_ACCEPT_STRIDE; | |||
| vf->priv = p = calloc(1, sizeof(struct vf_priv_s)); | |||
| p->ctx = c = pullup_alloc_context(); | |||
| p->fakecount = 1; | |||
| c->verbose = verbose>0; | |||
| c->junk_left = c->junk_right = 1; | |||
| c->junk_top = c->junk_bottom = 4; | |||
| c->strict_breaks = 0; | |||
| c->metric_plane = 0; | |||
| if (args) { | |||
| sscanf(args, "%d:%d:%d:%d:%d:%d", &c->junk_left, &c->junk_right, &c->junk_top, &c->junk_bottom, &c->strict_breaks, &c->metric_plane); | |||
| } | |||
| return 1; | |||
| } | |||
| const vf_info_t vf_info_pullup = { | |||
| "pullup (from field sequence to frames)", | |||
| "pullup", | |||
| "Rich Felker", | |||
| "", | |||
| vf_open, | |||
| NULL | |||
| }; | |||
| @@ -0,0 +1,177 @@ | |||
| /* | |||
| * Copyright (C) 2004 Michael Niedermayer <michaelni@gmx.at> | |||
| * | |||
| * This file is part of MPlayer. | |||
| * | |||
| * MPlayer 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. | |||
| * | |||
| * MPlayer 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 MPlayer; if not, write to the Free Software Foundation, Inc., | |||
| * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | |||
| */ | |||
| #include <stdio.h> | |||
| #include <stdlib.h> | |||
| #include <string.h> | |||
| #include <math.h> | |||
| #include <inttypes.h> | |||
| #include "mp_msg.h" | |||
| #include "cpudetect.h" | |||
| #include "img_format.h" | |||
| #include "mp_image.h" | |||
| #include "vf.h" | |||
| #include "libvo/fastmemcpy.h" | |||
| #include "libavcodec/avcodec.h" | |||
| #include "libavutil/eval.h" | |||
| struct vf_priv_s { | |||
| char eq[200]; | |||
| int8_t *qp; | |||
| int8_t lut[257]; | |||
| int qp_stride; | |||
| }; | |||
| static int config(struct vf_instance *vf, | |||
| int width, int height, int d_width, int d_height, | |||
| unsigned int flags, unsigned int outfmt){ | |||
| int h= (height+15)>>4; | |||
| int i; | |||
| vf->priv->qp_stride= (width+15)>>4; | |||
| vf->priv->qp= av_malloc(vf->priv->qp_stride*h*sizeof(int8_t)); | |||
| for(i=-129; i<128; i++){ | |||
| double const_values[]={ | |||
| M_PI, | |||
| M_E, | |||
| i != -129, | |||
| i, | |||
| 0 | |||
| }; | |||
| static const char *const_names[]={ | |||
| "PI", | |||
| "E", | |||
| "known", | |||
| "qp", | |||
| NULL | |||
| }; | |||
| double temp_val; | |||
| int res; | |||
| res= av_parse_and_eval_expr(&temp_val, vf->priv->eq, const_names, const_values, NULL, NULL, NULL, NULL, NULL, 0, NULL); | |||
| if (res < 0){ | |||
| mp_msg(MSGT_VFILTER, MSGL_ERR, "qp: Error evaluating \"%s\" \n", vf->priv->eq); | |||
| return 0; | |||
| } | |||
| vf->priv->lut[i+129]= lrintf(temp_val); | |||
| } | |||
| return vf_next_config(vf,width,height,d_width,d_height,flags,outfmt); | |||
| } | |||
| static void get_image(struct vf_instance *vf, mp_image_t *mpi){ | |||
| if(mpi->flags&MP_IMGFLAG_PRESERVE) return; // don't change | |||
| // ok, we can do pp in-place (or pp disabled): | |||
| vf->dmpi=vf_get_image(vf->next,mpi->imgfmt, | |||
| mpi->type, mpi->flags, mpi->w, mpi->h); | |||
| mpi->planes[0]=vf->dmpi->planes[0]; | |||
| mpi->stride[0]=vf->dmpi->stride[0]; | |||
| mpi->width=vf->dmpi->width; | |||
| if(mpi->flags&MP_IMGFLAG_PLANAR){ | |||
| mpi->planes[1]=vf->dmpi->planes[1]; | |||
| mpi->planes[2]=vf->dmpi->planes[2]; | |||
| mpi->stride[1]=vf->dmpi->stride[1]; | |||
| mpi->stride[2]=vf->dmpi->stride[2]; | |||
| } | |||
| mpi->flags|=MP_IMGFLAG_DIRECT; | |||
| } | |||
| static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts){ | |||
| mp_image_t *dmpi; | |||
| int x,y; | |||
| if(!(mpi->flags&MP_IMGFLAG_DIRECT)){ | |||
| // no DR, so get a new image! hope we'll get DR buffer: | |||
| vf->dmpi=vf_get_image(vf->next,mpi->imgfmt, | |||
| MP_IMGTYPE_TEMP, MP_IMGFLAG_ACCEPT_STRIDE|MP_IMGFLAG_PREFER_ALIGNED_STRIDE, | |||
| mpi->w,mpi->h); | |||
| } | |||
| dmpi= vf->dmpi; | |||
| if(!(mpi->flags&MP_IMGFLAG_DIRECT)){ | |||
| memcpy_pic(dmpi->planes[0], mpi->planes[0], mpi->w, mpi->h, dmpi->stride[0], mpi->stride[0]); | |||
| if(mpi->flags&MP_IMGFLAG_PLANAR){ | |||
| memcpy_pic(dmpi->planes[1], mpi->planes[1], mpi->w>>mpi->chroma_x_shift, mpi->h>>mpi->chroma_y_shift, dmpi->stride[1], mpi->stride[1]); | |||
| memcpy_pic(dmpi->planes[2], mpi->planes[2], mpi->w>>mpi->chroma_x_shift, mpi->h>>mpi->chroma_y_shift, dmpi->stride[2], mpi->stride[2]); | |||
| } | |||
| } | |||
| vf_clone_mpi_attributes(dmpi, mpi); | |||
| dmpi->qscale = vf->priv->qp; | |||
| dmpi->qstride= vf->priv->qp_stride; | |||
| if(mpi->qscale){ | |||
| for(y=0; y<((dmpi->h+15)>>4); y++){ | |||
| for(x=0; x<vf->priv->qp_stride; x++){ | |||
| dmpi->qscale[x + dmpi->qstride*y]= | |||
| vf->priv->lut[ 129 + ((int8_t)mpi->qscale[x + mpi->qstride*y]) ]; | |||
| } | |||
| } | |||
| }else{ | |||
| int qp= vf->priv->lut[0]; | |||
| for(y=0; y<((dmpi->h+15)>>4); y++){ | |||
| for(x=0; x<vf->priv->qp_stride; x++){ | |||
| dmpi->qscale[x + dmpi->qstride*y]= qp; | |||
| } | |||
| } | |||
| } | |||
| return vf_next_put_image(vf,dmpi, pts); | |||
| } | |||
| static void uninit(struct vf_instance *vf){ | |||
| if(!vf->priv) return; | |||
| av_free(vf->priv->qp); | |||
| vf->priv->qp= NULL; | |||
| av_free(vf->priv); | |||
| vf->priv=NULL; | |||
| } | |||
| //===========================================================================// | |||
| static int vf_open(vf_instance_t *vf, char *args){ | |||
| vf->config=config; | |||
| vf->put_image=put_image; | |||
| vf->get_image=get_image; | |||
| vf->uninit=uninit; | |||
| vf->priv=av_malloc(sizeof(struct vf_priv_s)); | |||
| memset(vf->priv, 0, sizeof(struct vf_priv_s)); | |||
| // avcodec_init(); | |||
| if (args) strncpy(vf->priv->eq, args, 199); | |||
| return 1; | |||
| } | |||
| const vf_info_t vf_info_qp = { | |||
| "QP changer", | |||
| "qp", | |||
| "Michael Niedermayer", | |||
| "", | |||
| vf_open, | |||
| NULL | |||
| }; | |||
| @@ -0,0 +1,181 @@ | |||
| /* | |||
| * This file is part of MPlayer. | |||
| * | |||
| * MPlayer 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. | |||
| * | |||
| * MPlayer 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 MPlayer; if not, write to the Free Software Foundation, Inc., | |||
| * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | |||
| */ | |||
| #include <stdio.h> | |||
| #include <stdlib.h> | |||
| #include <string.h> | |||
| #include "mp_image.h" | |||
| #include "mp_msg.h" | |||
| #include "vf.h" | |||
| #include "libvo/fastmemcpy.h" | |||
| #include "libavutil/common.h" | |||
| struct vf_priv_s { | |||
| int x, y, w, h; | |||
| }; | |||
| static int | |||
| config(struct vf_instance *vf, | |||
| int width, int height, int d_width, int d_height, | |||
| unsigned int flags, unsigned int outfmt) | |||
| { | |||
| if (vf->priv->w < 0 || width < vf->priv->w) | |||
| vf->priv->w = width; | |||
| if (vf->priv->h < 0 || height < vf->priv->h) | |||
| vf->priv->h = height; | |||
| if (vf->priv->x < 0) | |||
| vf->priv->x = (width - vf->priv->w) / 2; | |||
| if (vf->priv->y < 0) | |||
| vf->priv->y = (height - vf->priv->h) / 2; | |||
| if (vf->priv->w + vf->priv->x > width | |||
| || vf->priv->h + vf->priv->y > height) { | |||
| mp_msg(MSGT_VFILTER,MSGL_WARN,"rectangle: bad position/width/height - rectangle area is out of the original!\n"); | |||
| return 0; | |||
| } | |||
| return vf_next_config(vf, width, height, d_width, d_height, flags, outfmt); | |||
| } | |||
| static int | |||
| control(struct vf_instance *vf, int request, void *data) | |||
| { | |||
| const int *const tmp = data; | |||
| switch(request){ | |||
| case VFCTRL_CHANGE_RECTANGLE: | |||
| switch (tmp[0]){ | |||
| case 0: | |||
| vf->priv->w += tmp[1]; | |||
| return 1; | |||
| break; | |||
| case 1: | |||
| vf->priv->h += tmp[1]; | |||
| return 1; | |||
| break; | |||
| case 2: | |||
| vf->priv->x += tmp[1]; | |||
| return 1; | |||
| break; | |||
| case 3: | |||
| vf->priv->y += tmp[1]; | |||
| return 1; | |||
| break; | |||
| default: | |||
| mp_msg(MSGT_VFILTER,MSGL_FATAL,"Unknown param %d \n", tmp[0]); | |||
| return 0; | |||
| } | |||
| } | |||
| return vf_next_control(vf, request, data); | |||
| return 0; | |||
| } | |||
| static int | |||
| put_image(struct vf_instance *vf, mp_image_t* mpi, double pts){ | |||
| mp_image_t* dmpi; | |||
| unsigned int bpp = mpi->bpp / 8; | |||
| int x, y, w, h; | |||
| dmpi = vf_get_image(vf->next, mpi->imgfmt, MP_IMGTYPE_TEMP, | |||
| MP_IMGFLAG_ACCEPT_STRIDE | MP_IMGFLAG_PREFER_ALIGNED_STRIDE, | |||
| mpi->w, mpi->h); | |||
| memcpy_pic(dmpi->planes[0],mpi->planes[0],mpi->w*bpp, mpi->h, | |||
| dmpi->stride[0],mpi->stride[0]); | |||
| if(mpi->flags&MP_IMGFLAG_PLANAR && mpi->flags&MP_IMGFLAG_YUV){ | |||
| memcpy_pic(dmpi->planes[1],mpi->planes[1], | |||
| mpi->w>>mpi->chroma_x_shift, mpi->h>>mpi->chroma_y_shift, | |||
| dmpi->stride[1],mpi->stride[1]); | |||
| memcpy_pic(dmpi->planes[2],mpi->planes[2], | |||
| mpi->w>>mpi->chroma_x_shift, mpi->h>>mpi->chroma_y_shift, | |||
| dmpi->stride[2],mpi->stride[2]); | |||
| } | |||
| /* Draw the rectangle */ | |||
| mp_msg(MSGT_VFILTER,MSGL_INFO, "rectangle: -vf rectangle=%d:%d:%d:%d \n", vf->priv->w, vf->priv->h, vf->priv->x, vf->priv->y); | |||
| x = FFMIN(vf->priv->x, dmpi->width); | |||
| x = FFMAX(x, 0); | |||
| w = vf->priv->x + vf->priv->w - 1 - x; | |||
| w = FFMIN(w, dmpi->width - x); | |||
| w = FFMAX(w, 0); | |||
| y = FFMIN(vf->priv->y, dmpi->height); | |||
| y = FFMAX(y, 0); | |||
| h = vf->priv->y + vf->priv->h - 1 - y; | |||
| h = FFMIN(h, dmpi->height - y); | |||
| h = FFMAX(h, 0); | |||
| if (0 <= vf->priv->y && vf->priv->y <= dmpi->height) { | |||
| unsigned char *p = dmpi->planes[0] + y * dmpi->stride[0] + x * bpp; | |||
| unsigned int count = w * bpp; | |||
| while (count--) | |||
| p[count] = 0xff - p[count]; | |||
| } | |||
| if (h != 1 && vf->priv->y + vf->priv->h - 1 <= mpi->height) { | |||
| unsigned char *p = dmpi->planes[0] + (vf->priv->y + vf->priv->h - 1) * dmpi->stride[0] + x * bpp; | |||
| unsigned int count = w * bpp; | |||
| while (count--) | |||
| p[count] = 0xff - p[count]; | |||
| } | |||
| if (0 <= vf->priv->x && vf->priv->x <= dmpi->width) { | |||
| unsigned char *p = dmpi->planes[0] + y * dmpi->stride[0] + x * bpp; | |||
| unsigned int count = h; | |||
| while (count--) { | |||
| unsigned int i = bpp; | |||
| while (i--) | |||
| p[i] = 0xff - p[i]; | |||
| p += dmpi->stride[0]; | |||
| } | |||
| } | |||
| if (w != 1 && vf->priv->x + vf->priv->w - 1 <= mpi->width) { | |||
| unsigned char *p = dmpi->planes[0] + y * dmpi->stride[0] + (vf->priv->x + vf->priv->w - 1) * bpp; | |||
| unsigned int count = h; | |||
| while (count--) { | |||
| unsigned int i = bpp; | |||
| while (i--) | |||
| p[i] = 0xff - p[i]; | |||
| p += dmpi->stride[0]; | |||
| } | |||
| } | |||
| return vf_next_put_image(vf, dmpi, pts); | |||
| } | |||
| static int | |||
| vf_open(vf_instance_t *vf, char *args) { | |||
| vf->config = config; | |||
| vf->control = control; | |||
| vf->put_image = put_image; | |||
| vf->priv = malloc(sizeof(struct vf_priv_s)); | |||
| vf->priv->x = -1; | |||
| vf->priv->y = -1; | |||
| vf->priv->w = -1; | |||
| vf->priv->h = -1; | |||
| if (args) | |||
| sscanf(args, "%d:%d:%d:%d", | |||
| &vf->priv->w, &vf->priv->h, &vf->priv->x, &vf->priv->y); | |||
| return 1; | |||
| } | |||
| const vf_info_t vf_info_rectangle = { | |||
| "draw rectangle", | |||
| "rectangle", | |||
| "Kim Minh Kaplan", | |||
| "", | |||
| vf_open, | |||
| NULL | |||
| }; | |||
| @@ -0,0 +1,906 @@ | |||
| /* | |||
| * This filter loads a .pgm mask file showing where a logo is and uses | |||
| * a blur transform to remove the logo. | |||
| * | |||
| * Copyright (C) 2005 Robert Edele <yartrebo@earthlink.net> | |||
| * | |||
| * This file is part of MPlayer. | |||
| * | |||
| * MPlayer 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. | |||
| * | |||
| * MPlayer 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 MPlayer; if not, write to the Free Software Foundation, Inc., | |||
| * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | |||
| */ | |||
| /** | |||
| * \file vf_remove_logo.c | |||
| * | |||
| * \brief Advanced blur-based logo removing filter. | |||
| * Hello and welcome. This code implements a filter to remove annoying TV | |||
| * logos and other annoying images placed onto a video stream. It works by filling | |||
| * in the pixels that comprise the logo with neighboring pixels. The transform is | |||
| * very loosely based on a gaussian blur, but it is different enough to merit its | |||
| * own paragraph later on. It is a major improvement on the old delogo filter as | |||
| * it both uses a better blurring algorithm and uses a bitmap to use an arbitrary | |||
| * and generally much tighter fitting shape than a rectangle. | |||
| * | |||
| * The filter requires 1 argument and has no optional arguments. It requires | |||
| * a filter bitmap, which must be in PGM or PPM format. A sample invocation would | |||
| * be -vf remove_logo=/home/username/logo_bitmaps/xyz.pgm. Pixels with a value of | |||
| * zero are not part of the logo, and non-zero pixels are part of the logo. If you | |||
| * use white (255) for the logo and black (0) for the rest, you will be safe. For | |||
| * making the filter bitmap, I recommend taking a screen capture of a black frame | |||
| * with the logo visible, and then using The GIMP's threshold filter followed by | |||
| * the erode filter once or twice. If needed, little splotches can be fixed | |||
| * manually. Remember that if logo pixels are not covered, the filter quality will | |||
| * be much reduced. Marking too many pixels as part of the logo doesn't hurt as | |||
| * much, but it will increase the amount of blurring needed to cover over the | |||
| * image and will destroy more information than necessary. Additionally, this blur | |||
| * algorithm is O(n) = n^4, where n is the width and height of a hypothetical | |||
| * square logo, so extra pixels will slow things down on a large lo | |||
| * | |||
| * The logo removal algorithm has two key points. The first is that it | |||
| * distinguishes between pixels in the logo and those not in the logo by using the | |||
| * passed-in bitmap. Pixels not in the logo are copied over directly without being | |||
| * modified and they also serve as source pixels for the logo fill-in. Pixels | |||
| * inside the logo have the mask applied. | |||
| * | |||
| * At init-time the bitmap is reprocessed internally, and the distance to the | |||
| * nearest edge of the logo (Manhattan distance), along with a little extra to | |||
| * remove rough edges, is stored in each pixel. This is done using an in-place | |||
| * erosion algorithm, and incrementing each pixel that survives any given erosion. | |||
| * Once every pixel is eroded, the maximum value is recorded, and a set of masks | |||
| * from size 0 to this size are generaged. The masks are circular binary masks, | |||
| * where each pixel within a radius N (where N is the size of the mask) is a 1, | |||
| * and all other pixels are a 0. Although a gaussian mask would be more | |||
| * mathematically accurate, a binary mask works better in practice because we | |||
| * generally do not use the central pixels in the mask (because they are in the | |||
| * logo region), and thus a gaussian mask will cause too little blur and thus a | |||
| * very unstable image. | |||
| * | |||
| * The mask is applied in a special way. Namely, only pixels in the mask that | |||
| * line up to pixels outside the logo are used. The dynamic mask size means that | |||
| * the mask is just big enough so that the edges touch pixels outside the logo, so | |||
| * the blurring is kept to a minimum and at least the first boundary condition is | |||
| * met (that the image function itself is continuous), even if the second boundary | |||
| * condition (that the derivative of the image function is continuous) is not met. | |||
| * A masking algorithm that does preserve the second boundary coundition | |||
| * (perhaps something based on a highly-modified bi-cubic algorithm) should offer | |||
| * even better results on paper, but the noise in a typical TV signal should make | |||
| * anything based on derivatives hopelessly noisy. | |||
| */ | |||
| #include <stdio.h> | |||
| #include <stdlib.h> | |||
| #include <string.h> | |||
| #include <ctype.h> | |||
| #include <inttypes.h> | |||
| #include "config.h" | |||
| #include "mp_msg.h" | |||
| #include "libvo/fastmemcpy.h" | |||
| #include "img_format.h" | |||
| #include "mp_image.h" | |||
| #include "vf.h" | |||
| //===========================================================================// | |||
| /** \brief Returns the larger of the two arguments. **/ | |||
| #define max(x,y) ((x)>(y)?(x):(y)) | |||
| /** \brief Returns the smaller of the two arguments. **/ | |||
| #define min(x,y) ((x)>(y)?(y):(x)) | |||
| /** | |||
| * \brief Test if a pixel is part of the logo. | |||
| */ | |||
| #define test_filter(image, x, y) ((unsigned char) (image->pixel[((y) * image->width) + (x)])) | |||
| /** | |||
| * \brief Chooses a slightly larger mask size to improve performance. | |||
| * | |||
| * This function maps the absolute minimum mask size needed to the mask size we'll | |||
| * actually use. f(x) = x (the smallest that will work) will produce the sharpest | |||
| * results, but will be quite jittery. f(x) = 1.25x (what I'm using) is a good | |||
| * tradeoff in my opinion. This will calculate only at init-time, so you can put a | |||
| * long expression here without effecting performance. | |||
| */ | |||
| #define apply_mask_fudge_factor(x) (((x) >> 2) + x) | |||
| /** | |||
| * \brief Simple implementation of the PGM image format. | |||
| * | |||
| * This struct holds a bare-bones image loaded from a PGM or PPM file. Once | |||
| * loaded and pre-processed, each pixel in this struct will contain how far from | |||
| * the edge of the logo each pixel is, using the manhattan distance (|dx| + |dy|). | |||
| * | |||
| * pixels in char * pixel can be addressed using (y * width) + height. | |||
| */ | |||
| typedef struct | |||
| { | |||
| unsigned int width; | |||
| unsigned int height; | |||
| unsigned char * pixel; | |||
| } pgm_structure; | |||
| /** | |||
| * \brief Stores persistant variables. | |||
| * | |||
| * Variables stored here are kept from frame to frame, and separate instances of | |||
| * the filter will get their own separate copies. | |||
| */ | |||
| struct vf_priv_s | |||
| { | |||
| unsigned int fmt; /* Not exactly sure of the use for this. It came with the example filter I used as a basis for this, and it looks like a lot of stuff will break if I remove it. */ | |||
| int max_mask_size; /* The largest possible mask size that will be needed with the given filter and corresponding half_size_filter. The half_size_filter can have a larger requirment in some rare (but not degenerate) cases. */ | |||
| int * * * mask; /* Stores our collection of masks. The first * is for an array of masks, the second for the y axis, and the third for the x axis. */ | |||
| pgm_structure * filter; /* Stores the full-size filter image. This is used to tell what pixels are in the logo or not in the luma plane. */ | |||
| pgm_structure * half_size_filter; /* Stores a 50% width and 50% height filter image. This is used to tell what pixels are in the logo or not in the chroma planes. */ | |||
| /* These 8 variables store the bounding rectangles that the logo resides in. */ | |||
| int bounding_rectangle_posx1; | |||
| int bounding_rectangle_posy1; | |||
| int bounding_rectangle_posx2; | |||
| int bounding_rectangle_posy2; | |||
| int bounding_rectangle_half_size_posx1; | |||
| int bounding_rectangle_half_size_posy1; | |||
| int bounding_rectangle_half_size_posx2; | |||
| int bounding_rectangle_half_size_posy2; | |||
| } vf_priv_s; | |||
| /** | |||
| * \brief Mallocs memory and checks to make sure it succeeded. | |||
| * | |||
| * \param size How many bytes to allocate. | |||
| * | |||
| * \return A pointer to the freshly allocated memory block, or NULL on failutre. | |||
| * | |||
| * Mallocs memory, and checks to make sure it was successfully allocated. Because | |||
| * of how MPlayer works, it cannot safely halt execution, but at least the user | |||
| * will get an error message before the segfault happens. | |||
| */ | |||
| static void * safe_malloc(int size) | |||
| { | |||
| void * answer = malloc(size); | |||
| if (answer == NULL) | |||
| mp_msg(MSGT_VFILTER, MSGL_ERR, "Unable to allocate memory in vf_remove_logo.c\n"); | |||
| return answer; | |||
| } | |||
| /** | |||
| * \brief Calculates the smallest rectangle that will encompass the logo region. | |||
| * | |||
| * \param filter This image contains the logo around which the rectangle will | |||
| * will be fitted. | |||
| * | |||
| * The bounding rectangle is calculated by testing successive lines (from the four | |||
| * sides of the rectangle) until no more can be removed without removing logo | |||
| * pixels. The results are returned by reference to posx1, posy1, posx2, and | |||
| * posy2. | |||
| */ | |||
| static void calculate_bounding_rectangle(int * posx1, int * posy1, int * posx2, int * posy2, pgm_structure * filter) | |||
| { | |||
| int x; /* Temporary variables to run */ | |||
| int y; /* through each row or column. */ | |||
| int start_x; | |||
| int start_y; | |||
| int end_x = filter->width - 1; | |||
| int end_y = filter->height - 1; | |||
| int did_we_find_a_logo_pixel = 0; | |||
| /* Let's find the top bound first. */ | |||
| for (start_x = 0; start_x < filter->width && !did_we_find_a_logo_pixel; start_x++) | |||
| { | |||
| for (y = 0; y < filter->height; y++) | |||
| { | |||
| did_we_find_a_logo_pixel |= test_filter(filter, start_x, y); | |||
| } | |||
| } | |||
| start_x--; | |||
| /* Now the bottom bound. */ | |||
| did_we_find_a_logo_pixel = 0; | |||
| for (end_x = filter->width - 1; end_x > start_x && !did_we_find_a_logo_pixel; end_x--) | |||
| { | |||
| for (y = 0; y < filter->height; y++) | |||
| { | |||
| did_we_find_a_logo_pixel |= test_filter(filter, end_x, y); | |||
| } | |||
| } | |||
| end_x++; | |||
| /* Left bound. */ | |||
| did_we_find_a_logo_pixel = 0; | |||
| for (start_y = 0; start_y < filter->height && !did_we_find_a_logo_pixel; start_y++) | |||
| { | |||
| for (x = 0; x < filter->width; x++) | |||
| { | |||
| did_we_find_a_logo_pixel |= test_filter(filter, x, start_y); | |||
| } | |||
| } | |||
| start_y--; | |||
| /* Right bound. */ | |||
| did_we_find_a_logo_pixel = 0; | |||
| for (end_y = filter->height - 1; end_y > start_y && !did_we_find_a_logo_pixel; end_y--) | |||
| { | |||
| for (x = 0; x < filter->width; x++) | |||
| { | |||
| did_we_find_a_logo_pixel |= test_filter(filter, x, end_y); | |||
| } | |||
| } | |||
| end_y++; | |||
| *posx1 = start_x; | |||
| *posy1 = start_y; | |||
| *posx2 = end_x; | |||
| *posy2 = end_y; | |||
| return; | |||
| } | |||
| /** | |||
| * \brief Free mask memory. | |||
| * | |||
| * \param vf Data structure which stores our persistant data, and is to be freed. | |||
| * | |||
| * We call this function when our filter is done. It will free the memory | |||
| * allocated to the masks and leave the variables in a safe state. | |||
| */ | |||
| static void destroy_masks(vf_instance_t * vf) | |||
| { | |||
| int a, b; | |||
| /* Load values from the vf->priv struct for faster dereferencing. */ | |||
| int * * * mask = vf->priv->mask; | |||
| int max_mask_size = vf->priv->max_mask_size; | |||
| if (mask == NULL) | |||
| return; /* Nothing allocated, so return before we segfault. */ | |||
| /* Free all allocated memory. */ | |||
| for (a = 0; a <= max_mask_size; a++) /* Loop through each mask. */ | |||
| { | |||
| for (b = -a; b <= a; b++) /* Loop through each scanline in a mask. */ | |||
| { | |||
| free(mask[a][b + a]); /* Free a scanline. */ | |||
| } | |||
| free(mask[a]); /* Free a mask. */ | |||
| } | |||
| free(mask); /* Free the array of pointers pointing to the masks. */ | |||
| /* Set the pointer to NULL, so that any duplicate calls to this function will not cause a crash. */ | |||
| vf->priv->mask = NULL; | |||
| return; | |||
| } | |||
| /** | |||
| * \brief Set up our array of masks. | |||
| * | |||
| * \param vf Where our filter stores persistance data, like these masks. | |||
| * | |||
| * This creates an array of progressively larger masks and calculates their | |||
| * values. The values will not change during program execution once this function | |||
| * is done. | |||
| */ | |||
| static void initialize_masks(vf_instance_t * vf) | |||
| { | |||
| int a, b, c; | |||
| /* Load values from the vf->priv struct for faster dereferencing. */ | |||
| int * * * mask = vf->priv->mask; | |||
| int max_mask_size = vf->priv->max_mask_size; /* This tells us how many masks we'll need to generate. */ | |||
| /* Create a circular mask for each size up to max_mask_size. When the filter is applied, the mask size is | |||
| determined on a pixel by pixel basis, with pixels nearer the edge of the logo getting smaller mask sizes. */ | |||
| mask = (int * * *) safe_malloc(sizeof(int * *) * (max_mask_size + 1)); | |||
| for (a = 0; a <= max_mask_size; a++) | |||
| { | |||
| mask[a] = (int * *) safe_malloc(sizeof(int *) * ((a * 2) + 1)); | |||
| for (b = -a; b <= a; b++) | |||
| { | |||
| mask[a][b + a] = (int *) safe_malloc(sizeof(int) * ((a * 2) + 1)); | |||
| for (c = -a; c <= a; c++) | |||
| { | |||
| if ((b * b) + (c * c) <= (a * a)) /* Circular 0/1 mask. */ | |||
| mask[a][b + a][c + a] = 1; | |||
| else | |||
| mask[a][b + a][c + a] = 0; | |||
| } | |||
| } | |||
| } | |||
| /* Store values back to vf->priv so they aren't lost after the function returns. */ | |||
| vf->priv->mask = mask; | |||
| return; | |||
| } | |||
| /** | |||
| * \brief Pre-processes an image to give distance information. | |||
| * | |||
| * \param vf Data structure that holds persistant information. All it is used for | |||
| in this function is to store the calculated max_mask_size variable. | |||
| * \param mask This image will be converted from a greyscale image into a | |||
| * distance image. | |||
| * | |||
| * This function takes a greyscale image (pgm_structure * mask) and converts it | |||
| * in place into a distance image. A distance image is zero for pixels ourside of | |||
| * the logo and is the manhattan distance (|dx| + |dy|) for pixels inside of the | |||
| * logo. This will overestimate the distance, but that is safe, and is far easier | |||
| * to implement than a proper pythagorean distance since I'm using a modified | |||
| * erosion algorithm to compute the distances. | |||
| */ | |||
| static void convert_mask_to_strength_mask(vf_instance_t * vf, pgm_structure * mask) | |||
| { | |||
| int x, y; /* Used by our for loops to go through every single pixel in the picture one at a time. */ | |||
| int has_anything_changed = 1; /* Used by the main while() loop to know if anything changed on the last erosion. */ | |||
| int current_pass = 0; /* How many times we've gone through the loop. Used in the in-place erosion algorithm | |||
| and to get us max_mask_size later on. */ | |||
| int max_mask_size; /* This will record how large a mask the pixel that is the furthest from the edge of the logo | |||
| (and thus the neediest) is. */ | |||
| char * current_pixel = mask->pixel; /* This stores the actual pixel data. */ | |||
| /* First pass, set all non-zero values to 1. After this loop finishes, the data should be considered numeric | |||
| data for the filter, not color data. */ | |||
| for (x = 0; x < mask->height * mask->width; x++, current_pixel++) | |||
| if(*current_pixel) *current_pixel = 1; | |||
| /* Second pass and future passes. For each pass, if a pixel is itself the same value as the current pass, | |||
| and its four neighbors are too, then it is incremented. If no pixels are incremented by the end of the pass, | |||
| then we go again. Edge pixels are counted as always excluded (this should be true anyway for any sane mask, | |||
| but if it isn't this will ensure that we eventually exit). */ | |||
| while (has_anything_changed) | |||
| { | |||
| current_pass++; | |||
| current_pixel = mask->pixel; | |||
| has_anything_changed = 0; /* If this doesn't get set by the end of this pass, then we're done. */ | |||
| for (y = 1; y < mask->height - 1; y++) | |||
| { | |||
| for (x = 1; x < mask->width - 1; x++) | |||
| { | |||
| /* Apply the in-place erosion transform. It is based on the following two premises: 1 - Any pixel that fails 1 erosion | |||
| will fail all future erosions. 2 - Only pixels having survived all erosions up to the present will be >= to | |||
| current_pass. It doesn't matter if it survived the current pass, failed it, or hasn't been tested yet. */ | |||
| if (*current_pixel >= current_pass && /* By using >= instead of ==, we allow the algorithm to work in place. */ | |||
| *(current_pixel + 1) >= current_pass && | |||
| *(current_pixel - 1) >= current_pass && | |||
| *(current_pixel + mask->width) >= current_pass && | |||
| *(current_pixel - mask->width) >= current_pass) | |||
| { | |||
| (*current_pixel)++; /* Increment the value since it still has not been eroded, as evidenced by the if statement | |||
| that just evaluated to true. */ | |||
| has_anything_changed = 1; | |||
| } | |||
| current_pixel++; | |||
| } | |||
| } | |||
| } | |||
| /* Apply the fudge factor, which will increase the size of the mask a little to reduce jitter at the cost of more blur. */ | |||
| for (y = 1; y < mask->height - 1; y++) | |||
| { | |||
| for (x = 1; x < mask->width - 1; x++) | |||
| { | |||
| mask->pixel[(y * mask->width) + x] = apply_mask_fudge_factor(mask->pixel[(y * mask->width) + x]); | |||
| } | |||
| } | |||
| max_mask_size = current_pass + 1; /* As a side-effect, we now know the maximum mask size, which we'll use to generate our masks. */ | |||
| max_mask_size = apply_mask_fudge_factor(max_mask_size); /* Apply the fudge factor to this number too, since we must | |||
| ensure that enough masks are generated. */ | |||
| vf->priv->max_mask_size = max_mask_size; /* Commit the newly calculated max_mask_size to the vf->priv struct. */ | |||
| return; | |||
| } | |||
| /** | |||
| * \brief Our blurring function. | |||
| * | |||
| * \param vf Stores persistant data. In this function we are interested in the | |||
| * array of masks. | |||
| * \param value_out The properly blurred and delogoed pixel is outputted here. | |||
| * \param logo_mask Tells us which pixels are in the logo and which aren't. | |||
| * \param image The image that is having its logo removed. | |||
| * \param x x-coordinate of the pixel to blur. | |||
| * \param y y-coordinate of the pixel to blur. | |||
| * \param plane 0 = luma, 1 = blue chroma, 2 = red chroma (YUV). | |||
| * | |||
| * This function is the core of the filter. It takes a pixel that is inside the | |||
| * logo and blurs it. It does so by finding the average of all the pixels within | |||
| * the mask and outside of the logo. | |||
| */ | |||
| static void get_blur(const vf_instance_t * const vf, unsigned int * const value_out, const pgm_structure * const logo_mask, | |||
| const mp_image_t * const image, const int x, const int y, const int plane) | |||
| { | |||
| int mask_size; /* Mask size tells how large a circle to use. The radius is about (slightly larger than) mask size. */ | |||
| /* Get values from vf->priv for faster dereferencing. */ | |||
| int * * * mask = vf->priv->mask; | |||
| int start_posx, start_posy, end_posx, end_posy; | |||
| int i, j; | |||
| unsigned int accumulator = 0, divisor = 0; | |||
| const unsigned char * mask_read_position; /* What pixel we are reading out of the circular blur mask. */ | |||
| const unsigned char * logo_mask_read_position; /* What pixel we are reading out of the filter image. */ | |||
| /* Prepare our bounding rectangle and clip it if need be. */ | |||
| mask_size = test_filter(logo_mask, x, y); | |||
| start_posx = max(0, x - mask_size); | |||
| start_posy = max(0, y - mask_size); | |||
| end_posx = min(image->width - 1, x + mask_size); | |||
| end_posy = min(image->height - 1, y + mask_size); | |||
| mask_read_position = image->planes[plane] + (image->stride[plane] * start_posy) + start_posx; | |||
| logo_mask_read_position = logo_mask->pixel + (start_posy * logo_mask->width) + start_posx; | |||
| for (j = start_posy; j <= end_posy; j++) | |||
| { | |||
| for (i = start_posx; i <= end_posx; i++) | |||
| { | |||
| if (!(*logo_mask_read_position) && mask[mask_size][i - start_posx][j - start_posy]) | |||
| { /* Check to see if this pixel is in the logo or not. Only use the pixel if it is not. */ | |||
| accumulator += *mask_read_position; | |||
| divisor++; | |||
| } | |||
| mask_read_position++; | |||
| logo_mask_read_position++; | |||
| } | |||
| mask_read_position += (image->stride[plane] - ((end_posx + 1) - start_posx)); | |||
| logo_mask_read_position += (logo_mask->width - ((end_posx + 1) - start_posx)); | |||
| } | |||
| if (divisor == 0) /* This means that not a single pixel is outside of the logo, so we have no data. */ | |||
| { /* We should put some eye catching value here, to indicate the flaw to the user. */ | |||
| *value_out = 255; | |||
| } | |||
| else /* Else we need to normalise the data using the divisor. */ | |||
| { | |||
| *value_out = (accumulator + (divisor / 2)) / divisor; /* Divide, taking into account average rounding error. */ | |||
| } | |||
| return; | |||
| } | |||
| /** | |||
| * \brief Free a pgm_structure. Undoes load_pgm(...). | |||
| */ | |||
| static void destroy_pgm(pgm_structure * to_be_destroyed) | |||
| { | |||
| if (to_be_destroyed == NULL) | |||
| return; /* Don't do anything if a NULL pointer was passed it. */ | |||
| /* Internally allocated memory. */ | |||
| if (to_be_destroyed->pixel != NULL) | |||
| { | |||
| free(to_be_destroyed->pixel); | |||
| to_be_destroyed->pixel = NULL; | |||
| } | |||
| /* Free the actual struct instance. This is done here and not by the calling function. */ | |||
| free(to_be_destroyed); | |||
| } | |||
| /** \brief Helper function for load_pgm(...) to skip whitespace. */ | |||
| static void load_pgm_skip(FILE *f) { | |||
| int c, comment = 0; | |||
| do { | |||
| c = fgetc(f); | |||
| if (c == '#') | |||
| comment = 1; | |||
| if (c == '\n') | |||
| comment = 0; | |||
| } while (c != EOF && (isspace(c) || comment)); | |||
| ungetc(c, f); | |||
| } | |||
| #define REMOVE_LOGO_LOAD_PGM_ERROR_MESSAGE(message) {mp_msg(MSGT_VFILTER, MSGL_ERR, message); return NULL;} | |||
| /** | |||
| * \brief Loads a raw pgm or ppm file into a newly created pgm_structure object. | |||
| * | |||
| * \param file_name The name of the file to be loaded. So long as the file is a | |||
| * valid pgm or ppm file, it will load correctly, even if the | |||
| * extension is missing or invalid. | |||
| * | |||
| * \return A pointer to the newly created pgm_structure object. Don't forget to | |||
| * call destroy_pgm(...) when you're done with this. If an error occurs, | |||
| * NULL is returned. | |||
| * | |||
| * Can load either raw pgm (P5) or raw ppm (P6) image files as a binary image. | |||
| * While a pgm file will be loaded normally (greyscale), the only thing that is | |||
| * guaranteed with ppm is that all zero (R = 0, G = 0, B = 0) pixels will remain | |||
| * zero, and non-zero pixels will remain non-zero. | |||
| */ | |||
| static pgm_structure * load_pgm(const char * file_name) | |||
| { | |||
| int maximum_greyscale_value; | |||
| FILE * input; | |||
| int pnm_number; | |||
| pgm_structure * new_pgm = (pgm_structure *) safe_malloc (sizeof(pgm_structure)); | |||
| char * write_position; | |||
| char * end_position; | |||
| int image_size; /* width * height */ | |||
| if((input = fopen(file_name, "rb")) == NULL) REMOVE_LOGO_LOAD_PGM_ERROR_MESSAGE("[vf]remove-logo: Unable to open file. File not found or insufficient permissions.\n"); | |||
| /* Parse the PGM header. */ | |||
| if (fgetc(input) != 'P') REMOVE_LOGO_LOAD_PGM_ERROR_MESSAGE("[vf]remove-logo: File is not a valid PGM or PPM file.\n"); | |||
| pnm_number = fgetc(input) - '0'; | |||
| if (pnm_number != 5 && pnm_number != 6) REMOVE_LOGO_LOAD_PGM_ERROR_MESSAGE("[vf]remove-logo: Invalid PNM file. Only raw PGM (Portable Gray Map) and raw PPM (Portable Pixel Map) subtypes are allowed.\n"); | |||
| load_pgm_skip(input); | |||
| if (fscanf(input, "%i", &(new_pgm->width)) != 1) REMOVE_LOGO_LOAD_PGM_ERROR_MESSAGE("[vf]remove-logo: Invalid PGM/PPM header.\n"); | |||
| load_pgm_skip(input); | |||
| if (fscanf(input, "%i", &(new_pgm->height)) != 1) REMOVE_LOGO_LOAD_PGM_ERROR_MESSAGE("[vf]remove-logo: Invalid PGM/PPM header.\n"); | |||
| load_pgm_skip(input); | |||
| if (fscanf(input, "%i", &maximum_greyscale_value) != 1) REMOVE_LOGO_LOAD_PGM_ERROR_MESSAGE("[vf]remove-logo: Invalid PGM/PPM header.\n"); | |||
| if (maximum_greyscale_value >= 256) REMOVE_LOGO_LOAD_PGM_ERROR_MESSAGE("[vf]remove_logo: Only 1 byte per pixel (pgm) or 1 byte per color value (ppm) are supported.\n"); | |||
| load_pgm_skip(input); | |||
| new_pgm->pixel = (unsigned char *) safe_malloc (sizeof(unsigned char) * new_pgm->width * new_pgm->height); | |||
| /* Load the pixels. */ | |||
| /* Note: I am aware that fgetc(input) isn't the fastest way of doing things, but it is quite compact and the code only runs once when the filter is initialized.*/ | |||
| image_size = new_pgm->width * new_pgm->height; | |||
| end_position = new_pgm->pixel + image_size; | |||
| for (write_position = new_pgm->pixel; write_position < end_position; write_position++) | |||
| { | |||
| *write_position = fgetc(input); | |||
| if (pnm_number == 6) /* This tests to see if the file is a PPM file. */ | |||
| { /* If it is, then consider the pixel set if any of the three color channels are set. Since we just care about == 0 or != 0, a bitwise or will do the trick. */ | |||
| *write_position |= fgetc(input); | |||
| *write_position |= fgetc(input); | |||
| } | |||
| } | |||
| return new_pgm; | |||
| } | |||
| /** | |||
| * \brief Generates a scaled down image with half width, height, and intensity. | |||
| * | |||
| * \param vf Our struct for persistant data. In this case, it is used to update | |||
| * mask_max_size with the larger of the old or new value. | |||
| * \param input_image The image from which the new half-sized one will be based. | |||
| * | |||
| * \return The newly allocated and shrunken image. | |||
| * | |||
| * This function not only scales down an image, but halves the value in each pixel | |||
| * too. The purpose of this is to produce a chroma filter image out of a luma | |||
| * filter image. The pixel values store the distance to the edge of the logo and | |||
| * halving the dimensions halves the distance. This function rounds up, because | |||
| * a downwards rounding error could cause the filter to fail, but an upwards | |||
| * rounding error will only cause a minor amount of excess blur in the chroma | |||
| * planes. | |||
| */ | |||
| static pgm_structure * generate_half_size_image(vf_instance_t * vf, pgm_structure * input_image) | |||
| { | |||
| int x, y; | |||
| pgm_structure * new_pgm = (pgm_structure *) safe_malloc (sizeof(pgm_structure)); | |||
| int has_anything_changed = 1; | |||
| int current_pass; | |||
| int max_mask_size; | |||
| char * current_pixel; | |||
| new_pgm->width = input_image->width / 2; | |||
| new_pgm->height = input_image->height / 2; | |||
| new_pgm->pixel = (unsigned char *) safe_malloc (sizeof(unsigned char) * new_pgm->width * new_pgm->height); | |||
| /* Copy over the image data, using the average of 4 pixels for to calculate each downsampled pixel. */ | |||
| for (y = 0; y < new_pgm->height; y++) | |||
| for (x = 0; x < new_pgm->width; x++) | |||
| { | |||
| /* Set the pixel if there exists a non-zero value in the source pixels, else clear it. */ | |||
| new_pgm->pixel[(y * new_pgm->width) + x] = input_image->pixel[((y << 1) * input_image->width) + (x << 1)] || | |||
| input_image->pixel[((y << 1) * input_image->width) + (x << 1) + 1] || | |||
| input_image->pixel[(((y << 1) + 1) * input_image->width) + (x << 1)] || | |||
| input_image->pixel[(((y << 1) + 1) * input_image->width) + (x << 1) + 1]; | |||
| new_pgm->pixel[(y * new_pgm->width) + x] = min(1, new_pgm->pixel[(y * new_pgm->width) + x]); | |||
| } | |||
| /* Now we need to recalculate the numbers for the smaller size. Just using the old_value / 2 can cause subtle | |||
| and fairly rare, but very nasty, bugs. */ | |||
| current_pixel = new_pgm->pixel; | |||
| /* First pass, set all non-zero values to 1. */ | |||
| for (x = 0; x < new_pgm->height * new_pgm->width; x++, current_pixel++) | |||
| if(*current_pixel) *current_pixel = 1; | |||
| /* Second pass and future passes. For each pass, if a pixel is itself the same value as the current pass, | |||
| and its four neighbors are too, then it is incremented. If no pixels are incremented by the end of the pass, | |||
| then we go again. Edge pixels are counted as always excluded (this should be true anyway for any sane mask, | |||
| but if it isn't this will ensure that we eventually exit). */ | |||
| current_pass = 0; | |||
| while (has_anything_changed) | |||
| { | |||
| current_pass++; | |||
| has_anything_changed = 0; /* If this doesn't get set by the end of this pass, then we're done. */ | |||
| for (y = 1; y < new_pgm->height - 1; y++) | |||
| { | |||
| for (x = 1; x < new_pgm->width - 1; x++) | |||
| { | |||
| if (new_pgm->pixel[(y * new_pgm->width) + x] >= current_pass && /* By using >= instead of ==, we allow the algorithm to work in place. */ | |||
| new_pgm->pixel[(y * new_pgm->width) + (x + 1)] >= current_pass && | |||
| new_pgm->pixel[(y * new_pgm->width) + (x - 1)] >= current_pass && | |||
| new_pgm->pixel[((y + 1) * new_pgm->width) + x] >= current_pass && | |||
| new_pgm->pixel[((y - 1) * new_pgm->width) + x] >= current_pass) | |||
| { | |||
| new_pgm->pixel[(y * new_pgm->width) + x]++; /* Increment the value since it still has not been eroded, | |||
| as evidenced by the if statement that just evaluated to true. */ | |||
| has_anything_changed = 1; | |||
| } | |||
| } | |||
| } | |||
| } | |||
| for (y = 1; y < new_pgm->height - 1; y++) | |||
| { | |||
| for (x = 1; x < new_pgm->width - 1; x++) | |||
| { | |||
| new_pgm->pixel[(y * new_pgm->width) + x] = apply_mask_fudge_factor(new_pgm->pixel[(y * new_pgm->width) + x]); | |||
| } | |||
| } | |||
| max_mask_size = current_pass + 1; /* As a side-effect, we now know the maximum mask size, which we'll use to generate our masks. */ | |||
| max_mask_size = apply_mask_fudge_factor(max_mask_size); | |||
| /* Commit the newly calculated max_mask_size to the vf->priv struct. */ | |||
| vf->priv->max_mask_size = max(max_mask_size, vf->priv->max_mask_size); | |||
| return new_pgm; | |||
| } | |||
| /** | |||
| * \brief Checks if YV12 is supported by the next filter. | |||
| */ | |||
| static unsigned int find_best(struct vf_instance *vf){ | |||
| int is_format_okay = vf->next->query_format(vf->next, IMGFMT_YV12); | |||
| if ((is_format_okay & VFCAP_CSP_SUPPORTED_BY_HW) || (is_format_okay & VFCAP_CSP_SUPPORTED)) | |||
| return IMGFMT_YV12; | |||
| else | |||
| return 0; | |||
| } | |||
| //===========================================================================// | |||
| /** | |||
| * \brief Configure the filter and call the next filter's config function. | |||
| */ | |||
| static int config(struct vf_instance *vf, int width, int height, int d_width, int d_height, unsigned int flags, unsigned int outfmt) | |||
| { | |||
| if(!(vf->priv->fmt=find_best(vf))) | |||
| return 0; | |||
| else | |||
| return vf_next_config(vf,width,height,d_width,d_height,flags,vf->priv->fmt); | |||
| } | |||
| /** | |||
| * \brief Removes the logo from a plane (either luma or chroma). | |||
| * | |||
| * \param vf Not needed by this function, but needed by the blur function. | |||
| * \param source The image to have it's logo removed. | |||
| * \param destination Where the output image will be stored. | |||
| * \param source_stride How far apart (in memory) two consecutive lines are. | |||
| * \param destination Same as source_stride, but for the destination image. | |||
| * \param width Width of the image. This is the same for source and destination. | |||
| * \param height Height of the image. This is the same for source and destination. | |||
| * \param is_image_direct If the image is direct, then source and destination are | |||
| * the same and we can save a lot of time by not copying pixels that | |||
| * haven't changed. | |||
| * \param filter The image that stores the distance to the edge of the logo for | |||
| * each pixel. | |||
| * \param logo_start_x Smallest x-coordinate that contains at least 1 logo pixel. | |||
| * \param logo_start_y Smallest y-coordinate that contains at least 1 logo pixel. | |||
| * \param logo_end_x Largest x-coordinate that contains at least 1 logo pixel. | |||
| * \param logo_end_y Largest y-coordinate that contains at least 1 logo pixel. | |||
| * | |||
| * This function processes an entire plane. Pixels outside of the logo are copied | |||
| * to the output without change, and pixels inside the logo have the de-blurring | |||
| * function applied. | |||
| */ | |||
| static void convert_yv12(const vf_instance_t * const vf, const char * const source, const int source_stride, | |||
| const mp_image_t * const source_image, const int width, const int height, | |||
| char * const destination, const int destination_stride, int is_image_direct, pgm_structure * filter, | |||
| const int plane, const int logo_start_x, const int logo_start_y, const int logo_end_x, const int logo_end_y) | |||
| { | |||
| int y; | |||
| int x; | |||
| /* These pointers point to where we are getting our pixel data (inside mpi) and where we are storing it (inside dmpi). */ | |||
| const unsigned char * source_line; | |||
| unsigned char * destination_line; | |||
| if (!is_image_direct) | |||
| memcpy_pic(destination, source, width, height, destination_stride, source_stride); | |||
| for (y = logo_start_y; y <= logo_end_y; y++) | |||
| { | |||
| source_line = (const unsigned char *) source + (source_stride * y); | |||
| destination_line = (unsigned char *) destination + (destination_stride * y); | |||
| for (x = logo_start_x; x <= logo_end_x; x++) | |||
| { | |||
| unsigned int output; | |||
| if (filter->pixel[(y * filter->width) + x]) /* Only process if we are in the logo. */ | |||
| { | |||
| get_blur(vf, &output, filter, source_image, x, y, plane); | |||
| destination_line[x] = output; | |||
| } | |||
| else /* Else just copy the data. */ | |||
| if (!is_image_direct) | |||
| destination_line[x] = source_line[x]; | |||
| } | |||
| } | |||
| } | |||
| /** | |||
| * \brief Process a frame. | |||
| * | |||
| * \param mpi The image sent to use by the previous filter. | |||
| * \param dmpi Where we will store the processed output image. | |||
| * \param vf This is how the filter gets access to it's persistant data. | |||
| * | |||
| * \return The return code of the next filter, or 0 on failure/error. | |||
| * | |||
| * This function processes an entire frame. The frame is sent by the previous | |||
| * filter, has the logo removed by the filter, and is then sent to the next | |||
| * filter. | |||
| */ | |||
| static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts){ | |||
| mp_image_t *dmpi; | |||
| dmpi=vf_get_image(vf->next,vf->priv->fmt, | |||
| MP_IMGTYPE_TEMP, MP_IMGFLAG_ACCEPT_STRIDE, | |||
| mpi->w, mpi->h); | |||
| /* Check to make sure that the filter image and the video stream are the same size. */ | |||
| if (vf->priv->filter->width != mpi->w || vf->priv->filter->height != mpi->h) | |||
| { | |||
| mp_msg(MSGT_VFILTER,MSGL_ERR, "Filter image and video stream are not of the same size. (Filter: %d x %d, Stream: %d x %d)\n", | |||
| vf->priv->filter->width, vf->priv->filter->height, mpi->w, mpi->h); | |||
| return 0; | |||
| } | |||
| switch(dmpi->imgfmt){ | |||
| case IMGFMT_YV12: | |||
| convert_yv12(vf, mpi->planes[0], mpi->stride[0], mpi, mpi->w, mpi->h, | |||
| dmpi->planes[0], dmpi->stride[0], | |||
| mpi->flags & MP_IMGFLAG_DIRECT, vf->priv->filter, 0, | |||
| vf->priv->bounding_rectangle_posx1, vf->priv->bounding_rectangle_posy1, | |||
| vf->priv->bounding_rectangle_posx2, vf->priv->bounding_rectangle_posy2); | |||
| convert_yv12(vf, mpi->planes[1], mpi->stride[1], mpi, mpi->w / 2, mpi->h / 2, | |||
| dmpi->planes[1], dmpi->stride[1], | |||
| mpi->flags & MP_IMGFLAG_DIRECT, vf->priv->half_size_filter, 1, | |||
| vf->priv->bounding_rectangle_half_size_posx1, vf->priv->bounding_rectangle_half_size_posy1, | |||
| vf->priv->bounding_rectangle_half_size_posx2, vf->priv->bounding_rectangle_half_size_posy2); | |||
| convert_yv12(vf, mpi->planes[2], mpi->stride[2], mpi, mpi->w / 2, mpi->h / 2, | |||
| dmpi->planes[2], dmpi->stride[2], | |||
| mpi->flags & MP_IMGFLAG_DIRECT, vf->priv->half_size_filter, 2, | |||
| vf->priv->bounding_rectangle_half_size_posx1, vf->priv->bounding_rectangle_half_size_posy1, | |||
| vf->priv->bounding_rectangle_half_size_posx2, vf->priv->bounding_rectangle_half_size_posy2); | |||
| break; | |||
| default: | |||
| mp_msg(MSGT_VFILTER,MSGL_ERR,"Unhandled format: 0x%X\n",dmpi->imgfmt); | |||
| return 0; | |||
| } | |||
| return vf_next_put_image(vf,dmpi, pts); | |||
| } | |||
| //===========================================================================// | |||
| /** | |||
| * \brief Checks to see if the next filter accepts YV12 images. | |||
| */ | |||
| static int query_format(struct vf_instance *vf, unsigned int fmt) | |||
| { | |||
| if (fmt == IMGFMT_YV12) | |||
| return vf->next->query_format(vf->next, IMGFMT_YV12); | |||
| else | |||
| return 0; | |||
| } | |||
| /** | |||
| * \brief Frees memory that our filter allocated. | |||
| * | |||
| * This is called at exit-time. | |||
| */ | |||
| static void uninit(vf_instance_t *vf) | |||
| { | |||
| /* Destroy our masks and images. */ | |||
| destroy_pgm(vf->priv->filter); | |||
| destroy_pgm(vf->priv->half_size_filter); | |||
| destroy_masks(vf); | |||
| /* Destroy our private structure that had been used to store those masks and images. */ | |||
| free(vf->priv); | |||
| return; | |||
| } | |||
| /** | |||
| * \brief Initializes our filter. | |||
| * | |||
| * \param args The arguments passed in from the command line go here. This | |||
| * filter expects only a single argument telling it where the PGM | |||
| * or PPM file that describes the logo region is. | |||
| * | |||
| * This sets up our instance variables and parses the arguments to the filter. | |||
| */ | |||
| static int vf_open(vf_instance_t *vf, char *args) | |||
| { | |||
| vf->priv = safe_malloc(sizeof(vf_priv_s)); | |||
| vf->uninit = uninit; | |||
| /* Load our filter image. */ | |||
| if (args) | |||
| vf->priv->filter = load_pgm(args); | |||
| else | |||
| { | |||
| mp_msg(MSGT_VFILTER, MSGL_ERR, "[vf]remove_logo usage: remove_logo=/path/to/filter_image_file.pgm\n"); | |||
| free(vf->priv); | |||
| return 0; | |||
| } | |||
| if (vf->priv->filter == NULL) | |||
| { | |||
| /* Error message was displayed by load_pgm(). */ | |||
| free(vf->priv); | |||
| return 0; | |||
| } | |||
| /* Create the scaled down filter image for the chroma planes. */ | |||
| convert_mask_to_strength_mask(vf, vf->priv->filter); | |||
| vf->priv->half_size_filter = generate_half_size_image(vf, vf->priv->filter); | |||
| /* Now that we know how many masks we need (the info is in vf), we can generate the masks. */ | |||
| initialize_masks(vf); | |||
| /* Calculate our bounding rectangles, which determine in what region the logo resides for faster processing. */ | |||
| calculate_bounding_rectangle(&vf->priv->bounding_rectangle_posx1, &vf->priv->bounding_rectangle_posy1, | |||
| &vf->priv->bounding_rectangle_posx2, &vf->priv->bounding_rectangle_posy2, | |||
| vf->priv->filter); | |||
| calculate_bounding_rectangle(&vf->priv->bounding_rectangle_half_size_posx1, | |||
| &vf->priv->bounding_rectangle_half_size_posy1, | |||
| &vf->priv->bounding_rectangle_half_size_posx2, | |||
| &vf->priv->bounding_rectangle_half_size_posy2, | |||
| vf->priv->half_size_filter); | |||
| vf->config=config; | |||
| vf->put_image=put_image; | |||
| vf->query_format=query_format; | |||
| return 1; | |||
| } | |||
| /** | |||
| * \brief Meta data about our filter. | |||
| */ | |||
| const vf_info_t vf_info_remove_logo = { | |||
| "Removes a tv logo based on a mask image.", | |||
| "remove-logo", | |||
| "Robert Edele", | |||
| "", | |||
| vf_open, | |||
| NULL | |||
| }; | |||
| //===========================================================================// | |||
| @@ -0,0 +1,171 @@ | |||
| /* | |||
| * This file is part of MPlayer. | |||
| * | |||
| * MPlayer 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. | |||
| * | |||
| * MPlayer 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 MPlayer; if not, write to the Free Software Foundation, Inc., | |||
| * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | |||
| */ | |||
| #include <stdio.h> | |||
| #include <stdlib.h> | |||
| #include <string.h> | |||
| #include <inttypes.h> | |||
| #include "config.h" | |||
| #include "mp_msg.h" | |||
| #include "img_format.h" | |||
| #include "mp_image.h" | |||
| #include "vf.h" | |||
| //===========================================================================// | |||
| struct vf_priv_s { | |||
| unsigned int fmt; | |||
| int w, h; | |||
| }; | |||
| static unsigned int getfmt(unsigned int outfmt){ | |||
| switch(outfmt){ | |||
| case IMGFMT_RGB12: | |||
| case IMGFMT_RGB15: | |||
| case IMGFMT_RGB16: | |||
| case IMGFMT_RGB24: | |||
| case IMGFMT_RGBA: | |||
| case IMGFMT_ARGB: | |||
| case IMGFMT_BGR12: | |||
| case IMGFMT_BGR15: | |||
| case IMGFMT_BGR16: | |||
| case IMGFMT_BGR24: | |||
| case IMGFMT_BGRA: | |||
| case IMGFMT_ABGR: | |||
| return outfmt; | |||
| } | |||
| return 0; | |||
| } | |||
| static void put_pixel(uint8_t *buf, int x, int y, int stride, int r, int g, int b, int fmt){ | |||
| switch(fmt){ | |||
| case IMGFMT_BGR12: ((uint16_t*)(buf + y*stride))[x]= | |||
| ((r >> 4) << 8) | ((g >> 4) << 4) | (b >> 4); | |||
| break; | |||
| case IMGFMT_RGB12: ((uint16_t*)(buf + y*stride))[x]= | |||
| ((b >> 4) << 8) | ((g >> 4) << 4) | (r >> 4); | |||
| break; | |||
| case IMGFMT_BGR15: ((uint16_t*)(buf + y*stride))[x]= ((r>>3)<<10) | ((g>>3)<<5) | (b>>3); | |||
| break; | |||
| case IMGFMT_RGB15: ((uint16_t*)(buf + y*stride))[x]= ((b>>3)<<10) | ((g>>3)<<5) | (r>>3); | |||
| break; | |||
| case IMGFMT_BGR16: ((uint16_t*)(buf + y*stride))[x]= ((r>>3)<<11) | ((g>>2)<<5) | (b>>3); | |||
| break; | |||
| case IMGFMT_RGB16: ((uint16_t*)(buf + y*stride))[x]= ((b>>3)<<11) | ((g>>2)<<5) | (r>>3); | |||
| break; | |||
| case IMGFMT_RGB24: | |||
| buf[3*x + y*stride + 0]= r; | |||
| buf[3*x + y*stride + 1]= g; | |||
| buf[3*x + y*stride + 2]= b; | |||
| break; | |||
| case IMGFMT_BGR24: | |||
| buf[3*x + y*stride + 0]= b; | |||
| buf[3*x + y*stride + 1]= g; | |||
| buf[3*x + y*stride + 2]= r; | |||
| break; | |||
| case IMGFMT_RGBA: | |||
| buf[4*x + y*stride + 0]= r; | |||
| buf[4*x + y*stride + 1]= g; | |||
| buf[4*x + y*stride + 2]= b; | |||
| break; | |||
| case IMGFMT_BGRA: | |||
| buf[4*x + y*stride + 0]= b; | |||
| buf[4*x + y*stride + 1]= g; | |||
| buf[4*x + y*stride + 2]= r; | |||
| break; | |||
| case IMGFMT_ARGB: | |||
| buf[4*x + y*stride + 1]= r; | |||
| buf[4*x + y*stride + 2]= g; | |||
| buf[4*x + y*stride + 3]= b; | |||
| break; | |||
| case IMGFMT_ABGR: | |||
| buf[4*x + y*stride + 1]= b; | |||
| buf[4*x + y*stride + 2]= g; | |||
| buf[4*x + y*stride + 3]= r; | |||
| break; | |||
| } | |||
| } | |||
| static int config(struct vf_instance *vf, | |||
| int width, int height, int d_width, int d_height, | |||
| unsigned int flags, unsigned int outfmt){ | |||
| if (vf->priv->w > 0) { d_width = width = vf->priv->w; } | |||
| if (vf->priv->h > 0) { d_height = height = vf->priv->h; } | |||
| vf->priv->fmt=getfmt(outfmt); | |||
| mp_msg(MSGT_VFILTER,MSGL_V,"rgb test format:%s\n", vo_format_name(outfmt)); | |||
| return vf_next_config(vf,width,height,d_width,d_height,flags,vf->priv->fmt); | |||
| } | |||
| static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts){ | |||
| mp_image_t *dmpi; | |||
| int x, y; | |||
| int w = vf->priv->w > 0 ? vf->priv->w : mpi->w; | |||
| int h = vf->priv->h > 0 ? vf->priv->h : mpi->h; | |||
| // hope we'll get DR buffer: | |||
| dmpi=vf_get_image(vf->next,vf->priv->fmt, | |||
| MP_IMGTYPE_TEMP, MP_IMGFLAG_ACCEPT_STRIDE, | |||
| w, h); | |||
| for(y=0; y<h; y++){ | |||
| for(x=0; x<w; x++){ | |||
| int c= 256*x/w; | |||
| int r=0,g=0,b=0; | |||
| if(3*y<h) r=c; | |||
| else if(3*y<2*h) g=c; | |||
| else b=c; | |||
| put_pixel(dmpi->planes[0], x, y, dmpi->stride[0], r, g, b, vf->priv->fmt); | |||
| } | |||
| } | |||
| return vf_next_put_image(vf,dmpi, pts); | |||
| } | |||
| //===========================================================================// | |||
| static int query_format(struct vf_instance *vf, unsigned int outfmt){ | |||
| unsigned int fmt=getfmt(outfmt); | |||
| if(!fmt) return 0; | |||
| return vf_next_query_format(vf,fmt) & (~VFCAP_CSP_SUPPORTED_BY_HW); | |||
| } | |||
| static int vf_open(vf_instance_t *vf, char *args){ | |||
| vf->config=config; | |||
| vf->put_image=put_image; | |||
| vf->query_format=query_format; | |||
| vf->priv=malloc(sizeof(struct vf_priv_s)); | |||
| vf->priv->w = vf->priv->h = 0; | |||
| if (args) | |||
| sscanf(args, "%d:%d", &vf->priv->w, &vf->priv->h); | |||
| return 1; | |||
| } | |||
| const vf_info_t vf_info_rgbtest = { | |||
| "rgbtest", | |||
| "rgbtest", | |||
| "Michael Niedermayer", | |||
| "", | |||
| vf_open, | |||
| NULL | |||
| }; | |||
| //===========================================================================// | |||
| @@ -0,0 +1,152 @@ | |||
| /* | |||
| * This file is part of MPlayer. | |||
| * | |||
| * MPlayer 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. | |||
| * | |||
| * MPlayer 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 MPlayer; if not, write to the Free Software Foundation, Inc., | |||
| * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | |||
| */ | |||
| #include <stdio.h> | |||
| #include <stdlib.h> | |||
| #include <string.h> | |||
| #include <inttypes.h> | |||
| #include "config.h" | |||
| #include "mp_msg.h" | |||
| #include "img_format.h" | |||
| #include "mp_image.h" | |||
| #include "vf.h" | |||
| struct vf_priv_s { | |||
| int direction; | |||
| }; | |||
| static void rotate(unsigned char* dst,unsigned char* src,int dststride,int srcstride,int w,int h,int bpp,int dir){ | |||
| int y; | |||
| if(dir&1){ | |||
| src+=srcstride*(w-1); | |||
| srcstride*=-1; | |||
| } | |||
| if(dir&2){ | |||
| dst+=dststride*(h-1); | |||
| dststride*=-1; | |||
| } | |||
| for(y=0;y<h;y++){ | |||
| int x; | |||
| switch(bpp){ | |||
| case 1: | |||
| for(x=0;x<w;x++) dst[x]=src[y+x*srcstride]; | |||
| break; | |||
| case 2: | |||
| for(x=0;x<w;x++) *((short*)(dst+x*2))=*((short*)(src+y*2+x*srcstride)); | |||
| break; | |||
| case 3: | |||
| for(x=0;x<w;x++){ | |||
| dst[x*3+0]=src[0+y*3+x*srcstride]; | |||
| dst[x*3+1]=src[1+y*3+x*srcstride]; | |||
| dst[x*3+2]=src[2+y*3+x*srcstride]; | |||
| } | |||
| break; | |||
| case 4: | |||
| for(x=0;x<w;x++) *((int*)(dst+x*4))=*((int*)(src+y*4+x*srcstride)); | |||
| } | |||
| dst+=dststride; | |||
| } | |||
| } | |||
| //===========================================================================// | |||
| static int config(struct vf_instance *vf, | |||
| int width, int height, int d_width, int d_height, | |||
| unsigned int flags, unsigned int outfmt){ | |||
| if (vf->priv->direction & 4) { | |||
| if (width<height) vf->priv->direction&=3; | |||
| } | |||
| if (vf->priv->direction & 4){ | |||
| vf->put_image=vf_next_put_image; // passthru mode! | |||
| if (vf->next->draw_slice) vf->draw_slice=vf_next_draw_slice; | |||
| /* FIXME: this should be in an other procedure in vf.c; that should always check | |||
| whether the filter after the passthrough one still (not)supports slices */ | |||
| return vf_next_config(vf,width,height,d_width,d_height,flags,outfmt); | |||
| } | |||
| return vf_next_config(vf,height,width,d_height,d_width,flags,outfmt); | |||
| } | |||
| static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts){ | |||
| mp_image_t *dmpi; | |||
| // hope we'll get DR buffer: | |||
| dmpi=vf_get_image(vf->next,mpi->imgfmt, | |||
| MP_IMGTYPE_TEMP, MP_IMGFLAG_ACCEPT_STRIDE, | |||
| mpi->h, mpi->w); | |||
| if(mpi->flags&MP_IMGFLAG_PLANAR){ | |||
| rotate(dmpi->planes[0],mpi->planes[0], | |||
| dmpi->stride[0],mpi->stride[0], | |||
| dmpi->w,dmpi->h,1,vf->priv->direction); | |||
| rotate(dmpi->planes[1],mpi->planes[1], | |||
| dmpi->stride[1],mpi->stride[1], | |||
| dmpi->w>>mpi->chroma_x_shift,dmpi->h>>mpi->chroma_y_shift,1,vf->priv->direction); | |||
| rotate(dmpi->planes[2],mpi->planes[2], | |||
| dmpi->stride[2],mpi->stride[2], | |||
| dmpi->w>>mpi->chroma_x_shift,dmpi->h>>mpi->chroma_y_shift,1,vf->priv->direction); | |||
| } else { | |||
| rotate(dmpi->planes[0],mpi->planes[0], | |||
| dmpi->stride[0],mpi->stride[0], | |||
| dmpi->w,dmpi->h,dmpi->bpp>>3,vf->priv->direction); | |||
| dmpi->planes[1] = mpi->planes[1]; // passthrough rgb8 palette | |||
| } | |||
| return vf_next_put_image(vf,dmpi, pts); | |||
| } | |||
| //===========================================================================// | |||
| static int query_format(struct vf_instance *vf, unsigned int fmt){ | |||
| if(IMGFMT_IS_RGB(fmt) || IMGFMT_IS_BGR(fmt)) return vf_next_query_format(vf, fmt); | |||
| // we can support only symmetric (chroma_x_shift==chroma_y_shift) YUV formats: | |||
| switch(fmt) { | |||
| case IMGFMT_YV12: | |||
| case IMGFMT_I420: | |||
| case IMGFMT_IYUV: | |||
| case IMGFMT_YVU9: | |||
| // case IMGFMT_IF09: | |||
| case IMGFMT_Y8: | |||
| case IMGFMT_Y800: | |||
| case IMGFMT_444P: | |||
| return vf_next_query_format(vf, fmt); | |||
| } | |||
| return 0; | |||
| } | |||
| static int vf_open(vf_instance_t *vf, char *args){ | |||
| vf->config=config; | |||
| vf->put_image=put_image; | |||
| vf->query_format=query_format; | |||
| vf->priv=malloc(sizeof(struct vf_priv_s)); | |||
| vf->priv->direction=args?atoi(args):0; | |||
| return 1; | |||
| } | |||
| const vf_info_t vf_info_rotate = { | |||
| "rotate", | |||
| "rotate", | |||
| "A'rpi", | |||
| "", | |||
| vf_open, | |||
| NULL | |||
| }; | |||
| //===========================================================================// | |||
| @@ -0,0 +1,321 @@ | |||
| /* | |||
| * Copyright (C) 2002 Michael Niedermayer <michaelni@gmx.at> | |||
| * | |||
| * This file is part of MPlayer. | |||
| * | |||
| * MPlayer 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. | |||
| * | |||
| * MPlayer 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 MPlayer; if not, write to the Free Software Foundation, Inc., | |||
| * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | |||
| */ | |||
| #include <stdio.h> | |||
| #include <stdlib.h> | |||
| #include <string.h> | |||
| #include <inttypes.h> | |||
| #include <assert.h> | |||
| #include "config.h" | |||
| #include "mp_msg.h" | |||
| #if HAVE_MALLOC_H | |||
| #include <malloc.h> | |||
| #endif | |||
| #include "libavutil/avutil.h" | |||
| #include "img_format.h" | |||
| #include "mp_image.h" | |||
| #include "vf.h" | |||
| #include "libswscale/swscale.h" | |||
| #include "vf_scale.h" | |||
| //===========================================================================// | |||
| typedef struct FilterParam{ | |||
| float radius; | |||
| float preFilterRadius; | |||
| float strength; | |||
| float quality; | |||
| struct SwsContext *preFilterContext; | |||
| uint8_t *preFilterBuf; | |||
| int preFilterStride; | |||
| int distWidth; | |||
| int distStride; | |||
| int *distCoeff; | |||
| int colorDiffCoeff[512]; | |||
| }FilterParam; | |||
| struct vf_priv_s { | |||
| FilterParam luma; | |||
| FilterParam chroma; | |||
| }; | |||
| /***************************************************************************/ | |||
| //FIXME stupid code duplication | |||
| static void getSubSampleFactors(int *h, int *v, int format){ | |||
| switch(format){ | |||
| case IMGFMT_YV12: | |||
| case IMGFMT_I420: | |||
| *h=1; | |||
| *v=1; | |||
| break; | |||
| case IMGFMT_YVU9: | |||
| *h=2; | |||
| *v=2; | |||
| break; | |||
| case IMGFMT_444P: | |||
| *h=0; | |||
| *v=0; | |||
| break; | |||
| case IMGFMT_422P: | |||
| *h=1; | |||
| *v=0; | |||
| break; | |||
| case IMGFMT_411P: | |||
| *h=2; | |||
| *v=0; | |||
| break; | |||
| } | |||
| } | |||
| static int allocStuff(FilterParam *f, int width, int height){ | |||
| int stride= (width+7)&~7; | |||
| SwsVector *vec; | |||
| SwsFilter swsF; | |||
| int i,x,y; | |||
| f->preFilterBuf= (uint8_t*)memalign(8, stride*height); | |||
| f->preFilterStride= stride; | |||
| vec = sws_getGaussianVec(f->preFilterRadius, f->quality); | |||
| swsF.lumH= swsF.lumV= vec; | |||
| swsF.chrH= swsF.chrV= NULL; | |||
| f->preFilterContext= sws_getContext( | |||
| width, height, PIX_FMT_GRAY8, width, height, PIX_FMT_GRAY8, get_sws_cpuflags()|SWS_POINT, &swsF, NULL, NULL); | |||
| sws_freeVec(vec); | |||
| vec = sws_getGaussianVec(f->strength, 5.0); | |||
| for(i=0; i<512; i++){ | |||
| double d; | |||
| int index= i-256 + vec->length/2; | |||
| if(index<0 || index>=vec->length) d= 0.0; | |||
| else d= vec->coeff[index]; | |||
| f->colorDiffCoeff[i]= (int)(d/vec->coeff[vec->length/2]*(1<<12) + 0.5); | |||
| } | |||
| sws_freeVec(vec); | |||
| vec = sws_getGaussianVec(f->radius, f->quality); | |||
| f->distWidth= vec->length; | |||
| f->distStride= (vec->length+7)&~7; | |||
| f->distCoeff= (int32_t*)memalign(8, f->distWidth*f->distStride*sizeof(int32_t)); | |||
| for(y=0; y<vec->length; y++){ | |||
| for(x=0; x<vec->length; x++){ | |||
| double d= vec->coeff[x] * vec->coeff[y]; | |||
| f->distCoeff[x + y*f->distStride]= (int)(d*(1<<10) + 0.5); | |||
| // if(y==vec->length/2) | |||
| // printf("%6d ", f->distCoeff[x + y*f->distStride]); | |||
| } | |||
| } | |||
| sws_freeVec(vec); | |||
| return 0; | |||
| } | |||
| static int config(struct vf_instance *vf, | |||
| int width, int height, int d_width, int d_height, | |||
| unsigned int flags, unsigned int outfmt){ | |||
| int sw, sh; | |||
| //__asm__ volatile("emms\n\t"); | |||
| allocStuff(&vf->priv->luma, width, height); | |||
| getSubSampleFactors(&sw, &sh, outfmt); | |||
| allocStuff(&vf->priv->chroma, width>>sw, height>>sh); | |||
| return vf_next_config(vf,width,height,d_width,d_height,flags,outfmt); | |||
| } | |||
| static void freeBuffers(FilterParam *f){ | |||
| if(f->preFilterContext) sws_freeContext(f->preFilterContext); | |||
| f->preFilterContext=NULL; | |||
| free(f->preFilterBuf); | |||
| f->preFilterBuf=NULL; | |||
| free(f->distCoeff); | |||
| f->distCoeff=NULL; | |||
| } | |||
| static void uninit(struct vf_instance *vf){ | |||
| if(!vf->priv) return; | |||
| freeBuffers(&vf->priv->luma); | |||
| freeBuffers(&vf->priv->chroma); | |||
| free(vf->priv); | |||
| vf->priv=NULL; | |||
| } | |||
| static inline void blur(uint8_t *dst, uint8_t *src, int w, int h, int dstStride, int srcStride, FilterParam *fp){ | |||
| int x, y; | |||
| FilterParam f= *fp; | |||
| const int radius= f.distWidth/2; | |||
| const uint8_t* const srcArray[MP_MAX_PLANES] = {src}; | |||
| uint8_t *dstArray[MP_MAX_PLANES]= {f.preFilterBuf}; | |||
| int srcStrideArray[MP_MAX_PLANES]= {srcStride}; | |||
| int dstStrideArray[MP_MAX_PLANES]= {f.preFilterStride}; | |||
| // f.preFilterContext->swScale(f.preFilterContext, srcArray, srcStrideArray, 0, h, dstArray, dstStrideArray); | |||
| sws_scale(f.preFilterContext, srcArray, srcStrideArray, 0, h, dstArray, dstStrideArray); | |||
| for(y=0; y<h; y++){ | |||
| for(x=0; x<w; x++){ | |||
| int sum=0; | |||
| int div=0; | |||
| int dy; | |||
| const int preVal= f.preFilterBuf[x + y*f.preFilterStride]; | |||
| #if 0 | |||
| const int srcVal= src[x + y*srcStride]; | |||
| if((x/32)&1){ | |||
| dst[x + y*dstStride]= srcVal; | |||
| if(y%32==0) dst[x + y*dstStride]= 0; | |||
| continue; | |||
| } | |||
| #endif | |||
| if(x >= radius && x < w - radius){ | |||
| for(dy=0; dy<radius*2+1; dy++){ | |||
| int dx; | |||
| int iy= y+dy - radius; | |||
| if (iy<0) iy= -iy; | |||
| else if(iy>=h) iy= h+h-iy-1; | |||
| for(dx=0; dx<radius*2+1; dx++){ | |||
| const int ix= x+dx - radius; | |||
| int factor; | |||
| factor= f.colorDiffCoeff[256+preVal - f.preFilterBuf[ix + iy*f.preFilterStride] ] | |||
| *f.distCoeff[dx + dy*f.distStride]; | |||
| sum+= src[ix + iy*srcStride] *factor; | |||
| div+= factor; | |||
| } | |||
| } | |||
| }else{ | |||
| for(dy=0; dy<radius*2+1; dy++){ | |||
| int dx; | |||
| int iy= y+dy - radius; | |||
| if (iy<0) iy= -iy; | |||
| else if(iy>=h) iy= h+h-iy-1; | |||
| for(dx=0; dx<radius*2+1; dx++){ | |||
| int ix= x+dx - radius; | |||
| int factor; | |||
| if (ix<0) ix= -ix; | |||
| else if(ix>=w) ix= w+w-ix-1; | |||
| factor= f.colorDiffCoeff[256+preVal - f.preFilterBuf[ix + iy*f.preFilterStride] ] | |||
| *f.distCoeff[dx + dy*f.distStride]; | |||
| sum+= src[ix + iy*srcStride] *factor; | |||
| div+= factor; | |||
| } | |||
| } | |||
| } | |||
| dst[x + y*dstStride]= (sum + div/2)/div; | |||
| } | |||
| } | |||
| } | |||
| static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts){ | |||
| int cw= mpi->w >> mpi->chroma_x_shift; | |||
| int ch= mpi->h >> mpi->chroma_y_shift; | |||
| mp_image_t *dmpi=vf_get_image(vf->next,mpi->imgfmt, | |||
| MP_IMGTYPE_TEMP, MP_IMGFLAG_ACCEPT_STRIDE, | |||
| mpi->w,mpi->h); | |||
| assert(mpi->flags&MP_IMGFLAG_PLANAR); | |||
| blur(dmpi->planes[0], mpi->planes[0], mpi->w,mpi->h, dmpi->stride[0], mpi->stride[0], &vf->priv->luma); | |||
| blur(dmpi->planes[1], mpi->planes[1], cw , ch , dmpi->stride[1], mpi->stride[1], &vf->priv->chroma); | |||
| blur(dmpi->planes[2], mpi->planes[2], cw , ch , dmpi->stride[2], mpi->stride[2], &vf->priv->chroma); | |||
| return vf_next_put_image(vf,dmpi, pts); | |||
| } | |||
| //===========================================================================// | |||
| static int query_format(struct vf_instance *vf, unsigned int fmt){ | |||
| switch(fmt) | |||
| { | |||
| case IMGFMT_YV12: | |||
| case IMGFMT_I420: | |||
| case IMGFMT_IYUV: | |||
| case IMGFMT_YVU9: | |||
| case IMGFMT_444P: | |||
| case IMGFMT_422P: | |||
| case IMGFMT_411P: | |||
| return vf_next_query_format(vf, fmt); | |||
| } | |||
| return 0; | |||
| } | |||
| static int vf_open(vf_instance_t *vf, char *args){ | |||
| int e; | |||
| vf->config=config; | |||
| vf->put_image=put_image; | |||
| // vf->get_image=get_image; | |||
| vf->query_format=query_format; | |||
| vf->uninit=uninit; | |||
| vf->priv=malloc(sizeof(struct vf_priv_s)); | |||
| memset(vf->priv, 0, sizeof(struct vf_priv_s)); | |||
| if(args==NULL) return 0; | |||
| e=sscanf(args, "%f:%f:%f:%f:%f:%f", | |||
| &vf->priv->luma.radius, | |||
| &vf->priv->luma.preFilterRadius, | |||
| &vf->priv->luma.strength, | |||
| &vf->priv->chroma.radius, | |||
| &vf->priv->chroma.preFilterRadius, | |||
| &vf->priv->chroma.strength | |||
| ); | |||
| vf->priv->luma.quality = vf->priv->chroma.quality= 3.0; | |||
| if(e==3){ | |||
| vf->priv->chroma.radius= vf->priv->luma.radius; | |||
| vf->priv->chroma.preFilterRadius = vf->priv->luma.preFilterRadius; | |||
| vf->priv->chroma.strength= vf->priv->luma.strength; | |||
| }else if(e!=6) | |||
| return 0; | |||
| // if(vf->priv->luma.radius < 0) return 0; | |||
| // if(vf->priv->chroma.radius < 0) return 0; | |||
| return 1; | |||
| } | |||
| const vf_info_t vf_info_sab = { | |||
| "shape adaptive blur", | |||
| "sab", | |||
| "Michael Niedermayer", | |||
| "", | |||
| vf_open, | |||
| NULL | |||
| }; | |||
| //===========================================================================// | |||
| @@ -0,0 +1,35 @@ | |||
| /* | |||
| * This file is part of MPlayer. | |||
| * | |||
| * MPlayer 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. | |||
| * | |||
| * MPlayer 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 MPlayer; if not, write to the Free Software Foundation, Inc., | |||
| * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | |||
| */ | |||
| #ifndef MPLAYER_VF_SCALE_H | |||
| #define MPLAYER_VF_SCALE_H | |||
| extern int sws_chr_vshift; | |||
| extern int sws_chr_hshift; | |||
| extern float sws_chr_gblur; | |||
| extern float sws_lum_gblur; | |||
| extern float sws_chr_sharpen; | |||
| extern float sws_lum_sharpen; | |||
| extern int sws_flags; | |||
| int get_sws_cpuflags(void); | |||
| struct SwsContext *sws_getContextFromCmdLine(int srcW, int srcH, int srcFormat, int dstW, int dstH, int dstFormat); | |||
| #endif /* MPLAYER_VF_SCALE_H */ | |||
| @@ -0,0 +1,322 @@ | |||
| /* | |||
| * This file is part of MPlayer. | |||
| * | |||
| * MPlayer 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. | |||
| * | |||
| * MPlayer 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 MPlayer; if not, write to the Free Software Foundation, Inc., | |||
| * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | |||
| */ | |||
| #include "config.h" | |||
| #include <stdio.h> | |||
| #include <stdlib.h> | |||
| #if HAVE_MALLOC_H | |||
| #include <malloc.h> | |||
| #endif | |||
| #include <string.h> | |||
| #include <inttypes.h> | |||
| #include <sys/types.h> | |||
| #include <sys/stat.h> | |||
| #include <unistd.h> | |||
| #include "mp_msg.h" | |||
| #include "img_format.h" | |||
| #include "mp_image.h" | |||
| #include "vf.h" | |||
| #include "vf_scale.h" | |||
| #include "libswscale/swscale.h" | |||
| #include "libavcodec/avcodec.h" | |||
| struct vf_priv_s { | |||
| int frameno; | |||
| char fname[102]; | |||
| /// shot stores current screenshot mode: | |||
| /// 0: don't take screenshots | |||
| /// 1: take single screenshot, reset to 0 afterwards | |||
| /// 2: take screenshots of each frame | |||
| int shot, store_slices; | |||
| int dw, dh, stride; | |||
| uint8_t *buffer; | |||
| struct SwsContext *ctx; | |||
| AVCodecContext *avctx; | |||
| uint8_t *outbuffer; | |||
| int outbuffer_size; | |||
| }; | |||
| //===========================================================================// | |||
| static int config(struct vf_instance *vf, | |||
| int width, int height, int d_width, int d_height, | |||
| unsigned int flags, unsigned int outfmt) | |||
| { | |||
| vf->priv->ctx=sws_getContextFromCmdLine(width, height, outfmt, | |||
| d_width, d_height, IMGFMT_RGB24); | |||
| vf->priv->outbuffer_size = d_width * d_height * 3 * 2; | |||
| vf->priv->outbuffer = realloc(vf->priv->outbuffer, vf->priv->outbuffer_size); | |||
| vf->priv->avctx->width = d_width; | |||
| vf->priv->avctx->height = d_height; | |||
| vf->priv->avctx->pix_fmt = PIX_FMT_RGB24; | |||
| vf->priv->avctx->compression_level = 0; | |||
| vf->priv->dw = d_width; | |||
| vf->priv->dh = d_height; | |||
| vf->priv->stride = (3*vf->priv->dw+15)&~15; | |||
| free(vf->priv->buffer); // probably reconfigured | |||
| vf->priv->buffer = NULL; | |||
| return vf_next_config(vf,width,height,d_width,d_height,flags,outfmt); | |||
| } | |||
| static void write_png(struct vf_priv_s *priv) | |||
| { | |||
| char *fname = priv->fname; | |||
| FILE * fp; | |||
| AVFrame pic; | |||
| int size; | |||
| fp = fopen (fname, "wb"); | |||
| if (fp == NULL) { | |||
| mp_msg(MSGT_VFILTER,MSGL_ERR,"\nPNG Error opening %s for writing!\n", fname); | |||
| return; | |||
| } | |||
| pic.data[0] = priv->buffer; | |||
| pic.linesize[0] = priv->stride; | |||
| size = avcodec_encode_video(priv->avctx, priv->outbuffer, priv->outbuffer_size, &pic); | |||
| if (size > 0) | |||
| fwrite(priv->outbuffer, size, 1, fp); | |||
| fclose (fp); | |||
| } | |||
| static int fexists(char *fname) | |||
| { | |||
| struct stat dummy; | |||
| if (stat(fname, &dummy) == 0) return 1; | |||
| else return 0; | |||
| } | |||
| static void gen_fname(struct vf_priv_s* priv) | |||
| { | |||
| do { | |||
| snprintf (priv->fname, 100, "shot%04d.png", ++priv->frameno); | |||
| } while (fexists(priv->fname) && priv->frameno < 100000); | |||
| if (fexists(priv->fname)) { | |||
| priv->fname[0] = '\0'; | |||
| return; | |||
| } | |||
| mp_msg(MSGT_VFILTER,MSGL_INFO,"*** screenshot '%s' ***\n",priv->fname); | |||
| } | |||
| static void scale_image(struct vf_priv_s* priv, mp_image_t *mpi) | |||
| { | |||
| uint8_t *dst[MP_MAX_PLANES] = {NULL}; | |||
| int dst_stride[MP_MAX_PLANES] = {0}; | |||
| dst_stride[0] = priv->stride; | |||
| if (!priv->buffer) | |||
| priv->buffer = av_malloc(dst_stride[0]*priv->dh); | |||
| dst[0] = priv->buffer; | |||
| sws_scale(priv->ctx, mpi->planes, mpi->stride, 0, priv->dh, dst, dst_stride); | |||
| } | |||
| static void start_slice(struct vf_instance *vf, mp_image_t *mpi) | |||
| { | |||
| vf->dmpi=vf_get_image(vf->next,mpi->imgfmt, | |||
| mpi->type, mpi->flags, mpi->width, mpi->height); | |||
| if (vf->priv->shot) { | |||
| vf->priv->store_slices = 1; | |||
| if (!vf->priv->buffer) | |||
| vf->priv->buffer = av_malloc(vf->priv->stride*vf->priv->dh); | |||
| } | |||
| } | |||
| static void draw_slice(struct vf_instance *vf, unsigned char** src, | |||
| int* stride, int w,int h, int x, int y) | |||
| { | |||
| if (vf->priv->store_slices) { | |||
| uint8_t *dst[MP_MAX_PLANES] = {NULL}; | |||
| int dst_stride[MP_MAX_PLANES] = {0}; | |||
| dst_stride[0] = vf->priv->stride; | |||
| dst[0] = vf->priv->buffer; | |||
| sws_scale(vf->priv->ctx, src, stride, y, h, dst, dst_stride); | |||
| } | |||
| vf_next_draw_slice(vf,src,stride,w,h,x,y); | |||
| } | |||
| static void get_image(struct vf_instance *vf, mp_image_t *mpi) | |||
| { | |||
| // FIXME: should vf.c really call get_image when using slices?? | |||
| if (mpi->flags & MP_IMGFLAG_DRAW_CALLBACK) | |||
| return; | |||
| vf->dmpi= vf_get_image(vf->next, mpi->imgfmt, | |||
| mpi->type, mpi->flags/* | MP_IMGFLAG_READABLE*/, mpi->width, mpi->height); | |||
| mpi->planes[0]=vf->dmpi->planes[0]; | |||
| mpi->stride[0]=vf->dmpi->stride[0]; | |||
| if(mpi->flags&MP_IMGFLAG_PLANAR){ | |||
| mpi->planes[1]=vf->dmpi->planes[1]; | |||
| mpi->planes[2]=vf->dmpi->planes[2]; | |||
| mpi->stride[1]=vf->dmpi->stride[1]; | |||
| mpi->stride[2]=vf->dmpi->stride[2]; | |||
| } | |||
| mpi->width=vf->dmpi->width; | |||
| mpi->flags|=MP_IMGFLAG_DIRECT; | |||
| mpi->priv=(void*)vf->dmpi; | |||
| } | |||
| static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts) | |||
| { | |||
| mp_image_t *dmpi = (mp_image_t *)mpi->priv; | |||
| if (mpi->flags & MP_IMGFLAG_DRAW_CALLBACK) | |||
| dmpi = vf->dmpi; | |||
| else | |||
| if(!(mpi->flags&MP_IMGFLAG_DIRECT)){ | |||
| dmpi=vf_get_image(vf->next,mpi->imgfmt, | |||
| MP_IMGTYPE_EXPORT, 0, | |||
| mpi->width, mpi->height); | |||
| vf_clone_mpi_attributes(dmpi, mpi); | |||
| dmpi->planes[0]=mpi->planes[0]; | |||
| dmpi->planes[1]=mpi->planes[1]; | |||
| dmpi->planes[2]=mpi->planes[2]; | |||
| dmpi->stride[0]=mpi->stride[0]; | |||
| dmpi->stride[1]=mpi->stride[1]; | |||
| dmpi->stride[2]=mpi->stride[2]; | |||
| dmpi->width=mpi->width; | |||
| dmpi->height=mpi->height; | |||
| } | |||
| if(vf->priv->shot) { | |||
| if (vf->priv->shot==1) | |||
| vf->priv->shot=0; | |||
| gen_fname(vf->priv); | |||
| if (vf->priv->fname[0]) { | |||
| if (!vf->priv->store_slices) | |||
| scale_image(vf->priv, dmpi); | |||
| write_png(vf->priv); | |||
| } | |||
| vf->priv->store_slices = 0; | |||
| } | |||
| return vf_next_put_image(vf, dmpi, pts); | |||
| } | |||
| static int control (vf_instance_t *vf, int request, void *data) | |||
| { | |||
| /** data contains an integer argument | |||
| * 0: take screenshot with the next frame | |||
| * 1: take screenshots with each frame until the same command is given once again | |||
| **/ | |||
| if(request==VFCTRL_SCREENSHOT) { | |||
| if (data && *(int*)data) { // repeated screenshot mode | |||
| if (vf->priv->shot==2) | |||
| vf->priv->shot=0; | |||
| else | |||
| vf->priv->shot=2; | |||
| } else { // single screenshot | |||
| if (!vf->priv->shot) | |||
| vf->priv->shot=1; | |||
| } | |||
| return CONTROL_TRUE; | |||
| } | |||
| return vf_next_control (vf, request, data); | |||
| } | |||
| //===========================================================================// | |||
| static int query_format(struct vf_instance *vf, unsigned int fmt) | |||
| { | |||
| switch(fmt){ | |||
| case IMGFMT_YV12: | |||
| case IMGFMT_I420: | |||
| case IMGFMT_IYUV: | |||
| case IMGFMT_UYVY: | |||
| case IMGFMT_YUY2: | |||
| case IMGFMT_BGR32: | |||
| case IMGFMT_BGR24: | |||
| case IMGFMT_BGR16: | |||
| case IMGFMT_BGR15: | |||
| case IMGFMT_BGR12: | |||
| case IMGFMT_RGB32: | |||
| case IMGFMT_RGB24: | |||
| case IMGFMT_Y800: | |||
| case IMGFMT_Y8: | |||
| case IMGFMT_YVU9: | |||
| case IMGFMT_IF09: | |||
| case IMGFMT_444P: | |||
| case IMGFMT_422P: | |||
| case IMGFMT_411P: | |||
| return vf_next_query_format(vf, fmt); | |||
| } | |||
| return 0; | |||
| } | |||
| static void uninit(vf_instance_t *vf) | |||
| { | |||
| avcodec_close(vf->priv->avctx); | |||
| av_freep(&vf->priv->avctx); | |||
| if(vf->priv->ctx) sws_freeContext(vf->priv->ctx); | |||
| av_free(vf->priv->buffer); | |||
| free(vf->priv->outbuffer); | |||
| free(vf->priv); | |||
| } | |||
| static int vf_open(vf_instance_t *vf, char *args) | |||
| { | |||
| vf->config=config; | |||
| vf->control=control; | |||
| vf->put_image=put_image; | |||
| vf->query_format=query_format; | |||
| vf->start_slice=start_slice; | |||
| vf->draw_slice=draw_slice; | |||
| vf->get_image=get_image; | |||
| vf->uninit=uninit; | |||
| vf->priv=malloc(sizeof(struct vf_priv_s)); | |||
| vf->priv->frameno=0; | |||
| vf->priv->shot=0; | |||
| vf->priv->store_slices=0; | |||
| vf->priv->buffer=0; | |||
| vf->priv->outbuffer=0; | |||
| vf->priv->ctx=0; | |||
| vf->priv->avctx = avcodec_alloc_context(); | |||
| avcodec_register_all(); | |||
| if (avcodec_open(vf->priv->avctx, avcodec_find_encoder(CODEC_ID_PNG))) { | |||
| mp_msg(MSGT_VFILTER, MSGL_FATAL, "Could not open libavcodec PNG encoder\n"); | |||
| return 0; | |||
| } | |||
| return 1; | |||
| } | |||
| const vf_info_t vf_info_screenshot = { | |||
| "screenshot to file", | |||
| "screenshot", | |||
| "A'rpi, Jindrich Makovicka", | |||
| "", | |||
| vf_open, | |||
| NULL | |||
| }; | |||
| //===========================================================================// | |||
| @@ -0,0 +1,262 @@ | |||
| /* | |||
| * Copyright (C) 2002 Michael Niedermayer <michaelni@gmx.at> | |||
| * | |||
| * This file is part of MPlayer. | |||
| * | |||
| * MPlayer 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. | |||
| * | |||
| * MPlayer 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 MPlayer; if not, write to the Free Software Foundation, Inc., | |||
| * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | |||
| */ | |||
| #include <stdio.h> | |||
| #include <stdlib.h> | |||
| #include <string.h> | |||
| #include <inttypes.h> | |||
| #include <assert.h> | |||
| #include "mp_msg.h" | |||
| #include "libavutil/avutil.h" | |||
| #include "img_format.h" | |||
| #include "mp_image.h" | |||
| #include "vf.h" | |||
| #include "libswscale/swscale.h" | |||
| #include "vf_scale.h" | |||
| //===========================================================================// | |||
| typedef struct FilterParam{ | |||
| float radius; | |||
| float strength; | |||
| int threshold; | |||
| float quality; | |||
| struct SwsContext *filterContext; | |||
| }FilterParam; | |||
| struct vf_priv_s { | |||
| FilterParam luma; | |||
| FilterParam chroma; | |||
| }; | |||
| /***************************************************************************/ | |||
| //FIXME stupid code duplication | |||
| static void getSubSampleFactors(int *h, int *v, int format){ | |||
| switch(format){ | |||
| case IMGFMT_YV12: | |||
| case IMGFMT_I420: | |||
| *h=1; | |||
| *v=1; | |||
| break; | |||
| case IMGFMT_YVU9: | |||
| *h=2; | |||
| *v=2; | |||
| break; | |||
| case IMGFMT_444P: | |||
| *h=0; | |||
| *v=0; | |||
| break; | |||
| case IMGFMT_422P: | |||
| *h=1; | |||
| *v=0; | |||
| break; | |||
| case IMGFMT_411P: | |||
| *h=2; | |||
| *v=0; | |||
| break; | |||
| } | |||
| } | |||
| static int allocStuff(FilterParam *f, int width, int height){ | |||
| SwsVector *vec; | |||
| SwsFilter swsF; | |||
| vec = sws_getGaussianVec(f->radius, f->quality); | |||
| sws_scaleVec(vec, f->strength); | |||
| vec->coeff[vec->length/2]+= 1.0 - f->strength; | |||
| swsF.lumH= swsF.lumV= vec; | |||
| swsF.chrH= swsF.chrV= NULL; | |||
| f->filterContext= sws_getContext( | |||
| width, height, PIX_FMT_GRAY8, width, height, PIX_FMT_GRAY8, SWS_BICUBIC | get_sws_cpuflags(), &swsF, NULL, NULL); | |||
| sws_freeVec(vec); | |||
| return 0; | |||
| } | |||
| static int config(struct vf_instance *vf, | |||
| int width, int height, int d_width, int d_height, | |||
| unsigned int flags, unsigned int outfmt){ | |||
| int sw, sh; | |||
| allocStuff(&vf->priv->luma, width, height); | |||
| getSubSampleFactors(&sw, &sh, outfmt); | |||
| allocStuff(&vf->priv->chroma, width>>sw, height>>sh); | |||
| return vf_next_config(vf,width,height,d_width,d_height,flags,outfmt); | |||
| } | |||
| static void freeBuffers(FilterParam *f){ | |||
| if(f->filterContext) sws_freeContext(f->filterContext); | |||
| f->filterContext=NULL; | |||
| } | |||
| static void uninit(struct vf_instance *vf){ | |||
| if(!vf->priv) return; | |||
| freeBuffers(&vf->priv->luma); | |||
| freeBuffers(&vf->priv->chroma); | |||
| free(vf->priv); | |||
| vf->priv=NULL; | |||
| } | |||
| static inline void blur(uint8_t *dst, uint8_t *src, int w, int h, int dstStride, int srcStride, FilterParam *fp){ | |||
| int x, y; | |||
| FilterParam f= *fp; | |||
| const uint8_t* const srcArray[MP_MAX_PLANES] = {src}; | |||
| uint8_t *dstArray[MP_MAX_PLANES]= {dst}; | |||
| int srcStrideArray[MP_MAX_PLANES]= {srcStride}; | |||
| int dstStrideArray[MP_MAX_PLANES]= {dstStride}; | |||
| sws_scale(f.filterContext, srcArray, srcStrideArray, 0, h, dstArray, dstStrideArray); | |||
| if(f.threshold > 0){ | |||
| for(y=0; y<h; y++){ | |||
| for(x=0; x<w; x++){ | |||
| const int orig= src[x + y*srcStride]; | |||
| const int filtered= dst[x + y*dstStride]; | |||
| const int diff= orig - filtered; | |||
| if(diff > 0){ | |||
| if(diff > 2*f.threshold){ | |||
| dst[x + y*dstStride]= orig; | |||
| }else if(diff > f.threshold){ | |||
| dst[x + y*dstStride]= filtered + diff - f.threshold; | |||
| } | |||
| }else{ | |||
| if(-diff > 2*f.threshold){ | |||
| dst[x + y*dstStride]= orig; | |||
| }else if(-diff > f.threshold){ | |||
| dst[x + y*dstStride]= filtered + diff + f.threshold; | |||
| } | |||
| } | |||
| } | |||
| } | |||
| }else if(f.threshold < 0){ | |||
| for(y=0; y<h; y++){ | |||
| for(x=0; x<w; x++){ | |||
| const int orig= src[x + y*srcStride]; | |||
| const int filtered= dst[x + y*dstStride]; | |||
| const int diff= orig - filtered; | |||
| if(diff > 0){ | |||
| if(diff > -2*f.threshold){ | |||
| }else if(diff > -f.threshold){ | |||
| dst[x + y*dstStride]= orig - diff - f.threshold; | |||
| }else | |||
| dst[x + y*dstStride]= orig; | |||
| }else{ | |||
| if(diff < 2*f.threshold){ | |||
| }else if(diff < f.threshold){ | |||
| dst[x + y*dstStride]= orig - diff + f.threshold; | |||
| }else | |||
| dst[x + y*dstStride]= orig; | |||
| } | |||
| } | |||
| } | |||
| } | |||
| } | |||
| static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts){ | |||
| int cw= mpi->w >> mpi->chroma_x_shift; | |||
| int ch= mpi->h >> mpi->chroma_y_shift; | |||
| FilterParam *f= &vf->priv; | |||
| mp_image_t *dmpi=vf_get_image(vf->next,mpi->imgfmt, | |||
| MP_IMGTYPE_TEMP, MP_IMGFLAG_ACCEPT_STRIDE| | |||
| (f->threshold) ? MP_IMGFLAG_READABLE : 0, | |||
| mpi->w,mpi->h); | |||
| assert(mpi->flags&MP_IMGFLAG_PLANAR); | |||
| blur(dmpi->planes[0], mpi->planes[0], mpi->w,mpi->h, dmpi->stride[0], mpi->stride[0], &vf->priv->luma); | |||
| blur(dmpi->planes[1], mpi->planes[1], cw , ch , dmpi->stride[1], mpi->stride[1], &vf->priv->chroma); | |||
| blur(dmpi->planes[2], mpi->planes[2], cw , ch , dmpi->stride[2], mpi->stride[2], &vf->priv->chroma); | |||
| return vf_next_put_image(vf,dmpi, pts); | |||
| } | |||
| //===========================================================================// | |||
| static int query_format(struct vf_instance *vf, unsigned int fmt){ | |||
| switch(fmt) | |||
| { | |||
| case IMGFMT_YV12: | |||
| case IMGFMT_I420: | |||
| case IMGFMT_IYUV: | |||
| case IMGFMT_YVU9: | |||
| case IMGFMT_444P: | |||
| case IMGFMT_422P: | |||
| case IMGFMT_411P: | |||
| return vf_next_query_format(vf, fmt); | |||
| } | |||
| return 0; | |||
| } | |||
| static int vf_open(vf_instance_t *vf, char *args){ | |||
| int e; | |||
| vf->config=config; | |||
| vf->put_image=put_image; | |||
| // vf->get_image=get_image; | |||
| vf->query_format=query_format; | |||
| vf->uninit=uninit; | |||
| vf->priv=malloc(sizeof(struct vf_priv_s)); | |||
| memset(vf->priv, 0, sizeof(struct vf_priv_s)); | |||
| if(args==NULL) return 0; | |||
| e=sscanf(args, "%f:%f:%d:%f:%f:%d", | |||
| &vf->priv->luma.radius, | |||
| &vf->priv->luma.strength, | |||
| &vf->priv->luma.threshold, | |||
| &vf->priv->chroma.radius, | |||
| &vf->priv->chroma.strength, | |||
| &vf->priv->chroma.threshold | |||
| ); | |||
| vf->priv->luma.quality = vf->priv->chroma.quality= 3.0; | |||
| if(e==3){ | |||
| vf->priv->chroma.radius= vf->priv->luma.radius; | |||
| vf->priv->chroma.strength= vf->priv->luma.strength; | |||
| vf->priv->chroma.threshold = vf->priv->luma.threshold; | |||
| }else if(e!=6) | |||
| return 0; | |||
| return 1; | |||
| } | |||
| const vf_info_t vf_info_smartblur = { | |||
| "smart blur", | |||
| "smartblur", | |||
| "Michael Niedermayer", | |||
| "", | |||
| vf_open, | |||
| NULL | |||
| }; | |||
| //===========================================================================// | |||
| @@ -0,0 +1,164 @@ | |||
| /* | |||
| * This file is part of MPlayer. | |||
| * | |||
| * MPlayer 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. | |||
| * | |||
| * MPlayer 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 MPlayer; if not, write to the Free Software Foundation, Inc., | |||
| * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | |||
| */ | |||
| #include <stdio.h> | |||
| #include <stdlib.h> | |||
| #include <string.h> | |||
| #include "config.h" | |||
| #include "mp_msg.h" | |||
| #include "img_format.h" | |||
| #include "mp_image.h" | |||
| #include "vf.h" | |||
| #include "libvo/fastmemcpy.h" | |||
| struct vf_priv_s { | |||
| int state; | |||
| long long in; | |||
| long long out; | |||
| }; | |||
| static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts) | |||
| { | |||
| mp_image_t *dmpi; | |||
| int ret = 0; | |||
| int flags = mpi->fields; | |||
| int state = vf->priv->state; | |||
| dmpi = vf_get_image(vf->next, mpi->imgfmt, | |||
| MP_IMGTYPE_STATIC, MP_IMGFLAG_ACCEPT_STRIDE | | |||
| MP_IMGFLAG_PRESERVE, mpi->width, mpi->height); | |||
| vf->priv->in++; | |||
| if ((state == 0 && | |||
| !(flags & MP_IMGFIELD_TOP_FIRST)) || | |||
| (state == 1 && | |||
| flags & MP_IMGFIELD_TOP_FIRST)) { | |||
| mp_msg(MSGT_VFILTER, MSGL_WARN, | |||
| "softpulldown: Unexpected field flags: state=%d top_field_first=%d repeat_first_field=%d\n", | |||
| state, | |||
| (flags & MP_IMGFIELD_TOP_FIRST) != 0, | |||
| (flags & MP_IMGFIELD_REPEAT_FIRST) != 0); | |||
| state ^= 1; | |||
| } | |||
| if (state == 0) { | |||
| ret = vf_next_put_image(vf, mpi, MP_NOPTS_VALUE); | |||
| vf->priv->out++; | |||
| if (flags & MP_IMGFIELD_REPEAT_FIRST) { | |||
| my_memcpy_pic(dmpi->planes[0], | |||
| mpi->planes[0], mpi->w, mpi->h/2, | |||
| dmpi->stride[0]*2, mpi->stride[0]*2); | |||
| if (mpi->flags & MP_IMGFLAG_PLANAR) { | |||
| my_memcpy_pic(dmpi->planes[1], | |||
| mpi->planes[1], | |||
| mpi->chroma_width, | |||
| mpi->chroma_height/2, | |||
| dmpi->stride[1]*2, | |||
| mpi->stride[1]*2); | |||
| my_memcpy_pic(dmpi->planes[2], | |||
| mpi->planes[2], | |||
| mpi->chroma_width, | |||
| mpi->chroma_height/2, | |||
| dmpi->stride[2]*2, | |||
| mpi->stride[2]*2); | |||
| } | |||
| state=1; | |||
| } | |||
| } else { | |||
| my_memcpy_pic(dmpi->planes[0]+dmpi->stride[0], | |||
| mpi->planes[0]+mpi->stride[0], mpi->w, mpi->h/2, | |||
| dmpi->stride[0]*2, mpi->stride[0]*2); | |||
| if (mpi->flags & MP_IMGFLAG_PLANAR) { | |||
| my_memcpy_pic(dmpi->planes[1]+dmpi->stride[1], | |||
| mpi->planes[1]+mpi->stride[1], | |||
| mpi->chroma_width, mpi->chroma_height/2, | |||
| dmpi->stride[1]*2, mpi->stride[1]*2); | |||
| my_memcpy_pic(dmpi->planes[2]+dmpi->stride[2], | |||
| mpi->planes[2]+mpi->stride[2], | |||
| mpi->chroma_width, mpi->chroma_height/2, | |||
| dmpi->stride[2]*2, mpi->stride[2]*2); | |||
| } | |||
| ret = vf_next_put_image(vf, dmpi, MP_NOPTS_VALUE); | |||
| vf->priv->out++; | |||
| if (flags & MP_IMGFIELD_REPEAT_FIRST) { | |||
| ret |= vf_next_put_image(vf, mpi, MP_NOPTS_VALUE); | |||
| vf->priv->out++; | |||
| state=0; | |||
| } else { | |||
| my_memcpy_pic(dmpi->planes[0], | |||
| mpi->planes[0], mpi->w, mpi->h/2, | |||
| dmpi->stride[0]*2, mpi->stride[0]*2); | |||
| if (mpi->flags & MP_IMGFLAG_PLANAR) { | |||
| my_memcpy_pic(dmpi->planes[1], | |||
| mpi->planes[1], | |||
| mpi->chroma_width, | |||
| mpi->chroma_height/2, | |||
| dmpi->stride[1]*2, | |||
| mpi->stride[1]*2); | |||
| my_memcpy_pic(dmpi->planes[2], | |||
| mpi->planes[2], | |||
| mpi->chroma_width, | |||
| mpi->chroma_height/2, | |||
| dmpi->stride[2]*2, | |||
| mpi->stride[2]*2); | |||
| } | |||
| } | |||
| } | |||
| vf->priv->state = state; | |||
| return ret; | |||
| } | |||
| static int config(struct vf_instance *vf, | |||
| int width, int height, int d_width, int d_height, | |||
| unsigned int flags, unsigned int outfmt) | |||
| { | |||
| return vf_next_config(vf,width,height,d_width,d_height,flags,outfmt); | |||
| } | |||
| static void uninit(struct vf_instance *vf) | |||
| { | |||
| mp_msg(MSGT_VFILTER, MSGL_INFO, "softpulldown: %lld frames in, %lld frames out\n", vf->priv->in, vf->priv->out); | |||
| free(vf->priv); | |||
| } | |||
| static int vf_open(vf_instance_t *vf, char *args) | |||
| { | |||
| struct vf_priv_s *p; | |||
| vf->config = config; | |||
| vf->put_image = put_image; | |||
| vf->uninit = uninit; | |||
| vf->default_reqs = VFCAP_ACCEPT_STRIDE; | |||
| vf->priv = p = calloc(1, sizeof(struct vf_priv_s)); | |||
| vf->priv->state = 0; | |||
| return 1; | |||
| } | |||
| const vf_info_t vf_info_softpulldown = { | |||
| "mpeg2 soft 3:2 pulldown", | |||
| "softpulldown", | |||
| "Tobias Diedrich <ranma+mplayer@tdiedrich.de>", | |||
| "", | |||
| vf_open, | |||
| NULL | |||
| }; | |||
| @@ -0,0 +1,102 @@ | |||
| /* | |||
| * This file is part of MPlayer. | |||
| * | |||
| * MPlayer 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. | |||
| * | |||
| * MPlayer 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 MPlayer; if not, write to the Free Software Foundation, Inc., | |||
| * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | |||
| */ | |||
| #include <stdio.h> | |||
| #include <stdlib.h> | |||
| #include <string.h> | |||
| #include "config.h" | |||
| #include "mp_msg.h" | |||
| #include "img_format.h" | |||
| #include "mp_image.h" | |||
| #include "vf.h" | |||
| struct vf_priv_s { | |||
| int skipflag; | |||
| }; | |||
| static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts) | |||
| { | |||
| mp_image_t *dmpi; | |||
| if (vf->priv->skipflag) | |||
| return vf->priv->skipflag = 0; | |||
| dmpi = vf_get_image(vf->next, mpi->imgfmt, | |||
| MP_IMGTYPE_EXPORT, 0, mpi->width, mpi->height); | |||
| vf_clone_mpi_attributes(dmpi, mpi); | |||
| dmpi->planes[0] = mpi->planes[0]; | |||
| dmpi->stride[0] = mpi->stride[0]; | |||
| if (dmpi->flags&MP_IMGFLAG_PLANAR) { | |||
| dmpi->planes[1] = mpi->planes[1]; | |||
| dmpi->stride[1] = mpi->stride[1]; | |||
| dmpi->planes[2] = mpi->planes[2]; | |||
| dmpi->stride[2] = mpi->stride[2]; | |||
| } | |||
| return vf_next_put_image(vf, dmpi, pts); | |||
| } | |||
| static int control(struct vf_instance *vf, int request, void* data) | |||
| { | |||
| switch (request) { | |||
| case VFCTRL_SKIP_NEXT_FRAME: | |||
| vf->priv->skipflag = 1; | |||
| return CONTROL_TRUE; | |||
| } | |||
| return vf_next_control(vf, request, data); | |||
| } | |||
| #if 0 | |||
| static int query_format(struct vf_instance *vf, unsigned int fmt) | |||
| { | |||
| /* FIXME - figure out which other formats work */ | |||
| switch (fmt) { | |||
| case IMGFMT_YV12: | |||
| case IMGFMT_IYUV: | |||
| case IMGFMT_I420: | |||
| return vf_next_query_format(vf, fmt); | |||
| } | |||
| return 0; | |||
| } | |||
| #endif | |||
| static void uninit(struct vf_instance *vf) | |||
| { | |||
| free(vf->priv); | |||
| } | |||
| static int vf_open(vf_instance_t *vf, char *args) | |||
| { | |||
| vf->put_image = put_image; | |||
| vf->control = control; | |||
| vf->uninit = uninit; | |||
| vf->priv = calloc(1, sizeof(struct vf_priv_s)); | |||
| return 1; | |||
| } | |||
| const vf_info_t vf_info_softskip = { | |||
| "soft (post-filter) frame skipping for encoding", | |||
| "softskip", | |||
| "Rich Felker", | |||
| "", | |||
| vf_open, | |||
| NULL | |||
| }; | |||
| @@ -0,0 +1,620 @@ | |||
| /* | |||
| * Copyright (C) 2003 Michael Niedermayer <michaelni@gmx.at> | |||
| * | |||
| * This file is part of MPlayer. | |||
| * | |||
| * MPlayer 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. | |||
| * | |||
| * MPlayer 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 MPlayer; if not, write to the Free Software Foundation, Inc., | |||
| * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | |||
| */ | |||
| /* | |||
| * This implementation is based on an algorithm described in | |||
| * "Aria Nosratinia Embedded Post-Processing for | |||
| * Enhancement of Compressed Images (1999)" | |||
| * (http://citeseer.nj.nec.com/nosratinia99embedded.html) | |||
| */ | |||
| #include <stdio.h> | |||
| #include <stdlib.h> | |||
| #include <string.h> | |||
| #include <inttypes.h> | |||
| #include <math.h> | |||
| #include "config.h" | |||
| #include "mp_msg.h" | |||
| #include "cpudetect.h" | |||
| #include "libavutil/internal.h" | |||
| #include "libavutil/intreadwrite.h" | |||
| #include "libavcodec/avcodec.h" | |||
| #include "libavcodec/dsputil.h" | |||
| #undef fprintf | |||
| #undef free | |||
| #undef malloc | |||
| #include "img_format.h" | |||
| #include "mp_image.h" | |||
| #include "vf.h" | |||
| #include "vd_ffmpeg.h" | |||
| #include "libvo/fastmemcpy.h" | |||
| #define XMIN(a,b) ((a) < (b) ? (a) : (b)) | |||
| //===========================================================================// | |||
| static const uint8_t __attribute__((aligned(8))) dither[8][8]={ | |||
| { 0, 48, 12, 60, 3, 51, 15, 63, }, | |||
| { 32, 16, 44, 28, 35, 19, 47, 31, }, | |||
| { 8, 56, 4, 52, 11, 59, 7, 55, }, | |||
| { 40, 24, 36, 20, 43, 27, 39, 23, }, | |||
| { 2, 50, 14, 62, 1, 49, 13, 61, }, | |||
| { 34, 18, 46, 30, 33, 17, 45, 29, }, | |||
| { 10, 58, 6, 54, 9, 57, 5, 53, }, | |||
| { 42, 26, 38, 22, 41, 25, 37, 21, }, | |||
| }; | |||
| static const uint8_t offset[127][2]= { | |||
| {0,0}, | |||
| {0,0}, {4,4}, | |||
| {0,0}, {2,2}, {6,4}, {4,6}, | |||
| {0,0}, {5,1}, {2,2}, {7,3}, {4,4}, {1,5}, {6,6}, {3,7}, | |||
| {0,0}, {4,0}, {1,1}, {5,1}, {3,2}, {7,2}, {2,3}, {6,3}, | |||
| {0,4}, {4,4}, {1,5}, {5,5}, {3,6}, {7,6}, {2,7}, {6,7}, | |||
| {0,0}, {0,2}, {0,4}, {0,6}, {1,1}, {1,3}, {1,5}, {1,7}, | |||
| {2,0}, {2,2}, {2,4}, {2,6}, {3,1}, {3,3}, {3,5}, {3,7}, | |||
| {4,0}, {4,2}, {4,4}, {4,6}, {5,1}, {5,3}, {5,5}, {5,7}, | |||
| {6,0}, {6,2}, {6,4}, {6,6}, {7,1}, {7,3}, {7,5}, {7,7}, | |||
| {0,0}, {4,4}, {0,4}, {4,0}, {2,2}, {6,6}, {2,6}, {6,2}, | |||
| {0,2}, {4,6}, {0,6}, {4,2}, {2,0}, {6,4}, {2,4}, {6,0}, | |||
| {1,1}, {5,5}, {1,5}, {5,1}, {3,3}, {7,7}, {3,7}, {7,3}, | |||
| {1,3}, {5,7}, {1,7}, {5,3}, {3,1}, {7,5}, {3,5}, {7,1}, | |||
| {0,1}, {4,5}, {0,5}, {4,1}, {2,3}, {6,7}, {2,7}, {6,3}, | |||
| {0,3}, {4,7}, {0,7}, {4,3}, {2,1}, {6,5}, {2,5}, {6,1}, | |||
| {1,0}, {5,4}, {1,4}, {5,0}, {3,2}, {7,6}, {3,6}, {7,2}, | |||
| {1,2}, {5,6}, {1,6}, {5,2}, {3,0}, {7,4}, {3,4}, {7,0}, | |||
| }; | |||
| struct vf_priv_s { | |||
| int log2_count; | |||
| int qp; | |||
| int mode; | |||
| int mpeg2; | |||
| int temp_stride; | |||
| uint8_t *src; | |||
| int16_t *temp; | |||
| AVCodecContext *avctx; | |||
| DSPContext dsp; | |||
| char *non_b_qp; | |||
| }; | |||
| #define SHIFT 22 | |||
| static void hardthresh_c(DCTELEM dst[64], DCTELEM src[64], int qp, uint8_t *permutation){ | |||
| int i; | |||
| int bias= 0; //FIXME | |||
| unsigned int threshold1, threshold2; | |||
| threshold1= qp*((1<<4) - bias) - 1; | |||
| threshold2= (threshold1<<1); | |||
| memset(dst, 0, 64*sizeof(DCTELEM)); | |||
| dst[0]= (src[0] + 4)>>3; | |||
| for(i=1; i<64; i++){ | |||
| int level= src[i]; | |||
| if(((unsigned)(level+threshold1))>threshold2){ | |||
| const int j= permutation[i]; | |||
| dst[j]= (level + 4)>>3; | |||
| } | |||
| } | |||
| } | |||
| static void softthresh_c(DCTELEM dst[64], DCTELEM src[64], int qp, uint8_t *permutation){ | |||
| int i; | |||
| int bias= 0; //FIXME | |||
| unsigned int threshold1, threshold2; | |||
| threshold1= qp*((1<<4) - bias) - 1; | |||
| threshold2= (threshold1<<1); | |||
| memset(dst, 0, 64*sizeof(DCTELEM)); | |||
| dst[0]= (src[0] + 4)>>3; | |||
| for(i=1; i<64; i++){ | |||
| int level= src[i]; | |||
| if(((unsigned)(level+threshold1))>threshold2){ | |||
| const int j= permutation[i]; | |||
| if(level>0) | |||
| dst[j]= (level - threshold1 + 4)>>3; | |||
| else | |||
| dst[j]= (level + threshold1 + 4)>>3; | |||
| } | |||
| } | |||
| } | |||
| #if HAVE_MMX | |||
| static void hardthresh_mmx(DCTELEM dst[64], DCTELEM src[64], int qp, uint8_t *permutation){ | |||
| int bias= 0; //FIXME | |||
| unsigned int threshold1; | |||
| threshold1= qp*((1<<4) - bias) - 1; | |||
| __asm__ volatile( | |||
| #define REQUANT_CORE(dst0, dst1, dst2, dst3, src0, src1, src2, src3) \ | |||
| "movq " #src0 ", %%mm0 \n\t"\ | |||
| "movq " #src1 ", %%mm1 \n\t"\ | |||
| "movq " #src2 ", %%mm2 \n\t"\ | |||
| "movq " #src3 ", %%mm3 \n\t"\ | |||
| "psubw %%mm4, %%mm0 \n\t"\ | |||
| "psubw %%mm4, %%mm1 \n\t"\ | |||
| "psubw %%mm4, %%mm2 \n\t"\ | |||
| "psubw %%mm4, %%mm3 \n\t"\ | |||
| "paddusw %%mm5, %%mm0 \n\t"\ | |||
| "paddusw %%mm5, %%mm1 \n\t"\ | |||
| "paddusw %%mm5, %%mm2 \n\t"\ | |||
| "paddusw %%mm5, %%mm3 \n\t"\ | |||
| "paddw %%mm6, %%mm0 \n\t"\ | |||
| "paddw %%mm6, %%mm1 \n\t"\ | |||
| "paddw %%mm6, %%mm2 \n\t"\ | |||
| "paddw %%mm6, %%mm3 \n\t"\ | |||
| "psubusw %%mm6, %%mm0 \n\t"\ | |||
| "psubusw %%mm6, %%mm1 \n\t"\ | |||
| "psubusw %%mm6, %%mm2 \n\t"\ | |||
| "psubusw %%mm6, %%mm3 \n\t"\ | |||
| "psraw $3, %%mm0 \n\t"\ | |||
| "psraw $3, %%mm1 \n\t"\ | |||
| "psraw $3, %%mm2 \n\t"\ | |||
| "psraw $3, %%mm3 \n\t"\ | |||
| \ | |||
| "movq %%mm0, %%mm7 \n\t"\ | |||
| "punpcklwd %%mm2, %%mm0 \n\t" /*A*/\ | |||
| "punpckhwd %%mm2, %%mm7 \n\t" /*C*/\ | |||
| "movq %%mm1, %%mm2 \n\t"\ | |||
| "punpcklwd %%mm3, %%mm1 \n\t" /*B*/\ | |||
| "punpckhwd %%mm3, %%mm2 \n\t" /*D*/\ | |||
| "movq %%mm0, %%mm3 \n\t"\ | |||
| "punpcklwd %%mm1, %%mm0 \n\t" /*A*/\ | |||
| "punpckhwd %%mm7, %%mm3 \n\t" /*C*/\ | |||
| "punpcklwd %%mm2, %%mm7 \n\t" /*B*/\ | |||
| "punpckhwd %%mm2, %%mm1 \n\t" /*D*/\ | |||
| \ | |||
| "movq %%mm0, " #dst0 " \n\t"\ | |||
| "movq %%mm7, " #dst1 " \n\t"\ | |||
| "movq %%mm3, " #dst2 " \n\t"\ | |||
| "movq %%mm1, " #dst3 " \n\t" | |||
| "movd %2, %%mm4 \n\t" | |||
| "movd %3, %%mm5 \n\t" | |||
| "movd %4, %%mm6 \n\t" | |||
| "packssdw %%mm4, %%mm4 \n\t" | |||
| "packssdw %%mm5, %%mm5 \n\t" | |||
| "packssdw %%mm6, %%mm6 \n\t" | |||
| "packssdw %%mm4, %%mm4 \n\t" | |||
| "packssdw %%mm5, %%mm5 \n\t" | |||
| "packssdw %%mm6, %%mm6 \n\t" | |||
| REQUANT_CORE( (%1), 8(%1), 16(%1), 24(%1), (%0), 8(%0), 64(%0), 72(%0)) | |||
| REQUANT_CORE(32(%1), 40(%1), 48(%1), 56(%1),16(%0),24(%0), 48(%0), 56(%0)) | |||
| REQUANT_CORE(64(%1), 72(%1), 80(%1), 88(%1),32(%0),40(%0), 96(%0),104(%0)) | |||
| REQUANT_CORE(96(%1),104(%1),112(%1),120(%1),80(%0),88(%0),112(%0),120(%0)) | |||
| : : "r" (src), "r" (dst), "g" (threshold1+1), "g" (threshold1+5), "g" (threshold1-4) //FIXME maybe more accurate then needed? | |||
| ); | |||
| dst[0]= (src[0] + 4)>>3; | |||
| } | |||
| static void softthresh_mmx(DCTELEM dst[64], DCTELEM src[64], int qp, uint8_t *permutation){ | |||
| int bias= 0; //FIXME | |||
| unsigned int threshold1; | |||
| threshold1= qp*((1<<4) - bias) - 1; | |||
| __asm__ volatile( | |||
| #undef REQUANT_CORE | |||
| #define REQUANT_CORE(dst0, dst1, dst2, dst3, src0, src1, src2, src3) \ | |||
| "movq " #src0 ", %%mm0 \n\t"\ | |||
| "movq " #src1 ", %%mm1 \n\t"\ | |||
| "pxor %%mm6, %%mm6 \n\t"\ | |||
| "pxor %%mm7, %%mm7 \n\t"\ | |||
| "pcmpgtw %%mm0, %%mm6 \n\t"\ | |||
| "pcmpgtw %%mm1, %%mm7 \n\t"\ | |||
| "pxor %%mm6, %%mm0 \n\t"\ | |||
| "pxor %%mm7, %%mm1 \n\t"\ | |||
| "psubusw %%mm4, %%mm0 \n\t"\ | |||
| "psubusw %%mm4, %%mm1 \n\t"\ | |||
| "pxor %%mm6, %%mm0 \n\t"\ | |||
| "pxor %%mm7, %%mm1 \n\t"\ | |||
| "movq " #src2 ", %%mm2 \n\t"\ | |||
| "movq " #src3 ", %%mm3 \n\t"\ | |||
| "pxor %%mm6, %%mm6 \n\t"\ | |||
| "pxor %%mm7, %%mm7 \n\t"\ | |||
| "pcmpgtw %%mm2, %%mm6 \n\t"\ | |||
| "pcmpgtw %%mm3, %%mm7 \n\t"\ | |||
| "pxor %%mm6, %%mm2 \n\t"\ | |||
| "pxor %%mm7, %%mm3 \n\t"\ | |||
| "psubusw %%mm4, %%mm2 \n\t"\ | |||
| "psubusw %%mm4, %%mm3 \n\t"\ | |||
| "pxor %%mm6, %%mm2 \n\t"\ | |||
| "pxor %%mm7, %%mm3 \n\t"\ | |||
| \ | |||
| "paddsw %%mm5, %%mm0 \n\t"\ | |||
| "paddsw %%mm5, %%mm1 \n\t"\ | |||
| "paddsw %%mm5, %%mm2 \n\t"\ | |||
| "paddsw %%mm5, %%mm3 \n\t"\ | |||
| "psraw $3, %%mm0 \n\t"\ | |||
| "psraw $3, %%mm1 \n\t"\ | |||
| "psraw $3, %%mm2 \n\t"\ | |||
| "psraw $3, %%mm3 \n\t"\ | |||
| \ | |||
| "movq %%mm0, %%mm7 \n\t"\ | |||
| "punpcklwd %%mm2, %%mm0 \n\t" /*A*/\ | |||
| "punpckhwd %%mm2, %%mm7 \n\t" /*C*/\ | |||
| "movq %%mm1, %%mm2 \n\t"\ | |||
| "punpcklwd %%mm3, %%mm1 \n\t" /*B*/\ | |||
| "punpckhwd %%mm3, %%mm2 \n\t" /*D*/\ | |||
| "movq %%mm0, %%mm3 \n\t"\ | |||
| "punpcklwd %%mm1, %%mm0 \n\t" /*A*/\ | |||
| "punpckhwd %%mm7, %%mm3 \n\t" /*C*/\ | |||
| "punpcklwd %%mm2, %%mm7 \n\t" /*B*/\ | |||
| "punpckhwd %%mm2, %%mm1 \n\t" /*D*/\ | |||
| \ | |||
| "movq %%mm0, " #dst0 " \n\t"\ | |||
| "movq %%mm7, " #dst1 " \n\t"\ | |||
| "movq %%mm3, " #dst2 " \n\t"\ | |||
| "movq %%mm1, " #dst3 " \n\t" | |||
| "movd %2, %%mm4 \n\t" | |||
| "movd %3, %%mm5 \n\t" | |||
| "packssdw %%mm4, %%mm4 \n\t" | |||
| "packssdw %%mm5, %%mm5 \n\t" | |||
| "packssdw %%mm4, %%mm4 \n\t" | |||
| "packssdw %%mm5, %%mm5 \n\t" | |||
| REQUANT_CORE( (%1), 8(%1), 16(%1), 24(%1), (%0), 8(%0), 64(%0), 72(%0)) | |||
| REQUANT_CORE(32(%1), 40(%1), 48(%1), 56(%1),16(%0),24(%0), 48(%0), 56(%0)) | |||
| REQUANT_CORE(64(%1), 72(%1), 80(%1), 88(%1),32(%0),40(%0), 96(%0),104(%0)) | |||
| REQUANT_CORE(96(%1),104(%1),112(%1),120(%1),80(%0),88(%0),112(%0),120(%0)) | |||
| : : "r" (src), "r" (dst), "g" (threshold1), "rm" (4) //FIXME maybe more accurate then needed? | |||
| ); | |||
| dst[0]= (src[0] + 4)>>3; | |||
| } | |||
| #endif | |||
| static inline void add_block(int16_t *dst, int stride, DCTELEM block[64]){ | |||
| int y; | |||
| for(y=0; y<8; y++){ | |||
| *(uint32_t*)&dst[0 + y*stride]+= *(uint32_t*)&block[0 + y*8]; | |||
| *(uint32_t*)&dst[2 + y*stride]+= *(uint32_t*)&block[2 + y*8]; | |||
| *(uint32_t*)&dst[4 + y*stride]+= *(uint32_t*)&block[4 + y*8]; | |||
| *(uint32_t*)&dst[6 + y*stride]+= *(uint32_t*)&block[6 + y*8]; | |||
| } | |||
| } | |||
| static void store_slice_c(uint8_t *dst, int16_t *src, int dst_stride, int src_stride, int width, int height, int log2_scale){ | |||
| int y, x; | |||
| #define STORE(pos) \ | |||
| temp= ((src[x + y*src_stride + pos]<<log2_scale) + d[pos])>>6;\ | |||
| if(temp & 0x100) temp= ~(temp>>31);\ | |||
| dst[x + y*dst_stride + pos]= temp; | |||
| for(y=0; y<height; y++){ | |||
| const uint8_t *d= dither[y]; | |||
| for(x=0; x<width; x+=8){ | |||
| int temp; | |||
| STORE(0); | |||
| STORE(1); | |||
| STORE(2); | |||
| STORE(3); | |||
| STORE(4); | |||
| STORE(5); | |||
| STORE(6); | |||
| STORE(7); | |||
| } | |||
| } | |||
| } | |||
| #if HAVE_MMX | |||
| static void store_slice_mmx(uint8_t *dst, int16_t *src, int dst_stride, int src_stride, int width, int height, int log2_scale){ | |||
| int y; | |||
| for(y=0; y<height; y++){ | |||
| uint8_t *dst1= dst; | |||
| int16_t *src1= src; | |||
| __asm__ volatile( | |||
| "movq (%3), %%mm3 \n\t" | |||
| "movq (%3), %%mm4 \n\t" | |||
| "movd %4, %%mm2 \n\t" | |||
| "pxor %%mm0, %%mm0 \n\t" | |||
| "punpcklbw %%mm0, %%mm3 \n\t" | |||
| "punpckhbw %%mm0, %%mm4 \n\t" | |||
| "psraw %%mm2, %%mm3 \n\t" | |||
| "psraw %%mm2, %%mm4 \n\t" | |||
| "movd %5, %%mm2 \n\t" | |||
| "1: \n\t" | |||
| "movq (%0), %%mm0 \n\t" | |||
| "movq 8(%0), %%mm1 \n\t" | |||
| "paddw %%mm3, %%mm0 \n\t" | |||
| "paddw %%mm4, %%mm1 \n\t" | |||
| "psraw %%mm2, %%mm0 \n\t" | |||
| "psraw %%mm2, %%mm1 \n\t" | |||
| "packuswb %%mm1, %%mm0 \n\t" | |||
| "movq %%mm0, (%1) \n\t" | |||
| "add $16, %0 \n\t" | |||
| "add $8, %1 \n\t" | |||
| "cmp %2, %1 \n\t" | |||
| " jb 1b \n\t" | |||
| : "+r" (src1), "+r"(dst1) | |||
| : "r"(dst + width), "r"(dither[y]), "g"(log2_scale), "g"(6-log2_scale) | |||
| ); | |||
| src += src_stride; | |||
| dst += dst_stride; | |||
| } | |||
| // if(width != mmxw) | |||
| // store_slice_c(dst + mmxw, src + mmxw, dst_stride, src_stride, width - mmxw, log2_scale); | |||
| } | |||
| #endif | |||
| static void (*store_slice)(uint8_t *dst, int16_t *src, int dst_stride, int src_stride, int width, int height, int log2_scale)= store_slice_c; | |||
| static void (*requantize)(DCTELEM dst[64], DCTELEM src[64], int qp, uint8_t *permutation)= hardthresh_c; | |||
| static void filter(struct vf_priv_s *p, uint8_t *dst, uint8_t *src, int dst_stride, int src_stride, int width, int height, uint8_t *qp_store, int qp_stride, int is_luma){ | |||
| int x, y, i; | |||
| const int count= 1<<p->log2_count; | |||
| const int stride= is_luma ? p->temp_stride : ((width+16+15)&(~15)); | |||
| uint64_t __attribute__((aligned(16))) block_align[32]; | |||
| DCTELEM *block = (DCTELEM *)block_align; | |||
| DCTELEM *block2= (DCTELEM *)(block_align+16); | |||
| if (!src || !dst) return; // HACK avoid crash for Y8 colourspace | |||
| for(y=0; y<height; y++){ | |||
| int index= 8 + 8*stride + y*stride; | |||
| fast_memcpy(p->src + index, src + y*src_stride, width); | |||
| for(x=0; x<8; x++){ | |||
| p->src[index - x - 1]= p->src[index + x ]; | |||
| p->src[index + width + x ]= p->src[index + width - x - 1]; | |||
| } | |||
| } | |||
| for(y=0; y<8; y++){ | |||
| fast_memcpy(p->src + ( 7-y)*stride, p->src + ( y+8)*stride, stride); | |||
| fast_memcpy(p->src + (height+8+y)*stride, p->src + (height-y+7)*stride, stride); | |||
| } | |||
| //FIXME (try edge emu) | |||
| for(y=0; y<height+8; y+=8){ | |||
| memset(p->temp + (8+y)*stride, 0, 8*stride*sizeof(int16_t)); | |||
| for(x=0; x<width+8; x+=8){ | |||
| const int qps= 3 + is_luma; | |||
| int qp; | |||
| if(p->qp) | |||
| qp= p->qp; | |||
| else{ | |||
| qp= qp_store[ (XMIN(x, width-1)>>qps) + (XMIN(y, height-1)>>qps) * qp_stride]; | |||
| qp = FFMAX(1, norm_qscale(qp, p->mpeg2)); | |||
| } | |||
| for(i=0; i<count; i++){ | |||
| const int x1= x + offset[i+count-1][0]; | |||
| const int y1= y + offset[i+count-1][1]; | |||
| const int index= x1 + y1*stride; | |||
| p->dsp.get_pixels(block, p->src + index, stride); | |||
| p->dsp.fdct(block); | |||
| requantize(block2, block, qp, p->dsp.idct_permutation); | |||
| p->dsp.idct(block2); | |||
| add_block(p->temp + index, stride, block2); | |||
| } | |||
| } | |||
| if(y) | |||
| store_slice(dst + (y-8)*dst_stride, p->temp + 8 + y*stride, dst_stride, stride, width, XMIN(8, height+8-y), 6-p->log2_count); | |||
| } | |||
| #if 0 | |||
| for(y=0; y<height; y++){ | |||
| for(x=0; x<width; x++){ | |||
| if((((x>>6) ^ (y>>6)) & 1) == 0) | |||
| dst[x + y*dst_stride]= p->src[8 + 8*stride + x + y*stride]; | |||
| if((x&63) == 0 || (y&63)==0) | |||
| dst[x + y*dst_stride] += 128; | |||
| } | |||
| } | |||
| #endif | |||
| //FIXME reorder for better caching | |||
| } | |||
| static int config(struct vf_instance *vf, | |||
| int width, int height, int d_width, int d_height, | |||
| unsigned int flags, unsigned int outfmt){ | |||
| int h= (height+16+15)&(~15); | |||
| vf->priv->temp_stride= (width+16+15)&(~15); | |||
| vf->priv->temp= malloc(vf->priv->temp_stride*h*sizeof(int16_t)); | |||
| vf->priv->src = malloc(vf->priv->temp_stride*h*sizeof(uint8_t)); | |||
| return vf_next_config(vf,width,height,d_width,d_height,flags,outfmt); | |||
| } | |||
| static void get_image(struct vf_instance *vf, mp_image_t *mpi){ | |||
| if(mpi->flags&MP_IMGFLAG_PRESERVE) return; // don't change | |||
| // ok, we can do pp in-place (or pp disabled): | |||
| vf->dmpi=vf_get_image(vf->next,mpi->imgfmt, | |||
| mpi->type, mpi->flags | MP_IMGFLAG_READABLE, mpi->width, mpi->height); | |||
| mpi->planes[0]=vf->dmpi->planes[0]; | |||
| mpi->stride[0]=vf->dmpi->stride[0]; | |||
| mpi->width=vf->dmpi->width; | |||
| if(mpi->flags&MP_IMGFLAG_PLANAR){ | |||
| mpi->planes[1]=vf->dmpi->planes[1]; | |||
| mpi->planes[2]=vf->dmpi->planes[2]; | |||
| mpi->stride[1]=vf->dmpi->stride[1]; | |||
| mpi->stride[2]=vf->dmpi->stride[2]; | |||
| } | |||
| mpi->flags|=MP_IMGFLAG_DIRECT; | |||
| } | |||
| static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts){ | |||
| mp_image_t *dmpi; | |||
| if(!(mpi->flags&MP_IMGFLAG_DIRECT)){ | |||
| // no DR, so get a new image! hope we'll get DR buffer: | |||
| dmpi=vf_get_image(vf->next,mpi->imgfmt, | |||
| MP_IMGTYPE_TEMP, | |||
| MP_IMGFLAG_ACCEPT_STRIDE|MP_IMGFLAG_PREFER_ALIGNED_STRIDE, | |||
| mpi->width,mpi->height); | |||
| vf_clone_mpi_attributes(dmpi, mpi); | |||
| }else{ | |||
| dmpi=vf->dmpi; | |||
| } | |||
| vf->priv->mpeg2= mpi->qscale_type; | |||
| if(mpi->pict_type != 3 && mpi->qscale && !vf->priv->qp){ | |||
| int w = mpi->qstride; | |||
| int h = (mpi->h + 15) >> 4; | |||
| if (!w) { | |||
| w = (mpi->w + 15) >> 4; | |||
| h = 1; | |||
| } | |||
| if(!vf->priv->non_b_qp) | |||
| vf->priv->non_b_qp= malloc(w*h); | |||
| fast_memcpy(vf->priv->non_b_qp, mpi->qscale, w*h); | |||
| } | |||
| if(vf->priv->log2_count || !(mpi->flags&MP_IMGFLAG_DIRECT)){ | |||
| char *qp_tab= vf->priv->non_b_qp; | |||
| if((vf->priv->mode&4) || !qp_tab) | |||
| qp_tab= mpi->qscale; | |||
| if(qp_tab || vf->priv->qp){ | |||
| filter(vf->priv, dmpi->planes[0], mpi->planes[0], dmpi->stride[0], mpi->stride[0], mpi->w, mpi->h, qp_tab, mpi->qstride, 1); | |||
| filter(vf->priv, dmpi->planes[1], mpi->planes[1], dmpi->stride[1], mpi->stride[1], mpi->w>>mpi->chroma_x_shift, mpi->h>>mpi->chroma_y_shift, qp_tab, mpi->qstride, 0); | |||
| filter(vf->priv, dmpi->planes[2], mpi->planes[2], dmpi->stride[2], mpi->stride[2], mpi->w>>mpi->chroma_x_shift, mpi->h>>mpi->chroma_y_shift, qp_tab, mpi->qstride, 0); | |||
| }else{ | |||
| memcpy_pic(dmpi->planes[0], mpi->planes[0], mpi->w, mpi->h, dmpi->stride[0], mpi->stride[0]); | |||
| memcpy_pic(dmpi->planes[1], mpi->planes[1], mpi->w>>mpi->chroma_x_shift, mpi->h>>mpi->chroma_y_shift, dmpi->stride[1], mpi->stride[1]); | |||
| memcpy_pic(dmpi->planes[2], mpi->planes[2], mpi->w>>mpi->chroma_x_shift, mpi->h>>mpi->chroma_y_shift, dmpi->stride[2], mpi->stride[2]); | |||
| } | |||
| } | |||
| #if HAVE_MMX | |||
| if(gCpuCaps.hasMMX) __asm__ volatile ("emms\n\t"); | |||
| #endif | |||
| #if HAVE_MMX2 | |||
| if(gCpuCaps.hasMMX2) __asm__ volatile ("sfence\n\t"); | |||
| #endif | |||
| return vf_next_put_image(vf,dmpi, pts); | |||
| } | |||
| static void uninit(struct vf_instance *vf){ | |||
| if(!vf->priv) return; | |||
| free(vf->priv->temp); | |||
| vf->priv->temp= NULL; | |||
| free(vf->priv->src); | |||
| vf->priv->src= NULL; | |||
| free(vf->priv->avctx); | |||
| vf->priv->avctx= NULL; | |||
| free(vf->priv->non_b_qp); | |||
| vf->priv->non_b_qp= NULL; | |||
| free(vf->priv); | |||
| vf->priv=NULL; | |||
| } | |||
| //===========================================================================// | |||
| static int query_format(struct vf_instance *vf, unsigned int fmt){ | |||
| switch(fmt){ | |||
| case IMGFMT_YVU9: | |||
| case IMGFMT_IF09: | |||
| case IMGFMT_YV12: | |||
| case IMGFMT_I420: | |||
| case IMGFMT_IYUV: | |||
| case IMGFMT_CLPL: | |||
| case IMGFMT_Y800: | |||
| case IMGFMT_Y8: | |||
| case IMGFMT_444P: | |||
| case IMGFMT_422P: | |||
| case IMGFMT_411P: | |||
| return vf_next_query_format(vf,fmt); | |||
| } | |||
| return 0; | |||
| } | |||
| static int control(struct vf_instance *vf, int request, void* data){ | |||
| switch(request){ | |||
| case VFCTRL_QUERY_MAX_PP_LEVEL: | |||
| return 6; | |||
| case VFCTRL_SET_PP_LEVEL: | |||
| vf->priv->log2_count= *((unsigned int*)data); | |||
| return CONTROL_TRUE; | |||
| } | |||
| return vf_next_control(vf,request,data); | |||
| } | |||
| static int vf_open(vf_instance_t *vf, char *args){ | |||
| int log2c=-1; | |||
| vf->config=config; | |||
| vf->put_image=put_image; | |||
| vf->get_image=get_image; | |||
| vf->query_format=query_format; | |||
| vf->uninit=uninit; | |||
| vf->control= control; | |||
| vf->priv=malloc(sizeof(struct vf_priv_s)); | |||
| memset(vf->priv, 0, sizeof(struct vf_priv_s)); | |||
| init_avcodec(); | |||
| vf->priv->avctx= avcodec_alloc_context(); | |||
| dsputil_init(&vf->priv->dsp, vf->priv->avctx); | |||
| vf->priv->log2_count= 3; | |||
| if (args) sscanf(args, "%d:%d:%d", &log2c, &vf->priv->qp, &vf->priv->mode); | |||
| if( log2c >=0 && log2c <=6 ) | |||
| vf->priv->log2_count = log2c; | |||
| if(vf->priv->qp < 0) | |||
| vf->priv->qp = 0; | |||
| switch(vf->priv->mode&3){ | |||
| default: | |||
| case 0: requantize= hardthresh_c; break; | |||
| case 1: requantize= softthresh_c; break; | |||
| } | |||
| #if HAVE_MMX | |||
| if(gCpuCaps.hasMMX){ | |||
| store_slice= store_slice_mmx; | |||
| switch(vf->priv->mode&3){ | |||
| case 0: requantize= hardthresh_mmx; break; | |||
| case 1: requantize= softthresh_mmx; break; | |||
| } | |||
| } | |||
| #endif | |||
| return 1; | |||
| } | |||
| const vf_info_t vf_info_spp = { | |||
| "simple postprocess", | |||
| "spp", | |||
| "Michael Niedermayer", | |||
| "", | |||
| vf_open, | |||
| NULL | |||
| }; | |||
| @@ -0,0 +1,106 @@ | |||
| /* | |||
| * Copyright (C) 2002 Michael Niedermayer <michaelni@gmx.at> | |||
| * | |||
| * This file is part of MPlayer. | |||
| * | |||
| * MPlayer 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. | |||
| * | |||
| * MPlayer 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 MPlayer; if not, write to the Free Software Foundation, Inc., | |||
| * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | |||
| */ | |||
| #include <stdio.h> | |||
| #include <stdlib.h> | |||
| #include <string.h> | |||
| #include <inttypes.h> | |||
| #include <assert.h> | |||
| #include "mp_msg.h" | |||
| #include "img_format.h" | |||
| #include "mp_image.h" | |||
| #include "vf.h" | |||
| //===========================================================================// | |||
| static void get_image(struct vf_instance *vf, mp_image_t *mpi){ | |||
| mp_image_t *dmpi= vf_get_image(vf->next, mpi->imgfmt, | |||
| mpi->type, mpi->flags, mpi->w, mpi->h); | |||
| mpi->planes[0]=dmpi->planes[0]; | |||
| mpi->planes[1]=dmpi->planes[2]; | |||
| mpi->planes[2]=dmpi->planes[1]; | |||
| mpi->stride[0]=dmpi->stride[0]; | |||
| mpi->stride[1]=dmpi->stride[2]; | |||
| mpi->stride[2]=dmpi->stride[1]; | |||
| mpi->width=dmpi->width; | |||
| mpi->flags|=MP_IMGFLAG_DIRECT; | |||
| mpi->priv=(void*)dmpi; | |||
| } | |||
| static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts){ | |||
| mp_image_t *dmpi; | |||
| if(mpi->flags&MP_IMGFLAG_DIRECT){ | |||
| dmpi=(mp_image_t*)mpi->priv; | |||
| } else { | |||
| dmpi=vf_get_image(vf->next, mpi->imgfmt, MP_IMGTYPE_EXPORT, 0, mpi->w, mpi->h); | |||
| assert(mpi->flags&MP_IMGFLAG_PLANAR); | |||
| dmpi->planes[0]=mpi->planes[0]; | |||
| dmpi->planes[1]=mpi->planes[2]; | |||
| dmpi->planes[2]=mpi->planes[1]; | |||
| dmpi->stride[0]=mpi->stride[0]; | |||
| dmpi->stride[1]=mpi->stride[2]; | |||
| dmpi->stride[2]=mpi->stride[1]; | |||
| dmpi->width=mpi->width; | |||
| } | |||
| vf_clone_mpi_attributes(dmpi, mpi); | |||
| return vf_next_put_image(vf,dmpi, pts); | |||
| } | |||
| //===========================================================================// | |||
| static int query_format(struct vf_instance *vf, unsigned int fmt){ | |||
| switch(fmt) | |||
| { | |||
| case IMGFMT_YV12: | |||
| case IMGFMT_I420: | |||
| case IMGFMT_IYUV: | |||
| case IMGFMT_YVU9: | |||
| case IMGFMT_444P: | |||
| case IMGFMT_422P: | |||
| case IMGFMT_411P: | |||
| return vf_next_query_format(vf, fmt); | |||
| } | |||
| return 0; | |||
| } | |||
| static int vf_open(vf_instance_t *vf, char *args){ | |||
| vf->put_image=put_image; | |||
| vf->get_image=get_image; | |||
| vf->query_format=query_format; | |||
| return 1; | |||
| } | |||
| const vf_info_t vf_info_swapuv = { | |||
| "UV swapper", | |||
| "swapuv", | |||
| "Michael Niedermayer", | |||
| "", | |||
| vf_open, | |||
| NULL | |||
| }; | |||
| //===========================================================================// | |||
| @@ -0,0 +1,155 @@ | |||
| /* | |||
| * This file is part of MPlayer. | |||
| * | |||
| * MPlayer 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. | |||
| * | |||
| * MPlayer 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 MPlayer; if not, write to the Free Software Foundation, Inc., | |||
| * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | |||
| */ | |||
| #include <stdio.h> | |||
| #include <stdlib.h> | |||
| #include <string.h> | |||
| #include "config.h" | |||
| #include "mp_msg.h" | |||
| #include "img_format.h" | |||
| #include "mp_image.h" | |||
| #include "vf.h" | |||
| #include "libvo/fastmemcpy.h" | |||
| struct vf_priv_s { | |||
| int frame; | |||
| }; | |||
| static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts) | |||
| { | |||
| mp_image_t *dmpi; | |||
| int ret; | |||
| vf->priv->frame = (vf->priv->frame+1)%4; | |||
| dmpi = vf_get_image(vf->next, mpi->imgfmt, | |||
| MP_IMGTYPE_STATIC, MP_IMGFLAG_ACCEPT_STRIDE | | |||
| MP_IMGFLAG_PRESERVE, mpi->width, mpi->height); | |||
| ret = 0; | |||
| // 0/0 1/1 2/2 2/3 3/0 | |||
| switch (vf->priv->frame) { | |||
| case 0: | |||
| my_memcpy_pic(dmpi->planes[0]+dmpi->stride[0], | |||
| mpi->planes[0]+mpi->stride[0], mpi->w, mpi->h/2, | |||
| dmpi->stride[0]*2, mpi->stride[0]*2); | |||
| if (mpi->flags & MP_IMGFLAG_PLANAR) { | |||
| my_memcpy_pic(dmpi->planes[1]+dmpi->stride[1], | |||
| mpi->planes[1]+mpi->stride[1], | |||
| mpi->chroma_width, mpi->chroma_height/2, | |||
| dmpi->stride[1]*2, mpi->stride[1]*2); | |||
| my_memcpy_pic(dmpi->planes[2]+dmpi->stride[2], | |||
| mpi->planes[2]+mpi->stride[2], | |||
| mpi->chroma_width, mpi->chroma_height/2, | |||
| dmpi->stride[2]*2, mpi->stride[2]*2); | |||
| } | |||
| ret = vf_next_put_image(vf, dmpi, MP_NOPTS_VALUE); | |||
| case 1: | |||
| case 2: | |||
| memcpy_pic(dmpi->planes[0], mpi->planes[0], mpi->w, mpi->h, | |||
| dmpi->stride[0], mpi->stride[0]); | |||
| if (mpi->flags & MP_IMGFLAG_PLANAR) { | |||
| memcpy_pic(dmpi->planes[1], mpi->planes[1], | |||
| mpi->chroma_width, mpi->chroma_height, | |||
| dmpi->stride[1], mpi->stride[1]); | |||
| memcpy_pic(dmpi->planes[2], mpi->planes[2], | |||
| mpi->chroma_width, mpi->chroma_height, | |||
| dmpi->stride[2], mpi->stride[2]); | |||
| } | |||
| return vf_next_put_image(vf, dmpi, MP_NOPTS_VALUE) || ret; | |||
| case 3: | |||
| my_memcpy_pic(dmpi->planes[0]+dmpi->stride[0], | |||
| mpi->planes[0]+mpi->stride[0], mpi->w, mpi->h/2, | |||
| dmpi->stride[0]*2, mpi->stride[0]*2); | |||
| if (mpi->flags & MP_IMGFLAG_PLANAR) { | |||
| my_memcpy_pic(dmpi->planes[1]+dmpi->stride[1], | |||
| mpi->planes[1]+mpi->stride[1], | |||
| mpi->chroma_width, mpi->chroma_height/2, | |||
| dmpi->stride[1]*2, mpi->stride[1]*2); | |||
| my_memcpy_pic(dmpi->planes[2]+dmpi->stride[2], | |||
| mpi->planes[2]+mpi->stride[2], | |||
| mpi->chroma_width, mpi->chroma_height/2, | |||
| dmpi->stride[2]*2, mpi->stride[2]*2); | |||
| } | |||
| ret = vf_next_put_image(vf, dmpi, MP_NOPTS_VALUE); | |||
| my_memcpy_pic(dmpi->planes[0], mpi->planes[0], mpi->w, mpi->h/2, | |||
| dmpi->stride[0]*2, mpi->stride[0]*2); | |||
| if (mpi->flags & MP_IMGFLAG_PLANAR) { | |||
| my_memcpy_pic(dmpi->planes[1], mpi->planes[1], | |||
| mpi->chroma_width, mpi->chroma_height/2, | |||
| dmpi->stride[1]*2, mpi->stride[1]*2); | |||
| my_memcpy_pic(dmpi->planes[2], mpi->planes[2], | |||
| mpi->chroma_width, mpi->chroma_height/2, | |||
| dmpi->stride[2]*2, mpi->stride[2]*2); | |||
| } | |||
| return ret; | |||
| } | |||
| return 0; | |||
| } | |||
| #if 0 | |||
| static int query_format(struct vf_instance *vf, unsigned int fmt) | |||
| { | |||
| /* FIXME - figure out which other formats work */ | |||
| switch (fmt) { | |||
| case IMGFMT_YV12: | |||
| case IMGFMT_IYUV: | |||
| case IMGFMT_I420: | |||
| return vf_next_query_format(vf, fmt); | |||
| } | |||
| return 0; | |||
| } | |||
| static int config(struct vf_instance *vf, | |||
| int width, int height, int d_width, int d_height, | |||
| unsigned int flags, unsigned int outfmt) | |||
| { | |||
| return vf_next_config(vf,width,height,d_width,d_height,flags,outfmt); | |||
| } | |||
| #endif | |||
| static void uninit(struct vf_instance *vf) | |||
| { | |||
| free(vf->priv); | |||
| } | |||
| static int vf_open(vf_instance_t *vf, char *args) | |||
| { | |||
| //vf->config = config; | |||
| vf->put_image = put_image; | |||
| //vf->query_format = query_format; | |||
| vf->uninit = uninit; | |||
| vf->default_reqs = VFCAP_ACCEPT_STRIDE; | |||
| vf->priv = calloc(1, sizeof(struct vf_priv_s)); | |||
| vf->priv->frame = 1; | |||
| if (args) sscanf(args, "%d", &vf->priv->frame); | |||
| vf->priv->frame--; | |||
| return 1; | |||
| } | |||
| const vf_info_t vf_info_telecine = { | |||
| "telecine filter", | |||
| "telecine", | |||
| "Rich Felker", | |||
| "", | |||
| vf_open, | |||
| NULL | |||
| }; | |||
| @@ -0,0 +1,333 @@ | |||
| /* | |||
| * Copyright (C) 2002 Michael Niedermayer <michaelni@gmx.at> | |||
| * | |||
| * This file is part of MPlayer. | |||
| * | |||
| * MPlayer 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. | |||
| * | |||
| * MPlayer 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 MPlayer; if not, write to the Free Software Foundation, Inc., | |||
| * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | |||
| */ | |||
| #include <stdio.h> | |||
| #include <stdlib.h> | |||
| #include <string.h> | |||
| #include <inttypes.h> | |||
| #include "config.h" | |||
| #include "mp_msg.h" | |||
| #include "help_mp.h" | |||
| #include "img_format.h" | |||
| #include "mp_image.h" | |||
| #include "vf.h" | |||
| //===========================================================================// | |||
| #include <inttypes.h> | |||
| #include <math.h> | |||
| #define MAX(a,b) ((a) > (b) ? (a) : (b)) | |||
| #define MIN(a,b) ((a) < (b) ? (a) : (b)) | |||
| #define ABS(a,b) ((a) > 0 ? (a) : -(a)) | |||
| #define WIDTH 512 | |||
| #define HEIGHT 512 | |||
| struct vf_priv_s { | |||
| int frame_num; | |||
| }; | |||
| static int config(struct vf_instance *vf, | |||
| int width, int height, int d_width, int d_height, | |||
| unsigned int flags, unsigned int outfmt){ | |||
| if(vf_next_query_format(vf,IMGFMT_YV12)<=0){ | |||
| mp_msg(MSGT_VFILTER, MSGL_WARN, MSGTR_MPCODECS_WarnNextFilterDoesntSupport, "YV12"); | |||
| return 0; | |||
| } | |||
| //hmm whats the meaning of these ... ;) | |||
| d_width= width= WIDTH; | |||
| d_height= height= HEIGHT; | |||
| return vf_next_config(vf,width,height,d_width,d_height,flags,IMGFMT_YV12); | |||
| } | |||
| static double c[64]; | |||
| static void initIdct(void) | |||
| { | |||
| int i; | |||
| for (i=0; i<8; i++) | |||
| { | |||
| double s= i==0 ? sqrt(0.125) : 0.5; | |||
| int j; | |||
| for(j=0; j<8; j++) | |||
| c[i*8+j]= s*cos((3.141592654/8.0)*i*(j+0.5)); | |||
| } | |||
| } | |||
| static void idct(uint8_t *dst, int dstStride, int src[64]) | |||
| { | |||
| int i, j, k; | |||
| double tmp[64]; | |||
| for(i=0; i<8; i++) | |||
| { | |||
| for(j=0; j<8; j++) | |||
| { | |||
| double sum= 0.0; | |||
| for(k=0; k<8; k++) | |||
| sum+= c[k*8+j]*src[8*i+k]; | |||
| tmp[8*i+j]= sum; | |||
| } | |||
| } | |||
| for(j=0; j<8; j++) | |||
| { | |||
| for(i=0; i<8; i++) | |||
| { | |||
| int v; | |||
| double sum= 0.0; | |||
| for(k=0; k<8; k++) | |||
| sum+= c[k*8+i]*tmp[8*k+j]; | |||
| v= (int)floor(sum+0.5); | |||
| if(v<0) v=0; | |||
| else if(v>255) v=255; | |||
| dst[dstStride*i + j] = v; | |||
| } | |||
| } | |||
| } | |||
| static void drawDc(uint8_t *dst, int stride, int color, int w, int h) | |||
| { | |||
| int y; | |||
| for(y=0; y<h; y++) | |||
| { | |||
| int x; | |||
| for(x=0; x<w; x++) | |||
| { | |||
| dst[x + y*stride]= color; | |||
| } | |||
| } | |||
| } | |||
| static void drawBasis(uint8_t *dst, int stride, int amp, int freq, int dc) | |||
| { | |||
| int src[64]; | |||
| memset(src, 0, 64*sizeof(int)); | |||
| src[0]= dc; | |||
| if(amp) src[freq]= amp; | |||
| idct(dst, stride, src); | |||
| } | |||
| static void drawCbp(uint8_t *dst[3], int stride[3], int cbp, int amp, int dc) | |||
| { | |||
| if(cbp&1) drawBasis(dst[0] , stride[0], amp, 1, dc); | |||
| if(cbp&2) drawBasis(dst[0]+8 , stride[0], amp, 1, dc); | |||
| if(cbp&4) drawBasis(dst[0]+ 8*stride[0], stride[0], amp, 1, dc); | |||
| if(cbp&8) drawBasis(dst[0]+8+8*stride[0], stride[0], amp, 1, dc); | |||
| if(cbp&16)drawBasis(dst[1] , stride[1], amp, 1, dc); | |||
| if(cbp&32)drawBasis(dst[2] , stride[2], amp, 1, dc); | |||
| } | |||
| static void dc1Test(uint8_t *dst, int stride, int w, int h, int off) | |||
| { | |||
| const int step= MAX(256/(w*h/256), 1); | |||
| int y; | |||
| int color=off; | |||
| for(y=0; y<h; y+=16) | |||
| { | |||
| int x; | |||
| for(x=0; x<w; x+=16) | |||
| { | |||
| drawDc(dst + x + y*stride, stride, color, 8, 8); | |||
| color+=step; | |||
| } | |||
| } | |||
| } | |||
| static void freq1Test(uint8_t *dst, int stride, int off) | |||
| { | |||
| int y; | |||
| int freq=0; | |||
| for(y=0; y<8*16; y+=16) | |||
| { | |||
| int x; | |||
| for(x=0; x<8*16; x+=16) | |||
| { | |||
| drawBasis(dst + x + y*stride, stride, 4*(96+off), freq, 128*8); | |||
| freq++; | |||
| } | |||
| } | |||
| } | |||
| static void amp1Test(uint8_t *dst, int stride, int off) | |||
| { | |||
| int y; | |||
| int amp=off; | |||
| for(y=0; y<16*16; y+=16) | |||
| { | |||
| int x; | |||
| for(x=0; x<16*16; x+=16) | |||
| { | |||
| drawBasis(dst + x + y*stride, stride, 4*(amp), 1, 128*8); | |||
| amp++; | |||
| } | |||
| } | |||
| } | |||
| static void cbp1Test(uint8_t *dst[3], int stride[3], int off) | |||
| { | |||
| int y; | |||
| int cbp=0; | |||
| for(y=0; y<16*8; y+=16) | |||
| { | |||
| int x; | |||
| for(x=0; x<16*8; x+=16) | |||
| { | |||
| uint8_t *dst1[3]; | |||
| dst1[0]= dst[0] + x*2 + y*2*stride[0]; | |||
| dst1[1]= dst[1] + x + y*stride[1]; | |||
| dst1[2]= dst[2] + x + y*stride[2]; | |||
| drawCbp(dst1, stride, cbp, (64+off)*4, 128*8); | |||
| cbp++; | |||
| } | |||
| } | |||
| } | |||
| static void mv1Test(uint8_t *dst, int stride, int off) | |||
| { | |||
| int y; | |||
| for(y=0; y<16*16; y++) | |||
| { | |||
| int x; | |||
| if(y&16) continue; | |||
| for(x=0; x<16*16; x++) | |||
| { | |||
| dst[x + y*stride]= x + off*8/(y/32+1); | |||
| } | |||
| } | |||
| } | |||
| static void ring1Test(uint8_t *dst, int stride, int off) | |||
| { | |||
| int y; | |||
| int color=0; | |||
| for(y=off; y<16*16; y+=16) | |||
| { | |||
| int x; | |||
| for(x=off; x<16*16; x+=16) | |||
| { | |||
| drawDc(dst + x + y*stride, stride, ((x+y)&16) ? color : -color, 16, 16); | |||
| // dst[x + y*stride]= 255 + (off&1); | |||
| color++; | |||
| } | |||
| } | |||
| } | |||
| static void ring2Test(uint8_t *dst, int stride, int off) | |||
| { | |||
| int y; | |||
| for(y=0; y<16*16; y++) | |||
| { | |||
| int x; | |||
| for(x=0; x<16*16; x++) | |||
| { | |||
| double d= sqrt((x-8*16)*(x-8*16) + (y-8*16)*(y-8*16)); | |||
| double r= d/20 - (int)(d/20); | |||
| if(r<off/30.0) | |||
| { | |||
| dst[x + y*stride]= 255; | |||
| dst[x + y*stride+256]= 0; | |||
| } | |||
| else{ | |||
| dst[x + y*stride]= x; | |||
| dst[x + y*stride+256]= x; | |||
| } | |||
| } | |||
| } | |||
| } | |||
| static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts){ | |||
| mp_image_t *dmpi; | |||
| int frame= vf->priv->frame_num; | |||
| // hope we'll get DR buffer: | |||
| dmpi=vf_get_image(vf->next,IMGFMT_YV12, | |||
| MP_IMGTYPE_TEMP, MP_IMGFLAG_ACCEPT_STRIDE, | |||
| WIDTH, HEIGHT); | |||
| // clean | |||
| memset(dmpi->planes[0], 0, dmpi->stride[0]*dmpi->h); | |||
| memset(dmpi->planes[1], 128, dmpi->stride[1]*dmpi->h>>dmpi->chroma_y_shift); | |||
| memset(dmpi->planes[2], 128, dmpi->stride[2]*dmpi->h>>dmpi->chroma_y_shift); | |||
| if(frame%30) | |||
| { | |||
| switch(frame/30) | |||
| { | |||
| case 0: dc1Test(dmpi->planes[0], dmpi->stride[0], 256, 256, frame%30); break; | |||
| case 1: dc1Test(dmpi->planes[1], dmpi->stride[1], 256, 256, frame%30); break; | |||
| case 2: freq1Test(dmpi->planes[0], dmpi->stride[0], frame%30); break; | |||
| case 3: freq1Test(dmpi->planes[1], dmpi->stride[1], frame%30); break; | |||
| case 4: amp1Test(dmpi->planes[0], dmpi->stride[0], frame%30); break; | |||
| case 5: amp1Test(dmpi->planes[1], dmpi->stride[1], frame%30); break; | |||
| case 6: cbp1Test(dmpi->planes , dmpi->stride , frame%30); break; | |||
| case 7: mv1Test(dmpi->planes[0], dmpi->stride[0], frame%30); break; | |||
| case 8: ring1Test(dmpi->planes[0], dmpi->stride[0], frame%30); break; | |||
| case 9: ring2Test(dmpi->planes[0], dmpi->stride[0], frame%30); break; | |||
| } | |||
| } | |||
| frame++; | |||
| vf->priv->frame_num= frame; | |||
| return vf_next_put_image(vf,dmpi, pts); | |||
| } | |||
| //===========================================================================// | |||
| static int query_format(struct vf_instance *vf, unsigned int fmt){ | |||
| return vf_next_query_format(vf,IMGFMT_YV12) & (~VFCAP_CSP_SUPPORTED_BY_HW); | |||
| } | |||
| static int vf_open(vf_instance_t *vf, char *args){ | |||
| vf->config=config; | |||
| vf->put_image=put_image; | |||
| vf->query_format=query_format; | |||
| vf->priv=malloc(sizeof(struct vf_priv_s)); | |||
| vf->priv->frame_num= args ? atoi(args) : 0; | |||
| initIdct(); | |||
| return 1; | |||
| } | |||
| const vf_info_t vf_info_test = { | |||
| "test pattern generator", | |||
| "test", | |||
| "Michael Niedermayer", | |||
| "", | |||
| vf_open, | |||
| NULL | |||
| }; | |||
| //===========================================================================// | |||
| @@ -0,0 +1,330 @@ | |||
| /* | |||
| * filter to tile a serie of image in a single, bigger, image | |||
| * | |||
| * The parameters are: | |||
| * | |||
| * xtile: number of tile on the x axis (5) | |||
| * ytile: number of tile on the y axis (5) | |||
| * xytile: when write the image, it can be different then xtile * ytile | |||
| * (for example you can write 8 * 7 tile, writing the file every | |||
| * 50 frame, to have one image every 2 seconds @ 25 fps ). | |||
| * start: pixel at the start (x/y), default 2 | |||
| * delta: pixel between 2 tile, (x/y), default 4 | |||
| * | |||
| * For example a valid command line is: | |||
| * ... -vf tile=10:5:-1:4:8 ... | |||
| * that make images of 10 * 5 tiles, with 4 pixel at the beginning and | |||
| * 8 pixel between tiles. | |||
| * | |||
| * The default command is: | |||
| * ... -vf tile=5:5:25:2:4 | |||
| * | |||
| * If you omit a parameter or put a value less then 0, the default is used. | |||
| * ... -vf tile=10:5::-1:10 | |||
| * | |||
| * You can also stop when you're ok | |||
| * ... -vf tile=10:5 | |||
| * (and this is probably the option you will use more often ...) | |||
| * | |||
| * Probably is good to put the scale filter before the tile :-) | |||
| * | |||
| * copyright (c) 2003 Daniele Forghieri ( guru@digitalfantasy.it ) | |||
| * | |||
| * This file is part of MPlayer. | |||
| * | |||
| * MPlayer 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. | |||
| * | |||
| * MPlayer 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 MPlayer; if not, write to the Free Software Foundation, Inc., | |||
| * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | |||
| */ | |||
| // strtoi memcpy_pic | |||
| #include <stdio.h> | |||
| #include <stdlib.h> | |||
| #include <string.h> | |||
| #include "config.h" | |||
| #include "mp_msg.h" | |||
| #include "help_mp.h" | |||
| #include "cpudetect.h" | |||
| #include "img_format.h" | |||
| #include "mp_image.h" | |||
| #include "vf.h" | |||
| #include "libvo/fastmemcpy.h" | |||
| /* private data */ | |||
| struct vf_priv_s { | |||
| /* configuration data */ | |||
| /* Number on hor/ver tiles */ | |||
| int xtile; | |||
| int ytile; | |||
| /* When write the whole frame (default = xtile * ytile) */ | |||
| int xytile; | |||
| /* pixel at start / end (default = 4) */ | |||
| int start; | |||
| /* pixel between image (default = 2) */ | |||
| int delta; | |||
| // /* Background color, in destination format */ | |||
| // int bkgSet; | |||
| /* Work data */ | |||
| int frame_cur; | |||
| }; | |||
| static int config(struct vf_instance *vf, | |||
| int width, int height, int d_width, int d_height, | |||
| unsigned int flags, unsigned int outfmt){ | |||
| struct vf_priv_s *priv; | |||
| int xw; | |||
| int yh; | |||
| /* Calculate new destination size */ | |||
| priv = vf->priv; | |||
| xw = priv->start * 2 + | |||
| priv->xtile * width + | |||
| (priv->xtile - 1) * priv->delta; | |||
| yh = priv->start * 2 + | |||
| priv->ytile * height + | |||
| (priv->ytile - 1) * priv->delta; | |||
| mp_msg(MSGT_VFILTER,MSGL_V,"vf_tile:config size set to %d * %d\n", xw, yh); | |||
| return vf_next_config(vf, xw, yh, xw, yh, flags, outfmt); | |||
| } | |||
| /* Filter handler */ | |||
| static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts) | |||
| { | |||
| mp_image_t *dmpi; | |||
| struct vf_priv_s *priv; | |||
| int t; | |||
| int xw; | |||
| int yh; | |||
| int xi; | |||
| int yi; | |||
| int by; | |||
| int dw; | |||
| /* Calculate new size */ | |||
| priv = vf->priv; | |||
| xw = priv->start * 2 + | |||
| priv->xtile * mpi->w + | |||
| (priv->xtile - 1) * priv->delta; | |||
| yh = priv->start * 2 + | |||
| priv->ytile * mpi->h+ | |||
| (priv->ytile - 1) * priv->delta; | |||
| /* Get the big image! */ | |||
| dmpi=vf_get_image(vf->next, mpi->imgfmt, | |||
| MP_IMGTYPE_STATIC, MP_IMGFLAG_ACCEPT_STRIDE, | |||
| xw, yh); | |||
| /* bytes x pixel & bytes x line */ | |||
| if (mpi->flags & MP_IMGFLAG_PLANAR) { | |||
| by = 1; | |||
| dw = mpi->w; | |||
| } | |||
| else { | |||
| by = (mpi->bpp + 7) / 8; | |||
| dw = mpi->w * by; | |||
| } | |||
| /* Index position */ | |||
| t = priv->frame_cur % priv->xytile; | |||
| // if ((t == 0) && (bkg != 0)) { | |||
| // /* First frame, delete the background */ | |||
| // | |||
| // } | |||
| /* Position of image */ | |||
| xi = priv->start + (mpi->w + priv->delta) * (t % priv->xtile); | |||
| yi = priv->start + (mpi->h + priv->delta) * (t / priv->xtile); | |||
| /* Copy first (or only) plane */ | |||
| memcpy_pic( dmpi->planes[0] + xi * by + yi * dmpi->stride[0], | |||
| mpi->planes[0], | |||
| dw, | |||
| mpi->h, | |||
| dmpi->stride[0], | |||
| mpi->stride[0]); | |||
| if (mpi->flags & MP_IMGFLAG_PLANAR) { | |||
| /* Copy the other 2 planes */ | |||
| memcpy_pic( dmpi->planes[1] + (xi >> mpi->chroma_x_shift) + (yi >> mpi->chroma_y_shift) * dmpi->stride[1], | |||
| mpi->planes[1], | |||
| mpi->chroma_width, | |||
| mpi->chroma_height, | |||
| dmpi->stride[1], | |||
| mpi->stride[1]); | |||
| memcpy_pic( dmpi->planes[2] + (xi >> mpi->chroma_x_shift) + (yi >> mpi->chroma_y_shift) * dmpi->stride[2], | |||
| mpi->planes[2], | |||
| mpi->chroma_width, | |||
| mpi->chroma_height, | |||
| dmpi->stride[2], | |||
| mpi->stride[2]); | |||
| } | |||
| /* Increment current frame */ | |||
| ++priv->frame_cur; | |||
| if (t == priv->xytile - 1) { | |||
| /* Display the composition */ | |||
| dmpi->width = xw; | |||
| dmpi->height = yh; | |||
| return vf_next_put_image(vf, dmpi, MP_NOPTS_VALUE); | |||
| } | |||
| else { | |||
| /* Skip the frame */ | |||
| return 0; | |||
| } | |||
| } | |||
| static void uninit(struct vf_instance *vf) | |||
| { | |||
| /* free local data */ | |||
| free(vf->priv); | |||
| } | |||
| /* rgb/bgr 12...32 supported & some Yxxx */ | |||
| static int query_format(struct vf_instance *vf, unsigned int fmt) | |||
| { | |||
| switch (fmt) { | |||
| /* rgb 12...32 bit */ | |||
| case IMGFMT_RGB12: | |||
| case IMGFMT_RGB15: | |||
| case IMGFMT_RGB16: | |||
| case IMGFMT_RGB24: | |||
| case IMGFMT_RGB32: | |||
| /* bgr 12...32 bit */ | |||
| case IMGFMT_BGR12: | |||
| case IMGFMT_BGR15: | |||
| case IMGFMT_BGR16: | |||
| case IMGFMT_BGR24: | |||
| case IMGFMT_BGR32: | |||
| /* Various Yxxx Formats */ | |||
| case IMGFMT_444P: | |||
| case IMGFMT_422P: | |||
| case IMGFMT_411P: | |||
| case IMGFMT_YUY2: | |||
| case IMGFMT_YV12: | |||
| case IMGFMT_I420: | |||
| case IMGFMT_YVU9: | |||
| case IMGFMT_IF09: | |||
| case IMGFMT_IYUV: | |||
| return vf_next_query_format(vf, fmt); | |||
| } | |||
| return 0; | |||
| } | |||
| /* Get an integer from the string pointed by s, adjusting s. | |||
| * If the value is less then 0 def_val is used. | |||
| * Return 0 for ok | |||
| * | |||
| * Look below ( in vf_open(...) ) for a use ... | |||
| */ | |||
| static int parse_int(char **s, int *rt, int def_val) | |||
| { | |||
| int t = 0; | |||
| if (**s) { | |||
| /* Get value (dec, hex or octal) */ | |||
| t = strtol( *s, s, 0 ); | |||
| /* Use default */ | |||
| if (t < 0) { | |||
| t = def_val; | |||
| } | |||
| if (**s == ':') { | |||
| /* Point to next character (problably a digit) */ | |||
| ++(*s); | |||
| } | |||
| else if (**s != '\0') { | |||
| /* Error, we got some wrong char */ | |||
| return 1; | |||
| } | |||
| } | |||
| else { | |||
| t = def_val; | |||
| } | |||
| *rt = t; | |||
| return 0; | |||
| } | |||
| /* Main entry funct for the filter */ | |||
| static int vf_open(vf_instance_t *vf, char *args) | |||
| { | |||
| struct vf_priv_s *p; | |||
| int er; | |||
| vf->put_image = put_image; | |||
| vf->query_format = query_format; | |||
| vf->config = config; | |||
| vf->uninit = uninit; | |||
| vf->default_reqs = VFCAP_ACCEPT_STRIDE; | |||
| /* Private data */ | |||
| vf->priv = p = calloc(1, sizeof(struct vf_priv_s)); | |||
| if (p == NULL) { | |||
| return 0; | |||
| } | |||
| if (args == NULL) { | |||
| /* Use the default */ | |||
| args = ""; | |||
| } | |||
| /* Parse all the arguments */ | |||
| er = parse_int( &args, &p->xtile, 5 ); | |||
| er |= parse_int( &args, &p->ytile, 5 ); | |||
| er |= parse_int( &args, &p->xytile, 0 ); | |||
| er |= parse_int( &args, &p->start, 2 ); | |||
| er |= parse_int( &args, &p->delta, 4 ); | |||
| // er |= parse_int( &args, &p->bkgSet, 0 ); | |||
| if (er) { | |||
| mp_msg(MSGT_VFILTER, MSGL_ERR, MSGTR_MPCODECS_ErrorParsingArgument); | |||
| return 0; | |||
| } | |||
| /* Load some default */ | |||
| if ((p->xytile <= 0) || (p->xytile > p->xtile * p->ytile)) { | |||
| p->xytile = p->xtile * p->ytile; | |||
| } | |||
| /* Say what happen: use mp_msg(...)? */ | |||
| if ( mp_msg_test(MSGT_VFILTER,MSGL_V) ) { | |||
| printf("vf_tile: tiling %d * %d, output every %d frames\n", | |||
| p->xtile, | |||
| p->ytile, | |||
| p->xytile); | |||
| printf("vf_tile: start pixel %d, delta pixel %d\n", | |||
| p->start, | |||
| p->delta); | |||
| // printf("vf_tile: background 0x%x\n", | |||
| // p->bkgSet); | |||
| } | |||
| return 1; | |||
| } | |||
| const vf_info_t vf_info_tile = { | |||
| "Make a single image tiling x/y images", | |||
| "tile", | |||
| "Daniele Forghieri", | |||
| "", | |||
| vf_open, | |||
| NULL | |||
| }; | |||
| @@ -0,0 +1,235 @@ | |||
| /* | |||
| * Copyright (C) 2003 Michael Zucchi <notzed@ximian.com> | |||
| * | |||
| * This file is part of MPlayer. | |||
| * | |||
| * MPlayer 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. | |||
| * | |||
| * MPlayer 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 MPlayer; if not, write to the Free Software Foundation, Inc., | |||
| * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | |||
| */ | |||
| #include <stdio.h> | |||
| #include <stdlib.h> | |||
| #include <string.h> | |||
| #include "config.h" | |||
| #include "mp_msg.h" | |||
| #include "img_format.h" | |||
| #include "mp_image.h" | |||
| #include "vf.h" | |||
| #include "libvo/fastmemcpy.h" | |||
| struct vf_priv_s { | |||
| int mode; | |||
| int frame; | |||
| mp_image_t *dmpi; | |||
| }; | |||
| static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts) | |||
| { | |||
| int ret = 0; | |||
| mp_image_t *dmpi; | |||
| switch (vf->priv->mode) { | |||
| case 0: | |||
| dmpi = vf->priv->dmpi; | |||
| if (dmpi == NULL) { | |||
| dmpi = vf_get_image(vf->next, mpi->imgfmt, | |||
| MP_IMGTYPE_STATIC, MP_IMGFLAG_ACCEPT_STRIDE | | |||
| MP_IMGFLAG_PRESERVE, | |||
| mpi->width, mpi->height*2); | |||
| vf->priv->dmpi = dmpi; | |||
| memcpy_pic(dmpi->planes[0], mpi->planes[0], mpi->w, mpi->h, | |||
| dmpi->stride[0]*2, mpi->stride[0]); | |||
| if (mpi->flags & MP_IMGFLAG_PLANAR) { | |||
| memcpy_pic(dmpi->planes[1], mpi->planes[1], | |||
| mpi->chroma_width, mpi->chroma_height, | |||
| dmpi->stride[1]*2, mpi->stride[1]); | |||
| memcpy_pic(dmpi->planes[2], mpi->planes[2], | |||
| mpi->chroma_width, mpi->chroma_height, | |||
| dmpi->stride[2]*2, mpi->stride[2]); | |||
| } | |||
| } else { | |||
| vf->priv->dmpi = NULL; | |||
| memcpy_pic(dmpi->planes[0]+dmpi->stride[0], mpi->planes[0], mpi->w, mpi->h, | |||
| dmpi->stride[0]*2, mpi->stride[0]); | |||
| if (mpi->flags & MP_IMGFLAG_PLANAR) { | |||
| memcpy_pic(dmpi->planes[1]+dmpi->stride[1], mpi->planes[1], | |||
| mpi->chroma_width, mpi->chroma_height, | |||
| dmpi->stride[1]*2, mpi->stride[1]); | |||
| memcpy_pic(dmpi->planes[2]+dmpi->stride[2], mpi->planes[2], | |||
| mpi->chroma_width, mpi->chroma_height, | |||
| dmpi->stride[2]*2, mpi->stride[2]); | |||
| } | |||
| ret = vf_next_put_image(vf, dmpi, MP_NOPTS_VALUE); | |||
| } | |||
| break; | |||
| case 1: | |||
| if (vf->priv->frame & 1) | |||
| ret = vf_next_put_image(vf, mpi, MP_NOPTS_VALUE); | |||
| break; | |||
| case 2: | |||
| if ((vf->priv->frame & 1) == 0) | |||
| ret = vf_next_put_image(vf, mpi, MP_NOPTS_VALUE); | |||
| break; | |||
| case 3: | |||
| dmpi = vf_get_image(vf->next, mpi->imgfmt, | |||
| MP_IMGTYPE_TEMP, MP_IMGFLAG_ACCEPT_STRIDE, | |||
| mpi->width, mpi->height*2); | |||
| /* fixme, just clear alternate lines */ | |||
| vf_mpi_clear(dmpi, 0, 0, dmpi->w, dmpi->h); | |||
| if ((vf->priv->frame & 1) == 0) { | |||
| memcpy_pic(dmpi->planes[0], mpi->planes[0], mpi->w, mpi->h, | |||
| dmpi->stride[0]*2, mpi->stride[0]); | |||
| if (mpi->flags & MP_IMGFLAG_PLANAR) { | |||
| memcpy_pic(dmpi->planes[1], mpi->planes[1], | |||
| mpi->chroma_width, mpi->chroma_height, | |||
| dmpi->stride[1]*2, mpi->stride[1]); | |||
| memcpy_pic(dmpi->planes[2], mpi->planes[2], | |||
| mpi->chroma_width, mpi->chroma_height, | |||
| dmpi->stride[2]*2, mpi->stride[2]); | |||
| } | |||
| } else { | |||
| memcpy_pic(dmpi->planes[0]+dmpi->stride[0], mpi->planes[0], mpi->w, mpi->h, | |||
| dmpi->stride[0]*2, mpi->stride[0]); | |||
| if (mpi->flags & MP_IMGFLAG_PLANAR) { | |||
| memcpy_pic(dmpi->planes[1]+dmpi->stride[1], mpi->planes[1], | |||
| mpi->chroma_width, mpi->chroma_height, | |||
| dmpi->stride[1]*2, mpi->stride[1]); | |||
| memcpy_pic(dmpi->planes[2]+dmpi->stride[2], mpi->planes[2], | |||
| mpi->chroma_width, mpi->chroma_height, | |||
| dmpi->stride[2]*2, mpi->stride[2]); | |||
| } | |||
| } | |||
| ret = vf_next_put_image(vf, dmpi, MP_NOPTS_VALUE); | |||
| break; | |||
| case 4: | |||
| // Interleave even lines (only) from Frame 'i' with odd | |||
| // lines (only) from Frame 'i+1', halving the Frame | |||
| // rate and preserving image height. | |||
| dmpi = vf->priv->dmpi; | |||
| // @@ Need help: Should I set dmpi->fields to indicate | |||
| // that the (new) frame will be interlaced!? E.g. ... | |||
| // dmpi->fields |= MP_IMGFIELD_INTERLACED; | |||
| // dmpi->fields |= MP_IMGFIELD_TOP_FIRST; | |||
| // etc. | |||
| if (dmpi == NULL) { | |||
| dmpi = vf_get_image(vf->next, mpi->imgfmt, | |||
| MP_IMGTYPE_STATIC, MP_IMGFLAG_ACCEPT_STRIDE | | |||
| MP_IMGFLAG_PRESERVE, | |||
| mpi->width, mpi->height); | |||
| vf->priv->dmpi = dmpi; | |||
| my_memcpy_pic(dmpi->planes[0], mpi->planes[0], mpi->w, mpi->h/2, | |||
| dmpi->stride[0]*2, mpi->stride[0]*2); | |||
| if (mpi->flags & MP_IMGFLAG_PLANAR) { | |||
| my_memcpy_pic(dmpi->planes[1], mpi->planes[1], | |||
| mpi->chroma_width, mpi->chroma_height/2, | |||
| dmpi->stride[1]*2, mpi->stride[1]*2); | |||
| my_memcpy_pic(dmpi->planes[2], mpi->planes[2], | |||
| mpi->chroma_width, mpi->chroma_height/2, | |||
| dmpi->stride[2]*2, mpi->stride[2]*2); | |||
| } | |||
| } else { | |||
| vf->priv->dmpi = NULL; | |||
| my_memcpy_pic(dmpi->planes[0]+dmpi->stride[0], | |||
| mpi->planes[0]+mpi->stride[0], | |||
| mpi->w, mpi->h/2, | |||
| dmpi->stride[0]*2, mpi->stride[0]*2); | |||
| if (mpi->flags & MP_IMGFLAG_PLANAR) { | |||
| my_memcpy_pic(dmpi->planes[1]+dmpi->stride[1], | |||
| mpi->planes[1]+mpi->stride[1], | |||
| mpi->chroma_width, mpi->chroma_height/2, | |||
| dmpi->stride[1]*2, mpi->stride[1]*2); | |||
| my_memcpy_pic(dmpi->planes[2]+dmpi->stride[2], | |||
| mpi->planes[2]+mpi->stride[2], | |||
| mpi->chroma_width, mpi->chroma_height/2, | |||
| dmpi->stride[2]*2, mpi->stride[2]*2); | |||
| } | |||
| ret = vf_next_put_image(vf, dmpi, MP_NOPTS_VALUE); | |||
| } | |||
| break; | |||
| } | |||
| vf->priv->frame++; | |||
| return ret; | |||
| } | |||
| static int query_format(struct vf_instance *vf, unsigned int fmt) | |||
| { | |||
| /* FIXME - figure out which other formats work */ | |||
| switch (fmt) { | |||
| case IMGFMT_YV12: | |||
| case IMGFMT_IYUV: | |||
| case IMGFMT_I420: | |||
| return vf_next_query_format(vf, fmt); | |||
| } | |||
| return 0; | |||
| } | |||
| static int config(struct vf_instance *vf, | |||
| int width, int height, int d_width, int d_height, | |||
| unsigned int flags, unsigned int outfmt) | |||
| { | |||
| switch (vf->priv->mode) { | |||
| case 0: | |||
| case 3: | |||
| return vf_next_config(vf,width,height*2,d_width,d_height*2,flags,outfmt); | |||
| case 1: /* odd frames */ | |||
| case 2: /* even frames */ | |||
| case 4: /* alternate frame (height-preserving) interlacing */ | |||
| return vf_next_config(vf,width,height,d_width,d_height,flags,outfmt); | |||
| } | |||
| return 0; | |||
| } | |||
| static void uninit(struct vf_instance *vf) | |||
| { | |||
| free(vf->priv); | |||
| } | |||
| static int vf_open(vf_instance_t *vf, char *args) | |||
| { | |||
| struct vf_priv_s *p; | |||
| vf->config = config; | |||
| vf->put_image = put_image; | |||
| vf->query_format = query_format; | |||
| vf->uninit = uninit; | |||
| vf->default_reqs = VFCAP_ACCEPT_STRIDE; | |||
| vf->priv = p = calloc(1, sizeof(struct vf_priv_s)); | |||
| vf->priv->mode = 0; | |||
| if (args) | |||
| sscanf(args, "%d", &vf->priv->mode); | |||
| vf->priv->frame = 0; | |||
| return 1; | |||
| } | |||
| const vf_info_t vf_info_tinterlace = { | |||
| "temporal field interlacing", | |||
| "tinterlace", | |||
| "Michael Zucchi", | |||
| "", | |||
| vf_open, | |||
| NULL | |||
| }; | |||
| @@ -0,0 +1,324 @@ | |||
| /* | |||
| * Copyright (C) 2002 Remi Guyomarch <rguyom@pobox.com> | |||
| * | |||
| * This file is part of MPlayer. | |||
| * | |||
| * MPlayer 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. | |||
| * | |||
| * MPlayer 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 MPlayer; if not, write to the Free Software Foundation, Inc., | |||
| * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | |||
| */ | |||
| #include <stdio.h> | |||
| #include <stdlib.h> | |||
| #include <string.h> | |||
| #include <inttypes.h> | |||
| #include <math.h> | |||
| #include "config.h" | |||
| #include "mp_msg.h" | |||
| #include "cpudetect.h" | |||
| #if HAVE_MALLOC_H | |||
| #include <malloc.h> | |||
| #endif | |||
| #include "img_format.h" | |||
| #include "mp_image.h" | |||
| #include "vf.h" | |||
| #include "libvo/fastmemcpy.h" | |||
| #include "libavutil/common.h" | |||
| //===========================================================================// | |||
| #define MIN_MATRIX_SIZE 3 | |||
| #define MAX_MATRIX_SIZE 63 | |||
| typedef struct FilterParam { | |||
| int msizeX, msizeY; | |||
| double amount; | |||
| uint32_t *SC[MAX_MATRIX_SIZE-1]; | |||
| } FilterParam; | |||
| struct vf_priv_s { | |||
| FilterParam lumaParam; | |||
| FilterParam chromaParam; | |||
| unsigned int outfmt; | |||
| }; | |||
| //===========================================================================// | |||
| /* This code is based on : | |||
| An Efficient algorithm for Gaussian blur using finite-state machines | |||
| Frederick M. Waltz and John W. V. Miller | |||
| SPIE Conf. on Machine Vision Systems for Inspection and Metrology VII | |||
| Originally published Boston, Nov 98 | |||
| */ | |||
| static void unsharp( uint8_t *dst, uint8_t *src, int dstStride, int srcStride, int width, int height, FilterParam *fp ) { | |||
| uint32_t **SC = fp->SC; | |||
| uint32_t SR[MAX_MATRIX_SIZE-1], Tmp1, Tmp2; | |||
| uint8_t* src2 = src; // avoid gcc warning | |||
| int32_t res; | |||
| int x, y, z; | |||
| int amount = fp->amount * 65536.0; | |||
| int stepsX = fp->msizeX/2; | |||
| int stepsY = fp->msizeY/2; | |||
| int scalebits = (stepsX+stepsY)*2; | |||
| int32_t halfscale = 1 << ((stepsX+stepsY)*2-1); | |||
| if( !fp->amount ) { | |||
| if( src == dst ) | |||
| return; | |||
| if( dstStride == srcStride ) | |||
| fast_memcpy( dst, src, srcStride*height ); | |||
| else | |||
| for( y=0; y<height; y++, dst+=dstStride, src+=srcStride ) | |||
| fast_memcpy( dst, src, width ); | |||
| return; | |||
| } | |||
| for( y=0; y<2*stepsY; y++ ) | |||
| memset( SC[y], 0, sizeof(SC[y][0]) * (width+2*stepsX) ); | |||
| for( y=-stepsY; y<height+stepsY; y++ ) { | |||
| if( y < height ) src2 = src; | |||
| memset( SR, 0, sizeof(SR[0]) * (2*stepsX-1) ); | |||
| for( x=-stepsX; x<width+stepsX; x++ ) { | |||
| Tmp1 = x<=0 ? src2[0] : x>=width ? src2[width-1] : src2[x]; | |||
| for( z=0; z<stepsX*2; z+=2 ) { | |||
| Tmp2 = SR[z+0] + Tmp1; SR[z+0] = Tmp1; | |||
| Tmp1 = SR[z+1] + Tmp2; SR[z+1] = Tmp2; | |||
| } | |||
| for( z=0; z<stepsY*2; z+=2 ) { | |||
| Tmp2 = SC[z+0][x+stepsX] + Tmp1; SC[z+0][x+stepsX] = Tmp1; | |||
| Tmp1 = SC[z+1][x+stepsX] + Tmp2; SC[z+1][x+stepsX] = Tmp2; | |||
| } | |||
| if( x>=stepsX && y>=stepsY ) { | |||
| uint8_t* srx = src - stepsY*srcStride + x - stepsX; | |||
| uint8_t* dsx = dst - stepsY*dstStride + x - stepsX; | |||
| res = (int32_t)*srx + ( ( ( (int32_t)*srx - (int32_t)((Tmp1+halfscale) >> scalebits) ) * amount ) >> 16 ); | |||
| *dsx = res>255 ? 255 : res<0 ? 0 : (uint8_t)res; | |||
| } | |||
| } | |||
| if( y >= 0 ) { | |||
| dst += dstStride; | |||
| src += srcStride; | |||
| } | |||
| } | |||
| } | |||
| //===========================================================================// | |||
| static int config( struct vf_instance *vf, | |||
| int width, int height, int d_width, int d_height, | |||
| unsigned int flags, unsigned int outfmt ) { | |||
| int z, stepsX, stepsY; | |||
| FilterParam *fp; | |||
| char *effect; | |||
| // allocate buffers | |||
| fp = &vf->priv->lumaParam; | |||
| effect = fp->amount == 0 ? "don't touch" : fp->amount < 0 ? "blur" : "sharpen"; | |||
| mp_msg( MSGT_VFILTER, MSGL_INFO, "unsharp: %dx%d:%0.2f (%s luma) \n", fp->msizeX, fp->msizeY, fp->amount, effect ); | |||
| memset( fp->SC, 0, sizeof( fp->SC ) ); | |||
| stepsX = fp->msizeX/2; | |||
| stepsY = fp->msizeY/2; | |||
| for( z=0; z<2*stepsY; z++ ) | |||
| fp->SC[z] = av_malloc(sizeof(*(fp->SC[z])) * (width+2*stepsX)); | |||
| fp = &vf->priv->chromaParam; | |||
| effect = fp->amount == 0 ? "don't touch" : fp->amount < 0 ? "blur" : "sharpen"; | |||
| mp_msg( MSGT_VFILTER, MSGL_INFO, "unsharp: %dx%d:%0.2f (%s chroma)\n", fp->msizeX, fp->msizeY, fp->amount, effect ); | |||
| memset( fp->SC, 0, sizeof( fp->SC ) ); | |||
| stepsX = fp->msizeX/2; | |||
| stepsY = fp->msizeY/2; | |||
| for( z=0; z<2*stepsY; z++ ) | |||
| fp->SC[z] = av_malloc(sizeof(*(fp->SC[z])) * (width+2*stepsX)); | |||
| return vf_next_config( vf, width, height, d_width, d_height, flags, outfmt ); | |||
| } | |||
| //===========================================================================// | |||
| static void get_image( struct vf_instance *vf, mp_image_t *mpi ) { | |||
| if( mpi->flags & MP_IMGFLAG_PRESERVE ) | |||
| return; // don't change | |||
| if( mpi->imgfmt!=vf->priv->outfmt ) | |||
| return; // colorspace differ | |||
| vf->dmpi = vf_get_image( vf->next, mpi->imgfmt, mpi->type, mpi->flags, mpi->w, mpi->h ); | |||
| mpi->planes[0] = vf->dmpi->planes[0]; | |||
| mpi->stride[0] = vf->dmpi->stride[0]; | |||
| mpi->width = vf->dmpi->width; | |||
| if( mpi->flags & MP_IMGFLAG_PLANAR ) { | |||
| mpi->planes[1] = vf->dmpi->planes[1]; | |||
| mpi->planes[2] = vf->dmpi->planes[2]; | |||
| mpi->stride[1] = vf->dmpi->stride[1]; | |||
| mpi->stride[2] = vf->dmpi->stride[2]; | |||
| } | |||
| mpi->flags |= MP_IMGFLAG_DIRECT; | |||
| } | |||
| static int put_image( struct vf_instance *vf, mp_image_t *mpi, double pts) { | |||
| mp_image_t *dmpi; | |||
| if( !(mpi->flags & MP_IMGFLAG_DIRECT) ) | |||
| // no DR, so get a new image! hope we'll get DR buffer: | |||
| vf->dmpi = vf_get_image( vf->next,vf->priv->outfmt, MP_IMGTYPE_TEMP, MP_IMGFLAG_ACCEPT_STRIDE, mpi->w, mpi->h); | |||
| dmpi= vf->dmpi; | |||
| unsharp( dmpi->planes[0], mpi->planes[0], dmpi->stride[0], mpi->stride[0], mpi->w, mpi->h, &vf->priv->lumaParam ); | |||
| unsharp( dmpi->planes[1], mpi->planes[1], dmpi->stride[1], mpi->stride[1], mpi->w/2, mpi->h/2, &vf->priv->chromaParam ); | |||
| unsharp( dmpi->planes[2], mpi->planes[2], dmpi->stride[2], mpi->stride[2], mpi->w/2, mpi->h/2, &vf->priv->chromaParam ); | |||
| vf_clone_mpi_attributes(dmpi, mpi); | |||
| #if HAVE_MMX | |||
| if(gCpuCaps.hasMMX) | |||
| __asm__ volatile ("emms\n\t"); | |||
| #endif | |||
| #if HAVE_MMX2 | |||
| if(gCpuCaps.hasMMX2) | |||
| __asm__ volatile ("sfence\n\t"); | |||
| #endif | |||
| return vf_next_put_image( vf, dmpi, pts); | |||
| } | |||
| static void uninit( struct vf_instance *vf ) { | |||
| unsigned int z; | |||
| FilterParam *fp; | |||
| if( !vf->priv ) return; | |||
| fp = &vf->priv->lumaParam; | |||
| for( z=0; z<sizeof(fp->SC)/sizeof(fp->SC[0]); z++ ) { | |||
| av_free( fp->SC[z] ); | |||
| fp->SC[z] = NULL; | |||
| } | |||
| fp = &vf->priv->chromaParam; | |||
| for( z=0; z<sizeof(fp->SC)/sizeof(fp->SC[0]); z++ ) { | |||
| av_free( fp->SC[z] ); | |||
| fp->SC[z] = NULL; | |||
| } | |||
| free( vf->priv ); | |||
| vf->priv = NULL; | |||
| } | |||
| //===========================================================================// | |||
| static int query_format( struct vf_instance *vf, unsigned int fmt ) { | |||
| switch(fmt) { | |||
| case IMGFMT_YV12: | |||
| case IMGFMT_I420: | |||
| case IMGFMT_IYUV: | |||
| return vf_next_query_format( vf, vf->priv->outfmt ); | |||
| } | |||
| return 0; | |||
| } | |||
| //===========================================================================// | |||
| static void parse( FilterParam *fp, char* args ) { | |||
| // l7x5:0.8:c3x3:-0.2 | |||
| char *z; | |||
| char *pos = args; | |||
| char *max = args + strlen(args); | |||
| // parse matrix sizes | |||
| fp->msizeX = ( pos && pos+1<max ) ? atoi( pos+1 ) : 0; | |||
| z = strchr( pos+1, 'x' ); | |||
| fp->msizeY = ( z && z+1<max ) ? atoi( pos=z+1 ) : fp->msizeX; | |||
| // min/max & odd | |||
| fp->msizeX = 1 | av_clip(fp->msizeX, MIN_MATRIX_SIZE, MAX_MATRIX_SIZE); | |||
| fp->msizeY = 1 | av_clip(fp->msizeY, MIN_MATRIX_SIZE, MAX_MATRIX_SIZE); | |||
| // parse amount | |||
| pos = strchr( pos+1, ':' ); | |||
| fp->amount = ( pos && pos+1<max ) ? atof( pos+1 ) : 0; | |||
| } | |||
| //===========================================================================// | |||
| static const unsigned int fmt_list[] = { | |||
| IMGFMT_YV12, | |||
| IMGFMT_I420, | |||
| IMGFMT_IYUV, | |||
| 0 | |||
| }; | |||
| static int vf_open( vf_instance_t *vf, char *args ) { | |||
| vf->config = config; | |||
| vf->put_image = put_image; | |||
| vf->get_image = get_image; | |||
| vf->query_format = query_format; | |||
| vf->uninit = uninit; | |||
| vf->priv = malloc( sizeof(struct vf_priv_s) ); | |||
| memset( vf->priv, 0, sizeof(struct vf_priv_s) ); | |||
| if( args ) { | |||
| char *args2 = strchr( args, 'l' ); | |||
| if( args2 ) | |||
| parse( &vf->priv->lumaParam, args2 ); | |||
| else { | |||
| vf->priv->lumaParam.amount = | |||
| vf->priv->lumaParam.msizeX = | |||
| vf->priv->lumaParam.msizeY = 0; | |||
| } | |||
| args2 = strchr( args, 'c' ); | |||
| if( args2 ) | |||
| parse( &vf->priv->chromaParam, args2 ); | |||
| else { | |||
| vf->priv->chromaParam.amount = | |||
| vf->priv->chromaParam.msizeX = | |||
| vf->priv->chromaParam.msizeY = 0; | |||
| } | |||
| if( !vf->priv->lumaParam.msizeX && !vf->priv->chromaParam.msizeX ) | |||
| return 0; // nothing to do | |||
| } | |||
| // check csp: | |||
| vf->priv->outfmt = vf_match_csp( &vf->next, fmt_list, IMGFMT_YV12 ); | |||
| if( !vf->priv->outfmt ) { | |||
| uninit( vf ); | |||
| return 0; // no csp match :( | |||
| } | |||
| return 1; | |||
| } | |||
| const vf_info_t vf_info_unsharp = { | |||
| "unsharp mask & gaussian blur", | |||
| "unsharp", | |||
| "Remi Guyomarch", | |||
| "", | |||
| vf_open, | |||
| NULL | |||
| }; | |||
| //===========================================================================// | |||
| @@ -0,0 +1,385 @@ | |||
| /* | |||
| * Copyright (C) 2005 Michael Niedermayer <michaelni@gmx.at> | |||
| * | |||
| * This file is part of MPlayer. | |||
| * | |||
| * MPlayer 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. | |||
| * | |||
| * MPlayer 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 MPlayer; if not, write to the Free Software Foundation, Inc., | |||
| * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | |||
| */ | |||
| #include <stdio.h> | |||
| #include <stdlib.h> | |||
| #include <string.h> | |||
| #include <inttypes.h> | |||
| #include <math.h> | |||
| #include <assert.h> | |||
| #include "config.h" | |||
| #include "mp_msg.h" | |||
| #include "cpudetect.h" | |||
| #include "libavcodec/avcodec.h" | |||
| #include "img_format.h" | |||
| #include "mp_image.h" | |||
| #include "vf.h" | |||
| #include "vd_ffmpeg.h" | |||
| #include "libvo/fastmemcpy.h" | |||
| #define XMIN(a,b) ((a) < (b) ? (a) : (b)) | |||
| #define BLOCK 16 | |||
| //===========================================================================// | |||
| static const uint8_t __attribute__((aligned(8))) dither[8][8]={ | |||
| { 0*4, 48*4, 12*4, 60*4, 3*4, 51*4, 15*4, 63*4, }, | |||
| { 32*4, 16*4, 44*4, 28*4, 35*4, 19*4, 47*4, 31*4, }, | |||
| { 8*4, 56*4, 4*4, 52*4, 11*4, 59*4, 7*4, 55*4, }, | |||
| { 40*4, 24*4, 36*4, 20*4, 43*4, 27*4, 39*4, 23*4, }, | |||
| { 2*4, 50*4, 14*4, 62*4, 1*4, 49*4, 13*4, 61*4, }, | |||
| { 34*4, 18*4, 46*4, 30*4, 33*4, 17*4, 45*4, 29*4, }, | |||
| { 10*4, 58*4, 6*4, 54*4, 9*4, 57*4, 5*4, 53*4, }, | |||
| { 42*4, 26*4, 38*4, 22*4, 41*4, 25*4, 37*4, 21*4, }, | |||
| }; | |||
| static const uint8_t offset[511][2]= { | |||
| { 0, 0}, | |||
| { 0, 0}, { 8, 8}, | |||
| { 0, 0}, { 4, 4}, {12, 8}, { 8,12}, | |||
| { 0, 0}, {10, 2}, { 4, 4}, {14, 6}, { 8, 8}, { 2,10}, {12,12}, { 6,14}, | |||
| { 0, 0}, {10, 2}, { 4, 4}, {14, 6}, { 8, 8}, { 2,10}, {12,12}, { 6,14}, | |||
| { 5, 1}, {15, 3}, { 9, 5}, { 3, 7}, {13, 9}, { 7,11}, { 1,13}, {11,15}, | |||
| { 0, 0}, { 8, 0}, { 0, 8}, { 8, 8}, { 5, 1}, {13, 1}, { 5, 9}, {13, 9}, | |||
| { 2, 2}, {10, 2}, { 2,10}, {10,10}, { 7, 3}, {15, 3}, { 7,11}, {15,11}, | |||
| { 4, 4}, {12, 4}, { 4,12}, {12,12}, { 1, 5}, { 9, 5}, { 1,13}, { 9,13}, | |||
| { 6, 6}, {14, 6}, { 6,14}, {14,14}, { 3, 7}, {11, 7}, { 3,15}, {11,15}, | |||
| { 0, 0}, { 8, 0}, { 0, 8}, { 8, 8}, { 4, 0}, {12, 0}, { 4, 8}, {12, 8}, | |||
| { 1, 1}, { 9, 1}, { 1, 9}, { 9, 9}, { 5, 1}, {13, 1}, { 5, 9}, {13, 9}, | |||
| { 3, 2}, {11, 2}, { 3,10}, {11,10}, { 7, 2}, {15, 2}, { 7,10}, {15,10}, | |||
| { 2, 3}, {10, 3}, { 2,11}, {10,11}, { 6, 3}, {14, 3}, { 6,11}, {14,11}, | |||
| { 0, 4}, { 8, 4}, { 0,12}, { 8,12}, { 4, 4}, {12, 4}, { 4,12}, {12,12}, | |||
| { 1, 5}, { 9, 5}, { 1,13}, { 9,13}, { 5, 5}, {13, 5}, { 5,13}, {13,13}, | |||
| { 3, 6}, {11, 6}, { 3,14}, {11,14}, { 7, 6}, {15, 6}, { 7,14}, {15,14}, | |||
| { 2, 7}, {10, 7}, { 2,15}, {10,15}, { 6, 7}, {14, 7}, { 6,15}, {14,15}, | |||
| { 0, 0}, { 8, 0}, { 0, 8}, { 8, 8}, { 0, 2}, { 8, 2}, { 0,10}, { 8,10}, | |||
| { 0, 4}, { 8, 4}, { 0,12}, { 8,12}, { 0, 6}, { 8, 6}, { 0,14}, { 8,14}, | |||
| { 1, 1}, { 9, 1}, { 1, 9}, { 9, 9}, { 1, 3}, { 9, 3}, { 1,11}, { 9,11}, | |||
| { 1, 5}, { 9, 5}, { 1,13}, { 9,13}, { 1, 7}, { 9, 7}, { 1,15}, { 9,15}, | |||
| { 2, 0}, {10, 0}, { 2, 8}, {10, 8}, { 2, 2}, {10, 2}, { 2,10}, {10,10}, | |||
| { 2, 4}, {10, 4}, { 2,12}, {10,12}, { 2, 6}, {10, 6}, { 2,14}, {10,14}, | |||
| { 3, 1}, {11, 1}, { 3, 9}, {11, 9}, { 3, 3}, {11, 3}, { 3,11}, {11,11}, | |||
| { 3, 5}, {11, 5}, { 3,13}, {11,13}, { 3, 7}, {11, 7}, { 3,15}, {11,15}, | |||
| { 4, 0}, {12, 0}, { 4, 8}, {12, 8}, { 4, 2}, {12, 2}, { 4,10}, {12,10}, | |||
| { 4, 4}, {12, 4}, { 4,12}, {12,12}, { 4, 6}, {12, 6}, { 4,14}, {12,14}, | |||
| { 5, 1}, {13, 1}, { 5, 9}, {13, 9}, { 5, 3}, {13, 3}, { 5,11}, {13,11}, | |||
| { 5, 5}, {13, 5}, { 5,13}, {13,13}, { 5, 7}, {13, 7}, { 5,15}, {13,15}, | |||
| { 6, 0}, {14, 0}, { 6, 8}, {14, 8}, { 6, 2}, {14, 2}, { 6,10}, {14,10}, | |||
| { 6, 4}, {14, 4}, { 6,12}, {14,12}, { 6, 6}, {14, 6}, { 6,14}, {14,14}, | |||
| { 7, 1}, {15, 1}, { 7, 9}, {15, 9}, { 7, 3}, {15, 3}, { 7,11}, {15,11}, | |||
| { 7, 5}, {15, 5}, { 7,13}, {15,13}, { 7, 7}, {15, 7}, { 7,15}, {15,15}, | |||
| { 0, 0}, { 8, 0}, { 0, 8}, { 8, 8}, { 4, 4}, {12, 4}, { 4,12}, {12,12}, { 0, 4}, { 8, 4}, { 0,12}, { 8,12}, { 4, 0}, {12, 0}, { 4, 8}, {12, 8}, { 2, 2}, {10, 2}, { 2,10}, {10,10}, { 6, 6}, {14, 6}, { 6,14}, {14,14}, { 2, 6}, {10, 6}, { 2,14}, {10,14}, { 6, 2}, {14, 2}, { 6,10}, {14,10}, { 0, 2}, { 8, 2}, { 0,10}, { 8,10}, { 4, 6}, {12, 6}, { 4,14}, {12,14}, { 0, 6}, { 8, 6}, { 0,14}, { 8,14}, { 4, 2}, {12, 2}, { 4,10}, {12,10}, { 2, 0}, {10, 0}, { 2, 8}, {10, 8}, { 6, 4}, {14, 4}, { 6,12}, {14,12}, { 2, 4}, {10, 4}, { 2,12}, {10,12}, { 6, 0}, {14, 0}, { 6, 8}, {14, 8}, { 1, 1}, { 9, 1}, { 1, 9}, { 9, 9}, { 5, 5}, {13, 5}, { 5,13}, {13,13}, { 1, 5}, { 9, 5}, { 1,13}, { 9,13}, { 5, 1}, {13, 1}, { 5, 9}, {13, 9}, { 3, 3}, {11, 3}, { 3,11}, {11,11}, { 7, 7}, {15, 7}, { 7,15}, {15,15}, { 3, 7}, {11, 7}, { 3,15}, {11,15}, { 7, 3}, {15, 3}, { 7,11}, {15,11}, { 1, 3}, { 9, 3}, { 1,11}, { 9,11}, { 5, 7}, {13, 7}, { 5,15}, {13,15}, { 1, 7}, { 9, 7}, { 1,15}, { 9,15}, { 5, 3}, {13, 3}, { 5,11}, {13,11}, { 3, 1}, {11, 1}, { 3, 9}, {11, 9}, { 7, 5}, {15, 5}, { 7,13}, {15,13}, { 3, 5}, {11, 5}, { 3,13}, {11,13}, { 7, 1}, {15, 1}, { 7, 9}, {15, 9}, { 0, 1}, { 8, 1}, { 0, 9}, { 8, 9}, { 4, 5}, {12, 5}, { 4,13}, {12,13}, { 0, 5}, { 8, 5}, { 0,13}, { 8,13}, { 4, 1}, {12, 1}, { 4, 9}, {12, 9}, { 2, 3}, {10, 3}, { 2,11}, {10,11}, { 6, 7}, {14, 7}, { 6,15}, {14,15}, { 2, 7}, {10, 7}, { 2,15}, {10,15}, { 6, 3}, {14, 3}, { 6,11}, {14,11}, { 0, 3}, { 8, 3}, { 0,11}, { 8,11}, { 4, 7}, {12, 7}, { 4,15}, {12,15}, { 0, 7}, { 8, 7}, { 0,15}, { 8,15}, { 4, 3}, {12, 3}, { 4,11}, {12,11}, { 2, 1}, {10, 1}, { 2, 9}, {10, 9}, { 6, 5}, {14, 5}, { 6,13}, {14,13}, { 2, 5}, {10, 5}, { 2,13}, {10,13}, { 6, 1}, {14, 1}, { 6, 9}, {14, 9}, { 1, 0}, { 9, 0}, { 1, 8}, { 9, 8}, { 5, 4}, {13, 4}, { 5,12}, {13,12}, { 1, 4}, { 9, 4}, { 1,12}, { 9,12}, { 5, 0}, {13, 0}, { 5, 8}, {13, 8}, { 3, 2}, {11, 2}, { 3,10}, {11,10}, { 7, 6}, {15, 6}, { 7,14}, {15,14}, { 3, 6}, {11, 6}, { 3,14}, {11,14}, { 7, 2}, {15, 2}, { 7,10}, {15,10}, { 1, 2}, { 9, 2}, { 1,10}, { 9,10}, { 5, 6}, {13, 6}, { 5,14}, {13,14}, { 1, 6}, { 9, 6}, { 1,14}, { 9,14}, { 5, 2}, {13, 2}, { 5,10}, {13,10}, { 3, 0}, {11, 0}, { 3, 8}, {11, 8}, { 7, 4}, {15, 4}, { 7,12}, {15,12}, { 3, 4}, {11, 4}, { 3,12}, {11,12}, { 7, 0}, {15, 0}, { 7, 8}, {15, 8}, | |||
| }; | |||
| struct vf_priv_s { | |||
| int log2_count; | |||
| int qp; | |||
| int mode; | |||
| int mpeg2; | |||
| int temp_stride[3]; | |||
| uint8_t *src[3]; | |||
| int16_t *temp[3]; | |||
| int outbuf_size; | |||
| uint8_t *outbuf; | |||
| AVCodecContext *avctx_enc[BLOCK*BLOCK]; | |||
| AVFrame *frame; | |||
| AVFrame *frame_dec; | |||
| }; | |||
| static void store_slice_c(uint8_t *dst, int16_t *src, int dst_stride, int src_stride, int width, int height, int log2_scale){ | |||
| int y, x; | |||
| #define STORE(pos) \ | |||
| temp= ((src[x + y*src_stride + pos]<<log2_scale) + d[pos])>>8;\ | |||
| if(temp & 0x100) temp= ~(temp>>31);\ | |||
| dst[x + y*dst_stride + pos]= temp; | |||
| for(y=0; y<height; y++){ | |||
| const uint8_t *d= dither[y&7]; | |||
| for(x=0; x<width; x+=8){ | |||
| int temp; | |||
| STORE(0); | |||
| STORE(1); | |||
| STORE(2); | |||
| STORE(3); | |||
| STORE(4); | |||
| STORE(5); | |||
| STORE(6); | |||
| STORE(7); | |||
| } | |||
| } | |||
| } | |||
| static void filter(struct vf_priv_s *p, uint8_t *dst[3], uint8_t *src[3], int dst_stride[3], int src_stride[3], int width, int height, uint8_t *qp_store, int qp_stride){ | |||
| int x, y, i, j; | |||
| const int count= 1<<p->log2_count; | |||
| for(i=0; i<3; i++){ | |||
| int is_chroma= !!i; | |||
| int w= width >>is_chroma; | |||
| int h= height>>is_chroma; | |||
| int stride= p->temp_stride[i]; | |||
| int block= BLOCK>>is_chroma; | |||
| if (!src[i] || !dst[i]) | |||
| continue; // HACK avoid crash for Y8 colourspace | |||
| for(y=0; y<h; y++){ | |||
| int index= block + block*stride + y*stride; | |||
| fast_memcpy(p->src[i] + index, src[i] + y*src_stride[i], w); | |||
| for(x=0; x<block; x++){ | |||
| p->src[i][index - x - 1]= p->src[i][index + x ]; | |||
| p->src[i][index + w + x ]= p->src[i][index + w - x - 1]; | |||
| } | |||
| } | |||
| for(y=0; y<block; y++){ | |||
| fast_memcpy(p->src[i] + ( block-1-y)*stride, p->src[i] + ( y+block )*stride, stride); | |||
| fast_memcpy(p->src[i] + (h+block +y)*stride, p->src[i] + (h-y+block-1)*stride, stride); | |||
| } | |||
| p->frame->linesize[i]= stride; | |||
| memset(p->temp[i], 0, (h+2*block)*stride*sizeof(int16_t)); | |||
| } | |||
| if(p->qp) | |||
| p->frame->quality= p->qp * FF_QP2LAMBDA; | |||
| else | |||
| p->frame->quality= norm_qscale(qp_store[0], p->mpeg2) * FF_QP2LAMBDA; | |||
| // init per MB qscale stuff FIXME | |||
| for(i=0; i<count; i++){ | |||
| const int x1= offset[i+count-1][0]; | |||
| const int y1= offset[i+count-1][1]; | |||
| int offset, out_size; | |||
| p->frame->data[0]= p->src[0] + x1 + y1 * p->frame->linesize[0]; | |||
| p->frame->data[1]= p->src[1] + x1/2 + y1/2 * p->frame->linesize[1]; | |||
| p->frame->data[2]= p->src[2] + x1/2 + y1/2 * p->frame->linesize[2]; | |||
| out_size = avcodec_encode_video(p->avctx_enc[i], p->outbuf, p->outbuf_size, p->frame); | |||
| p->frame_dec = p->avctx_enc[i]->coded_frame; | |||
| offset= (BLOCK-x1) + (BLOCK-y1)*p->frame_dec->linesize[0]; | |||
| //FIXME optimize | |||
| for(y=0; y<height; y++){ | |||
| for(x=0; x<width; x++){ | |||
| p->temp[0][ x + y*p->temp_stride[0] ] += p->frame_dec->data[0][ x + y*p->frame_dec->linesize[0] + offset ]; | |||
| } | |||
| } | |||
| offset= (BLOCK/2-x1/2) + (BLOCK/2-y1/2)*p->frame_dec->linesize[1]; | |||
| for(y=0; y<height/2; y++){ | |||
| for(x=0; x<width/2; x++){ | |||
| p->temp[1][ x + y*p->temp_stride[1] ] += p->frame_dec->data[1][ x + y*p->frame_dec->linesize[1] + offset ]; | |||
| p->temp[2][ x + y*p->temp_stride[2] ] += p->frame_dec->data[2][ x + y*p->frame_dec->linesize[2] + offset ]; | |||
| } | |||
| } | |||
| } | |||
| for(j=0; j<3; j++){ | |||
| int is_chroma= !!j; | |||
| store_slice_c(dst[j], p->temp[j], dst_stride[j], p->temp_stride[j], width>>is_chroma, height>>is_chroma, 8-p->log2_count); | |||
| } | |||
| } | |||
| static int config(struct vf_instance *vf, | |||
| int width, int height, int d_width, int d_height, | |||
| unsigned int flags, unsigned int outfmt){ | |||
| int i; | |||
| AVCodec *enc= avcodec_find_encoder(CODEC_ID_SNOW); | |||
| for(i=0; i<3; i++){ | |||
| int is_chroma= !!i; | |||
| int w= ((width + 4*BLOCK-1) & (~(2*BLOCK-1)))>>is_chroma; | |||
| int h= ((height + 4*BLOCK-1) & (~(2*BLOCK-1)))>>is_chroma; | |||
| vf->priv->temp_stride[i]= w; | |||
| vf->priv->temp[i]= malloc(vf->priv->temp_stride[i]*h*sizeof(int16_t)); | |||
| vf->priv->src [i]= malloc(vf->priv->temp_stride[i]*h*sizeof(uint8_t)); | |||
| } | |||
| for(i=0; i< (1<<vf->priv->log2_count); i++){ | |||
| AVCodecContext *avctx_enc; | |||
| avctx_enc= | |||
| vf->priv->avctx_enc[i]= avcodec_alloc_context(); | |||
| avctx_enc->width = width + BLOCK; | |||
| avctx_enc->height = height + BLOCK; | |||
| avctx_enc->time_base= (AVRational){1,25}; // meaningless | |||
| avctx_enc->gop_size = 300; | |||
| avctx_enc->max_b_frames= 0; | |||
| avctx_enc->pix_fmt = PIX_FMT_YUV420P; | |||
| avctx_enc->flags = CODEC_FLAG_QSCALE | CODEC_FLAG_LOW_DELAY; | |||
| avctx_enc->strict_std_compliance = FF_COMPLIANCE_EXPERIMENTAL; | |||
| avctx_enc->global_quality= 123; | |||
| avcodec_open(avctx_enc, enc); | |||
| assert(avctx_enc->codec); | |||
| } | |||
| vf->priv->frame= avcodec_alloc_frame(); | |||
| vf->priv->frame_dec= avcodec_alloc_frame(); | |||
| vf->priv->outbuf_size= (width + BLOCK)*(height + BLOCK)*10; | |||
| vf->priv->outbuf= malloc(vf->priv->outbuf_size); | |||
| return vf_next_config(vf,width,height,d_width,d_height,flags,outfmt); | |||
| } | |||
| static void get_image(struct vf_instance *vf, mp_image_t *mpi){ | |||
| if(mpi->flags&MP_IMGFLAG_PRESERVE) return; // don't change | |||
| // ok, we can do pp in-place (or pp disabled): | |||
| vf->dmpi=vf_get_image(vf->next,mpi->imgfmt, | |||
| mpi->type, mpi->flags | MP_IMGFLAG_READABLE, mpi->width, mpi->height); | |||
| mpi->planes[0]=vf->dmpi->planes[0]; | |||
| mpi->stride[0]=vf->dmpi->stride[0]; | |||
| mpi->width=vf->dmpi->width; | |||
| if(mpi->flags&MP_IMGFLAG_PLANAR){ | |||
| mpi->planes[1]=vf->dmpi->planes[1]; | |||
| mpi->planes[2]=vf->dmpi->planes[2]; | |||
| mpi->stride[1]=vf->dmpi->stride[1]; | |||
| mpi->stride[2]=vf->dmpi->stride[2]; | |||
| } | |||
| mpi->flags|=MP_IMGFLAG_DIRECT; | |||
| } | |||
| static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts){ | |||
| mp_image_t *dmpi; | |||
| if(!(mpi->flags&MP_IMGFLAG_DIRECT)){ | |||
| // no DR, so get a new image! hope we'll get DR buffer: | |||
| dmpi=vf_get_image(vf->next,mpi->imgfmt, | |||
| MP_IMGTYPE_TEMP, | |||
| MP_IMGFLAG_ACCEPT_STRIDE|MP_IMGFLAG_PREFER_ALIGNED_STRIDE, | |||
| mpi->width,mpi->height); | |||
| vf_clone_mpi_attributes(dmpi, mpi); | |||
| }else{ | |||
| dmpi=vf->dmpi; | |||
| } | |||
| vf->priv->mpeg2= mpi->qscale_type; | |||
| if(vf->priv->log2_count || !(mpi->flags&MP_IMGFLAG_DIRECT)){ | |||
| if(mpi->qscale || vf->priv->qp){ | |||
| filter(vf->priv, dmpi->planes, mpi->planes, dmpi->stride, mpi->stride, mpi->w, mpi->h, mpi->qscale, mpi->qstride); | |||
| }else{ | |||
| memcpy_pic(dmpi->planes[0], mpi->planes[0], mpi->w, mpi->h, dmpi->stride[0], mpi->stride[0]); | |||
| memcpy_pic(dmpi->planes[1], mpi->planes[1], mpi->w>>mpi->chroma_x_shift, mpi->h>>mpi->chroma_y_shift, dmpi->stride[1], mpi->stride[1]); | |||
| memcpy_pic(dmpi->planes[2], mpi->planes[2], mpi->w>>mpi->chroma_x_shift, mpi->h>>mpi->chroma_y_shift, dmpi->stride[2], mpi->stride[2]); | |||
| } | |||
| } | |||
| #if HAVE_MMX | |||
| if(gCpuCaps.hasMMX) __asm__ volatile ("emms\n\t"); | |||
| #endif | |||
| #if HAVE_MMX2 | |||
| if(gCpuCaps.hasMMX2) __asm__ volatile ("sfence\n\t"); | |||
| #endif | |||
| return vf_next_put_image(vf,dmpi, pts); | |||
| } | |||
| static void uninit(struct vf_instance *vf){ | |||
| int i; | |||
| if(!vf->priv) return; | |||
| for(i=0; i<3; i++){ | |||
| free(vf->priv->temp[i]); | |||
| vf->priv->temp[i]= NULL; | |||
| free(vf->priv->src[i]); | |||
| vf->priv->src[i]= NULL; | |||
| } | |||
| for(i=0; i<BLOCK*BLOCK; i++){ | |||
| av_freep(&vf->priv->avctx_enc[i]); | |||
| } | |||
| free(vf->priv); | |||
| vf->priv=NULL; | |||
| } | |||
| //===========================================================================// | |||
| static int query_format(struct vf_instance *vf, unsigned int fmt){ | |||
| switch(fmt){ | |||
| case IMGFMT_YV12: | |||
| case IMGFMT_I420: | |||
| case IMGFMT_IYUV: | |||
| case IMGFMT_Y800: | |||
| case IMGFMT_Y8: | |||
| return vf_next_query_format(vf,fmt); | |||
| } | |||
| return 0; | |||
| } | |||
| static int control(struct vf_instance *vf, int request, void* data){ | |||
| switch(request){ | |||
| case VFCTRL_QUERY_MAX_PP_LEVEL: | |||
| return 8; | |||
| case VFCTRL_SET_PP_LEVEL: | |||
| vf->priv->log2_count= *((unsigned int*)data); | |||
| //FIXME we have to realloc a few things here | |||
| return CONTROL_TRUE; | |||
| } | |||
| return vf_next_control(vf,request,data); | |||
| } | |||
| static int vf_open(vf_instance_t *vf, char *args){ | |||
| int log2c=-1; | |||
| vf->config=config; | |||
| vf->put_image=put_image; | |||
| vf->get_image=get_image; | |||
| vf->query_format=query_format; | |||
| vf->uninit=uninit; | |||
| vf->control= control; | |||
| vf->priv=malloc(sizeof(struct vf_priv_s)); | |||
| memset(vf->priv, 0, sizeof(struct vf_priv_s)); | |||
| init_avcodec(); | |||
| vf->priv->log2_count= 4; | |||
| if (args) sscanf(args, "%d:%d:%d", &log2c, &vf->priv->qp, &vf->priv->mode); | |||
| if( log2c >=0 && log2c <=8 ) | |||
| vf->priv->log2_count = log2c; | |||
| if(vf->priv->qp < 0) | |||
| vf->priv->qp = 0; | |||
| // #if HAVE_MMX | |||
| // if(gCpuCaps.hasMMX){ | |||
| // store_slice= store_slice_mmx; | |||
| // } | |||
| // #endif | |||
| return 1; | |||
| } | |||
| const vf_info_t vf_info_uspp = { | |||
| "ultra simple/slow postprocess", | |||
| "uspp", | |||
| "Michael Niedermayer", | |||
| "", | |||
| vf_open, | |||
| NULL | |||
| }; | |||
| @@ -0,0 +1,120 @@ | |||
| /* | |||
| * This file is part of MPlayer. | |||
| * | |||
| * MPlayer 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. | |||
| * | |||
| * MPlayer 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 MPlayer; if not, write to the Free Software Foundation, Inc., | |||
| * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | |||
| */ | |||
| #include <stdio.h> | |||
| #include <stdlib.h> | |||
| #include <string.h> | |||
| #include <inttypes.h> | |||
| #include "config.h" | |||
| #include "mp_msg.h" | |||
| #include "img_format.h" | |||
| #include "mp_image.h" | |||
| #include "vf.h" | |||
| struct vf_priv_s { | |||
| int csp; | |||
| }; | |||
| //===========================================================================// | |||
| static int config(struct vf_instance *vf, | |||
| int width, int height, int d_width, int d_height, | |||
| unsigned int flags, unsigned int outfmt){ | |||
| return vf_next_config(vf, width, height, d_width, d_height, flags, outfmt); | |||
| } | |||
| static inline int clamp_y(int x){ | |||
| return (x > 235) ? 235 : (x < 16) ? 16 : x; | |||
| } | |||
| static inline int clamp_c(int x){ | |||
| return (x > 240) ? 240 : (x < 16) ? 16 : x; | |||
| } | |||
| static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts){ | |||
| int i,j; | |||
| uint8_t *y_in, *cb_in, *cr_in; | |||
| uint8_t *y_out, *cb_out, *cr_out; | |||
| vf->dmpi=vf_get_image(vf->next,mpi->imgfmt, | |||
| MP_IMGTYPE_TEMP, MP_IMGFLAG_ACCEPT_STRIDE, | |||
| mpi->width, mpi->height); | |||
| y_in = mpi->planes[0]; | |||
| cb_in = mpi->planes[1]; | |||
| cr_in = mpi->planes[2]; | |||
| y_out = vf->dmpi->planes[0]; | |||
| cb_out = vf->dmpi->planes[1]; | |||
| cr_out = vf->dmpi->planes[2]; | |||
| for (i = 0; i < mpi->height; i++) | |||
| for (j = 0; j < mpi->width; j++) | |||
| y_out[i*vf->dmpi->stride[0]+j] = clamp_y(y_in[i*mpi->stride[0]+j]); | |||
| for (i = 0; i < mpi->chroma_height; i++) | |||
| for (j = 0; j < mpi->chroma_width; j++) | |||
| { | |||
| cb_out[i*vf->dmpi->stride[1]+j] = clamp_c(cb_in[i*mpi->stride[1]+j]); | |||
| cr_out[i*vf->dmpi->stride[2]+j] = clamp_c(cr_in[i*mpi->stride[2]+j]); | |||
| } | |||
| return vf_next_put_image(vf,vf->dmpi, pts); | |||
| } | |||
| //===========================================================================// | |||
| /* | |||
| static void uninit(struct vf_instance *vf){ | |||
| free(vf->priv); | |||
| } | |||
| */ | |||
| static int query_format(struct vf_instance *vf, unsigned int fmt){ | |||
| switch(fmt){ | |||
| case IMGFMT_YV12: | |||
| case IMGFMT_I420: | |||
| case IMGFMT_IYUV: | |||
| return 1; | |||
| } | |||
| return 0; | |||
| } | |||
| static int vf_open(vf_instance_t *vf, char *args){ | |||
| vf->config=config; | |||
| vf->put_image=put_image; | |||
| // vf->uninit=uninit; | |||
| vf->query_format=query_format; | |||
| // vf->priv=calloc(1, sizeof(struct vf_priv_s)); | |||
| // if (args) | |||
| // vf->priv->csp = atoi(args); | |||
| return 1; | |||
| } | |||
| const vf_info_t vf_info_yuvcsp = { | |||
| "yuv colorspace converter", | |||
| "yuvcsp", | |||
| "Alex Beregszaszi", | |||
| "", | |||
| vf_open, | |||
| NULL | |||
| }; | |||
| //===========================================================================// | |||
| @@ -0,0 +1,105 @@ | |||
| /* | |||
| * This file is part of MPlayer. | |||
| * | |||
| * MPlayer 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. | |||
| * | |||
| * MPlayer 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 MPlayer; if not, write to the Free Software Foundation, Inc., | |||
| * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | |||
| */ | |||
| #include <stdio.h> | |||
| #include <stdlib.h> | |||
| #include <string.h> | |||
| #include <inttypes.h> | |||
| #include "config.h" | |||
| #include "mp_msg.h" | |||
| #include "help_mp.h" | |||
| #include "img_format.h" | |||
| #include "mp_image.h" | |||
| #include "vf.h" | |||
| #include "libvo/fastmemcpy.h" | |||
| //===========================================================================// | |||
| static int config(struct vf_instance *vf, | |||
| int width, int height, int d_width, int d_height, | |||
| unsigned int flags, unsigned int outfmt){ | |||
| if(vf_next_query_format(vf,IMGFMT_YV12)<=0){ | |||
| mp_msg(MSGT_VFILTER, MSGL_WARN, MSGTR_MPCODECS_WarnNextFilterDoesntSupport, "YVU9"); | |||
| return 0; | |||
| } | |||
| return vf_next_config(vf,width,height,d_width,d_height,flags,IMGFMT_YV12); | |||
| } | |||
| static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts){ | |||
| mp_image_t *dmpi; | |||
| int y,w,h; | |||
| // hope we'll get DR buffer: | |||
| dmpi=vf_get_image(vf->next,IMGFMT_YV12, | |||
| MP_IMGTYPE_TEMP, 0/*MP_IMGFLAG_ACCEPT_STRIDE*/, | |||
| mpi->w, mpi->h); | |||
| for(y=0;y<mpi->h;y++) | |||
| fast_memcpy(dmpi->planes[0]+dmpi->stride[0]*y, | |||
| mpi->planes[0]+mpi->stride[0]*y, | |||
| mpi->w); | |||
| w=mpi->w/4; h=mpi->h/2; | |||
| for(y=0;y<h;y++){ | |||
| unsigned char* s=mpi->planes[1]+mpi->stride[1]*(y>>1); | |||
| unsigned char* d=dmpi->planes[1]+dmpi->stride[1]*y; | |||
| int x; | |||
| for(x=0;x<w;x++) d[2*x]=d[2*x+1]=s[x]; | |||
| } | |||
| for(y=0;y<h;y++){ | |||
| unsigned char* s=mpi->planes[2]+mpi->stride[2]*(y>>1); | |||
| unsigned char* d=dmpi->planes[2]+dmpi->stride[2]*y; | |||
| int x; | |||
| for(x=0;x<w;x++) d[2*x]=d[2*x+1]=s[x]; | |||
| } | |||
| vf_clone_mpi_attributes(dmpi, mpi); | |||
| return vf_next_put_image(vf,dmpi, pts); | |||
| } | |||
| //===========================================================================// | |||
| static int query_format(struct vf_instance *vf, unsigned int fmt){ | |||
| if (fmt == IMGFMT_YVU9 || fmt == IMGFMT_IF09) | |||
| return vf_next_query_format(vf,IMGFMT_YV12) & (~VFCAP_CSP_SUPPORTED_BY_HW); | |||
| return 0; | |||
| } | |||
| static int vf_open(vf_instance_t *vf, char *args){ | |||
| vf->config=config; | |||
| vf->put_image=put_image; | |||
| vf->query_format=query_format; | |||
| return 1; | |||
| } | |||
| const vf_info_t vf_info_yvu9 = { | |||
| "fast YVU9->YV12 conversion", | |||
| "yvu9", | |||
| "alex", | |||
| "", | |||
| vf_open, | |||
| NULL | |||
| }; | |||
| //===========================================================================// | |||
| @@ -0,0 +1,56 @@ | |||
| /* VFCAP_* values: they are flags, returned by query_format(): | |||
| * | |||
| * This file is part of MPlayer. | |||
| * | |||
| * MPlayer 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. | |||
| * | |||
| * MPlayer 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 MPlayer; if not, write to the Free Software Foundation, Inc., | |||
| * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | |||
| */ | |||
| #ifndef MPLAYER_VFCAP_H | |||
| #define MPLAYER_VFCAP_H | |||
| // set, if the given colorspace is supported (with or without conversion) | |||
| #define VFCAP_CSP_SUPPORTED 0x1 | |||
| // set, if the given colorspace is supported _without_ conversion | |||
| #define VFCAP_CSP_SUPPORTED_BY_HW 0x2 | |||
| // set if the driver/filter can draw OSD | |||
| #define VFCAP_OSD 0x4 | |||
| // set if the driver/filter can handle compressed SPU stream | |||
| #define VFCAP_SPU 0x8 | |||
| // scaling up/down by hardware, or software: | |||
| #define VFCAP_HWSCALE_UP 0x10 | |||
| #define VFCAP_HWSCALE_DOWN 0x20 | |||
| #define VFCAP_SWSCALE 0x40 | |||
| // driver/filter can do vertical flip (upside-down) | |||
| #define VFCAP_FLIP 0x80 | |||
| // driver/hardware handles timing (blocking) | |||
| #define VFCAP_TIMER 0x100 | |||
| // driver _always_ flip image upside-down (for ve_vfw) | |||
| #define VFCAP_FLIPPED 0x200 | |||
| // vf filter: accepts stride (put_image) | |||
| // vo driver: has draw_slice() support for the given csp | |||
| #define VFCAP_ACCEPT_STRIDE 0x400 | |||
| // filter does postprocessing (so you shouldn't scale/filter image before it) | |||
| #define VFCAP_POSTPROC 0x800 | |||
| // filter cannot be reconfigured to different size & format | |||
| #define VFCAP_CONSTANT 0x1000 | |||
| // filter can draw EOSD | |||
| #define VFCAP_EOSD 0x2000 | |||
| // filter will draw EOSD at screen resolution (without scaling) | |||
| #define VFCAP_EOSD_UNSCALED 0x4000 | |||
| // used by libvo and vf_vo, indicates the VO does not support draw_slice for this format | |||
| #define VOCAP_NOSLICES 0x8000 | |||
| #endif /* MPLAYER_VFCAP_H */ | |||