Skip to main content

django-video-encoding helps to convert your videos into different formats and resolutions.

Project description

django-video-encoding

PyPI GitHub Workflow Status (master) Coveralls github branch PyPI - Python Version PyPI - License

django-video-encoding helps to convert your videos into different formats and resolutions.

Requirements

  • Python 3.6.1 or newer
  • ffmpeg and ffprobe

Installation

  1. Install django-video-encoding

    pip install django-video-encoding
    
  2. Add video_encoding to your INSTALLED_APPS.

Integration

Add a VideoField and a GenericRelation(Format) to your model. You can optionally store the width, height and duration of the video by supplying the corresponding field names to the VideoField.

from django.contrib.contenttypes.fields import GenericRelation
from django.db import models
from video_encoding.fields import VideoField
from video_encoding.models import Format


class Video(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 the FormatInline to your ModelAdmin

from django.contrib import admin
from video_encoding.admin import FormatInline

from .models import Video


@admin.register(Video)
class VideoAdmin(admin.ModelAdmin):
   inlines = (FormatInline,)

   list_dispaly = ('get_filename', 'width', 'height', 'duration')
   fields = ('file', 'width', 'height', 'duration')
   readonly_fields = fields

The conversion of the video should be done in a separate process. Typical options are django-rq or celery. We will use django-rq in the following example. The configuration for celery is similar. django-video-encoding already 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 the post-save signal and enqueue the saved instance for processing.

# signals.py
from django.db.models.signals import post_save
from django.dispatch import receiver
from django_rq import enqueue

from video_encoding import tasks

from .models import Video


@receiver(post_save, sender=Video)
def convert_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 using

video = Video.objects.get(...)
for format in video.format_set.complete().all():
   # do something

Generate a video thumbnail

The backend provides a get_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.py
from django.db import models

class Video(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.py
from django.core.files import File
from video_encoding.backends import get_backend

from .models import Video


def create_thumbnail(video_pk):
   video = Video.objects.get(pk=video_pk)
   if not video.file:
      # no video file attached
      return

   if video.thumbnail:
      # thumbnail has already been generated
      return

   encoding_backend = get_backend()
   thumbnail_path = encoding_backend.get_thumbnail(video.file.path)
   filename = os.path.basename(self.url),

   try:
      with open(thumbnail_path, 'rb') as file_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 using django-rq, celery or similar) and enqueue execution from within a post_save signal.

# signals.py
from django.db.models.signals import post_save
from django.dispatch import receiver
from django_rq import enqueue

from . import tasks
from .models import Video


@receiver(post_save, sender=Video)
def create_thumbnail(sender, instance, **kwargs):
    enqueue(tasks.create_thumbnail, instance.pk)

Signals

During the encoding multiple signals are emitted to report the progress. You can register to the signals as described in the Django documentation.

This simple example demonstrates, on how to update the "video model" once the convertion is finished.

# apps.py
from django.apps import AppConfig


class MyAppConfig(AppConfig):
   # ...

    def ready(self) -> None:
      from . import signals  # register signals


# signals.py
from typing import Type

from django.dispatch import receiver
from video_encoding import signals

from myapp.models import Video


@receiver(signals.encoding_finished, sender=Video)
def mark_as_finished(sender: Type[Video], instance: Video) -> None:
   """
   Mark video as "convertion has been finished".
   """
   video.processed = True
   video.save(update_fields=['processed'])

signals.encoding_started

This is sent before the encoding starts.

Arguments
sender: Type[models.Model]: Model which contains the VideoField.
instance: models.Model): Instance of the model containing the VideoField.

signals.encoding_finished

Like encoding_started(), but sent after the file had been converted into all formats.

Arguments
sender: Type[models.Model]: Model which contains the VideoField.
instance: models.Model): Instance of the model containing the VideoField.

signals.format_started

This is sent before the video is converted to one of the configured formats.

Arguments
sender: Type[models.Model]: Model which contains the VideoField.
instance: models.Model): Instance of the model containing the VideoField.
format: Format: The format instance, which will reference the encoded video file.

signals.format_finished

Like format_finished, but sent after the video encoding process and includes whether the encoding was succesful or not.

Arguments
sender: Type[models.Model]: Model which contains the VideoField.
instance: models.Model): Instance of the model containing the VideoField.
format: Format: The format instance, which will reference the encoded video file.
result: ConversionResult: Instance of video_encoding.signals.ConversionResult and indicates whether the convertion FAILED, SUCCEEDED or was SKIPPED.

Configuration

VIDEO_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-encoding only supports ffmpeg, 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 as dict.

VIDEO_ENCODING_FORMATS (for defaults see video_encoding/config.py)
This dictionary defines all required encodings and has some resonable defaults. If you want to customize the formats, you have to specify name, extension and params for each format. For example

VIDEO_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 Backends

video_encoding.backends.ffmpeg.FFmpegBackend (default)

Backend for using ffmpeg and ffprobe to convert your videos.

Options

VIDEO_ENCODING_FFMPEG_PATH
Path to ffmpeg. If no path is provided, the backend uses which to locate it. VIDEO_ENCODING_FFPROBE_PATH
Path to ffprobe. If no path is provided, the backend uses which to locate it.

Custom Backend

You can implement a custom encoding backend. Create a new class which inherits from video_encoding.backends.base.BaseEncodingBackend. You must set the property name and implement the methods encode, get_media_info and get_thumbnail. For further details see the reference implementation: video_encoding.backends.ffmpeg.FFmpegBackend.

If you want to open source your backend, follow these steps.

  1. create a packages named django-video-encoding-BACKENDNAME

  2. publish your package to pypi

  3. Submit a pull requests with the following changes:

    • add the package to extra_requires
    • provide reasonable defaults for VIDEO_ENCODING_FORMATS

Development

This project uses poetry for packaging and managing all dependencies and pre-commit to run flake8, isort, mypy and black.

Clone this repository and run

poetry install
poetry run pre-commit install

to create a virtual enviroment containing all dependencies. Afterwards, You can run the test suite using

poetry run pytest

This repository follows the Conventional Commits style.

Cookiecutter template

This project was created using cruft and the cookiecutter-pyproject template. In order to update this repository to the latest template version run

cruft update

in the root of this repository.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

django-video-encoding-1.0.0.tar.gz (18.0 kB view details)

Uploaded Source

Built Distribution

django_video_encoding-1.0.0-py3-none-any.whl (17.7 kB view details)

Uploaded Python 3

File details

Details for the file django-video-encoding-1.0.0.tar.gz.

File metadata

  • Download URL: django-video-encoding-1.0.0.tar.gz
  • Upload date:
  • Size: 18.0 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: poetry/1.1.4 CPython/3.7.5 Linux/5.9.8-arch1-1

File hashes

Hashes for django-video-encoding-1.0.0.tar.gz
Algorithm Hash digest
SHA256 933901782f127200ae63b03b95c846eecec98a5d75cc2db27decbc862692ed49
MD5 b60469c4e7e9b07b4efd92a9dc535e45
BLAKE2b-256 fce514861849efd731b5d6320306bce835c2e831efbe795cc1afa6c92a297cc6

See more details on using hashes here.

File details

Details for the file django_video_encoding-1.0.0-py3-none-any.whl.

File metadata

File hashes

Hashes for django_video_encoding-1.0.0-py3-none-any.whl
Algorithm Hash digest
SHA256 a30fd6e48389d379963965102dc1ae9090394a1ad85e6d0b98091ada2dece658
MD5 035132d950db2111eb770779b72502b9
BLAKE2b-256 5e1e14ea39842be5f77dbefefd22a36ce2fc82fe0b772df2d9ed32d81091dbb7

See more details on using hashes here.

Supported by

AWS AWS Cloud computing and Security Sponsor Datadog Datadog Monitoring Fastly Fastly CDN Google Google Download Analytics Microsoft Microsoft PSF Sponsor Pingdom Pingdom Monitoring Sentry Sentry Error logging StatusPage StatusPage Status page