VideoHelp Forum
+ Reply to Thread
Results 1 to 7 of 7
Thread
  1. Member
    Join Date
    Jul 2008
    Location
    United States
    Search Comp PM
    Hi --

    I have a large, uncompressed AVI (~30m) containing captured super 8 film footage. It's in 29.97, but in reality a single frame of the file represents a single film frame.

    Being Super 8 footage, different sections of the file use different frame rates (18, 24, etc).

    I want to extract sections of the file and transcode to h264 at different frame rates. (I have already mapped out which sections are which frame rates.)

    I'm trying to use this command to e.g. take frames 0 through 99 and encode to a 24 fps mp4:

    ffmpeg -r 24 -i input.avi -vf 'select=gte(n\,0)*lt(n\,100),setpts=PTS-STARTPTS' -c:v libx264 -b:v 40000k -preset veryslow -profile:v high444 output.mp4
    The issue I'm having is that the "select" filter seems to work, but (understandably) ffmpeg correctly stops encoding at 100 frames and then needs to read every remaining frame just to check the "select" filter, which takes ~30m for this file (if my estimate is correct). That is, ffmpeg doesn't cleverly parse the "select" filter to realize that it can stop encoding after 100 frames and just close out the file -- instead, it churns through all the remaining frames.

    What's the smarter way to do this? I have 12 or so consecutive sections of the file that are at different frame rates. If there was a fancy way to put all of this into one giant filter chain and output 12 different files at different frame rates, I would only have to churn through the file once.

    I know I can SIGINT the process and it will cleanly close the file -- that can work, but I'd like to batch this up and run it overnight, rather than babysitting it. I guess I could write a babysitting script that determines when the file being generated stops growing and then SIGINT's ffmpeg. :-)

    It'd be nice if there was a filter like exitif(condition) -- then I could say:
    'select=gte(n\,0)*lt(n\,100),setpts=PTS,exitif(gte (n\,100))'

    ...anything like that exist? Couldn't find it in the docs...

    Thanks!
    Last edited by chconnor; 26th Feb 2018 at 16:08.
    Quote Quote  
  2. Member Budman1's Avatar
    Join Date
    Jul 2012
    Location
    NORTHWEST ILLINOIS, USA
    Search Comp PM
    If you have avisynth installed it is simple to create an avs script as:

    "Video24fps.avs"
    Code:
    directshowsource("c:\path\to\video\video.mp4")
    trim(0,-100)
    Then use this as the video in ffmpeg:

    Code:
    ffmpeg -i video24fps.avs -c:v libx264 -r 24 -b:v 40000k -preset veryslow -profile:v high444 output.mp4
    That will encode frames 0-99 (0,-100 means 100 frames starting at 0)

    The other method to use ffmpeg alone is to know what the frame time is and use -ss to seek to the frame and encode:

    Code:
    ffmpeg -ss 00:00:00.000 -i "c:\path\to\video\video.mp4" -vframes 100 -c:v libx264 -r 24 -b:v 40000k -preset veryslow -profile:v high444 output.mp4
    or
    Code:
    ffmpeg -ss 00:00:00.000 -to 00:00:04.170 -i "c:\path\to\video\video.mp4" -c:v libx264 -r 24 -b:v 40000k -preset veryslow -profile:v high444 output.mp4
    NOTE 00:00:04.170 is the time of NEXT frame (100) that you want to cut just BEFORE

    To start in the middle of a video you will have to know the time of that frame. The image below shows the output of the above script ending at 0-99 frames.

    POTPLAYER or other player that accepts AVS file
    Image
    [Attachment 44762 - Click to enlarge]
    Last edited by Budman1; 26th Feb 2018 at 17:46. Reason: script wrong
    Quote Quote  
  3. Member
    Join Date
    Jul 2008
    Location
    United States
    Search Comp PM
    Thanks! I was hoping to keep this in linux (AVISynth is windows only, yeah?) but maybe I'll go that route on the second batch of files -- it sounds like it would certainly be faster/better.

    I guess what I really want is for ffmpeg's -ss to accept frame number specifications so I could be sure what it was going to extract. But I guess if I'm precise with the timing it'd be accurate to the frame.

    I did end up making a babysitter shell script that just SIGINT's the current ffmpeg once the file size of the most recently modified file in the directory has stabilized. Worked fine for the first batch.

    Also, I realized I had a mistake (with the setpts) in my ffmpeg encoding string; here's the corrected form in case anyone cares:

    ffmpeg -r 18 -i input.avi -vf 'select=gte(n\,2625)*lt(n\,11110),setpts=PTS-STARTPTS' -c:v libx264 -b:v 30000k -preset veryslow -profile:v high444 output.mp4
    Quote Quote  
  4. Member Budman1's Avatar
    Join Date
    Jul 2012
    Location
    NORTHWEST ILLINOIS, USA
    Search Comp PM
    I don't know if it would help but there have been several post recently that describe how to list the key frames or all frames and their times. I do not have the articles url at the moment until i get on the computer.

    How are you finding the frame number? If you are scanning the video to find you could use the showframe/showtime options as shown in my image above.
    Quote Quote  
  5. Originally Posted by Budman1 View Post
    I don't know if it would help but there have been several post recently that describe how to list the key frames or all frames and their times. I do not have the articles url at the moment until i get on the computer.

    How are you finding the frame number? If you are scanning the video to find you could use the showframe/showtime options as shown in my image above.
    He's using uncompressed, so every frame is a keyframe in this case.



    The shell script is an interesting workaround. I didn't test it but couldn't you just limit the frame range with -frames:v 100 ? (or whatever number of frames)

    Another method is -vf trim to specify start and end frames (start frame is included, but the end frame is exclusive in ffmpeg, so if you wanted "0 to 99" inclusive, it would be start_frame=0:end_frame=100).

    But accurate seeking is not ideal in ffmpeg. Using any method including trim. In accurate mode, it has to parse all the frames, starting at the beginning, each and every single one before the start time - so it's slow. (if you use -ss it has to be done as an input option, not output option) . It can't just jump to the first IDR frame closest to the seek point when using accurate mode. So in your sequential batch, the first few files might be relatively quick, but the later files are going to be wasting a lot of time seeking, starting all over again.




    Or another way is physically split or edit the files beforehand into individual AVI's then batch ffmpeg process the individual files. You can change the framerate in ffmpeg or avi header . It will actually end up being much faster without the stupid seek latency issues

    Or as budman suggested avisynth, or in linux you can use vapoursynth (end frame is exclusive in vapoursynth, like ffmpeg; but unlike avisynth which is inclusive) . If you use avspmod/vdub or vapoursynth editor you can "see" if the frame ranges are accurate . And unlike ffmpeg in accurate mode, the seeks are fast. You can jump directly to the frame instead of starting all the beginning. (In long gop formats there might be a tiny pause because you jump to the closest IDR frame and decode the frames in the GOP)



    Also, what type of "uncompressed AVI" do you have ? e.g is it 8bit444 , RGB, 10bit422 etc.. ?
    Quote Quote  
  6. Member
    Join Date
    Jul 2008
    Location
    United States
    Search Comp PM
    Thanks all -- just back from a trip:

    Thanks Budman1 for the frame time tip and example image -- what's the video player there to be used with showframe/showtime?

    Originally Posted by poisondeathray View Post
    The shell script is an interesting workaround. I didn't test it but couldn't you just limit the frame range with -frames:v 100 ? (or whatever number of frames)
    D'oh, forgot all about -frames:v... that will save the post-cut churn time, and I won't need a babysitter script, thanks.

    Or another way is physically split or edit the files beforehand into individual AVI's then batch ffmpeg process the individual files. You can change the framerate in ffmpeg or avi header . It will actually end up being much faster without the stupid seek latency issues
    Yeah i think this is the smart way. I haven't sorted how to render a bunch of files from a timeline in Davinci Resolve, but I'm sure it's quite simple. I thought this method would be simpler, but I was obviously wrong.

    or in linux you can use vapoursynth
    Oh thanks, hadn't heard of vapoursynth yet.

    Also, what type of "uncompressed AVI" do you have ? e.g is it 8bit444 , RGB, 10bit422 etc.. ?
    Not sure; I think it was just listed as "RGB 10bit" in Resolve, but here's the ffprobe:

    Stream #0:0: Video: r210 (r210 / 0x30313272), rgb48le(10 bpc), 1440x1080, 1524685 kb/s, 29.97 fps, 29.97 tbr, 29.97 tbn, 29.97 tbc

    I think I understand my options:

    * just render separate clips from Resolve like a reasonable person and transcode separately
    * use avisynth or vapoursynth to quickly seek to frame locations
    * use -ss or trim or select() to slowly seek, limit post-clip churn with -frames:v

    Thanks as usual for the awesome help.
    Quote Quote  
  7. Member Budman1's Avatar
    Join Date
    Jul 2012
    Location
    NORTHWEST ILLINOIS, USA
    Search Comp PM
    @chconnor... Any video player that supports AVISYNTH 'AVS' file playing will work. You just need the Avisynth script that I forgot to include in my thread.

    Code:
    FFmpegSource2("C:\Users\Bud\Documents\Applian\Replay Media Catcher\Video.mp4", atrack=-1).Crop(0,0,-0,-0).LanczosResize(720,404)
    ScriptClip(Last, """Subtitle("[ "+Chr(FFPICT_TYPE)+" ]", size=(Height*56.0/720), align=2)""", after_frame=true)
    Subtitle("C:\Users\Bud\Documents\Applian\Replay Media Catcher\Video.mp4", x=720, y=424, font="Arial", size=24, text_color=$ff0000, align=3)
    ShowFrameNumber(scroll=true, x=10, y=27, font="Arial", size=24, text_color=$ff0000)
    ShowTime(x=72, y=44, font="Arial", size=24, text_color=$ff0000)
    ShowSMPTE(fps=29.97, x=68, y=61, font="Arial", size=24, text_color=$ff0000)
    The attributes for each line is set automatically by my program for the video size and for alignment of the text. If you adjust the font size or have a different video size, the output will be different but should still be readable.
    Quote Quote  



Similar Threads

Visit our sponsor! Try DVDFab and backup Blu-rays!