Android 中的 FFMPEG 视频录制正在获取绿色锁存器的覆盖
FFMPEG Video Recording in Android getting overlay of Green latches
我使用 FFMPEG 和 OpenCV 将视频播放器集成到 Android 应用程序中。
构建 Gradle:-
compile('org.bytedeco:javacv-platform:1.4') {
exclude group: 'org.bytedeco.javacpp-presets'
}
compile group: 'org.bytedeco.javacpp-presets', name: 'opencv', version: '3.4.0-1.4'
compile group: 'org.bytedeco.javacpp-presets', name: 'ffmpeg', version: '3.4.1-1.4'
compile files('libs/ffmpeg-android-arm.jar')
compile files('libs/ffmpeg-android-x86.jar')
compile files('libs/opencv-android-arm.jar')
compile files('libs/opencv-android-x86.jar')
我已将 'jniLibs' 包含在 'main' 文件夹中 'armeabi,amreabi-v7a, x86' 文件夹的。
我可以打开相机并录制视频。
视频O/P未按预期播放,音频质量良好。请看下图。
我用于集成的代码:https://github.com/CrazyOrr/FFmpegRecorder
提前致谢!!
我使用 SurfaceView 找到了解决方法。检查我的工作代码。
public class SurfaceViewVideo extends Activity implements MediaPlayer.OnPreparedListener{
private Camera myCamera;
private MyCameraSurfaceView myCameraSurfaceView;
private MediaRecorder mediaRecorder;
private int currentCameraId=1;
ImageView myButton,switchCamera;
SurfaceHolder surfaceHolder;
boolean recording;
boolean isVideoStopped;
private MediaPlayer mediaPlayer;
private SurfaceView playSurfaceView;
private SurfaceHolder playSurfaceHolder;
private FrameLayout videoView;
private List<Camera.Size> mSupportedPreviewSizes;
private Camera.Size mPreviewSize;
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
recording = false;
isVideoStopped = false;
setContentView(R.layout.activity_surface_view_video);
switchCamera = (ImageView)findViewById(R.id.switchCamera);
playSurfaceView = (SurfaceView)findViewById(R.id.playSurface);
playSurfaceHolder = playSurfaceView.getHolder();
videoView = (FrameLayout)findViewById(R.id.videoview);
//Get Camera for preview
myCamera = getCameraInstance();
if(myCamera == null){
Toast.makeText(this,
"Fail to get Camera",
Toast.LENGTH_LONG).show();
}
myCameraSurfaceView = new MyCameraSurfaceView(this, myCamera);
FrameLayout myCameraPreview = (FrameLayout)findViewById(R.id.videoview);
myCameraPreview.addView(myCameraSurfaceView);
myButton = (ImageView)findViewById(R.id.mybutton);
myButton.setOnClickListener(myButtonOnClickListener);
switchCamera.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
onCameraChange();
}
});
}
Button.OnClickListener myButtonOnClickListener
= new Button.OnClickListener(){
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
if(!isVideoStopped) {
if (recording) {
// stop recording and release camera
mediaRecorder.stop(); // stop the recording
releaseMediaRecorder(); // release the MediaRecorder object
myButton.setImageResource(R.drawable.ic_play);
isVideoStopped = true;
videoView.setVisibility(View.GONE);
myCameraSurfaceView.setVisibility(View.GONE);
playSurfaceView.setVisibility(View.VISIBLE);
} else {
//Release Camera before MediaRecorder start
releaseCamera();
if (!prepareMediaRecorder()) {
Toast.makeText(SurfaceViewVideo.this,
"Fail in prepareMediaRecorder()!\n - Ended -",
Toast.LENGTH_LONG).show();
}
mediaRecorder.start();
recording = true;
myButton.setImageResource(R.drawable.ic_stop_white_24px);
}
}else{
if(mediaPlayer==null) {
mediaPlayer = new MediaPlayer();
try {
mediaPlayer.setDisplay(playSurfaceHolder);
mediaPlayer.setDataSource("/sdcard/myvideo.mp4");
mediaPlayer.prepare();
mediaPlayer.setOnPreparedListener(SurfaceViewVideo.this);
mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
} catch (Exception e) {
e.printStackTrace();
}
}else{
mediaPlayer.start();
}
}
}};
private Camera getCameraInstance(){
// TODO Auto-generated method stub
Camera c = null;
try {
c = Camera.open(1); // attempt to get a Camera instance
c.setDisplayOrientation(90);
}
catch (Exception e){
// Camera is not available (in use or does not exist)
}
return c; // returns null if camera is unavailable
}
public void onCameraChange() {
myCamera.stopPreview();
myCamera.release();
if(currentCameraId == Camera.CameraInfo.CAMERA_FACING_BACK){
currentCameraId = Camera.CameraInfo.CAMERA_FACING_FRONT;
}
else {
currentCameraId = Camera.CameraInfo.CAMERA_FACING_BACK;
}
myCamera = Camera.open(currentCameraId);
Camera.CameraInfo info = new Camera.CameraInfo();
Camera.getCameraInfo(Camera.CameraInfo.CAMERA_FACING_FRONT, info);
int rotation = this.getWindowManager().getDefaultDisplay().getRotation();
int degrees = 0;
switch (rotation) {
case Surface.ROTATION_0: degrees = 0; break; //Natural orientation
case Surface.ROTATION_90: degrees = 90; break; //Landscape left
case Surface.ROTATION_180: degrees = 180; break;//Upside down
case Surface.ROTATION_270: degrees = 270; break;//Landscape right
}
int rotate = (info.orientation - degrees + 360) % 360;
//STEP #2: Set the 'rotation' parameter
Camera.Parameters params = myCamera.getParameters();
params.setRotation(rotate);
try {
myCamera.setPreviewDisplay(myCameraSurfaceView.getHolder());
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
myCamera.setParameters(params);
myCamera.setDisplayOrientation(90);
myCamera.startPreview();
}
private boolean prepareMediaRecorder(){
myCamera = getCameraInstance();
mediaRecorder = new MediaRecorder();
myCamera.unlock();
mediaRecorder.setCamera(myCamera);
mediaRecorder.setAudioSource(MediaRecorder.AudioSource.CAMCORDER);
mediaRecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA);
mediaRecorder.setProfile(CamcorderProfile.get(CamcorderProfile.QUALITY_480P));
mediaRecorder.setOutputFile("/sdcard/myvideo.mp4");
mediaRecorder.setMaxDuration(60000); // Set max duration 60 sec.
mediaRecorder.setMaxFileSize(5000000); // Set max file size 5M
mediaRecorder.setPreviewDisplay(myCameraSurfaceView.getHolder().getSurface());
mediaRecorder.setOrientationHint(270);
try {
mediaRecorder.prepare();
} catch (IllegalStateException e) {
releaseMediaRecorder();
return false;
} catch (IOException e) {
releaseMediaRecorder();
return false;
}
return true;
}
@Override
protected void onPause() {
super.onPause();
releaseMediaRecorder(); // if you are using MediaRecorder, release it first
releaseCamera(); // release the camera immediately on pause event
releaseMediaPlayer();
}
private void releaseMediaRecorder(){
if (mediaRecorder != null) {
mediaRecorder.reset(); // clear recorder configuration
mediaRecorder.release(); // release the recorder object
mediaRecorder = null;
myCamera.lock(); // lock camera for later use
}
}
private void releaseCamera(){
if (myCamera != null){
myCamera.release(); // release the camera for other applications
myCamera = null;
}
}
public void releaseMediaPlayer(){
if(mediaPlayer!=null){
mediaPlayer.release();
mediaPlayer = null;
}
}
@Override
public void onPrepared(MediaPlayer mediaPlayer) {
mediaPlayer.start();
}
public class MyCameraSurfaceView extends SurfaceView implements SurfaceHolder.Callback{
private SurfaceHolder mHolder;
private Camera mCamera;
public MyCameraSurfaceView(Context context, Camera camera) {
super(context);
mCamera = camera;
// supported preview sizes
mSupportedPreviewSizes = myCamera.getParameters().getSupportedPreviewSizes();
// Install a SurfaceHolder.Callback so we get notified when the
// underlying surface is created and destroyed.
mHolder = getHolder();
mHolder.addCallback(this);
// deprecated setting, but required on Android versions prior to 3.0
mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
}
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int weight,
int height) {
// If your preview can change or rotate, take care of those events here.
// Make sure to stop the preview before resizing or reformatting it.
if (mHolder.getSurface() == null){
// preview surface does not exist
return;
}
// stop preview before making changes
try {
mCamera.stopPreview();
} catch (Exception e){
// ignore: tried to stop a non-existent preview
}
// make any resize, rotate or reformatting changes here
// start preview with new settings
try {
Camera.Parameters parameters = mCamera.getParameters();
parameters.setPreviewSize(mPreviewSize.width, mPreviewSize.height);
mCamera.setParameters(parameters);
mCamera.setDisplayOrientation(90);
mCamera.setPreviewDisplay(mHolder);
mCamera.startPreview();
} catch (Exception e){
}
}
@Override
public void surfaceCreated(SurfaceHolder holder) {
// TODO Auto-generated method stub
// The Surface has been created, now tell the camera where to draw the preview.
try {
mCamera.setPreviewDisplay(holder);
mCamera.startPreview();
} catch (IOException e) {
}
}
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
// TODO Auto-generated method stub
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
final int width = resolveSize(getSuggestedMinimumWidth(), widthMeasureSpec);
final int height = resolveSize(getSuggestedMinimumHeight(), heightMeasureSpec);
setMeasuredDimension(width, height);
if (mSupportedPreviewSizes != null) {
mPreviewSize = getOptimalPreviewSize(mSupportedPreviewSizes, width, height);
}
}
}
private Camera.Size getOptimalPreviewSize(List<Camera.Size> sizes, int w, int h) {
final double ASPECT_TOLERANCE = 0.1;
double targetRatio=(double)h / w;
if (sizes == null) return null;
Camera.Size optimalSize = null;
double minDiff = Double.MAX_VALUE;
int targetHeight = h;
for (Camera.Size size : sizes) {
double ratio = (double) size.width / size.height;
if (Math.abs(ratio - targetRatio) > ASPECT_TOLERANCE) continue;
if (Math.abs(size.height - targetHeight) < minDiff) {
optimalSize = size;
minDiff = Math.abs(size.height - targetHeight);
}
}
if (optimalSize == null) {
minDiff = Double.MAX_VALUE;
for (Camera.Size size : sizes) {
if (Math.abs(size.height - targetHeight) < minDiff) {
optimalSize = size;
minDiff = Math.abs(size.height - targetHeight);
}
}
}
return optimalSize;
}
}
我使用 FFMPEG 和 OpenCV 将视频播放器集成到 Android 应用程序中。
构建 Gradle:-
compile('org.bytedeco:javacv-platform:1.4') {
exclude group: 'org.bytedeco.javacpp-presets'
}
compile group: 'org.bytedeco.javacpp-presets', name: 'opencv', version: '3.4.0-1.4'
compile group: 'org.bytedeco.javacpp-presets', name: 'ffmpeg', version: '3.4.1-1.4'
compile files('libs/ffmpeg-android-arm.jar')
compile files('libs/ffmpeg-android-x86.jar')
compile files('libs/opencv-android-arm.jar')
compile files('libs/opencv-android-x86.jar')
我已将 'jniLibs' 包含在 'main' 文件夹中 'armeabi,amreabi-v7a, x86' 文件夹的。
我可以打开相机并录制视频。
视频O/P未按预期播放,音频质量良好。请看下图。
我用于集成的代码:https://github.com/CrazyOrr/FFmpegRecorder
提前致谢!!
我使用 SurfaceView 找到了解决方法。检查我的工作代码。
public class SurfaceViewVideo extends Activity implements MediaPlayer.OnPreparedListener{
private Camera myCamera;
private MyCameraSurfaceView myCameraSurfaceView;
private MediaRecorder mediaRecorder;
private int currentCameraId=1;
ImageView myButton,switchCamera;
SurfaceHolder surfaceHolder;
boolean recording;
boolean isVideoStopped;
private MediaPlayer mediaPlayer;
private SurfaceView playSurfaceView;
private SurfaceHolder playSurfaceHolder;
private FrameLayout videoView;
private List<Camera.Size> mSupportedPreviewSizes;
private Camera.Size mPreviewSize;
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
recording = false;
isVideoStopped = false;
setContentView(R.layout.activity_surface_view_video);
switchCamera = (ImageView)findViewById(R.id.switchCamera);
playSurfaceView = (SurfaceView)findViewById(R.id.playSurface);
playSurfaceHolder = playSurfaceView.getHolder();
videoView = (FrameLayout)findViewById(R.id.videoview);
//Get Camera for preview
myCamera = getCameraInstance();
if(myCamera == null){
Toast.makeText(this,
"Fail to get Camera",
Toast.LENGTH_LONG).show();
}
myCameraSurfaceView = new MyCameraSurfaceView(this, myCamera);
FrameLayout myCameraPreview = (FrameLayout)findViewById(R.id.videoview);
myCameraPreview.addView(myCameraSurfaceView);
myButton = (ImageView)findViewById(R.id.mybutton);
myButton.setOnClickListener(myButtonOnClickListener);
switchCamera.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
onCameraChange();
}
});
}
Button.OnClickListener myButtonOnClickListener
= new Button.OnClickListener(){
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
if(!isVideoStopped) {
if (recording) {
// stop recording and release camera
mediaRecorder.stop(); // stop the recording
releaseMediaRecorder(); // release the MediaRecorder object
myButton.setImageResource(R.drawable.ic_play);
isVideoStopped = true;
videoView.setVisibility(View.GONE);
myCameraSurfaceView.setVisibility(View.GONE);
playSurfaceView.setVisibility(View.VISIBLE);
} else {
//Release Camera before MediaRecorder start
releaseCamera();
if (!prepareMediaRecorder()) {
Toast.makeText(SurfaceViewVideo.this,
"Fail in prepareMediaRecorder()!\n - Ended -",
Toast.LENGTH_LONG).show();
}
mediaRecorder.start();
recording = true;
myButton.setImageResource(R.drawable.ic_stop_white_24px);
}
}else{
if(mediaPlayer==null) {
mediaPlayer = new MediaPlayer();
try {
mediaPlayer.setDisplay(playSurfaceHolder);
mediaPlayer.setDataSource("/sdcard/myvideo.mp4");
mediaPlayer.prepare();
mediaPlayer.setOnPreparedListener(SurfaceViewVideo.this);
mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
} catch (Exception e) {
e.printStackTrace();
}
}else{
mediaPlayer.start();
}
}
}};
private Camera getCameraInstance(){
// TODO Auto-generated method stub
Camera c = null;
try {
c = Camera.open(1); // attempt to get a Camera instance
c.setDisplayOrientation(90);
}
catch (Exception e){
// Camera is not available (in use or does not exist)
}
return c; // returns null if camera is unavailable
}
public void onCameraChange() {
myCamera.stopPreview();
myCamera.release();
if(currentCameraId == Camera.CameraInfo.CAMERA_FACING_BACK){
currentCameraId = Camera.CameraInfo.CAMERA_FACING_FRONT;
}
else {
currentCameraId = Camera.CameraInfo.CAMERA_FACING_BACK;
}
myCamera = Camera.open(currentCameraId);
Camera.CameraInfo info = new Camera.CameraInfo();
Camera.getCameraInfo(Camera.CameraInfo.CAMERA_FACING_FRONT, info);
int rotation = this.getWindowManager().getDefaultDisplay().getRotation();
int degrees = 0;
switch (rotation) {
case Surface.ROTATION_0: degrees = 0; break; //Natural orientation
case Surface.ROTATION_90: degrees = 90; break; //Landscape left
case Surface.ROTATION_180: degrees = 180; break;//Upside down
case Surface.ROTATION_270: degrees = 270; break;//Landscape right
}
int rotate = (info.orientation - degrees + 360) % 360;
//STEP #2: Set the 'rotation' parameter
Camera.Parameters params = myCamera.getParameters();
params.setRotation(rotate);
try {
myCamera.setPreviewDisplay(myCameraSurfaceView.getHolder());
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
myCamera.setParameters(params);
myCamera.setDisplayOrientation(90);
myCamera.startPreview();
}
private boolean prepareMediaRecorder(){
myCamera = getCameraInstance();
mediaRecorder = new MediaRecorder();
myCamera.unlock();
mediaRecorder.setCamera(myCamera);
mediaRecorder.setAudioSource(MediaRecorder.AudioSource.CAMCORDER);
mediaRecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA);
mediaRecorder.setProfile(CamcorderProfile.get(CamcorderProfile.QUALITY_480P));
mediaRecorder.setOutputFile("/sdcard/myvideo.mp4");
mediaRecorder.setMaxDuration(60000); // Set max duration 60 sec.
mediaRecorder.setMaxFileSize(5000000); // Set max file size 5M
mediaRecorder.setPreviewDisplay(myCameraSurfaceView.getHolder().getSurface());
mediaRecorder.setOrientationHint(270);
try {
mediaRecorder.prepare();
} catch (IllegalStateException e) {
releaseMediaRecorder();
return false;
} catch (IOException e) {
releaseMediaRecorder();
return false;
}
return true;
}
@Override
protected void onPause() {
super.onPause();
releaseMediaRecorder(); // if you are using MediaRecorder, release it first
releaseCamera(); // release the camera immediately on pause event
releaseMediaPlayer();
}
private void releaseMediaRecorder(){
if (mediaRecorder != null) {
mediaRecorder.reset(); // clear recorder configuration
mediaRecorder.release(); // release the recorder object
mediaRecorder = null;
myCamera.lock(); // lock camera for later use
}
}
private void releaseCamera(){
if (myCamera != null){
myCamera.release(); // release the camera for other applications
myCamera = null;
}
}
public void releaseMediaPlayer(){
if(mediaPlayer!=null){
mediaPlayer.release();
mediaPlayer = null;
}
}
@Override
public void onPrepared(MediaPlayer mediaPlayer) {
mediaPlayer.start();
}
public class MyCameraSurfaceView extends SurfaceView implements SurfaceHolder.Callback{
private SurfaceHolder mHolder;
private Camera mCamera;
public MyCameraSurfaceView(Context context, Camera camera) {
super(context);
mCamera = camera;
// supported preview sizes
mSupportedPreviewSizes = myCamera.getParameters().getSupportedPreviewSizes();
// Install a SurfaceHolder.Callback so we get notified when the
// underlying surface is created and destroyed.
mHolder = getHolder();
mHolder.addCallback(this);
// deprecated setting, but required on Android versions prior to 3.0
mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
}
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int weight,
int height) {
// If your preview can change or rotate, take care of those events here.
// Make sure to stop the preview before resizing or reformatting it.
if (mHolder.getSurface() == null){
// preview surface does not exist
return;
}
// stop preview before making changes
try {
mCamera.stopPreview();
} catch (Exception e){
// ignore: tried to stop a non-existent preview
}
// make any resize, rotate or reformatting changes here
// start preview with new settings
try {
Camera.Parameters parameters = mCamera.getParameters();
parameters.setPreviewSize(mPreviewSize.width, mPreviewSize.height);
mCamera.setParameters(parameters);
mCamera.setDisplayOrientation(90);
mCamera.setPreviewDisplay(mHolder);
mCamera.startPreview();
} catch (Exception e){
}
}
@Override
public void surfaceCreated(SurfaceHolder holder) {
// TODO Auto-generated method stub
// The Surface has been created, now tell the camera where to draw the preview.
try {
mCamera.setPreviewDisplay(holder);
mCamera.startPreview();
} catch (IOException e) {
}
}
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
// TODO Auto-generated method stub
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
final int width = resolveSize(getSuggestedMinimumWidth(), widthMeasureSpec);
final int height = resolveSize(getSuggestedMinimumHeight(), heightMeasureSpec);
setMeasuredDimension(width, height);
if (mSupportedPreviewSizes != null) {
mPreviewSize = getOptimalPreviewSize(mSupportedPreviewSizes, width, height);
}
}
}
private Camera.Size getOptimalPreviewSize(List<Camera.Size> sizes, int w, int h) {
final double ASPECT_TOLERANCE = 0.1;
double targetRatio=(double)h / w;
if (sizes == null) return null;
Camera.Size optimalSize = null;
double minDiff = Double.MAX_VALUE;
int targetHeight = h;
for (Camera.Size size : sizes) {
double ratio = (double) size.width / size.height;
if (Math.abs(ratio - targetRatio) > ASPECT_TOLERANCE) continue;
if (Math.abs(size.height - targetHeight) < minDiff) {
optimalSize = size;
minDiff = Math.abs(size.height - targetHeight);
}
}
if (optimalSize == null) {
minDiff = Double.MAX_VALUE;
for (Camera.Size size : sizes) {
if (Math.abs(size.height - targetHeight) < minDiff) {
optimalSize = size;
minDiff = Math.abs(size.height - targetHeight);
}
}
}
return optimalSize;
}
}