Why Doesn't it Work?
Over the holidays we made an effort to clean up our family movie collection. Cutting multi-hour videos into smaller chunks, catagorizing by people, renaming from MAH1982983.MPG to something sensible like “Evelyn is Sally Ride.MPG”.
Along the way we noticed there were playback issues that seemed inconsistent across devices. For example some files worked great everywhere
Media | LG TV | FireTV | Mac | PC |
---|---|---|---|---|
Audio | ✔ | ✔ | ✔ | ✔ |
Video | ✔ | ✔ | ✔ | ✔ |
Preview | ✔ | ✔ | ✔ | ✔ |
But other videos were less consistent - they partially rendered or only rendered on some platforms
Media | LG TV | FireTV | Mac | PC |
---|---|---|---|---|
Audio | ✔ | ✔ | X | ✔ |
Video | X | X | X | ✔ |
Preview | X | ✔ | X | ✔ |
This is obviously some issue where the video or audio codec is incompatible with the player but I didn’t really want to spend any time thinking about it. So decided to bulk convert everything to H.264 MP4’s with a 128bit AAC audio stream.
To do this I used ffmpeg.
Converting a Single File
Here is an example of an ffprobe output for one of the videos that would play audio, but not video, over the FireTV Plex client:
Input #0, mpeg, from 'Evelyn is Sally Ride.MPG':
Duration: 00:00:33.80, start: 0.110000, bitrate: 2914 kb/s
Stream #0:0[0x1c0]: Audio: mp2, 32000 Hz, mono, s16p, 64 kb/s
Stream #0:1[0x1e0]: Video: mpeg1video, yuv420p(tv), 640x480 [SAR 1:1 DAR 4:3], 104857 kb/s, 25 fps, 25 tbr, 90k tbn
To convert this file to something that would play both video and audio, I ran the following command:
ffmpeg -i "Evelyn is Sally Ride.MPG" -c:v libx264 -preset slow -crf 20 -c:a aac -b:a 128k -vf format=yuv420p -movflags +faststart "converted\Evelyn is Sally Ride.mp4"
Which created an file whose ffprobe output is:
Input #0, mov,mp4,m4a,3gp,3g2,mj2, from 'Evelyn is Sally Ride.mp4':
Metadata:
major_brand : isom
minor_version : 512
compatible_brands: isomiso2avc1mp41
encoder : Lavf59.16.100
Duration: 00:00:33.84, start: 0.000000, bitrate: 1645 kb/s
Stream #0:0[0x1](und): Video: h264 (High) (avc1 / 0x31637661), yuv420p(progressive), 640x480 [SAR 1:1 DAR 4:3], 1509 kb/s, 25 fps, 25 tbr, 12800 tbn (default)
Metadata:
handler_name : VideoHandler
vendor_id : [0][0][0][0]
Stream #0:1[0x2](und): Audio: aac (LC) (mp4a / 0x6134706D), 32000 Hz, mono, fltp, 129 kb/s (default)
Metadata:
handler_name : SoundHandler
vendor_id : [0][0][0][0]
And now when added back to the NAS and synced to Plex, everything works exactly as desired with no noticable change in audio or video quality.
Bulk Converting using ffmpeg
to do this in bulk, I wrote the following batch file:
if not exist converted mkdir converted
if exist converted\temp.mp4 del converted\temp.mp4
for %%I in (*) do (
if exist "converted\%%~nI.mp4" del "converted\%%~nI.mp4"
ffmpeg -i "%%I" -c:v libx264 -preset slow -crf 20 -c:a aac -b:a 128k -vf format=yuv420p -movflags +faststart converted\temp.mp4
move converted\temp.mp4 "converted\%%~nI.mp4"
)
This is pretty straight-forward.
Basically conversion is done for every file in a source folder and a temporary output file is created. Using a temp output file means I can kill the process mid-way through a conversation and I won’t leave a partially rendered artifact in place. Should I have needed to cancel the operation, or if it failed, it would be easier to be able to restart the process and skip things that had already successfully converted.