如何动态创建一个SurfaceView来预览android 相机拍照预览

在 SegmentFault,解决技术问题
每个月,我们帮助 1000 万的开发者解决各种各样的技术问题。并助力他们在技术能力、职业生涯、影响力上获得提升。
一线的工程师、著名开源项目的作者们,都在这里:
获取验证码
已有账号?
标签:至少1个,最多5个
网上已经有很多人提到过,导致这种现象的原因是,传入的相机预览图像长宽比例,与SurfaceView本身大小长宽比例不一致。
那么解决方法也非常简单,只要获取一下设备本身支持的相机比例,然后选择其中一个与SurfaceView实际比例(经常就是设备的长宽)最相近的即可。
下面的代码是创建一个用于相机预览的SurfaceView的过程:
//继承SurfaceView并且实现SurfaceHolder.Callback接口
public class CameraPreview extends SurfaceView implements SurfaceHolder.Callback
private static final String TAG = "CameraPreview";
private final SurfaceHolder mH
private Camera mC
public CameraPreview(Context context, Camera camera) {
super(context);
mHolder = getHolder();
mHolder.addCallback(this);
//下面一行适用于Android3.0之前的设备适配,一般可以省略
mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
public void surfaceCreated(SurfaceHolder holder) {
//制定相机图像的绘制区域为这个SurfaceView,并且启动相机的预览
mCamera.setPreviewDisplay(holder);
mCamera.startPreview();
} catch (IOException e) {
e.printStackTrace();
public void surfaceDestroyed(SurfaceHolder holder) {
//摧毁时释放相机的资源,如果留空的话则需要在activity里释放camera
mCamera.release();
public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
//当SurfaceView尺寸变化时(包括设备横屏竖屏改变时时),需要重新设定相关参数
if (mHolder.getSurface() == null) {
//检查SurfaceView是否存在
//改变设置前先关闭相机
mCamera.stopPreview();
} catch (Exception e) {
e.printStackTrace();
//使用最佳比例配置重启相机
mCamera.setPreviewDisplay(mHolder);
final Camera.Parameters parameters = mCamera.getParameters();
final Camera.Size size = getBestPreviewSize(w, h);
parameters.setPreviewSize(size.width, size.height);
mCamera.setParameters(parameters);
mCamera.startPreview();
} catch (Exception e) {
Log.d(TAG, "Error starting camera preview: " + e.getMessage());
private Camera.Size getBestPreviewSize(int width, int height) {
//在下面叙述
接下来是`getBestPreviewSize(int,int)的实现:
private Camera.Size getBestPreviewSize(int width, int height) {
Camera.Size result =
final Camera.Parameters p = mCamera.getParameters();
//特别注意此处需要规定rate的比是大的比小的,不然有可能出现rate = height/width,但是后面遍历的时候,current_rate = width/height,所以我们限定都为大的比小的。
float rate = (float) Math.max(width, height)/ (float)Math.min(width, height);
float tmp_
float min_diff = -1f;
for (Camera.Size size : p.getSupportedPreviewSizes()) {
float current_rate = (float) Math.max(size.width, size.height)/ (float)Math.min(size.width, size.height);
tmp_diff = Math.abs(current_rate-rate);
if( min_diff & 0){
min_diff = tmp_
if( tmp_diff & min_diff ){
min_diff = tmp_
0 收藏&&|&&1
你可能感兴趣的文章
2 收藏,1.1k
这种方式还是会存在问题的,我遇到过一台魅族的,相机差别特别大,导致拉伸验证,所以最好的方式还是等比例扩展预览图片,这样才能保证图片不拉伸
这种方式还是会存在问题的,我遇到过一台魅族的,相机差别特别大,导致拉伸验证,所以最好的方式还是等比例扩展预览图片,这样才能保证图片不拉伸
变更SurfaceView的大小
变更SurfaceView的大小
话说拉伸预览图片的话,还是通过setPreviewSize来实现吗?
话说拉伸预览图片的话,还是通过setPreviewSize来实现吗?
代码部分有笔误,还要修改:float current_rate = (float) Math.max(size.width, size.height)/ (float)Math.max(size.width, size.height);应该是:float current_rate = (float) Math.max(size.width, size.height)/ (float)Math.min(size.width, size.height);去掉 if( diff & 0){
min_diff = tmp_
float t应该为float tmp_diff还有,float min_diff是设定最小比率误差,应该大于0的小数,而不是这里的-1,我写的是0.1f作者太不注意了,不要误导
代码部分有笔误,还要修改:
float current_rate = (float) Math.max(size.width, size.height)/ (float)Math.max(size.width, size.height);
float current_rate = (float) Math.max(size.width, size.height)/ (float)Math.min(size.width, size.height);
去掉 if( diff & 0){
min_diff = tmp_
float t应该为float tmp_diff
还有,float min_diff是设定最小比率误差,应该大于0的小数,而不是这里的-1,我写的是0.1f
作者太不注意了,不要误导
非常感谢!当时代码放上来的时候,一些变量名想改一下名字,于是都是在网页编辑器里修改的,没有注意,导致了出错,非常感谢你的指出!
非常感谢!当时代码放上来的时候,一些变量名想改一下名字,于是都是在网页编辑器里修改的,没有注意,导致了出错,非常感谢你的指出!
min_diff写成-1是为了它可以被第一个比率替换掉,在比较第二个时,第一个比率默认是当前的min_diff
min_diff写成-1是为了它可以被第一个比率替换掉,在比较第二个时,第一个比率默认是当前的min_diff
你的 tmp_diff = Math.abs(),则tmp_diff&=0,而当if( tmp_diff & min_diff ),如果min_diff=-1,则if恒为false,根本就没机会替换
你的 tmp_diff = Math.abs(),则tmp_diff&=0,而当if( tmp_diff & min_diff ),如果min_diff=-1,则if恒为false,根本就没机会替换
还是你的办法管用最后计算出来之后
private void resizeSurfaceView(int width, int height) {
View view = findViewById(R.id.surfaceview);
RelativeLayout.LayoutParams layoutParams = (RelativeLayout.LayoutParams) view.getLayoutParams();
layoutParams.width =
layoutParams.height =
还是你的办法管用
最后计算出来之后
private void resizeSurfaceView(int width, int height) {
View view = findViewById(R.id.surfaceview);
RelativeLayout.LayoutParams layoutParams = (RelativeLayout.LayoutParams) view.getLayoutParams();
layoutParams.width =
layoutParams.height =
分享到微博?
我要该,理由是:君,已阅读到文档的结尾了呢~~
Android--相机预览及拍照临时文件-SurfaceView(可编辑),android 临时文件,surfaceview 拍照,android 拍照,android拍照上传,android 拍照权限,android拍照裁剪,android拍照代码,android 全景拍照,android拍照保存
扫扫二维码,随身浏览文档
手机或平板扫扫即可继续访问
Android--相机预览及拍照临时文件-SurfaceView(可编辑)
举报该文档为侵权文档。
举报该文档含有违规或不良信息。
反馈该文档无法正常浏览。
举报该文档为重复文档。
推荐理由:
将文档分享至:
分享完整地址
文档地址:
粘贴到BBS或博客
flash地址:
支持嵌入FLASH地址的网站使用
html代码:
&embed src='/DocinViewer-4.swf' width='100%' height='600' type=application/x-shockwave-flash ALLOWFULLSCREEN='true' ALLOWSCRIPTACCESS='always'&&/embed&
450px*300px480px*400px650px*490px
支持嵌入HTML代码的网站使用
您的内容已经提交成功
您所提交的内容需要审核后才能发布,请您等待!
3秒自动关闭窗口Android SurfaceView拍照录像实现方法
作者:Smile_muse
字体:[ ] 类型:转载 时间:
这篇文章主要为大家详细介绍了Android SurfaceView拍照录像实现代码,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
Surface的拍照实现也是很简单,一个小demo就可以把流程看懂了。
话不多说,直接上代码
&SurfaceView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/sv_main_surface"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:onClick="tackPhoto"
android:text="拍照"
public class MainActivity extends AppCompatActivity {
private SurfaceView sv_main_
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
sv_main_surface = (SurfaceView) findViewById(R.id.sv_main_surface);
//添加surface回调函数
sv_main_surface.getHolder().addCallback(new SurfaceHolder.Callback() {
@Override//控件创建时,打开照相机
public void surfaceCreated(SurfaceHolder holder) {
//打开照相机
camera = Camera.open();
//设置参数
Camera.Parameters parameters=camera.getParameters();
parameters.setPictureFormat(PixelFormat.JPEG);
parameters.set("jpeg-quality",85);
camera.setParameters(parameters);
//将画面展示到SurfaceView
camera.setPreviewDisplay(sv_main_surface.getHolder());
} catch (IOException e) {
e.printStackTrace();
//开启预览效果
camera.startPreview();
@Override//控件改变
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
@Override//控件销毁
public void surfaceDestroyed(SurfaceHolder holder) {
//照相同一时刻只能允许一个软件打开
if(camera!=null){
camera.stopPreview();
camera.release();//释放内存
public void takePhoto(View view){
camera.takePicture(null, null, new Camera.PictureCallback() {
public void onPictureTaken(byte[] bytes, Camera camera) {
//技术:图片压缩技术(如果图片不压缩,图片大小会过大,会报一个oom内存溢出的错误)
Bitmap bitmap= BitmapFactory.decodeByteArray(bytes,0,bytes.length);
FileOutputStream fos = new FileOutputStream("/mnt/sdcard/qq"+System.currentTimeMillis()+".png");//图片保存路径
pressFormat.PNG,85,fos);//压缩格式,质量,压缩路径
camera.stopPreview();
camera.startPreview();
} catch (FileNotFoundException e) {
e.printStackTrace();
我们还要添加权限
&!--打开照相机的权限--&
&uses-permission android:name="android.permission.CAMERA"&&/uses-permission&
&!--创建文件的权限--&
&uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"&&/uses-permission&
&!--写内存卡的权限--&
&uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"&&/uses-permission&
就这样一个小案例就完成了
既然可以拍照,那肯定也是可以录像的,所以我们再来看看录像是怎么实现的
&?xml version="1.0" encoding="utf-8"?&
&RelativeLayout xmlns:android="/apk/res/android"
xmlns:tools="/tools"
android:id="@+id/activity_media_recorder"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context="com.zking.familyapp.MediaRecorderActivity"&
&SurfaceView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/sv_media_surface"
&LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
&&/LinearLayout&
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="开始"
android:onClick="start"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="停止"
android:onClick="stop"
&/RelativeLayout&
public class MediaRecorderActivity extends AppCompatActivity {
private SurfaceView sv_media_
private MediaRecorder mediaR
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_media_recorder);
sv_media_surface = (SurfaceView) findViewById(R.id.sv_media_surface);
//实例化媒体录制器
mediaRecorder = new MediaRecorder();
public void start(View view){
mediaRecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA);
mediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
//设置格式
mediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4);
mediaRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.H263);
mediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
//设置保存路径
mediaRecorder.setOutputFile("/mnt/sdcard/uu"+System.currentTimeMillis()+".mp4");
mediaRecorder.setPreviewDisplay(sv_media_surface.getHolder().getSurface());
mediaRecorder.prepare();
mediaRecorder.start();
} catch (IOException e) {
e.printStackTrace();
public void stop(View view){
if(mediaRecorder!=null){
mediaRecorder.stop();
mediaRecorder.release();
mediaRecorder=
&!-- 录像的权限--&
&uses-permission android:name="android.permission.RECORD_AUDIO"&&/uses-permission&
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持脚本之家。
您可能感兴趣的文章:
大家感兴趣的内容
12345678910
最近更新的内容
常用在线小工具}

我要回帖

更多关于 相机链接电脑预览不了 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信