2009-11-30 4 views

ответ

5

Вы записываете аудио и видео с использованием того же класса MediaRecorder. Это довольно просто. Вот example.

+0

Требуется немного больше работы для записи видео, поскольку вам приходится иметь дело с поверхностью предварительного просмотра. – vanevery

+1

В реализации мультимедиа в MediaRecorder есть тонкие ошибки, которые приводят к ошибкам сегментации по непредсказуемым причинам. Я подозреваю, поэтому @Vishnuparsad публиковал этот вопрос в первую очередь. – bobpoekert

+0

Тогда он должен был упомянуть об этом :) – Drakosha

3

Проверьте этот образец кода предварительного просмотра камеры, CameraPreview. Это поможет вам в разработке кода видеозаписи для предварительного просмотра видео, создайте объект MediaRecorder и установите параметры записи видео.

+0

ссылка is 404 error –

+2

Правильный URL: http://developer.android.com/resources/samples/ApiDemos/src/com/example/android/apis/graphics/CameraPreview. HTML. Возможно, это изменилось, так как piyshnp отправил свой ответ – Bilthon

+0

и снова: [Управление камерой] (http://developer.android.com/training/camera/cameradirect.html) –

148

Вот простой видео пример записи с помощью 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(); 
    } 
} 

Это из моей книги: Pro Android Media: Developing Graphics, Music, Video, and Rich Media Apps for Smartphones and Tablets

Кроме того, не забудьте включить эти разрешения в манифесте:

<uses-permission android:name="android.permission.RECORD_AUDIO" /> 
<uses-permission android:name="android.permission.CAMERA" /> 
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> 
+27

Это отличный пример. У меня возникли проблемы с его работой. Моя ошибка связана с размером вывода файла 0 байтов. Я начал отладку, и виновник оказался record.prepare(). Я не устанавливал новый выходной файл для рекордера, поэтому каждый раз, когда я касался экрана, я записывал свое существующее видео, чтобы остановить запись видео. Надеюсь, это поможет кому-то еще :-) Кстати, стоит упомянуть, что вам также нужно добавить разрешения RECORD_AUDIO, CAMERA и WRITE_EXTERNAL_STORAGE к вашему манифесту, чтобы этот образец кода работал. –

+0

'CamcorderProfile' Feature is Начиная с api level 8 и моего проекта. Начиная с версии 3 (1.5), вы можете сказать мне, что является альтернативой? –

+0

@Leffy У меня есть тот же пробный рейз, который я получил 0 бит, поэтому у меня есть remove prepare(), но это исключение, вы можете сказать мне, что я здесь делаю? –

42

Вот еще один пример, который работает

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> 

И, конечно, включать эти разрешения в манифесте:

<uses-permission android:name="android.permission.RECORD_AUDIO" /> 
<uses-permission android:name="android.permission.CAMERA" /> 
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> 
+0

Hi Проверьте это: http://stackoverflow.com/questions/10594553/android-could-not-connect-to-camera-error – Ponmalar

+0

Спасибо, пример vanevery хранит файл размером 0 байт, что не полезно – user609239

+0

Нажав на меню аппаратного обеспечения, будут показаны начальные и конечные записи. Но в планшетах Android нет аппаратного меню. В этом сценарии, как я могу начать и остановить захват видео.? – Karthick

5

Это демо будет полезна для вас ....

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> 

Ваш Основная деятельность: 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 

} 

} 

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... 
} 
+0

Привет. Я пытаюсь реализовать свой код в моем проекте, но функция surfaceCreated никогда не называется? – REJH

+0

@REJH, это называется, когда создается поверхность, потому что эта строка 'mHolder.addCallback (this);' attach Activity class для обработки поверхностных событий. Возможно, ваша IDE не сможет распознать этот вызов, но его нужно вызвать. –

0

Как примечание стороны - там, кажется, ошибка в Android API или неисправны или, может быть, я просто глуп. Документы Google ясно говорится следующее:

Note: Starting with Android 4.0 (API level 14), the Camera.lock() and Camera.unlock() calls are managed for you automatically.

См: http://developer.android.com/guide/topics/media/camera.html

Это, кажется, не будет так!

После битвы за буквальные дни без каких-либо успехов и многих небольших проблем, таких как «не удалось запустить», я решил вручную реализовать блокировку и БАМ! все работало нормально.

Im используя genymotion эмулятор для устройства 4.1.1 с мин SDK до 14

2

В пользу искателей, этот пример даст вам активный просмотр с кнопки пуска/остановки записи.Он был изменен с этого андроида blog и кажется довольно надежным.

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 

     } 
    } 
} 

активность (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> 
+0

Запуск проекта в Android Studio выдает следующее сообщение об ошибке в файле .xml: Ошибка: (29) Ошибка разбора XML: элемент не найден , где 29 является линией, соответствующей bergercookie

+0

@bergercookie - сделал вы находите/исправляете проблему? Я снял это с моего рабочего кода (используя Android Studio). Не стесняйтесь редактировать мой пост, если есть проблема. – HockeyJ

+1

@bergercookie - образец xml просто отсутствует закрывающий тег RelativeLayout. Я исправил форматирование, и теперь закрывающий тег отображается правильно – mjp66

1

Приведенный выше пример будет работать, если вы используете камеру заднего. Если вы используете переднюю камеру, вам придется отрегулировать некоторые вещи:

Прежде всего, вам нужно будет добавить новое разрешение в манифест.

<uses-feature android:name="android.hardware.camera.front" android:required="false" />

В вашем методе initRecorder вместо

CamcorderProfile cpHigh = CamcorderProfile 
       .get(CamcorderProfile.QUALITY_HIGH); 
recorder.setProfile(cpHigh); 

Вы должны использовать:

CamcorderProfile profile = CamcorderProfile.get(Camera.CameraInfo.CAMERA_FACING_FRONT, CamcorderProfile.QUALITY_LOW); 
recorder.setProfile(profile); 

потому CamcorderProfile.QUALITY_HIGH зарезервирован для камеры заднего вида.

Вам также необходимо установить размер видео для медиарекордера, так как он находится в вашем представлении на поверхности.

Вот полный пример записи видео с передней камеры с небольшим редв.просмотр:

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(); 
    } 
} 
+0

Это не работает. Он отключает мое приложение, отключив виртуальную машину. –

+0

Работает! но записанное видео перевернуто. Также, когда я пытаюсь сделать match_parent по ширине, предварительный просмотр не отображается. :/ – usman

+0

для полноэкранного просмотра, установленного ширины и высоты, как wrap_content. – usman

0

По состоянию на декабрь 2017 года, были некоторые обновления, например, использование android.hardware.Camera устарело. В то время как новый android.hardware.camera2 поставляется с удобными вещами, такими как CameraManager.

Я лично, как этот пример много, что делает использование этого текущего API и работает как шарм: https://github.com/googlesamples/android-Camera2Video

Он также включает в себя спрашивать у пользователя необходимых разрешений при запуске и функции предварительного просмотра видео перед началом запись видео.

(Кроме того, я нахожу код действительно красивое (и это очень редко для меня ^^), но это только мое субъективное мнение.)

 Смежные вопросы

  • Нет связанных вопросов^_^