Skip to content
Snippets Groups Projects
utils.c 56.6 KiB
Newer Older
  • Learn to ignore specific revisions
  •     } // initialize horizontal stuff
    
        /* precalculate vertical scaler filter coefficients */
        {
            const int filterAlign=
                (flags & SWS_CPU_CAPS_MMX) && (flags & SWS_ACCURATE_RND) ? 2 :
                (flags & SWS_CPU_CAPS_ALTIVEC) ? 8 :
                1;
    
            if (initFilter(&c->vLumFilter, &c->vLumFilterPos, &c->vLumFilterSize, c->lumYInc,
                           srcH      ,        dstH, filterAlign, (1<<12),
                           (flags&SWS_BICUBLIN) ? (flags|SWS_BICUBIC)  : flags,
                           srcFilter->lumV, dstFilter->lumV, c->param) < 0)
                goto fail;
            if (initFilter(&c->vChrFilter, &c->vChrFilterPos, &c->vChrFilterSize, c->chrYInc,
                           c->chrSrcH, c->chrDstH, filterAlign, (1<<12),
                           (flags&SWS_BICUBLIN) ? (flags|SWS_BILINEAR) : flags,
                           srcFilter->chrV, dstFilter->chrV, c->param) < 0)
                goto fail;
    
    
            FF_ALLOC_OR_GOTO(c, c->vYCoeffsBank, sizeof (vector signed short)*c->vLumFilterSize*c->dstH, fail);
            FF_ALLOC_OR_GOTO(c, c->vCCoeffsBank, sizeof (vector signed short)*c->vChrFilterSize*c->chrDstH, fail);
    
            for (i=0;i<c->vLumFilterSize*c->dstH;i++) {
                int j;
                short *p = (short *)&c->vYCoeffsBank[i];
                for (j=0;j<8;j++)
                    p[j] = c->vLumFilter[i];
            }
    
            for (i=0;i<c->vChrFilterSize*c->chrDstH;i++) {
                int j;
                short *p = (short *)&c->vCCoeffsBank[i];
                for (j=0;j<8;j++)
                    p[j] = c->vChrFilter[i];
            }
    #endif
        }
    
        // calculate buffer sizes so that they won't run out while handling these damn slices
        c->vLumBufSize= c->vLumFilterSize;
        c->vChrBufSize= c->vChrFilterSize;
        for (i=0; i<dstH; i++) {
            int chrI= i*c->chrDstH / dstH;
            int nextSlice= FFMAX(c->vLumFilterPos[i   ] + c->vLumFilterSize - 1,
                               ((c->vChrFilterPos[chrI] + c->vChrFilterSize - 1)<<c->chrSrcVSubSample));
    
            nextSlice>>= c->chrSrcVSubSample;
            nextSlice<<= c->chrSrcVSubSample;
            if (c->vLumFilterPos[i   ] + c->vLumBufSize < nextSlice)
                c->vLumBufSize= nextSlice - c->vLumFilterPos[i];
            if (c->vChrFilterPos[chrI] + c->vChrBufSize < (nextSlice>>c->chrSrcVSubSample))
                c->vChrBufSize= (nextSlice>>c->chrSrcVSubSample) - c->vChrFilterPos[chrI];
        }
    
        // allocate pixbufs (we use dynamic allocation because otherwise we would need to
        // allocate several megabytes to handle all possible cases)
        FF_ALLOC_OR_GOTO(c, c->lumPixBuf, c->vLumBufSize*2*sizeof(int16_t*), fail);
        FF_ALLOC_OR_GOTO(c, c->chrPixBuf, c->vChrBufSize*2*sizeof(int16_t*), fail);
        if (CONFIG_SWSCALE_ALPHA && isALPHA(c->srcFormat) && isALPHA(c->dstFormat))
            FF_ALLOCZ_OR_GOTO(c, c->alpPixBuf, c->vLumBufSize*2*sizeof(int16_t*), fail);
        //Note we need at least one pixel more at the end because of the MMX code (just in case someone wanna replace the 4000/8000)
        /* align at 16 bytes for AltiVec */
        for (i=0; i<c->vLumBufSize; i++) {
            FF_ALLOCZ_OR_GOTO(c, c->lumPixBuf[i+c->vLumBufSize], VOF+1, fail);
            c->lumPixBuf[i] = c->lumPixBuf[i+c->vLumBufSize];
        }
        for (i=0; i<c->vChrBufSize; i++) {
            FF_ALLOC_OR_GOTO(c, c->chrPixBuf[i+c->vChrBufSize], (VOF+1)*2, fail);
            c->chrPixBuf[i] = c->chrPixBuf[i+c->vChrBufSize];
        }
        if (CONFIG_SWSCALE_ALPHA && c->alpPixBuf)
            for (i=0; i<c->vLumBufSize; i++) {
                FF_ALLOCZ_OR_GOTO(c, c->alpPixBuf[i+c->vLumBufSize], VOF+1, fail);
                c->alpPixBuf[i] = c->alpPixBuf[i+c->vLumBufSize];
            }
    
        //try to avoid drawing green stuff between the right end and the stride end
        for (i=0; i<c->vChrBufSize; i++) memset(c->chrPixBuf[i], 64, (VOF+1)*2);
    
        assert(2*VOFW == VOF);
    
        assert(c->chrDstH <= dstH);
    
        if (flags&SWS_PRINT_INFO) {
            if (flags&SWS_FAST_BILINEAR)
                av_log(c, AV_LOG_INFO, "FAST_BILINEAR scaler, ");
            else if (flags&SWS_BILINEAR)
                av_log(c, AV_LOG_INFO, "BILINEAR scaler, ");
            else if (flags&SWS_BICUBIC)
                av_log(c, AV_LOG_INFO, "BICUBIC scaler, ");
            else if (flags&SWS_X)
                av_log(c, AV_LOG_INFO, "Experimental scaler, ");
            else if (flags&SWS_POINT)
                av_log(c, AV_LOG_INFO, "Nearest Neighbor / POINT scaler, ");
            else if (flags&SWS_AREA)
                av_log(c, AV_LOG_INFO, "Area Averaging scaler, ");
            else if (flags&SWS_BICUBLIN)
                av_log(c, AV_LOG_INFO, "luma BICUBIC / chroma BILINEAR scaler, ");
            else if (flags&SWS_GAUSS)
                av_log(c, AV_LOG_INFO, "Gaussian scaler, ");
            else if (flags&SWS_SINC)
                av_log(c, AV_LOG_INFO, "Sinc scaler, ");
            else if (flags&SWS_LANCZOS)
                av_log(c, AV_LOG_INFO, "Lanczos scaler, ");
            else if (flags&SWS_SPLINE)
                av_log(c, AV_LOG_INFO, "Bicubic spline scaler, ");
            else
                av_log(c, AV_LOG_INFO, "ehh flags invalid?! ");
    
            av_log(c, AV_LOG_INFO, "from %s to %s%s ",
                   sws_format_name(srcFormat),
    #ifdef DITHER1XBPP
    
                   dstFormat == PIX_FMT_BGR555 || dstFormat == PIX_FMT_BGR565 ||
                   dstFormat == PIX_FMT_RGB444BE || dstFormat == PIX_FMT_RGB444LE ||
                   dstFormat == PIX_FMT_BGR444BE || dstFormat == PIX_FMT_BGR444LE ? "dithered " : "",
    
    #else
                   "",
    #endif
                   sws_format_name(dstFormat));
    
            if (flags & SWS_CPU_CAPS_MMX2)
                av_log(c, AV_LOG_INFO, "using MMX2\n");
            else if (flags & SWS_CPU_CAPS_3DNOW)
                av_log(c, AV_LOG_INFO, "using 3DNOW\n");
            else if (flags & SWS_CPU_CAPS_MMX)
                av_log(c, AV_LOG_INFO, "using MMX\n");
            else if (flags & SWS_CPU_CAPS_ALTIVEC)
                av_log(c, AV_LOG_INFO, "using AltiVec\n");
            else
                av_log(c, AV_LOG_INFO, "using C\n");
    
            if (flags & SWS_CPU_CAPS_MMX) {
                if (c->canMMX2BeUsed && (flags&SWS_FAST_BILINEAR))
                    av_log(c, AV_LOG_VERBOSE, "using FAST_BILINEAR MMX2 scaler for horizontal scaling\n");
                else {
                    if (c->hLumFilterSize==4)
                        av_log(c, AV_LOG_VERBOSE, "using 4-tap MMX scaler for horizontal luminance scaling\n");
                    else if (c->hLumFilterSize==8)
                        av_log(c, AV_LOG_VERBOSE, "using 8-tap MMX scaler for horizontal luminance scaling\n");
                    else
                        av_log(c, AV_LOG_VERBOSE, "using n-tap MMX scaler for horizontal luminance scaling\n");
    
                    if (c->hChrFilterSize==4)
                        av_log(c, AV_LOG_VERBOSE, "using 4-tap MMX scaler for horizontal chrominance scaling\n");
                    else if (c->hChrFilterSize==8)
                        av_log(c, AV_LOG_VERBOSE, "using 8-tap MMX scaler for horizontal chrominance scaling\n");
                    else
                        av_log(c, AV_LOG_VERBOSE, "using n-tap MMX scaler for horizontal chrominance scaling\n");
                }
            } else {
    #if ARCH_X86
                av_log(c, AV_LOG_VERBOSE, "using x86 asm scaler for horizontal scaling\n");
    #else
                if (flags & SWS_FAST_BILINEAR)
                    av_log(c, AV_LOG_VERBOSE, "using FAST_BILINEAR C scaler for horizontal scaling\n");
                else
                    av_log(c, AV_LOG_VERBOSE, "using C scaler for horizontal scaling\n");
    #endif
            }
            if (isPlanarYUV(dstFormat)) {
                if (c->vLumFilterSize==1)
                    av_log(c, AV_LOG_VERBOSE, "using 1-tap %s \"scaler\" for vertical scaling (YV12 like)\n", (flags & SWS_CPU_CAPS_MMX) ? "MMX" : "C");
                else
                    av_log(c, AV_LOG_VERBOSE, "using n-tap %s scaler for vertical scaling (YV12 like)\n", (flags & SWS_CPU_CAPS_MMX) ? "MMX" : "C");
            } else {
                if (c->vLumFilterSize==1 && c->vChrFilterSize==2)
                    av_log(c, AV_LOG_VERBOSE, "using 1-tap %s \"scaler\" for vertical luminance scaling (BGR)\n"
                           "      2-tap scaler for vertical chrominance scaling (BGR)\n", (flags & SWS_CPU_CAPS_MMX) ? "MMX" : "C");
                else if (c->vLumFilterSize==2 && c->vChrFilterSize==2)
                    av_log(c, AV_LOG_VERBOSE, "using 2-tap linear %s scaler for vertical scaling (BGR)\n", (flags & SWS_CPU_CAPS_MMX) ? "MMX" : "C");
                else
                    av_log(c, AV_LOG_VERBOSE, "using n-tap %s scaler for vertical scaling (BGR)\n", (flags & SWS_CPU_CAPS_MMX) ? "MMX" : "C");
            }
    
            if (dstFormat==PIX_FMT_BGR24)
                av_log(c, AV_LOG_VERBOSE, "using %s YV12->BGR24 converter\n",
                       (flags & SWS_CPU_CAPS_MMX2) ? "MMX2" : ((flags & SWS_CPU_CAPS_MMX) ? "MMX" : "C"));
            else if (dstFormat==PIX_FMT_RGB32)
                av_log(c, AV_LOG_VERBOSE, "using %s YV12->BGR32 converter\n", (flags & SWS_CPU_CAPS_MMX) ? "MMX" : "C");
            else if (dstFormat==PIX_FMT_BGR565)
                av_log(c, AV_LOG_VERBOSE, "using %s YV12->BGR16 converter\n", (flags & SWS_CPU_CAPS_MMX) ? "MMX" : "C");
            else if (dstFormat==PIX_FMT_BGR555)
                av_log(c, AV_LOG_VERBOSE, "using %s YV12->BGR15 converter\n", (flags & SWS_CPU_CAPS_MMX) ? "MMX" : "C");
    
            else if (dstFormat == PIX_FMT_RGB444BE || dstFormat == PIX_FMT_RGB444LE ||
                     dstFormat == PIX_FMT_BGR444BE || dstFormat == PIX_FMT_BGR444LE)
                av_log(c, AV_LOG_VERBOSE, "using %s YV12->BGR12 converter\n", (flags & SWS_CPU_CAPS_MMX) ? "MMX" : "C");
    
    
            av_log(c, AV_LOG_VERBOSE, "%dx%d -> %dx%d\n", srcW, srcH, dstW, dstH);
            av_log(c, AV_LOG_DEBUG, "lum srcW=%d srcH=%d dstW=%d dstH=%d xInc=%d yInc=%d\n",
                   c->srcW, c->srcH, c->dstW, c->dstH, c->lumXInc, c->lumYInc);
            av_log(c, AV_LOG_DEBUG, "chr srcW=%d srcH=%d dstW=%d dstH=%d xInc=%d yInc=%d\n",
                   c->chrSrcW, c->chrSrcH, c->chrDstW, c->chrDstH, c->chrXInc, c->chrYInc);
        }
    
        c->swScale= ff_getSwsFunc(c);
        return c;
    
    fail:
        sws_freeContext(c);
        return NULL;
    }
    
    SwsFilter *sws_getDefaultFilter(float lumaGBlur, float chromaGBlur,
                                    float lumaSharpen, float chromaSharpen,
                                    float chromaHShift, float chromaVShift,
                                    int verbose)
    {
        SwsFilter *filter= av_malloc(sizeof(SwsFilter));
        if (!filter)
            return NULL;
    
        if (lumaGBlur!=0.0) {
            filter->lumH= sws_getGaussianVec(lumaGBlur, 3.0);
            filter->lumV= sws_getGaussianVec(lumaGBlur, 3.0);
        } else {
            filter->lumH= sws_getIdentityVec();
            filter->lumV= sws_getIdentityVec();
        }
    
        if (chromaGBlur!=0.0) {
            filter->chrH= sws_getGaussianVec(chromaGBlur, 3.0);
            filter->chrV= sws_getGaussianVec(chromaGBlur, 3.0);
        } else {
            filter->chrH= sws_getIdentityVec();
            filter->chrV= sws_getIdentityVec();
        }
    
        if (chromaSharpen!=0.0) {
            SwsVector *id= sws_getIdentityVec();
            sws_scaleVec(filter->chrH, -chromaSharpen);
            sws_scaleVec(filter->chrV, -chromaSharpen);
            sws_addVec(filter->chrH, id);
            sws_addVec(filter->chrV, id);
            sws_freeVec(id);
        }
    
        if (lumaSharpen!=0.0) {
            SwsVector *id= sws_getIdentityVec();
            sws_scaleVec(filter->lumH, -lumaSharpen);
            sws_scaleVec(filter->lumV, -lumaSharpen);
            sws_addVec(filter->lumH, id);
            sws_addVec(filter->lumV, id);
            sws_freeVec(id);
        }
    
        if (chromaHShift != 0.0)
            sws_shiftVec(filter->chrH, (int)(chromaHShift+0.5));
    
        if (chromaVShift != 0.0)
            sws_shiftVec(filter->chrV, (int)(chromaVShift+0.5));
    
        sws_normalizeVec(filter->chrH, 1.0);
        sws_normalizeVec(filter->chrV, 1.0);
        sws_normalizeVec(filter->lumH, 1.0);
        sws_normalizeVec(filter->lumV, 1.0);
    
        if (verbose) sws_printVec2(filter->chrH, NULL, AV_LOG_DEBUG);
        if (verbose) sws_printVec2(filter->lumH, NULL, AV_LOG_DEBUG);
    
        return filter;
    }
    
    SwsVector *sws_allocVec(int length)
    {
        SwsVector *vec = av_malloc(sizeof(SwsVector));
        if (!vec)
            return NULL;
        vec->length = length;
        vec->coeff  = av_malloc(sizeof(double) * length);
        if (!vec->coeff)
            av_freep(&vec);
        return vec;
    }
    
    SwsVector *sws_getGaussianVec(double variance, double quality)
    {
        const int length= (int)(variance*quality + 0.5) | 1;
        int i;
        double middle= (length-1)*0.5;
        SwsVector *vec= sws_allocVec(length);
    
        if (!vec)
            return NULL;
    
        for (i=0; i<length; i++) {
            double dist= i-middle;
    
            vec->coeff[i]= exp(-dist*dist/(2*variance*variance)) / sqrt(2*variance*M_PI);
    
        }
    
        sws_normalizeVec(vec, 1.0);
    
        return vec;
    }
    
    SwsVector *sws_getConstVec(double c, int length)
    {
        int i;
        SwsVector *vec= sws_allocVec(length);
    
        if (!vec)
            return NULL;
    
        for (i=0; i<length; i++)
            vec->coeff[i]= c;
    
        return vec;
    }
    
    SwsVector *sws_getIdentityVec(void)
    {
        return sws_getConstVec(1.0, 1);
    }
    
    
    static double sws_dcVec(SwsVector *a)
    
    {
        int i;
        double sum=0;
    
        for (i=0; i<a->length; i++)
            sum+= a->coeff[i];
    
        return sum;
    }
    
    void sws_scaleVec(SwsVector *a, double scalar)
    {
        int i;
    
        for (i=0; i<a->length; i++)
            a->coeff[i]*= scalar;
    }
    
    void sws_normalizeVec(SwsVector *a, double height)
    {
        sws_scaleVec(a, height/sws_dcVec(a));
    }
    
    static SwsVector *sws_getConvVec(SwsVector *a, SwsVector *b)
    {
        int length= a->length + b->length - 1;
        int i, j;
        SwsVector *vec= sws_getConstVec(0.0, length);
    
        if (!vec)
            return NULL;
    
        for (i=0; i<a->length; i++) {
            for (j=0; j<b->length; j++) {
                vec->coeff[i+j]+= a->coeff[i]*b->coeff[j];
            }
        }
    
        return vec;
    }
    
    static SwsVector *sws_sumVec(SwsVector *a, SwsVector *b)
    {
        int length= FFMAX(a->length, b->length);
        int i;
        SwsVector *vec= sws_getConstVec(0.0, length);
    
        if (!vec)
            return NULL;
    
        for (i=0; i<a->length; i++) vec->coeff[i + (length-1)/2 - (a->length-1)/2]+= a->coeff[i];
        for (i=0; i<b->length; i++) vec->coeff[i + (length-1)/2 - (b->length-1)/2]+= b->coeff[i];
    
        return vec;
    }
    
    static SwsVector *sws_diffVec(SwsVector *a, SwsVector *b)
    {
        int length= FFMAX(a->length, b->length);
        int i;
        SwsVector *vec= sws_getConstVec(0.0, length);
    
        if (!vec)
            return NULL;
    
        for (i=0; i<a->length; i++) vec->coeff[i + (length-1)/2 - (a->length-1)/2]+= a->coeff[i];
        for (i=0; i<b->length; i++) vec->coeff[i + (length-1)/2 - (b->length-1)/2]-= b->coeff[i];
    
        return vec;
    }
    
    /* shift left / or right if "shift" is negative */
    static SwsVector *sws_getShiftedVec(SwsVector *a, int shift)
    {
        int length= a->length + FFABS(shift)*2;
        int i;
        SwsVector *vec= sws_getConstVec(0.0, length);
    
        if (!vec)
            return NULL;
    
        for (i=0; i<a->length; i++) {
            vec->coeff[i + (length-1)/2 - (a->length-1)/2 - shift]= a->coeff[i];
        }
    
        return vec;
    }
    
    void sws_shiftVec(SwsVector *a, int shift)
    {
        SwsVector *shifted= sws_getShiftedVec(a, shift);
        av_free(a->coeff);
        a->coeff= shifted->coeff;
        a->length= shifted->length;
        av_free(shifted);
    }
    
    void sws_addVec(SwsVector *a, SwsVector *b)
    {
        SwsVector *sum= sws_sumVec(a, b);
        av_free(a->coeff);
        a->coeff= sum->coeff;
        a->length= sum->length;
        av_free(sum);
    }
    
    void sws_subVec(SwsVector *a, SwsVector *b)
    {
        SwsVector *diff= sws_diffVec(a, b);
        av_free(a->coeff);
        a->coeff= diff->coeff;
        a->length= diff->length;
        av_free(diff);
    }
    
    void sws_convVec(SwsVector *a, SwsVector *b)
    {
        SwsVector *conv= sws_getConvVec(a, b);
        av_free(a->coeff);
        a->coeff= conv->coeff;
        a->length= conv->length;
        av_free(conv);
    }
    
    SwsVector *sws_cloneVec(SwsVector *a)
    {
        int i;
        SwsVector *vec= sws_allocVec(a->length);
    
        if (!vec)
            return NULL;
    
        for (i=0; i<a->length; i++) vec->coeff[i]= a->coeff[i];
    
        return vec;
    }
    
    void sws_printVec2(SwsVector *a, AVClass *log_ctx, int log_level)
    {
        int i;
        double max=0;
        double min=0;
        double range;
    
        for (i=0; i<a->length; i++)
            if (a->coeff[i]>max) max= a->coeff[i];
    
        for (i=0; i<a->length; i++)
            if (a->coeff[i]<min) min= a->coeff[i];
    
        range= max - min;
    
        for (i=0; i<a->length; i++) {
            int x= (int)((a->coeff[i]-min)*60.0/range +0.5);
            av_log(log_ctx, log_level, "%1.3f ", a->coeff[i]);
            for (;x>0; x--) av_log(log_ctx, log_level, " ");
            av_log(log_ctx, log_level, "|\n");
        }
    }
    
    #if LIBSWSCALE_VERSION_MAJOR < 1
    void sws_printVec(SwsVector *a)
    {
        sws_printVec2(a, NULL, AV_LOG_DEBUG);
    }
    #endif
    
    void sws_freeVec(SwsVector *a)
    {
        if (!a) return;
        av_freep(&a->coeff);
        a->length=0;
        av_free(a);
    }
    
    void sws_freeFilter(SwsFilter *filter)
    {
        if (!filter) return;
    
        if (filter->lumH) sws_freeVec(filter->lumH);
        if (filter->lumV) sws_freeVec(filter->lumV);
        if (filter->chrH) sws_freeVec(filter->chrH);
        if (filter->chrV) sws_freeVec(filter->chrV);
        av_free(filter);
    }
    
    void sws_freeContext(SwsContext *c)
    {
        int i;
        if (!c) return;
    
        if (c->lumPixBuf) {
            for (i=0; i<c->vLumBufSize; i++)
                av_freep(&c->lumPixBuf[i]);
            av_freep(&c->lumPixBuf);
        }
    
        if (c->chrPixBuf) {
            for (i=0; i<c->vChrBufSize; i++)
                av_freep(&c->chrPixBuf[i]);
            av_freep(&c->chrPixBuf);
        }
    
        if (CONFIG_SWSCALE_ALPHA && c->alpPixBuf) {
            for (i=0; i<c->vLumBufSize; i++)
                av_freep(&c->alpPixBuf[i]);
            av_freep(&c->alpPixBuf);
        }
    
        av_freep(&c->vLumFilter);
        av_freep(&c->vChrFilter);
        av_freep(&c->hLumFilter);
        av_freep(&c->hChrFilter);
    
        av_freep(&c->vYCoeffsBank);
        av_freep(&c->vCCoeffsBank);
    #endif
    
        av_freep(&c->vLumFilterPos);
        av_freep(&c->vChrFilterPos);
        av_freep(&c->hLumFilterPos);
        av_freep(&c->hChrFilterPos);
    
    
    #ifdef MAP_ANONYMOUS
        if (c->lumMmx2FilterCode) munmap(c->lumMmx2FilterCode, c->lumMmx2FilterCodeSize);
        if (c->chrMmx2FilterCode) munmap(c->chrMmx2FilterCode, c->chrMmx2FilterCodeSize);
    #elif HAVE_VIRTUALALLOC
    
        if (c->lumMmx2FilterCode) VirtualFree(c->lumMmx2FilterCode, 0, MEM_RELEASE);
        if (c->chrMmx2FilterCode) VirtualFree(c->chrMmx2FilterCode, 0, MEM_RELEASE);
    
    #else
        av_free(c->lumMmx2FilterCode);
        av_free(c->chrMmx2FilterCode);
    #endif
        c->lumMmx2FilterCode=NULL;
        c->chrMmx2FilterCode=NULL;
    
    
        av_freep(&c->yuvTable);
    
        av_free(c);
    }
    
    struct SwsContext *sws_getCachedContext(struct SwsContext *context,
                                            int srcW, int srcH, enum PixelFormat srcFormat,
                                            int dstW, int dstH, enum PixelFormat dstFormat, int flags,
                                            SwsFilter *srcFilter, SwsFilter *dstFilter, const double *param)
    {
        static const double default_param[2] = {SWS_PARAM_DEFAULT, SWS_PARAM_DEFAULT};
    
        if (!param)
            param = default_param;
    
    
            (context->srcW      != srcW      ||
             context->srcH      != srcH      ||
             context->srcFormat != srcFormat ||
             context->dstW      != dstW      ||
             context->dstH      != dstH      ||
             context->dstFormat != dstFormat ||
             context->flags     != flags     ||
             context->param[0]  != param[0]  ||
    
             context->param[1]  != param[1])) {
            sws_freeContext(context);
            context = NULL;
        }
    
        if (!context) {
            return sws_getContext(srcW, srcH, srcFormat,
                                  dstW, dstH, dstFormat, flags,
                                  srcFilter, dstFilter, param);
        }
        return context;
    }