/*
 * Copyright (C) 2010 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package android.media.videoeditor;

import java.io.File;
import java.io.IOException;
import java.math.BigDecimal;
import java.nio.IntBuffer;
import java.util.Iterator;
import java.util.List;
import java.util.concurrent.Semaphore;

import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.Matrix;
import android.media.videoeditor.VideoEditor.ExportProgressListener;
import android.media.videoeditor.VideoEditor.PreviewProgressListener;
import android.media.videoeditor.VideoEditor.MediaProcessingProgressListener;
import android.util.Log;
import android.util.Pair;
import android.view.Surface;

/**
 *This class provide Native methods to be used by MediaArtist {@hide}
 */
class MediaArtistNativeHelper {
    private static final String TAG = "MediaArtistNativeHelper";

    static {
        System.loadLibrary("videoeditor_jni");
    }

    private static final int MAX_THUMBNAIL_PERMITTED = 8;

    public static final int TASK_LOADING_SETTINGS = 1;
    public static final int TASK_ENCODING = 2;

    /**
     *  The resize paint
     */
    private static final Paint sResizePaint = new Paint(Paint.FILTER_BITMAP_FLAG);

    private final VideoEditor mVideoEditor;
    /*
     *  Semaphore to control preview calls
     */
    private final Semaphore mLock;

    private EditSettings mStoryBoardSettings;

    private String mOutputFilename;

    private PreviewClipProperties mClipProperties = null;

    private EditSettings mPreviewEditSettings;

    private AudioSettings mAudioSettings = null;

    private AudioTrack mAudioTrack = null;

    private boolean mInvalidatePreviewArray = true;

    private boolean mRegenerateAudio = true;

    private String mExportFilename = null;
    private int mExportVideoCodec = 0;
    private int mExportAudioCodec = 0;
    private int mProgressToApp;

    private String mRenderPreviewOverlayFile;
    private int mRenderPreviewRenderingMode;

    private boolean mIsFirstProgress;

    private static final String AUDIO_TRACK_PCM_FILE = "AudioPcm.pcm";

    // Processing indication
    public static final int PROCESSING_NONE          = 0;
    public static final int PROCESSING_AUDIO_PCM     = 1;
    public static final int PROCESSING_TRANSITION    = 2;
    public static final int PROCESSING_KENBURNS      = 3;
    public static final int PROCESSING_INTERMEDIATE1 = 11;
    public static final int PROCESSING_INTERMEDIATE2 = 12;
    public static final int PROCESSING_INTERMEDIATE3 = 13;
    public static final int PROCESSING_EXPORT        = 20;

    private int mProcessingState;
    private Object mProcessingObject;
    private PreviewProgressListener mPreviewProgressListener;
    private ExportProgressListener mExportProgressListener;
    private ExtractAudioWaveformProgressListener mExtractAudioWaveformProgressListener;
    private MediaProcessingProgressListener mMediaProcessingProgressListener;
    private final String mProjectPath;

    private long mPreviewProgress;

    private String mAudioTrackPCMFilePath;

    private int mTotalClips = 0;

    private boolean mErrorFlagSet = false;

    @SuppressWarnings("unused")
    private long mManualEditContext;

    /* Listeners */

    /**
     * Interface definition for a listener to be invoked when there is an update
     * in a running task.
     */
    public interface OnProgressUpdateListener {
        /**
         * Called when there is an update.
         *
         * @param taskId id of the task reporting an update.
         * @param progress progress of the task [0..100].
         * @see BasicEdit#TASK_ENCODING
         */
        public void OnProgressUpdate(int taskId, int progress);
    }

    /** Defines the version. */
    public final class Version {

        /** Major version number */
        public int major;

        /** Minor version number */
        public int minor;

        /** Revision number */
        public int revision;

        /** VIDEOEDITOR major version number */
        private static final int VIDEOEDITOR_MAJOR_VERSION = 0;

        /** VIDEOEDITOR minor version number */
        private static final int VIDEOEDITOR_MINOR_VERSION = 0;

        /** VIDEOEDITOR revision number */
        private static final int VIDEOEDITOR_REVISION_VERSION = 1;

        /** Method which returns the current VIDEOEDITOR version */
        public Version getVersion() {
            Version version = new Version();

            version.major = Version.VIDEOEDITOR_MAJOR_VERSION;
            version.minor = Version.VIDEOEDITOR_MINOR_VERSION;
            version.revision = Version.VIDEOEDITOR_REVISION_VERSION;

            return version;
        }
    }

    /**
     * Defines output audio formats.
     */
    public final class AudioFormat {
        /** No audio present in output clip. Used to generate video only clip */
        public static final int NO_AUDIO = 0;

        /** AMR Narrow Band. */
        public static final int AMR_NB = 1;

        /** Advanced Audio Coding (AAC). */
        public static final int AAC = 2;

        /** Advanced Audio Codec Plus (HE-AAC v1). */
        public static final int AAC_PLUS = 3;

        /** Advanced Audio Codec Plus (HE-AAC v2). */
        public static final int ENHANCED_AAC_PLUS = 4;

        /** MPEG layer 3 (MP3). */
        public static final int MP3 = 5;

        /** Enhanced Variable RateCodec (EVRC). */
        public static final int EVRC = 6;

        /** PCM (PCM). */
        public static final int PCM = 7;

        /** No transcoding. Output audio format is same as input audio format */
        public static final int NULL_AUDIO = 254;

        /** Unsupported audio format. */
        public static final int UNSUPPORTED_AUDIO = 255;
    }

    /**
     * Defines audio sampling frequencies.
     */
    public final class AudioSamplingFrequency {
        /**
         * Default sampling frequency. Uses the default frequency for a specific
         * audio format. For AAC the only supported (and thus default) sampling
         * frequency is 16 kHz. For this audio format the sampling frequency in
         * the OutputParams.
         **/
        public static final int FREQ_DEFAULT = 0;

        /** Audio sampling frequency of 8000 Hz. */
        public static final int FREQ_8000 = 8000;

        /** Audio sampling frequency of 11025 Hz. */
        public static final int FREQ_11025 = 11025;

        /** Audio sampling frequency of 12000 Hz. */
        public static final int FREQ_12000 = 12000;

        /** Audio sampling frequency of 16000 Hz. */
        public static final int FREQ_16000 = 16000;

        /** Audio sampling frequency of 22050 Hz. */
        public static final int FREQ_22050 = 22050;

        /** Audio sampling frequency of 24000 Hz. */
        public static final int FREQ_24000 = 24000;

        /** Audio sampling frequency of 32000 Hz. */
        public static final int FREQ_32000 = 32000;

        /** Audio sampling frequency of 44100 Hz. */
        public static final int FREQ_44100 = 44100;

        /** Audio sampling frequency of 48000 Hz. Not available for output file. */
        public static final int FREQ_48000 = 48000;
    }

    /**
     * Defines the supported fixed audio and video bitrates. These values are
     * for output audio video only.
     */
    public final class Bitrate {
        /** Variable bitrate. Means no bitrate regulation */
        public static final int VARIABLE = -1;

        /** An undefined bitrate. */
        public static final int UNDEFINED = 0;

        /** A bitrate of 9.2 kbits/s. */
        public static final int BR_9_2_KBPS = 9200;

        /** A bitrate of 12.2 kbits/s. */
        public static final int BR_12_2_KBPS = 12200;

        /** A bitrate of 16 kbits/s. */
        public static final int BR_16_KBPS = 16000;

        /** A bitrate of 24 kbits/s. */
        public static final int BR_24_KBPS = 24000;

        /** A bitrate of 32 kbits/s. */
        public static final int BR_32_KBPS = 32000;

        /** A bitrate of 48 kbits/s. */
        public static final int BR_48_KBPS = 48000;

        /** A bitrate of 64 kbits/s. */
        public static final int BR_64_KBPS = 64000;

        /** A bitrate of 96 kbits/s. */
        public static final int BR_96_KBPS = 96000;

        /** A bitrate of 128 kbits/s. */
        public static final int BR_128_KBPS = 128000;

        /** A bitrate of 192 kbits/s. */
        public static final int BR_192_KBPS = 192000;

        /** A bitrate of 256 kbits/s. */
        public static final int BR_256_KBPS = 256000;

        /** A bitrate of 288 kbits/s. */
        public static final int BR_288_KBPS = 288000;

        /** A bitrate of 384 kbits/s. */
        public static final int BR_384_KBPS = 384000;

        /** A bitrate of 512 kbits/s. */
        public static final int BR_512_KBPS = 512000;

        /** A bitrate of 800 kbits/s. */
        public static final int BR_800_KBPS = 800000;

        /** A bitrate of 2 Mbits/s. */
        public static final int BR_2_MBPS = 2000000;

        /** A bitrate of 5 Mbits/s. */
        public static final int BR_5_MBPS = 5000000;

        /** A bitrate of 8 Mbits/s. */
        public static final int BR_8_MBPS = 8000000;
    }

    /**
     * Defines all supported file types.
     */
    public final class FileType {
        /** 3GPP file type. */
        public static final int THREE_GPP = 0;

        /** MP4 file type. */
        public static final int MP4 = 1;

        /** AMR file type. */
        public static final int AMR = 2;

        /** MP3 audio file type. */
        public static final int MP3 = 3;

        /** PCM audio file type. */
        public static final int PCM = 4;

        /** JPEG image file type. */
        public static final int JPG = 5;

        /** GIF image file type. */
        public static final int GIF = 7;

        /** PNG image file type. */
        public static final int PNG = 8;

        /** M4V file type. */
        public static final int M4V = 10;

        /** Unsupported file type. */
        public static final int UNSUPPORTED = 255;
    }

    /**
     * Defines rendering types. Rendering can only be applied to files
     * containing video streams.
     **/
    public final class MediaRendering {
        /**
         * Resize to fit the output video with changing the aspect ratio if
         * needed.
         */
        public static final int RESIZING = 0;

        /**
         * Crop the input video to fit it with the output video resolution.
         **/
        public static final int CROPPING = 1;

        /**
         * Resize to fit the output video resolution but maintain the aspect
         * ratio. This framing type adds black borders if needed.
         */
        public static final int BLACK_BORDERS = 2;
    }

    /**
     * Defines the results.
     */
    public final class Result {
        /** No error. result OK */
        public static final int NO_ERROR = 0;

        /** File not found */
        public static final int ERR_FILE_NOT_FOUND = 1;

        /**
         * In case of UTF8 conversion, the size of the converted path will be
         * more than the corresponding allocated buffer.
         */
        public static final int ERR_BUFFER_OUT_TOO_SMALL = 2;

        /** Invalid file type. */
        public static final int ERR_INVALID_FILE_TYPE = 3;

        /** Invalid effect kind. */
        public static final int ERR_INVALID_EFFECT_KIND = 4;

        /** Invalid video effect. */
        public static final int ERR_INVALID_VIDEO_EFFECT_TYPE = 5;

        /** Invalid audio effect. */
        public static final int ERR_INVALID_AUDIO_EFFECT_TYPE = 6;

        /** Invalid video transition. */
        public static final int ERR_INVALID_VIDEO_TRANSITION_TYPE = 7;

        /** Invalid audio transition. */
        public static final int ERR_INVALID_AUDIO_TRANSITION_TYPE = 8;

        /** Invalid encoding frame rate. */
        public static final int ERR_INVALID_VIDEO_ENCODING_FRAME_RATE = 9;

        /** External effect is called but this function is not set. */
        public static final int ERR_EXTERNAL_EFFECT_NULL = 10;

        /** External transition is called but this function is not set. */
        public static final int ERR_EXTERNAL_TRANSITION_NULL = 11;

        /** Begin time cut is larger than the video clip duration. */
        public static final int ERR_BEGIN_CUT_LARGER_THAN_DURATION = 12;

        /** Begin cut time is larger or equal than end cut. */
        public static final int ERR_BEGIN_CUT_LARGER_THAN_END_CUT = 13;

        /** Two consecutive transitions are overlapping on one clip. */
        public static final int ERR_OVERLAPPING_TRANSITIONS = 14;

        /** Internal error, type size mismatch. */
        public static final int ERR_ANALYSIS_DATA_SIZE_TOO_SMALL = 15;

        /** An input 3GPP file is invalid/corrupted. */
        public static final int ERR_INVALID_3GPP_FILE = 16;

        /** A file contains an unsupported video format. */
        public static final int ERR_UNSUPPORTED_INPUT_VIDEO_FORMAT = 17;

        /** A file contains an unsupported audio format. */
        public static final int ERR_UNSUPPORTED_INPUT_AUDIO_FORMAT = 18;

        /** A file format is not supported. */
        public static final int ERR_AMR_EDITING_UNSUPPORTED = 19;

        /** An input clip has an unexpectedly large Video AU. */
        public static final int ERR_INPUT_VIDEO_AU_TOO_LARGE = 20;

        /** An input clip has an unexpectedly large Audio AU. */
        public static final int ERR_INPUT_AUDIO_AU_TOO_LARGE = 21;

        /** An input clip has a corrupted Audio AU. */
        public static final int ERR_INPUT_AUDIO_CORRUPTED_AU = 22;

        /** The video encoder encountered an Access Unit error. */
        public static final int ERR_ENCODER_ACCES_UNIT_ERROR = 23;

        /** Unsupported video format for Video Editing. */
        public static final int ERR_EDITING_UNSUPPORTED_VIDEO_FORMAT = 24;

        /** Unsupported H263 profile for Video Editing. */
        public static final int ERR_EDITING_UNSUPPORTED_H263_PROFILE = 25;

        /** Unsupported MPEG-4 profile for Video Editing. */
        public static final int ERR_EDITING_UNSUPPORTED_MPEG4_PROFILE = 26;

        /** Unsupported MPEG-4 RVLC tool for Video Editing. */
        public static final int ERR_EDITING_UNSUPPORTED_MPEG4_RVLC = 27;

        /** Unsupported audio format for Video Editing. */
        public static final int ERR_EDITING_UNSUPPORTED_AUDIO_FORMAT = 28;

        /** File contains no supported stream. */
        public static final int ERR_EDITING_NO_SUPPORTED_STREAM_IN_FILE = 29;

        /** File contains no video stream or an unsupported video stream. */
        public static final int ERR_EDITING_NO_SUPPORTED_VIDEO_STREAM_IN_FILE = 30;

        /** Internal error, clip analysis version mismatch. */
        public static final int ERR_INVALID_CLIP_ANALYSIS_VERSION = 31;

        /**
         * At least one of the clip analysis has been generated on another
         * platform (WIN32, ARM, etc.).
         */
        public static final int ERR_INVALID_CLIP_ANALYSIS_PLATFORM = 32;

        /** Clips don't have the same video format (H263 or MPEG4). */
        public static final int ERR_INCOMPATIBLE_VIDEO_FORMAT = 33;

        /** Clips don't have the same frame size. */
        public static final int ERR_INCOMPATIBLE_VIDEO_FRAME_SIZE = 34;

        /** Clips don't have the same MPEG-4 time scale. */
        public static final int ERR_INCOMPATIBLE_VIDEO_TIME_SCALE = 35;

        /** Clips don't have the same use of MPEG-4 data partitioning. */
        public static final int ERR_INCOMPATIBLE_VIDEO_DATA_PARTITIONING = 36;

        /** MP3 clips can't be assembled. */
        public static final int ERR_UNSUPPORTED_MP3_ASSEMBLY = 37;

        /**
         * The input 3GPP file does not contain any supported audio or video
         * track.
         */
        public static final int ERR_NO_SUPPORTED_STREAM_IN_FILE = 38;

        /**
         * The Volume of the added audio track (AddVolume) must be strictly
         * superior than zero.
         */
        public static final int ERR_ADDVOLUME_EQUALS_ZERO = 39;

        /**
         * The time at which an audio track is added can't be higher than the
         * input video track duration..
         */
        public static final int ERR_ADDCTS_HIGHER_THAN_VIDEO_DURATION = 40;

        /** The audio track file format setting is undefined. */
        public static final int ERR_UNDEFINED_AUDIO_TRACK_FILE_FORMAT = 41;

        /** The added audio track stream has an unsupported format. */
        public static final int ERR_UNSUPPORTED_ADDED_AUDIO_STREAM = 42;

        /** The audio mixing feature doesn't support the audio track type. */
        public static final int ERR_AUDIO_MIXING_UNSUPPORTED = 43;

        /** The audio mixing feature doesn't support MP3 audio tracks. */
        public static final int ERR_AUDIO_MIXING_MP3_UNSUPPORTED = 44;

        /**
         * An added audio track limits the available features: uiAddCts must be
         * 0 and bRemoveOriginal must be true.
         */
        public static final int ERR_FEATURE_UNSUPPORTED_WITH_AUDIO_TRACK = 45;

        /**
         * An added audio track limits the available features: uiAddCts must be
         * 0 and bRemoveOriginal must be true.
         */
        public static final int ERR_FEATURE_UNSUPPORTED_WITH_AAC = 46;

        /** Input audio track is not of a type that can be mixed with output. */
        public static final int ERR_AUDIO_CANNOT_BE_MIXED = 47;

        /** Input audio track is not AMR-NB, so it can't be mixed with output. */
        public static final int ERR_ONLY_AMRNB_INPUT_CAN_BE_MIXED = 48;

        /**
         * An added EVRC audio track limit the available features: uiAddCts must
         * be 0 and bRemoveOriginal must be true.
         */
        public static final int ERR_FEATURE_UNSUPPORTED_WITH_EVRC = 49;

        /** H263 profiles other than 0 are not supported. */
        public static final int ERR_H263_PROFILE_NOT_SUPPORTED = 51;

        /** File contains no video stream or an unsupported video stream. */
        public static final int ERR_NO_SUPPORTED_VIDEO_STREAM_IN_FILE = 52;

        /** Transcoding of the input file(s) is necessary. */
        public static final int WAR_TRANSCODING_NECESSARY = 53;

        /**
         * The size of the output file will exceed the maximum configured value.
         */
        public static final int WAR_MAX_OUTPUT_SIZE_EXCEEDED = 54;

        /** The time scale is too big. */
        public static final int WAR_TIMESCALE_TOO_BIG = 55;

        /** The year is out of range */
        public static final int ERR_CLOCK_BAD_REF_YEAR = 56;

        /** The directory could not be opened */
        public static final int ERR_DIR_OPEN_FAILED = 57;

        /** The directory could not be read */
        public static final int ERR_DIR_READ_FAILED = 58;

        /** There are no more entries in the current directory */
        public static final int ERR_DIR_NO_MORE_ENTRY = 59;

        /** The input parameter/s has error */
        public static final int ERR_PARAMETER = 60;

        /** There is a state machine error */
        public static final int ERR_STATE = 61;

        /** Memory allocation failed */
        public static final int ERR_ALLOC = 62;

        /** Context is invalid */
        public static final int ERR_BAD_CONTEXT = 63;

        /** Context creation failed */
        public static final int ERR_CONTEXT_FAILED = 64;

        /** Invalid stream ID */
        public static final int ERR_BAD_STREAM_ID = 65;

        /** Invalid option ID */
        public static final int ERR_BAD_OPTION_ID = 66;

        /** The option is write only */
        public static final int ERR_WRITE_ONLY = 67;

        /** The option is read only */
        public static final int ERR_READ_ONLY = 68;

        /** The feature is not implemented in this version */
        public static final int ERR_NOT_IMPLEMENTED = 69;

        /** The media type is not supported */
        public static final int ERR_UNSUPPORTED_MEDIA_TYPE = 70;

        /** No data to be encoded */
        public static final int WAR_NO_DATA_YET = 71;

        /** No data to be decoded */
        public static final int WAR_NO_MORE_STREAM = 72;

        /** Time stamp is invalid */
        public static final int WAR_INVALID_TIME = 73;

        /** No more data to be decoded */
        public static final int WAR_NO_MORE_AU = 74;

        /** Semaphore timed out */
        public static final int WAR_TIME_OUT = 75;

        /** Memory buffer is full */
        public static final int WAR_BUFFER_FULL = 76;

        /** Server has asked for redirection */
        public static final int WAR_REDIRECT = 77;

        /** Too many streams in input */
        public static final int WAR_TOO_MUCH_STREAMS = 78;

        /** The file cannot be opened/ written into as it is locked */
        public static final int ERR_FILE_LOCKED = 79;

        /** The file access mode is invalid */
        public static final int ERR_FILE_BAD_MODE_ACCESS = 80;

        /** The file pointer points to an invalid location */
        public static final int ERR_FILE_INVALID_POSITION = 81;

        /** Invalid string */
        public static final int ERR_STR_BAD_STRING = 94;

        /** The input string cannot be converted */
        public static final int ERR_STR_CONV_FAILED = 95;

        /** The string size is too large */
        public static final int ERR_STR_OVERFLOW = 96;

        /** Bad string arguments */
        public static final int ERR_STR_BAD_ARGS = 97;

        /** The string value is larger than maximum size allowed */
        public static final int WAR_STR_OVERFLOW = 98;

        /** The string value is not present in this comparison operation */
        public static final int WAR_STR_NOT_FOUND = 99;

        /** The thread is not started */
        public static final int ERR_THREAD_NOT_STARTED = 100;

        /** Trancoding done warning */
        public static final int WAR_TRANSCODING_DONE = 101;

        /** Unsupported mediatype */
        public static final int WAR_MEDIATYPE_NOT_SUPPORTED = 102;

        /** Input file contains invalid/unsupported streams */
        public static final int ERR_INPUT_FILE_CONTAINS_NO_SUPPORTED_STREAM = 103;

        /** Invalid input file */
        public static final int ERR_INVALID_INPUT_FILE = 104;

        /** Invalid output video format */
        public static final int ERR_UNDEFINED_OUTPUT_VIDEO_FORMAT = 105;

        /** Invalid output video frame size */
        public static final int ERR_UNDEFINED_OUTPUT_VIDEO_FRAME_SIZE = 106;

        /** Invalid output video frame rate */
        public static final int ERR_UNDEFINED_OUTPUT_VIDEO_FRAME_RATE = 107;

        /** Invalid output audio format */
        public static final int ERR_UNDEFINED_OUTPUT_AUDIO_FORMAT = 108;

        /** Invalid video frame size for H.263 */
        public static final int ERR_INVALID_VIDEO_FRAME_SIZE_FOR_H263 = 109;

        /** Invalid video frame rate for H.263 */
        public static final int ERR_INVALID_VIDEO_FRAME_RATE_FOR_H263 = 110;

        /** invalid playback duration */
        public static final int ERR_DURATION_IS_NULL = 111;

        /** Invalid H.263 profile in file */
        public static final int ERR_H263_FORBIDDEN_IN_MP4_FILE = 112;

        /** Invalid AAC sampling frequency */
        public static final int ERR_INVALID_AAC_SAMPLING_FREQUENCY = 113;

        /** Audio conversion failure */
        public static final int ERR_AUDIO_CONVERSION_FAILED = 114;

        /** Invalid trim start and end times */
        public static final int ERR_BEGIN_CUT_EQUALS_END_CUT = 115;

        /** End time smaller than start time for trim */
        public static final int ERR_END_CUT_SMALLER_THAN_BEGIN_CUT = 116;

        /** Output file size is small */
        public static final int ERR_MAXFILESIZE_TOO_SMALL = 117;

        /** Output video bitrate is too low */
        public static final int ERR_VIDEOBITRATE_TOO_LOW = 118;

        /** Output audio bitrate is too low */
        public static final int ERR_AUDIOBITRATE_TOO_LOW = 119;

        /** Output video bitrate is too high */
        public static final int ERR_VIDEOBITRATE_TOO_HIGH = 120;

        /** Output audio bitrate is too high */
        public static final int ERR_AUDIOBITRATE_TOO_HIGH = 121;

        /** Output file size is too small */
        public static final int ERR_OUTPUT_FILE_SIZE_TOO_SMALL = 122;

        /** Unknown stream type */
        public static final int ERR_READER_UNKNOWN_STREAM_TYPE = 123;

        /** Invalid metadata in input stream */
        public static final int WAR_READER_NO_METADATA = 124;

        /** Invalid file reader info warning */
        public static final int WAR_READER_INFORMATION_NOT_PRESENT = 125;

        /** Warning to indicate the the writer is being stopped */
        public static final int WAR_WRITER_STOP_REQ = 131;

        /** Video decoder failed to provide frame for transcoding */
        public static final int WAR_VIDEORENDERER_NO_NEW_FRAME = 132;

        /** Video deblocking filter is not implemented */
        public static final int WAR_DEBLOCKING_FILTER_NOT_IMPLEMENTED = 133;

        /** H.263 decoder profile not supported */
        public static final int ERR_DECODER_H263_PROFILE_NOT_SUPPORTED = 134;

        /** The input file contains unsupported H.263 profile */
        public static final int ERR_DECODER_H263_NOT_BASELINE = 135;

        /** There is no more space to store the output file */
        public static final int ERR_NOMORE_SPACE_FOR_FILE = 136;

        /** Internal error. */
        public static final int ERR_INTERNAL = 255;
    }

    /**
     * Defines output video formats.
     */
    public final class VideoFormat {
        /** No video present in output clip. Used to generate audio only clip */
        public static final int NO_VIDEO = 0;

        /** H263 video format. */
        public static final int H263 = 1;

        /** H264 video */
        public static final int H264 = 2;

        /** MPEG4 video format. */
        public static final int MPEG4 = 3;

        /** No transcoding. Output video format is same as input video format */
        public static final int NULL_VIDEO = 254;

        /** Unsupported video format. */
        public static final int UNSUPPORTED = 255;
    }

    /** Defines video frame sizes. */
    public final class VideoFrameSize {

        public static final int SIZE_UNDEFINED = -1;

        /** SQCIF 128 x 96 pixels. */
        public static final int SQCIF = 0;

        /** QQVGA 160 x 120 pixels. */
        public static final int QQVGA = 1;

        /** QCIF 176 x 144 pixels. */
        public static final int QCIF = 2;

        /** QVGA 320 x 240 pixels. */
        public static final int QVGA = 3;

        /** CIF 352 x 288 pixels. */
        public static final int CIF = 4;

        /** VGA 640 x 480 pixels. */
        public static final int VGA = 5;

        /** WVGA 800 X 480 pixels */
        public static final int WVGA = 6;

        /** NTSC 720 X 480 pixels */
        public static final int NTSC = 7;

        /** 640 x 360 */
        public static final int nHD = 8;

        /** 854 x 480 */
        public static final int WVGA16x9 = 9;

        /** 720p 1280 X 720 */
        public static final int V720p = 10;

        /** W720p 1080 x 720 */
        public static final int W720p = 11;

        /** S720p 960 x 720 */
        public static final int S720p = 12;

        /** 1080p 1920 x 1080 */
        public static final int V1080p = 13;
    }

    /**
     * Defines output video frame rates.
     */
    public final class VideoFrameRate {
        /** Frame rate of 5 frames per second. */
        public static final int FR_5_FPS = 0;

        /** Frame rate of 7.5 frames per second. */
        public static final int FR_7_5_FPS = 1;

        /** Frame rate of 10 frames per second. */
        public static final int FR_10_FPS = 2;

        /** Frame rate of 12.5 frames per second. */
        public static final int FR_12_5_FPS = 3;

        /** Frame rate of 15 frames per second. */
        public static final int FR_15_FPS = 4;

        /** Frame rate of 20 frames per second. */
        public static final int FR_20_FPS = 5;

        /** Frame rate of 25 frames per second. */
        public static final int FR_25_FPS = 6;

        /** Frame rate of 30 frames per second. */
        public static final int FR_30_FPS = 7;
    }

    /**
     * Defines Video Effect Types.
     */
    public static class VideoEffect {

        public static final int NONE = 0;

        public static final int FADE_FROM_BLACK = 8;

        public static final int FADE_TO_BLACK = 16;

        public static final int EXTERNAL = 256;

        public static final int BLACK_AND_WHITE = 257;

        public static final int PINK = 258;

        public static final int GREEN = 259;

        public static final int SEPIA = 260;

        public static final int NEGATIVE = 261;

        public static final int FRAMING = 262;

        public static final int TEXT = 263;

        public static final int ZOOM_IN = 264;

        public static final int ZOOM_OUT = 265;

        public static final int FIFTIES = 266;

        public static final int COLORRGB16 = 267;

        public static final int GRADIENT = 268;
    }

    /**
     * Defines the video transitions.
     */
    public static class VideoTransition {
        /** No transition */
        public static final int NONE = 0;

        /** Cross fade transition */
        public static final int CROSS_FADE = 1;

        /** External transition. Currently not available. */
        public static final int EXTERNAL = 256;

        /** AlphaMagic transition. */
        public static final int ALPHA_MAGIC = 257;

        /** Slide transition. */
        public static final int SLIDE_TRANSITION = 258;

        /** Fade to black transition. */
        public static final int FADE_BLACK = 259;
    }

    /**
     * Defines settings for the AlphaMagic transition
     */
    public static class AlphaMagicSettings {
        /** Name of the alpha file (JPEG file). */
        public String file;

        /** Blending percentage [0..100] 0 = no blending. */
        public int blendingPercent;

        /** Invert the default rotation direction of the AlphaMagic effect. */
        public boolean invertRotation;

        public int rgbWidth;
        public int rgbHeight;
    }

    /** Defines the direction of the Slide transition. */
    public static final class SlideDirection {

        /** Right out left in. */
        public static final int RIGHT_OUT_LEFT_IN = 0;

        /** Left out right in. */
        public static final int LEFT_OUT_RIGTH_IN = 1;

        /** Top out bottom in. */
        public static final int TOP_OUT_BOTTOM_IN = 2;

        /** Bottom out top in */
        public static final int BOTTOM_OUT_TOP_IN = 3;
    }

    /** Defines the Slide transition settings. */
    public static class SlideTransitionSettings {
        /**
         * Direction of the slide transition. See {@link SlideDirection
         * SlideDirection} for valid values.
         */
        public int direction;
    }

    /**
     * Defines the settings of a single clip.
     */
    public static class ClipSettings {

        /**
         * The path to the clip file.
         * <p>
         * File format of the clip, it can be:
         * <ul>
         * <li>3GP file containing MPEG4/H263/H264 video and AAC/AMR audio
         * <li>JPG file
         * </ul>
         */

        public String clipPath;

        /**
         * The path of the decoded file. This is used only for image files.
         */
        public String clipDecodedPath;

        /**
         * The path of the Original file. This is used only for image files.
         */
        public String clipOriginalPath;

        /**
         * File type of the clip. See {@link FileType FileType} for valid
         * values.
         */
        public int fileType;

        /** Begin of the cut in the clip in milliseconds. */
        public int beginCutTime;

        /**
         * End of the cut in the clip in milliseconds. Set both
         * <code>beginCutTime</code> and <code>endCutTime</code> to
         * <code>0</code> to get the full length of the clip without a cut. In
         * case of JPG clip, this is the duration of the JPEG file.
         */
        public int endCutTime;

        /**
         * Begin of the cut in the clip in percentage of the file duration.
         */
        public int beginCutPercent;

        /**
         * End of the cut in the clip in percentage of the file duration. Set
         * both <code>beginCutPercent</code> and <code>endCutPercent</code> to
         * <code>0</code> to get the full length of the clip without a cut.
         */
        public int endCutPercent;

        /** Enable panning and zooming. */
        public boolean panZoomEnabled;

        /** Zoom percentage at start of clip. 0 = no zoom, 100 = full zoom */
        public int panZoomPercentStart;

        /** Top left X coordinate at start of clip. */
        public int panZoomTopLeftXStart;

        /** Top left Y coordinate at start of clip. */
        public int panZoomTopLeftYStart;

        /** Zoom percentage at start of clip. 0 = no zoom, 100 = full zoom */
        public int panZoomPercentEnd;

        /** Top left X coordinate at end of clip. */
        public int panZoomTopLeftXEnd;

        /** Top left Y coordinate at end of clip. */
        public int panZoomTopLeftYEnd;

        /**
         * Set The media rendering. See {@link MediaRendering MediaRendering}
         * for valid values.
         */
        public int mediaRendering;

        /**
         * RGB width and Height
         */
         public int rgbWidth;
         public int rgbHeight;
         /**
         * Video rotation degree.
         */
         public int rotationDegree;
    }

    /**
     * Defines settings for a transition.
     */
    public static class TransitionSettings {

        /** Duration of the transition in msec. */
        public int duration;

        /**
         * Transition type for video. See {@link VideoTransition
         * VideoTransition} for valid values.
         */
        public int videoTransitionType;

        /**
         * Transition type for audio. See {@link AudioTransition
         * AudioTransition} for valid values.
         */
        public int audioTransitionType;

        /**
         * Transition behaviour. See {@link TransitionBehaviour
         * TransitionBehaviour} for valid values.
         */
        public int transitionBehaviour;

        /**
         * Settings for AlphaMagic transition. Only needs to be set if
         * <code>videoTransitionType</code> is set to
         * <code>VideoTransition.ALPHA_MAGIC</code>. See
         * {@link AlphaMagicSettings AlphaMagicSettings}.
         */
        public AlphaMagicSettings alphaSettings;

        /**
         * Settings for the Slide transition. See
         * {@link SlideTransitionSettings SlideTransitionSettings}.
         */
        public SlideTransitionSettings slideSettings;
    }

    public static final class AudioTransition {
        /** No audio transition. */
        public static final int NONE = 0;

        /** Cross-fade audio transition. */
        public static final int CROSS_FADE = 1;
    }

    /**
     * Defines transition behaviors.
     */
    public static final class TransitionBehaviour {

        /** The transition uses an increasing speed. */
        public static final int SPEED_UP = 0;

        /** The transition uses a linear (constant) speed. */
        public static final int LINEAR = 1;

        /** The transition uses a decreasing speed. */
        public static final int SPEED_DOWN = 2;

        /**
         * The transition uses a constant speed, but slows down in the middle
         * section.
         */
        public static final int SLOW_MIDDLE = 3;

        /**
         * The transition uses a constant speed, but increases speed in the
         * middle section.
         */
        public static final int FAST_MIDDLE = 4;
    }

    /**
     * Defines settings for the background music.
     */
    public static class BackgroundMusicSettings {

        /** Background music file. */
        public String file;

        /** File type. See {@link FileType FileType} for valid values. */
        public int fileType;

        /**
         * Insertion time in milliseconds, in the output video where the
         * background music must be inserted.
         */
        public long insertionTime;

        /**
         * Volume, as a percentage of the background music track, to use. If
         * this field is set to 100, the background music will replace the audio
         * from the video input file(s).
         */
        public int volumePercent;

        /**
         * Start time in milliseconds in the background muisc file from where
         * the background music should loop. Set both <code>beginLoop</code> and
         * <code>endLoop</code> to <code>0</code> to disable looping.
         */
        public long beginLoop;

        /**
         * End time in milliseconds in the background music file to where the
         * background music should loop. Set both <code>beginLoop</code> and
         * <code>endLoop</code> to <code>0</code> to disable looping.
         */
        public long endLoop;

        public boolean enableDucking;

        public int duckingThreshold;

        public int lowVolume;

        public boolean isLooping;
    }

    /** Defines settings for an effect. */
    public static class AudioEffect {
        /** No audio effect. */
        public static final int NONE = 0;

        /** Fade-in effect. */
        public static final int FADE_IN = 8;

        /** Fade-out effect. */
        public static final int FADE_OUT = 16;
    }

    /** Defines the effect settings. */
    public static class EffectSettings {

        /** Start time of the effect in milliseconds. */
        public int startTime;

        /** Duration of the effect in milliseconds. */
        public int duration;

        /**
         * Video effect type. See {@link VideoEffect VideoEffect} for valid
         * values.
         */
        public int videoEffectType;

        /**
         * Audio effect type. See {@link AudioEffect AudioEffect} for valid
         * values.
         */
        public int audioEffectType;

        /**
         * Start time of the effect in percents of the duration of the clip. A
         * value of 0 percent means start time is from the beginning of the
         * clip.
         */
        public int startPercent;

        /**
         * Duration of the effect in percents of the duration of the clip.
         */
        public int durationPercent;

        /**
         * Framing file.
         * <p>
         * This field is only used when the field <code>videoEffectType</code>
         * is set to {@link VideoEffect#FRAMING VideoEffect.FRAMING}. Otherwise
         * this field is ignored.
         */
        public String framingFile;

        /**
         * Framing buffer.
         * <p>
         * This field is only used when the field <code>videoEffectType</code>
         * is set to {@link VideoEffect#FRAMING VideoEffect.FRAMING}. Otherwise
         * this field is ignored.
         */
        public int[] framingBuffer;

        /**
         * Bitmap type Can be from RGB_565 (4), ARGB_4444 (5), ARGB_8888 (6);
         **/

        public int bitmapType;

        public int width;

        public int height;

        /**
         * Top left x coordinate. This coordinate is used to set the x
         * coordinate of the picture in the framing file when the framing file
         * is selected. The x coordinate is also used to set the location of the
         * text in the text effect.
         * <p>
         * This field is only used when the field <code>videoEffectType</code>
         * is set to {@link VideoEffect#FRAMING VideoEffect.FRAMING} or
         * {@link VideoEffect#TEXT VideoEffect.TEXT}. Otherwise this field is
         * ignored.
         */
        public int topLeftX;

        /**
         * Top left y coordinate. This coordinate is used to set the y
         * coordinate of the picture in the framing file when the framing file
         * is selected. The y coordinate is also used to set the location of the
         * text in the text effect.
         * <p>
         * This field is only used when the field <code>videoEffectType</code>
         * is set to {@link VideoEffect#FRAMING VideoEffect.FRAMING} or
         * {@link VideoEffect#TEXT VideoEffect.TEXT}. Otherwise this field is
         * ignored.
         */
        public int topLeftY;

        /**
         * Should the frame be resized or not. If this field is set to
         * <link>true</code> then the frame size is matched with the output
         * video size.
         * <p>
         * This field is only used when the field <code>videoEffectType</code>
         * is set to {@link VideoEffect#FRAMING VideoEffect.FRAMING}. Otherwise
         * this field is ignored.
         */
        public boolean framingResize;

        /**
         * Size to which the framing buffer needs to be resized to
         * This is valid only if framingResize is true
         */
        public int framingScaledSize;
        /**
         * Text to insert in the video.
         * <p>
         * This field is only used when the field <code>videoEffectType</code>
         * is set to {@link VideoEffect#TEXT VideoEffect.TEXT}. Otherwise this
         * field is ignored.
         */
        public String text;

        /**
         * Text attributes for the text to insert in the video.
         * <p>
         * This field is only used when the field <code>videoEffectType</code>
         * is set to {@link VideoEffect#TEXT VideoEffect.TEXT}. Otherwise this
         * field is ignored. For more details about this field see the
         * integration guide.
         */
        public String textRenderingData;

        /** Width of the text buffer in pixels. */
        public int textBufferWidth;

        /** Height of the text buffer in pixels. */
        public int textBufferHeight;

        /**
         * Processing rate for the fifties effect. A high value (e.g. 30)
         * results in high effect strength.
         * <p>
         * This field is only used when the field <code>videoEffectType</code>
         * is set to {@link VideoEffect#FIFTIES VideoEffect.FIFTIES}. Otherwise
         * this field is ignored.
         */
        public int fiftiesFrameRate;

        /**
         * RGB 16 color of the RGB16 and gradient color effect.
         * <p>
         * This field is only used when the field <code>videoEffectType</code>
         * is set to {@link VideoEffect#COLORRGB16 VideoEffect.COLORRGB16} or
         * {@link VideoEffect#GRADIENT VideoEffect.GRADIENT}. Otherwise this
         * field is ignored.
         */
        public int rgb16InputColor;

        /**
         * Start alpha blending percentage.
         * <p>
         * This field is only used when the field <code>videoEffectType</code>
         * is set to {@link VideoEffect#TEXT VideoEffect.TEXT} or
         * {@link VideoEffect#FRAMING VideoEffect.FRAMING}. Otherwise this field
         * is ignored.
         */
        public int alphaBlendingStartPercent;

        /**
         * Middle alpha blending percentage.
         * <p>
         * This field is only used when the field <code>videoEffectType</code>
         * is set to {@link VideoEffect#TEXT VideoEffect.TEXT} or
         * {@link VideoEffect#FRAMING VideoEffect.FRAMING}. Otherwise this field
         * is ignored.
         */
        public int alphaBlendingMiddlePercent;

        /**
         * End alpha blending percentage.
         * <p>
         * This field is only used when the field <code>videoEffectType</code>
         * is set to {@link VideoEffect#TEXT VideoEffect.TEXT} or
         * {@link VideoEffect#FRAMING VideoEffect.FRAMING}. Otherwise this field
         * is ignored.
         */
        public int alphaBlendingEndPercent;

        /**
         * Duration, in percentage of effect duration of the fade-in phase.
         * <p>
         * This field is only used when the field <code>videoEffectType</code>
         * is set to {@link VideoEffect#TEXT VideoEffect.TEXT} or
         * {@link VideoEffect#FRAMING VideoEffect.FRAMING}. Otherwise this field
         * is ignored.
         */
        public int alphaBlendingFadeInTimePercent;

        /**
         * Duration, in percentage of effect duration of the fade-out phase.
         * <p>
         * This field is only used when the field <code>videoEffectType</code>
         * is set to {@link VideoEffect#TEXT VideoEffect.TEXT} or
         * {@link VideoEffect#FRAMING VideoEffect.FRAMING}. Otherwise this field
         * is ignored.
         */
        public int alphaBlendingFadeOutTimePercent;
    }

    /** Defines the clip properties for preview */
    public static class PreviewClips {

        /**
         * The path to the clip file.
         * <p>
         * File format of the clip, it can be:
         * <ul>
         * <li>3GP file containing MPEG4/H263 video and AAC/AMR audio
         * <li>JPG file
         * </ul>
         */

        public String clipPath;

        /**
         * File type of the clip. See {@link FileType FileType} for valid
         * values.
         */
        public int fileType;

        /** Begin of the cut in the clip in milliseconds. */
        public long beginPlayTime;

        public long endPlayTime;

        /**
         * Set The media rendering. See {@link MediaRendering MediaRendering}
         * for valid values.
         */
        public int mediaRendering;

    }

    /** Defines the audio settings. */
    public static class AudioSettings {

        String pFile;

        /** < PCM file path */
        String Id;

        boolean bRemoveOriginal;

        /** < If true, the original audio track is not taken into account */
        int channels;

        /** < Number of channels (1=mono, 2=stereo) of BGM clip */
        int Fs;

        /**
         * < Sampling audio frequency (8000 for amr, 16000 or more for aac) of
         * BGM clip
         */
        int ExtendedFs;

        /** < Extended frequency for AAC+, eAAC+ streams of BGM clip */
        long startMs;

        /** < Time, in milliseconds, at which the added audio track is inserted */
        long beginCutTime;

        long endCutTime;

        int fileType;

        int volume;

        /** < Volume, in percentage, of the added audio track */
        boolean loop;

        /** < Looping on/off > **/

        /** Audio mix and Duck **/
        int ducking_threshold;

        int ducking_lowVolume;

        boolean bInDucking_enable;

        String pcmFilePath;
    }

    /** Encapsulates preview clips and effect settings */
    public static class PreviewSettings {

        public PreviewClips[] previewClipsArray;

        /** The effect settings. */
        public EffectSettings[] effectSettingsArray;

    }

    /** Encapsulates clip properties */
    public static class PreviewClipProperties {

        public Properties[] clipProperties;

    }

    /** Defines the editing settings. */
    public static class EditSettings {

        /**
         * Array of clip settings. There is one <code>clipSetting</code> for
         * each clip.
         */
        public ClipSettings[] clipSettingsArray;

        /**
         * Array of transition settings. If there are n clips (and thus n
         * <code>clipSettings</code>) then there are (n-1) transitions and (n-1)
         * <code>transistionSettings</code> in
         * <code>transistionSettingsArray</code>.
         */
        public TransitionSettings[] transitionSettingsArray;

        /** The effect settings. */
        public EffectSettings[] effectSettingsArray;

        /**
         * Video frame rate of the output clip. See {@link VideoFrameRate
         * VideoFrameRate} for valid values.
         */
        public int videoFrameRate;

        /** Output file name. Must be an absolute path. */
        public String outputFile;

        /**
         * Size of the video frames in the output clip. See
         * {@link VideoFrameSize VideoFrameSize} for valid values.
         */
        public int videoFrameSize;

        /**
         * Format of the video stream in the output clip. See
         * {@link VideoFormat VideoFormat} for valid values.
         */
        public int videoFormat;

        /**
         * Profile of the video stream in the output clip.
         */
        public int videoProfile;

        /**
         * Level of the video stream in the output clip.
         */
        public int videoLevel;

        /**
         * Format of the audio stream in the output clip. See
         * {@link AudioFormat AudioFormat} for valid values.
         */
        public int audioFormat;

        /**
         * Sampling frequency of the audio stream in the output clip. See
         * {@link AudioSamplingFrequency AudioSamplingFrequency} for valid
         * values.
         */
        public int audioSamplingFreq;

        /**
         * Maximum file size. By setting this you can set the maximum size of
         * the output clip. Set it to <code>0</code> to let the class ignore
         * this filed.
         */
        public int maxFileSize;

        /**
         * Number of audio channels in output clip. Use <code>0</code> for none,
         * <code>1</code> for mono or <code>2</code> for stereo. None is only
         * allowed when the <code>audioFormat</code> field is set to
         * {@link AudioFormat#NO_AUDIO AudioFormat.NO_AUDIO} or
         * {@link AudioFormat#NULL_AUDIO AudioFormat.NULL_AUDIO} Mono is only
         * allowed when the <code>audioFormat</code> field is set to
         * {@link AudioFormat#AAC AudioFormat.AAC}
         */
        public int audioChannels;

        /** Video bitrate. See {@link Bitrate Bitrate} for valid values. */
        public int videoBitrate;

        /** Audio bitrate. See {@link Bitrate Bitrate} for valid values. */
        public int audioBitrate;

        /**
         * Background music settings. See {@link BackgroundMusicSettings
         * BackgroundMusicSettings} for valid values.
         */
        public BackgroundMusicSettings backgroundMusicSettings;

        public int primaryTrackVolume;

    }

    /**
     * Defines the media properties.
     **/

    public static class Properties {

        /**
         * Duration of the media in milliseconds.
         */

        public int duration;

        /**
         * File type.
         */

        public int fileType;

        /**
         * Video format.
         */

        public int videoFormat;

        /**
         * Duration of the video stream of the media in milliseconds.
         */

        public int videoDuration;

        /**
         * Bitrate of the video stream of the media.
         */

        public int videoBitrate;

        /**
         * Width of the video frames or the width of the still picture in
         * pixels.
         */

        public int width;

        /**
         * Height of the video frames or the height of the still picture in
         * pixels.
         */

        public int height;

        /**
         * Average frame rate of video in the media in frames per second.
         */

        public float averageFrameRate;

        /**
         * Profile of the video in the media.
         */

        public int profile;

        /**
         * Level of the video in the media.
         */

        public int level;

        /**
         * Is Video Profile supported.
         */

        public boolean profileSupported;

        /**
         * Is Video Level supported.
         */

        public boolean levelSupported;

        /**
         * Audio format.
         */

        public int audioFormat;

        /**
         * Duration of the audio stream of the media in milliseconds.
         */

        public int audioDuration;

        /**
         * Bitrate of the audio stream of the media.
         */

        public int audioBitrate;

        /**
         * Number of audio channels in the media.
         */

        public int audioChannels;

        /**
         * Sampling frequency of the audio stream in the media in samples per
         * second.
         */

        public int audioSamplingFrequency;

        /**
         * Volume value of the audio track as percentage.
         */
        public int audioVolumeValue;

        /**
         * Video rotation degree.
         */
        public int videoRotation;

        public String Id;
    }

    /**
     * Constructor
     *
     * @param projectPath The path where the VideoEditor stores all files
     *        related to the project
     * @param lock The semaphore
     * @param veObj The video editor reference
     */
    public MediaArtistNativeHelper(String projectPath, Semaphore lock, VideoEditor veObj) {
        mProjectPath = projectPath;
        if (veObj != null) {
            mVideoEditor = veObj;
        } else {
            mVideoEditor = null;
            throw new IllegalArgumentException("video editor object is null");
        }
        if (mStoryBoardSettings == null) {
            mStoryBoardSettings = new EditSettings();
        }

        mLock = lock;

        _init(mProjectPath, "null");
        mAudioTrackPCMFilePath = null;
    }

    /**
     * @return The project path
     */
    String getProjectPath() {
        return mProjectPath;
    }

    /**
     * @return The Audio Track PCM file path
     */
    String getProjectAudioTrackPCMFilePath() {
        return mAudioTrackPCMFilePath;
    }

    /**
     * Invalidates the PCM file
     */
    void invalidatePcmFile() {
        if (mAudioTrackPCMFilePath != null) {
            new File(mAudioTrackPCMFilePath).delete();
            mAudioTrackPCMFilePath = null;
        }
    }

    @SuppressWarnings("unused")
    private void onProgressUpdate(int taskId, int progress) {
        if (mProcessingState == PROCESSING_EXPORT) {
            if (mExportProgressListener != null) {
                if (mProgressToApp < progress) {
                    mExportProgressListener.onProgress(mVideoEditor, mOutputFilename, progress);
                    /* record previous progress */
                    mProgressToApp = progress;
                }
            }
        }
        else {
            // Adapt progress depending on current state
            int actualProgress = 0;
            int action = 0;

            if (mProcessingState == PROCESSING_AUDIO_PCM) {
                action = MediaProcessingProgressListener.ACTION_DECODE;
            } else {
                action = MediaProcessingProgressListener.ACTION_ENCODE;
            }

            switch (mProcessingState) {
                case PROCESSING_AUDIO_PCM:
                    actualProgress = progress;
                    break;
                case PROCESSING_TRANSITION:
                    actualProgress = progress;
                    break;
                case PROCESSING_KENBURNS:
                    actualProgress = progress;
                    break;
                case PROCESSING_INTERMEDIATE1:
                    if ((progress == 0) && (mProgressToApp != 0)) {
                        mProgressToApp = 0;
                    }
                    if ((progress != 0) || (mProgressToApp != 0)) {
                        actualProgress = progress/4;
                    }
                    break;
                case PROCESSING_INTERMEDIATE2:
                    if ((progress != 0) || (mProgressToApp != 0)) {
                        actualProgress = 25 + progress/4;
                    }
                    break;
                case PROCESSING_INTERMEDIATE3:
                    if ((progress != 0) || (mProgressToApp != 0)) {
                        actualProgress = 50 + progress/2;
                    }
                    break;
                case PROCESSING_NONE:

                default:
                    Log.e(TAG, "ERROR unexpected State=" + mProcessingState);
                    return;
            }
            if ((mProgressToApp != actualProgress) && (actualProgress != 0)) {

                mProgressToApp = actualProgress;

                if (mMediaProcessingProgressListener != null) {
                    // Send the progress indication
                    mMediaProcessingProgressListener.onProgress(mProcessingObject, action,
                                                                actualProgress);
                }
            }
            /* avoid 0 in next intermediate call */
            if (mProgressToApp == 0) {
                if (mMediaProcessingProgressListener != null) {
                    /*
                     *  Send the progress indication
                     */
                    mMediaProcessingProgressListener.onProgress(mProcessingObject, action,
                                                                actualProgress);
                }
                mProgressToApp = 1;
            }
        }
    }

    @SuppressWarnings("unused")
    private void onPreviewProgressUpdate(int progress, boolean isFinished,
                  boolean updateOverlay, String filename, int renderingMode, int error) {
        if (mPreviewProgressListener != null) {
            if (mIsFirstProgress) {
                mPreviewProgressListener.onStart(mVideoEditor);
                mIsFirstProgress = false;
            }

            final VideoEditor.OverlayData overlayData;
            if (updateOverlay) {
                overlayData = new VideoEditor.OverlayData();
                if (filename != null) {
                    overlayData.set(BitmapFactory.decodeFile(filename), renderingMode);
                } else {
                    overlayData.setClear();
                }
            } else {
                overlayData = null;
            }

            if (progress != 0) {
                mPreviewProgress = progress;
            }

            if (isFinished) {
                mPreviewProgressListener.onStop(mVideoEditor);
            } else if (error != 0) {
                mPreviewProgressListener.onError(mVideoEditor, error);
            } else {
                mPreviewProgressListener.onProgress(mVideoEditor, progress, overlayData);
            }
        }
    }

    /**
     * Release the native helper object
     */
    void releaseNativeHelper() throws InterruptedException {
        release();
    }

    /**
     * Release the native helper to end the Audio Graph process
     */
    @SuppressWarnings("unused")
    private void onAudioGraphExtractProgressUpdate(int progress, boolean isVideo) {
        if ((mExtractAudioWaveformProgressListener != null) && (progress > 0)) {
            mExtractAudioWaveformProgressListener.onProgress(progress);
        }
    }

    /**
     * Populates the Effect Settings in EffectSettings
     *
     * @param effects The reference of EffectColor
     *
     * @return The populated effect settings in EffectSettings reference
     */
    EffectSettings getEffectSettings(EffectColor effects) {
        EffectSettings effectSettings = new EffectSettings();
        effectSettings.startTime = (int)effects.getStartTime();
        effectSettings.duration = (int)effects.getDuration();
        effectSettings.videoEffectType = getEffectColorType(effects);
        effectSettings.audioEffectType = 0;
        effectSettings.startPercent = 0;
        effectSettings.durationPercent = 0;
        effectSettings.framingFile = null;
        effectSettings.topLeftX = 0;
        effectSettings.topLeftY = 0;
        effectSettings.framingResize = false;
        effectSettings.text = null;
        effectSettings.textRenderingData = null;
        effectSettings.textBufferWidth = 0;
        effectSettings.textBufferHeight = 0;
        if (effects.getType() == EffectColor.TYPE_FIFTIES) {
            effectSettings.fiftiesFrameRate = 15;
        } else {
            effectSettings.fiftiesFrameRate = 0;
        }

        if ((effectSettings.videoEffectType == VideoEffect.COLORRGB16)
                || (effectSettings.videoEffectType == VideoEffect.GRADIENT)) {
            effectSettings.rgb16InputColor = effects.getColor();
        }

        effectSettings.alphaBlendingStartPercent = 0;
        effectSettings.alphaBlendingMiddlePercent = 0;
        effectSettings.alphaBlendingEndPercent = 0;
        effectSettings.alphaBlendingFadeInTimePercent = 0;
        effectSettings.alphaBlendingFadeOutTimePercent = 0;
        return effectSettings;
    }

    /**
     * Populates the Overlay Settings in EffectSettings
     *
     * @param overlay The reference of OverlayFrame
     *
     * @return The populated overlay settings in EffectSettings reference
     */
    EffectSettings getOverlaySettings(OverlayFrame overlay) {
        EffectSettings effectSettings = new EffectSettings();
        Bitmap bitmap = null;

        effectSettings.startTime = (int)overlay.getStartTime();
        effectSettings.duration = (int)overlay.getDuration();
        effectSettings.videoEffectType = VideoEffect.FRAMING;
        effectSettings.audioEffectType = 0;
        effectSettings.startPercent = 0;
        effectSettings.durationPercent = 0;
        effectSettings.framingFile = null;

        if ((bitmap = overlay.getBitmap()) != null) {
            effectSettings.framingFile = overlay.getFilename();

            if (effectSettings.framingFile == null) {
                try {
                    (overlay).save(mProjectPath);
                } catch (IOException e) {
                    Log.e(TAG, "getOverlaySettings : File not found");
                }
                effectSettings.framingFile = overlay.getFilename();
            }
            if (bitmap.getConfig() == Bitmap.Config.ARGB_8888)
                effectSettings.bitmapType = 6;
            else if (bitmap.getConfig() == Bitmap.Config.ARGB_4444)
                effectSettings.bitmapType = 5;
            else if (bitmap.getConfig() == Bitmap.Config.RGB_565)
                effectSettings.bitmapType = 4;
            else if (bitmap.getConfig() == Bitmap.Config.ALPHA_8)
                throw new RuntimeException("Bitmap config not supported");

            effectSettings.width = bitmap.getWidth();
            effectSettings.height = bitmap.getHeight();
            effectSettings.framingBuffer = new int[effectSettings.width];
            int tmp = 0;
            short maxAlpha = 0;
            short minAlpha = (short)0xFF;
            short alpha = 0;
            while (tmp < effectSettings.height) {
                bitmap.getPixels(effectSettings.framingBuffer, 0,
                                 effectSettings.width, 0, tmp,
                                 effectSettings.width, 1);
                for (int i = 0; i < effectSettings.width; i++) {
                    alpha = (short)((effectSettings.framingBuffer[i] >> 24) & 0xFF);
                    if (alpha > maxAlpha) {
                        maxAlpha = alpha;
                    }
                    if (alpha < minAlpha) {
                        minAlpha = alpha;
                    }
                }
                tmp += 1;
            }
            alpha = (short)((maxAlpha + minAlpha) / 2);
            alpha = (short)((alpha * 100) / 256);
            effectSettings.alphaBlendingEndPercent = alpha;
            effectSettings.alphaBlendingMiddlePercent = alpha;
            effectSettings.alphaBlendingStartPercent = alpha;
            effectSettings.alphaBlendingFadeInTimePercent = 100;
            effectSettings.alphaBlendingFadeOutTimePercent = 100;
            effectSettings.framingBuffer = null;

            /*
             * Set the resized RGB file dimensions
             */
            effectSettings.width = overlay.getResizedRGBSizeWidth();
            if(effectSettings.width == 0) {
                effectSettings.width = bitmap.getWidth();
            }

            effectSettings.height = overlay.getResizedRGBSizeHeight();
            if(effectSettings.height == 0) {
                effectSettings.height = bitmap.getHeight();
            }

        }

        effectSettings.topLeftX = 0;
        effectSettings.topLeftY = 0;

        effectSettings.framingResize = true;
        effectSettings.text = null;
        effectSettings.textRenderingData = null;
        effectSettings.textBufferWidth = 0;
        effectSettings.textBufferHeight = 0;
        effectSettings.fiftiesFrameRate = 0;
        effectSettings.rgb16InputColor = 0;
        int mediaItemHeight;
        int aspectRatio;
        if (overlay.getMediaItem() instanceof MediaImageItem) {
            if (((MediaImageItem)overlay.getMediaItem()).getGeneratedImageClip() != null) {
                // Ken Burns was applied
                mediaItemHeight = ((MediaImageItem)overlay.getMediaItem()).getGeneratedClipHeight();
                aspectRatio = getAspectRatio(
                    ((MediaImageItem)overlay.getMediaItem()).getGeneratedClipWidth()
                    , mediaItemHeight);
            } else {
                //For image get the scaled height. Aspect ratio would remain the same
                mediaItemHeight = ((MediaImageItem)overlay.getMediaItem()).getScaledHeight();
                aspectRatio = overlay.getMediaItem().getAspectRatio();
            }
        } else {
            aspectRatio = overlay.getMediaItem().getAspectRatio();
            mediaItemHeight = overlay.getMediaItem().getHeight();
        }
        effectSettings.framingScaledSize = findVideoResolution(aspectRatio, mediaItemHeight);
        return effectSettings;
    }

     /* get Video Editor aspect ratio */
    int nativeHelperGetAspectRatio() {
        return mVideoEditor.getAspectRatio();
    }

    /**
     * Sets the export audio codec
     *
     * @param export audio codec
     *
     */
    void setAudioCodec(int codec) {
        mExportAudioCodec = codec;
    }
    /**
     * Sets the export video codec
     *
     * @param export video codec
     *
     */
    void setVideoCodec(int codec) {
        mExportVideoCodec = codec;
    }

    /**
     * Sets the audio regenerate flag
     *
     * @param flag The boolean to set the audio regenerate flag
     *
     */
    void setAudioflag(boolean flag) {
        //check if the file exists.
        if (!(new File(String.format(mProjectPath + "/" + AUDIO_TRACK_PCM_FILE)).exists())) {
            flag = true;
        }
        mRegenerateAudio = flag;
    }

    /**
     * Gets the audio regenerate flag
     *
     * @param return The boolean to get the audio regenerate flag
     *
     */
    boolean getAudioflag() {
        return mRegenerateAudio;
    }

    /**
     * Maps the average frame rate to one of the defined enum values
     *
     * @param averageFrameRate The average frame rate of video item
     *
     * @return The frame rate from one of the defined enum values
     */
    int GetClosestVideoFrameRate(int averageFrameRate) {
        if (averageFrameRate >= 25) {
            return VideoFrameRate.FR_30_FPS;
        } else if (averageFrameRate >= 20) {
            return VideoFrameRate.FR_25_FPS;
        } else if (averageFrameRate >= 15) {
            return VideoFrameRate.FR_20_FPS;
        } else if (averageFrameRate >= 12) {
            return VideoFrameRate.FR_15_FPS;
        } else if (averageFrameRate >= 10) {
            return VideoFrameRate.FR_12_5_FPS;
        } else if (averageFrameRate >= 7) {
            return VideoFrameRate.FR_10_FPS;
        } else if (averageFrameRate >= 5) {
            return VideoFrameRate.FR_7_5_FPS;
        } else {
            return -1;
        }
    }

    /**
     * Helper function to adjust the effect or overlay start time
     * depending on the begin and end boundary time of meddia item
     */
    public void adjustEffectsStartTimeAndDuration(EffectSettings lEffect, int beginCutTime,
                                                  int endCutTime) {

        int effectStartTime = 0;
        int effectDuration = 0;

        /**
         * cbct -> clip begin cut time
         * cect -> clip end cut time
         ****************************************
         *  |                                 |
         *  |         cbct        cect        |
         *  | <-1-->   |           |          |
         *  |       <--|-2->       |          |
         *  |          | <---3---> |          |
         *  |          |        <--|-4--->    |
         *  |          |           | <--5-->  |
         *  |      <---|------6----|---->     |
         *  |                                 |
         *  < : effectStart
         *  > : effectStart + effectDuration
         ****************************************
         **/

        /** 1 & 5 */
        /**
         * Effect falls out side the trim duration. In such a case effects shall
         * not be applied.
         */
        if ((lEffect.startTime > endCutTime)
                || ((lEffect.startTime + lEffect.duration) <= beginCutTime)) {

            effectStartTime = 0;
            effectDuration = 0;

            lEffect.startTime = effectStartTime;
            lEffect.duration = effectDuration;
            return;
        }

        /** 2 */
        if ((lEffect.startTime < beginCutTime)
                && ((lEffect.startTime + lEffect.duration) > beginCutTime)
                && ((lEffect.startTime + lEffect.duration) <= endCutTime)) {
            effectStartTime = 0;
            effectDuration = lEffect.duration;

            effectDuration -= (beginCutTime - lEffect.startTime);
            lEffect.startTime = effectStartTime;
            lEffect.duration = effectDuration;
            return;
        }

        /** 3 */
        if ((lEffect.startTime >= beginCutTime)
                && ((lEffect.startTime + lEffect.duration) <= endCutTime)) {
            effectStartTime = lEffect.startTime - beginCutTime;
            lEffect.startTime = effectStartTime;
            lEffect.duration = lEffect.duration;
            return;
        }

        /** 4 */
        if ((lEffect.startTime >= beginCutTime)
                && ((lEffect.startTime + lEffect.duration) > endCutTime)) {
            effectStartTime = lEffect.startTime - beginCutTime;
            effectDuration = endCutTime - lEffect.startTime;
            lEffect.startTime = effectStartTime;
            lEffect.duration = effectDuration;
            return;
        }

        /** 6 */
        if ((lEffect.startTime < beginCutTime)
                && ((lEffect.startTime + lEffect.duration) > endCutTime)) {
            effectStartTime = 0;
            effectDuration = endCutTime - beginCutTime;
            lEffect.startTime = effectStartTime;
            lEffect.duration = effectDuration;
            return;
        }

    }

    /**
     * Generates the clip for preview or export
     *
     * @param editSettings The EditSettings reference for generating
     * a clip for preview or export
     *
     * @return error value
     */
    public int generateClip(EditSettings editSettings) {
        int err = 0;

        try {
            err = nativeGenerateClip(editSettings);
        } catch (IllegalArgumentException ex) {
            Log.e(TAG, "Illegal Argument exception in load settings");
            return -1;
        } catch (IllegalStateException ex) {
            Log.e(TAG, "Illegal state exception in load settings");
            return -1;
        } catch (RuntimeException ex) {
            Log.e(TAG, "Runtime exception in load settings");
            return -1;
        }
        return err;
    }

    /**
     * Init function to initialiZe the  ClipSettings reference to
     * default values
     *
     * @param lclipSettings The ClipSettings reference
     */
    void initClipSettings(ClipSettings lclipSettings) {
        lclipSettings.clipPath = null;
        lclipSettings.clipDecodedPath = null;
        lclipSettings.clipOriginalPath = null;
        lclipSettings.fileType = 0;
        lclipSettings.endCutTime = 0;
        lclipSettings.beginCutTime = 0;
        lclipSettings.beginCutPercent = 0;
        lclipSettings.endCutPercent = 0;
        lclipSettings.panZoomEnabled = false;
        lclipSettings.panZoomPercentStart = 0;
        lclipSettings.panZoomTopLeftXStart = 0;
        lclipSettings.panZoomTopLeftYStart = 0;
        lclipSettings.panZoomPercentEnd = 0;
        lclipSettings.panZoomTopLeftXEnd = 0;
        lclipSettings.panZoomTopLeftYEnd = 0;
        lclipSettings.mediaRendering = 0;
        lclipSettings.rotationDegree = 0;
    }


    /**
     * Populates the settings for generating an effect clip
     *
     * @param lMediaItem The media item for which the effect clip
     * needs to be generated
     * @param lclipSettings The ClipSettings reference containing
     * clips data
     * @param e The EditSettings reference containing effect specific data
     * @param uniqueId The unique id used in the name of the output clip
     * @param clipNo Used for internal purpose
     *
     * @return The name and path of generated clip
     */
    String generateEffectClip(MediaItem lMediaItem, ClipSettings lclipSettings,
            EditSettings e,String uniqueId,int clipNo) {
        int err = 0;
        EditSettings editSettings = null;
        String EffectClipPath = null;
        int outVideoProfile = 0;
        int outVideoLevel = 0;
        editSettings = new EditSettings();

        editSettings.clipSettingsArray = new ClipSettings[1];
        editSettings.clipSettingsArray[0] = lclipSettings;

        editSettings.backgroundMusicSettings = null;
        editSettings.transitionSettingsArray = null;
        editSettings.effectSettingsArray = e.effectSettingsArray;

        EffectClipPath = String.format(mProjectPath + "/" + "ClipEffectIntermediate" + "_"
                + lMediaItem.getId() + uniqueId + ".3gp");

        File tmpFile = new File(EffectClipPath);
        if (tmpFile.exists()) {
            tmpFile.delete();
        }

        outVideoProfile = VideoEditorProfile.getExportProfile(VideoFormat.H264);
        outVideoLevel = VideoEditorProfile.getExportLevel(VideoFormat.H264);
        editSettings.videoProfile = outVideoProfile;
        editSettings.videoLevel= outVideoLevel;

        if (lMediaItem instanceof MediaVideoItem) {
            MediaVideoItem m = (MediaVideoItem)lMediaItem;

            editSettings.audioFormat = AudioFormat.AAC;
            editSettings.audioChannels = 2;
            editSettings.audioBitrate = Bitrate.BR_64_KBPS;
            editSettings.audioSamplingFreq = AudioSamplingFrequency.FREQ_32000;

            editSettings.videoFormat = VideoFormat.H264;
            editSettings.videoFrameRate = VideoFrameRate.FR_30_FPS;
            editSettings.videoFrameSize = findVideoResolution(mVideoEditor.getAspectRatio(),
                    m.getHeight());
            editSettings.videoBitrate = findVideoBitrate(editSettings.videoFrameSize);
        } else {
            MediaImageItem m = (MediaImageItem)lMediaItem;
            editSettings.audioBitrate = Bitrate.BR_64_KBPS;
            editSettings.audioChannels = 2;
            editSettings.audioFormat = AudioFormat.AAC;
            editSettings.audioSamplingFreq = AudioSamplingFrequency.FREQ_32000;

            editSettings.videoFormat = VideoFormat.H264;
            editSettings.videoFrameRate = VideoFrameRate.FR_30_FPS;
            editSettings.videoFrameSize = findVideoResolution(mVideoEditor.getAspectRatio(),
                    m.getScaledHeight());
            editSettings.videoBitrate = findVideoBitrate(editSettings.videoFrameSize);
        }

        editSettings.outputFile = EffectClipPath;

        if (clipNo == 1) {
            mProcessingState  = PROCESSING_INTERMEDIATE1;
        } else if (clipNo == 2) {
            mProcessingState  = PROCESSING_INTERMEDIATE2;
        }
        mProcessingObject = lMediaItem;
        err = generateClip(editSettings);
        mProcessingState  = PROCESSING_NONE;

        if (err == 0) {
            lclipSettings.clipPath = EffectClipPath;
            lclipSettings.fileType = FileType.THREE_GPP;
            return EffectClipPath;
        } else {
            throw new RuntimeException("preview generation cannot be completed");
        }
    }


    /**
     * Populates the settings for generating a Ken Burn effect clip
     *
     * @param m The media image item for which the Ken Burn effect clip
     * needs to be generated
     * @param e The EditSettings reference clip specific data
     *
     * @return The name and path of generated clip
     */
    String generateKenBurnsClip(EditSettings e, MediaImageItem m) {
        String output = null;
        int err = 0;
        int outVideoProfile = 0;
        int outVideoLevel = 0;

        e.backgroundMusicSettings = null;
        e.transitionSettingsArray = null;
        e.effectSettingsArray = null;
        output = String.format(mProjectPath + "/" + "ImageClip-" + m.getId() + ".3gp");

        File tmpFile = new File(output);
        if (tmpFile.exists()) {
            tmpFile.delete();
        }

        outVideoProfile = VideoEditorProfile.getExportProfile(VideoFormat.H264);
        outVideoLevel = VideoEditorProfile.getExportLevel(VideoFormat.H264);
        e.videoProfile = outVideoProfile;
        e.videoLevel = outVideoLevel;

        e.outputFile = output;
        e.audioBitrate = Bitrate.BR_64_KBPS;
        e.audioChannels = 2;
        e.audioFormat = AudioFormat.AAC;
        e.audioSamplingFreq = AudioSamplingFrequency.FREQ_32000;

        e.videoFormat = VideoFormat.H264;
        e.videoFrameRate = VideoFrameRate.FR_30_FPS;
        e.videoFrameSize = findVideoResolution(mVideoEditor.getAspectRatio(),
                                                           m.getScaledHeight());
        e.videoBitrate = findVideoBitrate(e.videoFrameSize);

        mProcessingState  = PROCESSING_KENBURNS;
        mProcessingObject = m;
        err = generateClip(e);
        // Reset the processing state and check for errors
        mProcessingState  = PROCESSING_NONE;
        if (err != 0) {
            throw new RuntimeException("preview generation cannot be completed");
        }
        return output;
    }


    /**
     * Calculates the output resolution for transition clip
     *
     * @param m1 First media item associated with transition
     * @param m2 Second media item associated with transition
     *
     * @return The transition resolution
     */
    private int getTransitionResolution(MediaItem m1, MediaItem m2) {
        int clip1Height = 0;
        int clip2Height = 0;
        int videoSize = 0;

        if (m1 != null && m2 != null) {
            if (m1 instanceof MediaVideoItem) {
                clip1Height = m1.getHeight();
            } else if (m1 instanceof MediaImageItem) {
                clip1Height = ((MediaImageItem)m1).getScaledHeight();
            }
            if (m2 instanceof MediaVideoItem) {
                clip2Height = m2.getHeight();
            } else if (m2 instanceof MediaImageItem) {
                clip2Height = ((MediaImageItem)m2).getScaledHeight();
            }
            if (clip1Height > clip2Height) {
                videoSize = findVideoResolution(mVideoEditor.getAspectRatio(), clip1Height);
            } else {
                videoSize = findVideoResolution(mVideoEditor.getAspectRatio(), clip2Height);
            }
        } else if (m1 == null && m2 != null) {
            if (m2 instanceof MediaVideoItem) {
                clip2Height = m2.getHeight();
            } else if (m2 instanceof MediaImageItem) {
                clip2Height = ((MediaImageItem)m2).getScaledHeight();
            }
            videoSize = findVideoResolution(mVideoEditor.getAspectRatio(), clip2Height);
        } else if (m1 != null && m2 == null) {
            if (m1 instanceof MediaVideoItem) {
                clip1Height = m1.getHeight();
            } else if (m1 instanceof MediaImageItem) {
                clip1Height = ((MediaImageItem)m1).getScaledHeight();
            }
            videoSize = findVideoResolution(mVideoEditor.getAspectRatio(), clip1Height);
        }
        return videoSize;
    }

    /**
     * Populates the settings for generating an transition clip
     *
     * @param m1 First media item associated with transition
     * @param m2 Second media item associated with transition
     * @param e The EditSettings reference containing
     * clip specific data
     * @param uniqueId The unique id used in the name of the output clip
     * @param t The Transition specific data
     *
     * @return The name and path of generated clip
     */
    String generateTransitionClip(EditSettings e, String uniqueId,
            MediaItem m1, MediaItem m2,Transition t) {
        String outputFilename = null;
        int err = 0;
        int outVideoProfile = 0;
        int outVideoLevel = 0;
        outputFilename = String.format(mProjectPath + "/" + uniqueId + ".3gp");

        outVideoProfile = VideoEditorProfile.getExportProfile(VideoFormat.H264);
        outVideoLevel = VideoEditorProfile.getExportLevel(VideoFormat.H264);
        e.videoProfile = outVideoProfile;
        e.videoLevel = outVideoLevel;

        e.outputFile = outputFilename;
        e.audioBitrate = Bitrate.BR_64_KBPS;
        e.audioChannels = 2;
        e.audioFormat = AudioFormat.AAC;
        e.audioSamplingFreq = AudioSamplingFrequency.FREQ_32000;

        e.videoFormat = VideoFormat.H264;
        e.videoFrameRate = VideoFrameRate.FR_30_FPS;
        e.videoFrameSize = getTransitionResolution(m1, m2);
        e.videoBitrate = findVideoBitrate(e.videoFrameSize);

        if (new File(outputFilename).exists()) {
            new File(outputFilename).delete();
        }
        mProcessingState  = PROCESSING_INTERMEDIATE3;
        mProcessingObject = t;
        err = generateClip(e);
        // Reset the processing state and check for errors
        mProcessingState  = PROCESSING_NONE;
        if (err != 0) {
            throw new RuntimeException("preview generation cannot be completed");
        }
        return outputFilename;
    }

    /**
     * Populates effects and overlays in EffectSettings structure
     * and also adjust the start time and duration of effects and overlays
     * w.r.t to total story board time
     *
     * @param m1 Media item associated with effect
     * @param effectSettings The EffectSettings reference containing
     *      effect specific data
     * @param beginCutTime The begin cut time of the clip associated with effect
     * @param endCutTime The end cut time of the clip associated with effect
     * @param storyBoardTime The current story board time
     *
     * @return The updated index
     */
    private int populateEffects(MediaItem m, EffectSettings[] effectSettings, int i,
            int beginCutTime, int endCutTime, int storyBoardTime) {

        if (m.getBeginTransition() != null && m.getBeginTransition().getDuration() > 0
                && m.getEndTransition() != null && m.getEndTransition().getDuration() > 0) {
            beginCutTime += m.getBeginTransition().getDuration();
            endCutTime -= m.getEndTransition().getDuration();
        } else if (m.getBeginTransition() == null && m.getEndTransition() != null
                && m.getEndTransition().getDuration() > 0) {
            endCutTime -= m.getEndTransition().getDuration();
        } else if (m.getEndTransition() == null && m.getBeginTransition() != null
                && m.getBeginTransition().getDuration() > 0) {
            beginCutTime += m.getBeginTransition().getDuration();
        }

        final List<Effect> effects = m.getAllEffects();
        final List<Overlay> overlays = m.getAllOverlays();

        for (Overlay overlay : overlays) {
            effectSettings[i] = getOverlaySettings((OverlayFrame)overlay);
            adjustEffectsStartTimeAndDuration(effectSettings[i], beginCutTime, endCutTime);
            effectSettings[i].startTime += storyBoardTime;
            i++;
        }

        for (Effect effect : effects) {
            if (effect instanceof EffectColor) {
                effectSettings[i] = getEffectSettings((EffectColor)effect);
                adjustEffectsStartTimeAndDuration(effectSettings[i], beginCutTime, endCutTime);
                effectSettings[i].startTime += storyBoardTime;
                i++;
            }
        }

        return i;
    }

    /**
     * Adjusts the media item boundaries for use in export or preview
     *
     * @param clipSettings The ClipSettings reference
     * @param clipProperties The Properties reference
     * @param m The media item
     */
    private void adjustMediaItemBoundary(ClipSettings clipSettings,
                                         Properties clipProperties, MediaItem m) {
        if (m.getBeginTransition() != null && m.getBeginTransition().getDuration() > 0
                && m.getEndTransition() != null && m.getEndTransition().getDuration() > 0) {
            clipSettings.beginCutTime += m.getBeginTransition().getDuration();
            clipSettings.endCutTime -= m.getEndTransition().getDuration();
        } else if (m.getBeginTransition() == null && m.getEndTransition() != null
                && m.getEndTransition().getDuration() > 0) {
            clipSettings.endCutTime -= m.getEndTransition().getDuration();
        } else if (m.getEndTransition() == null && m.getBeginTransition() != null
                && m.getBeginTransition().getDuration() > 0) {
            clipSettings.beginCutTime += m.getBeginTransition().getDuration();
        }

        clipProperties.duration = clipSettings.endCutTime - clipSettings.beginCutTime;

        if (clipProperties.videoDuration != 0) {
            clipProperties.videoDuration = clipSettings.endCutTime - clipSettings.beginCutTime;
        }

        if (clipProperties.audioDuration != 0) {
            clipProperties.audioDuration = clipSettings.endCutTime - clipSettings.beginCutTime;
        }
    }

    /**
     * Generates the transition if transition is present
     * and is in invalidated state
     *
     * @param transition The Transition reference
     * @param editSettings The EditSettings reference
     * @param clipPropertiesArray The clip Properties array
     * @param i The index in clip Properties array for current clip
     */
    private void generateTransition(Transition transition, EditSettings editSettings,
            PreviewClipProperties clipPropertiesArray, int index) {
        if (!(transition.isGenerated())) {
            transition.generate();
        }
        editSettings.clipSettingsArray[index] = new ClipSettings();
        editSettings.clipSettingsArray[index].clipPath = transition.getFilename();
        editSettings.clipSettingsArray[index].fileType = FileType.THREE_GPP;
        editSettings.clipSettingsArray[index].beginCutTime = 0;
        editSettings.clipSettingsArray[index].endCutTime = (int)transition.getDuration();
        editSettings.clipSettingsArray[index].mediaRendering = MediaRendering.BLACK_BORDERS;

        try {
            clipPropertiesArray.clipProperties[index] =
                getMediaProperties(transition.getFilename());
        } catch (Exception e) {
            throw new IllegalArgumentException("Unsupported file or file not found");
        }

        clipPropertiesArray.clipProperties[index].Id = null;
        clipPropertiesArray.clipProperties[index].audioVolumeValue = 100;
        clipPropertiesArray.clipProperties[index].duration = (int)transition.getDuration();
        if (clipPropertiesArray.clipProperties[index].videoDuration != 0) {
            clipPropertiesArray.clipProperties[index].videoDuration = (int)transition.getDuration();
        }

        if (clipPropertiesArray.clipProperties[index].audioDuration != 0) {
            clipPropertiesArray.clipProperties[index].audioDuration = (int)transition.getDuration();
        }
    }

    /**
     * Sets the volume for current media item in clip properties array
     *
     * @param m The media item
     * @param clipProperties The clip properties array reference
     * @param i The index in clip Properties array for current clip
     */
    private void adjustVolume(MediaItem m, PreviewClipProperties clipProperties,
                              int index) {
        if (m instanceof MediaVideoItem) {
            final boolean videoMuted = ((MediaVideoItem)m).isMuted();
            if (videoMuted == false) {
                mClipProperties.clipProperties[index].audioVolumeValue =
                    ((MediaVideoItem)m).getVolume();
            } else {
                mClipProperties.clipProperties[index].audioVolumeValue = 0;
            }
        } else if (m instanceof MediaImageItem) {
            mClipProperties.clipProperties[index].audioVolumeValue = 0;
        }
    }

    /**
     * Checks for odd size image width and height
     *
     * @param m The media item
     * @param clipProperties The clip properties array reference
     * @param i The index in clip Properties array for current clip
     */
    private void checkOddSizeImage(MediaItem m, PreviewClipProperties clipProperties, int index) {
        if (m instanceof MediaImageItem) {
            int width = mClipProperties.clipProperties[index].width;
            int height = mClipProperties.clipProperties[index].height;

            if ((width % 2) != 0) {
                width -= 1;
            }
            if ((height % 2) != 0) {
                height -= 1;
            }
            mClipProperties.clipProperties[index].width = width;
            mClipProperties.clipProperties[index].height = height;
        }
    }

    /**
     * Populates the media item properties and calculates the maximum
     * height among all the clips
     *
     * @param m The media item
     * @param i The index in clip Properties array for current clip
     * @param maxHeight The max height from the clip properties
     *
     * @return Updates the max height if current clip's height is greater
     * than all previous clips height
     */
    private int populateMediaItemProperties(MediaItem m, int index, int maxHeight) {
        mPreviewEditSettings.clipSettingsArray[index] = new ClipSettings();
        if (m instanceof MediaVideoItem) {
            mPreviewEditSettings.clipSettingsArray[index] =
                ((MediaVideoItem)m).getVideoClipProperties();
            if (((MediaVideoItem)m).getHeight() > maxHeight) {
                maxHeight = ((MediaVideoItem)m).getHeight();
            }
        } else if (m instanceof MediaImageItem) {
            mPreviewEditSettings.clipSettingsArray[index] =
                ((MediaImageItem)m).getImageClipProperties();
            if (((MediaImageItem)m).getScaledHeight() > maxHeight) {
                maxHeight = ((MediaImageItem)m).getScaledHeight();
            }
        }
        /** + Handle the image files here */
        if (mPreviewEditSettings.clipSettingsArray[index].fileType == FileType.JPG) {
            mPreviewEditSettings.clipSettingsArray[index].clipDecodedPath =
                ((MediaImageItem)m).getDecodedImageFileName();

            mPreviewEditSettings.clipSettingsArray[index].clipOriginalPath =
                         mPreviewEditSettings.clipSettingsArray[index].clipPath;
        }
        return maxHeight;
    }

    /**
     * Populates the background music track properties
     *
     * @param mediaBGMList The background music list
     *
     */
    private void populateBackgroundMusicProperties(List<AudioTrack> mediaBGMList) {

        if (mediaBGMList.size() == 1) {
            mAudioTrack = mediaBGMList.get(0);
        } else {
            mAudioTrack = null;
        }

        if (mAudioTrack != null) {
            mAudioSettings = new AudioSettings();
            Properties mAudioProperties = new Properties();
            mAudioSettings.pFile = null;
            mAudioSettings.Id = mAudioTrack.getId();
            try {
                mAudioProperties = getMediaProperties(mAudioTrack.getFilename());
            } catch (Exception e) {
               throw new IllegalArgumentException("Unsupported file or file not found");
            }
            mAudioSettings.bRemoveOriginal = false;
            mAudioSettings.channels = mAudioProperties.audioChannels;
            mAudioSettings.Fs = mAudioProperties.audioSamplingFrequency;
            mAudioSettings.loop = mAudioTrack.isLooping();
            mAudioSettings.ExtendedFs = 0;
            mAudioSettings.pFile = mAudioTrack.getFilename();
            mAudioSettings.startMs = mAudioTrack.getStartTime();
            mAudioSettings.beginCutTime = mAudioTrack.getBoundaryBeginTime();
            mAudioSettings.endCutTime = mAudioTrack.getBoundaryEndTime();
            if (mAudioTrack.isMuted()) {
                mAudioSettings.volume = 0;
            } else {
                mAudioSettings.volume = mAudioTrack.getVolume();
            }
            mAudioSettings.fileType = mAudioProperties.fileType;
            mAudioSettings.ducking_lowVolume = mAudioTrack.getDuckedTrackVolume();
            mAudioSettings.ducking_threshold = mAudioTrack.getDuckingThreshhold();
            mAudioSettings.bInDucking_enable = mAudioTrack.isDuckingEnabled();
            mAudioTrackPCMFilePath = String.format(mProjectPath + "/" + AUDIO_TRACK_PCM_FILE);
            mAudioSettings.pcmFilePath = mAudioTrackPCMFilePath;

            mPreviewEditSettings.backgroundMusicSettings = new BackgroundMusicSettings();
            mPreviewEditSettings.backgroundMusicSettings.file = mAudioTrackPCMFilePath;
            mPreviewEditSettings.backgroundMusicSettings.fileType = mAudioProperties.fileType;
            mPreviewEditSettings.backgroundMusicSettings.insertionTime =
                mAudioTrack.getStartTime();
            mPreviewEditSettings.backgroundMusicSettings.volumePercent = mAudioTrack.getVolume();
            mPreviewEditSettings.backgroundMusicSettings.beginLoop =
                mAudioTrack.getBoundaryBeginTime();
            mPreviewEditSettings.backgroundMusicSettings.endLoop =
                                               mAudioTrack.getBoundaryEndTime();
            mPreviewEditSettings.backgroundMusicSettings.enableDucking =
                mAudioTrack.isDuckingEnabled();
            mPreviewEditSettings.backgroundMusicSettings.duckingThreshold =
                mAudioTrack.getDuckingThreshhold();
            mPreviewEditSettings.backgroundMusicSettings.lowVolume =
                mAudioTrack.getDuckedTrackVolume();
            mPreviewEditSettings.backgroundMusicSettings.isLooping = mAudioTrack.isLooping();
            mPreviewEditSettings.primaryTrackVolume = 100;
            mProcessingState  = PROCESSING_AUDIO_PCM;
            mProcessingObject = mAudioTrack;
        } else {
            mAudioSettings = null;
            mPreviewEditSettings.backgroundMusicSettings = null;
            mAudioTrackPCMFilePath = null;
        }
    }

    /**
     * Calculates all the effects in all the media items
     * in media items list
     *
     * @param mediaItemsList The media item list
     *
     * @return The total number of effects
     *
     */
    private int getTotalEffects(List<MediaItem> mediaItemsList) {
        int totalEffects = 0;
        final Iterator<MediaItem> it = mediaItemsList.iterator();
        while (it.hasNext()) {
            final MediaItem t = it.next();
            totalEffects += t.getAllEffects().size();
            totalEffects += t.getAllOverlays().size();
            final Iterator<Effect> ef = t.getAllEffects().iterator();
            while (ef.hasNext()) {
                final Effect e = ef.next();
                if (e instanceof EffectKenBurns) {
                    totalEffects--;
                }
            }
        }
        return totalEffects;
    }

    /**
     * This function is responsible for forming clip settings
     * array and clip properties array including transition clips
     * and effect settings for preview purpose or export.
     *
     *
     * @param mediaItemsList The media item list
     * @param mediaTransitionList The transitions list
     * @param mediaBGMList The background music list
     * @param listener The MediaProcessingProgressListener
     *
     */
    void previewStoryBoard(List<MediaItem> mediaItemsList,
            List<Transition> mediaTransitionList, List<AudioTrack> mediaBGMList,
            MediaProcessingProgressListener listener) {
        if (mInvalidatePreviewArray) {
            int previewIndex = 0;
            int totalEffects = 0;
            int storyBoardTime = 0;
            int maxHeight = 0;
            int beginCutTime = 0;
            int endCutTime = 0;
            int effectIndex = 0;
            Transition lTransition = null;
            MediaItem lMediaItem = null;
            mPreviewEditSettings = new EditSettings();
            mClipProperties = new PreviewClipProperties();
            mTotalClips = 0;

            mTotalClips = mediaItemsList.size();
            for (Transition transition : mediaTransitionList) {
                if (transition.getDuration() > 0) {
                    mTotalClips++;
                }
            }

            totalEffects = getTotalEffects(mediaItemsList);

            mPreviewEditSettings.clipSettingsArray = new ClipSettings[mTotalClips];
            mPreviewEditSettings.effectSettingsArray = new EffectSettings[totalEffects];
            mClipProperties.clipProperties = new Properties[mTotalClips];

            /** record the call back progress listener */
            mMediaProcessingProgressListener = listener;
            mProgressToApp = 0;

            if (mediaItemsList.size() > 0) {
                for (int i = 0; i < mediaItemsList.size(); i++) {
                    /* Get the Media Item from the list */
                    lMediaItem = mediaItemsList.get(i);
                    if (lMediaItem instanceof MediaVideoItem) {
                        beginCutTime = (int)((MediaVideoItem)lMediaItem).getBoundaryBeginTime();
                        endCutTime = (int)((MediaVideoItem)lMediaItem).getBoundaryEndTime();
                    } else if (lMediaItem instanceof MediaImageItem) {
                        beginCutTime = 0;
                        endCutTime = (int)((MediaImageItem)lMediaItem).getTimelineDuration();
                    }
                    /* Get the transition associated with Media Item */
                    lTransition = lMediaItem.getBeginTransition();
                    if (lTransition != null && (lTransition.getDuration() > 0)) {
                        /* generate transition clip */
                        generateTransition(lTransition, mPreviewEditSettings,
                                           mClipProperties, previewIndex);
                        storyBoardTime += mClipProperties.clipProperties[previewIndex].duration;
                        previewIndex++;
                    }
                    /* Populate media item properties */
                    maxHeight = populateMediaItemProperties(lMediaItem, previewIndex, maxHeight);
                    /* Get the clip properties of the media item. */
                    if (lMediaItem instanceof MediaImageItem) {
                        int tmpCnt = 0;
                        boolean bEffectKbPresent = false;
                        final List<Effect> effectList = lMediaItem.getAllEffects();
                        /**
                         * Check if Ken Burns effect is present
                         */
                        while (tmpCnt < effectList.size()) {
                            if (effectList.get(tmpCnt) instanceof EffectKenBurns) {
                                bEffectKbPresent = true;
                                break;
                            }
                            tmpCnt++;
                        }

                        if (bEffectKbPresent) {
                            try {
                                  if(((MediaImageItem)lMediaItem).getGeneratedImageClip() != null) {
                                     mClipProperties.clipProperties[previewIndex]
                                        = getMediaProperties(((MediaImageItem)lMediaItem).
                                                             getGeneratedImageClip());
                                  }
                                  else {
                                   mClipProperties.clipProperties[previewIndex]
                                      = getMediaProperties(((MediaImageItem)lMediaItem).
                                                             getScaledImageFileName());
                                   mClipProperties.clipProperties[previewIndex].width =
                                             ((MediaImageItem)lMediaItem).getScaledWidth();
                                   mClipProperties.clipProperties[previewIndex].height =
                                             ((MediaImageItem)lMediaItem).getScaledHeight();
                                  }
                                } catch (Exception e) {
                                   throw new IllegalArgumentException("Unsupported file or file not found");
                                }
                         } else {
                              try {
                                  mClipProperties.clipProperties[previewIndex]
                                      = getMediaProperties(((MediaImageItem)lMediaItem).
                                                               getScaledImageFileName());
                              } catch (Exception e) {
                                throw new IllegalArgumentException("Unsupported file or file not found");
                              }
                            mClipProperties.clipProperties[previewIndex].width =
                                        ((MediaImageItem)lMediaItem).getScaledWidth();
                            mClipProperties.clipProperties[previewIndex].height =
                                        ((MediaImageItem)lMediaItem).getScaledHeight();
                        }
                    } else {
                        try {
                            mClipProperties.clipProperties[previewIndex]
                                 = getMediaProperties(lMediaItem.getFilename());
                            } catch (Exception e) {
                              throw new IllegalArgumentException("Unsupported file or file not found");
                          }
                    }
                    mClipProperties.clipProperties[previewIndex].Id = lMediaItem.getId();
                    checkOddSizeImage(lMediaItem, mClipProperties, previewIndex);
                    adjustVolume(lMediaItem, mClipProperties, previewIndex);

                    /*
                     * Adjust media item start time and end time w.r.t to begin
                     * and end transitions associated with media item
                     */

                    adjustMediaItemBoundary(mPreviewEditSettings.clipSettingsArray[previewIndex],
                            mClipProperties.clipProperties[previewIndex], lMediaItem);

                    /*
                     * Get all the effects and overlays for that media item and
                     * adjust start time and duration of effects
                     */

                    effectIndex = populateEffects(lMediaItem,
                            mPreviewEditSettings.effectSettingsArray, effectIndex, beginCutTime,
                            endCutTime, storyBoardTime);
                    storyBoardTime += mClipProperties.clipProperties[previewIndex].duration;
                    previewIndex++;

                    /* Check if there is any end transition at last media item */

                    if (i == (mediaItemsList.size() - 1)) {
                        lTransition = lMediaItem.getEndTransition();
                        if (lTransition != null && (lTransition.getDuration() > 0)) {
                            generateTransition(lTransition, mPreviewEditSettings, mClipProperties,
                                    previewIndex);
                            break;
                        }
                    }
                }

                if (!mErrorFlagSet) {
                    mPreviewEditSettings.videoFrameSize = findVideoResolution(mVideoEditor
                            .getAspectRatio(), maxHeight);
                    populateBackgroundMusicProperties(mediaBGMList);

                    /** call to native populate settings */
                    try {
                        nativePopulateSettings(mPreviewEditSettings, mClipProperties, mAudioSettings);
                    } catch (IllegalArgumentException ex) {
                        Log.e(TAG, "Illegal argument exception in nativePopulateSettings");
                        throw ex;
                    } catch (IllegalStateException ex) {
                        Log.e(TAG, "Illegal state exception in nativePopulateSettings");
                        throw ex;
                    } catch (RuntimeException ex) {
                        Log.e(TAG, "Runtime exception in nativePopulateSettings");
                        throw ex;
                    }
                    mInvalidatePreviewArray = false;
                    mProcessingState  = PROCESSING_NONE;
                }
            }
            if (mErrorFlagSet) {
                mErrorFlagSet = false;
                throw new RuntimeException("preview generation cannot be completed");
            }
        }
    } /* END of previewStoryBoard */

    /**
     * This function is responsible for starting the preview
     *
     *
     * @param surface The surface on which preview has to be displayed
     * @param fromMs The time in ms from which preview has to be started
     * @param toMs The time in ms till preview has to be played
     * @param loop To loop the preview or not
     * @param callbackAfterFrameCount INdicated after how many frames
     * the callback is needed
     * @param listener The PreviewProgressListener
     */
    void doPreview(Surface surface, long fromMs, long toMs, boolean loop,
            int callbackAfterFrameCount, PreviewProgressListener listener) {
        mPreviewProgress = fromMs;
        mIsFirstProgress = true;
        mPreviewProgressListener = listener;

        if (!mInvalidatePreviewArray) {
            try {
                /** Modify the image files names to rgb image files. */
                for (int clipCnt = 0; clipCnt < mPreviewEditSettings.clipSettingsArray.length;
                    clipCnt++) {
                    if (mPreviewEditSettings.clipSettingsArray[clipCnt].fileType == FileType.JPG) {
                        mPreviewEditSettings.clipSettingsArray[clipCnt].clipPath =
                            mPreviewEditSettings.clipSettingsArray[clipCnt].clipDecodedPath;
                    }
                }
                nativePopulateSettings(mPreviewEditSettings, mClipProperties, mAudioSettings);
                nativeStartPreview(surface, fromMs, toMs, callbackAfterFrameCount, loop);
            } catch (IllegalArgumentException ex) {
                Log.e(TAG, "Illegal argument exception in nativeStartPreview");
                throw ex;
            } catch (IllegalStateException ex) {
                Log.e(TAG, "Illegal state exception in nativeStartPreview");
                throw ex;
            } catch (RuntimeException ex) {
                Log.e(TAG, "Runtime exception in nativeStartPreview");
                throw ex;
            }
        } else {
            throw new IllegalStateException("generatePreview is in progress");
        }
    }

    /**
     * This function is responsible for stopping the preview
     */
    long stopPreview() {
        return nativeStopPreview();
    }

    /**
     * This function is responsible for rendering a single frame
     * from the complete story board on the surface
     *
     * @param surface The surface on which frame has to be rendered
     * @param time The time in ms at which the frame has to be rendered
     * @param surfaceWidth The surface width
     * @param surfaceHeight The surface height
     * @param overlayData The overlay data
     *
     * @return The actual time from the story board at which the  frame was extracted
     * and rendered
     */
    long renderPreviewFrame(Surface surface, long time, int surfaceWidth,
            int surfaceHeight, VideoEditor.OverlayData overlayData) {
        if (mInvalidatePreviewArray) {
            if (Log.isLoggable(TAG, Log.DEBUG)) {
                Log.d(TAG, "Call generate preview first");
            }
            throw new IllegalStateException("Call generate preview first");
        }

        long timeMs = 0;
        try {
            for (int clipCnt = 0; clipCnt < mPreviewEditSettings.clipSettingsArray.length;
                  clipCnt++) {
                if (mPreviewEditSettings.clipSettingsArray[clipCnt].fileType == FileType.JPG) {
                    mPreviewEditSettings.clipSettingsArray[clipCnt].clipPath =
                        mPreviewEditSettings.clipSettingsArray[clipCnt].clipDecodedPath;
                }
            }

            // Reset the render preview frame params that shall be set by native.
            mRenderPreviewOverlayFile = null;
            mRenderPreviewRenderingMode = MediaRendering.RESIZING;

            nativePopulateSettings(mPreviewEditSettings, mClipProperties, mAudioSettings);

            timeMs = (long)nativeRenderPreviewFrame(surface, time, surfaceWidth, surfaceHeight);

            if (mRenderPreviewOverlayFile != null) {
                overlayData.set(BitmapFactory.decodeFile(mRenderPreviewOverlayFile),
                        mRenderPreviewRenderingMode);
            } else {
                overlayData.setClear();
            }
        } catch (IllegalArgumentException ex) {
            Log.e(TAG, "Illegal Argument exception in nativeRenderPreviewFrame");
            throw ex;
        } catch (IllegalStateException ex) {
            Log.e(TAG, "Illegal state exception in nativeRenderPreviewFrame");
            throw ex;
        } catch (RuntimeException ex) {
            Log.e(TAG, "Runtime exception in nativeRenderPreviewFrame");
            throw ex;
        }

        return timeMs;
    }

    private void previewFrameEditInfo(String filename, int renderingMode) {
        mRenderPreviewOverlayFile = filename;
        mRenderPreviewRenderingMode = renderingMode;
    }


    /**
     * This function is responsible for rendering a single frame
     * from a single media item on the surface
     *
     * @param surface The surface on which frame has to be rendered
     * @param filepath The file path for which the frame needs to be displayed
     * @param time The time in ms at which the frame has to be rendered
     * @param framewidth The frame width
     * @param framewidth The frame height
     *
     * @return The actual time from media item at which the  frame was extracted
     * and rendered
     */
    long renderMediaItemPreviewFrame(Surface surface, String filepath,
                                            long time, int framewidth, int frameheight) {
        long timeMs = 0;
        try {
            timeMs = (long)nativeRenderMediaItemPreviewFrame(surface, filepath, framewidth,
                    frameheight, 0, 0, time);
        } catch (IllegalArgumentException ex) {
            Log.e(TAG, "Illegal Argument exception in renderMediaItemPreviewFrame");
            throw ex;
        } catch (IllegalStateException ex) {
            Log.e(TAG, "Illegal state exception in renderMediaItemPreviewFrame");
            throw ex;
        } catch (RuntimeException ex) {
            Log.e(TAG, "Runtime exception in renderMediaItemPreviewFrame");
            throw ex;
        }

        return timeMs;
    }

    /**
     * This function sets the flag to invalidate the preview array
     * and for generating the preview again
     */
    void setGeneratePreview(boolean isRequired) {
        boolean semAcquiredDone = false;
        try {
            lock();
            semAcquiredDone = true;
            mInvalidatePreviewArray = isRequired;
        } catch (InterruptedException ex) {
            Log.e(TAG, "Runtime exception in renderMediaItemPreviewFrame");
        } finally {
            if (semAcquiredDone) {
                unlock();
            }
        }
    }

    /**
     * @return Returns the current status of preview invalidation
     * flag
     */
    boolean getGeneratePreview() {
        return mInvalidatePreviewArray;
    }

    /**
     * Calculates the aspect ratio from widht and height
     *
     * @param w The width of media item
     * @param h The height of media item
     *
     * @return The calculated aspect ratio
     */
    int getAspectRatio(int w, int h) {
        double apRatio = (double)(w) / (double)(h);
        BigDecimal bd = new BigDecimal(apRatio);
        bd = bd.setScale(3, BigDecimal.ROUND_HALF_UP);
        apRatio = bd.doubleValue();
        int var = MediaProperties.ASPECT_RATIO_16_9;
        if (apRatio >= 1.7) {
            var = MediaProperties.ASPECT_RATIO_16_9;
        } else if (apRatio >= 1.6) {
            var = MediaProperties.ASPECT_RATIO_5_3;
        } else if (apRatio >= 1.5) {
            var = MediaProperties.ASPECT_RATIO_3_2;
        } else if (apRatio > 1.3) {
            var = MediaProperties.ASPECT_RATIO_4_3;
        } else if (apRatio >= 1.2) {
            var = MediaProperties.ASPECT_RATIO_11_9;
        }
        return var;
    }

    /**
     * Maps the file type used in native layer
     * to file type used in JAVA layer
     *
     * @param fileType The file type in native layer
     *
     * @return The File type in JAVA layer
     */
    int getFileType(int fileType) {
        int retValue = -1;
        switch (fileType) {
            case FileType.UNSUPPORTED:
                retValue = MediaProperties.FILE_UNSUPPORTED;
                break;
            case FileType.THREE_GPP:
                retValue = MediaProperties.FILE_3GP;
                break;
            case FileType.MP4:
                retValue = MediaProperties.FILE_MP4;
                break;
            case FileType.JPG:
                retValue = MediaProperties.FILE_JPEG;
                break;
            case FileType.PNG:
                retValue = MediaProperties.FILE_PNG;
                break;
            case FileType.MP3:
                retValue = MediaProperties.FILE_MP3;
                break;
            case FileType.M4V:
                retValue = MediaProperties.FILE_M4V;
                break;
            case FileType.AMR:
                retValue = MediaProperties.FILE_AMR;
                break;

            default:
                retValue = -1;
        }
        return retValue;
    }

    /**
     * Maps the video codec type used in native layer
     * to video codec type used in JAVA layer
     *
     * @param codecType The video codec type in native layer
     *
     * @return The video codec type in JAVA layer
     */
    int getVideoCodecType(int codecType) {
        int retValue = -1;
        switch (codecType) {
            case VideoFormat.H263:
                retValue = MediaProperties.VCODEC_H263;
                break;
            case VideoFormat.H264:
                retValue = MediaProperties.VCODEC_H264;
                break;
            case VideoFormat.MPEG4:
                retValue = MediaProperties.VCODEC_MPEG4;
                break;
            case VideoFormat.UNSUPPORTED:

            default:
                retValue = -1;
        }
        return retValue;
    }

    /**
     * Maps the audio codec type used in native layer
     * to audio codec type used in JAVA layer
     *
     * @param audioType The audio codec type in native layer
     *
     * @return The audio codec type in JAVA layer
     */
    int getAudioCodecType(int codecType) {
        int retValue = -1;
        switch (codecType) {
            case AudioFormat.AMR_NB:
                retValue = MediaProperties.ACODEC_AMRNB;
                break;
            case AudioFormat.AAC:
                retValue = MediaProperties.ACODEC_AAC_LC;
                break;
            case AudioFormat.MP3:
                retValue = MediaProperties.ACODEC_MP3;
                break;

            default:
                retValue = -1;
        }
        return retValue;
    }

    /**
     * Returns the frame rate as integer
     *
     * @param fps The fps as enum
     *
     * @return The frame rate as integer
     */
    int getFrameRate(int fps) {
        int retValue = -1;
        switch (fps) {
            case VideoFrameRate.FR_5_FPS:
                retValue = 5;
                break;
            case VideoFrameRate.FR_7_5_FPS:
                retValue = 8;
                break;
            case VideoFrameRate.FR_10_FPS:
                retValue = 10;
                break;
            case VideoFrameRate.FR_12_5_FPS:
                retValue = 13;
                break;
            case VideoFrameRate.FR_15_FPS:
                retValue = 15;
                break;
            case VideoFrameRate.FR_20_FPS:
                retValue = 20;
                break;
            case VideoFrameRate.FR_25_FPS:
                retValue = 25;
                break;
            case VideoFrameRate.FR_30_FPS:
                retValue = 30;
                break;

            default:
                retValue = -1;
        }
        return retValue;
    }

    /**
     * Maps the file type used in JAVA layer
     * to file type used in native layer
     *
     * @param fileType The file type in JAVA layer
     *
     * @return The File type in native layer
     */
    int getMediaItemFileType(int fileType) {
        int retValue = -1;

        switch (fileType) {
            case MediaProperties.FILE_UNSUPPORTED:
                retValue = FileType.UNSUPPORTED;
                break;
            case MediaProperties.FILE_3GP:
                retValue = FileType.THREE_GPP;
                break;
            case MediaProperties.FILE_MP4:
                retValue = FileType.MP4;
                break;
            case MediaProperties.FILE_JPEG:
                retValue = FileType.JPG;
                break;
            case MediaProperties.FILE_PNG:
                retValue = FileType.PNG;
                break;
            case MediaProperties.FILE_M4V:
                retValue = FileType.M4V;
                break;

            default:
                retValue = -1;
        }
        return retValue;

    }

    /**
     * Maps the rendering mode used in native layer
     * to rendering mode used in JAVA layer
     *
     * @param renderingMode The rendering mode in JAVA layer
     *
     * @return The rendering mode in native layer
     */
    int getMediaItemRenderingMode(int renderingMode) {
        int retValue = -1;
        switch (renderingMode) {
            case MediaItem.RENDERING_MODE_BLACK_BORDER:
                retValue = MediaRendering.BLACK_BORDERS;
                break;
            case MediaItem.RENDERING_MODE_STRETCH:
                retValue = MediaRendering.RESIZING;
                break;
            case MediaItem.RENDERING_MODE_CROPPING:
                retValue = MediaRendering.CROPPING;
                break;

            default:
                retValue = -1;
        }
        return retValue;
    }

    /**
     * Maps the transition behavior used in JAVA layer
     * to transition behavior used in native layer
     *
     * @param transitionType The transition behavior in JAVA layer
     *
     * @return The transition behavior in native layer
     */
    int getVideoTransitionBehaviour(int transitionType) {
        int retValue = -1;
        switch (transitionType) {
            case Transition.BEHAVIOR_SPEED_UP:
                retValue = TransitionBehaviour.SPEED_UP;
                break;
            case Transition.BEHAVIOR_SPEED_DOWN:
                retValue = TransitionBehaviour.SPEED_DOWN;
                break;
            case Transition.BEHAVIOR_LINEAR:
                retValue = TransitionBehaviour.LINEAR;
                break;
            case Transition.BEHAVIOR_MIDDLE_SLOW:
                retValue = TransitionBehaviour.SLOW_MIDDLE;
                break;
            case Transition.BEHAVIOR_MIDDLE_FAST:
                retValue = TransitionBehaviour.FAST_MIDDLE;
                break;

            default:
                retValue = -1;
        }
        return retValue;
    }

    /**
     * Maps the transition slide direction used in JAVA layer
     * to transition slide direction used in native layer
     *
     * @param slideDirection The transition slide direction
     * in JAVA layer
     *
     * @return The transition slide direction in native layer
     */
    int getSlideSettingsDirection(int slideDirection) {
        int retValue = -1;
        switch (slideDirection) {
            case TransitionSliding.DIRECTION_RIGHT_OUT_LEFT_IN:
                retValue = SlideDirection.RIGHT_OUT_LEFT_IN;
                break;
            case TransitionSliding.DIRECTION_LEFT_OUT_RIGHT_IN:
                retValue = SlideDirection.LEFT_OUT_RIGTH_IN;
                break;
            case TransitionSliding.DIRECTION_TOP_OUT_BOTTOM_IN:
                retValue = SlideDirection.TOP_OUT_BOTTOM_IN;
                break;
            case TransitionSliding.DIRECTION_BOTTOM_OUT_TOP_IN:
                retValue = SlideDirection.BOTTOM_OUT_TOP_IN;
                break;

            default:
                retValue = -1;
        }
        return retValue;
    }

    /**
     * Maps the effect color type used in JAVA layer
     * to effect color type used in native layer
     *
     * @param effect The EffectColor reference
     *
     * @return The color effect value from native layer
     */
    private int getEffectColorType(EffectColor effect) {
        int retValue = -1;
        switch (effect.getType()) {
            case EffectColor.TYPE_COLOR:
                if (effect.getColor() == EffectColor.GREEN) {
                    retValue = VideoEffect.GREEN;
                } else if (effect.getColor() == EffectColor.PINK) {
                    retValue = VideoEffect.PINK;
                } else if (effect.getColor() == EffectColor.GRAY) {
                    retValue = VideoEffect.BLACK_AND_WHITE;
                } else {
                    retValue = VideoEffect.COLORRGB16;
                }
                break;
            case EffectColor.TYPE_GRADIENT:
                retValue = VideoEffect.GRADIENT;
                break;
            case EffectColor.TYPE_SEPIA:
                retValue = VideoEffect.SEPIA;
                break;
            case EffectColor.TYPE_NEGATIVE:
                retValue = VideoEffect.NEGATIVE;
                break;
            case EffectColor.TYPE_FIFTIES:
                retValue = VideoEffect.FIFTIES;
                break;

            default:
                retValue = -1;
        }
        return retValue;
    }

    /**
     * Calculates video resolution for output clip
     * based on clip's height and aspect ratio of storyboard
     *
     * @param aspectRatio The aspect ratio of story board
     * @param height The height of clip
     *
     * @return The video resolution
     */
    private int findVideoResolution(int aspectRatio, int height) {
        final Pair<Integer, Integer>[] resolutions;
        final Pair<Integer, Integer> maxResolution;
        int retValue = VideoFrameSize.SIZE_UNDEFINED;
        switch (aspectRatio) {
            case MediaProperties.ASPECT_RATIO_3_2:
                if (height == MediaProperties.HEIGHT_480)
                    retValue = VideoFrameSize.NTSC;
                else if (height == MediaProperties.HEIGHT_720)
                    retValue = VideoFrameSize.W720p;
                break;
            case MediaProperties.ASPECT_RATIO_16_9:
                if (height == MediaProperties.HEIGHT_480)
                    retValue = VideoFrameSize.WVGA16x9;
                else if (height == MediaProperties.HEIGHT_720)
                    retValue = VideoFrameSize.V720p;
                else if (height == MediaProperties.HEIGHT_1080)
                    retValue = VideoFrameSize.V1080p;
                break;
            case MediaProperties.ASPECT_RATIO_4_3:
                if (height == MediaProperties.HEIGHT_480)
                    retValue = VideoFrameSize.VGA;
                else if (height == MediaProperties.HEIGHT_720)
                    retValue = VideoFrameSize.S720p;
                break;
            case MediaProperties.ASPECT_RATIO_5_3:
                if (height == MediaProperties.HEIGHT_480)
                    retValue = VideoFrameSize.WVGA;
                break;
            case MediaProperties.ASPECT_RATIO_11_9:
                if (height == MediaProperties.HEIGHT_144)
                    retValue = VideoFrameSize.QCIF;
                else if (height == MediaProperties.HEIGHT_288)
                    retValue = VideoFrameSize.CIF;
                break;
        }
        if (retValue == VideoFrameSize.SIZE_UNDEFINED) {
            resolutions = MediaProperties.getSupportedResolutions(mVideoEditor.getAspectRatio());
            // Get the highest resolution
            maxResolution = resolutions[resolutions.length - 1];
            retValue = findVideoResolution(mVideoEditor.getAspectRatio(), maxResolution.second);
        }

        return retValue;
    }

    /**
     *  Calculate a reasonable bitrate for generating intermediate clips.
     */
    private int findVideoBitrate(int videoFrameSize) {
        switch (videoFrameSize) {
            case VideoFrameSize.SQCIF:
            case VideoFrameSize.QQVGA:
            case VideoFrameSize.QCIF:
                return Bitrate.BR_128_KBPS;
            case VideoFrameSize.QVGA:
            case VideoFrameSize.CIF:
                return Bitrate.BR_384_KBPS;
            case VideoFrameSize.VGA:
            case VideoFrameSize.WVGA:
            case VideoFrameSize.NTSC:
            case VideoFrameSize.nHD:
            case VideoFrameSize.WVGA16x9:
                return Bitrate.BR_2_MBPS;
            case VideoFrameSize.V720p:
            case VideoFrameSize.W720p:
            case VideoFrameSize.S720p:
                return Bitrate.BR_5_MBPS;
            case VideoFrameSize.V1080p:
            default:
                return Bitrate.BR_8_MBPS;
        }
    }

    /**
     * This method is responsible for exporting a movie
     *
     * @param filePath The output file path
     * @param projectDir The output project directory
     * @param height The height of clip
     * @param bitrate The bitrate at which the movie should be exported
     * @param mediaItemsList The media items list
     * @param mediaTransitionList The transitions list
     * @param mediaBGMList The background track list
     * @param listener The ExportProgressListener
     *
     */
    void export(String filePath, String projectDir, int height, int bitrate,
            List<MediaItem> mediaItemsList, List<Transition> mediaTransitionList,
            List<AudioTrack> mediaBGMList, ExportProgressListener listener) {

        int outBitrate = 0;
        mExportFilename = filePath;
        previewStoryBoard(mediaItemsList, mediaTransitionList, mediaBGMList,null);
        mExportProgressListener = listener;
        int outVideoProfile = 0;
        int outVideoLevel = 0;

        /** Check the platform specific maximum export resolution */
        VideoEditorProfile veProfile = VideoEditorProfile.get();
        if (veProfile == null) {
            throw new RuntimeException("Can't get the video editor profile");
        }
        final int maxOutputHeight = veProfile.maxOutputVideoFrameHeight;
        final int maxOutputWidth = veProfile.maxOutputVideoFrameWidth;
        if (height > maxOutputHeight) {
            throw new IllegalArgumentException(
                    "Unsupported export resolution. Supported maximum width:" +
                    maxOutputWidth + " height:" + maxOutputHeight +
                    " current height:" + height);
        }
        outVideoProfile = VideoEditorProfile.getExportProfile(mExportVideoCodec);
        outVideoLevel = VideoEditorProfile.getExportLevel(mExportVideoCodec);

        mProgressToApp = 0;

        switch (bitrate) {
            case MediaProperties.BITRATE_28K:
                outBitrate = Bitrate.BR_32_KBPS;
                break;
            case MediaProperties.BITRATE_40K:
                outBitrate = Bitrate.BR_48_KBPS;
                break;
            case MediaProperties.BITRATE_64K:
                outBitrate = Bitrate.BR_64_KBPS;
                break;
            case MediaProperties.BITRATE_96K:
                outBitrate = Bitrate.BR_96_KBPS;
                break;
            case MediaProperties.BITRATE_128K:
                outBitrate = Bitrate.BR_128_KBPS;
                break;
            case MediaProperties.BITRATE_192K:
                outBitrate = Bitrate.BR_192_KBPS;
                break;
            case MediaProperties.BITRATE_256K:
                outBitrate = Bitrate.BR_256_KBPS;
                break;
            case MediaProperties.BITRATE_384K:
                outBitrate = Bitrate.BR_384_KBPS;
                break;
            case MediaProperties.BITRATE_512K:
                outBitrate = Bitrate.BR_512_KBPS;
                break;
            case MediaProperties.BITRATE_800K:
                outBitrate = Bitrate.BR_800_KBPS;
                break;
            case MediaProperties.BITRATE_2M:
                outBitrate = Bitrate.BR_2_MBPS;
                break;
            case MediaProperties.BITRATE_5M:
                outBitrate = Bitrate.BR_5_MBPS;
                break;
            case MediaProperties.BITRATE_8M:
                outBitrate = Bitrate.BR_8_MBPS;
                break;

            default:
                throw new IllegalArgumentException("Argument Bitrate incorrect");
        }
        mPreviewEditSettings.videoFrameRate = VideoFrameRate.FR_30_FPS;
        mPreviewEditSettings.outputFile = mOutputFilename = filePath;

        int aspectRatio = mVideoEditor.getAspectRatio();
        mPreviewEditSettings.videoFrameSize = findVideoResolution(aspectRatio, height);
        mPreviewEditSettings.videoFormat = mExportVideoCodec;
        mPreviewEditSettings.audioFormat = mExportAudioCodec;
        mPreviewEditSettings.videoProfile = outVideoProfile;
        mPreviewEditSettings.videoLevel = outVideoLevel;
        mPreviewEditSettings.audioSamplingFreq = AudioSamplingFrequency.FREQ_32000;
        mPreviewEditSettings.maxFileSize = 0;
        mPreviewEditSettings.audioChannels = 2;
        mPreviewEditSettings.videoBitrate = outBitrate;
        mPreviewEditSettings.audioBitrate = Bitrate.BR_96_KBPS;

        mPreviewEditSettings.transitionSettingsArray = new TransitionSettings[mTotalClips - 1];
        for (int index = 0; index < mTotalClips - 1; index++) {
            mPreviewEditSettings.transitionSettingsArray[index] = new TransitionSettings();
            mPreviewEditSettings.transitionSettingsArray[index].videoTransitionType =
                VideoTransition.NONE;
            mPreviewEditSettings.transitionSettingsArray[index].audioTransitionType =
                AudioTransition.NONE;
        }

        for (int clipCnt = 0; clipCnt < mPreviewEditSettings.clipSettingsArray.length; clipCnt++) {
            if (mPreviewEditSettings.clipSettingsArray[clipCnt].fileType == FileType.JPG) {
                mPreviewEditSettings.clipSettingsArray[clipCnt].clipPath =
                mPreviewEditSettings.clipSettingsArray[clipCnt].clipOriginalPath;
            }
        }
        nativePopulateSettings(mPreviewEditSettings, mClipProperties, mAudioSettings);

        int err = 0;
        try {
            mProcessingState  = PROCESSING_EXPORT;
            mProcessingObject = null;
            err = generateClip(mPreviewEditSettings);
            mProcessingState  = PROCESSING_NONE;
        } catch (IllegalArgumentException ex) {
            Log.e(TAG, "IllegalArgument for generateClip");
            throw ex;
        } catch (IllegalStateException ex) {
            Log.e(TAG, "IllegalStateExceptiont for generateClip");
            throw ex;
        } catch (RuntimeException ex) {
            Log.e(TAG, "RuntimeException for generateClip");
            throw ex;
        }

        if (err != 0) {
            Log.e(TAG, "RuntimeException for generateClip");
            throw new RuntimeException("generateClip failed with error=" + err);
        }

        mExportProgressListener = null;
    }

    /**
     * This methods takes care of stopping the Export process
     *
     * @param The input file name for which export has to be stopped
     */
    void stop(String filename) {
        try {
            stopEncoding();
            new File(mExportFilename).delete();
        } catch (IllegalStateException ex) {
            Log.e(TAG, "Illegal state exception in unload settings");
            throw ex;
        } catch (RuntimeException ex) {
            Log.e(TAG, "Runtime exception in unload settings");
            throw ex;
        }
    }

    /**
     * This method extracts a frame from the input file
     * and returns the frame as a bitmap. See getPixelsList() for more information.
     */
    Bitmap getPixels(String filename, int width, int height, long timeMs,
            int videoRotation) {
        final Bitmap result[] = new Bitmap[1];
        getPixelsList(filename, width, height, timeMs, timeMs, 1, new int[] {0},
                new MediaItem.GetThumbnailListCallback() {
            public void onThumbnail(Bitmap bitmap, int index) {
                result[0] = bitmap;
            }
        }, videoRotation);
        return result[0];
    }

    /**
     * This method extracts a list of frame from the
     * input file and returns the frame in bitmap array
     *
     * @param filename The input file name
     * @param width The width of the output frame, before rotation
     * @param height The height of the output frame, before rotation
     * @param startMs The starting time in ms
     * @param endMs The end time in ms
     * @param thumbnailCount The number of frames to be extracted
     * @param indices The indices of thumbnails wanted
     * @param callback The callback used to pass back the bitmaps
     * @param videoRotation The rotation degree need to be done for the bitmap
     *
     * @return The frames as bitmaps in bitmap array
     **/
    void getPixelsList(String filename, final int width, final int height,
            long startMs, long endMs, int thumbnailCount, int[] indices,
            final MediaItem.GetThumbnailListCallback callback,
            final int videoRotation) {

        // The decoder needs output width and height as even
        final int decWidth = (width + 1) & 0xFFFFFFFE;
        final int decHeight = (height + 1) & 0xFFFFFFFE;
        final int thumbnailSize = decWidth * decHeight;

        // We convert the decoder output (in int[]) to a bitmap by first
        // copy it into an IntBuffer, then use Bitmap.copyPixelsFromBuffer to
        // copy it to the bitmap.
        final int[] decArray = new int[thumbnailSize];
        final IntBuffer decBuffer = IntBuffer.allocate(thumbnailSize);

        // If we need to resize and/or rotate the decoder output, we need a
        // temporary bitmap to hold the decoded output.
        final boolean needToMassage =
                (decWidth != width || decHeight != height || videoRotation != 0);
        final Bitmap tmpBitmap = needToMassage
                ? Bitmap.createBitmap(decWidth, decHeight, Bitmap.Config.ARGB_8888)
                : null;

        // The final output bitmap width/height may swap because of rotation.
        final boolean needToSwapWH = (videoRotation == 90 || videoRotation == 270);
        final int outWidth = needToSwapWH ? height : width;
        final int outHeight = needToSwapWH ? width : height;

        nativeGetPixelsList(filename, decArray, decWidth, decHeight,
                thumbnailCount, startMs, endMs, indices,
                new NativeGetPixelsListCallback() {
            public void onThumbnail(int index) {
                // This is the bitmap we will output to the client
                Bitmap outBitmap = Bitmap.createBitmap(
                        outWidth, outHeight, Bitmap.Config.ARGB_8888);

                // Copy int[] to IntBuffer
                decBuffer.rewind();
                decBuffer.put(decArray, 0, thumbnailSize);
                decBuffer.rewind();

                if (!needToMassage) {
                    // We can directly read the decoded result to output bitmap
                    outBitmap.copyPixelsFromBuffer(decBuffer);
                } else {
                    // Copy the decoded result to an intermediate bitmap first
                    tmpBitmap.copyPixelsFromBuffer(decBuffer);

                    // Create a canvas to resize/rotate the bitmap
                    // First scale the decoded bitmap to (0,0)-(1,1), rotate it
                    // with (0.5, 0.5) as center, then scale it to
                    // (outWidth, outHeight).
                    final Canvas canvas = new Canvas(outBitmap);
                    Matrix m = new Matrix();
                    float sx = 1f / decWidth;
                    float sy = 1f / decHeight;
                    m.postScale(sx, sy);
                    m.postRotate(videoRotation, 0.5f, 0.5f);
                    m.postScale(outWidth, outHeight);
                    canvas.drawBitmap(tmpBitmap, m, sResizePaint);
                }
                callback.onThumbnail(outBitmap, index);
            }
        });

        if (tmpBitmap != null) {
            tmpBitmap.recycle();
        }
    }

    interface NativeGetPixelsListCallback {
        public void onThumbnail(int index);
    }

    /**
     * This method generates the audio graph
     *
     * @param uniqueId The unique id
     * @param inFileName The inputFile
     * @param OutAudiGraphFileName output filename
     * @param frameDuration The each frame duration
     * @param audioChannels The number of audio channels
     * @param samplesCount Total number of samples count
     * @param listener ExtractAudioWaveformProgressListener reference
     * @param isVideo The flag to indicate if the file is video file or not
     *
     **/
    void generateAudioGraph(String uniqueId, String inFileName, String OutAudiGraphFileName,
            int frameDuration, int audioChannels, int samplesCount,
            ExtractAudioWaveformProgressListener listener, boolean isVideo) {
        String tempPCMFileName;

        mExtractAudioWaveformProgressListener = listener;

        /**
         * In case of Video, first call will generate the PCM file to make the
         * audio graph
         */
        if (isVideo) {
            tempPCMFileName = String.format(mProjectPath + "/" + uniqueId + ".pcm");
        } else {
            tempPCMFileName = mAudioTrackPCMFilePath;
        }

        /**
         * For Video item, generate the PCM
         */
        if (isVideo) {
            nativeGenerateRawAudio(inFileName, tempPCMFileName);
        }

        nativeGenerateAudioGraph(tempPCMFileName, OutAudiGraphFileName, frameDuration,
                audioChannels, samplesCount);

        /**
         * Once the audio graph file is generated, delete the pcm file
         */
        if (isVideo) {
            new File(tempPCMFileName).delete();
        }
    }

    void clearPreviewSurface(Surface surface) {
        nativeClearSurface(surface);
    }

    /**
     * Grab the semaphore which arbitrates access to the editor
     *
     * @throws InterruptedException
     */
    private void lock() throws InterruptedException {
        if (Log.isLoggable(TAG, Log.DEBUG)) {
            Log.d(TAG, "lock: grabbing semaphore", new Throwable());
        }
        mLock.acquire();
        if (Log.isLoggable(TAG, Log.DEBUG)) {
            Log.d(TAG, "lock: grabbed semaphore");
        }
    }

    /**
     * Release the semaphore which arbitrates access to the editor
     */
    private void unlock() {
        if (Log.isLoggable(TAG, Log.DEBUG)) {
            Log.d(TAG, "unlock: releasing semaphore");
        }
        mLock.release();
    }

    /**     Native Methods        */
    native Properties getMediaProperties(String file) throws IllegalArgumentException,
            IllegalStateException, RuntimeException, Exception;

    /**
     * Get the version of ManualEdit.
     *
     * @return version of ManualEdit
     * @throws RuntimeException if an error occurred
     * @see Version
     */
    private static native Version getVersion() throws RuntimeException;

    /**
     * Returns the video thumbnail in an array of integers. Output format is
     * ARGB8888.
     *
     * @param pixelArray the array that receives the pixel values
     * @param width width of the video thumbnail
     * @param height height of the video thumbnail
     * @param timeMS desired time of the thumbnail in ms
     * @return actual time in ms of the thumbnail generated
     * @throws IllegalStateException if the class has not been initialized
     * @throws IllegalArgumentException if the pixelArray is not available or
     *             one of the dimensions is negative or zero or the time is
     *             negative
     * @throws RuntimeException on runtime errors in native code
     */
    private native int nativeGetPixels(String fileName, int[] pixelArray, int width, int height,
            long timeMS);

    private native int nativeGetPixelsList(String fileName, int[] pixelArray,
            int width, int height, int nosofTN, long startTimeMs,
            long endTimeMs, int[] indices, NativeGetPixelsListCallback callback);

    /**
     * Releases the JNI and cleans up the core native module.. Should be called
     * only after init( )
     *
     * @throws IllegalStateException if the method could not be called
     */
    private native void release() throws IllegalStateException, RuntimeException;

    /*
     * Clear the preview surface
     */
    private native void nativeClearSurface(Surface surface);

    /**
     * Stops the encoding. This method should only be called after encoding has
     * started using method <code> startEncoding</code>
     *
     * @throws IllegalStateException if the method could not be called
     */
    private native void stopEncoding() throws IllegalStateException, RuntimeException;


    private native void _init(String tempPath, String libraryPath)
            throws IllegalArgumentException, IllegalStateException, RuntimeException;

    private native void nativeStartPreview(Surface mSurface, long fromMs, long toMs,
            int callbackAfterFrameCount, boolean loop) throws IllegalArgumentException,
            IllegalStateException, RuntimeException;

    private native void nativePopulateSettings(EditSettings editSettings,
            PreviewClipProperties mProperties, AudioSettings mAudioSettings)
    throws IllegalArgumentException, IllegalStateException, RuntimeException;

    private native int nativeRenderPreviewFrame(Surface mSurface, long timeMs,
                                                 int surfaceWidth, int surfaceHeight)
                                                 throws IllegalArgumentException,
                                                 IllegalStateException, RuntimeException;

    private native int nativeRenderMediaItemPreviewFrame(Surface mSurface, String filepath,
            int framewidth, int frameheight, int surfacewidth, int surfaceheight, long timeMs)
    throws IllegalArgumentException, IllegalStateException, RuntimeException;

    private native int nativeStopPreview();

    private native int nativeGenerateAudioGraph(String pcmFilePath, String outGraphPath,
            int frameDuration, int channels, int sampleCount);

    private native int nativeGenerateRawAudio(String InFileName, String PCMFileName);

    private native int nativeGenerateClip(EditSettings editSettings)
    throws IllegalArgumentException, IllegalStateException, RuntimeException;

}
