Как передавать поток видеокамеры по сети, создавая действительный видеофайл, используя Android?

Я пытаюсь записать записи видеокамеры в сетевой поток, см. следующий фрагмент:

ParcelFileDescriptor fd = ParcelFileDescriptor.fromSocket(socket);
this.camera.lock(); // this.camera refers to an android.hardware.Camera instance.
this.camera.unlock();
this.mediaRecorder = new MediaRecorder();
this.mediaRecorder.setCamera(this.camera);
this.mediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
this.mediaRecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA);
this.mediaRecorder.setProfile(CamcorderProfile.get(0, CamcorderProfile.QUALITY_HIGH));
this.mediaRecorder.setOutputFile(fd.getFileDescriptor());
this.mediaRecorder.prepare();
this.mediaRecorder.start();

Затем я пытаюсь перехватить его на другой стороне соединения: с помощью Socket.getInputStream() я читаю байты, и да, байты приходят. Байты записываются на самом деле по сети.

Но когда вы пытаетесь сохранить его в файл с помощью класса FileOutputStream и открыть файл с помощью VLC, он просто не может быть прочитан.

Как я могу в конечном итоге сделать файл «воспроизводимым», что означает, что это действительный видеофайл?

Редактировать:

Когда я использую this.mediaRecorder.setOutputFile("/sdcard/out.mp4");, я могу открыть видеофайл из Android, и он будет успешно воспроизводиться. Однако, когда я использую this.mediaRecorder.setOutputFile(fd.getFileDescriptor());, этого не произойдет.


person MC Emperor    schedule 03.05.2014    source источник
comment
Я не знаю, что это возможно. Вам нужно будет использовать необработанный кодек или поток с возможностью поиска. Сокет не доступен для поиска, и я не знаю, поддерживает ли MediaRecorder необработанный кодек.   -  person CommonsWare    schedule 07.05.2014
comment
Но если байты, которые записываются на SD-карту, вместо этого передаются через сокет, то это должно работать, не так ли?   -  person MC Emperor    schedule 07.05.2014
comment
Нет, потому что сокет не доступен для поиска, и поэтому MediaRecorder не может вернуться к началу, чтобы исправить заголовок файла с результатами записи. Тот факт, что байты были записаны в файл кем-то другим, не имеет значения.   -  person CommonsWare    schedule 07.05.2014
comment
@CommonsWare Верно, значит, мне нужно использовать формат потокового видео? Я думал, что MP4 можно транслировать?   -  person MC Emperor    schedule 08.05.2014
comment
MP4 доступен для воспроизведения. Я не знаю, что MP4 можно транслировать для записи.   -  person CommonsWare    schedule 08.05.2014


Ответы (1)


Проблема может быть связана с тем, что вы не все настраиваете в профиле видеокамеры.

Вместо этого:

this.mediaRecorder.setProfile(CamcorderProfile.get(0, CamcorderProfile.QUALITY_HIGH));

попробуйте, например, это:

CamcorderProfile profile = CamcorderProfile.get(CamcorderProfile.QUALITY_HIGH);
profile.fileFormat = MediaRecorder.OutputFormat.MPEG_4;
profile.videoCodec = MediaRecorder.VideoEncoder.MPEG_4_SP;
this.mediaRecorder.setProfile(profile);

Кстати, вы пытаетесь передать это видео после того, как закончите его записывать, или в режиме реального времени, получая данные с вашей видеокамеры?

РЕДАКТИРОВАТЬ:

Если я правильно помню, формат файла mpeg4 не имеет нижнего колонтитула, поэтому не должно быть необходимости «ждать весь файл» ... НО: этот тип файла имеет структуру, которую вы не можете сломать, если хотите его прочитать. Поэтому может возникнуть проблема, если вы отправляете необработанные байты видео, подготовленного в формате файла mpeg4, и хотите открыть файл после того, как получили случайное количество этих байтов. Вы можете быть почти уверены, что вам не посчастливится получить нужное количество байтов вашего видео.

Я бы посоветовал вам сделать следующее:

  1. Проверь это. Например: отправить какое-то видео на другую сторону и использовать какое-то программное обеспечение, позволяющее проверить структуру файла. Возможно, один из них подскажет, правильная ли структура у вашего файла. Я могу попытаться связать некоторые инструменты, но я сам не пробовал ни один из них, поэтому, возможно, вам придется поискать что-то еще (если ни один из них не работает достаточно хорошо). Вы можете попробовать, например, это или что.

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

  3. Альтернативой может быть попытка отправки каких-то «сырых» видеокадров. И под «сырыми» я подразумеваю какие-то низкоуровневые данные с камеры, которые вы можете отправить и применить определенный кодек на принимающей стороне. Я никогда не пытался это сделать, поэтому вам может понадобиться проверить, возможно ли это вообще (чтобы получить этот тип данных).

person Bartek Lipinski    schedule 05.05.2014
comment
Я пытаюсь передать байты в режиме реального времени. - person MC Emperor; 05.05.2014
comment
Я хотел написать больше символов, которые вы можете поместить в комментарий, поэтому я отредактировал свой первоначальный ответ. Не стесняйтесь проверить это. - person Bartek Lipinski; 11.05.2014