Ini adalah contoh yang bagus. Saya mengalami kesulitan untuk membuatnya berfungsi pada awalnya. Kesalahan saya terkait dengan ukuran keluaran file 0 byte. Saya mulai men-debug dan pelakunya ternyata record.prepare (). Saya tidak menyetel file keluaran baru untuk perekam jadi itu menimpa video saya yang ada setiap kali saya menyentuh layar untuk menghentikan perekaman video. Semoga ini bisa membantu orang lain di luar sana :-) Ngomong-ngomong, perlu disebutkan bahwa Anda juga perlu menambahkan izin RECORD_AUDIO, CAMERA, dan WRITE_EXTERNAL_STORAGE ke manifes Anda agar kode contoh ini berfungsi.
PERINGATAN! Jika Anda akan menggunakan contoh ini, jangan lupa untuk menghapus metode finish () dari penghancuran permukaan! Ini menutup kesempatan Anda untuk kembali ke aktivitas ini dari aktivitas lain. Saya tersesat di sana lebih dari 2 jam)
Penyelam
3
@vanevery Masalah besar dari kode ini adalah .. itu membuat dua file, satu merekam bagus yang lain dibuat ketika kita menyiapkan perekam .. adakah cara untuk menghapus file itu jika kita tidak merekamnya ..
Swap-IOS -Android
46
Berikut adalah contoh lain yang berhasil
publicclassEnregistrementVideoStackActivityextendsActivityimplementsSurfaceHolder.Callback{
private SurfaceHolder surfaceHolder;
private SurfaceView surfaceView;
public MediaRecorder mrec = new MediaRecorder();
private Button startRecording = null;
File video;
private Camera mCamera;
@OverridepublicvoidonCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.camera_surface);
Log.i(null , "Video starting");
startRecording = (Button)findViewById(R.id.buttonstart);
mCamera = Camera.open();
surfaceView = (SurfaceView) findViewById(R.id.surface_camera);
surfaceHolder = surfaceView.getHolder();
surfaceHolder.addCallback(this);
surfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
}
@OverridepublicbooleanonCreateOptionsMenu(Menu menu){
menu.add(0, 0, 0, "StartRecording");
menu.add(0, 1, 0, "StopRecording");
returnsuper.onCreateOptionsMenu(menu);
}
@OverridepublicbooleanonOptionsItemSelected(MenuItem item){
switch (item.getItemId())
{
case0:
try {
startRecording();
} catch (Exception e) {
String message = e.getMessage();
Log.i(null, "Problem Start"+message);
mrec.release();
}
break;
case1: //GoToAllNotes
mrec.stop();
mrec.release();
mrec = null;
break;
default:
break;
}
returnsuper.onOptionsItemSelected(item);
}
protectedvoidstartRecording()throws IOException
{
mrec = new MediaRecorder(); // Works well
mCamera.unlock();
mrec.setCamera(mCamera);
mrec.setPreviewDisplay(surfaceHolder.getSurface());
mrec.setVideoSource(MediaRecorder.VideoSource.CAMERA);
mrec.setAudioSource(MediaRecorder.AudioSource.MIC);
mrec.setProfile(CamcorderProfile.get(CamcorderProfile.QUALITY_HIGH));
mrec.setPreviewDisplay(surfaceHolder.getSurface());
mrec.setOutputFile("/sdcard/zzzz.3gp");
mrec.prepare();
mrec.start();
}
protectedvoidstopRecording(){
mrec.stop();
mrec.release();
mCamera.release();
}
privatevoidreleaseMediaRecorder(){
if (mrec != null) {
mrec.reset(); // clear recorder configuration
mrec.release(); // release the recorder object
mrec = null;
mCamera.lock(); // lock camera for later use
}
}
privatevoidreleaseCamera(){
if (mCamera != null){
mCamera.release(); // release the camera for other applications
mCamera = null;
}
}
@OverridepublicvoidsurfaceChanged(SurfaceHolder holder, int format, int width,
int height){
}
@OverridepublicvoidsurfaceCreated(SurfaceHolder holder){
if (mCamera != null){
Parameters params = mCamera.getParameters();
mCamera.setParameters(params);
}
else {
Toast.makeText(getApplicationContext(), "Camera not available!", Toast.LENGTH_LONG).show();
finish();
}
}
@OverridepublicvoidsurfaceDestroyed(SurfaceHolder holder){
mCamera.stopPreview();
mCamera.release();
}
}
Terima kasih, contoh vanevery menyimpan file berukuran 0 byte, yang tidak berguna
user609239
Dengan mengklik menu perangkat keras, rekaman mulai dan hentikan akan ditampilkan. Namun di tablet Android tidak ada menu hardware. Dalam skenario itu, bagaimana saya bisa memulai dan menghentikan pengambilan video.?
Karthick
Beberapa penyesuaian untuk mendapatkan contoh untuk dikompilasi, tetapi ini bekerja dengan sangat baik bagi saya. Terima kasih!
Gopherkhan
@Milos Dapatkah Anda memberi tahu saya cara menyematkan gambar marker ke dalam video permukaan ??
Ahmad Arslan
5
Anda merekam audio dan video menggunakan kelas MediaRecorder yang sama. Sangat sederhana. Berikut contohnya .
Ada bug halus dalam implementasi video di MediaRecorder yang menyebabkan kesalahan segmentasi karena alasan yang tidak dapat diprediksi. Saya curiga inilah mengapa @Vishnuparsad memposting pertanyaan ini sejak awal.
bobpoekert
Maka dia seharusnya menyebutkannya :)
Drakosha
Dibutuhkan sedikit lebih banyak pekerjaan untuk merekam video karena Anda harus berurusan dengan permukaan pratinjau.
publicclassVideoextendsActivityimplementsOnClickListener,
SurfaceHolder.Callback{
privatestaticfinal String TAG = "CAMERA_TUTORIAL";
private SurfaceView mSurfaceView;
private SurfaceHolder mHolder;
private Camera mCamera;
privateboolean previewRunning;
private MediaRecorder mMediaRecorder;
privatefinalint maxDurationInMs = 20000;
privatefinallong maxFileSizeInBytes = 500000;
privatefinalint videoFramesPerSecond = 20;
Button btn_record;
boolean mInitSuccesful = false;
File file;
ToggleButton mToggleButton;
@OverridepublicvoidonCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.video);
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
mSurfaceView = (SurfaceView) findViewById(R.id.surface_camera);
mHolder = mSurfaceView.getHolder();
mHolder.addCallback(this);
mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
mToggleButton = (ToggleButton) findViewById(R.id.toggleRecordingButton);
mToggleButton.setOnClickListener(new OnClickListener() {
@Override// toggle video recordingpublicvoidonClick(View v){
if (((ToggleButton) v).isChecked())
mMediaRecorder.start();
else {
mMediaRecorder.stop();
mMediaRecorder.reset();
try {
initRecorder(mHolder.getSurface());
} catch (IOException e) {
e.printStackTrace();
}
}
}
});
}
privatevoidinitRecorder(Surface surface)throws IOException {
// It is very important to unlock the camera before doing setCamera// or it will results in a black previewif (mCamera == null)
{
mCamera = Camera.open();
mCamera.unlock();
}
if (mMediaRecorder == null)
mMediaRecorder = new MediaRecorder();
mMediaRecorder.setPreviewDisplay(surface);
mMediaRecorder.setCamera(mCamera);
mMediaRecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA);
mMediaRecorder.setAudioSource(MediaRecorder.AudioSource.DEFAULT);
mMediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.DEFAULT);
mMediaRecorder.setOutputFile(this.initFile().getAbsolutePath());
// No limit. Don't forget to check the space on disk.
mMediaRecorder.setMaxDuration(50000);
mMediaRecorder.setVideoFrameRate(24);
mMediaRecorder.setVideoSize(1280, 720);
mMediaRecorder.setVideoEncodingBitRate(3000000);
mMediaRecorder.setAudioEncodingBitRate(8000);
mMediaRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.DEFAULT);
mMediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
try {
mMediaRecorder.prepare();
} catch (IllegalStateException e) {
// This is thrown if the previous calls are not called with the// proper order
e.printStackTrace();
}
mInitSuccesful = true;
}
private File initFile(){
// File dir = new// File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_MOVIES),// this
File dir = new File(Environment.getExternalStorageDirectory(), this
.getClass().getPackage().getName());
if (!dir.exists() && !dir.mkdirs()) {
Log.wtf(TAG,
"Failed to create storage directory: "
+ dir.getAbsolutePath());
Toast.makeText(Video.this, "not record", Toast.LENGTH_SHORT);
file = null;
} else {
file = new File(dir.getAbsolutePath(), new SimpleDateFormat(
"'IMG_'yyyyMMddHHmmss'.mp4'").format(new Date()));
}
return file;
}
@OverridepublicvoidsurfaceCreated(SurfaceHolder holder){
try {
if (!mInitSuccesful)
initRecorder(mHolder.getSurface());
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
privatevoidshutdown(){
// Release MediaRecorder and especially the Camera as it's a shared// object that can be used by other applications
mMediaRecorder.reset();
mMediaRecorder.release();
mCamera.release();
// once the objects have been released they can't be reused
mMediaRecorder = null;
mCamera = null;
}
@OverridepublicvoidsurfaceDestroyed(SurfaceHolder holder){
shutdown();
}
@OverridepublicvoidsurfaceChanged(SurfaceHolder holder, int format, int width,
int height){
// TODO Auto-generated method stub
}
@OverridepublicvoidonClick(View v){
// TODO Auto-generated method stub
}
}
Kelas MediaMetadataRetriever
publicclassMediaMetadataRetriever{
static {
System.loadLibrary("media_jni");
native_init();
}
// The field below is accessed by native methods@SuppressWarnings("unused")privateint mNativeContext;
publicMediaMetadataRetriever(){
native_setup();
}
/**
* Call this method before setDataSource() so that the mode becomes
* effective for subsequent operations. This method can be called only once
* at the beginning if the intended mode of operation for a
* MediaMetadataRetriever object remains the same for its whole lifetime,
* and thus it is unnecessary to call this method each time setDataSource()
* is called. If this is not never called (which is allowed), by default the
* intended mode of operation is to both capture frame and retrieve meta
* data (i.e., MODE_GET_METADATA_ONLY | MODE_CAPTURE_FRAME_ONLY).
* Often, this may not be what one wants, since doing this has negative
* performance impact on execution time of a call to setDataSource(), since
* both types of operations may be time consuming.
*
* @param mode The intended mode of operation. Can be any combination of
* MODE_GET_METADATA_ONLY and MODE_CAPTURE_FRAME_ONLY:
* 1. MODE_GET_METADATA_ONLY & MODE_CAPTURE_FRAME_ONLY:
* For neither frame capture nor meta data retrieval
* 2. MODE_GET_METADATA_ONLY: For meta data retrieval only
* 3. MODE_CAPTURE_FRAME_ONLY: For frame capture only
* 4. MODE_GET_METADATA_ONLY | MODE_CAPTURE_FRAME_ONLY:
* For both frame capture and meta data retrieval
*/publicnativevoidsetMode(int mode);
/**
* @return the current mode of operation. A negative return value indicates
* some runtime error has occurred.
*/publicnativeintgetMode();
/**
* Sets the data source (file pathname) to use. Call this
* method before the rest of the methods in this class. This method may be
* time-consuming.
*
* @param path The path of the input media file.
* @throws IllegalArgumentException If the path is invalid.
*/publicnativevoidsetDataSource(String path)throws IllegalArgumentException;
/**
* Sets the data source (FileDescriptor) to use. It is the caller's
* responsibility to close the file descriptor. It is safe to do so as soon
* as this call returns. Call this method before the rest of the methods in
* this class. This method may be time-consuming.
*
* @param fd the FileDescriptor for the file you want to play
* @param offset the offset into the file where the data to be played starts,
* in bytes. It must be non-negative
* @param length the length in bytes of the data to be played. It must be
* non-negative.
* @throws IllegalArgumentException if the arguments are invalid
*/publicnativevoidsetDataSource(FileDescriptor fd, long offset, long length)throws IllegalArgumentException;
/**
* Sets the data source (FileDescriptor) to use. It is the caller's
* responsibility to close the file descriptor. It is safe to do so as soon
* as this call returns. Call this method before the rest of the methods in
* this class. This method may be time-consuming.
*
* @param fd the FileDescriptor for the file you want to play
* @throws IllegalArgumentException if the FileDescriptor is invalid
*/publicvoidsetDataSource(FileDescriptor fd)throws IllegalArgumentException {
// intentionally less than LONG_MAX
setDataSource(fd, 0, 0x7ffffffffffffffL);
}
/**
* Sets the data source as a content Uri. Call this method before
* the rest of the methods in this class. This method may be time-consuming.
*
* @param context the Context to use when resolving the Uri
* @param uri the Content URI of the data you want to play
* @throws IllegalArgumentException if the Uri is invalid
* @throws SecurityException if the Uri cannot be used due to lack of
* permission.
*/publicvoidsetDataSource(Context context, Uri uri)throws IllegalArgumentException, SecurityException {
if (uri == null) {
thrownew IllegalArgumentException();
}
String scheme = uri.getScheme();
if(scheme == null || scheme.equals("file")) {
setDataSource(uri.getPath());
return;
}
AssetFileDescriptor fd = null;
try {
ContentResolver resolver = context.getContentResolver();
try {
fd = resolver.openAssetFileDescriptor(uri, "r");
} catch(FileNotFoundException e) {
thrownew IllegalArgumentException();
}
if (fd == null) {
thrownew IllegalArgumentException();
}
FileDescriptor descriptor = fd.getFileDescriptor();
if (!descriptor.valid()) {
thrownew IllegalArgumentException();
}
// Note: using getDeclaredLength so that our behavior is the same// as previous versions when the content provider is returning// a full file.if (fd.getDeclaredLength() < 0) {
setDataSource(descriptor);
} else {
setDataSource(descriptor, fd.getStartOffset(), fd.getDeclaredLength());
}
return;
} catch (SecurityException ex) {
} finally {
try {
if (fd != null) {
fd.close();
}
} catch(IOException ioEx) {
}
}
setDataSource(uri.toString());
}
/**
* Call this method after setDataSource(). This method retrieves the
* meta data value associated with the keyCode.
*
* The keyCode currently supported is listed below as METADATA_XXX
* constants. With any other value, it returns a null pointer.
*
* @param keyCode One of the constants listed below at the end of the class.
* @return The meta data value associate with the given keyCode on success;
* null on failure.
*/publicnative String extractMetadata(int keyCode);
/**
* Call this method after setDataSource(). This method finds a
* representative frame if successful and returns it as a bitmap. This is
* useful for generating a thumbnail for an input media source.
*
* @return A Bitmap containing a representative video frame, which
* can be null, if such a frame cannot be retrieved.
*/publicnative Bitmap captureFrame();
/**
* Call this method after setDataSource(). This method finds the optional
* graphic or album art associated (embedded or external url linked) the
* related data source.
*
* @return null if no such graphic is found.
*/publicnativebyte[] extractAlbumArt();
/**
* Call it when one is done with the object. This method releases the memory
* allocated internally.
*/publicnativevoidrelease();
privatenativevoidnative_setup();
privatestaticnativevoidnative_init();
privatenativefinalvoidnative_finalize();
@Overrideprotectedvoidfinalize()throws Throwable {
try {
native_finalize();
} finally {
super.finalize();
}
}
publicstaticfinalint MODE_GET_METADATA_ONLY = 0x01;
publicstaticfinalint MODE_CAPTURE_FRAME_ONLY = 0x02;
/*
* Do not change these values without updating their counterparts
* in include/media/mediametadataretriever.h!
*/publicstaticfinalint METADATA_KEY_CD_TRACK_NUMBER = 0;
publicstaticfinalint METADATA_KEY_ALBUM = 1;
publicstaticfinalint METADATA_KEY_ARTIST = 2;
publicstaticfinalint METADATA_KEY_AUTHOR = 3;
publicstaticfinalint METADATA_KEY_COMPOSER = 4;
publicstaticfinalint METADATA_KEY_DATE = 5;
publicstaticfinalint METADATA_KEY_GENRE = 6;
publicstaticfinalint METADATA_KEY_TITLE = 7;
publicstaticfinalint METADATA_KEY_YEAR = 8;
publicstaticfinalint METADATA_KEY_DURATION = 9;
publicstaticfinalint METADATA_KEY_NUM_TRACKS = 10;
publicstaticfinalint METADATA_KEY_IS_DRM_CRIPPLED = 11;
publicstaticfinalint METADATA_KEY_CODEC = 12;
publicstaticfinalint METADATA_KEY_RATING = 13;
publicstaticfinalint METADATA_KEY_COMMENT = 14;
publicstaticfinalint METADATA_KEY_COPYRIGHT = 15;
publicstaticfinalint METADATA_KEY_BIT_RATE = 16;
publicstaticfinalint METADATA_KEY_FRAME_RATE = 17;
publicstaticfinalint METADATA_KEY_VIDEO_FORMAT = 18;
publicstaticfinalint METADATA_KEY_VIDEO_HEIGHT = 19;
publicstaticfinalint METADATA_KEY_VIDEO_WIDTH = 20;
publicstaticfinalint METADATA_KEY_WRITER = 21;
// Add more here...
}
Hai. Saya mencoba menerapkan kode Anda dalam proyek saya tetapi fungsi surfaceCreated tidak pernah dipanggil?
REJH
@REJH, disebutnya, saat permukaan dibuat, karena baris ini mHolder.addCallback(this);melampirkan kelas Aktivitas untuk menangani kejadian permukaan. Mungkin IDE Anda tidak dapat mengenali panggilan ini, tetapi seharusnya dipanggil.
vp_arth
3
Lihat Kode Pratinjau Kamera Contoh ini CameraPreview,. Ini akan membantu Anda dalam mengembangkan kode perekaman video untuk pratinjau video, membuat MediaRecorderobjek, dan mengatur parameter perekaman video.
Untuk kepentingan pencari, contoh ini akan memberikan pratinjau aktif, dengan tombol start / stop untuk merekam. Itu dimodifikasi dari blog android ini dan tampaknya cukup dapat diandalkan.
kelas java (VideoWithSurfaceVw)
package <<your packagename here>>;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;
import android.app.Activity;
import android.content.Context;
import android.hardware.Camera;
import android.media.CamcorderProfile;
import android.media.MediaRecorder;
import android.os.Bundle;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
import android.widget.Button;
import android.widget.FrameLayout;
import android.widget.Toast;
publicclassVideoWithSurfaceVwextendsActivity{
// Adapted from http://sandyandroidtutorials.blogspot.co.uk/2013/05/android-video-capture-tutorial.htmlprivate Camera myCamera;
private MyCameraSurfaceView myCameraSurfaceView;
private MediaRecorder mediaRecorder;
Button myButton;
SurfaceHolder surfaceHolder;
boolean recording;
/** Called when the activity is first created. */@OverridepublicvoidonCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
recording = false;
setContentView(R.layout.activity_video_with_surface_vw);
//Get Camera for preview
myCamera = getCameraInstance();
if(myCamera == null){
Toast.makeText(VideoWithSurfaceVw.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 = (Button)findViewById(R.id.mybutton);
myButton.setOnClickListener(myButtonOnClickListener);
}
Button.OnClickListener myButtonOnClickListener
= new Button.OnClickListener(){
@OverridepublicvoidonClick(View v){
// TODO Auto-generated method stubtry{
if(recording){
// stop recording and release camera
mediaRecorder.stop(); // stop the recording
releaseMediaRecorder(); // release the MediaRecorder object//Exit after saved//finish();
myButton.setText("REC");
recording = false;
}else{
//Release Camera before MediaRecorder start
releaseCamera();
if(!prepareMediaRecorder()){
Toast.makeText(VideoWithSurfaceVw.this,
"Fail in prepareMediaRecorder()!\n - Ended -",
Toast.LENGTH_LONG).show();
finish();
}
mediaRecorder.start();
recording = true;
myButton.setText("STOP");
}
}catch (Exception ex){
ex.printStackTrace();
}
}};
private Camera getCameraInstance(){
// TODO Auto-generated method stub
Camera c = null;
try {
c = Camera.open(); // attempt to get a Camera instance
}
catch (Exception e){
// Camera is not available (in use or does not exist)
}
return c; // returns null if camera is unavailable
}
private String getFileName_CustomFormat(){
SimpleDateFormat sdfDate = new SimpleDateFormat("yyyy-MM-dd HH_mm_ss");
Date now = new Date();
String strDate = sdfDate.format(now);
return strDate;
}
privatebooleanprepareMediaRecorder(){
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_HIGH));
mediaRecorder.setOutputFile("/sdcard/" + getFileName_CustomFormat() + ".mp4");
//mediaRecorder.setOutputFile("/sdcard/myvideo1.mp4");
mediaRecorder.setMaxDuration(60000); // Set max duration 60 sec.
mediaRecorder.setMaxFileSize(50000000); // Set max file size 50M
mediaRecorder.setPreviewDisplay(myCameraSurfaceView.getHolder().getSurface());
try {
mediaRecorder.prepare();
} catch (IllegalStateException e) {
releaseMediaRecorder();
returnfalse;
} catch (IOException e) {
releaseMediaRecorder();
returnfalse;
}
returntrue;
}
@OverrideprotectedvoidonPause(){
super.onPause();
releaseMediaRecorder(); // if you are using MediaRecorder, release it first
releaseCamera(); // release the camera immediately on pause event
}
privatevoidreleaseMediaRecorder(){
if (mediaRecorder != null) {
mediaRecorder.reset(); // clear recorder configuration
mediaRecorder.release(); // release the recorder object
mediaRecorder = new MediaRecorder();
myCamera.lock(); // lock camera for later use
}
}
privatevoidreleaseCamera(){
if (myCamera != null){
myCamera.release(); // release the camera for other applications
myCamera = null;
}
}
publicclassMyCameraSurfaceViewextendsSurfaceViewimplementsSurfaceHolder.Callback{
private SurfaceHolder mHolder;
private Camera mCamera;
publicMyCameraSurfaceView(Context context, Camera camera){
super(context);
mCamera = camera;
// 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);
}
@OverridepublicvoidsurfaceChanged(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 existreturn;
}
// stop preview before making changestry {
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 settingstry {
mCamera.setPreviewDisplay(mHolder);
mCamera.startPreview();
} catch (Exception e){
}
}
@OverridepublicvoidsurfaceCreated(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) {
}
}
@OverridepublicvoidsurfaceDestroyed(SurfaceHolder holder){
// TODO Auto-generated method stub
}
}
}
Menjalankan proyek di Android Studio menghasilkan pesan kesalahan berikut dalam file .xml: Kesalahan: (29) Kesalahan penguraian XML: tidak ada elemen yang ditemukan di mana 29 adalah baris yang sesuai dengan </RelativeLayout>
bergercookie
@bergercookie - apakah Anda menemukan / memperbaiki masalah? Saya mengangkat ini dari kode kerja saya (menggunakan Android Studio). Jangan sungkan untuk mengedit postingan saya jika ada masalah.
HockeyJ
1
@bergercookie - contoh xml hanya kehilangan tag penutup RelativeLayout. Saya memperbaiki pemformatannya dan sekarang tag penutup ditampilkan dengan benar
mjp66
1
Sebagai catatan tambahan - sepertinya ada bug di API Android atau dokumentasi yang salah atau mungkin saya hanya bodoh. Google docs dengan jelas menyatakan berikut ini:
Catatan: Mulai Android 4.0 (API level 14), panggilan Camera.lock () dan Camera.unlock () dikelola untuk Anda secara otomatis.
Setelah berjuang selama berhari-hari tanpa hasil dan banyak masalah kecil seperti "gagal untuk memulai" agak kesalahan, saya memutuskan untuk menerapkan penguncian dan BAM secara manual! semuanya bekerja dengan baik.
Saya menggunakan emulator genymotion untuk perangkat 4.1.1 dengan min sdk 14.
Ini tidak bekerja. Itu merusak aplikasi saya dengan mematikan VM.
Pink Jazz
Bekerja! tapi video yang direkam terbalik. Juga ketika saya mencoba melakukan match_parent pada lebar, pratinjau tidak terlihat. : /
M. Usman Khan
untuk pratinjau layar penuh, setel lebar dan tinggi sebagai wrap_content.
M. Usman Khan
Bagaimana cara menyetel varian POTRET?
Rozina
1
Mulai Desember 2017, telah ada beberapa pembaruan, misalnya penggunaan android.hardware.Camerasudah tidak digunakan lagi sekarang. Sementara yang lebih baru android.hardware.camera2hadir dengan hal-hal praktis seperti a CameraManager.
@pookie saya rasa iya, tapi lupa karena sudah 1,5 tahun. Sebenarnya Anda mungkin pernah melihat tautan repo GitHub tersebut, karena mereka akan memiliki beberapa "panduan memulai" yang dapat Anda ikuti.
ch271828n
@pookie Jika Anda pikir itu membantu tolong berikan upvote :)
Jawaban:
Berikut adalah contoh perekaman video sederhana menggunakan MediaRecorder:
public class VideoCapture extends Activity implements OnClickListener, SurfaceHolder.Callback { MediaRecorder recorder; SurfaceHolder holder; boolean recording = false; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); requestWindowFeature(Window.FEATURE_NO_TITLE); getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN); setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE); recorder = new MediaRecorder(); initRecorder(); setContentView(R.layout.main); SurfaceView cameraView = (SurfaceView) findViewById(R.id.CameraView); holder = cameraView.getHolder(); holder.addCallback(this); holder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS); cameraView.setClickable(true); cameraView.setOnClickListener(this); } private void initRecorder() { recorder.setAudioSource(MediaRecorder.AudioSource.DEFAULT); recorder.setVideoSource(MediaRecorder.VideoSource.DEFAULT); CamcorderProfile cpHigh = CamcorderProfile .get(CamcorderProfile.QUALITY_HIGH); recorder.setProfile(cpHigh); recorder.setOutputFile("/sdcard/videocapture_example.mp4"); recorder.setMaxDuration(50000); // 50 seconds recorder.setMaxFileSize(5000000); // Approximately 5 megabytes } private void prepareRecorder() { recorder.setPreviewDisplay(holder.getSurface()); try { recorder.prepare(); } catch (IllegalStateException e) { e.printStackTrace(); finish(); } catch (IOException e) { e.printStackTrace(); finish(); } } public void onClick(View v) { if (recording) { recorder.stop(); recording = false; // Let's initRecorder so we can record again initRecorder(); prepareRecorder(); } else { recording = true; recorder.start(); } } public void surfaceCreated(SurfaceHolder holder) { prepareRecorder(); } public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { } public void surfaceDestroyed(SurfaceHolder holder) { if (recording) { recorder.stop(); recording = false; } recorder.release(); finish(); } }
Ini dari buku saya: Media Android Pro: Mengembangkan Aplikasi Grafik, Musik, Video, dan Multimedia untuk Ponsel Cerdas dan Tablet
Selain itu, jangan lupa untuk menyertakan izin ini dalam manifes:
<uses-permission android:name="android.permission.RECORD_AUDIO" /> <uses-permission android:name="android.permission.CAMERA" /> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
sumber
Berikut adalah contoh lain yang berhasil
public class EnregistrementVideoStackActivity extends Activity implements SurfaceHolder.Callback { private SurfaceHolder surfaceHolder; private SurfaceView surfaceView; public MediaRecorder mrec = new MediaRecorder(); private Button startRecording = null; File video; private Camera mCamera; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.camera_surface); Log.i(null , "Video starting"); startRecording = (Button)findViewById(R.id.buttonstart); mCamera = Camera.open(); surfaceView = (SurfaceView) findViewById(R.id.surface_camera); surfaceHolder = surfaceView.getHolder(); surfaceHolder.addCallback(this); surfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS); } @Override public boolean onCreateOptionsMenu(Menu menu) { menu.add(0, 0, 0, "StartRecording"); menu.add(0, 1, 0, "StopRecording"); return super.onCreateOptionsMenu(menu); } @Override public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()) { case 0: try { startRecording(); } catch (Exception e) { String message = e.getMessage(); Log.i(null, "Problem Start"+message); mrec.release(); } break; case 1: //GoToAllNotes mrec.stop(); mrec.release(); mrec = null; break; default: break; } return super.onOptionsItemSelected(item); } protected void startRecording() throws IOException { mrec = new MediaRecorder(); // Works well mCamera.unlock(); mrec.setCamera(mCamera); mrec.setPreviewDisplay(surfaceHolder.getSurface()); mrec.setVideoSource(MediaRecorder.VideoSource.CAMERA); mrec.setAudioSource(MediaRecorder.AudioSource.MIC); mrec.setProfile(CamcorderProfile.get(CamcorderProfile.QUALITY_HIGH)); mrec.setPreviewDisplay(surfaceHolder.getSurface()); mrec.setOutputFile("/sdcard/zzzz.3gp"); mrec.prepare(); mrec.start(); } protected void stopRecording() { mrec.stop(); mrec.release(); mCamera.release(); } private void releaseMediaRecorder(){ if (mrec != null) { mrec.reset(); // clear recorder configuration mrec.release(); // release the recorder object mrec = null; mCamera.lock(); // lock camera for later use } } private void releaseCamera(){ if (mCamera != null){ mCamera.release(); // release the camera for other applications mCamera = null; } } @Override public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { } @Override public void surfaceCreated(SurfaceHolder holder) { if (mCamera != null){ Parameters params = mCamera.getParameters(); mCamera.setParameters(params); } else { Toast.makeText(getApplicationContext(), "Camera not available!", Toast.LENGTH_LONG).show(); finish(); } } @Override public void surfaceDestroyed(SurfaceHolder holder) { mCamera.stopPreview(); mCamera.release(); } }
camera_surface.xml
<?xml version="1.0" encoding="UTF-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" > <SurfaceView android:id="@+id/surface_camera" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_weight="1" /> <Button android:id="@+id/buttonstart" android:layout_width="wrap_content" android:layout_height="wrap_content" android:background="@drawable/record_start" /> </RelativeLayout>
Dan tentu saja termasuk izin ini dalam manifest:
<uses-permission android:name="android.permission.RECORD_AUDIO" /> <uses-permission android:name="android.permission.CAMERA" /> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
sumber
Anda merekam audio dan video menggunakan kelas MediaRecorder yang sama. Sangat sederhana. Berikut contohnya .
sumber
Demo ini akan membantu Anda ....
video.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent" android:orientation="vertical" > <ToggleButton android:id="@+id/toggleRecordingButton" android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_alignParentTop="true" /> <SurfaceView xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/surface_camera" android:layout_width="fill_parent" android:layout_height="fill_parent" android:layout_centerInParent="true" android:layout_weight="1" > </SurfaceView>
Aktivitas Utama Anda: Video.java
public class Video extends Activity implements OnClickListener, SurfaceHolder.Callback { private static final String TAG = "CAMERA_TUTORIAL"; private SurfaceView mSurfaceView; private SurfaceHolder mHolder; private Camera mCamera; private boolean previewRunning; private MediaRecorder mMediaRecorder; private final int maxDurationInMs = 20000; private final long maxFileSizeInBytes = 500000; private final int videoFramesPerSecond = 20; Button btn_record; boolean mInitSuccesful = false; File file; ToggleButton mToggleButton; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.video); setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE); mSurfaceView = (SurfaceView) findViewById(R.id.surface_camera); mHolder = mSurfaceView.getHolder(); mHolder.addCallback(this); mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS); mToggleButton = (ToggleButton) findViewById(R.id.toggleRecordingButton); mToggleButton.setOnClickListener(new OnClickListener() { @Override // toggle video recording public void onClick(View v) { if (((ToggleButton) v).isChecked()) mMediaRecorder.start(); else { mMediaRecorder.stop(); mMediaRecorder.reset(); try { initRecorder(mHolder.getSurface()); } catch (IOException e) { e.printStackTrace(); } } } }); } private void initRecorder(Surface surface) throws IOException { // It is very important to unlock the camera before doing setCamera // or it will results in a black preview if (mCamera == null) { mCamera = Camera.open(); mCamera.unlock(); } if (mMediaRecorder == null) mMediaRecorder = new MediaRecorder(); mMediaRecorder.setPreviewDisplay(surface); mMediaRecorder.setCamera(mCamera); mMediaRecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA); mMediaRecorder.setAudioSource(MediaRecorder.AudioSource.DEFAULT); mMediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.DEFAULT); mMediaRecorder.setOutputFile(this.initFile().getAbsolutePath()); // No limit. Don't forget to check the space on disk. mMediaRecorder.setMaxDuration(50000); mMediaRecorder.setVideoFrameRate(24); mMediaRecorder.setVideoSize(1280, 720); mMediaRecorder.setVideoEncodingBitRate(3000000); mMediaRecorder.setAudioEncodingBitRate(8000); mMediaRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.DEFAULT); mMediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB); try { mMediaRecorder.prepare(); } catch (IllegalStateException e) { // This is thrown if the previous calls are not called with the // proper order e.printStackTrace(); } mInitSuccesful = true; } private File initFile() { // File dir = new // File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_MOVIES), // this File dir = new File(Environment.getExternalStorageDirectory(), this .getClass().getPackage().getName()); if (!dir.exists() && !dir.mkdirs()) { Log.wtf(TAG, "Failed to create storage directory: " + dir.getAbsolutePath()); Toast.makeText(Video.this, "not record", Toast.LENGTH_SHORT); file = null; } else { file = new File(dir.getAbsolutePath(), new SimpleDateFormat( "'IMG_'yyyyMMddHHmmss'.mp4'").format(new Date())); } return file; } @Override public void surfaceCreated(SurfaceHolder holder) { try { if (!mInitSuccesful) initRecorder(mHolder.getSurface()); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } private void shutdown() { // Release MediaRecorder and especially the Camera as it's a shared // object that can be used by other applications mMediaRecorder.reset(); mMediaRecorder.release(); mCamera.release(); // once the objects have been released they can't be reused mMediaRecorder = null; mCamera = null; } @Override public void surfaceDestroyed(SurfaceHolder holder) { shutdown(); } @Override public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { // TODO Auto-generated method stub } @Override public void onClick(View v) { // TODO Auto-generated method stub } }
Kelas MediaMetadataRetriever
public class MediaMetadataRetriever { static { System.loadLibrary("media_jni"); native_init(); } // The field below is accessed by native methods @SuppressWarnings("unused") private int mNativeContext; public MediaMetadataRetriever() { native_setup(); } /** * Call this method before setDataSource() so that the mode becomes * effective for subsequent operations. This method can be called only once * at the beginning if the intended mode of operation for a * MediaMetadataRetriever object remains the same for its whole lifetime, * and thus it is unnecessary to call this method each time setDataSource() * is called. If this is not never called (which is allowed), by default the * intended mode of operation is to both capture frame and retrieve meta * data (i.e., MODE_GET_METADATA_ONLY | MODE_CAPTURE_FRAME_ONLY). * Often, this may not be what one wants, since doing this has negative * performance impact on execution time of a call to setDataSource(), since * both types of operations may be time consuming. * * @param mode The intended mode of operation. Can be any combination of * MODE_GET_METADATA_ONLY and MODE_CAPTURE_FRAME_ONLY: * 1. MODE_GET_METADATA_ONLY & MODE_CAPTURE_FRAME_ONLY: * For neither frame capture nor meta data retrieval * 2. MODE_GET_METADATA_ONLY: For meta data retrieval only * 3. MODE_CAPTURE_FRAME_ONLY: For frame capture only * 4. MODE_GET_METADATA_ONLY | MODE_CAPTURE_FRAME_ONLY: * For both frame capture and meta data retrieval */ public native void setMode(int mode); /** * @return the current mode of operation. A negative return value indicates * some runtime error has occurred. */ public native int getMode(); /** * Sets the data source (file pathname) to use. Call this * method before the rest of the methods in this class. This method may be * time-consuming. * * @param path The path of the input media file. * @throws IllegalArgumentException If the path is invalid. */ public native void setDataSource(String path) throws IllegalArgumentException; /** * Sets the data source (FileDescriptor) to use. It is the caller's * responsibility to close the file descriptor. It is safe to do so as soon * as this call returns. Call this method before the rest of the methods in * this class. This method may be time-consuming. * * @param fd the FileDescriptor for the file you want to play * @param offset the offset into the file where the data to be played starts, * in bytes. It must be non-negative * @param length the length in bytes of the data to be played. It must be * non-negative. * @throws IllegalArgumentException if the arguments are invalid */ public native void setDataSource(FileDescriptor fd, long offset, long length) throws IllegalArgumentException; /** * Sets the data source (FileDescriptor) to use. It is the caller's * responsibility to close the file descriptor. It is safe to do so as soon * as this call returns. Call this method before the rest of the methods in * this class. This method may be time-consuming. * * @param fd the FileDescriptor for the file you want to play * @throws IllegalArgumentException if the FileDescriptor is invalid */ public void setDataSource(FileDescriptor fd) throws IllegalArgumentException { // intentionally less than LONG_MAX setDataSource(fd, 0, 0x7ffffffffffffffL); } /** * Sets the data source as a content Uri. Call this method before * the rest of the methods in this class. This method may be time-consuming. * * @param context the Context to use when resolving the Uri * @param uri the Content URI of the data you want to play * @throws IllegalArgumentException if the Uri is invalid * @throws SecurityException if the Uri cannot be used due to lack of * permission. */ public void setDataSource(Context context, Uri uri) throws IllegalArgumentException, SecurityException { if (uri == null) { throw new IllegalArgumentException(); } String scheme = uri.getScheme(); if(scheme == null || scheme.equals("file")) { setDataSource(uri.getPath()); return; } AssetFileDescriptor fd = null; try { ContentResolver resolver = context.getContentResolver(); try { fd = resolver.openAssetFileDescriptor(uri, "r"); } catch(FileNotFoundException e) { throw new IllegalArgumentException(); } if (fd == null) { throw new IllegalArgumentException(); } FileDescriptor descriptor = fd.getFileDescriptor(); if (!descriptor.valid()) { throw new IllegalArgumentException(); } // Note: using getDeclaredLength so that our behavior is the same // as previous versions when the content provider is returning // a full file. if (fd.getDeclaredLength() < 0) { setDataSource(descriptor); } else { setDataSource(descriptor, fd.getStartOffset(), fd.getDeclaredLength()); } return; } catch (SecurityException ex) { } finally { try { if (fd != null) { fd.close(); } } catch(IOException ioEx) { } } setDataSource(uri.toString()); } /** * Call this method after setDataSource(). This method retrieves the * meta data value associated with the keyCode. * * The keyCode currently supported is listed below as METADATA_XXX * constants. With any other value, it returns a null pointer. * * @param keyCode One of the constants listed below at the end of the class. * @return The meta data value associate with the given keyCode on success; * null on failure. */ public native String extractMetadata(int keyCode); /** * Call this method after setDataSource(). This method finds a * representative frame if successful and returns it as a bitmap. This is * useful for generating a thumbnail for an input media source. * * @return A Bitmap containing a representative video frame, which * can be null, if such a frame cannot be retrieved. */ public native Bitmap captureFrame(); /** * Call this method after setDataSource(). This method finds the optional * graphic or album art associated (embedded or external url linked) the * related data source. * * @return null if no such graphic is found. */ public native byte[] extractAlbumArt(); /** * Call it when one is done with the object. This method releases the memory * allocated internally. */ public native void release(); private native void native_setup(); private static native void native_init(); private native final void native_finalize(); @Override protected void finalize() throws Throwable { try { native_finalize(); } finally { super.finalize(); } } public static final int MODE_GET_METADATA_ONLY = 0x01; public static final int MODE_CAPTURE_FRAME_ONLY = 0x02; /* * Do not change these values without updating their counterparts * in include/media/mediametadataretriever.h! */ public static final int METADATA_KEY_CD_TRACK_NUMBER = 0; public static final int METADATA_KEY_ALBUM = 1; public static final int METADATA_KEY_ARTIST = 2; public static final int METADATA_KEY_AUTHOR = 3; public static final int METADATA_KEY_COMPOSER = 4; public static final int METADATA_KEY_DATE = 5; public static final int METADATA_KEY_GENRE = 6; public static final int METADATA_KEY_TITLE = 7; public static final int METADATA_KEY_YEAR = 8; public static final int METADATA_KEY_DURATION = 9; public static final int METADATA_KEY_NUM_TRACKS = 10; public static final int METADATA_KEY_IS_DRM_CRIPPLED = 11; public static final int METADATA_KEY_CODEC = 12; public static final int METADATA_KEY_RATING = 13; public static final int METADATA_KEY_COMMENT = 14; public static final int METADATA_KEY_COPYRIGHT = 15; public static final int METADATA_KEY_BIT_RATE = 16; public static final int METADATA_KEY_FRAME_RATE = 17; public static final int METADATA_KEY_VIDEO_FORMAT = 18; public static final int METADATA_KEY_VIDEO_HEIGHT = 19; public static final int METADATA_KEY_VIDEO_WIDTH = 20; public static final int METADATA_KEY_WRITER = 21; // Add more here... }
sumber
mHolder.addCallback(this);
melampirkan kelas Aktivitas untuk menangani kejadian permukaan. Mungkin IDE Anda tidak dapat mengenali panggilan ini, tetapi seharusnya dipanggil.Lihat Kode Pratinjau Kamera Contoh ini
CameraPreview
,. Ini akan membantu Anda dalam mengembangkan kode perekaman video untuk pratinjau video, membuatMediaRecorder
objek, dan mengatur parameter perekaman video.sumber
Untuk kepentingan pencari, contoh ini akan memberikan pratinjau aktif, dengan tombol start / stop untuk merekam. Itu dimodifikasi dari blog android ini dan tampaknya cukup dapat diandalkan.
kelas java (VideoWithSurfaceVw)
package <<your packagename here>>; import java.io.IOException; import java.text.SimpleDateFormat; import java.util.Date; import android.app.Activity; import android.content.Context; import android.hardware.Camera; import android.media.CamcorderProfile; import android.media.MediaRecorder; import android.os.Bundle; import android.view.SurfaceHolder; import android.view.SurfaceView; import android.view.View; import android.widget.Button; import android.widget.FrameLayout; import android.widget.Toast; public class VideoWithSurfaceVw extends Activity{ // Adapted from http://sandyandroidtutorials.blogspot.co.uk/2013/05/android-video-capture-tutorial.html private Camera myCamera; private MyCameraSurfaceView myCameraSurfaceView; private MediaRecorder mediaRecorder; Button myButton; SurfaceHolder surfaceHolder; boolean recording; /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); recording = false; setContentView(R.layout.activity_video_with_surface_vw); //Get Camera for preview myCamera = getCameraInstance(); if(myCamera == null){ Toast.makeText(VideoWithSurfaceVw.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 = (Button)findViewById(R.id.mybutton); myButton.setOnClickListener(myButtonOnClickListener); } Button.OnClickListener myButtonOnClickListener = new Button.OnClickListener(){ @Override public void onClick(View v) { // TODO Auto-generated method stub try{ if(recording){ // stop recording and release camera mediaRecorder.stop(); // stop the recording releaseMediaRecorder(); // release the MediaRecorder object //Exit after saved //finish(); myButton.setText("REC"); recording = false; }else{ //Release Camera before MediaRecorder start releaseCamera(); if(!prepareMediaRecorder()){ Toast.makeText(VideoWithSurfaceVw.this, "Fail in prepareMediaRecorder()!\n - Ended -", Toast.LENGTH_LONG).show(); finish(); } mediaRecorder.start(); recording = true; myButton.setText("STOP"); } }catch (Exception ex){ ex.printStackTrace(); } }}; private Camera getCameraInstance(){ // TODO Auto-generated method stub Camera c = null; try { c = Camera.open(); // attempt to get a Camera instance } catch (Exception e){ // Camera is not available (in use or does not exist) } return c; // returns null if camera is unavailable } private String getFileName_CustomFormat() { SimpleDateFormat sdfDate = new SimpleDateFormat("yyyy-MM-dd HH_mm_ss"); Date now = new Date(); String strDate = sdfDate.format(now); return strDate; } 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_HIGH)); mediaRecorder.setOutputFile("/sdcard/" + getFileName_CustomFormat() + ".mp4"); //mediaRecorder.setOutputFile("/sdcard/myvideo1.mp4"); mediaRecorder.setMaxDuration(60000); // Set max duration 60 sec. mediaRecorder.setMaxFileSize(50000000); // Set max file size 50M mediaRecorder.setPreviewDisplay(myCameraSurfaceView.getHolder().getSurface()); 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 } private void releaseMediaRecorder(){ if (mediaRecorder != null) { mediaRecorder.reset(); // clear recorder configuration mediaRecorder.release(); // release the recorder object mediaRecorder = new MediaRecorder(); myCamera.lock(); // lock camera for later use } } private void releaseCamera(){ if (myCamera != null){ myCamera.release(); // release the camera for other applications myCamera = null; } } public class MyCameraSurfaceView extends SurfaceView implements SurfaceHolder.Callback{ private SurfaceHolder mHolder; private Camera mCamera; public MyCameraSurfaceView(Context context, Camera camera) { super(context); mCamera = camera; // 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 { 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 } } }
aktivitas (activity_video_with_surface_vw)
<RelativeLayout android:id="@+id/surface_camera" xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent" android:layout_centerInParent="true" android:layout_weight="1" > <RelativeLayout android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent" > <FrameLayout android:id="@+id/videoview" android:layout_width="fill_parent" android:layout_height="fill_parent"/> <Button android:id="@+id/mybutton" android:layout_width="100dp" android:layout_height="50dp" android:layout_centerHorizontal="true" android:layout_alignParentBottom="true" android:text="REC" android:textSize="12dp"/> </RelativeLayout> </RelativeLayout>
sumber
Sebagai catatan tambahan - sepertinya ada bug di API Android atau dokumentasi yang salah atau mungkin saya hanya bodoh. Google docs dengan jelas menyatakan berikut ini:
Lihat: http://developer.android.com/guide/topics/media/camera.html
Tampaknya tidak demikian!
Setelah berjuang selama berhari-hari tanpa hasil dan banyak masalah kecil seperti "gagal untuk memulai" agak kesalahan, saya memutuskan untuk menerapkan penguncian dan BAM secara manual! semuanya bekerja dengan baik.
Saya menggunakan emulator genymotion untuk perangkat 4.1.1 dengan min sdk 14.
sumber
Contoh di atas akan berfungsi jika Anda menggunakan kamera belakang. Jika Anda menggunakan kamera depan, Anda harus menyesuaikan beberapa hal:
Pertama, Anda perlu menambahkan izin baru di manifes.
<uses-feature android:name="android.hardware.camera.front" android:required="false" />
Dalam
initRecorder
metode Anda , bukanCamcorderProfile cpHigh = CamcorderProfile .get(CamcorderProfile.QUALITY_HIGH); recorder.setProfile(cpHigh);
Anda perlu menggunakan:
CamcorderProfile profile = CamcorderProfile.get(Camera.CameraInfo.CAMERA_FACING_FRONT, CamcorderProfile.QUALITY_LOW); recorder.setProfile(profile);
karena
CamcorderProfile.QUALITY_HIGH
dikhususkan untuk kamera belakang.Anda juga harus menyetel ukuran video untuk mediarecorder seperti pada tampilan permukaan Anda.
Berikut adalah contoh lengkap perekaman video dari kamera depan dengan tampilan pratinjau kecil:
Android.manifest
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.RECORD_AUDIO" /> <uses-permission android:name="android.permission.CAMERA" /> <uses-feature android:name="android.hardware.camera" android:required="false" /> <uses-feature android:name="android.hardware.camera.front" android:required="false" />
activity_camera.xml
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context="CameraActivity"> <SurfaceView android:layout_width="200dp" android:layout_height="wrap_content" android:id="@+id/surfaceView"/> <Button android:layout_width="100dp" android:layout_height="100dp" android:text="REC" android:id="@+id/btnRecord" android:layout_alignParentBottom="true" android:layout_marginBottom="25dp" /> </RelativeLayout>
CameraActivity.java
public class SongVideoActivity extends BaseActivity implements SurfaceHolder.Callback { private int mCameraContainerWidth = 0; private SurfaceView mSurfaceView = null; private SurfaceHolder mSurfaceHolder = null; private Camera mCamera = null; private boolean mIsRecording = false; private int mPreviewHeight; private int mPreviewWidth; MediaRecorder mRecorder; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_song_video); Thread.setDefaultUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() { @Override public void uncaughtException(Thread thread, Throwable ex) { releaseMediaRecorder(); releaseCamera(); } }); mCamera = getCamera(); //camera preview mSurfaceView = (SurfaceView) findViewById(R.id.surfaceView); mSurfaceHolder = mSurfaceView.getHolder(); mSurfaceHolder.addCallback(this); // deprecated setting, but required on Android versions prior to 3.0 mSurfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS); mCameraContainerWidth = mSurfaceView.getLayoutParams().width; findViewById(R.id.btnRecord).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { if (mIsRecording) { stopRecording(); } else { // initialize video camera if (prepareVideoRecorder()) { // Camera is available and unlocked, MediaRecorder is prepared, // now you can start recording mRecorder.start(); // inform the user that recording has started Toast.makeText(getApplicationContext(), "Started recording", Toast.LENGTH_SHORT).show(); mIsRecording = true; } else { // prepare didn't work, release the camera releaseMediaRecorder(); // inform user } } } }); } private void stopRecording() { mRecorder.stop(); // stop the recording releaseMediaRecorder(); // release the MediaRecorder object mCamera.lock(); // take camera access back from MediaRecorder // inform the user that recording has stopped Toast.makeText(this, "Recording complete", Toast.LENGTH_SHORT).show(); mIsRecording = false; } @Override protected void onDestroy() { super.onDestroy(); releaseMediaRecorder(); // if you are using MediaRecorder, release it first releaseCamera(); // release the camera immediately on pause event } private Camera getCamera() { Camera.CameraInfo cameraInfo = new Camera.CameraInfo(); for (int camIdx = 0; camIdx < Camera.getNumberOfCameras(); camIdx++) { Camera.getCameraInfo(camIdx, cameraInfo); if (cameraInfo.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) { try { return mCamera = Camera.open(camIdx); } catch (RuntimeException e) { Log.e("cameras", "Camera failed to open: " + e.getLocalizedMessage()); } } } return null; } @Override protected void onPause() { super.onPause(); releaseMediaRecorder(); // if you are using MediaRecorder, release it first releaseCamera(); // release the camera immediately on pause event } private Camera.Size getBestPreviewSize(Camera.Parameters parameters) { Camera.Size result=null; for (Camera.Size size : parameters.getSupportedPreviewSizes()) { if(size.width < size.height) continue; //we are only interested in landscape variants if (result == null) { result = size; } else { int resultArea = result.width*result.height; int newArea = size.width*size.height; if (newArea > resultArea) { result = size; } } } return(result); } private boolean prepareVideoRecorder(){ mRecorder = new MediaRecorder(); // Step 1: Unlock and set camera to MediaRecorder mCamera.unlock(); mRecorder.setCamera(mCamera); // Step 2: Set sources mRecorder.setAudioSource(MediaRecorder.AudioSource.DEFAULT); mRecorder.setVideoSource(MediaRecorder.VideoSource.DEFAULT); //recorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP); // Step 3: Set a CamcorderProfile (requires API Level 8 or higher) // Customise your profile based on a pre-existing profile CamcorderProfile profile = CamcorderProfile.get(Camera.CameraInfo.CAMERA_FACING_FRONT, CamcorderProfile.QUALITY_LOW); mRecorder.setProfile(profile); // Step 4: Set output file mRecorder.setOutputFile(new File(getFilesDir(), "movie-" + UUID.randomUUID().toString()).getAbsolutePath()); //recorder.setMaxDuration(50000); // 50 seconds //recorder.setMaxFileSize(500000000); // Approximately 500 megabytes mRecorder.setVideoSize(mPreviewWidth, mPreviewHeight); // Step 5: Set the preview output mRecorder.setPreviewDisplay(mSurfaceHolder.getSurface()); // Step 6: Prepare configured MediaRecorder try { mRecorder.prepare(); } catch (IllegalStateException e) { Toast.makeText(getApplicationContext(), "exception: " + e.getMessage(), Toast.LENGTH_LONG).show(); releaseMediaRecorder(); return false; } catch (IOException e) { Toast.makeText(getApplicationContext(), "exception: " + e.getMessage(), Toast.LENGTH_LONG).show(); releaseMediaRecorder(); return false; } return true; } private void releaseMediaRecorder(){ if (mRecorder != null) { mRecorder.reset(); // clear recorder configuration mRecorder.release(); // release the recorder object mRecorder = null; mCamera.lock(); // lock camera for later use } } private void releaseCamera(){ if (mCamera != null){ mCamera.release(); // release the camera for other applications mCamera = null; } } @Override public void surfaceCreated(SurfaceHolder holder) { // The Surface has been created, now tell the camera where to draw the preview. Camera.Parameters parameters = mCamera.getParameters(); parameters.setRecordingHint(true); Camera.Size size = getBestPreviewSize(parameters); mCamera.setParameters(parameters); //resize the view to the specified surface view width in layout int newHeight = size.height / (size.width / mCameraContainerWidth); mSurfaceView.getLayoutParams().height = newHeight; } @Override public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { mPreviewHeight = mCamera.getParameters().getPreviewSize().height; mPreviewWidth = mCamera.getParameters().getPreviewSize().width; mCamera.stopPreview(); try { mCamera.setPreviewDisplay(mSurfaceHolder); } catch (IOException e) { e.printStackTrace(); } mCamera.startPreview(); } @Override public void surfaceDestroyed(SurfaceHolder holder) { if (mIsRecording) { stopRecording(); } releaseMediaRecorder(); releaseCamera(); } }
sumber
Mulai Desember 2017, telah ada beberapa pembaruan, misalnya penggunaan
android.hardware.Camera
sudah tidak digunakan lagi sekarang. Sementara yang lebih baruandroid.hardware.camera2
hadir dengan hal-hal praktis seperti aCameraManager
.Saya pribadi sangat menyukai contoh ini, yang memanfaatkan API saat ini dan bekerja dengan sangat baik: https://github.com/googlesamples/android-Camera2Video
Ini juga termasuk meminta pengguna untuk izin yang diperlukan di awal dan menampilkan pratinjau video sebelum memulai perekaman video.
(Selain itu, saya menemukan kodenya sangat indah (dan ini sangat jarang bagi saya ^^), tapi itu hanya pendapat subjektif saya.)
sumber
Alih-alih menulis kode dari sketsa, Anda dapat menggunakan perpustakaan di GitHub. Misalnya: https://github.com/CameraKit/camerakit-android (atau https://github.com/google/cameraview , atau https://github.com/hujiaweibujidao/CameraView dan sebagainya). Maka Anda hanya perlu:
private CameraKitView cameraKitView; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); cameraKitView = findViewById(R.id.camera); } @Override protected void onStart() { super.onStart(); cameraKitView.onStart(); } @Override protected void onResume() { super.onResume(); cameraKitView.onResume(); } @Override protected void onPause() { cameraKitView.onPause(); super.onPause(); } @Override protected void onStop() { cameraKitView.onStop(); super.onStop(); } @Override public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) { super.onRequestPermissionsResult(requestCode, permissions, grantResults); cameraKitView.onRequestPermissionsResult(requestCode, permissions, grantResults); }
sumber