PotcFdk / youtube-sync

Script for maintaining an up-to-date offline mirror of a YouTube channel.
Apache License 2.0
44 stars 13 forks source link

Embedding subtitles ends in ERROR: Conversion failed! #18

Open thrdroom opened 5 years ago

thrdroom commented 5 years ago

Verbose log

./youtube-sync update PursuitofWonder
[debug] System config: []
[debug] User config: []
[debug] Custom config: []
[debug] Command-line args: [u'-v', u'-i', u'-f', u'22/136+bestaudio[ext=m4a]/bestvideo[height<=720]+bestaudio[ext=m4a]/best[height<=720]', u'--all-subs', u'--embed-subs', u'--merge-output-format', u'mkv', u'-o', u'SYNC/PursuitofWonder/ID/%(id)s.mkv', u'https://www.youtube.com/channel/UC-tLyAaPbRZiYrOJxAGB7dQ']
[debug] Encodings: locale UTF-8, fs UTF-8, out UTF-8, pref UTF-8
[debug] youtube-dl version 2019.07.27
[debug] Python version 2.7.15+ (CPython) - Linux-4.15.0-55-generic-x86_64-with-neon-18.04-bionic
[debug] exe versions: ffmpeg 3.4.6, ffprobe 3.4.6
[debug] Proxy map: {}
[youtube:channel] UC-tLyAaPbRZiYrOJxAGB7dQ: Downloading channel page
[youtube:playlist] UU-tLyAaPbRZiYrOJxAGB7dQ: Downloading webpage
[download] Downloading playlist: Uploads from Pursuit of Wonder
[youtube:playlist] UU-tLyAaPbRZiYrOJxAGB7dQ: Downloading page #1
[youtube:playlist] playlist Uploads from Pursuit of Wonder: Downloading 118 videos
[download] Downloading video 1 of 118
[youtube] oGVhOWqsBWM: Downloading webpage
[youtube] oGVhOWqsBWM: Downloading video info webpage
[info] Writing video subtitles to: SYNC/PursuitofWonder/ID/oGVhOWqsBWM.en.vtt
[debug] Invoking downloader on u'https://r1---sn-h0jeened.googlevideo.com/videoplayback?expire=1564423155&ei=k98-Xd3lH9mF7gOZk6SQCg&ip=188.192.204.78&id=o-AMMblYLeUu8C8082Av5b49QnEVTl9J6V0JioNZ4OeTHg&itag=22&source=youtube&requiressl=yes&mm=31%2C26&mn=sn-h0jeened%2Csn-4g5ednss&ms=au%2Conr&mv=m&mvi=0&pl=24&initcwndbps=1963750&mime=video%2Fmp4&ratebypass=yes&dur=354.290&lmt=1563856956947519&mt=1564401462&fvip=1&beids=9466586&c=WEB&txp=2316222&sparams=expire%2Cei%2Cip%2Cid%2Citag%2Csource%2Crequiressl%2Cmime%2Cratebypass%2Cdur%2Clmt&sig=ALgxI2wwRQIgcXQaxIjXihc8-NaINMoDL1kOQdNSGuCbEKqDQ4FqKsgCIQCxpUkaDH9VusAqpreRIFrqBBWApOWjAjO08KwLHOR0Qg%3D%3D&lsparams=mm%2Cmn%2Cms%2Cmv%2Cmvi%2Cpl%2Cinitcwndbps&lsig=AHylml4wRQIhALBSWb2iN_YwaZjUQ8CpCC2Bi9gwvMlKDfJI67u1kzeoAiBThssiapqK1wnQuWlikZtCj98tInS5meAh5kf0DKobjw%3D%3D'
[download] Destination: SYNC/PursuitofWonder/ID/oGVhOWqsBWM.mkv
[download] 100% of 46.87MiB in 00:02
[ffmpeg] Embedding subtitles in 'SYNC/PursuitofWonder/ID/oGVhOWqsBWM.mkv'
[debug] ffmpeg command line: ffmpeg -y -loglevel 'repeat+info' -i 'file:SYNC/PursuitofWonder/ID/oGVhOWqsBWM.mkv' -i 'file:SYNC/PursuitofWonder/ID/oGVhOWqsBWM.en.vtt' -map 0 -c copy -map '-0:s' -map '-0:d' '-c:s' mov_text -map '1:0' '-metadata:s:s:0' 'language=eng' 'file:SYNC/PursuitofWonder/ID/oGVhOWqsBWM.temp.mkv'
ERROR: Conversion failed!
Traceback (most recent call last):
  File "/usr/local/bin/youtube-dl/youtube_dl/YoutubeDL.py", line 2054, in post_process
    files_to_delete, info = pp.run(info)
  File "/usr/local/bin/youtube-dl/youtube_dl/postprocessor/ffmpeg.py", line 426, in run
    self.run_ffmpeg_multiple_files(input_files, temp_filename, opts)
  File "/usr/local/bin/youtube-dl/youtube_dl/postprocessor/ffmpeg.py", line 235, in run_ffmpeg_multiple_files
    raise FFmpegPostProcessorError(msg)
FFmpegPostProcessorError: Conversion failed!

[download] Downloading video 2 of 118
[youtube] V2BrmsAYpI0: Downloading webpage
[youtube] V2BrmsAYpI0: Downloading video info webpage
WARNING: video doesn't have subtitles
[debug] Invoking downloader on u'https://r3---sn-h0jeenl7.googlevideo.com/videoplayback?expire=1564423159&ei=l98-XZmZJcyL7gOa1JDABQ&ip=188.192.204.78&id=o-AJQU9EDlMg-bO9hSvUh_cG83TxH1128o6ZCTd7XjoVhu&itag=22&source=youtube&requiressl=yes&mm=31%2C26&mn=sn-h0jeenl7%2Csn-4g5ednsd&ms=au%2Conr&mv=m&mvi=2&pl=24&initcwndbps=1876250&mime=video%2Fmp4&ratebypass=yes&dur=631.954&lmt=1563261094104028&mt=1564401462&fvip=3&beids=9466586&c=WEB&txp=4432432&sparams=expire%2Cei%2Cip%2Cid%2Citag%2Csource%2Crequiressl%2Cmime%2Cratebypass%2Cdur%2Clmt&sig=ALgxI2wwRQIgNysZ2mUMfPREHGAtmaLJLdBPa8w9SQXNlM3J252LEUACIQDPUBnADrdgzG-MoRMVl8D_gFMv_H0Xd1Zn8xKw_5G9jg%3D%3D&lsparams=mm%2Cmn%2Cms%2Cmv%2Cmvi%2Cpl%2Cinitcwndbps&lsig=AHylml4wRgIhAOVZ82hz82luNwDCX381znP6IfL3U26ZquW2rnViya37AiEAthc9Q4yad5IHBqQtoiJZHti_9Cxz6W9iN6VMmRlsbNo%3D'
[download] Destination: SYNC/PursuitofWonder/ID/V2BrmsAYpI0.mkv
[download]  42.1% of 76.03MiB at 22.93MiB/s ETA 00:01^C
ERROR: Interrupted by user
(1/2) Updating metadata: oGVhOWqsBWM... [title[debug] System config: []
[debug] User config: []
[debug] Custom config: []
[debug] Command-line args: [u'-v', u'--get-filename', u'-o', u'%(title)s', u'--', u'oGVhOWqsBWM']
[debug] Encodings: locale UTF-8, fs UTF-8, out None, pref UTF-8
[debug] youtube-dl version 2019.07.27
[debug] Python version 2.7.15+ (CPython) - Linux-4.15.0-55-generic-x86_64-with-neon-18.04-bionic
[debug] exe versions: ffmpeg 3.4.6, ffprobe 3.4.6
[debug] Proxy map: {}
^C
ERROR: Interrupted by user

Description

When i try to download all videos of a channel i get the error "Conversion failed!" at the step "[ffmpeg] Embedding subtitles in 'SYNC/PursuitofWonder/ID/oGVhOWqsBWM.mkv'". Is this error youtube-dl or ffmpeg related? How to fix this?

The url of the video is https://www.youtube.com/watch?v=oGVhOWqsBWM

As @dstftw said "Do not hardcode extension in output template" in his comment here

So i guess he means the fact that youtube-sync does hardcode the .mkv filename extension in the script...But since youtube-dl doesn't offer the ability to force MKV-container(AFAIK) what should we do to fix this?

Reference to: https://github.com/ytdl-org/youtube-dl/issues/21929

myrdd commented 5 years ago

"Do not hardcode extension in output template" in his comment here

Okay, that's quite simple to fix, but I think that's not the issue here. youtube-dl already is invoked with --merge-output-format mkv.

What happens when you invoke ydl as follows?

youtube-dl -v -i -f '22/136+bestaudio[ext=m4a]/bestvideo[height<=720]+bestaudio[ext=m4a]/best[height<=720]' --all-subs --embed-subs --merge-output-format mkv -o 'SYNC/PursuitofWonder/ID/%(id)s.%(ext)s' 'https://www.youtube.com/channel/UC-tLyAaPbRZiYrOJxAGB7dQ'

thrdroom commented 5 years ago

"Do not hardcode extension in output template" in his comment here

Okay, that's quite simple to fix, but I think that's not the issue here. youtube-dl already is invoked with --merge-output-format mkv.

What happens when you invoke ydl as follows?

youtube-dl -v -i -f '22/136+bestaudio[ext=m4a]/bestvideo[height<=720]+bestaudio[ext=m4a]/best[height<=720]' --all-subs --embed-subs --merge-output-format mkv -o 'SYNC/PursuitofWonder/ID/%(id)s.%(ext)s' 'https://www.youtube.com/channel/UC-tLyAaPbRZiYrOJxAGB7dQ'

Then i get .mp4 instead of .mkv files. This fixes the subtitle issue of the merging error, but i need to have mkv files instead.

BTW: Is youtube-sync written in the way to only handle .mkv files or also mp4 witthout a problem?

myrdd commented 5 years ago

Then i get .mp4 instead of .mkv files.

no errors? and the mp4 contains the subtitles?
if so, that's good. we then need to find out how to acheive mkv.

BTW: Is youtube-sync written in the way to only handle .mkv files or also mp4 witthout a problem?

I guess it's written for mkv only. But a solution might be to not use extensions at all. What happens with the following command?

youtube-dl -v -i -f '22/136+bestaudio[ext=m4a]/bestvideo[height<=720]+bestaudio[ext=m4a]/best[height<=720]' --all-subs --embed-subs --merge-output-format mkv -o 'SYNC/PursuitofWonder/ID/%(id)s' 'https://www.youtube.com/channel/UC-tLyAaPbRZiYrOJxAGB7dQ'

and please try this as well: (it's with --recode-video mkv)

youtube-dl -v -i -f '22/136+bestaudio[ext=m4a]/bestvideo[height<=720]+bestaudio[ext=m4a]/best[height<=720]' --all-subs --embed-subs --merge-output-format mkv --recode-video mkv -o 'SYNC/PursuitofWonder/ID/%(id)s.%(ext)s' 'https://www.youtube.com/channel/UC-tLyAaPbRZiYrOJxAGB7dQ'

myrdd commented 5 years ago

and please try this as well: (it's with --recode-video mkv)

youtube-dl -v -i -f '22/136+bestaudio[ext=m4a]/bestvideo[height<=720]+bestaudio[ext=m4a]/best[height<=720]' --all-subs --embed-subs --merge-output-format mkv --recode-video mkv -o 'SYNC/PursuitofWonder/ID/%(id)s.%(ext)s' 'https://www.youtube.com/channel/UC-tLyAaPbRZiYrOJxAGB7dQ'

looks like it does work.

...
[download] Destination: SYNC/PursuitofWonder/ID/oGVhOWqsBWM.mp4
[download] 100% of 46.87MiB in 00:22
[ffmpeg] Converting video from mp4 to mkv, Destination: SYNC/PursuitofWonder/ID/oGVhOWqsBWM.mkv
[debug] ffmpeg command line: ffmpeg -y -loglevel 'repeat+info' -i 'file:SYNC/PursuitofWonder/ID/oGVhOWqsBWM.mp4' 'file:SYNC/PursuitofWonder/ID/oGVhOWqsBWM.mkv'
Deleting original file SYNC/PursuitofWonder/ID/oGVhOWqsBWM.mp4 (pass -k to keep)
[ffmpeg] Embedding subtitles in 'SYNC/PursuitofWonder/ID/oGVhOWqsBWM.mkv'
[debug] ffmpeg command line: ffmpeg -y -loglevel 'repeat+info' -i 'file:SYNC/PursuitofWonder/ID/oGVhOWqsBWM.mkv' -i 'file:SYNC/PursuitofWonder/ID/oGVhOWqsBWM.en.vtt' -map 0 -c copy -map '-0:s' -map '-0:d' -map '1:0' '-metadata:s:s:0' 'language=eng' 'file:SYNC/PursuitofWonder/ID/oGVhOWqsBWM.temp.mkv'
Deleting original file SYNC/PursuitofWonder/ID/oGVhOWqsBWM.en.vtt (pass -k to keep)

So you need to add --recode-video mkv and use -o 'SYNC/PursuitofWonder/ID/%(id)s.%(ext)s'.

But a solution might be to not use extensions at all.

Tested that just now. ydl doesn't seem to support that.

myrdd commented 5 years ago

@PotcFdk any idea how we should fix this in the ytsync script? Should we add --recode-video mkv, or should we add support for other file formats?

thrdroom commented 5 years ago

no errors? and the mp4 contains the subtitles?

Yes.

But a solution might be to not use extensions at all. What happens with the following command?

youtube-dl -v -i -f '22/136+bestaudio[ext=m4a]/bestvideo[height<=720]+bestaudio[ext=m4a]/best[height<=720]' --all-subs --embed-subs --merge-output-format mkv -o 'SYNC/PursuitofWonder/ID/%(id)s' 'https://www.youtube.com/channel/UC-tLyAaPbRZiYrOJxAGB7dQ'

This gives me the error: ERROR: file:SYNC/PursuitofWonder/ID/oGVhOWqsBWM.temp: Invalid argument youtube-dl cant find the file as its saved as "oGVhOWqsBWM" without the .temp-extension.

and please try this as well: (it's with --recode-video mkv)

I allready tried this, and it works, but imho we should avoid re-encondig at all costs! Especially because we don't have to as we could theoretically simply just copy the streams to another container(mp4 > mkv) without re-encoding. Also the reencode suffers in quality and is heavy on the cpu!

if so, that's good. we then need to find out how to acheive mkv. I think i have an idea, but atm i have not enough time to write it in code. My idea is that we use '%(id)s.%(ext)s' as the main output template, and omit the "--embed-subs" parameter . Then if youtube-sync detects that it has downloaded an mp4 or webm instead of an mkv it copys the streams together with all downloaded subtitles into a mkv and deletes all files besides the merged mkv.

Something like:

`youtube-dl -v -i -f '22/136+bestaudio[ext=m4a]/bestvideo[height<=720]+bestaudio[ext=m4a]/best[height<=720]' --all-subs --merge-output-format mkv -o 'SYNC/PursuitofWonder/ID/%(id)s.%(ext)s' 'https://www.youtube.com/channel/UC-tLyAaPbRZiYrOJxAGB7dQ'

if %(id)s.mp4|%(id)s.webm exist(){ ffmpeg -i %(id)s.mp4|wbm -i %(id)s..vtt -c copy -c:s srt %(id)s.mkv rm -rf %(id)s.mp4|%(id)s.webm %(id)s..vtt } elseif %(id)s.mkv exist(){ ffmpeg -i %(id)s.mkv -i %(id)s..vtt -c copy -c:s srt %(id)s-temp.mkv rm -rf %(id)s.mkv %(id)s..vtt mv %(id)s-temp.mkv %(id)s.mkv }` In this example we would outsource the mergepart of the subtitles from youtube-dl to ffmpeg and have to do this step extra but we gain the ability to choose the file format we(the user) want.

Beware that this dummycode above wont work, it is just for brainstorming. Maybe i could write it out more specific tomorrow and send a pr when im done. Just let me know what you think about that idea, so i know if its worth pursuing.

I think in general it would be nice to support more than one file format, let the user choose in a separate settings file in the script-root where he can set the default file format(mkv,mp4,webm) as also the default quality format (bestvideo+bestaudio,22 etc...)

myrdd commented 5 years ago

and please try this as well: (it's with --recode-video mkv)

I allready tried this, and it works, but imho we should avoid re-encondig at all costs!

I agree.

we could theoretically simply just copy the streams to another container(mp4 > mkv) without re-encoding

I guess so, too.

I think in general it would be nice to support more than one file format

Agree again.

let the user choose in a separate settings file in the script-root where he can set the default file format(mkv,mp4,webm) as also the default quality format (bestvideo+bestaudio,22 etc...)

yes, probably.


In this example we would outsource the mergepart of the subtitles

I thought ytdl actually merges the subtitles into the mp4. No?
I would rather convert the mp4 to mkv, if needed.

Maybe i could write it out more specific tomorrow and send a pr when im done.

Best if you try if it works, then share it.

Just let me know what you think about that idea, so i know if its worth pursuing.

note that I'm not the maintainer, just a user who contributed some code ;)

thrdroom commented 5 years ago

In this example we would outsource the mergepart of the subtitles

I thought ytdl actually merges the subtitles into the mp4. No? I would rather convert the mp4 to mkv, if needed.

Yes ytdl does this if you add "--embed-subs" parameter. But if you omit, it saves the subtitles files as *.vtt separately, then it is simple to merge the .mp4 + .vtt into an .mkv without loosing the formatting of the subtitles. I also tried to directly convert the merged .mp4 with integrated subtitles into mkv ffmpeg -i oGVhOWqsBWM.mp4 -c copy -c:s srt oGVhOWqsBWM.mkv but that way the formatting of the subtitles gets destroyed and the subs are very tiny in vlc.

Maybe i could write it out more specific tomorrow and send a pr when im done.

Best if you try if it works, then share it.

I already tried the steps above manually and they worked like a charm :) i just don't have enough time today to write the code nicely. Maybe tomorrow ;)

PotcFdk commented 5 years ago

Alright, so I finally had some time and motivation to investigate this.

Analysis

I tried to call youtube-dl without your custom -f and it worked, subtitles seemed to be ok. When I tried it with -f "22/136+bestaudio[ext=m4a]/bestvideo[height<=720]+bestaudio[ext=m4a]/best[height<=720]", the above error appeared. So that's reproducable - great!

Calling youtube-dl with -v helps to find out how ffmpeg is called, so I called it exactly like youtube-dl would. This resulted in the following error:

[matroska @ 0x55c97ea8aa80] Subtitle codec 94213 is not supported.
Could not write header for output file #0 (incorrect codec parameters ?): Function not implemented

Hmm, alright, but why would ffmpeg support it when using the standard -f in youtube-dl? Let's see what it does differently. So I went to call youtube-dl with the default -f and also -v:

The first one is the working call, the second one is the non-working call:

ffmpeg -y -loglevel repeat+info -i file:test.mkv -i file:test.ar.vtt -i file:test.hr.vtt -i file:test.en.vtt -i file:test.fr.vtt -i file:test.ko.vtt -i file:test.pt.vtt -i file:test.sr.vtt -i file:test.es.vtt -i file:test.tr.vtt -i file:test.vi.vtt -map 0 -c copy -map -0:s -map -0:d -map 1:0 -metadata:s:s:0 language=ara -map 2:0 -metadata:s:s:1 language=hrv -map 3:0 -metadata:s:s:2 language=eng -map 4:0 -metadata:s:s:3 language=fra -map 5:0 -metadata:s:s:4 language=kor -map 6:0 -metadata:s:s:5 language=por -map 7:0 -metadata:s:s:6 language=srp -map 8:0 -metadata:s:s:7 language=spa -map 9:0 -metadata:s:s:8 language=tur -map 10:0 -metadata:s:s:9 language=vie file:test.temp.mkv
ffmpeg -y -loglevel repeat+info -i file:test.mkv -i file:test.ar.vtt -i file:test.hr.vtt -i file:test.en.vtt -i file:test.fr.vtt -i file:test.ko.vtt -i file:test.pt.vtt -i file:test.sr.vtt -i file:test.es.vtt -i file:test.tr.vtt -i file:test.vi.vtt -map 0 -c copy -map -0:s -map -0:d -c:s mov_text -map 1:0 -metadata:s:s:0 language=ara -map 2:0 -metadata:s:s:1 language=hrv -map 3:0 -metadata:s:s:2 language=eng -map 4:0 -metadata:s:s:3 language=fra -map 5:0 -metadata:s:s:4 language=kor -map 6:0 -metadata:s:s:5 language=por -map 7:0 -metadata:s:s:6 language=srp -map 8:0 -metadata:s:s:7 language=spa -map 9:0 -metadata:s:s:8 language=tur -map 10:0 -metadata:s:s:9 language=vie file:test.temp.mkv

Aha! The difference is a -c:s mov_text that sneaked in. I suppose youtube-dl does some internal magic to end up with the urge to specify a subtitle codec that ffmpeg can't put into an MKV container.

Solution?

It's kind of tricky, honestly. I am not too sure why youtube-dl decides to suddenly specify a subtitle codec, but I assume they have their reason (although I might contact them to make sure it's not unintended behavior). As for our purposes, @thrdroom created PR #19 to parametrize a global default format to be applied to new profiles. I don't mind that goal and don't even mind his implementation too much - it might just be "good enough". What does bug me, though, is that it introduces ambiguity as to what file extension is used in a given profile and then tries to correct it by supplying a remux method that only handles the mp4->mkv (and mkv->mkv) cases. I am not sure if youtube-dl can give us cases where %(ext)s is replaced with something non-mkv and non-mp4, but if so, that's yet another case to deal with and that might require more maintenance down the road that could be avoidable. I think that the goal that I outlined in https://github.com/PotcFdk/youtube-sync/issues/11#issuecomment-425748762 would be the best way to deal with allowing the user to choose their own -f and merge-format + file extension. That would, for example, allow for a pure .mp3 profile to be supported out-of-the-box (!) whereas #19 would introduce complexity while still sticking to an mkv-only mode of operation.

Discussion

What are your opinions on this?

PotcFdk commented 5 years ago

Quick update: As you can see in https://github.com/ytdl-org/youtube-dl/issues/22090, the merge-output-format option works not like I though it did. It specifies the merge target in case a marge happens. But with your format selection, 22 (the very first alternative) is available on YouTube, so it gets chosen. Unfortunately, that is a combined file (it contains both the video and audio stream), so no merge is required -> merge-output-format is ignored -> the output file ends up being an mp4 file disguised as an mkv file (wrong file extension). youtube-dl then calls ffmpeg with a subtitle format that is supported by that container (mp4), but not by mkv, hence the error. The only reason we didn't encounter this previously, is because the default option always caused a merge to happen - so we really ended up with an mkv file.

TL;DR: We need to make sure that whatever is selected by -f, in combination with --merge-output-format in case the -f selection causes a merge to happen, matches the file extension we use. This is what is partially done by #19, but as outlined above, it specifically continues to target mkv only and only resolves the mp4 case. Alternatively, full (matching) sets of these command line parameters and their fitting file extensions could be carefully managed as part of #11 and the "profile presets". Following that design, you could still specify your own -f options, but you'd have to also configure a fitting --merge-output-format and file extension.

PotcFdk commented 5 years ago

This issue will be resolved by #11, which contains the plan to remove the hardcoded .mkv.