mirror of
				https://github.com/yt-dlp/yt-dlp.git
				synced 2025-10-31 06:35:12 +00:00 
			
		
		
		
	[youtube|ffmpeg] Automatically correct video with non-square pixels (Fixes #4674)
This commit is contained in:
		| @@ -70,6 +70,7 @@ from .extractor import get_info_extractor, gen_extractors | ||||
| from .downloader import get_suitable_downloader | ||||
| from .downloader.rtmp import rtmpdump_version | ||||
| from .postprocessor import ( | ||||
|     FFmpegFixupStretchedPP, | ||||
|     FFmpegMergerPP, | ||||
|     FFmpegPostProcessor, | ||||
|     get_postprocessor, | ||||
| @@ -204,6 +205,12 @@ class YoutubeDL(object): | ||||
|                        Progress hooks are guaranteed to be called at least once | ||||
|                        (with status "finished") if the download is successful. | ||||
|     merge_output_format: Extension to use when merging formats. | ||||
|     fixup:             Automatically correct known faults of the file. | ||||
|                        One of: | ||||
|                        - "never": do nothing | ||||
|                        - "warn": only emit a warning | ||||
|                        - "detect_or_warn": check whether we can do anything | ||||
|                                            about it, warn otherwise | ||||
|  | ||||
|  | ||||
|     The following parameters are not used by YoutubeDL itself, they are used by | ||||
| @@ -924,6 +931,7 @@ class YoutubeDL(object): | ||||
|                                 'fps': formats_info[0].get('fps'), | ||||
|                                 'vcodec': formats_info[0].get('vcodec'), | ||||
|                                 'vbr': formats_info[0].get('vbr'), | ||||
|                                 'stretched_ratio': formats_info[0].get('stretched_ratio'), | ||||
|                                 'acodec': formats_info[1].get('acodec'), | ||||
|                                 'abr': formats_info[1].get('abr'), | ||||
|                                 'ext': output_ext, | ||||
| @@ -1154,6 +1162,27 @@ class YoutubeDL(object): | ||||
|                     return | ||||
|  | ||||
|             if success: | ||||
|                 # Fixup content | ||||
|                 stretched_ratio = info_dict.get('stretched_ratio') | ||||
|                 if stretched_ratio is not None and stretched_ratio != 1: | ||||
|                     fixup_policy = self.params.get('fixup') | ||||
|                     if fixup_policy is None: | ||||
|                         fixup_policy = 'detect_or_warn' | ||||
|                     if fixup_policy == 'warn': | ||||
|                         self.report_warning('%s: Non-uniform pixel ratio (%s)' % ( | ||||
|                             info_dict['id'], stretched_ratio)) | ||||
|                     elif fixup_policy == 'detect_or_warn': | ||||
|                         stretched_pp = FFmpegFixupStretchedPP(self) | ||||
|                         if stretched_pp.available: | ||||
|                             info_dict.setdefault('__postprocessors', []) | ||||
|                             info_dict['__postprocessors'].append(stretched_pp) | ||||
|                         else: | ||||
|                             self.report_warning( | ||||
|                                 '%s: Non-uniform pixel ratio (%s). Install ffmpeg or avconv to fix this automatically.' % ( | ||||
|                                     info_dict['id'], stretched_ratio)) | ||||
|                     else: | ||||
|                         assert fixup_policy == 'ignore' | ||||
|  | ||||
|                 try: | ||||
|                     self.post_process(filename, info_dict) | ||||
|                 except (PostProcessingError) as err: | ||||
|   | ||||
| @@ -326,6 +326,7 @@ def _real_main(argv=None): | ||||
|         'extract_flat': opts.extract_flat, | ||||
|         'merge_output_format': opts.merge_output_format, | ||||
|         'postprocessors': postprocessors, | ||||
|         'fixup': opts.fixup, | ||||
|     } | ||||
|  | ||||
|     with YoutubeDL(ydl_opts) as ydl: | ||||
|   | ||||
| @@ -114,6 +114,9 @@ class InfoExtractor(object): | ||||
|                                  to add to the request. | ||||
|                     * http_post_data  Additional data to send with a POST | ||||
|                                  request. | ||||
|                     * stretched_ratio  If given and not 1, indicates that the | ||||
|                                        video's pixels are not square. | ||||
|                                        width : height ratio as float. | ||||
|     url:            Final video URL. | ||||
|     ext:            Video filename extension. | ||||
|     format:         The video format, defaults to ext (used for --get-format) | ||||
|   | ||||
| @@ -465,6 +465,20 @@ class YoutubeIE(YoutubeBaseInfoExtractor, SubtitlesInfoExtractor): | ||||
|                 'skip_download': 'requires avconv', | ||||
|             } | ||||
|         }, | ||||
|         # Non-square pixels | ||||
|         { | ||||
|             'url': 'https://www.youtube.com/watch?v=_b-2C3KPAM0', | ||||
|             'info_dict': { | ||||
|                 'id': '_b-2C3KPAM0', | ||||
|                 'ext': 'mp4', | ||||
|                 'stretched_ratio': 16 / 9., | ||||
|                 'upload_date': '20110310', | ||||
|                 'uploader_id': 'AllenMeow', | ||||
|                 'description': 'made by Wacom from Korea | 字幕&加油添醋 by TY\'s Allen | 感謝heylisa00cavey1001同學熱情提供梗及翻譯', | ||||
|                 'uploader': '孫艾倫', | ||||
|                 'title': '[A-made] 變態妍字幕版 太妍 我就是這樣的人', | ||||
|             }, | ||||
|         } | ||||
|     ] | ||||
|  | ||||
|     def __init__(self, *args, **kwargs): | ||||
| @@ -1051,6 +1065,16 @@ class YoutubeIE(YoutubeBaseInfoExtractor, SubtitlesInfoExtractor): | ||||
|                             f['preference'] = f.get('preference', 0) - 10000 | ||||
|                     formats.extend(dash_formats) | ||||
|  | ||||
|         # Check for malformed aspect ratio | ||||
|         stretched_m = re.search( | ||||
|             r'<meta\s+property="og:video:tag".*?content="yt:stretch=(?P<w>[0-9]+):(?P<h>[0-9]+)">', | ||||
|             video_webpage) | ||||
|         if stretched_m: | ||||
|             ratio = float(stretched_m.group('w')) / float(stretched_m.group('h')) | ||||
|             for f in formats: | ||||
|                 if f.get('vcodec') != 'none': | ||||
|                     f['stretched_ratio'] = ratio | ||||
|  | ||||
|         self._sort_formats(formats) | ||||
|  | ||||
|         return { | ||||
|   | ||||
| @@ -631,6 +631,13 @@ def parseOpts(overrideArguments=None): | ||||
|         '--xattrs', | ||||
|         action='store_true', dest='xattrs', default=False, | ||||
|         help='write metadata to the video file\'s xattrs (using dublin core and xdg standards)') | ||||
|     postproc.add_option( | ||||
|         '--fixup', | ||||
|         metavar='POLICY', dest='fixup', default='detect_or_warn', | ||||
|         help='(experimental) Automatically correct known faults of the file. ' | ||||
|              'One of never (do nothing), warn (only emit a warning), ' | ||||
|              'detect_or_warn(check whether we can do anything about it, warn ' | ||||
|              'otherwise') | ||||
|     postproc.add_option( | ||||
|         '--prefer-avconv', | ||||
|         action='store_false', dest='prefer_ffmpeg', | ||||
|   | ||||
| @@ -6,6 +6,7 @@ from .ffmpeg import ( | ||||
|     FFmpegAudioFixPP, | ||||
|     FFmpegEmbedSubtitlePP, | ||||
|     FFmpegExtractAudioPP, | ||||
|     FFmpegFixupStretchedPP, | ||||
|     FFmpegMergerPP, | ||||
|     FFmpegMetadataPP, | ||||
|     FFmpegVideoConvertorPP, | ||||
| @@ -24,6 +25,7 @@ __all__ = [ | ||||
|     'FFmpegAudioFixPP', | ||||
|     'FFmpegEmbedSubtitlePP', | ||||
|     'FFmpegExtractAudioPP', | ||||
|     'FFmpegFixupStretchedPP', | ||||
|     'FFmpegMergerPP', | ||||
|     'FFmpegMetadataPP', | ||||
|     'FFmpegPostProcessor', | ||||
|   | ||||
| @@ -50,6 +50,10 @@ class FFmpegPostProcessor(PostProcessor): | ||||
|         programs = ['avprobe', 'avconv', 'ffmpeg', 'ffprobe'] | ||||
|         return dict((p, get_exe_version(p, args=['-version'])) for p in programs) | ||||
|  | ||||
|     @property | ||||
|     def available(self): | ||||
|         return self._executable is not None | ||||
|  | ||||
|     @property | ||||
|     def _executable(self): | ||||
|         if self._downloader.params.get('prefer_ffmpeg', False): | ||||
| @@ -540,3 +544,22 @@ class FFmpegAudioFixPP(FFmpegPostProcessor): | ||||
|         os.rename(encodeFilename(temp_filename), encodeFilename(filename)) | ||||
|  | ||||
|         return True, info | ||||
|  | ||||
|  | ||||
| class FFmpegFixupStretchedPP(FFmpegPostProcessor): | ||||
|     def run(self, info): | ||||
|         stretched_ratio = info.get('stretched_ratio') | ||||
|         if stretched_ratio is None or stretched_ratio == 1: | ||||
|             return | ||||
|  | ||||
|         filename = info['filepath'] | ||||
|         temp_filename = prepend_extension(filename, 'temp') | ||||
|  | ||||
|         options = ['-c', 'copy', '-aspect', '%f' % stretched_ratio] | ||||
|         self._downloader.to_screen('[ffmpeg] Fixing aspect ratio in "%s"' % filename) | ||||
|         self.run_ffmpeg(filename, temp_filename, options) | ||||
|  | ||||
|         os.remove(encodeFilename(filename)) | ||||
|         os.rename(encodeFilename(temp_filename), encodeFilename(filename)) | ||||
|  | ||||
|         return True, info | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 Philipp Hagemeister
					Philipp Hagemeister