[JS] Grabar con camara desde web app

eXtreM3

Recurro a la sabiduría infinita mvidera: es posible hacer vía web una aplicación que empiece a grabar un vídeo con la cámara delantera del móvil y haya un botón para cambiar la cámara a la trasera y que el vídeo siga grabando por la trasera?

1 respuesta
Zoko

#1

Es posible si haces el truco que hacia snapchat en su dia. Grababan la pantalla en vez de grabar directamente usando la camara.
Osea que lo que mostrarias en pantalla seria lo que ve la camara y no el video que la camara produciria en si.

1 respuesta
eXtreM3

#2 correcto, hasta ahí bien. Lo que he conseguido hacer hasta ahora es elegir con qué cámara quieres empezar (ahí sale un desplegable con las cámaras disponibles), y cuando eliges inicio el stream y los trozos (chunks) grabados los paso a un canvas y luego eso es lo que guardo. Más o menos así:

navigator.mediaDevices.getUserMedia({
  audio: false,
  video: this.videoSettings
})
.then(stream => {
  const videoObj = document.getElementById('videoPreview')
  videoObj.srcObject = stream
  this.recordVideo(videoObj)
})

recordVideo (videoDOM) {
  this.startRecording(videoDOM.captureStream(), 60000)
  .then (recordedChunks => {
    let recordedBlob = new Blob(recordedChunks, this.videoOptions)
    this.uploadVideoBlob(recordedBlob) //aquí hago un axios y subo el video al servidor
    
}, false) .catch((error) => { console.log('error recordedChunks =>', error.response) }) }

El problema es que no tengo NI IDEA de cómo interactuar con el selector de cámara ni cómo cambiar entre trasera y delantera sin cortar el vídeo.

eXtreM3

Vale en teoría con esto https://codepen.io/apalshah/pen/XWdgPEw me debería servir si consigo agarrar los chunks y llamar a mi función record.

overflow

Hasta donde tengo entendido... si grabas "la pantalla" lo que grabas es la previsualización del video... algo que, al menos cuando lo tengo usado, ofrece una calidad mucho peor que lo que realmente graba la cámara. Esto lo tengo detectado cuando he trabajado con temas de OCR. Pero tampoco se si se puede hacer una previsualización 1:1 (por así decirlo).

1 respuesta
eXtreM3

#5 desde mi experiencia (que en estos temas es bastante poca) efectivamente la calidad es la que le digas al canvas del vídeo, en mi caso le tengo puesto { width: 1280, height: 720 } porque detecté que a más resolución el rendimiento caía en picado.

También lo utilizo para OCR.

Evidentemente lo ideal es desarrollar una app y poder utilizar las cámaras de manera nativa, pero en los requisitos de este proyecto en particular en el que estoy involucrado no es posible y hay que hacerlo vía web.

djamb

Pati to
https://www.digitalocean.com/community/tutorials/front-and-rear-camera-access-with-javascripts-getusermedia-es

1 1 respuesta
eXtreM3

#7 esa la vi ayer. El ejemplo del codepen a mí al menos no me funciona, y a vosotros? https://codepen.io/chrisbeast/pen/ebYwpX

eXtreM3

Actualizo. Que estoy haciendo esto a trompicones y creo que lo tengo ya casi casi, pero no sale. Mi prototipo es este, para ponernos en contexto:

Al pulsar alguno de los botones Front o Back, se activa la cámara correspondiente y entonces inicio el vídeo como indico en #3

Cuando startRecording termina, convierto los datos grabados en blob y este blob lo transformo a binarios con la función arrayBuffer:

recordedBlob.arrayBuffer().then(buffer => {
     this.partsArray.push(buffer)
})

Entonces, cuando grabo primero con una cámara y luego con otra, el resultado de esa variable es este:

Bien, las partes están agregadas en bruto. Ahora tengo que recorrer las partes y juntarlas cuando pulse el botón Download.

(en este punto, cada vez que cambio de cámara tengo una función que automáticamente me descarga el vídeo -los chunks- de dicha cámara, y se ve bien, tanto el frontal como el trasero)

El click del botón download me invoca esta función:

downloadFullVideo () {
  let mergedArrayBuffer = new Uint16Array()
  this.partsArray.forEach((part, i) => {
    console.log('each part', part, i, part.byteLength)

    var tmp = new Uint8Array(mergedArrayBuffer.byteLength + part.byteLength)
    tmp.set(new Uint8Array(mergedArrayBuffer), 0)
    tmp.set(new Uint8Array(part), mergedArrayBuffer.byteLength)
    mergedArrayBuffer = tmp
  })

  console.log('final merged', mergedArrayBuffer)
  let newblob = new Blob([mergedArrayBuffer], this.videoOptions)
  console.log('predownload', newblob)
  this.downloadFile(newblob)
}

El resultado de esos console log es este:

y el archivo descargado es este:

EL PROBLEMA

Al reproducir el vídeo solo aparece la parte que se haya grabado primero, a pesar de que el tamaño es la suma de los dos trozos y supuestamente se ha juntado y guardado bien :(

Usuarios habituales

  • eXtreM3
  • djamb
  • overflow
  • Zoko