экран становится черным после начала записи видео - приложение для Android

Я пытаюсь создать собственное приложение для записи видео и следил за учебным пособием в Интернете. Однако у меня возникает проблема, что экран становится черным после нажатия кнопки «Пуск», и больше ничего не происходит. После нажатия кнопки «Стоп» я проверил каталог, в который я помещал выходное видео. Он есть, но размер 0 КБ.

Я использовал представление поверхности, и вот макет xml:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
   android:orientation="vertical"
   android:layout_width="fill_parent"
   android:layout_height="fill_parent"
   >
<TextView 
   android:layout_width="fill_parent"
   android:layout_height="wrap_content"
   android:text="@string/hello"
   />
<Button
 android:id="@+id/start" 
   android:layout_width="fill_parent"
   android:layout_height="wrap_content"
   android:text="- Start Camera Preview -"
   />
<Button
 android:id="@+id/stop" 
   android:layout_width="fill_parent"
   android:layout_height="wrap_content"
   android:text="- Stop Camera Preview -"
   />
<SurfaceView
 android:id="@+id/surfaceview" 
   android:layout_width="fill_parent"
   android:layout_height="wrap_content"
   />
</LinearLayout>

А вот краткий код для записи видео:

public class CamTestActivity extends Activity implements SurfaceHolder.Callback{
    private static final String TAG = "Camera-Tutorial";

    private SurfaceView surfaceView;
    private SurfaceHolder surfaceHolder;
    private Camera camera;
    private boolean previewRunning;
    private int VIDEO_TYPE = 3;
    private int intVideoIndex = 1;

    private MediaRecorder mediaRecorder;
    private final int maxDurationInMs = 20000;
    private final int videoFramesPerSecond = 20;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        requestWindowFeature(Window.FEATURE_NO_TITLE);
        getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,WindowManager.LayoutParams.FLAG_FULLSCREEN);

        setContentView(R.layout.videopreview);

       // setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);

        surfaceView = (SurfaceView) findViewById(R.id.surfaceview);
        surfaceHolder = surfaceView.getHolder();
        surfaceHolder.addCallback(this);      
        Button start_video = (Button) findViewById(R.id.start);
        Button stop_video = (Button) findViewById(R.id.stop);


        stop_video.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                mediaRecorder.stop();
                camera.lock();
            }
        });

        start_video.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {

                try {
                    camera.unlock();                   
                    mediaRecorder = new MediaRecorder();
                    mediaRecorder.setCamera(camera);               
                    mediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
                    mediaRecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA);

                    mediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4);
                                                mediaRecorder.setOutputFile(GetOutputMediaFileDir(VIDEO_TYPE,intVideoIndex));
                   mediaRecorder.setVideoFrameRate(1);
                   mediaRecorder.setVideoEncoder(MediaRecorder.AudioEncoder.AAC);
                   mediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AAC);

                   mediaRecorder.prepare();
                    mediaRecorder.start();
                } catch (IllegalStateException e) {
                    Toast.makeText(getApplicationContext(), e.getMessage(), Toast.LENGTH_LONG).show();
                  //  Log.e(TAG,e.getMessage());
                 //   e.printStackTrace();

                } catch (IOException e) {
                    Log.e(TAG,e.getMessage());
                  //  e.printStackTrace();
                }
            }
        });
    }

    @Override
    public void surfaceCreated(SurfaceHolder holder) {
        camera = Camera.open();
        if (camera != null){
            Camera.Parameters params = camera.getParameters();
            camera.setParameters(params);
        }
        else {
            Toast.makeText(getApplicationContext(), "Camera not available!", Toast.LENGTH_LONG).show();
            finish();
        }
    }

    @Override
    public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
        if (previewRunning){
            camera.stopPreview();
        }
        Camera.Parameters p = camera.getParameters();
        p.setPreviewSize(width, height);
        camera.setParameters(p);

        try {
            camera.setPreviewDisplay(holder);
            camera.startPreview();
            previewRunning = true;
        }
        catch (IOException e) {
            Log.e(TAG,e.getMessage());
            e.printStackTrace();
        }
    }

    @Override
    public void surfaceDestroyed(SurfaceHolder holder) {
        camera.stopPreview();
        previewRunning = false;
        camera.release();
    }
 public static String GetOutputMediaFileDir(int fileType, int index){

        String fileDir=null;

          String strIndex = Integer.toString(index);
          if(fileType == 1)
          {
        File mediaStorageDir = new File(Environment.getExternalStoragePublicDirectory(
                Environment.DIRECTORY_MUSIC), "Audio");

        if (! mediaStorageDir.exists()){
            if (! mediaStorageDir.mkdirs()){

                return null;
            }
        }

          fileDir = mediaStorageDir.getPath() + File.separator +
                  "AUDIO_"+ strIndex + ".mp4";
          }
          if(fileType == 2)
          {
              File mediaStorageDir = new File(Environment.getExternalStoragePublicDirectory(
                        Environment.DIRECTORY_PICTURES), "Image");

                if (! mediaStorageDir.exists()){
                    if (! mediaStorageDir.mkdirs()){

                        return null;
                    }
                }

                  fileDir = mediaStorageDir.getPath() + File.separator +
                          "IMAGE_"+ strIndex + ".jpeg"; 
          }

          if(fileType == 3)
          {
              File mediaStorageDir = new File(Environment.getExternalStoragePublicDirectory(
                        Environment.DIRECTORY_MOVIES), "Video");

                if (! mediaStorageDir.exists()){
                    if (! mediaStorageDir.mkdirs()){

                        return null;
                    }
                }

                  fileDir = mediaStorageDir.getPath() + File.separator +
                          "VIDEO_"+ strIndex + ".mp4"; 
          }


       return fileDir;

        }

}

Любые идеи о том, как решить проблему? Заранее большое спасибо.

Изменения, решающие проблему:

Во-первых, я установил видеокодер на аудиокодер, это нужно изменить;

Во-вторых, mediaRecorder.setPreviewDisplay(surfaceView.getHolder().getSurface()); нужно добавить передmediaRecorder.prepare()

Тогда работает исправно.


person Iam619    schedule 27.06.2012    source источник


Ответы (1)


Я столкнулся с этой проблемой на устройстве HTC Incredible, но она отлично работала на 8 других устройствах, на которых я ее тестировал. Вот пост, который «решил» эту проблему:

https://stackoverflow.com/a/9903357/1426565

Я сузил фактическое исправление до определенной строки:

recorder.setVideoSize(width, height);

Настройки частоты кадров/битрейта не имели значения в исправлении, и я не уверен, что использование значений по умолчанию для источников, выходного формата и кодировщиков что-то изменит, но если подумать, это вообще не должно влиять на это.

Это другие настройки, которые я использую с ним (убедитесь, что размер установлен перед любым кодировщиком):

    recorder.setAudioSource(MediaRecorder.AudioSource.MIC);
    recorder.setVideoSource(MediaRecorder.VideoSource.CAMERA);
    recorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);

    recorder.setAudioEncoder(MediaRecorder.AudioEncoder.DEFAULT);
    recorder.setVideoEncoder(MediaRecorder.VideoEncoder.H264);

    recorder.setPReviewDisplay(surfaceView.getHolder().getSurface())

Также обратите внимание, вчера при тестировании на ICS мы столкнулись с проблемой, из-за которой setFrameRate не поддерживался, а setVideoSize не поддерживался. Итак, в исправлении, которое я собираюсь попробовать, я просто собираюсь окружить setVideoSize блоком try/catch, удалить setFrameRate и надеяться на Бога, что это исправит. Если нет, мне, вероятно, придется просто исключить его на определенных устройствах.

person Cruceo    schedule 27.06.2012
comment
Большое спасибо за ответы! Я заметил, что я установил видеокодер на аудиокодер. Однако после того, как я изменил кодировщик на h264 и частоту кадров на 24, приложение вылетает после нажатия кнопки запуска. Однако, если я установил кодировщик на H263 и частоту кадров на 1, то экран зависнет после нажатия кнопки запуска, и больше ничего не произойдет. Видеовыход находится в каталоге, но все еще 0 КБ. Я совершенно сбит с толку этим. Любая помощь приветствуется. - person Iam619; 27.06.2012
comment
Я буквально все еще тестирую это, пока мы говорим, но я думаю, что нашел конкретную строку, которая решает нашу проблему: recorder.setVideoSize(getMaxSupportedVideoSize().width, getMaxSupportedVideoSize().height); абсолютно необходимо. Я удалил setVideoFrameRate (поскольку устройство все равно управляет им на основе света) и setVideoEncodingBitRate (поскольку это также настраивается устройством), и теперь он работает правильно на всех устройствах, на которых я его пытаюсь использовать. Если setVideoSize отсутствует, он не работает и дает нам проблему, с которой мы сталкиваемся. - person Cruceo; 27.06.2012
comment
Обновлен основной пост с дополнительной информацией - person Cruceo; 27.06.2012
comment
Большое спасибо! Я добавил строку recorder.setVideoSize и удалил setVideoFrameRate и setVideoEncodingBitRate. Теперь, после относительно долгого отклика на нажатие кнопки запуска, приложение не вылетает! И выходное видео, наконец, теперь не 0 КБ, а 1 КБ (хотя устройство сказало, что я не могу его воспроизвести по каким-то причинам)~(продолжение) - person Iam619; 27.06.2012
comment
(продолжение) Я должен упомянуть одну вещь: я заменил getMaxSupportedVideoSize().width и .height двумя целыми числами (640, 480), так как у меня нет этих двух методов. Одна проблема заключается в том, что экран кажется зависающим после долгого времени отклика на кнопку запуска, вы сталкивались с этим Cruceo? - person Iam619; 27.06.2012
comment
Это действительно интересно... Он останавливается сразу после запуска? А у вас есть журнал ошибок? 640x480 — это нормально (просто убедитесь, что размер предварительного просмотра вашей камеры тоже установлен, иначе вы получите прерывистое видео), но что касается зависания, я никогда не сталкивался с этим. Вы можете добавить это в конце перед prepare(): recorder.setPreviewDisplay(mPreview.getHolder().getSurface()); - person Cruceo; 27.06.2012
comment
Я тестировал программу на сумсунге (такой, как айпад), а не в эмуляторе. Если я запущу программу в эмуляторе, то она даст старт failed logcat, может потому, что я не подключил камеру к компьютеру. - person Iam619; 27.06.2012
comment
Спасибо большое Круцео! Я добавил setPReviewDisplay(surfaceView.getHolder().getSurface()) перед подготовкой, и теперь он может работать правильно! Давно боролся с этой проблемой и наконец решился.... - person Iam619; 27.06.2012
comment
Очень рад, что смог помочь! Я добавил setPreviewDisplay к основному ответу - (И я бы принял ответ, чтобы у вас было больше шансов получить помощь в будущем, поскольку люди в сообществе SO, похоже, сильно не одобряют пользователей, не принимающих ответы (узнал об этом из опыта)) :П - person Cruceo; 27.06.2012
comment
да, я принял ответ. Я только сейчас искал, как принимать ответы: P Оказалось, что нужно нажать на галочку рядом с ответом ~ - person Iam619; 27.06.2012