[Xamarin] 透過 SurfaceView 取得相機影像

2015-08-26

今天筆記一下之前跌蠻多地方的SurfaceView ,主要目的是取道相機的影像,當然中間還要經過一些處理不過這篇Blog不會記錄那些處理的部份,介紹一下今天範例,主要就是一個SurfaceView   , APP 打開後會呈現相機中的畫面,不過我希望這SurfaceView是以 高:寬 – 4:3 呈現
1. 畫面介紹,只有一個 SurfaceView 基本上就是盡量簡單,打開APP後就會出現相機畫面
Image 093
AXML code:


<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent">
    <SurfaceView
        android:layout_height="500px"
        android:id="@+id/surfaceView1"
        android:layout_width="wrap_content"
        android:layout_centerInParent="true"
        android:layout_alignParentTop="true" />
</LinearLayout>

2.記得開CAMERA 權限


<?xml version="1.0" encoding="utf-8"?>

<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="TestSurface1.TestSurface1" android:versionCode="1" android:versionName="1.0"

android:installLocation="auto">

    <uses-sdk />
    <application android:label="TestSurface1" android:icon="@drawable/Icon"></application>
    <uses-permission android:name="android.permission.CAMERA" />
</manifest>OnPreviewFrame

3.接下來就是  C# Code 的部分 ,第一步該Activity 要繼承  ISurfaceHolderCallback, Camera.IPreviewCallback 這時候,SurfaceChanged 、SurfaceCreated、SurfaceDestroyed、OnPreviewFrame 必須要複寫,之後Code 會附上
首先在Activity onCreate 的部分


/// <summary>
 /// 主要的SurfaceView
 /// </summary>
 private SurfaceView mSurfaceView;
 
 /// <summary>
 /// SurfaceHolder 主要可以控制Surface的相關參數
 /// </summary>
 private ISurfaceHolder mHolder;
 
 /// <summary>
 /// Camera 主要可以控制相機的參數
 /// </summary>
 private Camera mCamera;
 
 protected override void OnCreate(Bundle bundle)
 {
     base.OnCreate(bundle);
 
     // Set our view from the "main" layout resource
     SetContentView(Resource.Layout.Main);
 
 
 
     mSurfaceView = FindViewById<SurfaceView>(Resource.Id.surfaceView1);
 
     Preview();
 
 }
 
 public void Preview()
 {
 
     mHolder = mSurfaceView.Holder;
     mHolder.AddCallback(this);
 }

接下來就是繼承後必須要實作的method


public void SurfaceChanged(ISurfaceHolder holder, Format format, int width, int height)
{
    //獲得相機參數
    var parameters = mCamera.GetParameters();
 
 
    var metrics = Resources.DisplayMetrics;
 
    //計算寬度
    var changeW = ((metrics.HeightPixels / 2) / 4) * 3;
 
    //設定surfaceView 寬度 跟高度
    var surfaceViewRelativeLayout = new LinearLayout.LayoutParams((int)changeW, metrics.HeightPixels / 2);
 
    surfaceViewRelativeLayout.SetMargins((metrics.WidthPixels - changeW) / 2, 0, 0, 0);
 
    mSurfaceView.LayoutParameters = (surfaceViewRelativeLayout);
 
    //取得Camera 所有Preview 支援的解析度
    var sizeList = mCamera.GetParameters().SupportedPreviewSizes;
 
    var fullw = 0;
    var fullh = 0;
 
    for (int i = 1; i < sizeList.Count; i++)
    {
        //方法很爛,但是我先這樣解吧
        //如果是4:3的比例,我就採用
        if ((Math.Round((decimal)sizeList[i].Width / sizeList[i].Height, 2)).ToString() == "1.33")
        {
 
            //判斷是不是最大的4:3的比例
            if (sizeList[i].Width > fullw)
            {
                fullw = sizeList[i].Width;
                fullh = sizeList[i].Height;
              
            }
 
        }
 
    }
    
 
    parameters.SetPreviewSize(fullw, fullh);
 
  
 
    mCamera.SetParameters(parameters);
 
    //此時才啟動Camera
    mCamera.StartPreview();
 
}
 
public void SurfaceCreated(ISurfaceHolder holder)
{
    mCamera = Camera.Open();
 
    try
    {
        if (mCamera != null)
        {
            var p = mCamera.GetParameters();
            p.PreviewFormat = (ImageFormatType.Nv21);
            
            p.ExposureCompensation = p.MaxExposureCompensation / 2;
     
            mCamera.SetDisplayOrientation(90);
            mCamera.SetPreviewDisplay(holder);
            mCamera.SetPreviewCallback(this);
 
        }
    }
    catch (Java.IO.IOException exception)
    {
        Log.Error("TAG", "IOException caused by SurfaceCreated()", exception);
    }
}
 
public void SurfaceDestroyed(ISurfaceHolder holder)
{
    // Surface will be destroyed when we return, so stop the preview.
    if (mCamera != null)
    {
        mCamera.StopPreview();
        mCamera.SetPreviewCallback(null);
        mCamera.Release();
        mCamera = null;
 
    }
}
 
public void OnPreviewFrame(byte[] data, Camera camera)
{
 
 
}

結果:
Screenshot_2015-08-26-12-35-11

Reference:
http://blog.csdn.net/xiaominghimi/article/details/6090575
http://developer.android.com/reference/android/view/SurfaceView.html
Source Code:


當麻許的超技八 2014 | Donma Hsu Design.