Android 曲面视图预览是垂直拉伸的

Android 曲面视图预览是垂直拉伸的,android,android-layout,surfaceview,glsurfaceview,Android,Android Layout,Surfaceview,Glsurfaceview,我正在使用RTMP开发实时流媒体应用程序。我在最初的状态,我成功地做了很多事情,但现在却停留在一个地方。我使用的是Surface view,我的视频有点垂直拉伸。代码如下: 这是我的摄影师 public class SrsCameraView extends GLSurfaceView implements GLSurfaceView.Renderer { private GPUImageFilter magicFilter; private SurfaceTexture surfaceTex

我正在使用RTMP开发实时流媒体应用程序。我在最初的状态,我成功地做了很多事情,但现在却停留在一个地方。我使用的是Surface view,我的视频有点垂直拉伸。代码如下:

这是我的摄影师

public class SrsCameraView extends GLSurfaceView implements GLSurfaceView.Renderer {

private GPUImageFilter magicFilter;
private SurfaceTexture surfaceTexture;
private int mOESTextureId = OpenGLUtils.NO_TEXTURE;
private int mSurfaceWidth;
private int mSurfaceHeight;
private int mPreviewWidth;
private int mPreviewHeight;
private boolean mIsEncoding;
private boolean mIsTorchOn = false;
private float mInputAspectRatio;
private float mOutputAspectRatio;
private float[] mProjectionMatrix = new float[16];
private float[] mSurfaceMatrix = new float[16];
private float[] mTransformMatrix = new float[16];

private Camera mCamera;
private ByteBuffer mGLPreviewBuffer;
private final static int PIXEL_FORMAT = ImageFormat.NV21;
private int mCamId = -1;
private int mPreviewRotation = 90;
private int mPreviewOrientation = Configuration.ORIENTATION_PORTRAIT;

private Thread worker;
private final Object writeLock = new Object();
private ConcurrentLinkedQueue<IntBuffer> mGLIntBufferCache = new 
ConcurrentLinkedQueue<>();
private PreviewCallback mPrevCb;

public SrsCameraView(Context context) {
    this(context, null);
}

public SrsCameraView(Context context, AttributeSet attrs) {
    super(context, attrs);

    setEGLContextClientVersion(2);
    setRenderer(this);
    setRenderMode(GLSurfaceView.RENDERMODE_WHEN_DIRTY);
}

@Override
public void onSurfaceCreated(GL10 gl, EGLConfig config) {
    GLES20.glDisable(GL10.GL_DITHER);
    GLES20.glClearColor(0, 0, 0, 0);

    magicFilter = new GPUImageFilter(MagicFilterType.NONE);
    magicFilter.init(getContext().getApplicationContext());
    magicFilter.onInputSizeChanged(mPreviewWidth, mPreviewHeight);

    mOESTextureId = OpenGLUtils.getExternalOESTextureID();
    surfaceTexture = new SurfaceTexture(mOESTextureId);
    surfaceTexture.setOnFrameAvailableListener(new 
     SurfaceTexture.OnFrameAvailableListener() {
        @Override
        public void onFrameAvailable(SurfaceTexture surfaceTexture) {
            requestRender();
        }
    });

    // For camera preview on activity creation
    if (mCamera != null) {
        try {
            mCamera.setPreviewTexture(surfaceTexture);
        } catch (IOException ioe) {
            ioe.printStackTrace();
        }
    }
}

@Override
public void onSurfaceChanged(GL10 gl, int width, int height) {
    GLES20.glViewport(0, 0, width, height);
    mSurfaceWidth = width;
    mSurfaceHeight = height;
    magicFilter.onDisplaySizeChanged(width, height);

    mOutputAspectRatio = width > height ? (float) width / height : (float) 
      height / width;
    float aspectRatio = mOutputAspectRatio / mInputAspectRatio;
    if (width > height) {
        Matrix.orthoM(mProjectionMatrix, 0, -1.0f, 1.0f, -aspectRatio, 
      aspectRatio, -1.0f, 1.0f);
    } else {
        Matrix.orthoM(mProjectionMatrix, 0, -aspectRatio, aspectRatio, -1.0f, 1.0f, -1.0f, 1.0f);
    }
}

@Override
public void onDrawFrame(GL10 gl) {
    GLES20.glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
    GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT | GLES20.GL_DEPTH_BUFFER_BIT);

    surfaceTexture.updateTexImage();

    surfaceTexture.getTransformMatrix(mSurfaceMatrix);
    Matrix.multiplyMM(mTransformMatrix, 0, mSurfaceMatrix, 0, 
    mProjectionMatrix, 0);
    magicFilter.setTextureTransformMatrix(mTransformMatrix);
    magicFilter.onDrawFrame(mOESTextureId);

    if (mIsEncoding) {
        mGLIntBufferCache.add(magicFilter.getGLFboBuffer());
        synchronized (writeLock) {
            writeLock.notifyAll();
        }
    }
}

public void setPreviewCallback(PreviewCallback cb) {
    mPrevCb = cb;
}

public int[] setPreviewResolution(int width, int height) {
    getHolder().setFixedSize(width, height);

    mCamera = openCamera();
    mPreviewWidth = width;
    mPreviewHeight = height;
    Camera.Size rs = adaptPreviewResolution(mCamera.new Size(width, 
    height));
    if (rs != null) {
        mPreviewWidth = rs.width;
        mPreviewHeight = rs.height;
    }
    mCamera.getParameters().setPreviewSize(mPreviewWidth, mPreviewHeight);

    mGLPreviewBuffer = ByteBuffer.allocateDirect(mPreviewWidth * 
    mPreviewHeight * 4);
    mInputAspectRatio = mPreviewWidth > mPreviewHeight ?
        (float) mPreviewWidth / mPreviewHeight : (float) mPreviewHeight / 
     mPreviewWidth;

    return new int[] { mPreviewWidth, mPreviewHeight };
}

public boolean setFilter(final MagicFilterType type) {
    if (mCamera == null) {
        return false;
    }

    queueEvent(new Runnable() {
        @Override
        public void run() {
            if (magicFilter != null) {
                magicFilter.destroy();
            }
            magicFilter = MagicFilterFactory.initFilters(type);
            if (magicFilter != null) {
                magicFilter.init(getContext().getApplicationContext());
                magicFilter.onInputSizeChanged(mPreviewWidth, 
           mPreviewHeight);
                magicFilter.onDisplaySizeChanged(mSurfaceWidth, 
           mSurfaceHeight);
            }
        }
    });
    requestRender();
    return true;
}

private void deleteTextures() {
    if (mOESTextureId != OpenGLUtils.NO_TEXTURE) {
        queueEvent(new Runnable() {
            @Override
            public void run() {
                GLES20.glDeleteTextures(1, new int[]{ mOESTextureId }, 0);
                mOESTextureId = OpenGLUtils.NO_TEXTURE;
            }
        });
    }
}

public void setCameraId(int id) {
    mCamId = id;
    setPreviewOrientation(mPreviewOrientation);
}

public void setPreviewOrientation(int orientation) {
    mPreviewOrientation = orientation;
    Camera.CameraInfo info = new Camera.CameraInfo();
    Camera.getCameraInfo(mCamId, info);
    if (orientation == Configuration.ORIENTATION_PORTRAIT) {
        if (info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) {
            mPreviewRotation = info.orientation % 360;
            mPreviewRotation = (360 - mPreviewRotation) % 360;  // compensate the mirror
        } else {
            mPreviewRotation = (info.orientation + 360) % 360;
        }
    } else if (orientation == Configuration.ORIENTATION_LANDSCAPE) {
        if (info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) {
            mPreviewRotation = (info.orientation + 90) % 360;
            mPreviewRotation = (360 - mPreviewRotation) % 360;  // compensate the mirror
        } else {
            mPreviewRotation = (info.orientation + 270) % 360;
        }
    }
}

public int getCameraId() {
    return mCamId;
}

public void enableEncoding() {
    worker = new Thread(new Runnable() {
        @Override
        public void run() {
            while (!Thread.interrupted()) {
                while (!mGLIntBufferCache.isEmpty()) {
                    IntBuffer picture = mGLIntBufferCache.poll();
                    mGLPreviewBuffer.asIntBuffer().put(picture.array());
                    mPrevCb.onGetRgbaFrame(mGLPreviewBuffer.array(), 
                     mPreviewWidth, mPreviewHeight);
                }
                // Waiting for next frame
                synchronized (writeLock) {
                    try {
                        // isEmpty() may take some time, so we set timeout to detect next frame
                        writeLock.wait(500);
                    } catch (InterruptedException ie) {
                        worker.interrupt();
                    }
                }
            }
        }
    });
    worker.start();
    mIsEncoding = true;
}

public void disableEncoding() {
    mIsEncoding = false;
    mGLIntBufferCache.clear();

    if (worker != null) {
        worker.interrupt();
        try {
            worker.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
            worker.interrupt();
        }
        worker = null;
    }
}

public boolean startCamera() {
    if (mCamera == null) {
        mCamera = openCamera();
        if (mCamera == null) {
            return false;
        }
    }

    Camera.Parameters params = mCamera.getParameters();
    params.setPictureSize(mPreviewWidth, mPreviewHeight);
    params.setPreviewSize(mPreviewWidth, mPreviewHeight);
    int[] range = adaptFpsRange(SrsEncoder.VFPS, 
    params.getSupportedPreviewFpsRange());
    params.setPreviewFpsRange(range[0], range[1]);
    params.setPreviewFormat(ImageFormat.NV21);
    params.setFlashMode(Camera.Parameters.FLASH_MODE_OFF);
    params.setWhiteBalance(Camera.Parameters.WHITE_BALANCE_AUTO);
    params.setSceneMode(Camera.Parameters.SCENE_MODE_AUTO);

    List<String> supportedFocusModes = params.getSupportedFocusModes();
    if (supportedFocusModes != null && !supportedFocusModes.isEmpty()) {
        if 


 params.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE);
        } else if 
(supportedFocusModes.contains(Camera.Parameters.FOCUS_MODE_AUTO)) {
            params.setFocusMode(Camera.Parameters.FOCUS_MODE_AUTO);
            mCamera.autoFocus(null);
        } else {
            params.setFocusMode(supportedFocusModes.get(0));
        }
    }

    List<String> supportedFlashModes = params.getSupportedFlashModes();
    if (supportedFlashModes != null && !supportedFlashModes.isEmpty()) {
        if 
   (supportedFlashModes.contains(Camera.Parameters.FLASH_MODE_TORCH)) {
            if (mIsTorchOn) {
                params.setFlashMode(Camera.Parameters.FLASH_MODE_TORCH);
            }
        } else {
            params.setFlashMode(supportedFlashModes.get(0));
        }
    }

    mCamera.setParameters(params);

    mCamera.setDisplayOrientation(mPreviewRotation);

    try {
        mCamera.setPreviewTexture(surfaceTexture);
    } catch (IOException e) {
        e.printStackTrace();
    }
    mCamera.startPreview();

    return true;
}

public void stopCamera() {
    disableEncoding();

    if (mCamera != null) {
        mCamera.stopPreview();
        mCamera.release();
        mCamera = null;
    }
  }

  private Camera openCamera() {
    Camera camera;
    if (mCamId < 0) {
        Camera.CameraInfo info = new Camera.CameraInfo();
        int numCameras = Camera.getNumberOfCameras();
        int frontCamId = -1;
        int backCamId = -1;
        for (int i = 0; i < numCameras; i++) {
            Camera.getCameraInfo(i, info);
            if (info.facing == Camera.CameraInfo.CAMERA_FACING_BACK) {
                backCamId = i;
            } else if (info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) 
      {
                frontCamId = i;
                break;
            }
        }
        if (frontCamId != -1) {
            mCamId = frontCamId;
        } else if (backCamId != -1) {
            mCamId = backCamId;
        } else {
            mCamId = 0;
        }
    }
    camera = Camera.open(mCamId);
    return camera;
}

 private Camera.Size adaptPreviewResolution(Camera.Size resolution) {
    float diff = 100f;
    float xdy = (float) resolution.width / (float) resolution.height;
    Camera.Size best = null;
    for (Camera.Size size : 
   mCamera.getParameters().getSupportedPreviewSizes()) {
        if (size.equals(resolution)) {
            return size;
        }
        float tmp = Math.abs(((float) size.width / (float) size.height) - 
   xdy);
        if (tmp < diff) {
            diff = tmp;
            best = size;
        }
    }
    return best;
}

private int[] adaptFpsRange(int expectedFps, List<int[]> fpsRanges) {
    expectedFps *= 1000;
    int[] closestRange = fpsRanges.get(0);
    int measure = Math.abs(closestRange[0] - expectedFps) + 
Math.abs(closestRange[1] - expectedFps);
    for (int[] range : fpsRanges) {
        if (range[0] <= expectedFps && range[1] >= expectedFps) {
            int curMeasure = Math.abs(range[0] - expectedFps) + 
Math.abs(range[1] - expectedFps);
            if (curMeasure < measure) {
                closestRange = range;
                measure = curMeasure;
            }
        }
    }
    return closestRange;
}

public interface PreviewCallback {

    void onGetRgbaFrame(byte[] data, int width, int height);
}
}
公共类SrsCameraView扩展GLSurfaceView实现GLSurfaceView.Renderer{
专用GPUImageFilter magicFilter;
私有表面结构表面结构;
private int mOESTextureId=OpenGLUtils.NO_纹理;
私有int mSurfaceWidth;
私人室内地面高度;
私人内部审查宽度;
私人内部审查权;
私有布尔编码;
私有布尔值mIsTorchOn=false;
私人浮点数;
私人浮动移动频谱;
私有浮动[]mProjectionMatrix=新浮动[16];
私有浮点[]mSurfaceMatrix=新浮点[16];
私有浮动[]MTTransferormMatrix=新浮动[16];
私人摄像机麦卡梅拉;
私人专用缓冲垫mGLPreviewBuffer;
私有最终静态整数像素_格式=ImageFormat.NV21;
私有int mCamId=-1;
私人内部审查旋转=90;
private int mPreviewOrientation=Configuration.ORIENTATION\u纵向;
私人线程工作者;
私有最终对象writeLock=新对象();
私有ConcurrentLinkedQueue mGLIntBufferCache=新建
ConcurrentLinkedQueue();
私有预览回调mPrevCb;
公共SrsCameraView(上下文){
这个(上下文,空);
}
公共SrsCameraView(上下文、属性集属性){
超级(上下文,attrs);
setEGLContextClientVersion(2);
(本),;
setRenderMode(GLSurfaceView.RENDERMODE_脏时);
}
@凌驾
已创建曲面上的公共void(GL10 gl、EGLConfig配置){
GLES20.glDisable(GL10.GLU抖动);
GLES20.glClearColor(0,0,0,0);
magicFilter=新的GPUImageFilter(MagicFilterType.NONE);
init(getContext().getApplicationContext());
magicFilter.onInputSizeChanged(mPreviewWidth,MPReviewWheight);
mOESTextureId=OpenGLUtils.getExternalOESTextureID();
表面结构=新表面结构(Moestextured);
SurfacetTexture.setOnFrameAvailableListener(新)
SurfacetTexture.OnFrameAvailableListener(){
@凌驾
框架上的公共空间可用(SurfaceTexture SurfaceTexture){
requestRender();
}
});
//用于活动创建时的摄影机预览
if(mCamera!=null){
试一试{
mCamera.setPreviewTexture(表面纹理);
}捕获(ioe异常ioe){
ioe.printStackTrace();
}
}
}
@凌驾
表面上的公共空隙已更改(GL10 gl,整型宽度,整型高度){
GLES20.glViewport(0,0,宽度,高度);
mSurfaceWidth=宽度;
mSurfaceHeight=高度;
magicFilter.onDisplaySizeChanged(宽度、高度);
mOutputAspectRatio=宽度>高度?(浮动)宽度/高度:(浮动)
高度/宽度;
float aspectRatio=mOutputAspectRatio/mInputAspectRatio;
如果(宽度>高度){
矩阵正交(投影矩阵,0,-1.0f,1.0f,-aspectRatio,
aspectRatio,-1.0f,1.0f);
}否则{
矩阵正交(投影矩阵,0,-aspectRatio,aspectRatio,-1.0f,1.0f,-1.0f,1.0f);
}
}
@凌驾
公共框架(GL10 gl){
GLES20.glClearColor(0.0f,0.0f,0.0f,0.0f);
GLES20.glClear(GLES20.GL_颜色_缓冲_位| GLES20.GL_深度_缓冲_位);
surfacettexture.updateMaximage();
获取传递矩阵(mSurfaceMatrix);
矩阵.multipleymm(mTransformMatrix,0,mSurfaceMatrix,0,
mProjectionMatrix,0);
magicFilter.SetTextRetransformMatrix(MTTransformMatrix);
magicFilter.onDrawFrame(Moestextured);
if(mIsEncoding){
mGLIntBufferCache.add(magicFilter.getGLFboBuffer());
已同步(写回){
writeLock.notifyAll();
}
}
}
公共无效设置PreviewCallback(PreviewCallback cb){
mPrevCb=cb;
}
公共int[]设置预览解决方案(int-width,int-height){
getHolder().setFixedSize(宽度、高度);
mCamera=openCamera();
mPreviewWidth=宽度;
mPreviewHeight=高度;
Camera.Size rs=Adapter解决方案(mCamera.new尺寸(宽度,
身高),;
如果(rs!=null){
mPreviewWidth=rs.宽度;
mPreviewHeight=相对高度;
}
mCamera.getParameters().setPreviewSize(mPreviewWidth、mpReviewWheight);
mGLPreviewBuffer=ByteBuffer.allocateDirect(mPreviewWidth*
mPreviewHeight*4);
mInputAspectRatio=mPreviewWidth>mpReviewWheeght?
(浮动)mPreviewWidth/MPReviewWight:(浮动)MPReviewWight/
mPreviewWidth;
返回新的int[]{mPreviewWidth,mpreviewwheight};
}
公共布尔setFilter(最终MagicFilterType类型){
if(mCamera==null){
返回false;
}
queueEvent(新的可运行(){
@凌驾
公开募捐{
if(magicFilter!=null){
magicFilter.destroy();
}
magicFilter=MagicFilterFactory.initFilters(类型);
if(magicFilter!=null){
init(getContext().getApplicationContext());
magicFilter.onInputSizeChanged(mPreviewWidth,
mPreviewHeight);
magicFilter.onDisplaySizeChanged(m表面宽度,
m表面高度);
}
}
});
requestRender();
返回true;
}
私有void deleteTextures(){
if(mOESTextureId!=OpenGLUtils.无纹理){
queueEvent(新的可运行(){
@凌驾
公开募捐{
GLES20.glDeleteTextures(1,新int[]{moestextured},0);
mOESTextureId=OpenGLUtils.NO_纹理;
}
});
}
}
公共无效setCameraId(内部id){
mCamId=id;
setPreviewOrientation(mPreviewOrientation);
}
公共void setPreviewOrientation(int方向){
mPreviewOrientation=方向;
Camera.CameraInfo info=新建Camera.CameraInfo();
Camera.getCameraInfo(mCamId,info);
如果(方向==Configuration.O
      public class MainActivity extends AppCompatActivity implements RtmpHandler.RtmpListener,
                    SrsRecordHandler.SrsRecordListener, SrsEncodeHandler.SrsEncodeListener {

private static final String TAG = "Yasea";

Button btnPublish = null;
Button btnSwitchCamera = null;
Button btnRecord = null;
Button btnSwitchEncoder = null;

private SharedPreferences sp;
private String rtmpUrl = "rtmp://00.00.000.00/live/" + getRandomAlphaString(3) + '/' + getRandomAlphaDigitString(5);
private String recPath = Environment.getExternalStorageDirectory().getPath() + "/test.mp4";

private SrsPublisher mPublisher;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
    setContentView(R.layout.activity_main);

    // response screen rotation event
    setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_FULL_SENSOR);

    // restore data.
    sp = getSharedPreferences("Yasea", MODE_PRIVATE);
    rtmpUrl = sp.getString("rtmpUrl", rtmpUrl);

    // initialize url.
    final EditText efu = (EditText) findViewById(R.id.url);
    efu.setText(rtmpUrl);

    btnPublish = (Button) findViewById(R.id.publish);
    btnSwitchCamera = (Button) findViewById(R.id.swCam);
    btnRecord = (Button) findViewById(R.id.record);
    btnSwitchEncoder = (Button) findViewById(R.id.swEnc);

    mPublisher = new SrsPublisher((SrsCameraView) findViewById(R.id.glsurfaceview_camera));
    mPublisher.setEncodeHandler(new SrsEncodeHandler(this));
    mPublisher.setRtmpHandler(new RtmpHandler(this));
    mPublisher.setRecordHandler(new SrsRecordHandler(this));
   mPublisher.setPreviewResolution(640, 480);
    mPublisher.setOutputResolution(720, 1280);
    mPublisher.setVideoHDMode();
    mPublisher.startCamera();

    btnPublish.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            if (btnPublish.getText().toString().contentEquals("publish")) {
                rtmpUrl = efu.getText().toString();
                SharedPreferences.Editor editor = sp.edit();
                editor.putString("rtmpUrl", rtmpUrl);
                editor.apply();

                mPublisher.startPublish(rtmpUrl);
                mPublisher.startCamera();

                if (btnSwitchEncoder.getText().toString().contentEquals("soft encoder")) {
                    Toast.makeText(getApplicationContext(), "Use hard encoder", Toast.LENGTH_SHORT).show();
                } else {
                    Toast.makeText(getApplicationContext(), "Use soft encoder", Toast.LENGTH_SHORT).show();
                }
                btnPublish.setText("stop");
                btnSwitchEncoder.setEnabled(false);
            } else if (btnPublish.getText().toString().contentEquals("stop")) {
                mPublisher.stopPublish();
                mPublisher.stopRecord();
                btnPublish.setText("publish");
                btnRecord.setText("record");
                btnSwitchEncoder.setEnabled(true);
            }
        }
    });

    btnSwitchCamera.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            mPublisher.switchCameraFace((mPublisher.getCamraId() + 1) % Camera.getNumberOfCameras());
        }
    });

    btnRecord.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            if (btnRecord.getText().toString().contentEquals("record")) {
                if (mPublisher.startRecord(recPath)) {
                    btnRecord.setText("pause");
                }
            } else if (btnRecord.getText().toString().contentEquals("pause")) {
                mPublisher.pauseRecord();
                btnRecord.setText("resume");
            } else if (btnRecord.getText().toString().contentEquals("resume")) {
                mPublisher.resumeRecord();
                btnRecord.setText("pause");
            }
        }
    });

    btnSwitchEncoder.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            if (btnSwitchEncoder.getText().toString().contentEquals("soft encoder")) {
                mPublisher.switchToSoftEncoder();
                btnSwitchEncoder.setText("hard encoder");
            } else if (btnSwitchEncoder.getText().toString().contentEquals("hard encoder")) {
                mPublisher.switchToHardEncoder();
                btnSwitchEncoder.setText("soft encoder");
            }
        }
    });
}

@Override
public boolean onCreateOptionsMenu(Menu menu) {
    // Inflate the menu; this adds items to the action bar if it is present.
    getMenuInflater().inflate(R.menu.menu_main, menu);
    return true;
}

@Override
public boolean onOptionsItemSelected(MenuItem item) {
    // Handle action bar item clicks here. The action bar will
    // automatically handle clicks on the Home/Up button, so long
    // as you specify a parent activity in AndroidManifest.xml.
    int id = item.getItemId();

    //noinspection SimplifiableIfStatement
    if (id == R.id.action_settings) {
        return true;
    } else {
        switch (id) {
            case R.id.cool_filter:
                mPublisher.switchCameraFilter(MagicFilterType.COOL);
                break;
            case R.id.beauty_filter:
                mPublisher.switchCameraFilter(MagicFilterType.BEAUTY);
                break;
            case R.id.early_bird_filter:
                mPublisher.switchCameraFilter(MagicFilterType.EARLYBIRD);
                break;
            case R.id.evergreen_filter:
                mPublisher.switchCameraFilter(MagicFilterType.EVERGREEN);
                break;
            case R.id.n1977_filter:
                mPublisher.switchCameraFilter(MagicFilterType.N1977);
                break;
            case R.id.nostalgia_filter:
                mPublisher.switchCameraFilter(MagicFilterType.NOSTALGIA);
                break;
            case R.id.romance_filter:
                mPublisher.switchCameraFilter(MagicFilterType.ROMANCE);
                break;
            case R.id.sunrise_filter:
                mPublisher.switchCameraFilter(MagicFilterType.SUNRISE);
                break;
            case R.id.sunset_filter:
                mPublisher.switchCameraFilter(MagicFilterType.SUNSET);
                break;
            case R.id.tender_filter:
                mPublisher.switchCameraFilter(MagicFilterType.TENDER);
                break;
            case R.id.toast_filter:
                mPublisher.switchCameraFilter(MagicFilterType.TOASTER2);
                break;
            case R.id.valencia_filter:
                mPublisher.switchCameraFilter(MagicFilterType.VALENCIA);
                break;
            case R.id.walden_filter:
                mPublisher.switchCameraFilter(MagicFilterType.WALDEN);
                break;
            case R.id.warm_filter:
                mPublisher.switchCameraFilter(MagicFilterType.WARM);
                break;
            case R.id.original_filter:
            default:
                mPublisher.switchCameraFilter(MagicFilterType.NONE);
                break;
        }
    }
    setTitle(item.getTitle());

    return super.onOptionsItemSelected(item);
}

@Override
protected void onResume() {
    super.onResume();
    final Button btn = (Button) findViewById(R.id.publish);
    btn.setEnabled(true);
    mPublisher.resumeRecord();
}

@Override
protected void onPause() {
    super.onPause();
    mPublisher.pauseRecord();
}

@Override
protected void onDestroy() {
    super.onDestroy();
    mPublisher.stopPublish();
    mPublisher.stopRecord();
}

@Override
public void onConfigurationChanged(Configuration newConfig) {
    super.onConfigurationChanged(newConfig);
    mPublisher.stopEncode();
    mPublisher.stopRecord();
    btnRecord.setText("record");
    mPublisher.setScreenOrientation(newConfig.orientation);
    if (btnPublish.getText().toString().contentEquals("stop")) {
        mPublisher.startEncode();
    }
    mPublisher.startCamera();
}

private static String getRandomAlphaString(int length) {
    String base = "abcdefghijklmnopqrstuvwxyz";
    Random random = new Random();
    StringBuilder sb = new StringBuilder();
    for (int i = 0; i < length; i++) {
        int number = random.nextInt(base.length());
        sb.append(base.charAt(number));
    }
    return sb.toString();
}

private static String getRandomAlphaDigitString(int length) {
    String base = "abcdefghijklmnopqrstuvwxyz0123456789";
    Random random = new Random();
    StringBuilder sb = new StringBuilder();
    for (int i = 0; i < length; i++) {
        int number = random.nextInt(base.length());
        sb.append(base.charAt(number));
    }
    return sb.toString();
}

private void handleException(Exception e) {
    try {
        Toast.makeText(getApplicationContext(), e.getMessage(), Toast.LENGTH_SHORT).show();
        mPublisher.stopPublish();
        mPublisher.stopRecord();
        btnPublish.setText("publish");
        btnRecord.setText("record");
        btnSwitchEncoder.setEnabled(true);
    } catch (Exception e1) {
        //
    }
}

// Implementation of SrsRtmpListener.

@Override
public void onRtmpConnecting(String msg) {
    Toast.makeText(getApplicationContext(), msg, Toast.LENGTH_SHORT).show();
}

@Override
public void onRtmpConnected(String msg) {
    Toast.makeText(getApplicationContext(), msg, Toast.LENGTH_SHORT).show();
}

@Override
public void onRtmpVideoStreaming() {
}

@Override
public void onRtmpAudioStreaming() {
}

@Override
public void onRtmpStopped() {
    Toast.makeText(getApplicationContext(), "Stopped", Toast.LENGTH_SHORT).show();
}

@Override
public void onRtmpDisconnected() {
    Toast.makeText(getApplicationContext(), "Disconnected", Toast.LENGTH_SHORT).show();
}

@Override
public void onRtmpVideoFpsChanged(double fps) {
    Log.i(TAG, String.format("Output Fps: %f", fps));
}

@Override
public void onRtmpVideoBitrateChanged(double bitrate) {
    int rate = (int) bitrate;
    if (rate / 1000 > 0) {
        Log.i(TAG, String.format("Video bitrate: %f kbps", bitrate / 1000));
    } else {
        Log.i(TAG, String.format("Video bitrate: %d bps", rate));
    }
}

@Override
public void onRtmpAudioBitrateChanged(double bitrate) {
    int rate = (int) bitrate;
    if (rate / 1000 > 0) {
        Log.i(TAG, String.format("Audio bitrate: %f kbps", bitrate / 1000));
    } else {
        Log.i(TAG, String.format("Audio bitrate: %d bps", rate));
    }
}

@Override
public void onRtmpSocketException(SocketException e) {
    handleException(e);
}

@Override
public void onRtmpIOException(IOException e) {
    handleException(e);
}

@Override
public void onRtmpIllegalArgumentException(IllegalArgumentException e) {
    handleException(e);
}

@Override
public void onRtmpIllegalStateException(IllegalStateException e) {
    handleException(e);
}

// Implementation of SrsRecordHandler.

@Override
public void onRecordPause() {
    Toast.makeText(getApplicationContext(), "Record paused", Toast.LENGTH_SHORT).show();
}

@Override
public void onRecordResume() {
    Toast.makeText(getApplicationContext(), "Record resumed", Toast.LENGTH_SHORT).show();
}

@Override
public void onRecordStarted(String msg) {
    Toast.makeText(getApplicationContext(), "Recording file: " + msg, Toast.LENGTH_SHORT).show();
}

@Override
public void onRecordFinished(String msg) {
    Toast.makeText(getApplicationContext(), "MP4 file saved: " + msg, Toast.LENGTH_SHORT).show();
}

@Override
public void onRecordIOException(IOException e) {
    handleException(e);
}

@Override
public void onRecordIllegalArgumentException(IllegalArgumentException e) {
    handleException(e);
}

// Implementation of SrsEncodeHandler.

@Override
public void onNetworkWeak() {
    Toast.makeText(getApplicationContext(), "Network weak", Toast.LENGTH_SHORT).show();
}

@Override
public void onNetworkResume() {
    Toast.makeText(getApplicationContext(), "Network resume", Toast.LENGTH_SHORT).show();
}

@Override
public void onEncodeIllegalArgumentException(IllegalArgumentException e) {
    handleException(e);
}
}
mOutputAspectRatio = width > height ? (float) width / height : (float) 
  height / width;
mOutputAspectRatio = width > height ? ((float) width) / ((float)height) : ((float) 
  height) / ((float) width);