OpenCV VideoCapture关闭了GoPro的视频

时间:2018-03-01 22:57:38

标签: python opencv ffmpeg

我有一个来自GoPro设备的视频文件,我只是使用这样的VideoCapture来处理它:

cap = cv2.VideoCapture(path)
        index = 0
        start = time.time()

        while cap.isOpened():
            ret, frame = cap.read()
            if not ret:
                break
            # do something here
        end = time.time()

这很奇怪,但我可以使用GoPro捕获的任何文件除外。流只是在某个时刻关闭,因为ret值变为Falseframe变为None。没有例外或其他任何事情。

谷歌搜索让我找到了this question。我用 ffmpeg 工具从文件中删除了音频流,然后一切正常。那么为什么会这样呢?请帮忙!

我使用的是Python 3.6.4 x64,Windows 10(但在Linux上相同)和来自this resource的OpenCV的预编译二进制文件。

4 个答案:

答案 0 :(得分:1)

我也遇到了这个问题,能够在不修剪音频的情况下解决它。实际上,我不相信音轨是问题所在。

我在这个问题上看到的所有ffmpeg转换命令都具有从视频文件中剥离所有元数据轨道的意外副作用。 GoPro实际上将许多原始传感器数据直接打包到MP4数据中。我认为这更可能是罪魁祸首,因为它是文件中存在的最少“标准”数据类型。

我通过使用以下命令剥离 just 音轨来测试了这一理论:

ffmpeg -i GH010001.MP4 -map 0 -map -0:a -c copy GH010001_MUTED.MP4

这个新的静音文件表现出相同的问题行为,因此简单地删除音轨是行不通的。

现在,如果您不关心元数据轨道,那么将其与其他ffmpeg调用剥离即可,完全可以!我实际上想使用该传感器,所以我不得不找到另一种解决方法。

解决方法

下面的代码在概念上很粗糙,但是可以工作。与其像通常使用OpenCV那样检查空帧,不如简单地计算我们知道应该存在的帧数,而跳过空帧。

auto expectedFrameCount = videoCapture.get(cv::CAP_PROP_FRAME_COUNT);
for(auto frameIndex = 0; frameIndex < expectedFrameCount; frameIndex++) {
  videoCapture >> frame;
  if(frame.empty()) {
    frameIndex--;
    continue;
  }
  // Do useful things with the frame here...
}

忽略文件末尾的通常标志肯定不正确,但是它可以正常工作,而且我能够播放原始视频文件的所有帧,而无需先进行任何ffmpeg转换。

答案 1 :(得分:0)

我和迈克尔有同样的问题,想要为人们添加ffmpeg输出。输出太长,无法添加到上面的编辑或评论。

MacBook-Pro:MacOS ben$ ffmpeg -i /Users/ben/Downloads/GP011399.MP4 ffmpeg version 3.3.4 Copyright (c) 2000-2017 the FFmpeg developers built with Apple LLVM version 8.1.0 (clang-802.0.42) configuration: --prefix=/usr/local/Cellar/ffmpeg/3.3.4 --enable-shared --enable-pthreads --enable-gpl --enable-version3 --enable-hardcoded-tables --enable-avresample --cc=clang --host-cflags= --host-ldflags= --enable-libmp3lame --enable-libx264 --enable-libxvid --enable-opencl --enable-videotoolbox --disable-lzma --enable-vda libavutil 55. 58.100 / 55. 58.100 libavcodec 57. 89.100 / 57. 89.100 libavformat 57. 71.100 / 57. 71.100 libavdevice 57. 6.100 / 57. 6.100 libavfilter 6. 82.100 / 6. 82.100 libavresample 3. 5. 0 / 3. 5. 0 libswscale 4. 6.100 / 4. 6.100 libswresample 2. 7.100 / 2. 7.100 libpostproc 54. 5.100 / 54. 5.100 Input #0, mov,mp4,m4a,3gp,3g2,mj2, from '/Users/ben/Downloads/GP011399.MP4': Metadata: major_brand : mp41 minor_version : 538120216 compatible_brands: mp41 creation_time : 2015-02-11T13:46:48.000000Z firmware : HD4.01.02.00.00 Duration: 00:26:30.59, start: 0.000000, bitrate: 20127 kb/s Stream #0:0(eng): Video: h264 (High) (avc1 / 0x31637661), yuvj420p(pc, bt709), 1280x720 [SAR 1:1 DAR 16:9], 19979 kb/s, 29.97 fps, 29.97 tbr, 90k tbn, 59.94 tbc (default) Metadata: creation_time : 2015-02-11T13:46:48.000000Z handler_name : GoPro AVC encoder : GoPro AVC encoder Stream #0:1(eng): Audio: aac (LC) (mp4a / 0x6134706D), 48000 Hz, stereo, fltp, 128 kb/s (default) Metadata: creation_time : 2015-02-11T13:46:48.000000Z handler_name : GoPro AAC Stream #0:2(eng): Data: none (tmcd / 0x64636D74) (default) Metadata: creation_time : 2015-02-11T13:46:48.000000Z handler_name : GoPro TCD timecode : 13:46:07:17 Stream #0:3(eng): Data: none (fdsc / 0x63736466), 9 kb/s (default) Metadata: creation_time : 2015-02-11T13:46:48.000000Z handler_name : GoPro SOS

可能与此有关吗?

OpenCV and GoPro - empty frames in VideoCapture stream

视频在VLC中播放时没有错误或明显损坏。相同的代码会打开我遇到过的所有其他视频文件(我已经使用此代码至少一年了。)

Opencv和Python版

2.7.10 (default, Feb 7 2017, 00:08:15) [GCC 4.2.1 Compatible Apple LLVM 8.0.0 (clang-800.0.34)] Python Type "help", "copyright", "credits" or "license" for more information. import cv2 cv2.__version__ '3.3.0'

与提交的代码相同Q.我的流读取26帧,然后返回ret = False。

答案 2 :(得分:0)

您未列出相机型号。但是我对GoPro的x264文件有问题。但不是x265文件。尝试在相机中将压缩模式从兼容模式更改为HEVC。对于x264,我使用“ ffmpeg -i video.mp4 -sn -an -vcodec mpeg4 -q:v 0 output.mp4”解压缩该文件,但此后文件大了约4倍。

答案 3 :(得分:0)

使用 OpenCV 4.4.0 对此进行更新(参考 Matt Barulic 的回答): 使用 VideoCapture 抓取/接收方法,我们已经通过类似的变通方法解决了这个问题。这段代码是用 C++ 编写的,但假设这种方法在 Python 中同样适用:

frameOk = videoCapture.grab();
if (!frameOk) {
    if (framei > 0 && framei < 100) {
        frameOk = true;
    }
}
if (frameOk)
    videoCapture.retrieve(image);
...