Java android捕获的视频质量差,缓冲视频时出错
我正在创建一个简单的应用程序,它可以预览一半屏幕上的摄像头视图并捕获视频,但我在缓冲视频和视频质量方面存在问题(保存到文件后,视频质量非常低)。按下“停止记录”按钮后,我的应用程序崩溃并显示以下错误:Java android捕获的视频质量差,缓冲视频时出错,java,android,Java,Android,我正在创建一个简单的应用程序,它可以预览一半屏幕上的摄像头视图并捕获视频,但我在缓冲视频和视频质量方面存在问题(保存到文件后,视频质量非常低)。按下“停止记录”按钮后,我的应用程序崩溃并显示以下错误: I/CameraDeviceState: Legacy camera service transitioning to state CAPTURING E/IMGSRV: :0: WSEGL_GetDrawableParameters: Failed to obtain minimal p
I/CameraDeviceState: Legacy camera service transitioning to state CAPTURING
E/IMGSRV: :0: WSEGL_GetDrawableParameters: Failed to obtain minimal parameters
E/IMGSRV: :0: KEGLGetDrawableParameters: Native window is invalid
E/libEGL: eglMakeCurrent:800 error 300b (EGL_BAD_NATIVE_WINDOW)
E/CameraDeviceGLThread-0: Received exception on GL render thread:
java.lang.IllegalStateException: makeCurrent: EGL error: 0x300b
at android.hardware.camera2.legacy.SurfaceTextureRenderer.checkEglError(SurfaceTextureRenderer.java:530)
at android.hardware.camera2.legacy.SurfaceTextureRenderer.makeCurrent(SurfaceTextureRenderer.java:518)
at android.hardware.camera2.legacy.SurfaceTextureRenderer.drawIntoSurfaces(SurfaceTextureRenderer.java:721)
at android.hardware.camera2.legacy.GLThreadManager$1.handleMessage(GLThreadManager.java:105)
at android.os.Handler.dispatchMessage(Handler.java:98)
at android.os.Looper.loop(Looper.java:148)
at android.os.HandlerThread.run(HandlerThread.java:61)
I/CameraDeviceState: Legacy camera service transitioning to state ERROR
E/RequestThread-0: Timed out while waiting for request to complete.
W/CaptureCollector: Preview buffers dropped for request: 1
E/CameraDeviceState: Cannot receive result while in state: 0
E/CameraDeviceState: Cannot receive result while in state: 0
E/CameraDeviceState: Cannot receive result while in state: 0
E/BufferQueueProducer: [SurfaceTexture-1-24067-2] cancelBuffer: BufferQueue has been abandoned
E/BufferQueueProducer: [SurfaceTexture-1-24067-2] cancelBuffer: BufferQueue has been abandoned
E/BufferQueueProducer: [SurfaceTexture-1-24067-2] cancelBuffer: BufferQueue has been abandoned
E/BufferQueueProducer: [SurfaceTexture-1-24067-2] cancelBuffer: BufferQueue has been abandoned
E/BufferQueueProducer: [SurfaceTexture-1-24067-2] cancelBuffer: BufferQueue has been abandoned
E/BufferQueueProducer: [SurfaceTexture-1-24067-2] cancelBuffer: BufferQueue has been abandoned
E/BufferQueueProducer: [SurfaceTexture-1-24067-2] cancelBuffer: BufferQueue has been abandoned
E/BufferQueueProducer: [SurfaceTexture-1-24067-2] cancelBuffer: BufferQueue has been abandoned
代码:
公共类SecondActivity扩展了AppCompatActivity{
私有静态最终int请求\摄像机\权限\结果=0;
私有静态最终整数请求\写入\外部\存储\权限\结果=0;
私有纹理视图mTextureView;
私有TextureView.SurfaceTextRelistener mSurfaceTextureListener=新的TextureView.SurfaceTextRelistener(){
@凌驾
SurfaceTextureAvailable上的公共空心(SurfaceTexture曲面、整型宽度、整型高度){
设置摄像机(宽度、高度);
连接摄像头();
}
@凌驾
SurfaceTextureSizeChanged上的公共空心(SurfaceTexture surface,int-width,int-height){
}
@凌驾
公共布尔onSurfaceTextureDestroyed(SurfaceTexture曲面){
如果(mMediaRecorder!=null){
mMediaRecorder.stop();
mMediaRecorder.release();
mMediaRecorder=null;
}
返回false;
}
@凌驾
已更新SurfaceTexture上的公共空间(SurfaceTexture surface){
}
};
私人摄像设备;
private CameraDevice.StateCallback mCameraDeviceStateCallback=新建CameraDevice.StateCallback(){
@凌驾
打开公共空间(摄像头副摄像头){
mCameraDevice=摄像机;
/*如果没有记录按钮*/
/*
试一试{
createVideoFileName();
}捕获(IOE异常){
e、 printStackTrace();
}
StartRecord();
mMediaRecorder.start();
*/
/*如果有记录按钮*/
如果(错误记录){
试一试{
createVideoFileName();
}捕获(IOE异常){
e、 printStackTrace();
}
StartRecord();
mMediaRecorder.start();
}否则{
startPreview();
}
}
@凌驾
已断开连接的公共空间(摄像头副摄像头){
摄像机关闭();
mCameraDevice=null;
}
@凌驾
公共无效onError(摄像头设备摄像头,int错误){
摄像机关闭();
mCameraDevice=null;
}
};
私有HandlerThread mBackgroundHandlerThread;
私人处理程序mBackgroundHandler;
私人字符串mCameraId;
私人规模的mPreviewSize;
私人规模;
专用媒体记录器;
私人国际旋转;
私有CaptureRequest.Builder mCaptureRequestBuilder;
私有图像按钮mRecordImageButton;
私有布尔错误记录=假;
私人文件夹;
私有字符串文件名;
专用静态SparseIntArray方向=新SparseIntArray();
静止的{
方向。附加(Surface.ROTATION_0,0);
方向。附加(Surface.ROTATION_90,90);
方向。附加(Surface.ROTATION_180,180);
方向。附加(Surface.ROTATION_270,270);
}
/**
*注意:这是自动生成的,用于实现应用程序索引API。
*看https://g.co/AppIndexing/AndroidStudio 了解更多信息。
*/
私人谷歌客户;
@凌驾
public void onStart(){
super.onStart();//注意:这是为实现应用程序索引API而自动生成的。
//看https://g.co/AppIndexing/AndroidStudio 了解更多信息。
client.connect();
//注意:这是自动生成的,用于实现应用程序索引API。
//看https://g.co/AppIndexing/AndroidStudio 了解更多信息。
AppIndex.AppIndexApi.start(客户端,getIndexApiAction());
}
@凌驾
公共void onStop(){
super.onStop();//注意:这是为实现应用程序索引API而自动生成的。
//看https://g.co/AppIndexing/AndroidStudio 了解更多信息。
AppIndex.AppIndexApi.end(客户端,getIndexApiAction());
//注意:这是自动生成的,用于实现应用程序索引API。
//看https://g.co/AppIndexing/AndroidStudio 了解更多信息。
client.disconnect();
}
/**
*注意:这是自动生成的,用于实现应用程序索引API。
*看https://g.co/AppIndexing/AndroidStudio 了解更多信息。
*/
公共行动getIndexApiAction(){
Thing对象=newthing.Builder()
.setName(“第二页”)//TODO:为显示的内容定义标题。
//TODO:确保此自动生成的URL正确无误。
.setUrl(Uri.parse(“http://[ENTER-YOUR-URL-HERE]”)
.build();
返回新的Action.Builder(Action.TYPE\u视图)
.setObject(对象)
.setActionStatus(操作.状态\类型\完成)
.build();
}
私有静态类CompareSizeByArea实现Comparator{
@凌驾
公共整数比较(大小lhs,大小rhs){
返回Long.signum((Long)lhs.getWidth()*lhs.getHeight()/
(长)rhs.getWidth()*rhs.getHeight());
}
}
@凌驾
创建时受保护的void(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_秒);
createVideoFolder();
mMediaRecorder=新的MediaRecorder();
mTextureView=(TextureView)findViewById(R.id.cameraView);
mRecordImageButton=(ImageButton)findViewById(R.id.videoOnlineImageButton);
mRecordImageButton.se
public class SecondActivity extends AppCompatActivity {
private static final int REQUEST_CAMERA_PERMISSION_RESULT = 0;
private static final int REQUEST_WRITE_EXTERNAL_STORAGE_PERMISSION_RESULT = 0;
private TextureView mTextureView;
private TextureView.SurfaceTextureListener mSurfaceTextureListener = new TextureView.SurfaceTextureListener() {
@Override
public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) {
setupCamera(width, height);
connectCamera();
}
@Override
public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) {
}
@Override
public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) {
if (mMediaRecorder != null) {
mMediaRecorder.stop();
mMediaRecorder.release();
mMediaRecorder = null;
}
return false;
}
@Override
public void onSurfaceTextureUpdated(SurfaceTexture surface) {
}
};
private CameraDevice mCameraDevice;
private CameraDevice.StateCallback mCameraDeviceStateCallback = new CameraDevice.StateCallback() {
@Override
public void onOpened(CameraDevice camera) {
mCameraDevice = camera;
/* if there is no record button */
/*
try {
createVideoFileName();
} catch (IOException e) {
e.printStackTrace();
}
StartRecord();
mMediaRecorder.start();
*/
/* if there is record button */
if (mIsRecording) {
try {
createVideoFileName();
} catch (IOException e) {
e.printStackTrace();
}
StartRecord();
mMediaRecorder.start();
} else {
startPreview();
}
}
@Override
public void onDisconnected(CameraDevice camera) {
camera.close();
mCameraDevice = null;
}
@Override
public void onError(CameraDevice camera, int error) {
camera.close();
mCameraDevice = null;
}
};
private HandlerThread mBackgroundHandlerThread;
private Handler mBackgroundHandler;
private String mCameraId;
private Size mPreviewSize;
private Size mVideoSize;
private MediaRecorder mMediaRecorder;
private int mTotalRotation;
private CaptureRequest.Builder mCaptureRequestBuilder;
private ImageButton mRecordImageButton;
private boolean mIsRecording = false;
private File mVideoFolder;
private String mVideoFileName;
private static SparseIntArray ORIENTATIONS = new SparseIntArray();
static {
ORIENTATIONS.append(Surface.ROTATION_0, 0);
ORIENTATIONS.append(Surface.ROTATION_90, 90);
ORIENTATIONS.append(Surface.ROTATION_180, 180);
ORIENTATIONS.append(Surface.ROTATION_270, 270);
}
/**
* ATTENTION: This was auto-generated to implement the App Indexing API.
* See https://g.co/AppIndexing/AndroidStudio for more information.
*/
private GoogleApiClient client;
@Override
public void onStart() {
super.onStart();// ATTENTION: This was auto-generated to implement the App Indexing API.
// See https://g.co/AppIndexing/AndroidStudio for more information.
client.connect();
// ATTENTION: This was auto-generated to implement the App Indexing API.
// See https://g.co/AppIndexing/AndroidStudio for more information.
AppIndex.AppIndexApi.start(client, getIndexApiAction());
}
@Override
public void onStop() {
super.onStop();// ATTENTION: This was auto-generated to implement the App Indexing API.
// See https://g.co/AppIndexing/AndroidStudio for more information.
AppIndex.AppIndexApi.end(client, getIndexApiAction());
// ATTENTION: This was auto-generated to implement the App Indexing API.
// See https://g.co/AppIndexing/AndroidStudio for more information.
client.disconnect();
}
/**
* ATTENTION: This was auto-generated to implement the App Indexing API.
* See https://g.co/AppIndexing/AndroidStudio for more information.
*/
public Action getIndexApiAction() {
Thing object = new Thing.Builder()
.setName("Second Page") // TODO: Define a title for the content shown.
// TODO: Make sure this auto-generated URL is correct.
.setUrl(Uri.parse("http://[ENTER-YOUR-URL-HERE]"))
.build();
return new Action.Builder(Action.TYPE_VIEW)
.setObject(object)
.setActionStatus(Action.STATUS_TYPE_COMPLETED)
.build();
}
private static class CompareSizeByArea implements Comparator<Size> {
@Override
public int compare(Size lhs, Size rhs) {
return Long.signum((long) lhs.getWidth() * lhs.getHeight() /
(long) rhs.getWidth() * rhs.getHeight());
}
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_second);
createVideoFolder();
mMediaRecorder = new MediaRecorder();
mTextureView = (TextureView) findViewById(R.id.cameraView);
mRecordImageButton = (ImageButton) findViewById(R.id.videoOnlineImageButton);
mRecordImageButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (mIsRecording) {
//createVideoFolder();
mIsRecording = false;
mMediaRecorder.stop();
mMediaRecorder.reset();
//startPreview();
} else {
//createVideoFolder();
mIsRecording = true;
checkWriteStoragePermission();
}
}
});
/* To stop recording */
/*
mMediaRecorder.stop();
mMediaRecorder.reset();
startPreview();
*/
// ATTENTION: This was auto-generated to implement the App Indexing API.
// See https://g.co/AppIndexing/AndroidStudio for more information.
client = new GoogleApiClient.Builder(this).addApi(AppIndex.API).build();
}
@Override
protected void onResume() {
super.onResume();
startBackgroundThread();
if (mTextureView.isAvailable()) {
setupCamera(mTextureView.getWidth(), mTextureView.getHeight());
connectCamera();
} else {
mTextureView.setSurfaceTextureListener(mSurfaceTextureListener);
}
}
@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
if (requestCode == REQUEST_CAMERA_PERMISSION_RESULT) {
if (grantResults[0] != PackageManager.PERMISSION_GRANTED) {
Toast.makeText(getApplicationContext(),
"Application will not run without camera services", Toast.LENGTH_SHORT).show();
}
}
if (requestCode == REQUEST_WRITE_EXTERNAL_STORAGE_PERMISSION_RESULT) {
if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
// Start recording
//
try {
createVideoFileName();
} catch (IOException e) {
e.printStackTrace();
}
// Starts
Toast.makeText(this,
"Permission successfully granted!", Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(this,
"App needs to save video to run", Toast.LENGTH_SHORT).show();
}
}
}
@Override
protected void onPause() {
closeCamera();
stopBackgroundThread();
super.onPause();
}
private void setupCamera(int width, int height) {
CameraManager cameraManager = (CameraManager) getSystemService(Context.CAMERA_SERVICE);
try {
for (String cameraId : cameraManager.getCameraIdList()) {
CameraCharacteristics cameraCharateristics = cameraManager.getCameraCharacteristics(cameraId);
if (cameraCharateristics.get(CameraCharacteristics.LENS_FACING) ==
CameraCharacteristics.LENS_FACING_FRONT) {
continue;
}
StreamConfigurationMap map = cameraCharateristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
int deviceOrientation = getWindowManager().getDefaultDisplay().getRotation();
mTotalRotation = sensorToDeviceRotation(cameraCharateristics, deviceOrientation);
boolean swapRotation = mTotalRotation == 90 || mTotalRotation == 270;
int rotatedWidth = width;
int rotatedHeight = height;
if (swapRotation) {
rotatedWidth = height;
rotatedHeight = width;
}
mPreviewSize = chooseOptimalSize(map.getOutputSizes(SurfaceTexture.class), rotatedWidth, rotatedHeight);
mVideoSize = chooseOptimalSize(map.getOutputSizes(MediaRecorder.class), rotatedWidth, rotatedHeight);
mCameraId = cameraId;
return;
}
} catch (CameraAccessException e) {
e.printStackTrace();
}
}
private void connectCamera() {
CameraManager cameraManager = (CameraManager) getSystemService(Context.CAMERA_SERVICE);
try {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
if (ContextCompat.checkSelfPermission(this, android.Manifest.permission.CAMERA) ==
PackageManager.PERMISSION_GRANTED) {
cameraManager.openCamera(mCameraId, mCameraDeviceStateCallback, mBackgroundHandler);
} else {
if (shouldShowRequestPermissionRationale(android.Manifest.permission.CAMERA)) {
Toast.makeText(this, "Video app required access to camera", Toast.LENGTH_SHORT).show();
}
requestPermissions(new String[]{android.Manifest.permission.CAMERA}, REQUEST_CAMERA_PERMISSION_RESULT);
}
} else {
cameraManager.openCamera(mCameraId, mCameraDeviceStateCallback, mBackgroundHandler);
}
} catch (CameraAccessException e) {
e.printStackTrace();
}
}
private void StartRecord() {
try {
setupMediaRecorder();
SurfaceTexture surfaceTexture = mTextureView.getSurfaceTexture();
surfaceTexture.setDefaultBufferSize(mPreviewSize.getWidth(), mPreviewSize.getHeight());
Surface previewSurface = new Surface(surfaceTexture);
Surface recordSurface = mMediaRecorder.getSurface();
mCaptureRequestBuilder = mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_RECORD);
mCaptureRequestBuilder.addTarget(previewSurface);
mCaptureRequestBuilder.addTarget(recordSurface);
mCameraDevice.createCaptureSession(Arrays.asList(previewSurface, recordSurface),
new CameraCaptureSession.StateCallback() {
@Override
public void onConfigured(CameraCaptureSession session) {
try {
session.setRepeatingRequest(
mCaptureRequestBuilder.build(), null, null
);
} catch (CameraAccessException e) {
e.printStackTrace();
}
}
@Override
public void onConfigureFailed(CameraCaptureSession session) {
}
}, null);
} catch (Exception e) {
e.printStackTrace();
}
}
private void startPreview() {
SurfaceTexture surfaceTexture = mTextureView.getSurfaceTexture();
surfaceTexture.setDefaultBufferSize(mPreviewSize.getWidth(), mPreviewSize.getHeight());
Surface previewSurface = new Surface(surfaceTexture);
try {
mCaptureRequestBuilder = mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
mCaptureRequestBuilder.addTarget(previewSurface);
mCameraDevice.createCaptureSession(Arrays.asList(previewSurface),
new CameraCaptureSession.StateCallback() {
@Override
public void onConfigured(CameraCaptureSession cameraCaptureSession) {
try {
cameraCaptureSession.setRepeatingRequest(mCaptureRequestBuilder.build(),
null, mBackgroundHandler);
} catch (CameraAccessException e) {
e.printStackTrace();
}
}
@Override
public void onConfigureFailed(CameraCaptureSession cameraCaptureSession) {
Toast.makeText(getApplicationContext(), "Unable to setup camera preview", Toast.LENGTH_SHORT).show();
}
}, null);
} catch (CameraAccessException e) {
e.printStackTrace();
}
}
private void closeCamera() {
if (mCameraDevice != null) {
mCameraDevice.close();
mCameraDevice = null;
}
}
private void startBackgroundThread() {
mBackgroundHandlerThread = new HandlerThread("Camera2VideoImage");
mBackgroundHandlerThread.start();
mBackgroundHandler = new Handler(mBackgroundHandlerThread.getLooper());
}
private void stopBackgroundThread() {
mBackgroundHandlerThread.quitSafely();
try {
mBackgroundHandlerThread.join();
mBackgroundHandlerThread = null;
mBackgroundHandler = null;
} catch (InterruptedException e) {
e.printStackTrace();
}
}
private static int sensorToDeviceRotation(CameraCharacteristics cameraCharacteristics, int deviceOrientation) {
int sensorOrientation = cameraCharacteristics.get(CameraCharacteristics.SENSOR_ORIENTATION);
deviceOrientation = ORIENTATIONS.get(deviceOrientation);
return (sensorOrientation + deviceOrientation + 360) % 360;
}
private static Size chooseOptimalSize(Size[] choices, int width, int height) {
List<Size> bigEnough = new ArrayList<Size>();
for (Size option : choices) {
if (option.getHeight() == option.getWidth() * height / width &&
option.getWidth() >= width && option.getHeight() >= height) {
bigEnough.add(option);
}
}
if (bigEnough.size() > 0) {
return Collections.min(bigEnough, new CompareSizeByArea());
} else {
return choices[0];
}
}
private void createVideoFolder() {
File movieFile = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_MOVIES);
mVideoFolder = new File(movieFile, "camera2VideoImage");
if (!mVideoFolder.exists()) {
mVideoFolder.mkdirs();
}
}
private File createVideoFileName() throws IOException {
// Vardas į failo pavadinimą
//String timestamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
String prepend = "VIDEO";
File videoFile = File.createTempFile(prepend, ".mp4", mVideoFolder);
mVideoFileName = videoFile.getAbsolutePath();
return videoFile;
}
private void checkWriteStoragePermission() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M)
if (ContextCompat.checkSelfPermission(this, android.Manifest.permission.WRITE_EXTERNAL_STORAGE)
== PackageManager.PERMISSION_GRANTED) {
try {
createVideoFileName();
} catch (IOException e) {
e.printStackTrace();
}
StartRecord();
mMediaRecorder.start();
} else {
if (shouldShowRequestPermissionRationale(android.Manifest.permission.WRITE_EXTERNAL_STORAGE)) {
Toast.makeText(this, "App needs to be able to save videos", Toast.LENGTH_SHORT).show();
}
requestPermissions(new String[]{android.Manifest.permission.WRITE_EXTERNAL_STORAGE}, REQUEST_WRITE_EXTERNAL_STORAGE_PERMISSION_RESULT);
}
else {
// Start recording
mIsRecording = true;
//
try {
createVideoFileName();
} catch (IOException e) {
e.printStackTrace();
}
StartRecord();
mMediaRecorder.start();
}
}
private void setupMediaRecorder() throws IOException {
mMediaRecorder.setVideoSource(MediaRecorder.VideoSource.SURFACE);
mMediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4);
mMediaRecorder.setOutputFile(mVideoFileName);
mMediaRecorder.setAudioEncodingBitRate(1000000);
mMediaRecorder.setVideoFrameRate(30);
mMediaRecorder.setVideoSize(mVideoSize.getWidth(), mVideoSize.getHeight());
mMediaRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.H264);
mMediaRecorder.setOrientationHint(mTotalRotation);
mMediaRecorder.prepare();
}
mIsRecording = false;
mMediaRecorder.stop();
mMediaRecorder.reset();
//startPreview();
mIsRecording = false;
startPreview();
mMediaRecorder.stop();
mMediaRecorder.reset();