Package: django-video-encoding
django-video-encodingdjango-video-encoding helps to convert your videos into different formats and resolutions.RequirementsPython 3.6.1 or newerffmpeg and ffprobeInstallationInstall django-video-encodingpipinstalldjango-video-encodingAddvideo_encodingto yourINSTALLED_APPS.IntegrationAdd aVideoFieldand aGenericRelation(Format)to your model.
You can optionally store thewidth,heightanddurationof the video
by supplying the corresponding field names to theVideoField.fromdjango.contrib.contenttypes.fieldsimportGenericRelationfromdjango.dbimportmodelsfromvideo_encoding.fieldsimportVideoFieldfromvideo_encoding.modelsimportFormatclassVideo(models.Model):width=models.PositiveIntegerField(editable=False,null=True)height=models.PositiveIntegerField(editable=False,null=True)duration=models.FloatField(editable=False,null=True)file=VideoField(width_field='width',height_field='height',duration_field='duration')format_set=GenericRelation(Format)To show all converted videos in the admin, you should add theFormatInlineto yourModelAdminfromdjango.contribimportadminfromvideo_encoding.adminimportFormatInlinefrom.modelsimportVideo@admin.register(Video)classVideoAdmin(admin.ModelAdmin):inlines=(FormatInline,)list_dispaly=('get_filename','width','height','duration')fields=('file','width','height','duration')readonly_fields=fieldsThe conversion of the video should be done in a separate process. Typical
options aredjango-rqorcelery. We will usedjango-rqin the
following example. The configuration forceleryis similar.django-video-encodingalready provides a task (convert_all_videos)
for converting all videos on a model.
This task should be triggered when a video was uploaded. Hence we listen to
thepost-savesignal and enqueue the saved instance for processing.# signals.pyfromdjango.db.models.signalsimportpost_savefromdjango.dispatchimportreceiverfromdjango_rqimportenqueuefromvideo_encodingimporttasksfrom.modelsimportVideo@receiver(post_save,sender=Video)defconvert_video(sender,instance,**kwargs):enqueue(tasks.convert_all_videos,instance._meta.app_label,instance._meta.model_name,instance.pk)After a while You can access the converted videos usingvideo=Video.objects.get(...)forformatinvideo.format_set.complete().all():# do somethingGenerate a video thumbnailThe backend provides aget_thumbnail()method to extract a thumbnail from a video.
Here is a basic example on how to generate the thumbnail and store it in the model.# models.pyfromdjango.dbimportmodelsclassVideo(models.Model):width=models.PositiveIntegerField(editable=False,null=True)height=models.PositiveIntegerField(editable=False,null=True)duration=models.FloatField(editable=False,null=True)thumbnail=ImageField(blank=True)file=VideoField(width_field='width',height_field='height',duration_field='duration')format_set=GenericRelation(Format)# tasks.pyfromdjango.core.filesimportFilefromvideo_encoding.backendsimportget_backendfrom.modelsimportVideodefcreate_thumbnail(video_pk):video=Video.objects.get(pk=video_pk)ifnotvideo.file:# no video file attachedreturnifvideo.thumbnail:# thumbnail has already been generatedreturnencoding_backend=get_backend()thumbnail_path=encoding_backend.get_thumbnail(video.file.path)filename=os.path.basename(self.url),try:withopen(thumbnail_path,'rb')asfile_handler:django_file=File(file_handler)video.thumbnail.save(filename,django_file)video.save()finally:os.unlink(thumbnail_path)You should run this method in a separate process by usingdjango-rq,celeryor similar) and enqueue execution from within apost_savesignal.# signals.pyfromdjango.db.models.signalsimportpost_savefromdjango.dispatchimportreceiverfromdjango_rqimportenqueuefrom.importtasksfrom.modelsimportVideo@receiver(post_save,sender=Video)defcreate_thumbnail(sender,instance,**kwargs):enqueue(tasks.create_thumbnail,instance.pk)SignalsDuring the encoding multiple signals are emitted to report the progress.
You can register to the signals as described in theDjango documentation.This simple example demonstrates, on how to update the "video model" once the convertion is finished.# apps.pyfromdjango.appsimportAppConfigclassMyAppConfig(AppConfig):# ...defready(self)->None:from.importsignals# register signals# signals.pyfromtypingimportTypefromdjango.dispatchimportreceiverfromvideo_encodingimportsignalsfrommyapp.modelsimportVideo@receiver(signals.encoding_finished,sender=Video)defmark_as_finished(sender:Type[Video],instance:Video)->None:"""Mark video as "convertion has been finished"."""video.processed=Truevideo.save(update_fields=['processed'])signals.encoding_startedThis is sent before the encoding starts.Argumentssender: Type[models.Model]: Model which contains theVideoField.instance: models.Model): Instance of the model containing theVideoField.signals.encoding_finishedLikeencoding_started(), but sent after the file had been converted into all formats.Argumentssender: Type[models.Model]: Model which contains theVideoField.instance: models.Model): Instance of the model containing theVideoField.signals.format_startedThis is sent before the video is converted to one of the configured formats.Argumentssender: Type[models.Model]: Model which contains theVideoField.instance: models.Model): Instance of the model containing theVideoField.format: Format: The format instance, which will reference the encoded video file.signals.format_finishedLikeformat_finished, but sent after the video encoding process and includes whether the encoding was succesful or not.Argumentssender: Type[models.Model]: Model which contains theVideoField.instance: models.Model): Instance of the model containing theVideoField.format: Format: The format instance, which will reference the encoded video file.result: ConversionResult: Instance ofvideo_encoding.signals.ConversionResultand indicates whether the convertionFAILED,SUCCEEDEDor wasSKIPPED.ConfigurationVIDEO_ENCODING_THREADS(default:1)Defines how many threads should be used for encoding. This may not be supported
by every backend.VIDEO_ENCODING_BACKEND(default:'video_encoding.backends.ffmpeg.FFmpegBackend')Choose the backend for encoding.django-video-encodingonly supportsffmpeg,
but you can implement your own backend. Feel free to pulish your plugin and
submit a pull request.VIDEO_ENCODING_BACKEND_PARAMS(default:{})If your backend requires some special configuration, you can specify them here
asdict.VIDEO_ENCODING_FORMATS(for defaults seevideo_encoding/config.py)This dictionary defines all required encodings and has some resonable defaults.
If you want to customize the formats, you have to specifyname,extensionandparamsfor each format. For exampleVIDEO_ENCODING_FORMATS={'FFmpeg':[{'name':'webm_sd','extension':'webm','params':['-b:v','1000k','-maxrate','1000k','-bufsize','2000k','-codec:v','libvpx','-r','30','-vf','scale=-1:480','-qmin','10','-qmax','42','-codec:a','libvorbis','-b:a','128k','-f','webm',],},]Encoding Backendsvideo_encoding.backends.ffmpeg.FFmpegBackend (default)Backend for usingffmpegandffprobeto convert your videos.OptionsVIDEO_ENCODING_FFMPEG_PATHPath toffmpeg. If no path is provided, the backend useswhichto
locate it.VIDEO_ENCODING_FFPROBE_PATHPath toffprobe. If no path is provided, the backend useswhichto
locate it.Custom BackendYou can implement a custom encoding backend. Create a new class which inherits fromvideo_encoding.backends.base.BaseEncodingBackend.
You must set the propertynameand implement the methodsencode,get_media_infoandget_thumbnail. For further details see the reference implementation:video_encoding.backends.ffmpeg.FFmpegBackend.If you want to open source your backend, follow these steps.create a packages named django-video-encoding-BACKENDNAMEpublish your package topypiSubmit a pull requests with the following changes:add the package toextra_requiresprovide reasonable defaults forVIDEO_ENCODING_FORMATSDevelopmentThis project usespoetryfor packaging and
managing all dependencies andpre-committo runflake8,isort,mypyandblack.Clone this repository and runpoetryinstall
poetryrunpre-commitinstallto create a virtual enviroment containing all dependencies.
Afterwards, You can run the test suite usingpoetryrunpytestThis repository follows theConventional Commitsstyle.Cookiecutter templateThis project was created usingcruftand thecookiecutter-pyprojecttemplate.
In order to update this repository to the latest template version runcruftupdatein the root of this repository.