/*===========================================================================*
 * frame.c                                   *
 *                                       *
 *  basic frame procedures                           *
 *                                       *
 * EXPORTED PROCEDURES:                              *
 *  Frame_Init                               *
 *  Frame_Exit                               *
 *  Frame_New                                *
 *  Frame_Free                               *
 *  Frame_AllocBlocks                            *
 *  Frame_AllocYCC                               *
 *  Frame_AllocDecoded                           *
 *  Frame_AllocHalf                                  *
 *  Frame_Resize                                     * 
 *                                       *
 *===========================================================================*/

/*
 * Copyright (c) 1995 The Regents of the University of California.
 * All rights reserved.
 *
 * Permission to use, copy, modify, and distribute this software and its
 * documentation for any purpose, without fee, and without written agreement is
 * hereby granted, provided that the above copyright notice and the following
 * two paragraphs appear in all copies of this software.
 *
 * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
 * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
 * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
 * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
 * AND FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
 * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
 * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
 */


#include "mallocvar.h"

#include "all.h"
#include "mtypes.h"
#include "frames.h"
#include "frame.h"
#include "fsize.h"
#include "dct.h"

/*===========*
 * CONSTANTS *
 *===========*/

/* The maximum number of B-Frames allowed between reference frames. */
#define  B_FRAME_RUN  16    

/*==================*
 * GLOBAL VARIABLES *
 *==================*/

static MpegFrame * frameMemory[B_FRAME_RUN+2];
static unsigned int numOfFrames;


/*====================================================
* Resize_Array_Width
*    
*   This function will resize any array width up
* or down in size.  The algorithm is based on the
* least common multiple approach more commonly
* used in audio frequency adjustments.
*=====================================================*/
static void 
Resize_Array_Width(uint8 ** const inarray,
                   int      const in_x,
                   int      const in_y,
                   uint8 ** const outarray,
                   int      const out_x) {

    unsigned int i;
    int in_total;
    int out_total;
    uint8 *inptr;
    uint8 *outptr;
#ifdef DOING_INTERPOLATION
    uint8 pointA,pointB;
    double slope,diff;
#endif
    
    for (i = 0; i < in_y; ++i) {     /* For each row */
        unsigned int j;
        inptr = &inarray[i][0];
        outptr = &outarray[i][0];
        in_total = 0;
        out_total = 0;
        for (j=0; j < out_x; ++j) {      /* For each output value */
            if (in_total == out_total) {
                *outptr = *inptr;
                outptr++;
                out_total=out_total+in_x;
                while(in_total < out_total){
                    in_total = in_total + out_x;
                    ++inptr;
                }
                if (in_total > out_total) {
                    in_total = in_total - out_x;
                    --inptr;
                }
            } else {  
#ifdef DOING_INTERPOLATION
                pointA = *inptr;
#endif
                ++inptr;
#ifdef DOING_INTERPOLATION
                pointB = *inptr;
#endif
                --inptr;
#ifdef DOING_INTERPOLATION
                /*Interpolative solution */
                slope = ((double)(pointB -pointA))/((double)(out_x));
                diff = (((double)(out_total - in_total)));
                if (diff < (out_x/2)){
                    *outptr = (pointA + (uint8)(slope*diff));
                } else {
                    *outptr = (pointB -
                               (uint8)(slope*(((float)(out_x)) - diff)));
                } 
#endif
                /* Non-Interpolative solution */
                *outptr = *inptr;  

                ++outptr;
                out_total = out_total + in_x;
                while(in_total < out_total) {
                    in_total = in_total + out_x;
                    ++inptr;
                }
                if (in_total > out_total) {
                    in_total = in_total - out_x;
                    --inptr;
                }
            }  /* end if */
        }  /* end for each output value */
    }  /* end for each row */
}  /* end main */



/*==============================
* Resize_Array_Height
*
*    Resize any array height larger or smaller.
* Same as Resize_array_Width except pointer
* manipulation must change.
*===============================*/
static void 
Resize_Array_Height(uint8 ** const inarray,
                    int      const in_x,
                    int      const in_y,
                    uint8 ** const outarray,
                    int      const out_y) {

    unsigned int i;

    for(i=0; i < in_x; ++i){    /* for each column */
        int in_total;
        int out_total;
#ifdef DOING_INTERPOLATION
        uint8 pointA, pointB;
        double slope, diff;
#endif
        unsigned int j;
        int k;

        in_total = 0;
        out_total = 0;
        k = 0;
        for(j=0; j < out_y; ++j){  /* for each output value */
            if (in_total == out_total) {  
                outarray[j][i] = inarray[k][i];
                out_total=out_total+in_y;
                while(in_total < out_total){
                    in_total = in_total + out_y;
                    ++k;
                }
                if (in_total > out_total) {
                    in_total = in_total - out_y;
                    --k;
                }
            } else {  
#ifdef DOING_INTERPOLATION
                pointA = inarray[k][i];
                if (k != (in_y - 1)) {
                    pointB = inarray[k+1][i];
                } else
                    pointB = pointA;
                /* Interpolative case */
                slope = ((double)(pointB -pointA))/(double)(out_y);
                diff = (double)(out_total - in_total);
                outarray[j][i] = (inarray[k][i] + (uint8)(slope*diff));
#endif
                /* Non-Interpolative case */
                outarray[j][i] = inarray[k][i];
                out_total = out_total + in_y;
                while (in_total < out_total) {
                    in_total = in_total + out_y;
                    ++k;
                }
                if (in_total > out_total){
                    in_total = in_total - out_y;
                    --k;
                }
            } 
        }
    }
}



/*========================================================
* Resize_Width
*======================================================*/
static void  
Resize_Width(MpegFrame * const omfrw,
             MpegFrame * const mfrw,
             int         const in_x,
             int         const in_y,
             int         const out_x) {

    int y;

    omfrw->orig_y = NULL;
    Fsize_x = out_x;

    /* Allocate new frame memory */
    MALLOCARRAY(omfrw->orig_y, Fsize_y);
    ERRCHK(omfrw->orig_y, "malloc");
    for (y = 0; y < Fsize_y; ++y) {
        MALLOCARRAY(omfrw->orig_y[y], out_x);
        ERRCHK(omfrw->orig_y[y], "malloc");
    }

    MALLOCARRAY(omfrw->orig_cr, Fsize_y / 2);
    ERRCHK(omfrw->orig_cr, "malloc");
    for (y = 0; y < Fsize_y / 2; ++y) {
        MALLOCARRAY(omfrw->orig_cr[y], out_x / 2);
        ERRCHK(omfrw->orig_cr[y], "malloc");
    }

    MALLOCARRAY(omfrw->orig_cb, Fsize_y / 2);
    ERRCHK(omfrw->orig_cb, "malloc");
    for (y = 0; y < Fsize_y / 2; ++y) {
        MALLOCARRAY(omfrw->orig_cb[y], out_x / 2);
        ERRCHK(omfrw->orig_cb[y], "malloc");
    }

    if (referenceFrame == ORIGINAL_FRAME) {
        omfrw->ref_y = omfrw->orig_y;
        omfrw->ref_cr = omfrw->orig_cr;
        omfrw->ref_cb = omfrw->orig_cb;
    }

    /* resize each component array separately */
    Resize_Array_Width(mfrw->orig_y, in_x, in_y, omfrw->orig_y, out_x);
    Resize_Array_Width(mfrw->orig_cr, (in_x/2), (in_y/2), omfrw->orig_cr,
                       (out_x/2));
    Resize_Array_Width(mfrw->orig_cb, (in_x/2), (in_y/2), omfrw->orig_cb,
                       (out_x/2));

    /* Free old frame memory */
    if (mfrw->orig_y) {
        unsigned int i;
        for (i = 0; i < in_y; ++i) {
            free(mfrw->orig_y[i]);
        }
        free(mfrw->orig_y);
        
        for (i = 0; i < in_y / 2; ++i) {
            free(mfrw->orig_cr[i]);
        }
        free(mfrw->orig_cr);
        
        for (i = 0; i < in_y / 2; ++i) {
            free(mfrw->orig_cb[i]);
        }
        free(mfrw->orig_cb);
    }
}



/*=======================================================
* Resize_Height
*
*   Resize Frame height up or down
*=======================================================*/
static  void
Resize_Height(MpegFrame * const omfrh,
              MpegFrame * const mfrh,
              int         const in_x,
              int         const in_y,
              int         const out_y) {
    
    unsigned int y; 
    
    Fsize_y = out_y;

    /* Allocate new frame memory */
    MALLOCARRAY(omfrh->orig_y, out_y);
    ERRCHK(omfrh->orig_y, "malloc");
    for (y = 0; y < out_y; ++y) {
        MALLOCARRAY(omfrh->orig_y[y], Fsize_x);
        ERRCHK(omfrh->orig_y[y], "malloc");
    }

    MALLOCARRAY(omfrh->orig_cr, out_y / 2);
    ERRCHK(omfrh->orig_cr, "malloc");
    for (y = 0; y < out_y / 2; ++y) {
        MALLOCARRAY(omfrh->orig_cr[y], Fsize_x / 2);
        ERRCHK(omfrh->orig_cr[y], "malloc");
    }

    MALLOCARRAY(omfrh->orig_cb, out_y / 2);
    ERRCHK(omfrh->orig_cb, "malloc");
    for (y = 0; y < out_y / 2; ++y) {
        MALLOCARRAY(omfrh->orig_cb[y], Fsize_x / 2);
        ERRCHK(omfrh->orig_cb[y], "malloc");
    }

    if (referenceFrame == ORIGINAL_FRAME) {
        omfrh->ref_y = omfrh->orig_y;
        omfrh->ref_cr = omfrh->orig_cr;
        omfrh->ref_cb = omfrh->orig_cb;
    }

    /* resize component arrays separately */
    Resize_Array_Height(mfrh->orig_y, in_x, in_y, omfrh->orig_y, out_y);
    Resize_Array_Height(mfrh->orig_cr, (in_x/2), (in_y/2), omfrh->orig_cr,
                        (out_y/2));
    Resize_Array_Height(mfrh->orig_cb, (in_x/2), (in_y/2), omfrh->orig_cb,
                        (out_y/2));

    /* Free old frame memory */
    if (mfrh->orig_y) {
        unsigned int i;
        for (i = 0; i < in_y; ++i) {
            free(mfrh->orig_y[i]);
        }
        free(mfrh->orig_y);
        
    for (i = 0; i < in_y / 2; ++i) {
        free(mfrh->orig_cr[i]);
    }
    free(mfrh->orig_cr);
    
    for (i = 0; i < in_y / 2; ++i) {
        free(mfrh->orig_cb[i]);
    }
    free(mfrh->orig_cb);
    }
}



/*===========================================================================*
 *
 * Frame_Init
 *
 *  initializes the memory associated with all frames ever
 *  If the input is not coming in from stdin, only 3 frames are needed ;
 *      else, the program must create frames equal to the greatest distance
 *      between two reference frames to hold the B frames while it is parsing
 *      the input from stdin.
 *
 * RETURNS: nothing
 *
 * SIDE EFFECTS:    frameMemory, numOfFrames
 *
 *===========================================================================*/
void
Frame_Init(unsigned int const numOfFramesRequested) {
    int idx;

    numOfFrames = numOfFramesRequested;

    for (idx = 0; idx < numOfFrames; ++idx) {
        MALLOCVAR(frameMemory[idx]);
        frameMemory[idx]->inUse = FALSE;
        frameMemory[idx]->orig_y = NULL;    
        frameMemory[idx]->y_blocks = NULL; 
        frameMemory[idx]->decoded_y = NULL;
        frameMemory[idx]->halfX = NULL;
        frameMemory[idx]->next = NULL;
    }
}


/*===========================================================================*
 *
 * FreeFrame
 *
 *  frees the memory associated with the given frame
 *
 * RETURNS: nothing
 *
 * SIDE EFFECTS:    none
 *
 *===========================================================================*/
static void
FreeFrame(MpegFrame * const frameP) {

    if (frameP) {
        if (frameP->orig_y) {
            unsigned int i;
            for (i = 0; i < Fsize_y; ++i)
                free(frameP->orig_y[i]);
            free(frameP->orig_y);

            for (i = 0; i < (Fsize_y / 2); ++i)
                free(frameP->orig_cr[i]);
            free(frameP->orig_cr);

            for (i = 0; i < (Fsize_y / 2); ++i)
                free(frameP->orig_cb[i]);
            free(frameP->orig_cb);
        }
        if (frameP->decoded_y) {
            unsigned int i;
            for (i = 0; i < Fsize_y; ++i)
                free(frameP->decoded_y[i]);
            free(frameP->decoded_y);

            for (i = 0; i < (Fsize_y / 2); ++i)
                free(frameP->decoded_cr[i]);
            free(frameP->decoded_cr);

            for (i = 0; i < (Fsize_y / 2); ++i)
                free(frameP->decoded_cb[i]);
            free(frameP->decoded_cb);
        }

        if (frameP->y_blocks) {
            unsigned int i;
            for (i = 0; i < Fsize_y / DCTSIZE; ++i)
                free(frameP->y_blocks[i]);
            free(frameP->y_blocks);

            for (i = 0; i < Fsize_y / (2 * DCTSIZE); ++i)
                free(frameP->cr_blocks[i]);
            free(frameP->cr_blocks);

            for (i = 0; i < Fsize_y / (2 * DCTSIZE); ++i)
                free(frameP->cb_blocks[i]);
            free(frameP->cb_blocks);
        }
        if (frameP->halfX) {
            unsigned int i;
            for ( i = 0; i < Fsize_y; ++i )
                free(frameP->halfX[i]);
            free(frameP->halfX);
            
            for (i = 0; i < Fsize_y-1; ++i)
                free(frameP->halfY[i]);
            free(frameP->halfY);
            
            for (i = 0; i < Fsize_y-1; ++i)
                free(frameP->halfBoth[i]);
            free(frameP->halfBoth);
        }
        free(frameP);
    }
}



/*===========================================================================*
 *
 * Frame_Exit
 *
 *  frees the memory associated with frames
 *
 * RETURNS: nothing
 *
 * SIDE EFFECTS:    frameMemory
 *
 *===========================================================================*/
void
Frame_Exit(void) {

    int idx;

    for (idx = 0; idx < numOfFrames; ++idx) {
        FreeFrame(frameMemory[idx]);
    }
}


/*===========================================================================*
 *
 * Frame_Free
 *
 *  frees the given frame -- allows it to be re-used
 *
 * RETURNS: nothing
 *
 * SIDE EFFECTS:    none
 *
 *===========================================================================*/
void
Frame_Free(MpegFrame * const frameP) {
    frameP->inUse = FALSE;
}



/*===========================================================================*
 *
 * GetUnusedFrame
 *
 *  return an unused frame
 *
 * RETURNS: the frame
 *
 * SIDE EFFECTS:    none
 *
 *===========================================================================*/
static MpegFrame *
GetUnusedFrame() {
    unsigned int idx;

    for (idx = 0; idx < numOfFrames; ++idx) {
        if (!frameMemory[idx]->inUse) {
            frameMemory[idx]->inUse = TRUE;
            break;
        }
    }
    if (idx >= numOfFrames) {
        fprintf(stderr, "ERROR:  No unused frames!!!\n");
        fprintf(stderr, "        If you are using stdin for input, "
                "it is likely that you have too many\n");
        fprintf(stderr, "        B-frames between two reference frames.  "
                "See the man page for help.\n");
        exit(1);
    }
    return frameMemory[idx]; 
}



/*===========================================================================*
 *
 * ResetFrame
 *
 *  reset a frame to the given id and type
 *
 * RETURNS: nothing
 *
 * SIDE EFFECTS:    none
 *
 *===========================================================================*/
static void
ResetFrame(int         const id,
           int         const type,
           MpegFrame * const frame) {

    switch (type) {
    case 'i':
        frame->type = TYPE_IFRAME;
        break;
    case 'p':
        frame->type = TYPE_PFRAME;
        break;
    case 'b':
        frame->type = TYPE_BFRAME;
        break;
    default:
        fprintf(stderr, "Invalid MPEG frame type %c\n", type);
        exit(1);
    }

    frame->id = id;
    frame->halfComputed = FALSE;
    frame->next = NULL;
}



/*===========================================================================*
 *
 * Frame_New
 *
 *  finds a frame that isn't currently being used and resets it
 *
 * RETURNS: the frame
 *
 * SIDE EFFECTS:    none
 *
 *===========================================================================*/
MpegFrame *
Frame_New(int const id,
          int const type) {

    MpegFrame *frame;

    frame = GetUnusedFrame();
    ResetFrame(id, type, frame);

    return frame;
}



/*===========================================================================*
 *
 * Frame_AllocBlocks
 *
 *  allocate memory for blocks for the given frame, if required
 *
 * RETURNS: nothing
 *
 * SIDE EFFECTS:    none
 *
 *===========================================================================*/
void
Frame_AllocBlocks(MpegFrame * const frameP) {

    if (frameP->y_blocks != NULL) {
        /* already allocated */
    } else {
        int const dctx = Fsize_x / DCTSIZE;
        int const dcty = Fsize_y / DCTSIZE;

        unsigned int i;

        MALLOCARRAY(frameP->y_blocks, dcty);
        ERRCHK(frameP->y_blocks, "malloc");
        for (i = 0; i < dcty; ++i) {
            MALLOCARRAY(frameP->y_blocks[i], dctx);
            ERRCHK(frameP->y_blocks[i], "malloc");
        }
    
        MALLOCARRAY(frameP->cr_blocks, dcty / 2);
        ERRCHK(frameP->cr_blocks, "malloc");
        MALLOCARRAY(frameP->cb_blocks, dcty / 2);
        ERRCHK(frameP->cb_blocks, "malloc");
        for (i = 0; i < (dcty / 2); ++i) {
            MALLOCARRAY(frameP->cr_blocks[i], dctx / 2);
            ERRCHK(frameP->cr_blocks[i], "malloc");
            MALLOCARRAY(frameP->cb_blocks[i], dctx / 2);
            ERRCHK(frameP->cb_blocks[i], "malloc");
        }
    }
}



/*===========================================================================*
 *
 * Frame_AllocYCC
 *
 *  allocate memory for YCC info for the given frame, if required
 *
 * RETURNS: nothing
 *
 * SIDE EFFECTS:    none
 *
 *===========================================================================*/
void
Frame_AllocYCC(MpegFrame * const frameP) {

    if (frameP->orig_y != NULL) {
        /* already allocated */
    } else {
        unsigned int y;
    
        DBG_PRINT(("ycc_calc:\n"));
        /*
         * first, allocate tons of memory
         */
        MALLOCARRAY(frameP->orig_y, Fsize_y);
        ERRCHK(frameP->orig_y, "malloc");
        for (y = 0; y < Fsize_y; ++y) {
            MALLOCARRAY(frameP->orig_y[y], Fsize_x);
            ERRCHK(frameP->orig_y[y], "malloc");
        }

        MALLOCARRAY(frameP->orig_cr, Fsize_y / 2);
        ERRCHK(frameP->orig_cr, "malloc");
        for (y = 0; y < (Fsize_y / 2); ++y) {
            MALLOCARRAY(frameP->orig_cr[y], Fsize_x / 2);
            ERRCHK(frameP->orig_cr[y], "malloc");
        }

        MALLOCARRAY(frameP->orig_cb, Fsize_y / 2);
        ERRCHK(frameP->orig_cb, "malloc");
        for (y = 0; y < (Fsize_y / 2); ++y) {
            MALLOCARRAY(frameP->orig_cb[y], Fsize_x / 2);
            ERRCHK(frameP->orig_cb[y], "malloc");
        }

        if (referenceFrame == ORIGINAL_FRAME) {
            frameP->ref_y  = frameP->orig_y;
            frameP->ref_cr = frameP->orig_cr;
            frameP->ref_cb = frameP->orig_cb;
        }
    }
}



/*===========================================================================*
 *
 * Frame_AllocHalf
 *
 *  allocate memory for half-pixel values for the given frame, if required
 *
 * RETURNS: nothing
 *
 * SIDE EFFECTS:    none
 *
 *===========================================================================*/
void
Frame_AllocHalf(MpegFrame * const frameP) {

    if (frameP->halfX != NULL) {
    } else {
        unsigned int y;

        MALLOCARRAY(frameP->halfX, Fsize_y);
        ERRCHK(frameP->halfX, "malloc");
        for (y = 0; y < Fsize_y; ++y) {
            MALLOCARRAY(frameP->halfX[y], Fsize_x - 1);
            ERRCHK(frameP->halfX[y], "malloc");
        }
        MALLOCARRAY(frameP->halfY, Fsize_y - 1);
        ERRCHK(frameP->halfY, "malloc");
        for (y = 0; y < Fsize_y - 1; ++y) {
            MALLOCARRAY(frameP->halfY[y], Fsize_x);
            ERRCHK(frameP->halfY[y], "malloc");
        }
        MALLOCARRAY(frameP->halfBoth, Fsize_y - 1);
        ERRCHK(frameP->halfBoth, "malloc");
        for (y = 0; y < Fsize_y - 1; ++y) {
            MALLOCARRAY(frameP->halfBoth[y], Fsize_x - 1);
            ERRCHK(frameP->halfBoth[y], "malloc");
        }
    }
}



/*===========================================================================*
 *
 * Frame_AllocDecoded
 *
 *  allocate memory for decoded frame for the given frame, if required
 *  if makeReference == TRUE, then makes it reference frame
 * 
 * RETURNS: nothing
 *
 * SIDE EFFECTS:    none
 *
 *===========================================================================*/
void
Frame_AllocDecoded(MpegFrame * const frameP,
                   bool        const makeReference) {

    if (frameP->decoded_y != NULL) {
        /* already allocated */
    } else {
        unsigned int y;

        /* allocate memory for decoded image */
        /* can probably reuse original image memory, but may decide to use
           it for some reason, so do it this way at least for now -- more
           flexible
        */
        MALLOCARRAY(frameP->decoded_y, Fsize_y);
        ERRCHK(frameP->decoded_y, "malloc");
        for (y = 0; y < Fsize_y; ++y) {
            MALLOCARRAY(frameP->decoded_y[y], Fsize_x);
            ERRCHK(frameP->decoded_y[y], "malloc");
        }
        
        MALLOCARRAY(frameP->decoded_cr, Fsize_y / 2);
        ERRCHK(frameP->decoded_cr, "malloc");
        for (y = 0; y < (Fsize_y / 2); ++y) {
            MALLOCARRAY(frameP->decoded_cr[y], Fsize_x / 2);
            ERRCHK(frameP->decoded_cr[y], "malloc");
        }
        
        MALLOCARRAY(frameP->decoded_cb, Fsize_y / 2);
        ERRCHK(frameP->decoded_cb, "malloc");
        for (y = 0; y < (Fsize_y / 2); ++y) {
            MALLOCARRAY(frameP->decoded_cb[y], Fsize_x / 2);
            ERRCHK(frameP->decoded_cb[y], "malloc");
        }

        if (makeReference) {
            frameP->ref_y  = frameP->decoded_y;
            frameP->ref_cr = frameP->decoded_cr;
            frameP->ref_cb = frameP->decoded_cb;
        }
    }
}



/*===============================================================
 *
 * Frame_Resize                  by James Boucher
 *                Boston University Multimedia Communications Lab
 *  
 *     This function takes the mf input frame, read in READFrame(),
 * and resizes all the input component arrays to the output
 * dimensions specified in the parameter file as OUT_SIZE.
 * The new frame is returned with the omf pointer.  As well,
 * the values of Fsize_x and Fsize_y are adjusted.
 ***************************************************************/
void
Frame_Resize(MpegFrame * const omf,
             MpegFrame * const mf,
             int         const insize_x,
             int         const insize_y,
             int         const outsize_x,
             int         const outsize_y) {

    MpegFrame * frameAP;  /* intermediate frame */

    MALLOCVAR_NOFAIL(frameAP);
    
    if (insize_x != outsize_x && insize_y != outsize_y) {
        Resize_Width(frameAP, mf, insize_x, insize_y, outsize_x);
        Resize_Height(omf, frameAP, outsize_x, insize_y, outsize_y);
    } else 
        if (insize_x ==outsize_x && insize_y != outsize_y) {
            Resize_Height(omf, mf, insize_x, insize_y, outsize_y);
        } else
            if (insize_x !=outsize_x && insize_y == outsize_y) {
                Resize_Width(omf, mf, insize_x, insize_y, outsize_x);
            } else
                exit(1);

    free(frameAP);
}
