lisamelton / video_transcoding

Tools to transcode, inspect and convert videos.
MIT License
2.37k stars 160 forks source link

Leverage `mediainfo` for better origin analysis than HandBrakeCLI #322

Open tweitzel opened 4 years ago

tweitzel commented 4 years ago

I know less than nothing about Ruby, but I have been doing media ripping from the command line for a long time.

Something I haven't been able to puzzle out is when transcode-video deinterlaces or not. It seems, from reading the source, that it just assumes that an mpeg 2 stream that isn't 23.976 is interlaced. This is bad for things like blu rays that use video-shot extras at 1080i, or OTA TV recordings.

I don't believe HandbrakeCLI exposes the scan type of a video stream directly, but fortunately MediaInfo from mediaarea.net does, and can output in any format you fine easiest to parse.

For example, my transcode-video wrapper script runs mediainfo '--Output=Video;%ScanType%' <filename> and it'll just return "Interlaced" or "Progressive". No guesswork.

I tried to hack support for it back into transcode-video, but ruby is alien to me :(

I hope this helps improve your project!

PS if you have homebrew installed, brew install mediainfo will do the right thing.

tweitzel commented 4 years ago

my wrapper script if you're curious and collecting data on used features


#!/usr/local/bin/bash
# wrap don melton's wrapper script for handbrake which wraps ffmpeg
SCANSTUFF="";

# figure out if the file is interlaced
if [[ $(/usr/local/bin/mediainfo '--Output=Video;%ScanType%' "$1") =~ 'Interlaced' ]]; then 
    # if it's interlaced and less than 640px high, use EEDI2 (too slow to use it on 1080i, plus it isn't noticeable there anyway)   
    if [ $(/usr/local/bin/mediainfo '--Output=Video;%Height%' "$1") -lt 640 ]; then 
        SCANSTUFF="--filter decomb=eedi2";
    else
        SCANSTUFF="--filter decomb";
    fi;
fi;

/usr/local/bin/transcode-video --encoder vt_h265 --keep-ac3-stereo --no-log $SCANSTUFF "$1"
lisamelton commented 4 years ago

@tweitzel Sorry I took so long to respond and thank you for your suggestion.

However, I definitely do not want to add yet another tool dependency to transcode-video. It has too many already and doing so would make it even more difficult to install for some users.

Also, the code does not assume that an MPEG-2 stream which isn't at 23.976 FPS is actually interlaced. Deinterlacing is only automatically applied when the input is at 29.97 FPS and not in MPEG-2 format.

So something else must be going on. Can you give me an example when this is happening because that could be bug? Thanks.

tweitzel commented 4 years ago

I'll let you know when it happens again using plain transcode-video.

Edit: Man, it was friday night when I sent that, I would have given you a week. :D

tweitzel commented 4 years ago

While I continue digging for another DVD or blu-ray extra that shows the problem, I have some more options for programmatically interrogating the video stream itself to decide if it's interlaced.

BTW, using --decomb instead of --deinterlace uses a much better deinterlacing filter in my opinion, and it already silently passes through progressive content by detecting per-frame whether it's interlaced. But transcode-video is inherently an opinionated tool, and I won't complain if you keep using --deinterlace. I just don't know how often you pop your head up to review the state of handbrake's builtins.

If you're willing to use ffprobe, which ships in the same package as ffmpeg, ffprobe -v error -select_streams v:0 -show_entries stream=field_order -of default=nokey=1:noprint_wrappers=1 <filename> will emit "progressive","tt", or "bt" signifying progressive scan, top-field first, bottom-field first deinterlacing.

If you want to keep using things straight from ffmpeg's output, just search for the regex "Stream.Video.progressive" from stderr and assume interlaced if the string doesn't appear. But I really thing leveraging at least ffprobe will get you a whole lot more data with less output parsing.

tweitzel commented 4 years ago

Also, the code does not assume that an MPEG-2 stream which isn't at 23.976 FPS is actually interlaced. Deinterlacing is only automatically applied when the input is at 29.97 FPS and not in MPEG-2 format.

My testing has now borne this out with one exception. 1080i ATSC broadcasts get the --deinterlace flag, while 480i DVD video does not. Both are MPEG-2 at 29.970.

pear-2:testland xarph$ for i in *; do printf "$i\t\t "; mediainfo '--Output=Video;%Format% %Format_Version% - %ScanType% - Stream:%FrameRate_Original% Output:%FrameRate%'  "$i"; transcode-video -n -o foo.mkv "$i"; done

atsc broadcast recording.mpg         MPEG Video Version 2 - Interlaced - Stream: Output:29.970
HandBrakeCLI --input=atsc\ broadcast\ recording.mpg --output=/Users/xarph/Movies/testland/foo.mkv --markers --encoder=x264 --crop=0:0:0:0 --auto-anamorphic --deinterlace --encoder-profile=high --encoder-level=4.0 --quality=1 --audio=1,1 --aencoder=copy,ca_aac --mixdown=,stereo --encopts=vbv-maxrate=6000:vbv-bufsize=12000:crf-max=25:qpmax=34

dvd feature.mkv      MPEG Video Version 2 - Progressive - Stream: Output:23.976
HandBrakeCLI --input=dvd\ feature.mkv --output=/Users/xarph/Movies/testland/foo.mkv --markers --encoder=x264 --crop=0:0:0:0 --auto-anamorphic --rate=23.976 --cfr --encoder-profile=high --encoder-level=3.0 --quality=1 --audio=1,1 --aencoder=copy,ca_aac --mixdown=,stereo --encopts=vbv-maxrate=1500:vbv-bufsize=3000:crf-max=25:qpmax=34

interlaced dvd extra.mkv         MPEG Video Version 2 - Interlaced - Stream: Output:29.970
HandBrakeCLI --input=interlaced\ dvd\ extra.mkv --output=/Users/xarph/Movies/testland/foo.mkv --markers --encoder=x264 --crop=0:0:0:0 --auto-anamorphic --rate=23.976 --cfr --encoder-profile=high --encoder-level=3.0 --quality=1 --audio=1 --aencoder=ca_aac --encopts=vbv-maxrate=1500:vbv-bufsize=3000:crf-max=25:qpmax=34

standard def blu ray extra.mkv       AVC  - Interlaced - Stream:29.970 Output:59.940
HandBrakeCLI --input=standard\ def\ blu\ ray\ extra.mkv --output=/Users/xarph/Movies/testland/foo.mkv --markers --encoder=x264 --crop=0:0:0:0 --auto-anamorphic --deinterlace --encoder-profile=high --encoder-level=3.0 --quality=1 --audio=1 --aencoder=ca_aac --encopts=vbv-maxrate=1500:vbv-bufsize=3000:crf-max=25:qpmax=34

Attached is the log of the first 1% of the ATSC transcode, as it is the main anomaly. I cancelled it after 1% since I don't think we need the output, but there you go.

atsc.mkv.log

tweitzel commented 4 years ago

Here's another fun one. If you do an ffmpeg stream copy (ffmpeg -i -vcodec copy -acodec copy) to encapsulate it in an .mkv file with no other changes, transcode-video decides it's a 3:2 pulldown progressive source and knocks it down to 23.976 with no deinterlacing, which looks awful. Re-encapsulating it back into an mpeg stream results in the correct behavior that we all want - no meddling with the framerate, deinterlacing applied.

source - atsc mkv.log source - atsc.mpg.log

lisamelton commented 4 years ago

@tweitzel I can't really tell much from those .log files. Can you include the --verbose option the next time? Thanks.