Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added VFR Detection #3376

Merged

Conversation

JoeSmithStarkers
Copy link
Contributor

This PR adds variable frame rate detection and optimisation to allow preview videos to be generated in a sane amout of time.

Problem: Some webcam captures are encoded with VFR, which ffmpeg sees as ridiculously high frames like 90,000. (In stash these high frame rates are mappped to 0 fps when ffprobe probes the video file, don't know why). When generating a preview for these files: ffmpeg with the default vsync 1 option, will respect the original frame rate 90k fps, and thus try to encode .75s of 90k frames for each chunk of the preview. This takes a long time.

The soultion is to dynamicly add the "-vsync 2" option to the ffmpeg command line which says ignore the frame rate of the original and use the internal timebase. This drastically improves the performance of preview generation.

This pr is a request for comment. Happy to make any improvements required.

@bnkai
Copy link
Collaborator

bnkai commented Jan 27, 2023

Stash gets the frame_rate from ffprobe here

if strings.Contains(videoStream.AvgFrameRate, "/") {

It uses the avg_frame_rate field of the first video stream. For some files (older wmvs usually) this is 0/0 so the code above sets that to 0.
There was also a fallback to get the r_frame_rate field if the above was 0, but i am not sure where that is used (only when generating ?) atm.
@JoeSmithStarkers out of curiocity can you provide the output of one of those files with ffprobe -print_format json -show_format -show_streams filename.mp4 ? (redact filename/meta if needed)

@JoeSmithStarkers
Copy link
Contributor Author

JoeSmithStarkers commented Jan 28, 2023

@bnkai here you go.

I think these files might be created via vlc doing some sort network capture or screen capture, and only encoding frames when the a new frame is provided, streaming mjpeg.

I can provide a sample file if you want, i have 240 ish of them, probably a smallish one in there.

ffprobe version 5.1.1-static https://johnvansickle.com/ffmpeg/  Copyright (c) 2007-2022 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      57. 28.100 / 57. 28.100
  libavcodec     59. 37.100 / 59. 37.100
  libavformat    59. 27.100 / 59. 27.100
  libavdevice    59.  7.100 / 59.  7.100
  libavfilter     8. 44.100 /  8. 44.100
  libswscale      6.  7.100 /  6.  7.100
  libswresample   4.  7.100 /  4.  7.100
  libpostproc    56.  6.100 / 56.  6.100
{
Input #0, mpegts, from 'v_huge_fr.mp4':
  Duration: 00:10:15.45, start: 1.400000, bitrate: 1304 kb/s
  Program 1
    Metadata:
      service_name    : Service01
      service_provider: FFmpeg
  Stream #0:0[0x100]: Video: h264 (Constrained Baseline) ([27][0][0][0] / 0x001B), yuv420p(progressive), 648x360, 90k tbr, 90k tbn
  Stream #0:1[0x101]: Audio: aac (Main) ([15][0][0][0] / 0x000F), 48000 Hz, stereo, fltp, 130 kb/s
    "streams": [
        {
            "index": 0,
            "codec_name": "h264",
            "codec_long_name": "H.264 / AVC / MPEG-4 AVC / MPEG-4 part 10",
            "profile": "Constrained Baseline",
            "codec_type": "video",
            "codec_tag_string": "[27][0][0][0]",
            "codec_tag": "0x001b",
            "width": 648,
            "height": 360,
            "coded_width": 648,
            "coded_height": 360,
            "closed_captions": 0,
            "film_grain": 0,
            "has_b_frames": 0,
            "pix_fmt": "yuv420p",
            "level": 31,
            "chroma_location": "left",
            "field_order": "progressive",
            "refs": 1,
            "is_avc": "false",
            "nal_length_size": "0",
            "id": "0x100",
            "r_frame_rate": "90000/1",
            "avg_frame_rate": "0/0",
            "time_base": "1/90000",
            "start_pts": 126000,
            "start_time": "1.400000",
            "duration_ts": 55390501,
            "duration": "615.450011",
            "bits_per_raw_sample": "8",
            "extradata_size": 28,
            "disposition": {
                "default": 0,
                "dub": 0,
                "original": 0,
                "comment": 0,
                "lyrics": 0,
                "karaoke": 0,
                "forced": 0,
                "hearing_impaired": 0,
                "visual_impaired": 0,
                "clean_effects": 0,
                "attached_pic": 0,
                "timed_thumbnails": 0,
                "captions": 0,
                "descriptions": 0,
                "metadata": 0,
                "dependent": 0,
                "still_image": 0
            }
        },
        {
            "index": 1,
            "codec_name": "aac",
            "codec_long_name": "AAC (Advanced Audio Coding)",
            "profile": "Main",
            "codec_type": "audio",
            "codec_tag_string": "[15][0][0][0]",
            "codec_tag": "0x000f",
            "sample_fmt": "fltp",
            "sample_rate": "48000",
            "channels": 2,
            "channel_layout": "stereo",
            "bits_per_sample": 0,
            "id": "0x101",
            "r_frame_rate": "0/0",
            "avg_frame_rate": "0/0",
            "time_base": "1/90000",
            "start_pts": 128790,
            "start_time": "1.431000",
            "duration_ts": 55384313,
            "duration": "615.381256",
            "bit_rate": "130714",
            "disposition": {
                "default": 0,
                "dub": 0,
                "original": 0,
                "comment": 0,
                "lyrics": 0,
                "karaoke": 0,
                "forced": 0,
                "hearing_impaired": 0,
                "visual_impaired": 0,
                "clean_effects": 0,
                "attached_pic": 0,
                "timed_thumbnails": 0,
                "captions": 0,
                "descriptions": 0,
                "metadata": 0,
                "dependent": 0,
                "still_image": 0
            }
        }
    ],
    "format": {
        "filename": "v_huge_fr.mp4",
        "nb_streams": 2,
        "nb_programs": 1,
        "format_name": "mpegts",
        "format_long_name": "MPEG-TS (MPEG-2 Transport Stream)",
        "start_time": "1.400000",
        "duration": "615.450011",
        "size": "100384292",
        "bit_rate": "1304857",
        "probe_score": 50
    }
}```

@bnkai
Copy link
Collaborator

bnkai commented Feb 4, 2023

@JoeSmithStarkers thanks for the sample
It seems that those were ts files so the frame rates could indeed be off.

I couldnt replicate the issue as i dont have similar files, i did try though with a few wmvs that have 0 as frame rate.
Some them were generating previews ok and some need the fallback method using current (dev) stash.
In both cases the generation time was close (10-20 seconds) so not exactly the issue you mention.
With the vsync2 option added they also generated previews, some using the normal and some using the fallback method (the detection worked), within the same time but the resulting previews have a more standard frame rate

In conclusion

  1. adding vsync 2 doesn't break anything
  2. in cases where the r_frame_rate is bogus (frame rate 0 in stash) the resulting previews are better with vsync 2

@WithoutPants WithoutPants added the improvement Something needed tweaking. label Feb 15, 2023
@WithoutPants WithoutPants added this to the Version 0.20.0 milestone Feb 15, 2023
@WithoutPants WithoutPants merged commit 390f722 into stashapp:develop Feb 17, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
improvement Something needed tweaking.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants