Skip to main content
 首页 » 编程设计

python之我可以在存储视频之前使用 ffmpeg 转换从表单上传的 django 视频吗

2025年05月04日32mfryf

数周以来,我一直在尝试使用 ffmpeg 将用户上传的视频转换为 flv。我使用 heroku 来托管我的网站,并使用 s3boto 将我的静态和媒体文件存储在 amazon S3 上。初始视频文件可以正常上传,但是当我检索视频并运行 celery 任务时(在上传初始视频文件的同一 View 中),新文件不会存储在 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') 

如果需要,我可以添加任何其他信息来帮助我解决问题。

请您参考如下方法:

不确定您是否会从类似的云场景中获得帮助,该场景涉及上传到云 (parse.com) 的媒体文件,这些文件在到达时需要 ffmpeg 处理并将输出 (.mp4) 写回云(通过 Curl 解析)。

参见 paste shellscript当前在 Heroku WEB 进程中运行,可以使用 CLI 调用脚本。

如果您可以调整它,以便 shellscript 在某个进程中运行,该进程具有对输入的 http 访问权限和可以写入临时文件的文件系统,并且如果您可以 CURL -X POST 一个 ffmpeg.output 从 tmp FS 返回到S3,那么它可能对你有用。