Webm-объекты MediaRecorder создают испорченное видео - PullRequest
4 голосов
/ 26 апреля 2020

Я пытаюсь передать webm Blob s (в кодировке Base64 и сгенерирован MediaRecorder) на мой сервер Phoenix через WS, где я Base64-декодирую их и добавляю в файл. В итоге получается неполноценное веб-видео. Я вижу первый кадр, когда открываю его в плеере, но оно несколько пиксельное, цвета отключены и т. Д. c. Длина видео не существует, и когда я пытаюсь диагностировать ошибки с помощью ffmpeg, он говорит:

[h264 @ 0x7fcbd3804200] decode_slice_header error
[h264 @ 0x7fcbd3804200] no frame!
[h264 @ 0x7fcbd3804200] non-existing PPS 0 referenced
(repeated many times)

Я не уверен, где я делаю ошибку (или если я сделав один), вот мой короткий код на стороне клиента:

const mediaStream = await navigator.mediaDevices.getUserMedia({ audio:true, video: true });
const options = {
  audioBitsPerSecond: 128000,
  videoBitsPerSecond: 2500000,
  mimeType: 'video/webm'
}
const mediaRecorder = new MediaRecorder(mediaStream,options);
mediaRecorder.ondataavailable = ((e) => {
  var reader = new window.FileReader();
  reader.readAsDataURL(e.data);
  reader.onloadend = (() => {
    base64data = reader.result;
    topic.push('video_feed', {data: base64data});
  })
})
mediaRecorder.start(1500);

Мой бэкэнд-код Elixir, отвечающий за декодирование файла IO и Base64:

{:ok, io} = File.open("some_file.webm", [:binary, :append]) # This part is triggered once
# Everything below is triggered upon receiving a blob (feed is the base64data object from 
# clientside code above)
"data:video/x-matroska;codecs=avc1,opus;base64," <> base64_bit = feed
decode_res = Base.decode64(base64_bit)
case decode_res do
  :error -> some_error_handling_code
  {:ok, data} -> io |> IO.binwrite(data)
end
{:noreply, state}

Я как-то испортил файл ввода-вывода ? Я подозреваю, что мне почему-то не хватает некоторых заголовков или файловых метаданных, которые требуются медиаплеерам.

1 Ответ

3 голосов
/ 01 мая 2020

Хорошо, после 2 дней копания и отладки файлов webm я понял, что это проблема на стороне клиента (связанная с кодом).

Возникло состояние гонки, когда я закрывал сокет на стороне клиента сразу после вызова mediaRecorder.stop(). Это была ошибка, так как я забыл, что в этом случае всегда генерируется конечное событие с остатком данных (фрагмент между временем последнего излучения и временем остановки рекордера). Это событие никогда не отправлялось, так как я немедленно закрыл вкладку программно (мудро, я знаю), поэтому мое видео было искажено. У меня были другие проблемы, связанные с кодом, но не такие большие.

Убедитесь, что вы получили это последнее событие, что-то вроде:

topic.push('feed', {data: base64data})
  .receive('ok', () => {
    // MR state will become inactive as soon as you call .stop() method
    if (mediaRecorder.state === 'inactive') {
      x.push('that_was_the_final_chunk_go_wild', {}).receive('ok' => {
        nowWeCanSurelySafelyTerminate();
      })
    }
  })
}
...