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 = [] |                     downloaded = [] | ||||||
|                     success = True |                     success = True | ||||||
|                     merger = FFmpegMergerPP(self, not self.params.get('keepvideo')) |                     merger = FFmpegMergerPP(self, not self.params.get('keepvideo')) | ||||||
|                     if not merger._executable: |                     if not merger.available(): | ||||||
|                         postprocessors = [] |                         postprocessors = [] | ||||||
|                         self.report_warning('You have requested multiple ' |                         self.report_warning('You have requested multiple ' | ||||||
|                                             'formats but ffmpeg or avconv are not installed.' |                                             'formats but ffmpeg or avconv are not installed.' | ||||||
| @@ -1647,7 +1647,7 @@ class YoutubeDL(object): | |||||||
|         self._write_string('[debug] Python version %s - %s\n' % ( |         self._write_string('[debug] Python version %s - %s\n' % ( | ||||||
|             platform.python_version(), platform_name())) |             platform.python_version(), platform_name())) | ||||||
|  |  | ||||||
|         exe_versions = FFmpegPostProcessor.get_versions() |         exe_versions = FFmpegPostProcessor.get_versions(self) | ||||||
|         exe_versions['rtmpdump'] = rtmpdump_version() |         exe_versions['rtmpdump'] = rtmpdump_version() | ||||||
|         exe_str = ', '.join( |         exe_str = ', '.join( | ||||||
|             '%s %s' % (exe, v) |             '%s %s' % (exe, v) | ||||||
|   | |||||||
| @@ -350,6 +350,7 @@ def _real_main(argv=None): | |||||||
|         'xattr_set_filesize': opts.xattr_set_filesize, |         'xattr_set_filesize': opts.xattr_set_filesize, | ||||||
|         'match_filter': match_filter, |         'match_filter': match_filter, | ||||||
|         'no_color': opts.no_color, |         'no_color': opts.no_color, | ||||||
|  |         'ffmpeg_location': opts.ffmpeg_location, | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     with YoutubeDL(ydl_opts) as ydl: |     with YoutubeDL(ydl_opts) as ydl: | ||||||
|   | |||||||
| @@ -23,15 +23,14 @@ class HlsFD(FileDownloader): | |||||||
|         tmpfilename = self.temp_name(filename) |         tmpfilename = self.temp_name(filename) | ||||||
|  |  | ||||||
|         ffpp = FFmpegPostProcessor(downloader=self) |         ffpp = FFmpegPostProcessor(downloader=self) | ||||||
|         program = ffpp._executable |         if not ffpp.available: | ||||||
|         if program is None: |  | ||||||
|             self.report_error('m3u8 download detected but ffmpeg or avconv could not be found. Please install one.') |             self.report_error('m3u8 download detected but ffmpeg or avconv could not be found. Please install one.') | ||||||
|             return False |             return False | ||||||
|         ffpp.check_version() |         ffpp.check_version() | ||||||
|  |  | ||||||
|         args = [ |         args = [ | ||||||
|             encodeArgument(opt) |             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)) |         args.append(encodeFilename(tmpfilename, True)) | ||||||
|  |  | ||||||
|         retval = subprocess.call(args) |         retval = subprocess.call(args) | ||||||
| @@ -48,7 +47,7 @@ class HlsFD(FileDownloader): | |||||||
|             return True |             return True | ||||||
|         else: |         else: | ||||||
|             self.to_stderr('\n') |             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 |             return False | ||||||
|  |  | ||||||
|  |  | ||||||
|   | |||||||
| @@ -735,6 +735,10 @@ def parseOpts(overrideArguments=None): | |||||||
|         '--prefer-ffmpeg', |         '--prefer-ffmpeg', | ||||||
|         action='store_true', dest='prefer_ffmpeg', |         action='store_true', dest='prefer_ffmpeg', | ||||||
|         help='Prefer ffmpeg over avconv for running the postprocessors') |         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( |     postproc.add_option( | ||||||
|         '--exec', |         '--exec', | ||||||
|         metavar='CMD', dest='exec_cmd', |         metavar='CMD', dest='exec_cmd', | ||||||
|   | |||||||
| @@ -30,54 +30,97 @@ class FFmpegPostProcessorError(PostProcessingError): | |||||||
| class FFmpegPostProcessor(PostProcessor): | class FFmpegPostProcessor(PostProcessor): | ||||||
|     def __init__(self, downloader=None, deletetempfiles=False): |     def __init__(self, downloader=None, deletetempfiles=False): | ||||||
|         PostProcessor.__init__(self, downloader) |         PostProcessor.__init__(self, downloader) | ||||||
|         self._versions = self.get_versions() |  | ||||||
|         self._deletetempfiles = deletetempfiles |         self._deletetempfiles = deletetempfiles | ||||||
|  |         self._determine_executables() | ||||||
|  |  | ||||||
|     def check_version(self): |     def check_version(self): | ||||||
|         if not self._executable: |         if not self.available(): | ||||||
|             raise FFmpegPostProcessorError('ffmpeg or avconv not found. Please install one.') |             raise FFmpegPostProcessorError('ffmpeg or avconv not found. Please install one.') | ||||||
|  |  | ||||||
|         required_version = '10-0' if self._uses_avconv() else '1.0' |         required_version = '10-0' if self._uses_avconv() else '1.0' | ||||||
|         if is_outdated_version( |         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.' % ( |             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: |             if self._downloader: | ||||||
|                 self._downloader.report_warning(warning) |                 self._downloader.report_warning(warning) | ||||||
|  |  | ||||||
|     @staticmethod |     @staticmethod | ||||||
|     def get_versions(): |     def get_versions(downloader=None): | ||||||
|  |         return FFmpegPostProcessor(downloader)._versions | ||||||
|  |  | ||||||
|  |     def _determine_executables(self): | ||||||
|         programs = ['avprobe', 'avconv', 'ffmpeg', 'ffprobe'] |         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 |         self.basename = None | ||||||
|     def available(self): |         self.probe_basename = None | ||||||
|         return self._executable is not None |  | ||||||
|  |  | ||||||
|     @property |         self._paths = None | ||||||
|     def _executable(self): |         self._versions = None | ||||||
|         if self._downloader.params.get('prefer_ffmpeg', False): |         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') |             prefs = ('ffmpeg', 'avconv') | ||||||
|         else: |         else: | ||||||
|             prefs = ('avconv', 'ffmpeg') |             prefs = ('avconv', 'ffmpeg') | ||||||
|         for p in prefs: |         for p in prefs: | ||||||
|             if self._versions[p]: |             if self._versions[p]: | ||||||
|                 return p |                 self.basename = p | ||||||
|         return None |                 break | ||||||
|  |  | ||||||
|     @property |         if prefer_ffmpeg: | ||||||
|     def _probe_executable(self): |  | ||||||
|         if self._downloader.params.get('prefer_ffmpeg', False): |  | ||||||
|             prefs = ('ffprobe', 'avprobe') |             prefs = ('ffprobe', 'avprobe') | ||||||
|         else: |         else: | ||||||
|             prefs = ('avprobe', 'ffprobe') |             prefs = ('avprobe', 'ffprobe') | ||||||
|         for p in prefs: |         for p in prefs: | ||||||
|             if self._versions[p]: |             if self._versions[p]: | ||||||
|                 return p |                 self.probe_basename = p | ||||||
|         return None |                 break | ||||||
|  |  | ||||||
|  |     def available(self): | ||||||
|  |         return self.basename is not None | ||||||
|  |  | ||||||
|     def _uses_avconv(self): |     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): |     def run_ffmpeg_multiple_files(self, input_paths, out_path, opts): | ||||||
|         self.check_version() |         self.check_version() | ||||||
| @@ -88,7 +131,7 @@ class FFmpegPostProcessor(PostProcessor): | |||||||
|         files_cmd = [] |         files_cmd = [] | ||||||
|         for path in input_paths: |         for path in input_paths: | ||||||
|             files_cmd.extend([encodeArgument('-i'), encodeFilename(path, True)]) |             files_cmd.extend([encodeArgument('-i'), encodeFilename(path, True)]) | ||||||
|         cmd = ([encodeFilename(self._executable, True), encodeArgument('-y')] + |         cmd = ([encodeFilename(self.executable, True), encodeArgument('-y')] + | ||||||
|                files_cmd + |                files_cmd + | ||||||
|                [encodeArgument(o) for o in opts] + |                [encodeArgument(o) for o in opts] + | ||||||
|                [encodeFilename(self._ffmpeg_filename_argument(out_path), True)]) |                [encodeFilename(self._ffmpeg_filename_argument(out_path), True)]) | ||||||
| @@ -127,13 +170,15 @@ class FFmpegExtractAudioPP(FFmpegPostProcessor): | |||||||
|  |  | ||||||
|     def get_audio_codec(self, path): |     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.') |             raise PostProcessingError('ffprobe or avprobe not found. Please install one.') | ||||||
|         try: |         try: | ||||||
|             cmd = [ |             cmd = [ | ||||||
|                 encodeFilename(self._probe_executable, True), |                 encodeFilename(self.probe_executable, True), | ||||||
|                 encodeArgument('-show_streams'), |                 encodeArgument('-show_streams'), | ||||||
|                 encodeFilename(self._ffmpeg_filename_argument(path), True)] |                 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) |             handle = subprocess.Popen(cmd, stderr=compat_subprocess_get_DEVNULL(), stdout=subprocess.PIPE) | ||||||
|             output = handle.communicate()[0] |             output = handle.communicate()[0] | ||||||
|             if handle.wait() != 0: |             if handle.wait() != 0: | ||||||
| @@ -223,14 +268,14 @@ class FFmpegExtractAudioPP(FFmpegPostProcessor): | |||||||
|             if self._nopostoverwrites and os.path.exists(encodeFilename(new_path)): |             if self._nopostoverwrites and os.path.exists(encodeFilename(new_path)): | ||||||
|                 self._downloader.to_screen('[youtube] Post-process file %s exists, skipping' % new_path) |                 self._downloader.to_screen('[youtube] Post-process file %s exists, skipping' % new_path) | ||||||
|             else: |             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) |                 self.run_ffmpeg(path, new_path, acodec, more_opts) | ||||||
|         except: |         except: | ||||||
|             etype, e, tb = sys.exc_info() |             etype, e, tb = sys.exc_info() | ||||||
|             if isinstance(e, AudioConversionError): |             if isinstance(e, AudioConversionError): | ||||||
|                 msg = 'audio conversion failed: ' + e.msg |                 msg = 'audio conversion failed: ' + e.msg | ||||||
|             else: |             else: | ||||||
|                 msg = 'error running ' + self._executable |                 msg = 'error running ' + self.basename | ||||||
|             raise PostProcessingError(msg) |             raise PostProcessingError(msg) | ||||||
|  |  | ||||||
|         # Try to update the date time for extracted audio file. |         # Try to update the date time for extracted audio file. | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user
	 Philipp Hagemeister
					Philipp Hagemeister