4

I have a videofile from a GoPro device and I simply work with it from a VideoCapture like this:

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()

It is very weird, but I can operate with any files except ones, captured at the GoPro. Stream just closes at some point because ret value becomes False and frame becomes None. No exceptions or anything else.

Googling helped me to find this question. I have deleted audio streams from file with ffmpeg tool and then everything works just fine. So why it is like so? Pleas help!

I am using Python 3.6.4 x64, Windows 10 (however at Linux same) and precompiled binaries for OpenCV from this resource.

Michael
  • 1,170
  • 2
  • 14
  • 35
  • What's the file extension of the video? – Jello Mar 02 '18 at 02:01
  • @Jello It is MP4, but video from a Panasonic camera I have tried additionally is same extension and it works fine – Michael Mar 02 '18 at 08:27
  • I have found this problem as well. Just go pro. OSX built from homebrew. Here is the output of ffmpeg in "answer" below. – bw4sz Apr 10 '18 at 18:40

4 Answers4

5

I also ran into this issue and was able to get around it without trimming the audio. In fact, I'm not convinced the audio track is the problem.

All of the ffmpeg conversion commands I've seen around this issue have the unintended side effect of stripping all of the metadata tracks from the video file as well. GoPro's actually pack a lot of raw sensor data directly into the MP4 data. I think this is the more likely culprit as it's the least "standard" type of data present in the file.

I tested this theory by stripping just the audio track with the following command:

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

This new muted file exhibited the same problematic behavior, so simply deleting the audio track didn't work.

Now if you don't care about the metadata tracks, stripping them out with the other ffmpeg calls is totally fine! I actually want to use that sensor so I had to find another way around it.

The Workaround

The code below is pretty gross at a conceptual level, but it works. Rather than checking for an empty frame as we would normally do with OpenCV, we simply count through the number of frames we know are supposed to be there, skipping the empty ones as they come.

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...
}

It definitely doesn't feel right ignoring the usual flag for the end of the file, but it worked and I was able to play back all of the frames of the original video file without any ffmpeg conversion first.

Matt Barulic
  • 61
  • 1
  • 3
0

I have the same issue as Michael and wanted to add ffmpeg output for people to see. Output is too long to add to edit or comment above.

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

May be related to here?

OpenCV and GoPro - empty frames in VideoCapture stream

Video plays in VLC without error or obvious corruption. Same code opens every other video file i've encountered (i've been using this code for atleast a year).

Opencv and Python version

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'

Same code as submitted Q. My stream reads in 26 frames and then returns ret=False.

bw4sz
  • 2,237
  • 2
  • 29
  • 53
  • Sorry, I don't understand. Where/how did you get the video file from Michael when there is no link provided? How can I get it? – Mark Setchell Apr 10 '18 at 20:10
  • Perhaps I was hijacking his question. He never responded with enough info. I have the same problem with a gopro video, not the one he provided. My file is too large to share (4gb). I'll trying to cut it with ffmpeg while mantaining codec. – bw4sz Apr 10 '18 at 20:58
  • I guess 50-100 frames is enough... if it fails at 26 – Mark Setchell Apr 10 '18 at 21:01
  • 1
    I can provide a link for the file, but I don't think it is necessary. It seems all video from GoPro cams has this issue with OpenCV. As a workaround, I am using ffmpeg tool with subprocess in python to mute needed videos. `ffmpeg -i [input_file] -vcodec copy -an [output_file]` Let me know if someone also needs output data about file I am trying to process from ffmpeg. – Michael Apr 11 '18 at 08:05
  • So its the audio codec that's doing it? Pretty weird. – bw4sz Apr 13 '18 at 17:16
0

You don't list your camera model. But I've had issues with the x264 files from GoPro. But not the x265 files. Try changing compression mode from compatable to HEVC, in your camera. For x264, I uncompress it using "ffmpeg -i video.mp4 -sn -an -vcodec mpeg4 -q:v 0 output.mp4", but the files are about 4X larger afterwards.

0

To give an update on this using OpenCV 4.4.0 (referring to Matt Barulic's answer): Using VideoCapture grab/receive methods, we have solved this with a similar work-around. This code is in C++ but assume this approach would equally work in Python:

frameOk = videoCapture.grab();
if (!frameOk) {
    if (framei > 0 && framei < 100) {
        frameOk = true;
    }
}
if (frameOk)
    videoCapture.retrieve(image);
...
Yost777
  • 597
  • 1
  • 6
  • 19