Это отличный пример. У меня были некоторые проблемы, заставляя это работать сначала. Моя ошибка была связана с размером файла 0 байтов. Я начал отладку, и виновник оказался record.prepare (). Я не устанавливал новый выходной файл для рекордера, поэтому он перезаписывал существующее видео каждый раз, когда я касался экрана, чтобы остановить запись. Надеюсь, что это поможет кому-то еще :-) Кстати, стоит упомянуть, что вам также нужно добавить разрешения RECORD_AUDIO, CAMERA и WRITE_EXTERNAL_STORAGE в ваш манифест, чтобы этот пример кода работал.
ПРЕДУПРЕЖДЕНИЕ! Если вы будете использовать этот пример, не забудьте удалить метод finish () из уничтожения поверхности! Это закрывает вам возможность вернуться к этому занятию из других занятий. Я потерял там более 2 часов)
Divers
3
@vanevery большая проблема этого кода в том, что он создает два файла, один - хорошая запись, другой - создает, когда мы готовим рекордер. Есть ли способ удалить этот файл, если мы его не записываем ...
Swap-IOS - Android
46
Вот еще один пример, который работает
publicclassEnregistrementVideoStackActivityextendsActivityimplementsSurfaceHolder.Callback{privateSurfaceHolder surfaceHolder;privateSurfaceView surfaceView;publicMediaRecorder mrec =newMediaRecorder();privateButton startRecording =null;File video;privateCamera mCamera;@Overridepublicvoid 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);}@Overridepublicboolean onCreateOptionsMenu(Menu menu){
menu.add(0,0,0,"StartRecording");
menu.add(0,1,0,"StopRecording");returnsuper.onCreateOptionsMenu(menu);}@Overridepublicboolean onOptionsItemSelected(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);}protectedvoid startRecording()throwsIOException{
mrec =newMediaRecorder();// 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();}protectedvoid stopRecording(){
mrec.stop();
mrec.release();
mCamera.release();}privatevoid releaseMediaRecorder(){if(mrec !=null){
mrec.reset();// clear recorder configuration
mrec.release();// release the recorder object
mrec =null;
mCamera.lock();// lock camera for later use}}privatevoid releaseCamera(){if(mCamera !=null){
mCamera.release();// release the camera for other applications
mCamera =null;}}@Overridepublicvoid surfaceChanged(SurfaceHolder holder,int format,int width,int height){}@Overridepublicvoid surfaceCreated(SurfaceHolder holder){if(mCamera !=null){Parametersparams= mCamera.getParameters();
mCamera.setParameters(params);}else{Toast.makeText(getApplicationContext(),"Camera not available!",Toast.LENGTH_LONG).show();
finish();}}@Overridepublicvoid surfaceDestroyed(SurfaceHolder holder){
mCamera.stopPreview();
mCamera.release();}}
Спасибо, пример vanevery хранит файл размером 0 байт, что бесполезно
user609239
При нажатии на аппаратное меню, будет показана запись начала и остановки. Но в планшетах Android нет аппаратного меню. В этом случае, как я могу начать и остановить захват видео.?
Картик
Некоторые настройки для компиляции примера, но это прекрасно сработало для меня. Спасибо!
Гоферхан
@Milos Можете ли вы сказать мне, как встроить изображение маркера в видео на поверхности?
Ахмад Арслан
5
Вы записываете аудио и видео, используя один и тот же класс MediaRecorder. Это довольно просто. Вот пример .
В реализации видео в MediaRecorder есть тонкие ошибки, которые приводят к ошибкам сегментации по непредсказуемым причинам. Я подозреваю, что именно поэтому @Vishnuparsad размещал этот вопрос в первую очередь.
bobpoekert
Тогда он должен был упомянуть об этом :)
Дракоша
Для записи видео требуется немного больше работы, так как вам приходится иметь дело с поверхностью предварительного просмотра.
publicclassVideoextendsActivityimplementsOnClickListener,SurfaceHolder.Callback{privatestaticfinalString TAG ="CAMERA_TUTORIAL";privateSurfaceView mSurfaceView;privateSurfaceHolder mHolder;privateCamera mCamera;privateboolean previewRunning;privateMediaRecorder mMediaRecorder;privatefinalint maxDurationInMs =20000;privatefinallong maxFileSizeInBytes =500000;privatefinalint videoFramesPerSecond =20;Button btn_record;boolean mInitSuccesful =false;File file;ToggleButton mToggleButton;@Overridepublicvoid 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(newOnClickListener(){@Override// toggle video recordingpublicvoid onClick(View v){if(((ToggleButton) v).isChecked())
mMediaRecorder.start();else{
mMediaRecorder.stop();
mMediaRecorder.reset();try{
initRecorder(mHolder.getSurface());}catch(IOException e){
e.printStackTrace();}}}});}privatevoid initRecorder(Surface surface)throwsIOException{// 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 =newMediaRecorder();
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;}privateFile initFile(){// File dir = new// File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_MOVIES),// thisFile dir =newFile(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 =newFile(dir.getAbsolutePath(),newSimpleDateFormat("'IMG_'yyyyMMddHHmmss'.mp4'").format(newDate()));}return file;}@Overridepublicvoid surfaceCreated(SurfaceHolder holder){try{if(!mInitSuccesful)
initRecorder(mHolder.getSurface());}catch(IOException e){// TODO Auto-generated catch block
e.printStackTrace();}}privatevoid 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;}@Overridepublicvoid surfaceDestroyed(SurfaceHolder holder){
shutdown();}@Overridepublicvoid surfaceChanged(SurfaceHolder holder,int format,int width,int height){// TODO Auto-generated method stub}@Overridepublicvoid onClick(View v){// TODO Auto-generated method stub}}
MediaMetadataRetriever Class
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
*/publicnativevoid setMode(int mode);/**
* @return the current mode of operation. A negative return value indicates
* some runtime error has occurred.
*/publicnativeint 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.
*/publicnativevoid setDataSource(String path)throwsIllegalArgumentException;/**
* 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
*/publicnativevoid setDataSource(FileDescriptor fd,long offset,long length)throwsIllegalArgumentException;/**
* 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
*/publicvoid setDataSource(FileDescriptor fd)throwsIllegalArgumentException{// 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.
*/publicvoid setDataSource(Context context,Uri uri)throwsIllegalArgumentException,SecurityException{if(uri ==null){thrownewIllegalArgumentException();}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){thrownewIllegalArgumentException();}if(fd ==null){thrownewIllegalArgumentException();}FileDescriptor descriptor = fd.getFileDescriptor();if(!descriptor.valid()){thrownewIllegalArgumentException();}// 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.
*/publicnativeString 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.
*/publicnativeBitmap 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.
*/publicnativevoid release();privatenativevoid native_setup();privatestaticnativevoid native_init();privatenativefinalvoid native_finalize();@Overrideprotectedvoid finalize()throwsThrowable{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...}
Здравствуй. Я пытаюсь реализовать ваш код в моем проекте, но функция surfaceCreated никогда не вызывается?
REJH
@REJH, он вызывается при создании поверхности, потому что эта строка mHolder.addCallback(this);присоединяет класс Activity для обработки событий поверхности. Может быть, ваша IDE не может распознать этот вызов, но он должен быть вызван.
vp_arth
3
Проверьте этот пример кода предварительного просмотра камеры CameraPreview. Это поможет вам в разработке кода записи видео для предварительного просмотра видео, создания MediaRecorderобъекта и установки параметров записи видео.
Для искателей этот пример даст вам активный предварительный просмотр с кнопкой запуска / остановки для записи. Он был изменен с этого блога Android и кажется довольно надежным.
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.htmlprivateCamera myCamera;privateMyCameraSurfaceView myCameraSurfaceView;privateMediaRecorder mediaRecorder;Button myButton;SurfaceHolder surfaceHolder;boolean recording;/** Called when the activity is first created. */@Overridepublicvoid 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 =newMyCameraSurfaceView(this, myCamera);FrameLayout myCameraPreview =(FrameLayout)findViewById(R.id.videoview);
myCameraPreview.addView(myCameraSurfaceView);
myButton =(Button)findViewById(R.id.mybutton);
myButton.setOnClickListener(myButtonOnClickListener);}Button.OnClickListener myButtonOnClickListener
=newButton.OnClickListener(){@Overridepublicvoid onClick(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();}}};privateCamera getCameraInstance(){// TODO Auto-generated method stubCamera 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}privateString getFileName_CustomFormat(){SimpleDateFormat sdfDate =newSimpleDateFormat("yyyy-MM-dd HH_mm_ss");Date now =newDate();String strDate = sdfDate.format(now);return strDate;}privateboolean prepareMediaRecorder(){
myCamera = getCameraInstance();
mediaRecorder =newMediaRecorder();
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;}@Overrideprotectedvoid onPause(){super.onPause();
releaseMediaRecorder();// if you are using MediaRecorder, release it first
releaseCamera();// release the camera immediately on pause event}privatevoid releaseMediaRecorder(){if(mediaRecorder !=null){
mediaRecorder.reset();// clear recorder configuration
mediaRecorder.release();// release the recorder object
mediaRecorder =newMediaRecorder();
myCamera.lock();// lock camera for later use}}privatevoid releaseCamera(){if(myCamera !=null){
myCamera.release();// release the camera for other applications
myCamera =null;}}publicclassMyCameraSurfaceViewextendsSurfaceViewimplementsSurfaceHolder.Callback{privateSurfaceHolder mHolder;privateCamera 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);}@Overridepublicvoid 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 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){}}@Overridepublicvoid 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){}}@Overridepublicvoid surfaceDestroyed(SurfaceHolder holder){// TODO Auto-generated method stub}}}
При запуске проекта в Android Studio в XML-файле появляется следующее сообщение об ошибке: Ошибка: (29) Ошибка синтаксического анализа XML: не найден элемент, где 29 - строка, соответствующая </ RelativeLayout>
bergercookie
@bergercookie - вы нашли / устранили проблему? Я снял это с моего рабочего кода (используя Android Studio). Не стесняйтесь редактировать мой пост, если есть проблема.
HockeyJ
1
@bergercookie - в примере xml отсутствует закрывающий тег RelativeLayout. Я исправил форматирование, и теперь закрывающий тег отображается правильно
mjp66
1
В качестве дополнительного примечания - кажется, что в Android API или в ошибочной документации есть ошибка или, может быть, я просто глупый. Документы Google ясно заявляют следующее:
Примечание. Начиная с Android 4.0 (уровень API 14), вызовы Camera.lock () и Camera.unlock () управляются автоматически.
После битвы в течение буквальных дней без какого-либо успеха и многих небольших проблем, таких как «не удалось запустить», вроде ошибок, я решил вручную реализовать блокировку и BAM! все работало нормально.
Я использую эмулятор genymotion для устройства 4.1.1 с минимальной SDK 14.
Приведенный выше пример будет работать, если вы используете заднюю камеру. Если вы используете фронтальную камеру, вам придется отрегулировать некоторые вещи:
Прежде всего, вам нужно будет добавить новое разрешение в манифест.
publicclassSongVideoActivityextendsBaseActivityimplementsSurfaceHolder.Callback{privateint mCameraContainerWidth =0;privateSurfaceView mSurfaceView =null;privateSurfaceHolder mSurfaceHolder =null;privateCamera mCamera =null;privateboolean mIsRecording =false;privateint mPreviewHeight;privateint mPreviewWidth;MediaRecorder mRecorder;@Overrideprotectedvoid onCreate(Bundle savedInstanceState){super.onCreate(savedInstanceState);
setContentView(R.layout.activity_song_video);Thread.setDefaultUncaughtExceptionHandler(newThread.UncaughtExceptionHandler(){@Overridepublicvoid 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(newView.OnClickListener(){@Overridepublicvoid onClick(View v){if(mIsRecording){
stopRecording();}else{// initialize video cameraif(prepareVideoRecorder()){// Camera is available and unlocked, MediaRecorder is prepared,// now you can start recording
mRecorder.start();// inform the user that recording has startedToast.makeText(getApplicationContext(),"Started recording",Toast.LENGTH_SHORT).show();
mIsRecording =true;}else{// prepare didn't work, release the camera
releaseMediaRecorder();// inform user}}}});}privatevoid 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 stoppedToast.makeText(this,"Recording complete",Toast.LENGTH_SHORT).show();
mIsRecording =false;}@Overrideprotectedvoid onDestroy(){super.onDestroy();
releaseMediaRecorder();// if you are using MediaRecorder, release it first
releaseCamera();// release the camera immediately on pause event}privateCamera getCamera(){Camera.CameraInfo cameraInfo =newCamera.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());}}}returnnull;}@Overrideprotectedvoid onPause(){super.onPause();
releaseMediaRecorder();// if you are using MediaRecorder, release it first
releaseCamera();// release the camera immediately on pause event}privateCamera.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 variantsif(result ==null){
result = size;}else{int resultArea = result.width*result.height;int newArea = size.width*size.height;if(newArea > resultArea){
result = size;}}}return(result);}privateboolean prepareVideoRecorder(){
mRecorder =newMediaRecorder();// 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 profileCamcorderProfile profile =CamcorderProfile.get(Camera.CameraInfo.CAMERA_FACING_FRONT,CamcorderProfile.QUALITY_LOW);
mRecorder.setProfile(profile);// Step 4: Set output file
mRecorder.setOutputFile(newFile(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 MediaRecordertry{
mRecorder.prepare();}catch(IllegalStateException e){Toast.makeText(getApplicationContext(),"exception: "+ e.getMessage(),Toast.LENGTH_LONG).show();
releaseMediaRecorder();returnfalse;}catch(IOException e){Toast.makeText(getApplicationContext(),"exception: "+ e.getMessage(),Toast.LENGTH_LONG).show();
releaseMediaRecorder();returnfalse;}returntrue;}privatevoid releaseMediaRecorder(){if(mRecorder !=null){
mRecorder.reset();// clear recorder configuration
mRecorder.release();// release the recorder object
mRecorder =null;
mCamera.lock();// lock camera for later use}}privatevoid releaseCamera(){if(mCamera !=null){
mCamera.release();// release the camera for other applications
mCamera =null;}}@Overridepublicvoid 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 layoutint newHeight = size.height /(size.width / mCameraContainerWidth);
mSurfaceView.getLayoutParams().height = newHeight;}@Overridepublicvoid 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();}@Overridepublicvoid surfaceDestroyed(SurfaceHolder holder){if(mIsRecording){
stopRecording();}
releaseMediaRecorder();
releaseCamera();}}
Это не работает. Это вылетает из моего приложения, выключая виртуальную машину.
Pink Jazz
Работает! но записанное видео вверх ногами. Также, когда я пытаюсь сделать match_parent по ширине, предварительный просмотр не виден. : /
М. Усман Хан
для полноэкранного предварительного просмотра установите ширину и высоту как wrap_content.
М. Усман Хан
Как установить вариант ПОРТРЕТ?
Розина
1
По состоянию на декабрь 2017 года произошли некоторые обновления, например, использование android.hardware.Cameraне рекомендуется. В то время как новый android.hardware.camera2приходит с такими удобными вещами, как CameraManager.
Это также включает в себя запрос пользователя о необходимых разрешениях при запуске и функции предварительного просмотра видео перед началом записи видео.
(Кроме того, я нахожу код действительно красивым (и это очень редко для меня ^^), но это только мое субъективное мнение.)
@pookie Я думаю, что да, но забыл, так как прошло 1,5 года. На самом деле вы можете взглянуть на эти ссылки на репозитории GitHub, поскольку они будут иметь «быстрый старт», по которому вы можете следовать.
ch271828n
Отлично, спасибо :)
Пуки
@pookie Если вы считаете, что это полезно, пожалуйста, дайте оценку :)
Ответы:
Вот простой пример видеозаписи с использованием MediaRecorder:
Это из моей книги: Pro Android Media: разработка приложений для графики, музыки, видео и мультимедиа для смартфонов и планшетов.
Также не забудьте включить эти разрешения в манифест:
источник
Вот еще один пример, который работает
camera_surface.xml
И, конечно, включить эти разрешения в манифесте:
источник
Вы записываете аудио и видео, используя один и тот же класс MediaRecorder. Это довольно просто. Вот пример .
источник
Это демо будет полезно для вас ....
video.xml
Ваша основная деятельность: Video.java
MediaMetadataRetriever Class
источник
mHolder.addCallback(this);
присоединяет класс Activity для обработки событий поверхности. Может быть, ваша IDE не может распознать этот вызов, но он должен быть вызван.Проверьте этот пример кода предварительного просмотра камеры
CameraPreview
. Это поможет вам в разработке кода записи видео для предварительного просмотра видео, созданияMediaRecorder
объекта и установки параметров записи видео.источник
Для искателей этот пример даст вам активный предварительный просмотр с кнопкой запуска / остановки для записи. Он был изменен с этого блога Android и кажется довольно надежным.
Java-класс (VideoWithSurfaceVw)
активность (activity_video_with_surface_vw)
источник
В качестве дополнительного примечания - кажется, что в Android API или в ошибочной документации есть ошибка или, может быть, я просто глупый. Документы Google ясно заявляют следующее:
Смотрите: http://developer.android.com/guide/topics/media/camera.html
Это не похоже на случай!
После битвы в течение буквальных дней без какого-либо успеха и многих небольших проблем, таких как «не удалось запустить», вроде ошибок, я решил вручную реализовать блокировку и BAM! все работало нормально.
Я использую эмулятор genymotion для устройства 4.1.1 с минимальной SDK 14.
источник
Приведенный выше пример будет работать, если вы используете заднюю камеру. Если вы используете фронтальную камеру, вам придется отрегулировать некоторые вещи:
Прежде всего, вам нужно будет добавить новое разрешение в манифест.
<uses-feature android:name="android.hardware.camera.front" android:required="false" />
В вашем
initRecorder
методе вместоВам необходимо использовать:
потому что
CamcorderProfile.QUALITY_HIGH
зарезервировано для задней камеры.Вам также нужно будет установить размер видео для медиа-рекордера в том виде, в каком он есть на виде поверхности.
Вот полный пример записи видео с фронтальной камеры с небольшим предварительным просмотром:
Android.manifest
activity_camera.xml
CameraActivity.java
источник
По состоянию на декабрь 2017 года произошли некоторые обновления, например, использование
android.hardware.Camera
не рекомендуется. В то время как новыйandroid.hardware.camera2
приходит с такими удобными вещами, какCameraManager
.Мне лично очень нравится этот пример, который использует этот текущий API и работает как шарм: https://github.com/googlesamples/android-Camera2Video
Это также включает в себя запрос пользователя о необходимых разрешениях при запуске и функции предварительного просмотра видео перед началом записи видео.
(Кроме того, я нахожу код действительно красивым (и это очень редко для меня ^^), но это только мое субъективное мнение.)
источник
Вместо написания кода из эскиза вы можете использовать библиотеку на GitHub. Например: https://github.com/CameraKit/camerakit-android (или https://github.com/google/cameraview или https://github.com/hujiaweibujidao/CameraView и т. Д.). Тогда вам нужно только:
источник