Загрузите видео и сохраните первый кадр как изображение JS - PullRequest
0 голосов
/ 06 августа 2020

У меня есть веб-страница, на которой пользователь перетаскивает видеофайл, а страница загружает видео и генерирует миниатюру на основе временной метки, предоставленной пользователем.

На данный момент я просто пытается создать миниатюру на основе ПЕРВОГО кадра видео.

вот краткий пример моего текущего прогресса:

(пожалуйста, используйте chrome, поскольку firefox будет пожаловаться на ссылку https, а также извините, если она автоматически загружает изображение) https://stackblitz.com/edit/rxjs-qc8iag

import { Observable, throwError } from 'rxjs'

const VIDEO = {
  imageFromFrame(videoSrc: any): Observable<any> {
    return new Observable<any>((obs) => {
      const canvas = document.createElement('canvas')
      const video = document.createElement('video')
      const context = canvas.getContext('2d')
      const source = document.createElement('source');

      source.setAttribute('src', videoSrc);

      video.appendChild(source);
      document.body.appendChild(canvas)
      document.body.appendChild(video)



      if (!context) {
        throwError(`Couldn't retrieve context 2d`)
        obs.complete()
        return
      }

      video.load()

      video.addEventListener('loadedmetadata', function () {
        console.log('loadedmetadata')
        // Set canvas dimensions same as video dimensions
        canvas.width = video.videoWidth
        canvas.height = video.videoHeight
      })

      video.addEventListener('canplay', function () {
        console.log('canplay')
        canvas.style.display = 'inline'
        context.drawImage(video, 0, 0, video.videoWidth, video.videoHeight)

        // Convert canvas image to Base64
        const img = canvas.toDataURL("image/png")
        // Convert Base64 image to binary
        obs.next(VIDEO.dataURItoBlob(img))
        obs.complete()
      })
    })
  },

  dataURItoBlob(dataURI: string): Blob {
    // convert base64/URLEncoded data component to raw binary data held in a string
    var byteString
    if (dataURI.split(',')[0].indexOf('base64') >= 0) byteString = atob(dataURI.split(',')[1])
    else byteString = unescape(dataURI.split(',')[1])
    // separate out the mime component
    var mimeString = dataURI.split(',')[0].split(':')[1].split(';')[0]
    // write the bytes of the string to a typed array
    var ia = new Uint8Array(byteString.length)
    for (var i = 0; i < byteString.length; i++) {
      ia[i] = byteString.charCodeAt(i)
    }
    return new Blob([ia], { type: mimeString })
  },
}

    VIDEO.imageFromFrame('https://www.learningcontainer.com/wp-content/uploads/2020/05/sample-mp4-file.mp4?_=1').subscribe((r) => {
      var a = document.createElement('a')
      document.body.appendChild(a)
      const url = window.URL.createObjectURL(r)
      a.href = url
      a.download = 'sdf'
      a.click()
      window.URL.revokeObjectURL(url)
    })

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

Я пытаюсь решить эту проблему, но если кто-то поможет мне выяснить проблему, спасибо.

1 Ответ

0 голосов
/ 06 августа 2020

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

  imageFromFrame(
    videoFile: File,
    options: { frameTimeInSeconds: number; filename?: string; fileType?: string } = {
      frameTimeInSeconds: 0.1,
    }
  ): Observable<File> {
    return new Observable<any>((obs) => {
      const canvas = document.createElement('canvas')
      const video = document.createElement('video')
      const source = document.createElement('source')
      const context = canvas.getContext('2d')
      const urlRef = URL.createObjectURL(videoFile)

      video.style.display = 'none'
      canvas.style.display = 'none'

      source.setAttribute('src', urlRef)
      video.setAttribute('crossorigin', 'anonymous')

      video.appendChild(source)
      document.body.appendChild(canvas)
      document.body.appendChild(video)

      if (!context) {
        throwError(`Couldn't retrieve context 2d`)
        obs.complete()
        return
      }

      video.currentTime = options.frameTimeInSeconds
      video.load()

      video.addEventListener('loadedmetadata', function () {
        canvas.width = video.videoWidth
        canvas.height = video.videoHeight
      })

      video.addEventListener('loadeddata', function () {
        context.drawImage(video, 0, 0, video.videoWidth, video.videoHeight)

        canvas.toBlob((blob) => {
          if (!blob) {
            return
          }
          obs.next(
            new File([blob], options.filename || FILES.getName(videoFile.name), {
              type: options.fileType || 'image/png',
            })
          )
          obs.complete()
          URL.revokeObjectURL(urlRef)

          video.remove()
          canvas.remove()
        }, options.fileType || 'image/png')
      })
    })
  },
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...