Add a post processor for joining video parts

This commit is contained in:
Jaime Marquínez Ferrándiz 2013-07-05 11:23:29 +02:00
parent 1e705ca327
commit fbbc7df126
2 changed files with 32 additions and 5 deletions

View File

@ -2,6 +2,7 @@ import os
import subprocess
import sys
import time
import io
from .utils import (
@ -78,15 +79,15 @@ class FFmpegPostProcessor(PostProcessor):
programs = ['avprobe', 'avconv', 'ffmpeg', 'ffprobe']
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']:
raise FFmpegPostProcessorError(u'ffmpeg or avconv not found. Please install one.')
files_cmd = []
for path in input_paths:
files_cmd.extend(['-i', encodeFilename(path)])
cmd = ([self._exes['avconv'] or self._exes['ffmpeg'], '-y'] + files_cmd
+ opts +
cmd = ([self._exes['avconv'] or self._exes['ffmpeg'], '-y'] +
input_opts + files_cmd + opts +
[encodeFilename(self._ffmpeg_filename_argument(out_path))])
if self._downloader.params.get('verbose', False):
@ -98,8 +99,8 @@ class FFmpegPostProcessor(PostProcessor):
msg = stderr.strip().split('\n')[-1]
raise FFmpegPostProcessorError(msg)
def run_ffmpeg(self, path, out_path, opts):
self.run_ffmpeg_multiple_files([path], out_path, opts)
def run_ffmpeg(self, path, out_path, opts, input_opts=[]):
self.run_ffmpeg_multiple_files([path], out_path, opts, input_opts)
def _ffmpeg_filename_argument(self, fn):
# ffmpeg broke --, see https://ffmpeg.org/trac/ffmpeg/ticket/2127 for details
@ -509,3 +510,18 @@ class FFmpegMetadataPP(FFmpegPostProcessor):
os.remove(encodeFilename(filename))
os.rename(encodeFilename(temp_filename), encodeFilename(filename))
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

View File

@ -52,6 +52,7 @@ from .utils import (
from .extractor import get_info_extractor, gen_extractors
from .FileDownloader import FileDownloader
from .version import __version__
from .PostProcessor import FFmpegJoinVideos
class YoutubeDL(object):
@ -790,6 +791,16 @@ class YoutubeDL(object):
parts_files.append(part_filename)
parts_success.append(self.fd._do_download(part_filename, part_info))
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:
self.report_error(u'unable to download video data: %s' % str(err))
return