1. 程式人生 > >Android視訊編輯器(四)通過OpenGL給視訊增加不同濾鏡效果

Android視訊編輯器(四)通過OpenGL給視訊增加不同濾鏡效果

    private GPUImageFilter curFilter;
    private GPUImageFilter leftFilter;
    private GPUImageFilter rightFilter;

    public void init() {
        curFilter.init();
        leftFilter.init();
        rightFilter.init();
    }
    private void onFilterSizeChanged(int width, int height) {
        curFilter.onInputSizeChanged(width, height);
        leftFilter.onInputSizeChanged(width, height);
        rightFilter.onInputSizeChanged(width, height);
        curFilter.onDisplaySizeChanged(width, height);
        leftFilter.onDisplaySizeChanged(width, height);
        rightFilter.onDisplaySizeChanged(width, height);
    }
      然後定義繪製的畫面的寬高,由介面從外部進行設定
     private int width, height;
     public void onSizeChanged(int width, int height) {
        this.width = width;
        this.height = height;
        GLES20.glGenFramebuffers(1, fFrame, 0);
        EasyGlUtils.genTexturesWithParameter(1, fTexture, 0, GLES20.GL_RGBA, width, height);
        onFilterSizeChanged(width, height);
     }
      然後再定義一個幀緩衝區和一個紋理,用於繪製圖像
    private int[] fFrame = new int[1];
    private int[] fTexture = new int[1];
     並且初始化一個Scroller,來完成滑動事件的響應,Scroller的使用可以見這篇文章
   private Scroller scroller;
   scroller = new Scroller(MyApplication.getContext());
      初始化一個當前的filter的index,也就是標記位,標識當前是哪一個filter。
     private int curIndex = 0;
      然後,在建構函式裡面進行一些初始化
    public SlideGpufilterGroup() {
        initFilter();
        scroller = new Scroller(MyApplication.getContext());
    }
       initFilter方法其實就是當前三種filter的初始化   
    public void initFilter() {
        curFilter = getFilter(getCurIndex());
        leftFilter = getFilter(getLeftIndex());
        rightFilter = getFilter(getRightIndex());
    }
       getFilter其實就是根據filter的index進行filter物件的初始化
   public GPUImageFilter getFilter(int index) {
        GPUImageFilter filter = MagicFilterFactory.initFilters(types[index]);
        if (filter == null) {
            filter = new GPUImageFilter();
        }
        return filter;
    }
       而getCurIndex、getLeftIndex、getRightIndex這三個方法,就是分別獲取到當前filter的index和左邊、右邊的filter的index。
    private int getCurIndex() {
        return curIndex;
    }
    private int getLeftIndex() {
        int leftIndex = curIndex - 1;
        if (leftIndex < 0) {
            leftIndex = types.length - 1;
        }
        return leftIndex;
    }
    private int getRightIndex() {
        int rightIndex = curIndex + 1;
        if (rightIndex >= types.length) {
            rightIndex = 0;
        }
        return rightIndex;
    }
       當前的filter和左邊、右邊的filter我們都有了,現在還有兩個點,一個就是怎麼樣具體去繪製當前資料幀,另一個就是怎麼進行filter的切換。
       首先,我們來看看詳細的繪製規則,首先對外提供一個onDrawFrame方法       
    public void onDrawFrame(int textureId) {
        EasyGlUtils.bindFrameTexture(fFrame[0], fTexture[0]);
        if (direction == 0 && offset == 0) {
            curFilter.onDrawFrame(textureId);
        } else if (direction == 1) {
            onDrawSlideLeft(textureId);
        } else if (direction == -1) {
            onDrawSlideRight(textureId);
        }
        EasyGlUtils.unBindFrameBuffer();
    }
       該方法,接受一個紋理id,就是我們當前要繪製的紋理。然後將幀緩衝和紋理進行繫結,下面就是一個if else的判斷,這裡direction其實就是我們自己定義的,用來表示當前是什麼動作的一個int。
     int direction;//0為靜止,-1為向左滑,1為向右滑
       用這樣一個int,就可以區分當前的滑動是什麼樣的狀態,如果為0表示沒有滑動,那麼我們只用繪製curFilter就行了。而上面我們已經進行了curFilter的初始化,它也繼承自GPUImageFilter。我們只用呼叫onDrawFragme把當前的紋理id傳入進去就行了。
       而這個offset,其實就是我們記錄的當前的滑動量,如果offset其實=0的,那表示沒有偏移量,那肯定也只用繪製當前這個filter就行了。
       如果,當前的狀態是向右滑動,也就是direction = 1,我們就呼叫onDrawSlideLeft函式。
    private void onDrawSlideLeft(int textureId) {
        if (locked && scroller.computeScrollOffset()) {
            offset = scroller.getCurrX();
            drawSlideLeft(textureId);
        } else {
            drawSlideLeft(textureId);
            if (locked) {
                if (needSwitch) {
                    reCreateRightFilter();
                    if (mListener != null) {
                        mListener.onFilterChange(types[curIndex]);
                    }
                }
                offset = 0;
                direction = 0;
                locked = false;
            }
        }
    }
        我們先來看看scroller的computeScrollOffset方法 官方註釋是     
    /**
     * Call this when you want to know the new location.  If it returns true,
     * the animation is not yet finished.
     */ 
    public boolean computeScrollOffset() {
        其實就是如果還在滑動的話,就返回true。