How to efficiently set the duration of the first frame of an mp4 movie?

0

I have a self-coded app that utilizes the Camera2Video sample Google published on GitHub. Unfortunately, there seems to be an issue from Android 6 on upwards that causes recorded videos to be broken. According to an issue report on GitHub, the decoding time of the first frame is ginormous compared to a working video.

For my example file of 11s length, the symptoms are:

  • On the Android phone itself, the video player freezes at the first frame. The audio is playing, the playback stops after 11s. After pulling the slider back to the start, video and audio are played back in sync.
  • On Windows using different players (Groove, WMP, VLC), there either is no video at all or it also freezes at the first frame. Audio is always fine. The video length is shown as 11s. Some players stop at the end, some keep incrementing the playback time after the playback slider is at 100%.
  • In Google Chrome on Windows, the video length is shown as 3.5 hours. The audio plays during the first 11s. The video shows the first frame for almost all the time, then 11s from the end the video is playing.

The Google Chrome behaviour shows best what's going on: there's 11s of audio and 11s*30fps = 330 frames in the file. But the first frame is not 1/30s but about 3.5 hours long.

At first, I had tried various video repair tools to fix the mp4 file, but most didn't change anything or didn't find any issue to fix and wouldn't run in the first place.

After a bit of trial an error, I found a first working solution. I used ffmpeg with the setpts filter option: .\ffmpeg.exe -i "broken.mp4" -vf setpts=N/FRAME_RATE/TB "fixed.mp4". Afterwards, the fixed file runs fine (and is a lot smaller as well).

The problem with this approach is that it takes about as long to complete as the length of the video I want to fix. But the video I want to make with the app may be about an hour long in the future.

So I wonder, is there any possiblity to adjust the duration that the first frame is shown for? In theory, this should mean ffmpeg just needs to replace one integer and not have to deal with de- or encoding at all. Can it be done, and how?

LWChris

Posted 2018-06-21T17:04:17.310

Reputation: 143

I posted the ffmpeg solution in the issue's thread already. – LWChris – 2018-06-21T17:06:13.640

Answers

0

Since, based on your working solution, it looks like you are ok with conforming the output to a constant frame-rate, I'll suggest this quicker two step method. No re-encoding involved.

Extract raw stream:

ffmpeg.exe -i "broken.mp4" -c copy broken.h264

Remux:

ffmpeg.exe -i broken.h264 -i broken.mp4 -map 0 -map 1:a -c copy new.mp4

Gyan

Posted 2018-06-21T17:04:17.310

Reputation: 21 016

It's right that I don't mind setting the video to fixed FPS as long as it stays relatively in sync with audio (< 100ms). Your method works, but ffmpeg output says: "Timestamps are unset in a packet for stream 0. This is deprecated and will stop working in the future. Fix your code to set the timestamps properly" – LWChris – 2018-06-21T23:51:14.153

Yes, my method relies on timestamps being unset. That message has been around for years, and no one's working on a patch to change that. If we do, I'll update the answer. – Gyan – 2018-06-22T05:02:38.823

Hm, the output is not quite right yet. First, it's rotated. I fixed that with -metadata:s:v rotate="-90". Second, the frame rate is only 25fps while the original has 30fps. That means there's too many frames in the video steam, causing the video to lag behind the audio over time. I tried -r 30 in both steps at various places but it doesn't seem to work. – LWChris – 2018-06-22T21:48:28.263

Sounds like you've an older version of ffmpeg; newer versions should read broken.h264 framerate. Anyway, you can add -r 30 before -i broken.h264 in the 2nd command. – Gyan – 2018-06-23T04:55:59.313