[Xamarin] 透過 SurfaceView 取得相機影像
今天筆記一下之前跌蠻多地方的SurfaceView ,主要目的是取道相機的影像,當然中間還要經過一些處理不過這篇Blog不會記錄那些處理的部份,介紹一下今天範例,主要就是一個SurfaceView , APP 打開後會呈現相機中的畫面,不過我希望這SurfaceView是以 高:寬 – 4:3 呈現
1. 畫面介紹,只有一個 SurfaceView 基本上就是盡量簡單,打開APP後就會出現相機畫面
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)
{
}
結果:
Reference:
http://blog.csdn.net/xiaominghimi/article/details/6090575
http://developer.android.com/reference/android/view/SurfaceView.html
Source Code: