preface
In Android audio and video development, online knowledge is too fragmented, self-learning is very difficult, but audio and video cattle Jhuster put forward “Android audio and video from the entry to improve – task list”. This is the third installment of the Android Audio and Video task list, and the corresponding contents to learn are: In Android platform using Camera API for video collection, respectively using SurfaceView, TextureView to preview Camera data, get NV21 data callback (for example, the NV21 data will be displayed in ImageView control after processing).
Audio and video task list
Audio and video task list: Click here to jump to view
A, directories,
(I) Steps of Camera data collection
(1) Open the camera
mCamera = Camera.open();
Copy the code
(2) Set the preview data interface of the camera
Call setPreviewDisplay to set the SurfaceHolder, which is bound to the SurfaceView. The setPreviewTexture method is called to set SurfaceTexture, which is bound to TextureView
(3) Get camera. Parameters parameter information (if it is a simple preview, there is no need to set parameter information)
Camera.Parameters parameters = mCamera.getParameters(); // Get camera parameters
// You can set parameters as required
// Zoom the lens
parameters.setZoom();
// Set the size of the preview photo
parameters.setPreviewSize(200.200);
// Sets the minimum and maximum number of frames per second to display when previewing photos
parameters.setPreviewFpsRange(4.10);
// Set the image format
parameters.setPictureFormat(ImageFormat.JPEG);
Image quality [0-100],100 is the highest
parameters.set("jpeg-quality".85);
// Set the size of the photo
parameters.setPictureSize(200.200);
mCamera.setParameters(parameters);
Copy the code
(4) after setting the added parameters back, call startPreview to startPreview
mCamera.startPreview();
Copy the code
(5) Release the camera
mCamera.release();
Copy the code
Note that the Camera must be released after use, otherwise the Camera can not be called elsewhere.
(2) SurfaceView to preview Camera data
package com.lzacking.cameraapidemo;
import androidx.appcompat.app.AppCompatActivity;
import android.graphics.SurfaceTexture;
import android.hardware.Camera;
import android.os.Bundle;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.TextureView;
import java.io.IOException;
public class CameraSurfaceViewActivity extends AppCompatActivity implements SurfaceHolder.Callback {
private SurfaceView mSurfaceView;
private Camera mCamera;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_camera_surface_view);
mSurfaceView = findViewById(R.id.surfaceView);
mSurfaceView.getHolder().addCallback(this);
// Open the camera and turn the display direction 90 degrees
mCamera = Camera.open(0);
mCamera.setDisplayOrientation(90);
}
//------ SurfaceView preview -------
@Override
public void surfaceCreated(SurfaceHolder holder) {
// Initialize the control when it is created
try {
mCamera.setPreviewDisplay(holder);
// Start preview
mCamera.startPreview();
} catch(IOException e) { e.printStackTrace(); }}@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
// You can perform corresponding operations when changing
}
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
// Release the cameramCamera.release(); }}Copy the code
(3) TextureView to preview Camera data
package com.lzacking.cameraapidemo;
import androidx.appcompat.app.AppCompatActivity;
import android.graphics.SurfaceTexture;
import android.hardware.Camera;
import android.os.Bundle;
import android.view.TextureView;
import java.io.IOException;
public class CameraTextureViewActivity extends AppCompatActivity implements TextureView.SurfaceTextureListener {
private TextureView mTextureView;
private Camera mCamera;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_camera_texture_view);
mTextureView = findViewById(R.id.textureView);
mTextureView.setSurfaceTextureListener(this);
// Open the camera and turn the display direction 90 degrees
mCamera = Camera.open(0);
mCamera.setDisplayOrientation(90);
}
//------ TextureView preview -------
@Override
public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) {
// Initialize the control when it is created
try {
mCamera.setPreviewTexture(surface);
// Start preview
mCamera.startPreview();
} catch(IOException e) { e.printStackTrace(); }}@Override
public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) {
// You can perform corresponding operations when changing
}
@Override
public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) {
// Release the camera
mCamera.release();
return false;
}
@Override
public void onSurfaceTextureUpdated(SurfaceTexture surface) {}}Copy the code
(4) Get NV21 data callback
The YUV format of Camera Preview Callback supported by Google in Android is NV21 and YV12. Android generally uses the YCbCr_420_SP format (NV21) by default.
Camera.Parameters parameters = camera.getParameters();
parameters.setPreviewFormat(ImageFormat.NV21);
camera.setParameters(parameters);
// Listen for previewcallback via setPreviewCallback:
camera.setPreviewCallback(new Camera.PreviewCallback() {
@Override
public void onPreviewFrame(byte[] bytes, Camera camera) {
// The Bytes are in NV21 format}});Copy the code
Use ImageView to display NV21 data
mCamera.setPreviewCallback(new Camera.PreviewCallback() {
@Override
public void onPreviewFrame(byte[] data, Camera camera) {
// Process data, where the data is in NV21 format, and display the data on the ImageView control
mPreviewSize = camera.getParameters().getPreviewSize();// Get the size for the format conversion
/ / remove hair YUVIMAGE
YuvImage yuvimage = new YuvImage(
data,
ImageFormat.NV21,
mPreviewSize.width,
mPreviewSize.height,
null);
mBaos = new ByteArrayOutputStream();
// YuvImage is converted to JPG format
yuvimage.compressToJpeg(new Rect(0.0, mPreviewSize.width, mPreviewSize.height), 100, mBaos);// 80--JPG image quality [0-100],100 highest
mImageBytes = mBaos.toByteArray();
// Convert mImageBytes to bitmap
BitmapFactory.Options options = new BitmapFactory.Options();
options.inPreferredConfig = Bitmap.Config.RGB_565;
mBitmap = BitmapFactory.decodeByteArray(mImageBytes, 0, mImageBytes.length, options); mImageView.setImageBitmap(rotateBitmap(mBitmap, getDegree())); }});Copy the code
(v) Complete code
(1) Layout
Activity_main. XML:
<? xml version="1.0" encoding="utf-8"? > <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity"
android:orientation="vertical"
android:gravity="center">
<Button
android:id="@+id/btn_surfaceview"
android:text="SurfaceView preview camera data"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<Button
android:id="@+id/btn_textureview"
android:text="TextureView camera data preview"
android:textAllCaps="false"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="30dp"/>
<Button
android:id="@+id/btn_nv21data_callback"
android:text="Call back NV21 data."
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="30dp"/>
</LinearLayout>
Copy the code
Activity_camera_surface_view. XML:
<? xml version="1.0" encoding="utf-8"? > <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".CameraSurfaceViewActivity">
<SurfaceView
android:id="@+id/surfaceView"
android:layout_width="match_parent"
android:layout_height="match_parent">
</SurfaceView>
</LinearLayout>
Copy the code
Activity_camera_texture_view. XML:
<? xml version="1.0" encoding="utf-8"? > <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".CameraTextureViewActivity">
<TextureView
android:id="@+id/textureView"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</LinearLayout>
Copy the code
Activity_nv21data_callback. XML:
<? xml version="1.0" encoding="utf-8"? > <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".NV21DataCallbackActivity"
android:orientation="vertical">
<SurfaceView
android:id="@+id/surfaceView"
android:layout_width="match_parent"
android:layout_height="400dp" />
<ImageView
android:id="@+id/iv_imageview"
android:layout_width="match_parent"
android:layout_height="200dp">
</ImageView>
</LinearLayout>
Copy the code
(2) Code
MainActivity.java
package com.lzacking.cameraapidemo;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;
import android.Manifest;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
private Button mSurfaceView;
private Button mTextureView;
private Button mNv21DataCallback;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// SurfaceView previews camera data
mSurfaceView = findViewById(R.id.btn_surfaceview);
mSurfaceView.setOnClickListener(this);
// TextureView previews camera data
mTextureView = findViewById(R.id.btn_textureview);
mTextureView.setOnClickListener(this);
// The obtained NV21 data is called back
mNv21DataCallback = findViewById(R.id.btn_nv21data_callback);
mNv21DataCallback.setOnClickListener(this);
// Request permission
if (ContextCompat.checkSelfPermission(MainActivity.this, Manifest.permission.CAMERA) ! = PackageManager.PERMISSION_GRANTED) { ActivityCompat.requestPermissions(MainActivity.this.new String[]{Manifest.permission.CAMERA}, 1); }}@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
switch (requestCode) {
case 1:
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
Log.i("info"."onRequestPermissionsResult: " + "Permission requested");
} else {
Toast.makeText(this."You need to turn on camera permissions.", Toast.LENGTH_LONG).show();
}
break;
default:}}@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.btn_surfaceview:
Intent intentSurfaceView = new Intent(this, CameraSurfaceViewActivity.class);
startActivity(intentSurfaceView);
break;
case R.id.btn_textureview:
Intent intentTextureView = new Intent(this, CameraTextureViewActivity.class);
startActivity(intentTextureView);
break;
case R.id.btn_nv21data_callback:
Intent intentNV21DataCallback = new Intent(this, NV21DataCallbackActivity.class);
startActivity(intentNV21DataCallback);
break;
default:
break; }}}Copy the code
CameraSurfaceViewActivity.java
package com.lzacking.cameraapidemo;
import androidx.appcompat.app.AppCompatActivity;
import android.graphics.SurfaceTexture;
import android.hardware.Camera;
import android.os.Bundle;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.TextureView;
import java.io.IOException;
public class CameraSurfaceViewActivity extends AppCompatActivity implements SurfaceHolder.Callback {
private SurfaceView mSurfaceView;
private Camera mCamera;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_camera_surface_view);
mSurfaceView = findViewById(R.id.surfaceView);
mSurfaceView.getHolder().addCallback(this);
// Open the camera and turn the display direction 90 degrees
mCamera = Camera.open(0);
mCamera.setDisplayOrientation(90);
}
//------ SurfaceView preview -------
@Override
public void surfaceCreated(SurfaceHolder holder) {
// Initialize the control when it is created
try {
mCamera.setPreviewDisplay(holder);
// Start preview
mCamera.startPreview();
} catch(IOException e) { e.printStackTrace(); }}@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
// You can perform corresponding operations when changing
}
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
// Release the cameramCamera.release(); }}Copy the code
CameraTextureViewActivity.java
package com.lzacking.cameraapidemo;
import androidx.appcompat.app.AppCompatActivity;
import android.graphics.SurfaceTexture;
import android.hardware.Camera;
import android.os.Bundle;
import android.view.TextureView;
import java.io.IOException;
public class CameraTextureViewActivity extends AppCompatActivity implements TextureView.SurfaceTextureListener {
private TextureView mTextureView;
private Camera mCamera;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_camera_texture_view);
mTextureView = findViewById(R.id.textureView);
mTextureView.setSurfaceTextureListener(this);
// Open the camera and turn the display direction 90 degrees
mCamera = Camera.open(0);
mCamera.setDisplayOrientation(90);
}
//------ TextureView preview -------
@Override
public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) {
// Initialize the control when it is created
try {
mCamera.setPreviewTexture(surface);
// Start preview
mCamera.startPreview();
} catch(IOException e) { e.printStackTrace(); }}@Override
public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) {
// You can perform corresponding operations when changing
}
@Override
public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) {
// Release the camera
mCamera.release();
return false;
}
@Override
public void onSurfaceTextureUpdated(SurfaceTexture surface) {}}Copy the code
NV21DataCallbackActivity
package com.lzacking.cameraapidemo;
import androidx.appcompat.app.AppCompatActivity;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.ImageFormat;
import android.graphics.Matrix;
import android.graphics.Rect;
import android.graphics.YuvImage;
import android.hardware.Camera;
import android.os.Bundle;
import android.util.Log;
import android.view.Surface;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.widget.ImageView;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
public class NV21DataCallbackActivity extends AppCompatActivity implements SurfaceHolder.Callback {
private Camera mCamera;
private SurfaceView mSurfaceView;
private Camera.Size mPreviewSize; // Preview the size
private ByteArrayOutputStream mBaos;
private byte[] mImageBytes;
private Bitmap mBitmap;
private ImageView mImageView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_nv21data_callback);
mImageView = findViewById(R.id.iv_imageview);
mSurfaceView = findViewById(R.id.surfaceView);
mSurfaceView.getHolder().addCallback(this);
// Open the camera and turn the display direction 90 degrees
mCamera = Camera.open(0);
mCamera.setDisplayOrientation(90);
}
@Override
public void surfaceCreated(SurfaceHolder holder) {}// Window changes
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
doChange(holder);
}
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
mCamera.release();
}
// When our program starts running, the surFaceView displays the content obtained by the current camera, and the obtained NV21 data is displayed on the ImageView control
private void doChange(SurfaceHolder holder) {
try {
mCamera.setPreviewDisplay(holder);// Set the camera preview screen
// Set the rotation Angle of the surfaceView
mCamera.setDisplayOrientation(getDegree());
if(mCamera ! =null ) {
try {
Camera.Parameters parameters = mCamera.getParameters(); // Get camera parameters
// You can set parameters as required
// Zoom the lens
// parameters.setZoom();
// Set the size of the preview photo
// parameters.setPreviewSize(200, 200);
// Sets the minimum and maximum number of frames per second to display when previewing photos
// parameters.setPreviewFpsRange(4, 10);
// Set the image format
// parameters.setPictureFormat(ImageFormat.JPEG);
Image quality [0-100],100 is the highest
// parameters.set("jpeg-quality", 85);
// Set the size of the photo
// parameters.setPictureSize(200, 200);
// Set the image format of the preview image
parameters.setPreviewFormat(ImageFormat.NV21);
mCamera.setParameters(parameters);
} catch (Exception e) {
e.printStackTrace();
}
}
mCamera.setPreviewCallback(new Camera.PreviewCallback() {
@Override
public void onPreviewFrame(byte[] data, Camera camera) {
// Process data, where the data is in NV21 format, and display the data on the ImageView control
mPreviewSize = camera.getParameters().getPreviewSize();// Get the size for the format conversion
/ / remove hair YUVIMAGE
YuvImage yuvimage = new YuvImage(
data,
ImageFormat.NV21,
mPreviewSize.width,
mPreviewSize.height,
null);
mBaos = new ByteArrayOutputStream();
// YuvImage is converted to JPG format
yuvimage.compressToJpeg(new Rect(0.0, mPreviewSize.width, mPreviewSize.height), 100, mBaos);// 80--JPG image quality [0-100],100 highest
mImageBytes = mBaos.toByteArray();
// Convert mImageBytes to bitmap
BitmapFactory.Options options = new BitmapFactory.Options();
options.inPreferredConfig = Bitmap.Config.RGB_565;
mBitmap = BitmapFactory.decodeByteArray(mImageBytes, 0, mImageBytes.length, options); mImageView.setImageBitmap(rotateBitmap(mBitmap, getDegree())); }}); mCamera.startPreview();// Start preview
} catch(IOException e) { e.printStackTrace(); }}private int getDegree(a) {
// Get the current screen rotation Angle
int rotating = this.getWindowManager().getDefaultDisplay().getRotation();
int degree = 0;/ / degree
// Set the surfaceView display Angle according to the rotation Angle of the phone
switch (rotating) {
case Surface.ROTATION_0:
degree = 90;
break;
case Surface.ROTATION_90:
degree = 0;
break;
case Surface.ROTATION_180:
degree = 270;
break;
case Surface.ROTATION_270:
degree = 180;
break;
}
return degree;
}
/** * select transform *@paramOrigin original *@paramDegree Degree of rotation, positive or negative *@returnRotated image */
private Bitmap rotateBitmap(Bitmap origin, float degree) {
if (origin == null) {
return null;
}
int width = origin.getWidth();
int height = origin.getHeight();
Matrix matrix = new Matrix();
matrix.setRotate(degree);
// Rotate around the place
Bitmap newBM = Bitmap.createBitmap(origin, 0.0, width, height, matrix, false);
if (newBM.equals(origin)) {
return newBM;
}
origin.recycle();
returnnewBM; }}Copy the code
(3) Permission
<uses-permission android:name="android.permission.CAMERA" />
Copy the code
Source code: Android audio and video development foundation (three) : The Android platform using Camera API for video collection, and preview Camera data, get NV21 data callback