mirror of
				https://github.com/yt-dlp/yt-dlp.git
				synced 2025-10-30 22:25:19 +00:00 
			
		
		
		
	[ffmpeg] Framework for feature detection
Related: #1502, #1237, https://github.com/ytdl-org/youtube-dl/pull/29581
This commit is contained in:
		| @@ -232,7 +232,8 @@ def _real_main(argv=None): | |||||||
|             parser.error('invalid audio format specified') |             parser.error('invalid audio format specified') | ||||||
|     if opts.audioquality: |     if opts.audioquality: | ||||||
|         opts.audioquality = opts.audioquality.strip('k').strip('K') |         opts.audioquality = opts.audioquality.strip('k').strip('K') | ||||||
|         if int_or_none(float_or_none(opts.audioquality)) is None:  # int_or_none prevents inf, nan |         audioquality = int_or_none(float_or_none(opts.audioquality))  # int_or_none prevents inf, nan | ||||||
|  |         if audioquality is None or audioquality < 0: | ||||||
|             parser.error('invalid audio quality specified') |             parser.error('invalid audio quality specified') | ||||||
|     if opts.recodevideo is not None: |     if opts.recodevideo is not None: | ||||||
|         opts.recodevideo = opts.recodevideo.replace(' ', '') |         opts.recodevideo = opts.recodevideo.replace(' ', '') | ||||||
|   | |||||||
| @@ -16,7 +16,8 @@ from ..utils import ( | |||||||
|     encodeArgument, |     encodeArgument, | ||||||
|     encodeFilename, |     encodeFilename, | ||||||
|     float_or_none, |     float_or_none, | ||||||
|     get_exe_version, |     _get_exe_version_output, | ||||||
|  |     detect_exe_version, | ||||||
|     is_outdated_version, |     is_outdated_version, | ||||||
|     ISO639Utils, |     ISO639Utils, | ||||||
|     orderedSet, |     orderedSet, | ||||||
| @@ -80,10 +81,10 @@ class FFmpegPostProcessor(PostProcessor): | |||||||
|  |  | ||||||
|     def _determine_executables(self): |     def _determine_executables(self): | ||||||
|         programs = ['avprobe', 'avconv', 'ffmpeg', 'ffprobe'] |         programs = ['avprobe', 'avconv', 'ffmpeg', 'ffprobe'] | ||||||
|         prefer_ffmpeg = True |  | ||||||
|  |  | ||||||
|         def get_ffmpeg_version(path): |         def get_ffmpeg_version(path, prog): | ||||||
|             ver = get_exe_version(path, args=['-version']) |             out = _get_exe_version_output(path, ['-bsfs']) | ||||||
|  |             ver = detect_exe_version(out) if out else False | ||||||
|             if ver: |             if ver: | ||||||
|                 regexs = [ |                 regexs = [ | ||||||
|                     r'(?:\d+:)?([0-9.]+)-[0-9]+ubuntu[0-9.]+$',  # Ubuntu, see [1] |                     r'(?:\d+:)?([0-9.]+)-[0-9]+ubuntu[0-9.]+$',  # Ubuntu, see [1] | ||||||
| @@ -94,42 +95,46 @@ class FFmpegPostProcessor(PostProcessor): | |||||||
|                     mobj = re.match(regex, ver) |                     mobj = re.match(regex, ver) | ||||||
|                     if mobj: |                     if mobj: | ||||||
|                         ver = mobj.group(1) |                         ver = mobj.group(1) | ||||||
|             return ver |             self._versions[prog] = ver | ||||||
|  |             if prog != 'ffmpeg' or not out: | ||||||
|  |                 return | ||||||
|  |  | ||||||
|  |             # TODO: Feature detection | ||||||
|  |  | ||||||
|         self.basename = None |         self.basename = None | ||||||
|         self.probe_basename = None |         self.probe_basename = None | ||||||
|  |  | ||||||
|         self._paths = None |         self._paths = None | ||||||
|         self._versions = None |         self._versions = None | ||||||
|         if self._downloader: |         self._features = {} | ||||||
|             prefer_ffmpeg = self.get_param('prefer_ffmpeg', True) |  | ||||||
|             location = self.get_param('ffmpeg_location') |  | ||||||
|             if location is not None: |  | ||||||
|                 if not os.path.exists(location): |  | ||||||
|                     self.report_warning( |  | ||||||
|                         'ffmpeg-location %s does not exist! ' |  | ||||||
|                         'Continuing without ffmpeg.' % (location)) |  | ||||||
|                     self._versions = {} |  | ||||||
|                     return |  | ||||||
|                 elif os.path.isdir(location): |  | ||||||
|                     dirname, basename = location, None |  | ||||||
|                 else: |  | ||||||
|                     basename = os.path.splitext(os.path.basename(location))[0] |  | ||||||
|                     basename = next((p for p in programs if basename.startswith(p)), 'ffmpeg') |  | ||||||
|                     dirname = os.path.dirname(os.path.abspath(location)) |  | ||||||
|                     if basename in ('ffmpeg', 'ffprobe'): |  | ||||||
|                         prefer_ffmpeg = True |  | ||||||
|  |  | ||||||
|                 self._paths = dict( |         prefer_ffmpeg = self.get_param('prefer_ffmpeg', True) | ||||||
|                     (p, os.path.join(dirname, p)) for p in programs) |         location = self.get_param('ffmpeg_location') | ||||||
|                 if basename: |         if location is None: | ||||||
|                     self._paths[basename] = location |             self._paths = {p: p for p in programs} | ||||||
|                 self._versions = dict( |         else: | ||||||
|                     (p, get_ffmpeg_version(self._paths[p])) for p in programs) |             if not os.path.exists(location): | ||||||
|         if self._versions is None: |                 self.report_warning( | ||||||
|             self._versions = dict( |                     'ffmpeg-location %s does not exist! ' | ||||||
|                 (p, get_ffmpeg_version(p)) for p in programs) |                     'Continuing without ffmpeg.' % (location)) | ||||||
|             self._paths = dict((p, p) for p in programs) |                 self._versions = {} | ||||||
|  |                 return | ||||||
|  |             elif os.path.isdir(location): | ||||||
|  |                 dirname, basename = location, None | ||||||
|  |             else: | ||||||
|  |                 basename = os.path.splitext(os.path.basename(location))[0] | ||||||
|  |                 basename = next((p for p in programs if basename.startswith(p)), 'ffmpeg') | ||||||
|  |                 dirname = os.path.dirname(os.path.abspath(location)) | ||||||
|  |                 if basename in ('ffmpeg', 'ffprobe'): | ||||||
|  |                     prefer_ffmpeg = True | ||||||
|  |  | ||||||
|  |             self._paths = dict( | ||||||
|  |                 (p, os.path.join(dirname, p)) for p in programs) | ||||||
|  |             if basename: | ||||||
|  |                 self._paths[basename] = location | ||||||
|  |  | ||||||
|  |         self._versions = {} | ||||||
|  |         for p in programs: | ||||||
|  |             get_ffmpeg_version(self._paths[p], p) | ||||||
|  |  | ||||||
|         if prefer_ffmpeg is False: |         if prefer_ffmpeg is False: | ||||||
|             prefs = ('avconv', 'ffmpeg') |             prefs = ('avconv', 'ffmpeg') | ||||||
| @@ -382,7 +387,9 @@ class FFmpegExtractAudioPP(FFmpegPostProcessor): | |||||||
|  |  | ||||||
|         limits = { |         limits = { | ||||||
|             'libmp3lame': (10, 0), |             'libmp3lame': (10, 0), | ||||||
|             'aac': (0.1, 11), |             # FFmpeg's AAC encoder does not have an upper limit for the value of -q:a. | ||||||
|  |             # Experimentally, with values over 4, bitrate changes were minimal or non-existent | ||||||
|  |             'aac': (0.1, 4), | ||||||
|             'vorbis': (0, 10), |             'vorbis': (0, 10), | ||||||
|             'opus': None,  # doesn't support -q:a |             'opus': None,  # doesn't support -q:a | ||||||
|             'wav': None, |             'wav': None, | ||||||
|   | |||||||
| @@ -4007,10 +4007,7 @@ def check_executable(exe, args=[]): | |||||||
|     return exe |     return exe | ||||||
|  |  | ||||||
|  |  | ||||||
| def get_exe_version(exe, args=['--version'], | def _get_exe_version_output(exe, args): | ||||||
|                     version_re=None, unrecognized='present'): |  | ||||||
|     """ Returns the version of the specified executable, |  | ||||||
|     or False if the executable is not present """ |  | ||||||
|     try: |     try: | ||||||
|         # STDIN should be redirected too. On UNIX-like systems, ffmpeg triggers |         # STDIN should be redirected too. On UNIX-like systems, ffmpeg triggers | ||||||
|         # SIGTTOU if yt-dlp is run in the background. |         # SIGTTOU if yt-dlp is run in the background. | ||||||
| @@ -4022,7 +4019,7 @@ def get_exe_version(exe, args=['--version'], | |||||||
|         return False |         return False | ||||||
|     if isinstance(out, bytes):  # Python 2.x |     if isinstance(out, bytes):  # Python 2.x | ||||||
|         out = out.decode('ascii', 'ignore') |         out = out.decode('ascii', 'ignore') | ||||||
|     return detect_exe_version(out, version_re, unrecognized) |     return out | ||||||
|  |  | ||||||
|  |  | ||||||
| def detect_exe_version(output, version_re=None, unrecognized='present'): | def detect_exe_version(output, version_re=None, unrecognized='present'): | ||||||
| @@ -4036,6 +4033,14 @@ def detect_exe_version(output, version_re=None, unrecognized='present'): | |||||||
|         return unrecognized |         return unrecognized | ||||||
|  |  | ||||||
|  |  | ||||||
|  | def get_exe_version(exe, args=['--version'], | ||||||
|  |                     version_re=None, unrecognized='present'): | ||||||
|  |     """ Returns the version of the specified executable, | ||||||
|  |     or False if the executable is not present """ | ||||||
|  |     out = _get_exe_version_output(exe, args) | ||||||
|  |     return detect_exe_version(out, version_re, unrecognized) if out else False | ||||||
|  |  | ||||||
|  |  | ||||||
| class LazyList(collections.abc.Sequence): | class LazyList(collections.abc.Sequence): | ||||||
|     ''' Lazy immutable list from an iterable |     ''' Lazy immutable list from an iterable | ||||||
|     Note that slices of a LazyList are lists and not LazyList''' |     Note that slices of a LazyList are lists and not LazyList''' | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user
	 pukkandan
					pukkandan