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.
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.