diff --git a/youtube_dl/__init__.py b/youtube_dl/__init__.py index e79320323..022800aa1 100644 --- a/youtube_dl/__init__.py +++ b/youtube_dl/__init__.py @@ -324,6 +324,7 @@ def _real_main(argv=None): 'encoding': opts.encoding, 'exec_cmd': opts.exec_cmd, 'extract_flat': opts.extract_flat, + 'fallback_mkv': opts.fallback_mkv, 'postprocessors': postprocessors, } diff --git a/youtube_dl/options.py b/youtube_dl/options.py index 21c452141..4351ec423 100644 --- a/youtube_dl/options.py +++ b/youtube_dl/options.py @@ -385,6 +385,11 @@ def parseOpts(overrideArguments=None): '--bidi-workaround', dest='bidi_workaround', action='store_true', help='Work around terminals that lack bidirectional text support. Requires bidiv or fribidi executable in PATH') + workarounds.add_option( + '--fallback-mkv', + dest='fallback_mkv', action='store_true', + help='If downloading separate vieo and audio (e.g. -f bestvideo+bestaudio) and merging fails, try to use an mkv container' + ) verbosity = optparse.OptionGroup(parser, 'Verbosity / Simulation Options') verbosity.add_option( diff --git a/youtube_dl/postprocessor/ffmpeg.py b/youtube_dl/postprocessor/ffmpeg.py index 048525efc..2d9fcf52e 100644 --- a/youtube_dl/postprocessor/ffmpeg.py +++ b/youtube_dl/postprocessor/ffmpeg.py @@ -516,13 +516,30 @@ class FFmpegMetadataPP(FFmpegPostProcessor): os.rename(encodeFilename(temp_filename), encodeFilename(filename)) return True, info - class FFmpegMergerPP(FFmpegPostProcessor): def run(self, info): filename = info['filepath'] args = ['-c', 'copy', '-map', '0:v:0', '-map', '1:a:0', '-shortest'] self._downloader.to_screen('[ffmpeg] Merging formats into "%s"' % filename) - self.run_ffmpeg_multiple_files(info['__files_to_merge'], filename, args) + #first attempt to merge them as normal but if a merge error happens attempt to eat it and try again with mkv output + #attempt to merge the files into the filename that the upstream methods have determined + #there's little point to try to guess from the start which video format will be compatible with which audio + #if the standard merge fails, fallback to mkv instead + try: + self.run_ffmpeg_multiple_files(info['__files_to_merge'], filename, args) + except FFmpegPostProcessorError as fpe: + if self._downloader.params.get('fallback_mkv', False) and "incorrect codec parameters" in fpe.msg.lower(): + warning = "Could not merge to %s format, ffmpeg said: '%s'\nAttempting to merge to mkv instead" % (info['ext'], fpe.msg) + self._downloader.report_warning(warning) + fname, ext = os.path.splitext(filename) + mkv_filename = fname + ".mkv" + self._downloader.to_screen('[ffmpeg] Merging formats into "%s"' % mkv_filename) + self.run_ffmpeg_multiple_files(info['__files_to_merge'], mkv_filename, args) + os.remove(encodeFilename(filename)) + info['filepath'] = mkv_filename + info['ext'] = 'mkv' + else: + raise fpe return True, info