From 959ffaba25523c408273495bd28be2d065b88dd1 Mon Sep 17 00:00:00 2001 From: j Date: Thu, 16 Nov 2017 16:39:38 +0100 Subject: [PATCH] use ffmpeg to merge mp4 files, support clip extraction from multiple parts --- pandora/item/models.py | 23 +++++++++++++++-------- pandora/item/views.py | 14 ++++++++++++-- 2 files changed, 27 insertions(+), 10 deletions(-) diff --git a/pandora/item/models.py b/pandora/item/models.py index a0de7112..df9e7930 100644 --- a/pandora/item/models.py +++ b/pandora/item/models.py @@ -498,14 +498,21 @@ class Item(models.Model): p.wait() return True elif format == "mp4": - fd, tmp_output = tempfile.mkstemp('.mp4') - shutil.copy(streams[0], tmp_output) - for s in streams[1:]: - cmd = ['MP4Box', '-cat', s, tmp_output] - p = subprocess.Popen(cmd, stdout=open('/dev/null', 'w'), stderr=open('/dev/null', 'w'), close_fds=True) - p.wait() - shutil.copy(tmp_output, output) - os.unlink(tmp_output) + fd, tmp_output_txt = tempfile.mkstemp('.txt') + with open(tmp_output_txt, 'w') as f: + f.write('\n'.join(["file '{}'".format(path) for path in streams])) + cmd = [ + settings.FFMPEG, + '-nostats', '-loglevel', 'error', + '-y', + '-f', 'concat', '-safe', '0', '-i', tmp_output_txt, + '-c', 'copy', + output + ] + p = subprocess.Popen( + cmd, stdout=open('/dev/null', 'w'), stderr=open('/dev/null', 'w'), close_fds=True) + p.wait() + os.unlink(tmp_output_txt) return True else: return None diff --git a/pandora/item/views.py b/pandora/item/views.py index 70f165af..e8a4e019 100644 --- a/pandora/item/views.py +++ b/pandora/item/views.py @@ -1022,7 +1022,6 @@ def video(request, id, resolution, format, index=None, track=None): path = stream.media.path # server side cutting - # FIXME: this needs to join segments if needed t = request.GET.get('t') if t: def parse_timestamp(s): @@ -1031,8 +1030,19 @@ def video(request, id, resolution, format, index=None, track=None): return float(s) t = list(map(parse_timestamp, t.split(','))) ext = '.%s' % format + duration = stream.info['duration'] + + # multipart request beyond first part, merge parts and chop that + if not index and streams.count() > 1 and stream.info['duration'] < t[1]: + video = NamedTemporaryFile(suffix=ext) + r = item.merge_streams(video.name, resolution, format) + if not r: + return HttpResponseForbidden() + path = video.name + duration = sum(item.json['durations']) + content_type = mimetypes.guess_type(path)[0] - if len(t) == 2 and t[1] > t[0] and stream.info['duration'] >= t[1]: + if len(t) == 2 and t[1] > t[0] and duration >= t[1]: response = HttpResponse(extract.chop(path, t[0], t[1]), content_type=content_type) filename = u"Clip of %s - %s-%s - %s %s%s" % ( item.get('title'),