{"id":13618000,"url":"https://github.com/escaped/django-video-encoding","last_synced_at":"2025-08-17T01:32:23.887Z","repository":{"id":20251359,"uuid":"84934176","full_name":"escaped/django-video-encoding","owner":"escaped","description":"django-video-encoding helps to convert your videos into different formats and resolutions.","archived":false,"fork":false,"pushed_at":"2024-01-05T09:16:04.000Z","size":5419,"stargazers_count":118,"open_issues_count":14,"forks_count":46,"subscribers_count":9,"default_branch":"master","last_synced_at":"2025-06-27T09:42:21.671Z","etag":null,"topics":["django","django-field","ffmpeg","hacktoberfest","python","video"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"bsd-3-clause","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/escaped.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null},"funding":{"github":["escaped"]}},"created_at":"2017-03-14T10:06:32.000Z","updated_at":"2025-03-19T11:28:39.000Z","dependencies_parsed_at":"2024-01-12T04:50:19.864Z","dependency_job_id":"8182896e-f6ba-484e-9666-708da5a764b7","html_url":"https://github.com/escaped/django-video-encoding","commit_stats":{"total_commits":69,"total_committers":6,"mean_commits":11.5,"dds":"0.14492753623188404","last_synced_commit":"e74f2f6871087bd43cdabd370e9197d6a8805df0"},"previous_names":[],"tags_count":6,"template":false,"template_full_name":null,"purl":"pkg:github/escaped/django-video-encoding","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/escaped%2Fdjango-video-encoding","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/escaped%2Fdjango-video-encoding/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/escaped%2Fdjango-video-encoding/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/escaped%2Fdjango-video-encoding/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/escaped","download_url":"https://codeload.github.com/escaped/django-video-encoding/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/escaped%2Fdjango-video-encoding/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":270796225,"owners_count":24647320,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-08-16T02:00:11.002Z","response_time":91,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["django","django-field","ffmpeg","hacktoberfest","python","video"],"created_at":"2024-08-01T20:01:52.437Z","updated_at":"2025-08-17T01:32:23.858Z","avatar_url":"https://github.com/escaped.png","language":"Python","funding_links":["https://github.com/sponsors/escaped"],"categories":["HarmonyOS","Language and platform specific libraries","Encoding \u0026 Codecs"],"sub_categories":["Windows Manager","Python","Encoding Tools"],"readme":"# django-video-encoding\n\n![PyPI](https://img.shields.io/pypi/v/django-video-encoding?style=flat-square)\n![GitHub Workflow Status (master)](https://img.shields.io/github/workflow/status/escaped/django-video-encoding/Test%20\u0026%20Lint/master?style=flat-square)\n![Coveralls github branch](https://img.shields.io/coveralls/github/escaped/django-video-encoding/master?style=flat-square)\n![PyPI - Python Version](https://img.shields.io/pypi/pyversions/django-video-encoding?style=flat-square)\n![PyPI - License](https://img.shields.io/pypi/l/django-video-encoding?style=flat-square)\n\ndjango-video-encoding helps to convert your videos into different formats and resolutions.\n\n## Requirements\n\n* Python 3.6.1 or newer\n* ffmpeg and ffprobe\n\n## Installation\n\n1. Install django-video-encoding\n\n   ```sh\n   pip install django-video-encoding\n   ```\n\n2. Add `video_encoding` to your `INSTALLED_APPS`.\n\n## Integration\n\nAdd a `VideoField` and a `GenericRelation(Format)` to your model.\nYou can optionally store the `width`, `height` and `duration` of the video\nby supplying the corresponding field names to the `VideoField`.\n\n```python\nfrom django.contrib.contenttypes.fields import GenericRelation\nfrom django.db import models\nfrom video_encoding.fields import VideoField\nfrom video_encoding.models import Format\n\n\nclass Video(models.Model):\n   width = models.PositiveIntegerField(editable=False, null=True)\n   height = models.PositiveIntegerField(editable=False, null=True)\n   duration = models.FloatField(editable=False, null=True)\n\n   file = VideoField(width_field='width', height_field='height',\n                     duration_field='duration')\n\n   format_set = GenericRelation(Format)\n```\n\nTo show all converted videos in the admin, you should add the `FormatInline`\nto your `ModelAdmin`\n\n```python\nfrom django.contrib import admin\nfrom video_encoding.admin import FormatInline\n\nfrom .models import Video\n\n\n@admin.register(Video)\nclass VideoAdmin(admin.ModelAdmin):\n   inlines = (FormatInline,)\n\n   list_dispaly = ('get_filename', 'width', 'height', 'duration')\n   fields = ('file', 'width', 'height', 'duration')\n   readonly_fields = fields\n```\n\n\nThe conversion of the video should be done in a separate process. Typical\noptions are [django-rq] or [celery]. We will use `django-rq` in the\nfollowing example. The configuration for `celery` is similar.\n`django-video-encoding` already provides a task (`convert_all_videos`)\nfor converting all videos on a model.\nThis task should be triggered when a video was uploaded. Hence we listen to\nthe `post-save` signal and enqueue the saved instance for processing.\n\n```python\n# signals.py\nfrom django.db.models.signals import post_save\nfrom django.dispatch import receiver\nfrom django_rq import enqueue\n\nfrom video_encoding import tasks\n\nfrom .models import Video\n\n\n@receiver(post_save, sender=Video)\ndef convert_video(sender, instance, **kwargs):\n    enqueue(tasks.convert_all_videos,\n            instance._meta.app_label,\n            instance._meta.model_name,\n            instance.pk)\n```\n\nAfter a while You can access the converted videos using\n\n```python\nvideo = Video.objects.get(...)\nfor format in video.format_set.complete().all():\n   # do something\n```\n\n[django-rq]: https://github.com/ui/django-rq\n[celery]: http://www.celeryproject.org/\n\n### Generate a video thumbnail\n\nThe backend provides a `get_thumbnail()` method to extract a thumbnail from a video.\nHere is a basic example on how to generate the thumbnail and store it in the model.\n\n```python\n# models.py\nfrom django.db import models\n\nclass Video(models.Model):\n   width = models.PositiveIntegerField(editable=False, null=True)\n   height = models.PositiveIntegerField(editable=False, null=True)\n   duration = models.FloatField(editable=False, null=True)\n\n   thumbnail = ImageField(blank=True)\n   file = VideoField(width_field='width', height_field='height',\n                     duration_field='duration')\n\n   format_set = GenericRelation(Format)\n\n\n# tasks.py\nfrom django.core.files import File\nfrom video_encoding.backends import get_backend\n\nfrom .models import Video\n\n\ndef create_thumbnail(video_pk):\n   video = Video.objects.get(pk=video_pk)\n   if not video.file:\n      # no video file attached\n      return\n\n   if video.thumbnail:\n      # thumbnail has already been generated\n      return\n\n   encoding_backend = get_backend()\n   thumbnail_path = encoding_backend.get_thumbnail(video.file.path)\n   filename = os.path.basename(self.url),\n\n   try:\n      with open(thumbnail_path, 'rb') as file_handler:\n         django_file = File(file_handler)\n         video.thumbnail.save(filename, django_file)\n      video.save()\n   finally:\n      os.unlink(thumbnail_path)\n```\n\nYou should run this method in a separate process by using `django-rq`, `celery`\nor similar) and enqueue execution from within a `post_save` signal.\n\n```python\n# signals.py\nfrom django.db.models.signals import post_save\nfrom django.dispatch import receiver\nfrom django_rq import enqueue\n\nfrom . import tasks\nfrom .models import Video\n\n\n@receiver(post_save, sender=Video)\ndef create_thumbnail(sender, instance, **kwargs):\n    enqueue(tasks.create_thumbnail, instance.pk)\n```\n\n### Signals\n\nDuring the encoding multiple signals are emitted to report the progress.\nYou can register to the signals as described in the [Django documentation](https://docs.djangoproject.com/en/3.1/topics/signals/#connecting-to-signals-sent-by-specific-senders).\n\nThis simple example demonstrates, on how to update the \"video model\" once the convertion is finished.\n\n```python\n# apps.py\nfrom django.apps import AppConfig\n\n\nclass MyAppConfig(AppConfig):\n   # ...\n\n    def ready(self) -\u003e None:\n      from . import signals  # register signals\n\n\n# signals.py\nfrom typing import Type\n\nfrom django.dispatch import receiver\nfrom video_encoding import signals\n\nfrom myapp.models import Video\n\n\n@receiver(signals.encoding_finished, sender=Video)\ndef mark_as_finished(sender: Type[Video], instance: Video) -\u003e None:\n   \"\"\"\n   Mark video as \"convertion has been finished\".\n   \"\"\"\n   video.processed = True\n   video.save(update_fields=['processed'])\n```\n\n#### `signals.encoding_started`\n\nThis is sent before the encoding starts.\n\n_Arguments_  \n`sender: Type[models.Model]`: Model which contains the `VideoField`.  \n`instance: models.Model)`: Instance of the model containing the `VideoField`.\n\n#### `signals.encoding_finished`\n\nLike `encoding_started()`, but sent after the file had been converted into all formats.\n\n_Arguments_  \n`sender: Type[models.Model]`: Model which contains the `VideoField`.  \n`instance: models.Model)`: Instance of the model containing the `VideoField`.\n\n#### `signals.format_started`\n\nThis is sent before the video is converted to one of the configured formats.\n\n_Arguments_  \n`sender: Type[models.Model]`: Model which contains the `VideoField`.  \n`instance: models.Model)`: Instance of the model containing the `VideoField`.  \n`format: Format`: The format instance, which will reference the encoded video file.\n\n#### `signals.format_finished`\n\nLike `format_finished`, but sent after the video encoding process and includes whether the encoding was succesful or not.\n\n_Arguments_  \n`sender: Type[models.Model]`: Model which contains the `VideoField`.  \n`instance: models.Model)`: Instance of the model containing the `VideoField`.  \n`format: Format`: The format instance, which will reference the encoded video file.  \n`result: ConversionResult`: Instance of `video_encoding.signals.ConversionResult` and indicates whether the convertion `FAILED`, `SUCCEEDED` or was `SKIPPED`.\n\n\n## Configuration\n\n**VIDEO_ENCODING_THREADS** (default: `1`)  \nDefines how many threads should be used for encoding. This may not be supported\nby every backend.\n\n**VIDEO_ENCODING_BACKEND** (default: `'video_encoding.backends.ffmpeg.FFmpegBackend'`)  \nChoose the backend for encoding. `django-video-encoding`  only supports `ffmpeg`,\nbut you can implement your own backend. Feel free to pulish your plugin and\nsubmit a pull request.\n\n**VIDEO_ENCODING_BACKEND_PARAMS** (default: `{}`)  \nIf your backend requires some special configuration, you can specify them here\nas `dict`.\n\n**VIDEO_ENCODING_FORMATS** (for defaults see `video_encoding/config.py`)  \nThis dictionary defines all required encodings and has some resonable defaults.\nIf you want to customize the formats, you have to specify `name`,\n`extension` and `params` for each format. For example\n\n```python\nVIDEO_ENCODING_FORMATS = {\n    'FFmpeg': [\n        {\n            'name': 'webm_sd',\n            'extension': 'webm',\n            'params': [\n                '-b:v', '1000k', '-maxrate', '1000k', '-bufsize', '2000k',\n                '-codec:v', 'libvpx', '-r', '30',\n                '-vf', 'scale=-1:480', '-qmin', '10', '-qmax', '42',\n                '-codec:a', 'libvorbis', '-b:a', '128k', '-f', 'webm',\n           ],\n        },\n     ]\n```\n\n## Encoding Backends\n\n### video_encoding.backends.ffmpeg.FFmpegBackend (default)\n\nBackend for using `ffmpeg` and `ffprobe` to convert your videos.\n\n#### Options\n\n**VIDEO_ENCODING_FFMPEG_PATH**  \nPath to `ffmpeg`. If no path is provided, the backend uses `which` to\nlocate it.\n**VIDEO_ENCODING_FFPROBE_PATH**  \nPath to `ffprobe`. If no path is provided, the backend uses `which` to\nlocate it.\n\n### Custom Backend\n\nYou can implement a custom encoding backend. Create a new class which inherits from\n[`video_encoding.backends.base.BaseEncodingBackend`](video_encoding/backends/base.py).\nYou must set the property `name` and implement the methods `encode`, `get_media_info`\nand `get_thumbnail`. For further details see the reference implementation:\n[`video_encoding.backends.ffmpeg.FFmpegBackend`](video_encoding/backends/ffmpeg.py).\n\nIf you want to open source your backend, follow these steps.\n\n1. create a packages named django-video-encoding-BACKENDNAME\n2. publish your package to [pypi]\n3. Submit a pull requests with the following changes:\n\n   * add the package to `extra_requires`\n   * provide reasonable defaults for `VIDEO_ENCODING_FORMATS`\n\n[pypi]: https://pypi.python.org/pypi\n\n## Development\n\nThis project uses [poetry](https://poetry.eustace.io/) for packaging and\nmanaging all dependencies and [pre-commit](https://pre-commit.com/) to run\n[flake8](http://flake8.pycqa.org/), [isort](https://pycqa.github.io/isort/),\n[mypy](http://mypy-lang.org/) and [black](https://github.com/python/black).\n\nAdditionally, [pdbpp](https://github.com/pdbpp/pdbpp) and [better-exceptions](https://github.com/qix-/better-exceptions) are installed to provide a better debugging experience.\nTo enable `better-exceptions` you have to run `export BETTER_EXCEPTIONS=1` in your current session/terminal.\n\nClone this repository and run\n\n```bash\npoetry install\npoetry run pre-commit install\n```\n\nto create a virtual enviroment containing all dependencies.\nAfterwards, You can run the test suite using\n\n```bash\npoetry run pytest\n```\n\nThis repository follows the [Conventional Commits](https://www.conventionalcommits.org/)\nstyle.\n\n### Cookiecutter template\n\nThis project was created using [cruft](https://github.com/cruft/cruft) and the\n[cookiecutter-pyproject](https://github.com/escaped/cookiecutter-pypackage) template.\nIn order to update this repository to the latest template version run\n\n```sh\ncruft update\n```\n\nin the root of this repository.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fescaped%2Fdjango-video-encoding","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fescaped%2Fdjango-video-encoding","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fescaped%2Fdjango-video-encoding/lists"}