Robin
Robin

Reputation: 5486

Transcode video using celery and ffmpeg in django

I would like to transcode user uploaded videos using celery. I think first I should upload the video, and spawn a celery task for transcoding.

Maybe something like this in the tasks.py:

subprocess.call('ffmpeg -i path/.../original path/.../output')

Just completed First steps with celery, so confused how to do so in the views.py and tasks.py. Also is it a good solution? I would really appreciate your help and advice. Thank you.

models.py:

class Video(models.Model):
    user = models.ForeignKey(User)
    title = models.CharField(max_length=100)
    original = models.FileField(upload_to=get_upload_file_name)
    mp4_480 = models.FileField(upload_to=get_upload_file_name, blank=True, null=True)
    mp4_720 = models.FileField(upload_to=get_upload_file_name, blank=True, null=True)
    privacy = models.CharField(max_length=1,choices=PRIVACY, default='F')
    pub_date = models.DateTimeField(auto_now_add=True, auto_now=False)

my incomplete views.py:

@login_required
def upload_video(request):
    if request.method == 'POST':
        form = VideoForm(request.POST, request.FILES)
        if form.is_valid():
            if form.cleaned_data:
                user = request.user
                #
                #
                # No IDEA WHAT TO DO NEXT
                #
                #
                return HttpResponseRedirect('/')

    else:
        form = VideoForm()
        return render(request, 'upload_video.html', {
            'form':form
            })

Upvotes: 3

Views: 3019

Answers (2)

Mijamo
Mijamo

Reputation: 3516

I guess you already have solved the problem but I will provide a bit more information to what already said GwynBleidD because I had the same issue.

So as GwynBleidD you need to call Celery tasks, but how to code those tasks ? here is the structure :

  1. the task get the video from the database
  2. it encodes it with ffmepg and outputs it anywhere you want
  3. when done with the encoding, it sets the corresponding attribute to the model and saves it (be careful, if you run various tasks on the same video, do not save with the old instance, as you may lose information from other tasks running)

First, set a FFMPEG_PATH variable in your settings, then:

import os, subprocess
from .models import Video

@app.task
def encode_mp4(video_id, height):
    try:
        video = Video.objects.get(id = video_id)
        input_file_path = video.original.path
        input_file_name = video.original.name

        #get the filename (without extension)
        filename = os.path.basename(input_file_path)

        # path to the new file, change it according to where you want to put it
        output_file_name = os.path.join('videos', 'mp4', '{}.mp4'.format(filename))
        output_file_path = os.path.join(settings.MEDIA_ROOT, output_file_name)

        # 2-pass encoding
        for i in range(1):
            subprocess.call([FFMPEG_PATH, '-i', input_file_path, '-s', '{}x{}'.format(height * 16 /9, height), '-vcodec', 'mpeg4', '-acodec', 'libvo_aacenc', '-b', '10000k', '-pass', i, '-r', '30', output_file_path])

        # Save the new file in the database
        video.mp4_720.name = output_file_name
        video.save(update_fields=['mp4_720'])

Upvotes: 1

GwynBleidD
GwynBleidD

Reputation: 20569

Modify your model so you can save original (uploaded) video without transcoded version(s) and maybe add some flag into your model that will save state if video was transcoded (and based on that flag you can display to user that video transcoding is still in progress).

After uploading video and saving it's model to database, run celery task passing ID of your video into it. In celery task retrieve video from database, transcode it and save it into database with changed flag.

Upvotes: 0

Related Questions