使用签名 url 将大型视频上传到 GCS,但视频已损坏

Upload large video to GCS use signed url but video is broken

我有一个 Google App Engine(GAE) 的应用程序,在前端使用 Vue.js,在后端使用 Flask。 我的应用程序允许用户上传 large 视频并对其进行分析。但是由于GAE的上传大小限制是32MB,所以我允许用户使用signed url直接上传到Google Cloud Storage(GCS).

我遇到的问题是用户可以成功上传视频到GCS,但是在后台(flask)下载视频分析时,出现如下错误:

*** OSError: MoviePy error: failed to read the duration of file /tmp/source_video.mp4.
Here are the file infos returned by ffmpeg:

ffmpeg version 4.2.2-static https://johnvansickle.com/ffmpeg/  Copyright (c) 2000-2019 the FFmpeg developers
  built with gcc 8 (Debian 8.3.0-6)
  configuration: --enable-gpl --enable-version3 --enable-static --disable-debug --disable-ffplay --disable-indev=sndio --disable-outdev=sndio --cc=gcc --enable-fontconfig --enable-frei0r --enable-gnutls --enable-gmp --enable-libgme --enable-gray --enable-libaom --enable-libfribidi --enable-libass --enable-libvmaf --enable-libfreetype --enable-libmp3lame --enable-libopencore-amrnb --enable-libopencore-amrwb --enable-libopenjpeg --enable-librubberband --enable-libsoxr --enable-libspeex --enable-libsrt --enable-libvorbis --enable-libopus --enable-libtheora --enable-libvidstab --enable-libvo-amrwbenc --enable-libvpx --enable-libwebp --enable-libx264 --enable-libx265 --enable-libxml2 --enable-libdav1d --enable-libxvid --enable-libzvbi --enable-libzimg
  libavutil      56. 31.100 / 56. 31.100
  libavcodec     58. 54.100 / 58. 54.100
  libavformat    58. 29.100 / 58. 29.100
  libavdevice    58.  8.100 / 58.  8.100
  libavfilter     7. 57.100 /  7. 57.100
  libswscale      5.  5.100 /  5.  5.100
  libswresample   3.  5.100 /  3.  5.100
  libpostproc    55.  5.100 / 55.  5.100
[mov,mp4,m4a,3gp,3g2,mj2 @ 0x7444500] Format mov,mp4,m4a,3gp,3g2,mj2 detected only with low score of 1, misdetection possible!
[mov,mp4,m4a,3gp,3g2,mj2 @ 0x7444500] moov atom not found
/tmp/source_video.mp4: Invalid data found when processing input

Flask代码下载:

class Analyser:
    def __init__(self):
        self.gcs_bucket = 'bucket_name'
        self.gcs_blob_video = 'videos/'

    def __storage_bucket(self):
        client = storage.Client()
        bucket = client.get_bucket(self.gcs_bucket)
        bucket.cors = [
            {
                "origin": ["*"],
                "responseHeader": [
                    "Access-Control-Allow-Origin"
                ],
                "method": ['PUT', 'POST', 'GET'],
                "maxAgeSeconds": 3600
            }
        ]
        bucket.patch()
        return bucket

    def __generate_upload_signed_url(self, bucket, blob):
        blob = bucket.blob(blob)
        return blob.generate_signed_url(
            version='v4',
            expiration=datetime.timedelta(minutes=15),
            method='PUT',
        )
   
    def analyze_video(self, pid):
        src_filepath = '/tmp/source_video.mp4'

        bucket = self.__storage_bucket()
        blob = bucket.blob(self.gcs_blob_video + 'filename.mp4')
        blob.download_to_filename(src_filepath)

        #error is here
        video = VideoFileClip(src_filepath)

Vuejs代码上传:

注意:上传成功,gcs上有文件要上传

async uploadVideo(_: any, video: File): Promise<string> {
      signed_url = "https://storage.googleapis.com/bucket_name...." #signed url is return from flask
      const formData = new FormData();
      formData.append('file', video);
      const response_upload_file = await fetch(
        signed_url,
        {
          method: 'PUT',
          body: formData
        }
      )
      return true
}

我在 google 上搜索了很多,但仍然没有找到解决方案。

真不知道是上传的时候坏了还是下载分析的时候坏了。 如果有人可以建议我解决这个问题的解决方案,我将不胜感激。

感谢阅读。

您正在将 formData 与 HTTP PUT 方法一起使用,这会破坏上传,因为预期是二进制数据流,而不是 MIME 数据。

要使用表单数据:

Upload an object with HTML forms