關於Android使用MediaRecorder錄像清晰度問題

移动开发 码拜 6年前 (2015-07-18) 935次浏览

使用MediaRecorder類、Camera開發基於Android系統手機的錄像功能

獲得的視頻文件十分模糊,無法達到系統再帶的相機所錄製的效果

經過分析后,發現在錄像的時候沒有使用自動聚焦功能,從而導致視頻效果極差

但是添加了自動對焦的代碼后,SurfaceView中的預覽已經達到預期效果,但是問題是錄製的視頻卻是花屏

已經糾結了好幾天了,希望Android開發的大牛能給予幫助

下面是代碼片段


public class MainActivity extends Activity implements OnClickListener {

	private Button video_record, video_stop;
	private SurfaceView surfaceView;
	private SurfaceHolder surfaceHolder;
	private Camera camera;
	private MediaRecorder mediaRecorder;

	private boolean isCard, isFocus, isRecord;
	private String sdCard, recordPath, recordFormat = ".mp4";

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		getWindow().setFormat(PixelFormat.TRANSLUCENT);
		setContentView(R.layout.activity_main);
		init();
		setListener();
	}

	private void init() {
		video_record = (Button) findViewById(R.id.video_record);
		video_stop = (Button) findViewById(R.id.video_stop);
		surfaceView = (SurfaceView) findViewById(R.id.video_surface);
		surfaceHolder = surfaceView.getHolder();
		surfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
		surfaceHolder.addCallback(new CustomCallBack());
		video_stop.setEnabled(false);

		isCard = Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED);
		isFocus = false;
		isRecord = false;
		if (isCard) {
			sdCard = SDCardUtils.getExternalPath();
		}
	}

	private void setListener() {
		video_record.setOnClickListener(this);
		video_stop.setOnClickListener(this);
	}

	@Override
	public void onClick(View v) {
		if (!isCard) {
			toast("SDCard is Invalid");
			return;
		}
		switch (v.getId()) {
			case R.id.video_record:
				record();
				break;
			case R.id.video_stop:
				stop();
				break;
		}
	}

	private void record() {
		isRecord = true;
		try {
			initCamera();
			initRecord();
		} catch (IOException e) {
			e.printStackTrace();
		}
		referenceView();
	}

	private void stop() {
		isRecord = false;
		freeRecordResource();
		freeCameraResource();
		referenceView();
	}

	private void referenceView() {
		if (isRecord) {
			video_record.setEnabled(false);
			video_stop.setEnabled(true);
		} else {
			video_record.setEnabled(true);
			video_stop.setEnabled(false);
			recordPath = null;
		}
	}

	private void initCamera() throws IOException {
		if (camera != null) {
			freeCameraResource();
		}
		try {
			camera = Camera.open();
		} catch (Exception e) {
			e.printStackTrace();
		}
		setCameraParams();
		camera.setDisplayOrientation(90);
		camera.setPreviewDisplay(surfaceHolder);
		camera.startPreview();
		if (isFocus) {
			camera.autoFocus(null);
		}
		camera.unlock();
	}

	private void initRecord() throws IOException {
		if (mediaRecorder != null) {
			freeRecordResource();
		}
		File file = createFile();
		mediaRecorder = new MediaRecorder();
		mediaRecorder.setCamera(camera);
		mediaRecorder.setPreviewDisplay(surfaceHolder.getSurface());
		mediaRecorder.setVideoSource(VideoSource.CAMERA);
		mediaRecorder.setAudioSource(AudioSource.MIC);
		mediaRecorder.setOutputFormat(OutputFormat.MPEG_4);
		mediaRecorder.setAudioEncoder(AudioEncoder.AMR_NB);
//		mediaRecorder.setProfile(CamcorderProfile.get(CamcorderProfile.QUALITY_HIGH));
		mediaRecorder.setVideoFrameRate(16);
		mediaRecorder.setVideoEncodingBitRate(3000000);
//		mediaRecorder.setOrientationHint(90);
		mediaRecorder.setVideoEncoder(VideoEncoder.MPEG_4_SP);
//		mediaRecorder.setMaxDuration(Constant.MAXVEDIOTIME * 1000);
		mediaRecorder.setOutputFile(file.getAbsolutePath());
		mediaRecorder.prepare();
		mediaRecorder.start();
	}

	private File createFile() throws IOException {
		if (recordPath == null) {
			recordPath = sdCard + File.separator + System.currentTimeMillis() + recordFormat;
		}
		File file = new File(recordPath);
		if (!file.exists()) {
			File parent = file.getParentFile();
			if (!parent.exists()) {
				parent.mkdirs();
			}
			file.createNewFile();
		}
		return file;
	}

	private void freeCameraResource() {
		if (camera != null) {
			camera.setPreviewCallback(null);
			camera.stopPreview();
			camera.lock();
			camera.release();
			camera = null;
		}
	}

	private void freeRecordResource() {
		if (mediaRecorder != null) {
			mediaRecorder.stop();
			mediaRecorder.reset();
			mediaRecorder.release();
			mediaRecorder = null;
		}
	}

	public void setCameraParams() {
		if (camera != null) {
			Parameters params = camera.getParameters();
			List<String> list = params.getSupportedFocusModes();
			if (list.contains(Parameters.FOCUS_MODE_AUTO)) {
				isFocus = true;
				params.setFocusMode(Parameters.FOCUS_MODE_CONTINUOUS_VIDEO);
			}
			params.set("orientation", "portrait");
			camera.setParameters(params);
		}
	}

	@Override
	protected void onStop() {
		stop();
		super.onStop();
	}

	@Override
	protected void onDestroy() {
		stop();
		super.onDestroy();
	}

	private void toast(String text) {
		Log.e("custom", text);
		Toast.makeText(this, text, Toast.LENGTH_LONG).show();
	}

	public class CustomCallBack implements Callback {

		@Override
		public void surfaceCreated(SurfaceHolder holder) {
			if (camera == null) {
				try {
					camera = Camera.open();
					camera.setDisplayOrientation(90);
					camera.setPreviewDisplay(holder);
//					camera.startPreview();
				} catch (IOException e) {
					freeCameraResource();
					e.printStackTrace();
				}
			}
		}

		@Override
		public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
			if (camera != null) {
				setCameraParams();
				camera.startPreview();
				if (isFocus) {
					camera.autoFocus(null);
				}
				camera.unlock();
			}
		}

		@Override
		public void surfaceDestroyed(SurfaceHolder holder) {
			if (camera != null) {
				freeCameraResource();
			}
		}

	}

}

    <uses-permission android:name="android.permission.CAMERA" />
    <uses-permission android:name="android.permission.RECORD_AUDIO" />
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

    <uses-feature android:name="android.hardware.camera" />

因為功能還沒有完成,所以沒有註釋,肯請看到的大牛能幫幫忙

10分

#1

会不会你设置的profile不好呢?
加上你注释掉的mediaRecorder.setProfile(CamcorderProfile.get(CamcorderProfile.QUALITY_HIGH));也不行么?
你把mediaRecorder.setVideoFrameRate(16);改成30试试

#2

測試的時候和這兩處代碼沒有關係的

mediaRecorder.setProfile(CamcorderProfile.get(CamcorderProfile.QUALITY_HIGH));
mediaRecorder.setVideoFrameRate(16);

如果將自動對焦的方法去掉,是可以錄製出可以播放的視頻的,但是清晰度方面極差

而且網絡上的一些博客中的關於手機錄製視頻的操作也是這種效果

再加上了自動對焦操作后才錄製出花屏了的視頻

#3

回复1楼:

測試的時候和這兩處代碼沒有關係的

mediaRecorder.setProfile(CamcorderProfile.get(CamcorderProfile.QUALITY_HIGH));
mediaRecorder.setVideoFrameRate(16);

如果將自動對焦的方法去掉,是可以錄製出可以播放的視頻的,但是清晰度方面極差

而且網絡上的一些博客中的關於手機錄製視頻的操作也是這種效果

再加上了自動對焦操作后才錄製出花屏了的視頻

10分

#4

学习了。后面怎么处理清晰率和压缩率的?
10分

#5

自动对焦的代码?是这个吗?
if (list.contains(Parameters.FOCUS_MODE_AUTO)) {
isFocus = true;
params.setFocusMode(Parameters.FOCUS_MODE_CONTINUOUS_VIDEO);
}
有没有把这个list打出来看看?这个代码判断是当前对焦模式是否支持自动,但设置的值却是连续自动对焦啊

#6

回复5楼:

我已经放弃了  ……

10分

#7

你的花屏,是第二次点击录制按钮才出现的吗?还是一开始录制就出现了花屏的?

#8

你还是不能清晰录制吗?跟手机本身的摄像功能相比,你用的聚焦功能,也不能达到清晰的效果吗?

#9

回复8楼:

SurfaceView中的显示内容和手机自带的没有什么差距   但是录制出来的文件是花屏

现在我是使用手机自带的录像功能,获取录制时返回的Uri操作

#10

你花屏是因为你写的camera.startPreview();,把这句话换成camera.stopPreview();就OK了

#11

LZ解决了么?

#12

我也遇到了这个问题,视频的大小和调用本地相机一样,但是不能在录制过程中聚焦,清晰度较差。请问有人解决了这个问题吗?

#13

mediaRecorder.setPreviewDisplay(surfaceHolder.getSurface());
将上面的这一句放到mediaRecorder.setOutputFile(file.getAbsolutePath());后面试试;

#14

是否是聚焦的问题呢

#15

楼主现在有思路了吗,解决了跟大家分享一下啊!

#16

我自己解决了,给大家分享一下我得方法:其他的基本是一样的,只是更改了编码率,我现在也没太弄明白编码率到底是怎么回事!

#17

我这里设置的分辨率:
mMediaRecorder.setVideoSize(640, 480);
这个我把它去掉了,感觉没什么用
//mMediaRecorder.setVideoFrameRate(16);
在这里我提高了帧频率,然后就清晰了
mMediaRecorder.setVideoEncodingBitRate(5*1024*1024);

#18

回复17楼:

这样设置后竟然解决在三星手机上拍摄视频后的播放花屏问题!感谢

#19

回复17楼:

感谢

十分感谢 的确清晰了

#20

回复17楼:

也解决了我在平板上花屏、绿屏的问题,非常感谢谢!

#21

mMediaRecorder.setVideoEncodingBitRate(5*1024*1024);
给力啊!终于解决了!感谢啊~~~~~~!
不过我适当调小了点,要不生成的文件太大了

#22

这位大哥, 我今天也遇到这个问题了。用了你的方法解决了,感谢你啊!

#24

我用了也清晰很多了 谢谢了。

#25

回复17楼:

第二句代码虽然注释掉可以使用,但如果使用,设置的不对就会出现报错了


CodeBye 版权所有丨如未注明 , 均为原创丨本网站采用BY-NC-SA协议进行授权 , 转载请注明關於Android使用MediaRecorder錄像清晰度問題
喜欢 (0)
[1034331897@qq.com]
分享 (0)