mirror of
				https://github.com/yt-dlp/yt-dlp.git
				synced 2025-10-31 14:45:14 +00:00 
			
		
		
		
	[ffmpeg] Add --ffmpeg-location
This commit is contained in:
		| @@ -1298,7 +1298,7 @@ class YoutubeDL(object): | ||||
|                     downloaded = [] | ||||
|                     success = True | ||||
|                     merger = FFmpegMergerPP(self, not self.params.get('keepvideo')) | ||||
|                     if not merger._executable: | ||||
|                     if not merger.available(): | ||||
|                         postprocessors = [] | ||||
|                         self.report_warning('You have requested multiple ' | ||||
|                                             'formats but ffmpeg or avconv are not installed.' | ||||
| @@ -1647,7 +1647,7 @@ class YoutubeDL(object): | ||||
|         self._write_string('[debug] Python version %s - %s\n' % ( | ||||
|             platform.python_version(), platform_name())) | ||||
|  | ||||
|         exe_versions = FFmpegPostProcessor.get_versions() | ||||
|         exe_versions = FFmpegPostProcessor.get_versions(self) | ||||
|         exe_versions['rtmpdump'] = rtmpdump_version() | ||||
|         exe_str = ', '.join( | ||||
|             '%s %s' % (exe, v) | ||||
|   | ||||
| @@ -350,6 +350,7 @@ def _real_main(argv=None): | ||||
|         'xattr_set_filesize': opts.xattr_set_filesize, | ||||
|         'match_filter': match_filter, | ||||
|         'no_color': opts.no_color, | ||||
|         'ffmpeg_location': opts.ffmpeg_location, | ||||
|     } | ||||
|  | ||||
|     with YoutubeDL(ydl_opts) as ydl: | ||||
|   | ||||
| @@ -23,15 +23,14 @@ class HlsFD(FileDownloader): | ||||
|         tmpfilename = self.temp_name(filename) | ||||
|  | ||||
|         ffpp = FFmpegPostProcessor(downloader=self) | ||||
|         program = ffpp._executable | ||||
|         if program is None: | ||||
|         if not ffpp.available: | ||||
|             self.report_error('m3u8 download detected but ffmpeg or avconv could not be found. Please install one.') | ||||
|             return False | ||||
|         ffpp.check_version() | ||||
|  | ||||
|         args = [ | ||||
|             encodeArgument(opt) | ||||
|             for opt in (program, '-y', '-i', url, '-f', 'mp4', '-c', 'copy', '-bsf:a', 'aac_adtstoasc')] | ||||
|             for opt in (ffpp.executable, '-y', '-i', url, '-f', 'mp4', '-c', 'copy', '-bsf:a', 'aac_adtstoasc')] | ||||
|         args.append(encodeFilename(tmpfilename, True)) | ||||
|  | ||||
|         retval = subprocess.call(args) | ||||
| @@ -48,7 +47,7 @@ class HlsFD(FileDownloader): | ||||
|             return True | ||||
|         else: | ||||
|             self.to_stderr('\n') | ||||
|             self.report_error('%s exited with code %d' % (program, retval)) | ||||
|             self.report_error('%s exited with code %d' % (ffpp.basename, retval)) | ||||
|             return False | ||||
|  | ||||
|  | ||||
|   | ||||
| @@ -735,6 +735,10 @@ def parseOpts(overrideArguments=None): | ||||
|         '--prefer-ffmpeg', | ||||
|         action='store_true', dest='prefer_ffmpeg', | ||||
|         help='Prefer ffmpeg over avconv for running the postprocessors') | ||||
|     postproc.add_option( | ||||
|         '--ffmpeg-location', '--avconv-location', metavar='PATH', | ||||
|         dest='ffmpeg_location', | ||||
|         help='Location of the ffmpeg/avconv binary; either the path to the binary or its containing directory.') | ||||
|     postproc.add_option( | ||||
|         '--exec', | ||||
|         metavar='CMD', dest='exec_cmd', | ||||
|   | ||||
| @@ -30,54 +30,97 @@ class FFmpegPostProcessorError(PostProcessingError): | ||||
| class FFmpegPostProcessor(PostProcessor): | ||||
|     def __init__(self, downloader=None, deletetempfiles=False): | ||||
|         PostProcessor.__init__(self, downloader) | ||||
|         self._versions = self.get_versions() | ||||
|         self._deletetempfiles = deletetempfiles | ||||
|         self._determine_executables() | ||||
|  | ||||
|     def check_version(self): | ||||
|         if not self._executable: | ||||
|         if not self.available(): | ||||
|             raise FFmpegPostProcessorError('ffmpeg or avconv not found. Please install one.') | ||||
|  | ||||
|         required_version = '10-0' if self._uses_avconv() else '1.0' | ||||
|         if is_outdated_version( | ||||
|                 self._versions[self._executable], required_version): | ||||
|                 self._versions[self.basename], required_version): | ||||
|             warning = 'Your copy of %s is outdated, update %s to version %s or newer if you encounter any errors.' % ( | ||||
|                 self._executable, self._executable, required_version) | ||||
|                 self.basename, self.basename, required_version) | ||||
|             if self._downloader: | ||||
|                 self._downloader.report_warning(warning) | ||||
|  | ||||
|     @staticmethod | ||||
|     def get_versions(): | ||||
|     def get_versions(downloader=None): | ||||
|         return FFmpegPostProcessor(downloader)._versions | ||||
|  | ||||
|     def _determine_executables(self): | ||||
|         programs = ['avprobe', 'avconv', 'ffmpeg', 'ffprobe'] | ||||
|         return dict((p, get_exe_version(p, args=['-version'])) for p in programs) | ||||
|         prefer_ffmpeg = self._downloader.params.get('prefer_ffmpeg', False) | ||||
|  | ||||
|     @property | ||||
|     def available(self): | ||||
|         return self._executable is not None | ||||
|         self.basename = None | ||||
|         self.probe_basename = None | ||||
|  | ||||
|     @property | ||||
|     def _executable(self): | ||||
|         if self._downloader.params.get('prefer_ffmpeg', False): | ||||
|         self._paths = None | ||||
|         self._versions = None | ||||
|         if self._downloader: | ||||
|             location = self._downloader.params.get('ffmpeg_location') | ||||
|             if location is not None: | ||||
|                 if not os.path.exists(location): | ||||
|                     self._downloader.report_warning( | ||||
|                         'ffmpeg-location %s does not exist! ' | ||||
|                         'Continuing without avconv/ffmpeg.' % (location)) | ||||
|                     self._versions = {} | ||||
|                     return | ||||
|                 elif not os.path.isdir(location): | ||||
|                     basename = os.path.splitext(os.path.basename(location))[0] | ||||
|                     if basename not in programs: | ||||
|                         self._downloader.report_warning( | ||||
|                             'Cannot identify executable %s, its basename should be one of %s. ' | ||||
|                             'Continuing without avconv/ffmpeg.' % | ||||
|                             (location, ', '.join(programs))) | ||||
|                         self._versions = {} | ||||
|                         return None | ||||
|                     location = os.path.dirname(os.path.abspath(location)) | ||||
|                     if basename in ('ffmpeg', 'ffprobe'): | ||||
|                         prefer_ffmpeg = True | ||||
|  | ||||
|                 self._paths = dict( | ||||
|                     (p, os.path.join(location, p)) for p in programs) | ||||
|                 self._versions = dict( | ||||
|                     (p, get_exe_version(self._paths[p], args=['-version'])) | ||||
|                     for p in programs) | ||||
|         if self._versions is None: | ||||
|             self._versions = dict( | ||||
|                 (p, get_exe_version(p, args=['-version'])) for p in programs) | ||||
|             self._paths = dict((p, p) for p in programs) | ||||
|  | ||||
|         if prefer_ffmpeg: | ||||
|             prefs = ('ffmpeg', 'avconv') | ||||
|         else: | ||||
|             prefs = ('avconv', 'ffmpeg') | ||||
|         for p in prefs: | ||||
|             if self._versions[p]: | ||||
|                 return p | ||||
|         return None | ||||
|                 self.basename = p | ||||
|                 break | ||||
|  | ||||
|     @property | ||||
|     def _probe_executable(self): | ||||
|         if self._downloader.params.get('prefer_ffmpeg', False): | ||||
|         if prefer_ffmpeg: | ||||
|             prefs = ('ffprobe', 'avprobe') | ||||
|         else: | ||||
|             prefs = ('avprobe', 'ffprobe') | ||||
|         for p in prefs: | ||||
|             if self._versions[p]: | ||||
|                 return p | ||||
|         return None | ||||
|                 self.probe_basename = p | ||||
|                 break | ||||
|  | ||||
|     def available(self): | ||||
|         return self.basename is not None | ||||
|  | ||||
|     def _uses_avconv(self): | ||||
|         return self._executable == 'avconv' | ||||
|         return self.basename == 'avconv' | ||||
|  | ||||
|     @property | ||||
|     def executable(self): | ||||
|         return self._paths[self.basename] | ||||
|  | ||||
|     @property | ||||
|     def probe_executable(self): | ||||
|         return self._paths[self.probe_basename] | ||||
|  | ||||
|     def run_ffmpeg_multiple_files(self, input_paths, out_path, opts): | ||||
|         self.check_version() | ||||
| @@ -88,7 +131,7 @@ class FFmpegPostProcessor(PostProcessor): | ||||
|         files_cmd = [] | ||||
|         for path in input_paths: | ||||
|             files_cmd.extend([encodeArgument('-i'), encodeFilename(path, True)]) | ||||
|         cmd = ([encodeFilename(self._executable, True), encodeArgument('-y')] + | ||||
|         cmd = ([encodeFilename(self.executable, True), encodeArgument('-y')] + | ||||
|                files_cmd + | ||||
|                [encodeArgument(o) for o in opts] + | ||||
|                [encodeFilename(self._ffmpeg_filename_argument(out_path), True)]) | ||||
| @@ -127,13 +170,15 @@ class FFmpegExtractAudioPP(FFmpegPostProcessor): | ||||
|  | ||||
|     def get_audio_codec(self, path): | ||||
|  | ||||
|         if not self._probe_executable: | ||||
|         if not self.probe_executable: | ||||
|             raise PostProcessingError('ffprobe or avprobe not found. Please install one.') | ||||
|         try: | ||||
|             cmd = [ | ||||
|                 encodeFilename(self._probe_executable, True), | ||||
|                 encodeFilename(self.probe_executable, True), | ||||
|                 encodeArgument('-show_streams'), | ||||
|                 encodeFilename(self._ffmpeg_filename_argument(path), True)] | ||||
|             if self._downloader.params.get('verbose', False): | ||||
|                 self._downloader.to_screen('[debug] ffprobe command line: %s' % shell_quote(cmd)) | ||||
|             handle = subprocess.Popen(cmd, stderr=compat_subprocess_get_DEVNULL(), stdout=subprocess.PIPE) | ||||
|             output = handle.communicate()[0] | ||||
|             if handle.wait() != 0: | ||||
| @@ -223,14 +268,14 @@ class FFmpegExtractAudioPP(FFmpegPostProcessor): | ||||
|             if self._nopostoverwrites and os.path.exists(encodeFilename(new_path)): | ||||
|                 self._downloader.to_screen('[youtube] Post-process file %s exists, skipping' % new_path) | ||||
|             else: | ||||
|                 self._downloader.to_screen('[' + self._executable + '] Destination: ' + new_path) | ||||
|                 self._downloader.to_screen('[' + self.basename + '] Destination: ' + new_path) | ||||
|                 self.run_ffmpeg(path, new_path, acodec, more_opts) | ||||
|         except: | ||||
|             etype, e, tb = sys.exc_info() | ||||
|             if isinstance(e, AudioConversionError): | ||||
|                 msg = 'audio conversion failed: ' + e.msg | ||||
|             else: | ||||
|                 msg = 'error running ' + self._executable | ||||
|                 msg = 'error running ' + self.basename | ||||
|             raise PostProcessingError(msg) | ||||
|  | ||||
|         # Try to update the date time for extracted audio file. | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 Philipp Hagemeister
					Philipp Hagemeister