Signed-off-by: Michael Niedermayer <michaelni@gmx.at>tags/n0.8
| @@ -38,7 +38,6 @@ | |||||
| #include "config.h" | #include "config.h" | ||||
| #include "ac3dec.h" | #include "ac3dec.h" | ||||
| #include "vorbis.h" | #include "vorbis.h" | ||||
| #include "png.h" | |||||
| uint8_t ff_cropTbl[256 + 2 * MAX_NEG_CROP] = {0, }; | uint8_t ff_cropTbl[256 + 2 * MAX_NEG_CROP] = {0, }; | ||||
| uint32_t ff_squareTbl[512] = {0, }; | uint32_t ff_squareTbl[512] = {0, }; | ||||
| @@ -1924,17 +1923,6 @@ static void add_bytes_c(uint8_t *dst, uint8_t *src, int w){ | |||||
| dst[i+0] += src[i+0]; | dst[i+0] += src[i+0]; | ||||
| } | } | ||||
| static void add_bytes_l2_c(uint8_t *dst, uint8_t *src1, uint8_t *src2, int w){ | |||||
| long i; | |||||
| for(i=0; i<=w-sizeof(long); i+=sizeof(long)){ | |||||
| long a = *(long*)(src1+i); | |||||
| long b = *(long*)(src2+i); | |||||
| *(long*)(dst+i) = ((a&pb_7f) + (b&pb_7f)) ^ ((a^b)&pb_80); | |||||
| } | |||||
| for(; i<w; i++) | |||||
| dst[i] = src1[i]+src2[i]; | |||||
| } | |||||
| static void diff_bytes_c(uint8_t *dst, uint8_t *src1, uint8_t *src2, int w){ | static void diff_bytes_c(uint8_t *dst, uint8_t *src1, uint8_t *src2, int w){ | ||||
| long i; | long i; | ||||
| #if !HAVE_FAST_UNALIGNED | #if !HAVE_FAST_UNALIGNED | ||||
| @@ -3087,7 +3075,6 @@ av_cold void dsputil_init(DSPContext* c, AVCodecContext *avctx) | |||||
| c->ssd_int8_vs_int16 = ssd_int8_vs_int16_c; | c->ssd_int8_vs_int16 = ssd_int8_vs_int16_c; | ||||
| c->add_bytes= add_bytes_c; | c->add_bytes= add_bytes_c; | ||||
| c->add_bytes_l2= add_bytes_l2_c; | |||||
| c->diff_bytes= diff_bytes_c; | c->diff_bytes= diff_bytes_c; | ||||
| c->add_hfyu_median_prediction= add_hfyu_median_prediction_c; | c->add_hfyu_median_prediction= add_hfyu_median_prediction_c; | ||||
| c->sub_hfyu_median_prediction= sub_hfyu_median_prediction_c; | c->sub_hfyu_median_prediction= sub_hfyu_median_prediction_c; | ||||
| @@ -3095,9 +3082,6 @@ av_cold void dsputil_init(DSPContext* c, AVCodecContext *avctx) | |||||
| c->add_hfyu_left_prediction_bgr32 = add_hfyu_left_prediction_bgr32_c; | c->add_hfyu_left_prediction_bgr32 = add_hfyu_left_prediction_bgr32_c; | ||||
| c->bswap_buf= bswap_buf; | c->bswap_buf= bswap_buf; | ||||
| c->bswap16_buf = bswap16_buf; | c->bswap16_buf = bswap16_buf; | ||||
| #if CONFIG_PNG_DECODER | |||||
| c->add_png_paeth_prediction= ff_add_png_paeth_prediction; | |||||
| #endif | |||||
| if (CONFIG_H263_DECODER || CONFIG_H263_ENCODER) { | if (CONFIG_H263_DECODER || CONFIG_H263_ENCODER) { | ||||
| c->h263_h_loop_filter= h263_h_loop_filter_c; | c->h263_h_loop_filter= h263_h_loop_filter_c; | ||||
| @@ -371,7 +371,6 @@ typedef struct DSPContext { | |||||
| /* huffyuv specific */ | /* huffyuv specific */ | ||||
| void (*add_bytes)(uint8_t *dst/*align 16*/, uint8_t *src/*align 16*/, int w); | void (*add_bytes)(uint8_t *dst/*align 16*/, uint8_t *src/*align 16*/, int w); | ||||
| void (*add_bytes_l2)(uint8_t *dst/*align 16*/, uint8_t *src1/*align 16*/, uint8_t *src2/*align 16*/, int w); | |||||
| void (*diff_bytes)(uint8_t *dst/*align 16*/, uint8_t *src1/*align 16*/, uint8_t *src2/*align 1*/,int w); | void (*diff_bytes)(uint8_t *dst/*align 16*/, uint8_t *src1/*align 16*/, uint8_t *src2/*align 1*/,int w); | ||||
| /** | /** | ||||
| * subtract huffyuv's variant of median prediction | * subtract huffyuv's variant of median prediction | ||||
| @@ -382,7 +381,6 @@ typedef struct DSPContext { | |||||
| int (*add_hfyu_left_prediction)(uint8_t *dst, const uint8_t *src, int w, int left); | int (*add_hfyu_left_prediction)(uint8_t *dst, const uint8_t *src, int w, int left); | ||||
| void (*add_hfyu_left_prediction_bgr32)(uint8_t *dst, const uint8_t *src, int w, int *red, int *green, int *blue, int *alpha); | void (*add_hfyu_left_prediction_bgr32)(uint8_t *dst, const uint8_t *src, int w, int *red, int *green, int *blue, int *alpha); | ||||
| /* this might write to dst[w] */ | /* this might write to dst[w] */ | ||||
| void (*add_png_paeth_prediction)(uint8_t *dst, uint8_t *src, uint8_t *top, int w, int bpp); | |||||
| void (*bswap_buf)(uint32_t *dst, const uint32_t *src, int w); | void (*bswap_buf)(uint32_t *dst, const uint32_t *src, int w); | ||||
| void (*bswap16_buf)(uint16_t *dst, const uint16_t *src, int len); | void (*bswap16_buf)(uint16_t *dst, const uint16_t *src, int len); | ||||
| @@ -23,6 +23,9 @@ | |||||
| #define AVCODEC_PNG_H | #define AVCODEC_PNG_H | ||||
| #include <stdint.h> | #include <stdint.h> | ||||
| #include <zlib.h> | |||||
| #include "avcodec.h" | |||||
| #define PNG_COLOR_MASK_PALETTE 1 | #define PNG_COLOR_MASK_PALETTE 1 | ||||
| #define PNG_COLOR_MASK_COLOR 2 | #define PNG_COLOR_MASK_COLOR 2 | ||||
| @@ -69,4 +72,41 @@ int ff_png_pass_row_size(int pass, int bits_per_pixel, int width); | |||||
| void ff_add_png_paeth_prediction(uint8_t *dst, uint8_t *src, uint8_t *top, int w, int bpp); | void ff_add_png_paeth_prediction(uint8_t *dst, uint8_t *src, uint8_t *top, int w, int bpp); | ||||
| typedef struct PNGDecContext { | |||||
| const uint8_t *bytestream; | |||||
| const uint8_t *bytestream_start; | |||||
| const uint8_t *bytestream_end; | |||||
| AVFrame picture1, picture2; | |||||
| AVFrame *current_picture, *last_picture; | |||||
| int state; | |||||
| int width, height; | |||||
| int bit_depth; | |||||
| int color_type; | |||||
| int compression_type; | |||||
| int interlace_type; | |||||
| int filter_type; | |||||
| int channels; | |||||
| int bits_per_pixel; | |||||
| int bpp; | |||||
| uint8_t *image_buf; | |||||
| int image_linesize; | |||||
| uint32_t palette[256]; | |||||
| uint8_t *crow_buf; | |||||
| uint8_t *last_row; | |||||
| uint8_t *tmp_row; | |||||
| int pass; | |||||
| int crow_size; /* compressed row size (include filter type) */ | |||||
| int row_size; /* decompressed row size */ | |||||
| int pass_row_size; /* decompress row size of the current pass */ | |||||
| int y; | |||||
| z_stream zstream; | |||||
| void (*add_bytes_l2)(uint8_t *dst, uint8_t *src1, uint8_t *src2, int w); | |||||
| void (*add_paeth_prediction)(uint8_t *dst, uint8_t *src, uint8_t *top, int w, int bpp); | |||||
| } PNGDecContext; | |||||
| void ff_png_init_mmx(PNGDecContext *s); | |||||
| #endif /* AVCODEC_PNG_H */ | #endif /* AVCODEC_PNG_H */ | ||||
| @@ -18,11 +18,13 @@ | |||||
| * License along with FFmpeg; if not, write to the Free Software | * License along with FFmpeg; if not, write to the Free Software | ||||
| * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | ||||
| */ | */ | ||||
| //#define DEBUG | |||||
| #include "libavutil/imgutils.h" | #include "libavutil/imgutils.h" | ||||
| #include "avcodec.h" | #include "avcodec.h" | ||||
| #include "bytestream.h" | #include "bytestream.h" | ||||
| #include "png.h" | #include "png.h" | ||||
| #include "dsputil.h" | |||||
| /* TODO: | /* TODO: | ||||
| * - add 2, 4 and 16 bit depth support | * - add 2, 4 and 16 bit depth support | ||||
| @@ -30,42 +32,6 @@ | |||||
| #include <zlib.h> | #include <zlib.h> | ||||
| //#define DEBUG | |||||
| typedef struct PNGDecContext { | |||||
| DSPContext dsp; | |||||
| const uint8_t *bytestream; | |||||
| const uint8_t *bytestream_start; | |||||
| const uint8_t *bytestream_end; | |||||
| AVFrame picture1, picture2; | |||||
| AVFrame *current_picture, *last_picture; | |||||
| int state; | |||||
| int width, height; | |||||
| int bit_depth; | |||||
| int color_type; | |||||
| int compression_type; | |||||
| int interlace_type; | |||||
| int filter_type; | |||||
| int channels; | |||||
| int bits_per_pixel; | |||||
| int bpp; | |||||
| uint8_t *image_buf; | |||||
| int image_linesize; | |||||
| uint32_t palette[256]; | |||||
| uint8_t *crow_buf; | |||||
| uint8_t *last_row; | |||||
| uint8_t *tmp_row; | |||||
| int pass; | |||||
| int crow_size; /* compressed row size (include filter type) */ | |||||
| int row_size; /* decompressed row size */ | |||||
| int pass_row_size; /* decompress row size of the current pass */ | |||||
| int y; | |||||
| z_stream zstream; | |||||
| } PNGDecContext; | |||||
| /* Mask to determine which y pixels can be written in a pass */ | /* Mask to determine which y pixels can be written in a pass */ | ||||
| static const uint8_t png_pass_dsp_ymask[NB_PASSES] = { | static const uint8_t png_pass_dsp_ymask[NB_PASSES] = { | ||||
| 0xff, 0xff, 0x0f, 0xcc, 0x33, 0xff, 0x55, | 0xff, 0xff, 0x0f, 0xcc, 0x33, 0xff, 0x55, | ||||
| @@ -134,7 +100,23 @@ static void png_put_interlaced_row(uint8_t *dst, int width, | |||||
| } | } | ||||
| } | } | ||||
| void ff_add_png_paeth_prediction(uint8_t *dst, uint8_t *src, uint8_t *top, int w, int bpp) | |||||
| // 0x7f7f7f7f or 0x7f7f7f7f7f7f7f7f or whatever, depending on the cpu's native arithmetic size | |||||
| #define pb_7f (~0UL/255 * 0x7f) | |||||
| #define pb_80 (~0UL/255 * 0x80) | |||||
| static void add_bytes_l2_c(uint8_t *dst, uint8_t *src1, uint8_t *src2, int w) | |||||
| { | |||||
| long i; | |||||
| for(i=0; i<=w-sizeof(long); i+=sizeof(long)){ | |||||
| long a = *(long*)(src1+i); | |||||
| long b = *(long*)(src2+i); | |||||
| *(long*)(dst+i) = ((a&pb_7f) + (b&pb_7f)) ^ ((a^b)&pb_80); | |||||
| } | |||||
| for(; i<w; i++) | |||||
| dst[i] = src1[i]+src2[i]; | |||||
| } | |||||
| static void add_paeth_prediction_c(uint8_t *dst, uint8_t *src, uint8_t *top, int w, int bpp) | |||||
| { | { | ||||
| int i; | int i; | ||||
| for(i = 0; i < w; i++) { | for(i = 0; i < w; i++) { | ||||
| @@ -191,7 +173,7 @@ void ff_add_png_paeth_prediction(uint8_t *dst, uint8_t *src, uint8_t *top, int w | |||||
| } | } | ||||
| /* NOTE: 'dst' can be equal to 'last' */ | /* NOTE: 'dst' can be equal to 'last' */ | ||||
| static void png_filter_row(DSPContext *dsp, uint8_t *dst, int filter_type, | |||||
| static void png_filter_row(PNGDecContext *s, uint8_t *dst, int filter_type, | |||||
| uint8_t *src, uint8_t *last, int size, int bpp) | uint8_t *src, uint8_t *last, int size, int bpp) | ||||
| { | { | ||||
| int i, p, r, g, b, a; | int i, p, r, g, b, a; | ||||
| @@ -217,7 +199,7 @@ static void png_filter_row(DSPContext *dsp, uint8_t *dst, int filter_type, | |||||
| } | } | ||||
| break; | break; | ||||
| case PNG_FILTER_VALUE_UP: | case PNG_FILTER_VALUE_UP: | ||||
| dsp->add_bytes_l2(dst, src, last, size); | |||||
| s->add_bytes_l2(dst, src, last, size); | |||||
| break; | break; | ||||
| case PNG_FILTER_VALUE_AVG: | case PNG_FILTER_VALUE_AVG: | ||||
| for(i = 0; i < bpp; i++) { | for(i = 0; i < bpp; i++) { | ||||
| @@ -235,10 +217,10 @@ static void png_filter_row(DSPContext *dsp, uint8_t *dst, int filter_type, | |||||
| if(bpp > 1 && size > 4) { | if(bpp > 1 && size > 4) { | ||||
| // would write off the end of the array if we let it process the last pixel with bpp=3 | // would write off the end of the array if we let it process the last pixel with bpp=3 | ||||
| int w = bpp==4 ? size : size-3; | int w = bpp==4 ? size : size-3; | ||||
| dsp->add_png_paeth_prediction(dst+i, src+i, last+i, w-i, bpp); | |||||
| s->add_paeth_prediction(dst+i, src+i, last+i, w-i, bpp); | |||||
| i = w; | i = w; | ||||
| } | } | ||||
| ff_add_png_paeth_prediction(dst+i, src+i, last+i, size-i, bpp); | |||||
| add_paeth_prediction_c(dst+i, src+i, last+i, size-i, bpp); | |||||
| break; | break; | ||||
| } | } | ||||
| } | } | ||||
| @@ -291,7 +273,7 @@ static void png_handle_row(PNGDecContext *s) | |||||
| ptr = s->image_buf + s->image_linesize * s->y; | ptr = s->image_buf + s->image_linesize * s->y; | ||||
| /* need to swap bytes correctly for RGB_ALPHA */ | /* need to swap bytes correctly for RGB_ALPHA */ | ||||
| if (s->color_type == PNG_COLOR_TYPE_RGB_ALPHA) { | if (s->color_type == PNG_COLOR_TYPE_RGB_ALPHA) { | ||||
| png_filter_row(&s->dsp, s->tmp_row, s->crow_buf[0], s->crow_buf + 1, | |||||
| png_filter_row(s, s->tmp_row, s->crow_buf[0], s->crow_buf + 1, | |||||
| s->last_row, s->row_size, s->bpp); | s->last_row, s->row_size, s->bpp); | ||||
| convert_to_rgb32(ptr, s->tmp_row, s->width, s->filter_type == PNG_FILTER_TYPE_LOCO); | convert_to_rgb32(ptr, s->tmp_row, s->width, s->filter_type == PNG_FILTER_TYPE_LOCO); | ||||
| FFSWAP(uint8_t*, s->last_row, s->tmp_row); | FFSWAP(uint8_t*, s->last_row, s->tmp_row); | ||||
| @@ -302,7 +284,7 @@ static void png_handle_row(PNGDecContext *s) | |||||
| else | else | ||||
| last_row = ptr - s->image_linesize; | last_row = ptr - s->image_linesize; | ||||
| png_filter_row(&s->dsp, ptr, s->crow_buf[0], s->crow_buf + 1, | |||||
| png_filter_row(s, ptr, s->crow_buf[0], s->crow_buf + 1, | |||||
| last_row, s->row_size, s->bpp); | last_row, s->row_size, s->bpp); | ||||
| } | } | ||||
| /* loco lags by 1 row so that it doesn't interfere with top prediction */ | /* loco lags by 1 row so that it doesn't interfere with top prediction */ | ||||
| @@ -325,7 +307,7 @@ static void png_handle_row(PNGDecContext *s) | |||||
| wait for the next one */ | wait for the next one */ | ||||
| if (got_line) | if (got_line) | ||||
| break; | break; | ||||
| png_filter_row(&s->dsp, s->tmp_row, s->crow_buf[0], s->crow_buf + 1, | |||||
| png_filter_row(s, s->tmp_row, s->crow_buf[0], s->crow_buf + 1, | |||||
| s->last_row, s->pass_row_size, s->bpp); | s->last_row, s->pass_row_size, s->bpp); | ||||
| FFSWAP(uint8_t*, s->last_row, s->tmp_row); | FFSWAP(uint8_t*, s->last_row, s->tmp_row); | ||||
| got_line = 1; | got_line = 1; | ||||
| @@ -633,14 +615,21 @@ static int decode_frame(AVCodecContext *avctx, | |||||
| goto the_end; | goto the_end; | ||||
| } | } | ||||
| static av_cold int png_dec_init(AVCodecContext *avctx){ | |||||
| static av_cold int png_dec_init(AVCodecContext *avctx) | |||||
| { | |||||
| PNGDecContext *s = avctx->priv_data; | PNGDecContext *s = avctx->priv_data; | ||||
| s->current_picture = &s->picture1; | s->current_picture = &s->picture1; | ||||
| s->last_picture = &s->picture2; | s->last_picture = &s->picture2; | ||||
| avcodec_get_frame_defaults(&s->picture1); | avcodec_get_frame_defaults(&s->picture1); | ||||
| avcodec_get_frame_defaults(&s->picture2); | avcodec_get_frame_defaults(&s->picture2); | ||||
| dsputil_init(&s->dsp, avctx); | |||||
| ff_png_init_mmx(s); | |||||
| if (!s->add_paeth_prediction) | |||||
| s->add_paeth_prediction = add_paeth_prediction_c; | |||||
| if (!s->add_bytes_l2) | |||||
| s->add_bytes_l2 = add_bytes_l2_c; | |||||
| return 0; | return 0; | ||||
| } | } | ||||
| @@ -25,6 +25,7 @@ MMX-OBJS-$(CONFIG_MP2FLOAT_DECODER) += x86/mpegaudiodec_mmx.o | |||||
| MMX-OBJS-$(CONFIG_MP3FLOAT_DECODER) += x86/mpegaudiodec_mmx.o | MMX-OBJS-$(CONFIG_MP3FLOAT_DECODER) += x86/mpegaudiodec_mmx.o | ||||
| MMX-OBJS-$(CONFIG_MP3ON4FLOAT_DECODER) += x86/mpegaudiodec_mmx.o | MMX-OBJS-$(CONFIG_MP3ON4FLOAT_DECODER) += x86/mpegaudiodec_mmx.o | ||||
| MMX-OBJS-$(CONFIG_MP3ADUFLOAT_DECODER) += x86/mpegaudiodec_mmx.o | MMX-OBJS-$(CONFIG_MP3ADUFLOAT_DECODER) += x86/mpegaudiodec_mmx.o | ||||
| MMX-OBJS-$(CONFIG_PNG_DECODER) += x86/png_mmx.o | |||||
| MMX-OBJS-$(CONFIG_ENCODERS) += x86/dsputilenc_mmx.o | MMX-OBJS-$(CONFIG_ENCODERS) += x86/dsputilenc_mmx.o | ||||
| YASM-OBJS-$(CONFIG_ENCODERS) += x86/dsputilenc_yasm.o | YASM-OBJS-$(CONFIG_ENCODERS) += x86/dsputilenc_yasm.o | ||||
| MMX-OBJS-$(CONFIG_GPL) += x86/idct_mmx.o | MMX-OBJS-$(CONFIG_GPL) += x86/idct_mmx.o | ||||
| @@ -579,28 +579,6 @@ static void add_bytes_mmx(uint8_t *dst, uint8_t *src, int w){ | |||||
| dst[i+0] += src[i+0]; | dst[i+0] += src[i+0]; | ||||
| } | } | ||||
| static void add_bytes_l2_mmx(uint8_t *dst, uint8_t *src1, uint8_t *src2, int w){ | |||||
| x86_reg i=0; | |||||
| __asm__ volatile( | |||||
| "jmp 2f \n\t" | |||||
| "1: \n\t" | |||||
| "movq (%2, %0), %%mm0 \n\t" | |||||
| "movq 8(%2, %0), %%mm1 \n\t" | |||||
| "paddb (%3, %0), %%mm0 \n\t" | |||||
| "paddb 8(%3, %0), %%mm1 \n\t" | |||||
| "movq %%mm0, (%1, %0) \n\t" | |||||
| "movq %%mm1, 8(%1, %0) \n\t" | |||||
| "add $16, %0 \n\t" | |||||
| "2: \n\t" | |||||
| "cmp %4, %0 \n\t" | |||||
| " js 1b \n\t" | |||||
| : "+r" (i) | |||||
| : "r"(dst), "r"(src1), "r"(src2), "r"((x86_reg)w-15) | |||||
| ); | |||||
| for(; i<w; i++) | |||||
| dst[i] = src1[i] + src2[i]; | |||||
| } | |||||
| #if HAVE_7REGS && HAVE_TEN_OPERANDS | #if HAVE_7REGS && HAVE_TEN_OPERANDS | ||||
| static void add_hfyu_median_prediction_cmov(uint8_t *dst, const uint8_t *top, const uint8_t *diff, int w, int *left, int *left_top) { | static void add_hfyu_median_prediction_cmov(uint8_t *dst, const uint8_t *top, const uint8_t *diff, int w, int *left, int *left_top) { | ||||
| x86_reg w2 = -w; | x86_reg w2 = -w; | ||||
| @@ -876,80 +854,6 @@ static void draw_edges_mmx(uint8_t *buf, int wrap, int width, int height, int w, | |||||
| } | } | ||||
| } | } | ||||
| #define PAETH(cpu, abs3)\ | |||||
| static void add_png_paeth_prediction_##cpu(uint8_t *dst, uint8_t *src, uint8_t *top, int w, int bpp)\ | |||||
| {\ | |||||
| x86_reg i = -bpp;\ | |||||
| x86_reg end = w-3;\ | |||||
| __asm__ volatile(\ | |||||
| "pxor %%mm7, %%mm7 \n"\ | |||||
| "movd (%1,%0), %%mm0 \n"\ | |||||
| "movd (%2,%0), %%mm1 \n"\ | |||||
| "punpcklbw %%mm7, %%mm0 \n"\ | |||||
| "punpcklbw %%mm7, %%mm1 \n"\ | |||||
| "add %4, %0 \n"\ | |||||
| "1: \n"\ | |||||
| "movq %%mm1, %%mm2 \n"\ | |||||
| "movd (%2,%0), %%mm1 \n"\ | |||||
| "movq %%mm2, %%mm3 \n"\ | |||||
| "punpcklbw %%mm7, %%mm1 \n"\ | |||||
| "movq %%mm2, %%mm4 \n"\ | |||||
| "psubw %%mm1, %%mm3 \n"\ | |||||
| "psubw %%mm0, %%mm4 \n"\ | |||||
| "movq %%mm3, %%mm5 \n"\ | |||||
| "paddw %%mm4, %%mm5 \n"\ | |||||
| abs3\ | |||||
| "movq %%mm4, %%mm6 \n"\ | |||||
| "pminsw %%mm5, %%mm6 \n"\ | |||||
| "pcmpgtw %%mm6, %%mm3 \n"\ | |||||
| "pcmpgtw %%mm5, %%mm4 \n"\ | |||||
| "movq %%mm4, %%mm6 \n"\ | |||||
| "pand %%mm3, %%mm4 \n"\ | |||||
| "pandn %%mm3, %%mm6 \n"\ | |||||
| "pandn %%mm0, %%mm3 \n"\ | |||||
| "movd (%3,%0), %%mm0 \n"\ | |||||
| "pand %%mm1, %%mm6 \n"\ | |||||
| "pand %%mm4, %%mm2 \n"\ | |||||
| "punpcklbw %%mm7, %%mm0 \n"\ | |||||
| "movq %6, %%mm5 \n"\ | |||||
| "paddw %%mm6, %%mm0 \n"\ | |||||
| "paddw %%mm2, %%mm3 \n"\ | |||||
| "paddw %%mm3, %%mm0 \n"\ | |||||
| "pand %%mm5, %%mm0 \n"\ | |||||
| "movq %%mm0, %%mm3 \n"\ | |||||
| "packuswb %%mm3, %%mm3 \n"\ | |||||
| "movd %%mm3, (%1,%0) \n"\ | |||||
| "add %4, %0 \n"\ | |||||
| "cmp %5, %0 \n"\ | |||||
| "jle 1b \n"\ | |||||
| :"+r"(i)\ | |||||
| :"r"(dst), "r"(top), "r"(src), "r"((x86_reg)bpp), "g"(end),\ | |||||
| "m"(ff_pw_255)\ | |||||
| :"memory"\ | |||||
| );\ | |||||
| } | |||||
| #define ABS3_MMX2\ | |||||
| "psubw %%mm5, %%mm7 \n"\ | |||||
| "pmaxsw %%mm7, %%mm5 \n"\ | |||||
| "pxor %%mm6, %%mm6 \n"\ | |||||
| "pxor %%mm7, %%mm7 \n"\ | |||||
| "psubw %%mm3, %%mm6 \n"\ | |||||
| "psubw %%mm4, %%mm7 \n"\ | |||||
| "pmaxsw %%mm6, %%mm3 \n"\ | |||||
| "pmaxsw %%mm7, %%mm4 \n"\ | |||||
| "pxor %%mm7, %%mm7 \n" | |||||
| #define ABS3_SSSE3\ | |||||
| "pabsw %%mm3, %%mm3 \n"\ | |||||
| "pabsw %%mm4, %%mm4 \n"\ | |||||
| "pabsw %%mm5, %%mm5 \n" | |||||
| PAETH(mmx2, ABS3_MMX2) | |||||
| #if HAVE_SSSE3 | |||||
| PAETH(ssse3, ABS3_SSSE3) | |||||
| #endif | |||||
| #define QPEL_V_LOW(m3,m4,m5,m6, pw_20, pw_3, rnd, in0, in1, in2, in7, out, OP)\ | #define QPEL_V_LOW(m3,m4,m5,m6, pw_20, pw_3, rnd, in0, in1, in2, in7, out, OP)\ | ||||
| "paddw " #m4 ", " #m3 " \n\t" /* x1 */\ | "paddw " #m4 ", " #m3 " \n\t" /* x1 */\ | ||||
| "movq "MANGLE(ff_pw_20)", %%mm4 \n\t" /* 20 */\ | "movq "MANGLE(ff_pw_20)", %%mm4 \n\t" /* 20 */\ | ||||
| @@ -2537,7 +2441,6 @@ void dsputil_init_mmx(DSPContext* c, AVCodecContext *avctx) | |||||
| #endif | #endif | ||||
| c->add_bytes= add_bytes_mmx; | c->add_bytes= add_bytes_mmx; | ||||
| c->add_bytes_l2= add_bytes_l2_mmx; | |||||
| if (!h264_high_depth) | if (!h264_high_depth) | ||||
| c->draw_edges = draw_edges_mmx; | c->draw_edges = draw_edges_mmx; | ||||
| @@ -2658,7 +2561,6 @@ void dsputil_init_mmx(DSPContext* c, AVCodecContext *avctx) | |||||
| c->add_hfyu_median_prediction = add_hfyu_median_prediction_cmov; | c->add_hfyu_median_prediction = add_hfyu_median_prediction_cmov; | ||||
| #endif | #endif | ||||
| c->add_png_paeth_prediction= add_png_paeth_prediction_mmx2; | |||||
| } else if (mm_flags & AV_CPU_FLAG_3DNOW) { | } else if (mm_flags & AV_CPU_FLAG_3DNOW) { | ||||
| c->prefetch = prefetch_3dnow; | c->prefetch = prefetch_3dnow; | ||||
| @@ -2772,7 +2674,6 @@ void dsputil_init_mmx(DSPContext* c, AVCodecContext *avctx) | |||||
| H264_QPEL_FUNCS(3, 2, ssse3); | H264_QPEL_FUNCS(3, 2, ssse3); | ||||
| H264_QPEL_FUNCS(3, 3, ssse3); | H264_QPEL_FUNCS(3, 3, ssse3); | ||||
| } | } | ||||
| c->add_png_paeth_prediction= add_png_paeth_prediction_ssse3; | |||||
| #if HAVE_YASM | #if HAVE_YASM | ||||
| if (!h264_high_depth) { | if (!h264_high_depth) { | ||||
| c->put_h264_chroma_pixels_tab[0]= ff_put_h264_chroma_mc8_ssse3_rnd; | c->put_h264_chroma_pixels_tab[0]= ff_put_h264_chroma_mc8_ssse3_rnd; | ||||
| @@ -0,0 +1,141 @@ | |||||
| /* | |||||
| * MMX optimized PNG utils | |||||
| * Copyright (c) 2008 Loren Merritt | |||||
| * | |||||
| * This file is part of FFmpeg. | |||||
| * | |||||
| * FFmpeg 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. | |||||
| * | |||||
| * FFmpeg 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 FFmpeg; if not, write to the Free Software | |||||
| * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | |||||
| * | |||||
| */ | |||||
| #include "libavutil/cpu.h" | |||||
| #include "libavutil/x86_cpu.h" | |||||
| #include "libavcodec/dsputil.h" | |||||
| #include "libavcodec/png.h" | |||||
| #include "dsputil_mmx.h" | |||||
| //#undef NDEBUG | |||||
| //#include <assert.h> | |||||
| static void add_bytes_l2_mmx(uint8_t *dst, uint8_t *src1, uint8_t *src2, int w) | |||||
| { | |||||
| x86_reg i=0; | |||||
| __asm__ volatile( | |||||
| "jmp 2f \n\t" | |||||
| "1: \n\t" | |||||
| "movq (%2, %0), %%mm0 \n\t" | |||||
| "movq 8(%2, %0), %%mm1 \n\t" | |||||
| "paddb (%3, %0), %%mm0 \n\t" | |||||
| "paddb 8(%3, %0), %%mm1 \n\t" | |||||
| "movq %%mm0, (%1, %0) \n\t" | |||||
| "movq %%mm1, 8(%1, %0) \n\t" | |||||
| "add $16, %0 \n\t" | |||||
| "2: \n\t" | |||||
| "cmp %4, %0 \n\t" | |||||
| " js 1b \n\t" | |||||
| : "+r" (i) | |||||
| : "r"(dst), "r"(src1), "r"(src2), "r"((x86_reg)w-15) | |||||
| ); | |||||
| for(; i<w; i++) | |||||
| dst[i] = src1[i] + src2[i]; | |||||
| } | |||||
| #define PAETH(cpu, abs3)\ | |||||
| static void add_paeth_prediction_##cpu(uint8_t *dst, uint8_t *src, uint8_t *top, int w, int bpp)\ | |||||
| {\ | |||||
| x86_reg i = -bpp;\ | |||||
| x86_reg end = w-3;\ | |||||
| __asm__ volatile(\ | |||||
| "pxor %%mm7, %%mm7 \n"\ | |||||
| "movd (%1,%0), %%mm0 \n"\ | |||||
| "movd (%2,%0), %%mm1 \n"\ | |||||
| "punpcklbw %%mm7, %%mm0 \n"\ | |||||
| "punpcklbw %%mm7, %%mm1 \n"\ | |||||
| "add %4, %0 \n"\ | |||||
| "1: \n"\ | |||||
| "movq %%mm1, %%mm2 \n"\ | |||||
| "movd (%2,%0), %%mm1 \n"\ | |||||
| "movq %%mm2, %%mm3 \n"\ | |||||
| "punpcklbw %%mm7, %%mm1 \n"\ | |||||
| "movq %%mm2, %%mm4 \n"\ | |||||
| "psubw %%mm1, %%mm3 \n"\ | |||||
| "psubw %%mm0, %%mm4 \n"\ | |||||
| "movq %%mm3, %%mm5 \n"\ | |||||
| "paddw %%mm4, %%mm5 \n"\ | |||||
| abs3\ | |||||
| "movq %%mm4, %%mm6 \n"\ | |||||
| "pminsw %%mm5, %%mm6 \n"\ | |||||
| "pcmpgtw %%mm6, %%mm3 \n"\ | |||||
| "pcmpgtw %%mm5, %%mm4 \n"\ | |||||
| "movq %%mm4, %%mm6 \n"\ | |||||
| "pand %%mm3, %%mm4 \n"\ | |||||
| "pandn %%mm3, %%mm6 \n"\ | |||||
| "pandn %%mm0, %%mm3 \n"\ | |||||
| "movd (%3,%0), %%mm0 \n"\ | |||||
| "pand %%mm1, %%mm6 \n"\ | |||||
| "pand %%mm4, %%mm2 \n"\ | |||||
| "punpcklbw %%mm7, %%mm0 \n"\ | |||||
| "movq %6, %%mm5 \n"\ | |||||
| "paddw %%mm6, %%mm0 \n"\ | |||||
| "paddw %%mm2, %%mm3 \n"\ | |||||
| "paddw %%mm3, %%mm0 \n"\ | |||||
| "pand %%mm5, %%mm0 \n"\ | |||||
| "movq %%mm0, %%mm3 \n"\ | |||||
| "packuswb %%mm3, %%mm3 \n"\ | |||||
| "movd %%mm3, (%1,%0) \n"\ | |||||
| "add %4, %0 \n"\ | |||||
| "cmp %5, %0 \n"\ | |||||
| "jle 1b \n"\ | |||||
| :"+r"(i)\ | |||||
| :"r"(dst), "r"(top), "r"(src), "r"((x86_reg)bpp), "g"(end),\ | |||||
| "m"(ff_pw_255)\ | |||||
| :"memory"\ | |||||
| );\ | |||||
| } | |||||
| #define ABS3_MMX2\ | |||||
| "psubw %%mm5, %%mm7 \n"\ | |||||
| "pmaxsw %%mm7, %%mm5 \n"\ | |||||
| "pxor %%mm6, %%mm6 \n"\ | |||||
| "pxor %%mm7, %%mm7 \n"\ | |||||
| "psubw %%mm3, %%mm6 \n"\ | |||||
| "psubw %%mm4, %%mm7 \n"\ | |||||
| "pmaxsw %%mm6, %%mm3 \n"\ | |||||
| "pmaxsw %%mm7, %%mm4 \n"\ | |||||
| "pxor %%mm7, %%mm7 \n" | |||||
| #define ABS3_SSSE3\ | |||||
| "pabsw %%mm3, %%mm3 \n"\ | |||||
| "pabsw %%mm4, %%mm4 \n"\ | |||||
| "pabsw %%mm5, %%mm5 \n" | |||||
| PAETH(mmx2, ABS3_MMX2) | |||||
| #if HAVE_SSSE3 | |||||
| PAETH(ssse3, ABS3_SSSE3) | |||||
| #endif | |||||
| void ff_png_init_mmx(PNGDecContext *s) | |||||
| { | |||||
| int mm_flags = av_get_cpu_flags(); | |||||
| if (mm_flags & AV_CPU_FLAG_MMX2) { | |||||
| s->add_bytes_l2 = add_bytes_l2_mmx; | |||||
| s->add_paeth_prediction = add_paeth_prediction_mmx2; | |||||
| #if HAVE_SSSE3 | |||||
| if (mm_flags & AV_CPU_FLAG_SSSE3) | |||||
| s->add_paeth_prediction = add_paeth_prediction_ssse3; | |||||
| #endif | |||||
| } | |||||
| } | |||||