Add a post processor for joining video parts
This commit is contained in:
parent
1e705ca327
commit
fbbc7df126
@ -2,6 +2,7 @@ import os
|
|||||||
import subprocess
|
import subprocess
|
||||||
import sys
|
import sys
|
||||||
import time
|
import time
|
||||||
|
import io
|
||||||
|
|
||||||
|
|
||||||
from .utils import (
|
from .utils import (
|
||||||
@ -78,15 +79,15 @@ class FFmpegPostProcessor(PostProcessor):
|
|||||||
programs = ['avprobe', 'avconv', 'ffmpeg', 'ffprobe']
|
programs = ['avprobe', 'avconv', 'ffmpeg', 'ffprobe']
|
||||||
return dict((program, executable(program)) for program in programs)
|
return dict((program, executable(program)) for program in programs)
|
||||||
|
|
||||||
def run_ffmpeg_multiple_files(self, input_paths, out_path, opts):
|
def run_ffmpeg_multiple_files(self, input_paths, out_path, opts, input_opts=[]):
|
||||||
if not self._exes['ffmpeg'] and not self._exes['avconv']:
|
if not self._exes['ffmpeg'] and not self._exes['avconv']:
|
||||||
raise FFmpegPostProcessorError(u'ffmpeg or avconv not found. Please install one.')
|
raise FFmpegPostProcessorError(u'ffmpeg or avconv not found. Please install one.')
|
||||||
|
|
||||||
files_cmd = []
|
files_cmd = []
|
||||||
for path in input_paths:
|
for path in input_paths:
|
||||||
files_cmd.extend(['-i', encodeFilename(path)])
|
files_cmd.extend(['-i', encodeFilename(path)])
|
||||||
cmd = ([self._exes['avconv'] or self._exes['ffmpeg'], '-y'] + files_cmd
|
cmd = ([self._exes['avconv'] or self._exes['ffmpeg'], '-y'] +
|
||||||
+ opts +
|
input_opts + files_cmd + opts +
|
||||||
[encodeFilename(self._ffmpeg_filename_argument(out_path))])
|
[encodeFilename(self._ffmpeg_filename_argument(out_path))])
|
||||||
|
|
||||||
if self._downloader.params.get('verbose', False):
|
if self._downloader.params.get('verbose', False):
|
||||||
@ -98,8 +99,8 @@ class FFmpegPostProcessor(PostProcessor):
|
|||||||
msg = stderr.strip().split('\n')[-1]
|
msg = stderr.strip().split('\n')[-1]
|
||||||
raise FFmpegPostProcessorError(msg)
|
raise FFmpegPostProcessorError(msg)
|
||||||
|
|
||||||
def run_ffmpeg(self, path, out_path, opts):
|
def run_ffmpeg(self, path, out_path, opts, input_opts=[]):
|
||||||
self.run_ffmpeg_multiple_files([path], out_path, opts)
|
self.run_ffmpeg_multiple_files([path], out_path, opts, input_opts)
|
||||||
|
|
||||||
def _ffmpeg_filename_argument(self, fn):
|
def _ffmpeg_filename_argument(self, fn):
|
||||||
# ffmpeg broke --, see https://ffmpeg.org/trac/ffmpeg/ticket/2127 for details
|
# ffmpeg broke --, see https://ffmpeg.org/trac/ffmpeg/ticket/2127 for details
|
||||||
@ -509,3 +510,18 @@ class FFmpegMetadataPP(FFmpegPostProcessor):
|
|||||||
os.remove(encodeFilename(filename))
|
os.remove(encodeFilename(filename))
|
||||||
os.rename(encodeFilename(temp_filename), encodeFilename(filename))
|
os.rename(encodeFilename(temp_filename), encodeFilename(filename))
|
||||||
return True, info
|
return True, info
|
||||||
|
|
||||||
|
|
||||||
|
class FFmpegJoinVideos(FFmpegPostProcessor):
|
||||||
|
def join(self, final_video, videos):
|
||||||
|
files_file = u'%s.videos' % final_video
|
||||||
|
with io.open(encodeFilename(files_file), 'w', encoding='utf-8') as f:
|
||||||
|
for video in videos:
|
||||||
|
f.write(u'file \'%s\'\n' % video)
|
||||||
|
self._downloader.to_screen(u'[ffmpeg] Joining video parts, destination: %s' % final_video)
|
||||||
|
try:
|
||||||
|
self.run_ffmpeg(files_file, final_video, ['-c', 'copy'], ['-f', 'concat'])
|
||||||
|
except FFmpegPostProcessorError:
|
||||||
|
return False
|
||||||
|
os.remove(encodeFilename(files_file))
|
||||||
|
return True
|
||||||
|
@ -52,6 +52,7 @@ from .utils import (
|
|||||||
from .extractor import get_info_extractor, gen_extractors
|
from .extractor import get_info_extractor, gen_extractors
|
||||||
from .FileDownloader import FileDownloader
|
from .FileDownloader import FileDownloader
|
||||||
from .version import __version__
|
from .version import __version__
|
||||||
|
from .PostProcessor import FFmpegJoinVideos
|
||||||
|
|
||||||
|
|
||||||
class YoutubeDL(object):
|
class YoutubeDL(object):
|
||||||
@ -790,6 +791,16 @@ class YoutubeDL(object):
|
|||||||
parts_files.append(part_filename)
|
parts_files.append(part_filename)
|
||||||
parts_success.append(self.fd._do_download(part_filename, part_info))
|
parts_success.append(self.fd._do_download(part_filename, part_info))
|
||||||
success = all(parts_success)
|
success = all(parts_success)
|
||||||
|
if success:
|
||||||
|
video_joiner = FFmpegJoinVideos(self)
|
||||||
|
join_success = video_joiner.join(filename, parts_files)
|
||||||
|
if not join_success:
|
||||||
|
self.report_error(u'Could not join the video parts')
|
||||||
|
else:
|
||||||
|
self.to_screen(u'[info] Removing video parts')
|
||||||
|
for part_file in parts_files:
|
||||||
|
os.remove(encodeFilename(part_file))
|
||||||
|
success = join_success
|
||||||
except (compat_urllib_error.URLError, compat_http_client.HTTPException, socket.error) as err:
|
except (compat_urllib_error.URLError, compat_http_client.HTTPException, socket.error) as err:
|
||||||
self.report_error(u'unable to download video data: %s' % str(err))
|
self.report_error(u'unable to download video data: %s' % str(err))
|
||||||
return
|
return
|
||||||
|
Loading…
x
Reference in New Issue
Block a user