[ANSWERED] Add option to embed soft subtitles in output files
#1
Goal: Automatic inclusion of subtitles into the mp4 file, for compatibility with players that are unable to read .srt files.

Current workaround: Manual use of Subler on osx for each file.

Almost functional workaround: user-specified command to call ffmpeg a second time. The problem is that the artwork added during the tagging phase is lost.

I am working on a changelist to support my goal by moving the postproc() code that merges the audio and video until after subtitles are downloaded but before tagging.

I am curious if A) if there is a better way to achieve my goal; or B) if there is a reason that the code is structured as is it that I need to be careful about to ever have a chance of a pull request being accepted. I see that there have been recent changes on github to subtitle processing, so it would also be good to know if there are planned changes near this code.
#2
The artwork for a get_iplayer mp4 is stored in the mp4 container as a second video stream in mjpeg format. Unfortunately, after further manipulation of the mp4 that stream does not seem to be recognized as cover art by players even when it still exists.

What you could do is to add another step to your almost functional workaround to add the artwork back.

Here's the steps (Windows I'm afraid, but should be straightforward to convert to other operating systems).

Starting with the downloaded, converted and tagged get_iplayer file: in.mp4 and the get_iplayer downloaded subtitles file: in.srt both in the current directory and with ffmpeg and atomicparsley in the PATH.
  1. Extract the thumbnail from the mp4
    Code:
    C:\>ffmpeg -i in.mp4 -c copy -map 0:2 out.jpg
  2. Add the subtitles as a stream
    Code:
    C:\>ffmpeg -i in.mp4 -i in.srt -c copy -c:s mov_text -map 0:0 -map 0:1 -map 1:0 -metadata:s:s:0 "language=eng" out.mp4
    Note: I've not bothered copying the mjpeg stream (-map 0:2), since I'll be adding the artwork back in the next step.
  3. Add back the artwork as an mjpeg stream
    Code:
    C:\>atomicparsley out.mp4 --freefree --overWrite --artwork out.jpg
  4. Check the output (optional)
    • get_iplayer Output:

      C:\>ffmpeg -i out.mp4 2>&1 | find "Stream #"
         Stream #0:0(und): Video: h264 (High) (avc1 / 0x31637661), yuv420p, 1280x720 [SAR 1:1 DAR 16:9],
             2309 kb/s, 25 fps, 25 tbr, 90k tbn, 50 tbc (default)
         Stream #0:1(und): Audio: aac (LC) (mp4a / 0x6134706D), 48000 Hz, stereo, fltp, 93 kb/s (default)
         Stream #0:2(eng): Subtitle: mov_text (tx3g / 0x67337874), 0 kb/s (default)
         Stream #0:3: Video: mjpeg, yuvj420p(pc, bt470bg/unknown/unknown), 192x108 [SAR 72:72 DAR 16:9],
             90k tbr, 90k tbn, 90k tbc

      get_iplayer Output:

      C:\>atomicparsley out.mp4 -t | find "covr"
         Atom "covr" contains: 1 piece of artwork
  5. Clean up (optional)
    Code:
    C:\>del in.* out.jpg
If you've used the --thumb option when downloading the programme you can skip step 1 and use the downloaded thumbnail in step 3.


After this process you'll end up with a tagged (with artwork) out.mp4 file with video, audio, subtitles and mjpeg streams.
#3
(18-12-2017, 05:16 AM)just_another_user Wrote: Goal: Automatic inclusion of subtitles into the mp4 file, for compatibility with players that are unable to read .srt files.
It's a no from me. I'm not willing to support such functionality. If you or anyone else should wish to implement this in get_iplayer yourself, I'm obliged to caution you: If you want to add such new features, you must take over as maintainer.

If you're on a computer you always have SRT-capable options, so this is mostly pertinent to hardware players. There is no way I can support hardware players if problems arise. get_iplayer does as little as possible with its output and leaves it up to you to adapt it for whatever systems you use. The only reason it even does SRT conversion is because the native TTML subtitles are useless with most players.

You can easily add soft subtitles to your MP4 output file with SublerCLI (macOS only) or mp4box, which both can be automated via --command. There may be other applications that also can do the job. The only caveat is that mp4box barfs on 50fps DASH video files. You shouldn't get those unless HLS isn't available for some unknown reason, or you specifically request them, but that's not a good idea on macOS since iTunes/QuickTime can't play the video in DASH-derived files, even after re-muxing. If there is an incantation to make those files QT-compatible without transcoding, I don't know it.

Two tips: 1) use -optimize with SublerCLI so the file is re-optimised for streaming (mp4box does this by default); 2) if your player can't handle (or ignore) the formatting tags used for subtitle colours, use --subs-mono with get_iplayer.
#4
Just signed up to report that I've been successful in this area. As noted above, private modifications are unsupported. This is accepted. Upon each release of GIP, I modify a copy of the code (renamed get_iplayer.pl), naming the modified code get_iplayer2.pl.

To get this to work, the srt file is downloaded first:
Code:
get_iplayer.pl --pid xxxxxxxx --modes=best --raw --subtitles-only

If there are no subtitles, the srt file does not exist, run the unmodified GIP:
Code:
get_iplayer.pl --pid xxxxxxxx --modes=best --radiomode --raw

If there are subtitles, the srt file does exist, run the modified GIP:
Code:
get_iplayer2.pl --pid xxxxxxxx --modes=best --radiomode --raw

This can be wrapped up into a batch file, which can make life easier! ;-)

For get_iplayer2.pl, the postproc() modifications are below:

In the ffmpeg call, change
Code:
$prog->{filepart},
to create a temporary file
Code:
join('',$prog->{dir},'\\',$prog->{fileprefix},'.temp.mp4'),

Add this immediately after the ffmpeg call returns
Code:
main::logger "INFO: Adding subtitles\n";

@cmd = (
       $bin->{ffmpeg},
       @{ $binopts->{ffmpeg} },
       '-i', join('',$prog->{dir},'\\',$prog->{fileprefix},'.temp.mp4'),
       '-i', join('',$prog->{dir},'\\',$prog->{fileprefix},'.srt'),
       '-c:v', 'copy',
       '-c:a', 'copy', '-metadata:s:a:0', 'language=eng',
       '-c:s', 'mov_text', '-metadata:s:s:0', 'language=eng',
       $prog->{filepart},
);

# Add subtitles
$return = main::run_cmd( 'STDERR', @cmd );

To keep things tidy, remove the temporary files, so after
Code:
unlink( $audio_file, $video_file );
add these 2 lines:
Code:
unlink( join('',$prog->{dir},'\\',$prog->{fileprefix},'.temp.mp4') );
unlink( join('',$prog->{dir},'\\',$prog->{fileprefix},'.srt') );

Disclaimer: As mentioned, this code is unsupported. I spent quite some time fiddling to get this to work satisfactority, but feel free to fiddle some more. Note that the options '--radiomode --raw' worked for me, SWAPPING THEM AROUND DID NOT, so adding more options to the command may work or may not work for you.

Also, atomic parsley sometimes throws a wobbly (code 1280, I think), which I just ignore.

Hope this is useful to someone here...