Search code examples
pythondjangoffmpegdjango-channels

How to compress base64 decoded video data using ffmpeg in django


I want to upload the video/audio file in my django-channels project. So I uploaded video(base64 encoded url) from websocket connection. It is working fine. But now after decoding base64 video data I want to compress that video using ffmpeg.But it showing error like this. ''Raw: No such file or directory'' I used 'AsyncJsonWebsocketConsumer' in consumers.py file.Here is my code: consumers.py:

async def send_file_to_room(self, room_id, dataUrl, filename):
        # decoding base64 data
        format, datastr = dataUrl.split(';base64,')
        ext = format.split('/')[-1]
        file = ContentFile(base64.b64decode(datastr), name=filename)
        print(f'file: {file}')
        # It prints 'Raw content'
        output_file_name = filename + '_temp.' + ext
        ff = f'ffmpeg -i {file} -vf "scale=iw/5:ih/5" {output_file_name}'
        subprocess.run(ff,shell=True) 

May be here ffmpeg can not recognize the file to be compressed. I also tried to solve this using post_save signal.

signals.py:

@receiver(post_save, sender=ChatRoomMessage)
def compress_video_or_audio(sender, instance, created, **kwargs):
    print("Inside signal")
    if created:
        if instance.id is None:
            print("Instance is not present")
        else:
            video_full_path = f'{instance.document.path}'
            print(video_full_path)
   // E:\..\..\..\Personal Chat Room\media\PersonalChatRoom\file\VID_20181219_134306_w5ow8F7.mp4
            output_file_name = filename + '_temp.' + extension
            ff = f'ffmpeg -i {filename} -vf "scale=iw/5:ih/5" {output_file_name}'
            subprocess.run(ff,shell=True)
            instance.document = output_file_name
            instance.save()

It is also causing "E:..\Django\New_Projects\Personal: No such file or directory". How can I solve this issue? Any suggetions.It will be more helpful if it can be compressed before saving the object in database. Thanks in advance.


Solution

  • After some struggle I haved solved the problem here. I don't know either it is a good solution or not but for me it has worked. I have used post_save signal here. So file has been saved allready. I tried instance.document.path first to pass the file path to ffmpeg. But ffmpeg can not recognize the file.

    video_full_path = f'{instance.document.path}'
    print(video_full_path)
    # E:\..\..\..\Personal Chat Room\media\PersonalChatRoom\file\VID_20181219_134306_w5ow8F7.mp4
    

    And the error was:

    "E:..\Django\New_Projects\Personal: No such file or directory"
    

    I think it is because of the space inside 'Personal Chat Room'. Later I tried with

    media_in = instance.document.url
    print(media_in)
    # /media/PersonalChatRoom-2/file/VID_20181219_134306_jS7H8fL.mp4
    

    Still ffmpeg could not recognize the file inside media. The trick has worked for me is:

    media_in = '.' + instance.document.url
    print(media_in)
    # ./media/PersonalChatRoom-2/file/VID_20181219_134306_jS7H8fL.mp4
    filename, extension = os.path.splitext(media_in)
    media_out = filename + '_temp' + extension
    print(media_out)
    # ./media/PersonalChatRoom-2/file/VID_20181219_134306_jS7H8fL_temp.mp4
    subprocess.run('ffmpeg -i ' + media_in + ' -vf "scale=iw/4:ih/4" ' +  media_out,  shell=True)
    

    Now this time ffmpeg recognized the file and output is saved in the media/. Next problem I had faced that,

    instance.document = media_out
    instance.save()
    print(instance.document.url)
    # /media/media/PersonalChatRoom-1/file/VID_20181219_134306_jS7H8fL_temp.mp4
    

    browser is not able to find out the file from the location because after saving extra '/media/' has added with the path. To solve this,

    output_file_name = media_out.split('./media/')[-1]
    print(output_file_name)
    # PersonalChatRoom-1/file/VID_20181219_134306_jS7H8fL_temp.mp4
    ...
    ...
    instance.document = output_file_name
    instance.save()
    

    This time it works perfectly.

    Full code: signals.py:

    from django.db.models.signals import post_save, pre_save
    from django.dispatch import receiver
    
    import os
    import subprocess
    
    from chat.models import ChatRoomMessage
    
    @receiver(post_save, sender=ChatRoomMessage)
    def compress_video_or_audio(sender, instance, created, **kwargs):
        if created:
            if instance.id is None:
                print("Instance is not present")
            else:
                media_in = '.' + instance.document.url
                filename, extension = os.path.splitext(media_in)
                media_out = filename + '_temp' + extension
                output_file_name = media_out.split('./media/')[-1]
                subprocess.run('ffmpeg -i ' + media_in + ' -vf "scale=iw/4:ih/4" ' +  media_out, shell=True)
                instance.document = output_file_name
                instance.save()
               
    

    The answer is given here, to compress the video file after saving object(still don't know how to do it before saving).So there are two video files created inside media folder for each object. The object.document.url is referencing 2nd one now. So, first one can be deleted later.