Merge pull request #8611 from remitamine/ffmpegfd
[downloader/external] Add FFmpegFD
This commit is contained in:
		
						commit
						2e7e561c1d
					
				
					 4 changed files with 122 additions and 78 deletions
				
			
		| 
						 | 
					@ -1,14 +1,16 @@
 | 
				
			||||||
from __future__ import unicode_literals
 | 
					from __future__ import unicode_literals
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from .common import FileDownloader
 | 
					from .common import FileDownloader
 | 
				
			||||||
from .external import get_external_downloader
 | 
					 | 
				
			||||||
from .f4m import F4mFD
 | 
					from .f4m import F4mFD
 | 
				
			||||||
from .hls import HlsFD
 | 
					from .hls import HlsFD
 | 
				
			||||||
from .hls import NativeHlsFD
 | 
					 | 
				
			||||||
from .http import HttpFD
 | 
					from .http import HttpFD
 | 
				
			||||||
from .rtsp import RtspFD
 | 
					 | 
				
			||||||
from .rtmp import RtmpFD
 | 
					from .rtmp import RtmpFD
 | 
				
			||||||
from .dash import DashSegmentsFD
 | 
					from .dash import DashSegmentsFD
 | 
				
			||||||
 | 
					from .rtsp import RtspFD
 | 
				
			||||||
 | 
					from .external import (
 | 
				
			||||||
 | 
					    get_external_downloader,
 | 
				
			||||||
 | 
					    FFmpegFD,
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from ..utils import (
 | 
					from ..utils import (
 | 
				
			||||||
    determine_protocol,
 | 
					    determine_protocol,
 | 
				
			||||||
| 
						 | 
					@ -16,8 +18,8 @@ from ..utils import (
 | 
				
			||||||
 | 
					
 | 
				
			||||||
PROTOCOL_MAP = {
 | 
					PROTOCOL_MAP = {
 | 
				
			||||||
    'rtmp': RtmpFD,
 | 
					    'rtmp': RtmpFD,
 | 
				
			||||||
    'm3u8_native': NativeHlsFD,
 | 
					    'm3u8_native': HlsFD,
 | 
				
			||||||
    'm3u8': HlsFD,
 | 
					    'm3u8': FFmpegFD,
 | 
				
			||||||
    'mms': RtspFD,
 | 
					    'mms': RtspFD,
 | 
				
			||||||
    'rtsp': RtspFD,
 | 
					    'rtsp': RtspFD,
 | 
				
			||||||
    'f4m': F4mFD,
 | 
					    'f4m': F4mFD,
 | 
				
			||||||
| 
						 | 
					@ -30,14 +32,17 @@ def get_suitable_downloader(info_dict, params={}):
 | 
				
			||||||
    protocol = determine_protocol(info_dict)
 | 
					    protocol = determine_protocol(info_dict)
 | 
				
			||||||
    info_dict['protocol'] = protocol
 | 
					    info_dict['protocol'] = protocol
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    # if (info_dict.get('start_time') or info_dict.get('end_time')) and not info_dict.get('requested_formats') and FFmpegFD.can_download(info_dict):
 | 
				
			||||||
 | 
					    #     return FFmpegFD
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    external_downloader = params.get('external_downloader')
 | 
					    external_downloader = params.get('external_downloader')
 | 
				
			||||||
    if external_downloader is not None:
 | 
					    if external_downloader is not None:
 | 
				
			||||||
        ed = get_external_downloader(external_downloader)
 | 
					        ed = get_external_downloader(external_downloader)
 | 
				
			||||||
        if ed.supports(info_dict):
 | 
					        if ed.can_download(info_dict):
 | 
				
			||||||
            return ed
 | 
					            return ed
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if protocol == 'm3u8' and params.get('hls_prefer_native'):
 | 
					    if protocol == 'm3u8' and params.get('hls_prefer_native'):
 | 
				
			||||||
        return NativeHlsFD
 | 
					        return HlsFD
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return PROTOCOL_MAP.get(protocol, HttpFD)
 | 
					    return PROTOCOL_MAP.get(protocol, HttpFD)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -2,8 +2,11 @@ from __future__ import unicode_literals
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import os.path
 | 
					import os.path
 | 
				
			||||||
import subprocess
 | 
					import subprocess
 | 
				
			||||||
 | 
					import sys
 | 
				
			||||||
 | 
					import re
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from .common import FileDownloader
 | 
					from .common import FileDownloader
 | 
				
			||||||
 | 
					from ..postprocessor.ffmpeg import FFmpegPostProcessor, EXT_TO_OUT_FORMATS
 | 
				
			||||||
from ..utils import (
 | 
					from ..utils import (
 | 
				
			||||||
    cli_option,
 | 
					    cli_option,
 | 
				
			||||||
    cli_valueless_option,
 | 
					    cli_valueless_option,
 | 
				
			||||||
| 
						 | 
					@ -11,6 +14,8 @@ from ..utils import (
 | 
				
			||||||
    cli_configuration_args,
 | 
					    cli_configuration_args,
 | 
				
			||||||
    encodeFilename,
 | 
					    encodeFilename,
 | 
				
			||||||
    encodeArgument,
 | 
					    encodeArgument,
 | 
				
			||||||
 | 
					    handle_youtubedl_headers,
 | 
				
			||||||
 | 
					    check_executable,
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -45,10 +50,18 @@ class ExternalFD(FileDownloader):
 | 
				
			||||||
    def exe(self):
 | 
					    def exe(self):
 | 
				
			||||||
        return self.params.get('external_downloader')
 | 
					        return self.params.get('external_downloader')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @classmethod
 | 
				
			||||||
 | 
					    def available(cls):
 | 
				
			||||||
 | 
					        return check_executable(cls.get_basename(), [cls.AVAILABLE_OPT])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @classmethod
 | 
					    @classmethod
 | 
				
			||||||
    def supports(cls, info_dict):
 | 
					    def supports(cls, info_dict):
 | 
				
			||||||
        return info_dict['protocol'] in ('http', 'https', 'ftp', 'ftps')
 | 
					        return info_dict['protocol'] in ('http', 'https', 'ftp', 'ftps')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @classmethod
 | 
				
			||||||
 | 
					    def can_download(cls, info_dict):
 | 
				
			||||||
 | 
					        return cls.available() and cls.supports(info_dict)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def _option(self, command_option, param):
 | 
					    def _option(self, command_option, param):
 | 
				
			||||||
        return cli_option(self.params, command_option, param)
 | 
					        return cli_option(self.params, command_option, param)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -76,6 +89,8 @@ class ExternalFD(FileDownloader):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class CurlFD(ExternalFD):
 | 
					class CurlFD(ExternalFD):
 | 
				
			||||||
 | 
					    AVAILABLE_OPT = '-V'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def _make_cmd(self, tmpfilename, info_dict):
 | 
					    def _make_cmd(self, tmpfilename, info_dict):
 | 
				
			||||||
        cmd = [self.exe, '--location', '-o', tmpfilename]
 | 
					        cmd = [self.exe, '--location', '-o', tmpfilename]
 | 
				
			||||||
        for key, val in info_dict['http_headers'].items():
 | 
					        for key, val in info_dict['http_headers'].items():
 | 
				
			||||||
| 
						 | 
					@ -89,6 +104,8 @@ class CurlFD(ExternalFD):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class AxelFD(ExternalFD):
 | 
					class AxelFD(ExternalFD):
 | 
				
			||||||
 | 
					    AVAILABLE_OPT = '-V'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def _make_cmd(self, tmpfilename, info_dict):
 | 
					    def _make_cmd(self, tmpfilename, info_dict):
 | 
				
			||||||
        cmd = [self.exe, '-o', tmpfilename]
 | 
					        cmd = [self.exe, '-o', tmpfilename]
 | 
				
			||||||
        for key, val in info_dict['http_headers'].items():
 | 
					        for key, val in info_dict['http_headers'].items():
 | 
				
			||||||
| 
						 | 
					@ -99,6 +116,8 @@ class AxelFD(ExternalFD):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class WgetFD(ExternalFD):
 | 
					class WgetFD(ExternalFD):
 | 
				
			||||||
 | 
					    AVAILABLE_OPT = '--version'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def _make_cmd(self, tmpfilename, info_dict):
 | 
					    def _make_cmd(self, tmpfilename, info_dict):
 | 
				
			||||||
        cmd = [self.exe, '-O', tmpfilename, '-nv', '--no-cookies']
 | 
					        cmd = [self.exe, '-O', tmpfilename, '-nv', '--no-cookies']
 | 
				
			||||||
        for key, val in info_dict['http_headers'].items():
 | 
					        for key, val in info_dict['http_headers'].items():
 | 
				
			||||||
| 
						 | 
					@ -112,6 +131,8 @@ class WgetFD(ExternalFD):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class Aria2cFD(ExternalFD):
 | 
					class Aria2cFD(ExternalFD):
 | 
				
			||||||
 | 
					    AVAILABLE_OPT = '-v'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def _make_cmd(self, tmpfilename, info_dict):
 | 
					    def _make_cmd(self, tmpfilename, info_dict):
 | 
				
			||||||
        cmd = [self.exe, '-c']
 | 
					        cmd = [self.exe, '-c']
 | 
				
			||||||
        cmd += self._configuration_args([
 | 
					        cmd += self._configuration_args([
 | 
				
			||||||
| 
						 | 
					@ -130,12 +151,85 @@ class Aria2cFD(ExternalFD):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class HttpieFD(ExternalFD):
 | 
					class HttpieFD(ExternalFD):
 | 
				
			||||||
 | 
					    @classmethod
 | 
				
			||||||
 | 
					    def available(cls):
 | 
				
			||||||
 | 
					        return check_executable('http', ['--version'])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def _make_cmd(self, tmpfilename, info_dict):
 | 
					    def _make_cmd(self, tmpfilename, info_dict):
 | 
				
			||||||
        cmd = ['http', '--download', '--output', tmpfilename, info_dict['url']]
 | 
					        cmd = ['http', '--download', '--output', tmpfilename, info_dict['url']]
 | 
				
			||||||
        for key, val in info_dict['http_headers'].items():
 | 
					        for key, val in info_dict['http_headers'].items():
 | 
				
			||||||
            cmd += ['%s:%s' % (key, val)]
 | 
					            cmd += ['%s:%s' % (key, val)]
 | 
				
			||||||
        return cmd
 | 
					        return cmd
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class FFmpegFD(ExternalFD):
 | 
				
			||||||
 | 
					    @classmethod
 | 
				
			||||||
 | 
					    def supports(cls, info_dict):
 | 
				
			||||||
 | 
					        return info_dict['protocol'] in ('http', 'https', 'ftp', 'ftps', 'm3u8', 'rtsp', 'rtmp', 'mms')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @classmethod
 | 
				
			||||||
 | 
					    def available(cls):
 | 
				
			||||||
 | 
					        return FFmpegPostProcessor().available
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def _call_downloader(self, tmpfilename, info_dict):
 | 
				
			||||||
 | 
					        url = info_dict['url']
 | 
				
			||||||
 | 
					        ffpp = FFmpegPostProcessor(downloader=self)
 | 
				
			||||||
 | 
					        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 = [ffpp.executable, '-y']
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        args += self._configuration_args()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        # start_time = info_dict.get('start_time') or 0
 | 
				
			||||||
 | 
					        # if start_time:
 | 
				
			||||||
 | 
					        #     args += ['-ss', compat_str(start_time)]
 | 
				
			||||||
 | 
					        # end_time = info_dict.get('end_time')
 | 
				
			||||||
 | 
					        # if end_time:
 | 
				
			||||||
 | 
					        #     args += ['-t', compat_str(end_time - start_time)]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if info_dict['http_headers'] and re.match(r'^https?://', url):
 | 
				
			||||||
 | 
					            # Trailing \r\n after each HTTP header is important to prevent warning from ffmpeg/avconv:
 | 
				
			||||||
 | 
					            # [http @ 00000000003d2fa0] No trailing CRLF found in HTTP header.
 | 
				
			||||||
 | 
					            headers = handle_youtubedl_headers(info_dict['http_headers'])
 | 
				
			||||||
 | 
					            args += [
 | 
				
			||||||
 | 
					                '-headers',
 | 
				
			||||||
 | 
					                ''.join('%s: %s\r\n' % (key, val) for key, val in headers.items())]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        args += ['-i', url, '-c', 'copy']
 | 
				
			||||||
 | 
					        if info_dict.get('protocol') == 'm3u8':
 | 
				
			||||||
 | 
					            if self.params.get('hls_use_mpegts', False):
 | 
				
			||||||
 | 
					                args += ['-f', 'mpegts']
 | 
				
			||||||
 | 
					            else:
 | 
				
			||||||
 | 
					                args += ['-f', 'mp4', '-bsf:a', 'aac_adtstoasc']
 | 
				
			||||||
 | 
					        else:
 | 
				
			||||||
 | 
					            args += ['-f', EXT_TO_OUT_FORMATS.get(info_dict['ext'], info_dict['ext'])]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        args = [encodeArgument(opt) for opt in args]
 | 
				
			||||||
 | 
					        args.append(encodeFilename(ffpp._ffmpeg_filename_argument(tmpfilename), True))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self._debug_cmd(args)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        proc = subprocess.Popen(args, stdin=subprocess.PIPE)
 | 
				
			||||||
 | 
					        try:
 | 
				
			||||||
 | 
					            retval = proc.wait()
 | 
				
			||||||
 | 
					        except KeyboardInterrupt:
 | 
				
			||||||
 | 
					            # subprocces.run would send the SIGKILL signal to ffmpeg and the
 | 
				
			||||||
 | 
					            # mp4 file couldn't be played, but if we ask ffmpeg to quit it
 | 
				
			||||||
 | 
					            # produces a file that is playable (this is mostly useful for live
 | 
				
			||||||
 | 
					            # streams). Note that Windows is not affected and produces playable
 | 
				
			||||||
 | 
					            # files (see https://github.com/rg3/youtube-dl/issues/8300).
 | 
				
			||||||
 | 
					            if sys.platform != 'win32':
 | 
				
			||||||
 | 
					                proc.communicate(b'q')
 | 
				
			||||||
 | 
					            raise
 | 
				
			||||||
 | 
					        return retval
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class AVconvFD(FFmpegFD):
 | 
				
			||||||
 | 
					    pass
 | 
				
			||||||
 | 
					
 | 
				
			||||||
_BY_NAME = dict(
 | 
					_BY_NAME = dict(
 | 
				
			||||||
    (klass.get_basename(), klass)
 | 
					    (klass.get_basename(), klass)
 | 
				
			||||||
    for name, klass in globals().items()
 | 
					    for name, klass in globals().items()
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,87 +1,19 @@
 | 
				
			||||||
from __future__ import unicode_literals
 | 
					from __future__ import unicode_literals
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import os
 | 
					import os.path
 | 
				
			||||||
import re
 | 
					import re
 | 
				
			||||||
import subprocess
 | 
					 | 
				
			||||||
import sys
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
from .common import FileDownloader
 | 
					 | 
				
			||||||
from .fragment import FragmentFD
 | 
					from .fragment import FragmentFD
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from ..compat import compat_urlparse
 | 
					from ..compat import compat_urlparse
 | 
				
			||||||
from ..postprocessor.ffmpeg import FFmpegPostProcessor
 | 
					 | 
				
			||||||
from ..utils import (
 | 
					from ..utils import (
 | 
				
			||||||
    encodeArgument,
 | 
					 | 
				
			||||||
    encodeFilename,
 | 
					    encodeFilename,
 | 
				
			||||||
    sanitize_open,
 | 
					    sanitize_open,
 | 
				
			||||||
    handle_youtubedl_headers,
 | 
					 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class HlsFD(FileDownloader):
 | 
					class HlsFD(FragmentFD):
 | 
				
			||||||
    def real_download(self, filename, info_dict):
 | 
					    """ A limited implementation that does not require ffmpeg """
 | 
				
			||||||
        url = info_dict['url']
 | 
					 | 
				
			||||||
        self.report_destination(filename)
 | 
					 | 
				
			||||||
        tmpfilename = self.temp_name(filename)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        ffpp = FFmpegPostProcessor(downloader=self)
 | 
					 | 
				
			||||||
        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 = [ffpp.executable, '-y']
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        if info_dict['http_headers'] and re.match(r'^https?://', url):
 | 
					 | 
				
			||||||
            # Trailing \r\n after each HTTP header is important to prevent warning from ffmpeg/avconv:
 | 
					 | 
				
			||||||
            # [http @ 00000000003d2fa0] No trailing CRLF found in HTTP header.
 | 
					 | 
				
			||||||
            headers = handle_youtubedl_headers(info_dict['http_headers'])
 | 
					 | 
				
			||||||
            args += [
 | 
					 | 
				
			||||||
                '-headers',
 | 
					 | 
				
			||||||
                ''.join('%s: %s\r\n' % (key, val) for key, val in headers.items())]
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        args += ['-i', url, '-c', 'copy']
 | 
					 | 
				
			||||||
        if self.params.get('hls_use_mpegts', False):
 | 
					 | 
				
			||||||
            args += ['-f', 'mpegts']
 | 
					 | 
				
			||||||
        else:
 | 
					 | 
				
			||||||
            args += ['-f', 'mp4', '-bsf:a', 'aac_adtstoasc']
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        args = [encodeArgument(opt) for opt in args]
 | 
					 | 
				
			||||||
        args.append(encodeFilename(ffpp._ffmpeg_filename_argument(tmpfilename), True))
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        self._debug_cmd(args)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        proc = subprocess.Popen(args, stdin=subprocess.PIPE)
 | 
					 | 
				
			||||||
        try:
 | 
					 | 
				
			||||||
            retval = proc.wait()
 | 
					 | 
				
			||||||
        except KeyboardInterrupt:
 | 
					 | 
				
			||||||
            # subprocces.run would send the SIGKILL signal to ffmpeg and the
 | 
					 | 
				
			||||||
            # mp4 file couldn't be played, but if we ask ffmpeg to quit it
 | 
					 | 
				
			||||||
            # produces a file that is playable (this is mostly useful for live
 | 
					 | 
				
			||||||
            # streams). Note that Windows is not affected and produces playable
 | 
					 | 
				
			||||||
            # files (see https://github.com/rg3/youtube-dl/issues/8300).
 | 
					 | 
				
			||||||
            if sys.platform != 'win32':
 | 
					 | 
				
			||||||
                proc.communicate(b'q')
 | 
					 | 
				
			||||||
            raise
 | 
					 | 
				
			||||||
        if retval == 0:
 | 
					 | 
				
			||||||
            fsize = os.path.getsize(encodeFilename(tmpfilename))
 | 
					 | 
				
			||||||
            self.to_screen('\r[%s] %s bytes' % (args[0], fsize))
 | 
					 | 
				
			||||||
            self.try_rename(tmpfilename, filename)
 | 
					 | 
				
			||||||
            self._hook_progress({
 | 
					 | 
				
			||||||
                'downloaded_bytes': fsize,
 | 
					 | 
				
			||||||
                'total_bytes': fsize,
 | 
					 | 
				
			||||||
                'filename': filename,
 | 
					 | 
				
			||||||
                'status': 'finished',
 | 
					 | 
				
			||||||
            })
 | 
					 | 
				
			||||||
            return True
 | 
					 | 
				
			||||||
        else:
 | 
					 | 
				
			||||||
            self.to_stderr('\n')
 | 
					 | 
				
			||||||
            self.report_error('%s exited with code %d' % (ffpp.basename, retval))
 | 
					 | 
				
			||||||
            return False
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
class NativeHlsFD(FragmentFD):
 | 
					 | 
				
			||||||
    """ A more limited implementation that does not require ffmpeg """
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    FD_NAME = 'hlsnative'
 | 
					    FD_NAME = 'hlsnative'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -25,6 +25,19 @@ from ..utils import (
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					EXT_TO_OUT_FORMATS = {
 | 
				
			||||||
 | 
					    "aac": "adts",
 | 
				
			||||||
 | 
					    "m4a": "ipod",
 | 
				
			||||||
 | 
					    "mka": "matroska",
 | 
				
			||||||
 | 
					    "mkv": "matroska",
 | 
				
			||||||
 | 
					    "mpg": "mpeg",
 | 
				
			||||||
 | 
					    "ogv": "ogg",
 | 
				
			||||||
 | 
					    "ts": "mpegts",
 | 
				
			||||||
 | 
					    "wma": "asf",
 | 
				
			||||||
 | 
					    "wmv": "asf",
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class FFmpegPostProcessorError(PostProcessingError):
 | 
					class FFmpegPostProcessorError(PostProcessingError):
 | 
				
			||||||
    pass
 | 
					    pass
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue