added flag to merge videos from a playlist into one continuous file

This commit is contained in:
Anthony Weems 2014-05-01 11:26:21 -05:00
parent b8b01bb92a
commit 2cd5408951
4 changed files with 62 additions and 1 deletions

View File

@ -59,7 +59,7 @@ from .utils import (
)
from .extractor import get_info_extractor, gen_extractors
from .downloader import get_suitable_downloader
from .postprocessor import FFmpegMergerPP
from .postprocessor import FFmpegMergerPP, FFmpegConcatPP
from .version import __version__
@ -645,6 +645,32 @@ class YoutubeDL(object):
extra_info=extra)
playlist_results.append(entry_result)
ie_result['entries'] = playlist_results
if download and not(self.params.get('simulate', False)) and \
self.params.get('concat', False):
downloaded = []
concat = FFmpegConcatPP(self)
if not concat._get_executable():
postprocessors = []
self.report_warning('You have requested multiple '
'formats but ffmpeg or avconv are not installed.'
' The formats won\'t be merged')
else:
postprocessors = [concat]
for f in ie_result['entries']:
new_info = dict(ie_result)
new_info.update(f)
if 'ext' in new_info: ie_result['ext'] = new_info['ext']
if 'id' in new_info: ie_result['id'] = new_info['id']
fname = self.prepare_filename(new_info)
downloaded.append(fname)
filename = self.prepare_filename(ie_result)
ie_result['__postprocessors'] = postprocessors
ie_result['__files_to_merge'] = downloaded
self.post_process(filename, ie_result)
return ie_result
elif result_type == 'compat_list':
def _fixup(r):

View File

@ -500,6 +500,8 @@ def parseOpts(overrideArguments=None):
help='ffmpeg/avconv audio quality specification, insert a value between 0 (better) and 9 (worse) for VBR or a specific bitrate like 128K (default 5)')
postproc.add_option('--recode-video', metavar='FORMAT', dest='recodevideo', default=None,
help='Encode the video to another format if necessary (currently supported: mp4|flv|ogg|webm)')
postproc.add_option('--concat', action='store_true', dest='concat',
help='Attempt to concatenate multiple videos into one file')
postproc.add_option('-k', '--keep-video', action='store_true', dest='keepvideo', default=False,
help='keeps the video file on disk after the post-processing; the video is erased by default')
postproc.add_option('--no-post-overwrites', action='store_true', dest='nopostoverwrites', default=False,
@ -518,6 +520,7 @@ def parseOpts(overrideArguments=None):
help='Prefer ffmpeg over avconv for running the postprocessors')
parser.add_option_group(general)
parser.add_option_group(selection)
parser.add_option_group(downloader)
@ -791,6 +794,7 @@ def _real_main(argv=None):
'bidi_workaround': opts.bidi_workaround,
'debug_printtraffic': opts.debug_printtraffic,
'prefer_ffmpeg': opts.prefer_ffmpeg,
'concat': opts.concat,
'include_ads': opts.include_ads,
'default_search': opts.default_search,
'youtube_include_dash_manifest': opts.youtube_include_dash_manifest,

View File

@ -1,6 +1,7 @@
from .atomicparsley import AtomicParsleyPP
from .ffmpeg import (
FFmpegConcatPP,
FFmpegAudioFixPP,
FFmpegMergerPP,
FFmpegMetadataPP,
@ -12,6 +13,7 @@ from .xattrpp import XAttrMetadataPP
__all__ = [
'AtomicParsleyPP',
'FFmpegConcatPP',
'FFmpegAudioFixPP',
'FFmpegMergerPP',
'FFmpegMetadataPP',

View File

@ -487,6 +487,35 @@ class FFmpegMergerPP(FFmpegPostProcessor):
self.run_ffmpeg_multiple_files(info['__files_to_merge'], filename, args)
return True, info
class FFmpegConcatPP(FFmpegPostProcessor):
def run(self, info):
filename = info['filepath']
args = ['-f', 'concat', '-i', '-', '-c', 'copy']
self._downloader.to_screen(u'[ffmpeg] Concatenating files into "%s"' % filename)
if not self._get_executable():
raise FFmpegPostProcessorError(u'ffmpeg or avconv not found. Please install one.')
cmd = ([self._get_executable(), '-y'] + args +
[encodeFilename(self._ffmpeg_filename_argument(filename), True)])
files = info['__files_to_merge']
if self._downloader.params.get('verbose', False):
self._downloader.to_screen(u'[debug] ffmpeg command line: %s' % shell_quote(cmd))
p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stdin=subprocess.PIPE, stderr=subprocess.PIPE)
files_cmd = u''
for path in files:
encoded_path = encodeFilename(path, True)
files_cmd += u'file \'%s\'\n' % path
stdout, stderr = p.communicate(input=files_cmd)
if p.returncode != 0:
stderr = stderr.decode('utf-8', 'replace')
msg = stderr.strip().split('\n')[-1]
raise FFmpegPostProcessorError(msg)
for path in files:
os.remove(encodeFilename(path))
class FFmpegAudioFixPP(FFmpegPostProcessor):
def run(self, info):