我已经被困了几个星期,试图使用ffmpeg将用户上传的视频转换为flv。我使用heroku来托管我的网站,并使用s3boto将我的静态和媒体文件存储在amazon S3上。初始视频文件将正常上传,但是当我检索视频并运行芹菜任务时(在上载初始视频文件的同一视图中),新文件将不会存储在S3上。我一直试图让这个工作超过一个月,没有运气,并且没有很好的资源可用于学习如何做到这一点,所以我想也许我可以在存储视频之前运行ffmpeg任务我也许能够让它发挥作用。不幸的是,我仍然不是一个非常先进的python(或django),所以我甚至不知道这是否可行。有人有主意吗?我愿意在这一点上使用任何解决方案,无论多么难看,只要它成功进行视频上传并使用ffmpeg转换为flv,结果文件存储在S3上。我的情况似乎并不常见,因为无论我在哪里,我找不到解释我应该尝试做什么的解决方案。因此,我将非常感谢任何指导。谢谢。我的相关代码如下:
#models.py
def content_file_name(instance, filename):
ext = filename.split('.')[-1]
new_file_name = "remove%s.%s" % (uuid.uuid4(), ext)
return '/'.join(['videos', instance.teacher.username, new_file_name])
class BroadcastUpload(models.Model):
title = models.CharField(max_length=50, verbose_name=_('Title'))
description = models.TextField(max_length=100, verbose_name=_('Description'))
teacher = models.ForeignKey(User, null=True, blank=True, related_name='teacher')
created_date = models.DateTimeField(auto_now_add=True)
video_upload = models.FileField(upload_to=content_file_name)
flvfilename = models.CharField(max_length=100, null=True, blank=True)
videothumbnail = models.CharField(max_length=100, null=True, blank=True)
#tasks.py
@task(name='celeryfiles.tasks.convert_flv')
def convert_flv(video_id):
video = BroadcastUpload.objects.get(pk=video_id)
print "ID: %s" % video.id
id = video.id
print "VIDEO NAME: %s" % video.video_upload.name
teacher = video.teacher
print "TEACHER: %s" % teacher
filename = video.video_upload
sourcefile = "%s%s" % (settings.MEDIA_URL, filename)
vidfilename = "%s_%s.flv" % (teacher, video.id)
targetfile = "%svideos/flv/%s" % (settings.MEDIA_URL, vidfilename)
ffmpeg = "ffmpeg -i %s %s" % (sourcefile, vidfilename)
try:
ffmpegresult = subprocess.call(ffmpeg)
#also tried separately with following line:
#ffmpegresult = commands.getoutput(ffmpeg)
print "---------------FFMPEG---------------"
print "FFMPEGRESULT: %s" % ffmpegresult
except Exception as e:
ffmpegresult = None
print("Failed to convert video file %s to %s" % (sourcefile, targetfile))
print(traceback.format_exc())
video.flvfilename = vidfilename
video.save()
@task(name='celeryfiles.tasks.ffmpeg_image')
def ffmpeg_image(video_id):
video = BroadcastUpload.objects.get(pk=video_id)
print "ID: %s" %video.id
id = video.id
print "VIDEO NAME: %s" % video.video_upload.name
teacher = video.teacher
print "TEACHER: %s" % teacher
filename = video.video_upload
sourcefile = "%s%s" % (settings.MEDIA_URL, filename)
imagefilename = "%s_%s.png" % (teacher, video.id)
thumbnailfilename = "%svideos/flv/%s" % (settings.MEDIA_URL, thumbnailfilename)
grabimage = "ffmpeg -y -i %s -vframes 1 -ss 00:00:02 -an -vcodec png -f rawvideo -s 320x240 %s" % (sourcefile, thumbnailfilename)
try:
videothumbnail = subprocess.call(grabimage)
#also tried separately following line:
#videothumbnail = commands.getoutput(grabimage)
print "---------------IMAGE---------------"
print "VIDEOTHUMBNAIL: %s" % videothumbnail
except Exception as e:
videothumbnail = None
print("Failed to convert video file %s to %s" % (sourcefile, thumbnailfilename))
print(traceback.format_exc())
video.videothumbnail = imagefilename
video.save()
#views.py
def upload_broadcast(request):
if request.method == 'POST':
form = BroadcastUploadForm(request.POST, request.FILES)
if form.is_valid():
upload=form.save()
video_id = upload.id
image_grab = ffmpeg_image.delay(video_id)
video_conversion = convert_flv.delay(video_id)
return HttpResponseRedirect('/current_classes/')
else:
form = BroadcastUploadForm(initial={'teacher': request.user,})
return render_to_response('videos/create_video.html', {'form': form,}, context_instance=RequestContext(request))
#settings.py
DEFAULT_FILE_STORAGE = 'myapp.s3utils.MediaRootS3BotoStorage'
DEFAULT_S3_PATH = "media"
STATICFILES_STORAGE = 'myapp.s3utils.StaticRootS3BotoStorage'
STATIC_S3_PATH = "static"
AWS_STORAGE_BUCKET_NAME = 'my_bucket'
CLOUDFRONT_DOMAIN = 'domain.cloudfront.net'
AWS_ACCESS_KEY_ID = 'MY_KEY_ID'
AWS_SECRET_ACCESS_KEY = 'MY_SECRET_KEY'
MEDIA_ROOT = '/%s/' % DEFAULT_S3_PATH
MEDIA_URL = 'http://%s/%s/' % (CLOUDFRONT_DOMAIN, DEFAULT_S3_PATH)
...
#s3utils.py
from storages.backends.s3boto import S3BotoStorage
from django.utils.functional import SimpleLazyObject
StaticRootS3BotoStorage = lambda: S3BotoStorage(location='static')
MediaRootS3BotoStorage = lambda: S3BotoStorage(location='media')
如果需要,我可以添加任何其他信息来帮助我解决问题。
答案 0 :(得分:0)
不确定您是否从涉及上传到云(parse.com)的媒体文件的类似云场景获得帮助,这些场景需要在到达时使用ffmpeg进程并将输出(.mp4)写回到Cloud(通过Curl解析)。 / p>
请参阅当前在Heroku WEB进程中运行的paste shellscript,该进程可以使用CLI调用脚本。
如果你可以对它进行调整,那么shellcript会在某个进程中运行,该进程具有对输入的http访问权限,以及可以写入临时文件的文件系统,如果你可以将tmp FS中的ffmpeg.output从CURL -X POST回到S3,那么它可能对你有用。
答案 1 :(得分:0)
而不是使用settings.Media_url使用media_root
答案 2 :(得分:0)
为了将subprocess.call与包含所有参数的字符串一起使用,您 需要添加shell=True:
ffmpegresult = subprocess.call(ffmpeg, shell=True)
...
videothumbnail = subprocess.call(grabimage, shell=True)
答案 3 :(得分:0)
我已对您的代码进行了一些修改,现在它正在运行。 一些问题:
以下是代码:
from django.contrib.auth.models import User
def content_file_name(instance, filename):
ext = filename.split('.')[-1]
new_file_name = "remove%s.%s" % (uuid.uuid4(), ext)
return '/'.join(['videos', instance.teacher.username, new_file_name])
class BroadcastUpload(models.Model):
title = models.CharField(max_length=50, verbose_name=_('Title'))
description = models.TextField(max_length=100, verbose_name=_('Description'))
teacher = models.ForeignKey(User, null=True, blank=True, related_name='teacher')
created_date = models.DateTimeField(auto_now_add=True)
video_upload = models.FileField(upload_to=content_file_name)
#flvfilename = models.CharField(max_length=100, null=True, blank=True)
video_flv = models.FileField(upload_to='flv', blank=True)
#videothumbnail = models.CharField(max_length=100, null=True, blank=True)
video_thumbnail = models.FileField(upload_to='thumbs', blank=True)
def __unicode__(self):
return u'%s - %s' % (self.title, self.teacher)
def save(self, *args, **kwargs):
# optional parameter to indicate whether perform
# conversion or not. Defaults to True
do_conversion = kwargs.pop('do_conversion', True)
# do something only when the entry is created
if not self.pk:
super(BroadcastUpload, self).save(*args, **kwargs)
# do something every time the entry is updated
if do_conversion:
ffmpeg_image.delay(self.pk)
convert_flv.delay(self.pk)
# then call the parent save:
super(BroadcastUpload, self).save(*args, **kwargs)
from django.core.files.uploadedfile import SimpleUploadedFile
import tempfile
@task
def convert_flv(video_id):
video = BroadcastUpload.objects.get(pk=video_id)
print "ID: %s" % video.id
id = video.id
print "VIDEO NAME: %s" % video.video_upload.name
teacher = video.teacher
print "TEACHER: %s" % teacher
filename = video.video_upload
#sourcefile = "%s%s" % (settings.MEDIA_URL, filename)
sourcefile = video.video_upload.url
# ffmpeg cannot deal with https?
sourcefile = sourcefile.replace("https","http")
print "sourcefile: %s" % sourcefile
# temporary output image
OUTPUT_VIDEO_EXT = 'flv'
OUTPUT_VIDEO_CONTENT_TYPE = 'video/flv'
f_out = tempfile.NamedTemporaryFile(suffix=".%s"%OUTPUT_VIDEO_EXT, delete=False)
tmp_output_video = f_out.name
#ffmpeg = "ffmpeg -i '%s' -qscale 0 -ar 44100 '%s'" % (sourcefile, vidfilename)
ffmpeg = "ffmpeg -y -i '%s' -qscale 0 -ar 44100 '%s'" % (sourcefile, tmp_output_video)
print "convert_flv: %s" % ffmpeg
try:
ffmpegresult = subprocess.call(ffmpeg, shell=True)
#also tried separately with following line:
#ffmpegresult = commands.getoutput(ffmpeg)
print "---------------FFMPEG---------------"
print "FFMPEGRESULT: %s" % ffmpegresult
except Exception as e:
ffmpegresult = None
#print("Failed to convert video file %s to %s" % (sourcefile, targetfile))
print("Failed to convert video file %s to %s" % (sourcefile, tmp_output_video))
#print(traceback.format_exc())
print "Error: %s" % e
#vidfilename = "%s_%s.flv" % (teacher, video.id)
vidfilename = "%s_%s.%s" % (teacher, video.id, OUTPUT_VIDEO_EXT)
#targetfile = "%svideos/flv/%s" % (settings.MEDIA_URL, vidfilename)
# prepare an object with the generated temporary image
suf = SimpleUploadedFile(
vidfilename,
f_out.read(),
content_type=OUTPUT_VIDEO_CONTENT_TYPE
)
# upload converted video to S3 and set the name.
# save set to False to avoid infinite loop
video.video_flv.save(
vidfilename,
suf,
save=False
)
# delete temporary output file
print "[convert_flv] removing temporary file: %s" % tmp_output_video
os.remove(tmp_output_video)
#video.flvfilename = vidfilename
# add do_conversion=False to avoid infinite loop.
# update_fields is needed in order to not delete video_thumbnail
# if it did not exist when starting the task
video.save(do_conversion=False, update_fields=['video_flv'])
@task
def ffmpeg_image(video_id):
video = BroadcastUpload.objects.get(pk=video_id)
print "ID: %s" %video.id
id = video.id
print "VIDEO NAME: %s" % video.video_upload.name
teacher = video.teacher
print "TEACHER: %s" % teacher
filename = video.video_upload
#sourcefile = "%s%s" % (settings.MEDIA_URL, filename)
sourcefile = video.video_upload.url
# ffmpeg cannot deal with https?
sourcefile = sourcefile.replace("https","http")
# temporary output image
OUTPUT_IMAGE_EXT = 'png'
OUTPUT_IMAGE_CONTENT_TYPE = 'image/png'
f_out = tempfile.NamedTemporaryFile(suffix=".%s"%OUTPUT_IMAGE_EXT, delete=False)
tmp_output_image = f_out.name
#grabimage = "ffmpeg -y -i '%s' -vframes 1 -ss 00:00:02 -an -vcodec png -f rawvideo -s 320x240 '%s'" % (sourcefile, thumbnailfilename)
grabimage = "ffmpeg -y -i '%s' -vframes 1 -ss 00:00:02 -an -vcodec png -f rawvideo -s 320x240 '%s'" % (sourcefile, tmp_output_image)
print "ffmpeg_image: %s" % grabimage
try:
videothumbnail = subprocess.call(grabimage, shell=True)
#also tried separately following line:
#videothumbnail = commands.getoutput(grabimage)
print "---------------IMAGE---------------"
print "VIDEOTHUMBNAIL: %s" % videothumbnail
except Exception as e:
videothumbnail = None
#print("Failed to extract thumbnail from %s to %s" % (sourcefile, thumbnailfilename))
print("Failed to extract thumbnail from %s to %s" % (sourcefile, tmp_output_image))
#print(traceback.format_exc())
print "Error: %s" % e
#imagefilename = "%s_%s.png" % (teacher, video.id)
imagefilename = "%s_%s.%s" % (teacher, video.id, OUTPUT_IMAGE_EXT)
#thumbnailfilename = "%svideos/flv/%s" % (settings.MEDIA_URL, thumbnailfilename)
#thumbnailfilename = 'thumbnail_image.png'
# prepare an object with the generated temporary image
suf = SimpleUploadedFile(
imagefilename,
f_out.read(),
content_type=OUTPUT_IMAGE_CONTENT_TYPE
)
# upload converted image to S3 and set the name.
# save set to False to avoid infinite loop
video.video_thumbnail.save(
imagefilename,
suf,
save=False
)
# delete temporary output file
print "[ffmpeg_image] removing temporary file: %s" % tmp_output_image
os.remove(tmp_output_image)
#video.videothumbnail = imagefilename
# add do_conversion=False to avoid infinite loop
video.save(do_conversion=False, update_fields=['video_thumbnail'])