Recherche avancée

Médias (91)

Autres articles (29)

  • List of compatible distributions

    26 avril 2011, par

    The table below is the list of Linux distributions compatible with the automated installation script of MediaSPIP. Distribution nameVersion nameVersion number Debian Squeeze 6.x.x Debian Weezy 7.x.x Debian Jessie 8.x.x Ubuntu The Precise Pangolin 12.04 LTS Ubuntu The Trusty Tahr 14.04
    If you want to help us improve this list, you can provide us access to a machine whose distribution is not mentioned above or send the necessary fixes to add (...)

  • Personnaliser en ajoutant son logo, sa bannière ou son image de fond

    5 septembre 2013, par

    Certains thèmes prennent en compte trois éléments de personnalisation : l’ajout d’un logo ; l’ajout d’une bannière l’ajout d’une image de fond ;

  • Ecrire une actualité

    21 juin 2013, par

    Présentez les changements dans votre MédiaSPIP ou les actualités de vos projets sur votre MédiaSPIP grâce à la rubrique actualités.
    Dans le thème par défaut spipeo de MédiaSPIP, les actualités sont affichées en bas de la page principale sous les éditoriaux.
    Vous pouvez personnaliser le formulaire de création d’une actualité.
    Formulaire de création d’une actualité Dans le cas d’un document de type actualité, les champs proposés par défaut sont : Date de publication ( personnaliser la date de publication ) (...)

Sur d’autres sites (5437)

  • Video encoding task not working with Django Celery Redis FFMPEG and GraphQL

    18 juin 2023, par phanio

    I'm having a hard time trying to understand how is this FFMPEG encoding works while using Django, Celery, Redis, GraphQL and Docker too.

    


    I have this video / courses platform project and want I'm trying to do using FFMPEG, Celery and Redis is to create different video resolutions so I can display them the way Youtube does inside the videoplayer ( the videoplayer is handled in frontend by Nextjs and Apollo Client ), now on the backend I've just learned that in order to use properly the FFMPEG to resize the oridinal video size, I need to use Celery and Redis to perform asyncronus tasks. I've found a few older posts here on stackoverflow and google, but is not quite enough info for someone who is using the ffmpeg and clery and redis for the first time ( I've started already step by step and created that example that adds two numbers together with celery, that works well ). Now I'm not sure what is wrong with my code, because first of all I'm not really sure where should I trigger the task from, I mean from which file, because at the end of the task I want to send the data through api using GrapQL Strawberry.

    


    This is what I've tried by now :

    


    So first things first my project structure looks like this

    


    - backend #root directory
 --- backend
    -- __init__.py
    -- celery.py
    -- settings.py
    -- urls.py
      etc..

 --- static
   -- videos

 --- video
   -- models.py
   -- schema.py
   -- tasks.py
   -- types.py
   etc..

 --- .env

 --- db.sqlite3

 --- docker-compose.yml

 --- Dockerfile

 --- manage.py

 --- requirements.txt


    


    here is my settings.py file :

    


    from pathlib import Path
import os

# Build paths inside the project like this: BASE_DIR / 'subdir'.
BASE_DIR = Path(__file__).resolve().parent.parent

DEBUG = True

ALLOWED_HOSTS=["localhost", "0.0.0.0", "127.0.0.1"]

DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'


# Application definition

INSTALLED_APPS = [
    "corsheaders",
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',

    "strawberry.django",
    "video"
]

etc...

STATIC_URL = '/static/'
MEDIA_URL = '/videos/'

STATICFILES_DIRS = [
    BASE_DIR / 'static',
    # BASE_DIR / 'frontend/build/static',
]

MEDIA_ROOT = BASE_DIR / 'static/videos'

STATIC_ROOT = BASE_DIR / 'staticfiles'

STATICFILES_STORAGE = 'whitenoise.storage.CompressedManifestStaticFilesStorage'

CORS_ALLOW_ALL_ORIGINS = True


CELERY_BEAT_SCHEDULER = 'django_celery_beat.schedulers:DatabaseScheduler'

# REDIS CACHE
CACHES = {
    "default": {
        "BACKEND": "django_redis.cache.RedisCache",
        "LOCATION": f"redis://127.0.0.1:6379/1",
        "OPTIONS": {
            "CLIENT_CLASS": "django_redis.client.DefaultClient",
        },
    }
}

# Docker
CELERY_BROKER_URL = os.environ.get("CELERY_BROKER", "redis://redis:6379/0")
CELERY_RESULT_BACKEND = os.environ.get("CELERY_BROKER", "redis://redis:6379/0")


    


    This is my main urls.py file :

    


    from django.contrib import admin
from django.conf import settings
from django.conf.urls.static import static
from django.urls import path
from django.urls.conf import include
from strawberry.django.views import GraphQLView

from video.schema import schema

urlpatterns = [
    path('admin/', admin.site.urls),
    path("graphql", GraphQLView.as_view(schema=schema)),
]

if settings.DEBUG:
    urlpatterns += static(settings.MEDIA_URL,
                          document_root=settings.MEDIA_ROOT)
    urlpatterns += static(settings.STATIC_URL,
                          document_root=settings.STATIC_ROOT)


    


    This is my celery.py file :

    


    from __future__ import absolute_import, unicode_literals
import os
from celery import Celery
from django.conf import settings

os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'backend.settings')

backend = Celery('backend')

backend.config_from_object('django.conf:settings', namespace="CELERY")

backend.autodiscover_tasks()

@backend.task(bind=True)
def debug_task(self):
    print('Request: {0!r}'.format(self.request))


    


    This is my init.py file :

    


    from .celery import backend as celery_backend

__all__ = ('celery_backend',)


    


    This is my Dockerfile :

    


    FROM python:3
ENV PYTHONUNBUFFERED=1

WORKDIR /usr/src/backend

RUN apt-get -y update
RUN apt-get -y upgrade
RUN apt-get install -y ffmpeg

COPY requirements.txt ./
RUN pip install -r requirements.txt


    


    This is my docker-compose.yml file :

    


    version: "3.8"

services:
  django:
    build: .
    container_name: django
    command: python manage.py runserver 0.0.0.0:8000
    volumes:
      - .:/usr/src/backend/
    ports:
      - "8000:8000"
    environment:
      - DEBUG=1
      - DJANGO_ALLOWED_HOSTS=localhost 127.0.0.1 [::1]
      - CELERY_BROKER=redis://redis:6379/0
      - CELERY_BACKEND=redis://redis:6379/0
    depends_on:
      - pgdb
      - redis

  celery:
    build: .
    command: celery -A backend worker -l INFO
    volumes:
      - .:/usr/src/backend
    depends_on:
      - django
      - redis

  pgdb:
    image: postgres
    container_name: pgdb
    environment:
      - POSTGRES_DB=postgres
      - POSTGRES_USER=postgres
      - POSTGRES_PASSWORD=postgres
    volumes:
      - pgdata:/var/lib/postgresql/data/

  redis:
    image: "redis:alpine"

volumes:
  pgdata:


    


    And now inside my video app folder :

    


    My models.py file :

    


      

    • here I've created separated fields for all resolution sizes, from video_file_2k to video_file_144, I was thinking that maybe after the process of the encoding this will populate those fields..
    • 


    


    from django.db import models
from django.urls import reverse


class Video(models.Model):
    video_id = models.AutoField(primary_key=True, editable=False)
    slug = models.SlugField(max_length=255)
    title = models.CharField(max_length=150, blank=True, null=True)
    description = models.TextField(blank=True, null=True)
    video_file = models.FileField(null=False, blank=False)
    video_file_2k = models.FileField(null=True, blank=True)
    video_file_fullhd = models.FileField(null=True, blank=True)
    video_file_hd = models.FileField(null=True, blank=True)
    video_file_480 = models.FileField(null=True, blank=True)
    video_file_360 = models.FileField(null=True, blank=True)
    video_file_240 = models.FileField(null=True, blank=True)
    video_file_144 = models.FileField(null=True, blank=True)
    category = models.CharField(max_length=64, blank=False, null=False)
    created_at = models.DateTimeField(
        ("Created at"), auto_now_add=True, editable=False)
    updated_at = models.DateTimeField(("Updated at"), auto_now=True)

    class Meta:
        ordering = ("-created_at",)
        verbose_name = ("Video")
        verbose_name_plural = ("Videos")

    def get_absolute_url(self):
        return reverse("store:video_detail", args=[self.slug])

    def __str__(self):
        return self.title


    


    This is my schema.py file :

    


    import strawberry
from strawberry.file_uploads import Upload
from typing import List
from .types import VideoType
from .models import Video
from .tasks import task_video_encoding_1080p, task_video_encoding_720p


@strawberry.type
class Query:
    @strawberry.field
    def videos(self, category: str = None) -> List[VideoType]:
        if category:
            videos = Video.objects.filter(category=category)
            return videos
        return Video.objects.all()

    @strawberry.field
    def video(self, slug: str) -> VideoType:
        if slug == slug:
            video = Video.objects.get(slug=slug)
            return video

    @strawberry.field
    def video_by_id(self, video_id: int) -> VideoType:
        if video_id == video_id:
            video = Video.objects.get(pk=video_id)

          # Here I've tried to trigger my tasks, when I visited 0.0.0.0:8000/graphql url
          # and I was querying for a video by it's id , then I've got the error from celery 
            task_video_encoding_1080p.delay(video_id)
            task_video_encoding_720p.delay(video_id)

            return video


@strawberry.type
class Mutation:
    @strawberry.field
    def create_video(self, slug: str, title: str, description: str, video_file: Upload, video_file_2k: str, video_file_fullhd: str, video_file_hd: str, video_file_480: str, video_file_360: str, video_file_240: str, video_file_144: str, category: str) -> VideoType:

        video = Video(slug=slug, title=title, description=description,
                      video_file=video_file, video_file_2k=video_file_2k, video_file_fullhd=video_file_fullhd, video_file_hd=video_file_hd, video_file_480=video_file_480, video_file_360=video_file_360, video_file_240=video_file_240, video_file_144=video_file_144,category=category)
        
        video.save()
        return video

    @strawberry.field
    def update_video(self, video_id: int, slug: str, title: str, description: str, video_file: str, category: str) -> VideoType:
        video = Video.objects.get(video_id=video_id)
        video.slug = slug
        video.title = title
        video.description = description
        video.video_file = video_file
        video.category = category
        video.save()
        return video

    @strawberry.field
    def delete_video(self, video_id: int) -> bool:
        video = Video.objects.get(video_id=video_id)
        video.delete
        return True


schema = strawberry.Schema(query=Query, mutation=Mutation)


    


    This is my types.py file ( strawberry graphql related ) :

    


    import strawberry

from .models import Video


@strawberry.django.type(Video)
class VideoType:
    video_id: int
    slug: str
    title: str
    description: str
    video_file: str
    video_file_2k: str
    video_file_fullhd: str
    video_file_hd: str
    video_file_480: str
    video_file_360: str
    video_file_240: str
    video_file_144: str
    category: str


    


    And this is my tasks.py file :

    


    from __future__ import absolute_import, unicode_literals
import os, subprocess
from django.conf import settings
from django.core.exceptions import ValidationError
from celery import shared_task
from celery.utils.log import get_task_logger
from .models import Video
FFMPEG_PATH = os.environ["IMAGEIO_FFMPEG_EXE"] = "/opt/homebrew/Cellar/ffmpeg/6.0/bin/ffmpeg"

logger = get_task_logger(__name__)


# CELERY TASKS
@shared_task
def add(x,y):
    return x + y


@shared_task
def task_video_encoding_720p(video_id):
    logger.info('Video Processing started')
    try:
        video = Video.objects.get(video_id=video_id)
        input_file_path = video.video_file.path
        input_file_url = video.video_file.url
        input_file_name = video.video_file.name

        # get the filename (without extension)
        filename = os.path.basename(input_file_url)

        # path to the new file, change it according to where you want to put it
        output_file_name = os.path.join('videos', 'mp4', '{}.mp4'.format(filename))
        output_file_path = os.path.join(settings.MEDIA_ROOT, output_file_name)

        # 2-pass encoding
        for i in range(1):
           new_video_720p = subprocess.call([FFMPEG_PATH, '-i', input_file_path, '-s', '1280x720', '-vcodec', 'mpeg4', '-acodec', 'libvo_aacenc', '-b', '10000k', '-pass', i, '-r', '30', output_file_path])
        #    new_video_720p = subprocess.call([FFMPEG_PATH, '-i', input_file_path, '-s', '{}x{}'.format(height * 16/9, height), '-vcodec', 'mpeg4', '-acodec', 'libvo_aacenc', '-b', '10000k', '-pass', i, '-r', '30', output_file_path])

        if new_video_720p == 0:
            # save the new file in the database
            # video.video_file_hd.name = output_file_name
            video.save(update_fields=['video_file_hd'])
            logger.info('Video Processing Finished')
            return video

        else:
            logger.info('Proceesing Failed.') # Just for now

    except:
        raise ValidationError('Something went wrong')


@shared_task
# def task_video_encoding_1080p(video_id, height):
def task_video_encoding_1080p(video_id):
    logger.info('Video Processing started')
    try:
        video = Video.objects.get(video_id=video_id)
        input_file_path = video.video_file.url
        input_file_name = video.video_file.name

        # get the filename (without extension)
        filename = os.path.basename(input_file_path)

        # path to the new file, change it according to where you want to put it
        output_file_name = os.path.join('videos', 'mp4', '{}.mp4'.format(filename))
        output_file_path = os.path.join(settings.MEDIA_ROOT, output_file_name)

        for i in range(1):
            new_video_1080p = subprocess.call([FFMPEG_PATH, '-i', input_file_path, '-s', '1920x1080', '-vcodec', 'mpeg4', '-acodec', 'libvo_aacenc', '-b', '10000k', '-pass', i, '-r', '30', output_file_path])

        if new_video_1080p == 0:
            # save the new file in the database
            # video.video_file_hd.name = output_file_name
            video.save(update_fields=['video_file_fullhd'])
            logger.info('Video Processing Finished')
            return video
        else:
            logger.info('Proceesing Failed.') # Just for now

    except:
        raise ValidationError('Something went wrong')


    


    In my first attempt I wasn't triggering the tasks no where, then I've tried to trigger the task from the schema.py file from graphql inside the video_by_id, but there I've got this error :

    


    backend-celery-1  | django.core.exceptions.ValidationError: ['Something went wrong']
backend-celery-1  | [2023-06-18 16:38:52,859: ERROR/ForkPoolWorker-4] Task video.tasks.task_video_encoding_1080p[d33b1a42-5914-467c-ad5c-00565bc8be6f] raised unexpected: ValidationError(['Something went wrong'])
backend-celery-1  | Traceback (most recent call last):
backend-celery-1  |   File "/usr/src/backend/video/tasks.py", line 81, in task_video_encoding_1080p
backend-celery-1  |     new_video_1080p = subprocess.call([FFMPEG_PATH, '-i', input_file_path, '-s', '1920x1080', '-vcodec', 'mpeg4', '-acodec', 'libvo_aacenc', '-b', '10000k', '-pass', i, '-r', '30', output_file_path])
backend-celery-1  |                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
backend-celery-1  |   File "/usr/local/lib/python3.11/subprocess.py", line 389, in call
backend-celery-1  |     with Popen(*popenargs, **kwargs) as p:
backend-celery-1  |          ^^^^^^^^^^^^^^^^^^^^^^^^^^^
backend-celery-1  |   File "/usr/local/lib/python3.11/subprocess.py", line 1026, in __init__
backend-celery-1  |     self._execute_child(args, executable, preexec_fn, close_fds,
backend-celery-1  |   File "/usr/local/lib/python3.11/subprocess.py", line 1883, in _execute_child
backend-celery-1  |     self.pid = _fork_exec(
backend-celery-1  |                ^^^^^^^^^^^
backend-celery-1  | TypeError: expected str, bytes or os.PathLike object, not int
backend-celery-1  | 
backend-celery-1  | During handling of the above exception, another exception occurred:
backend-celery-1  | 
backend-celery-1  | Traceback (most recent call last):
backend-celery-1  |   File "/usr/local/lib/python3.11/site-packages/celery/app/trace.py", line 477, in trace_task
backend-celery-1  |     R = retval = fun(*args, **kwargs)
backend-celery-1  |                  ^^^^^^^^^^^^^^^^^^^^
backend-celery-1  |   File "/usr/local/lib/python3.11/site-packages/celery/app/trace.py", line 760, in __protected_call__
backend-celery-1  |     return self.run(*args, **kwargs)
backend-celery-1  |            ^^^^^^^^^^^^^^^^^^^^^^^^^
backend-celery-1  |   File "/usr/src/backend/video/tasks.py", line 93, in task_video_encoding_1080p
backend-celery-1  |     raise ValidationError('Something went wrong')
backend-celery-1  | django.core.exceptions.ValidationError: ['Something went wrong']


    


    If anyone has done this kind of project or something like this please any suggestion or help is much appreciated.

    


    Thank you in advance !

    


  • Code can not read property 1 of undefined [closed]

    25 mai 2023, par Jesse Copas

    I'm a very new programmer and am working on a Tdarr plugin in JS.
Everything works fine until a 4k file tries to get transcoded and it fails with this log

    


    2023-05-24T19:09:54.906Z ZoBKWMMKG:Node\[hidden-hog\]:Worker\[tall-tuna\]:{"pluginInputs":{"BitRate":"4000","ResolutionSelection":"1080p","Container":"mkv","AudioType":"AAC","FrameRate":"24"}}

2023-05-24T19:09:54.907Z ZoBKWMMKG:Node\[hidden-hog\]:Worker\[tall-tuna\]:Error TypeError: Cannot read property '1' of undefined


    


    It's saying that it's unable to read property 1 of undefined and I'm looked and looked and looked and can't find what it is referring to. Hoping to get another set of eyes on it
The plugin Code is here

    


    /* eslint no-plusplus: ["error", { "allowForLoopAfterthoughts": true }] */
/* eslint-disable no-restricted-globals */
const details = () => ({
  id: 'Tdarr_Plugin_Jeso_AV1_HandBrake_Transcode',
  Stage: 'Pre-processing',
  Name: 'AV1 HandBrake Transcoder',
  Type: 'Video',
  Operation: 'Transcode',
  Description: 'Transcodes to AV1 at the selected Bitrate. This is best used with Remux Files.',
  Version: '2.1.3',
  Tags: 'HandBrake,configurable',
  Inputs: [
    {
      name: 'BitRate',
      type: 'string',
      defaultValue: '4000',
      inputUI: {
        type: 'text',
      },
      tooltip: `
        ~ Requested Bitrate ~ \\n
        Put in the Bitrate you want to process to in Kbps. For example 4000Kbps is 4Mbps. `,
    },
    {
      name: 'ResolutionSelection',
      type: 'string',
      defaultValue: '1080p',
      inputUI: {
        type: 'dropdown',
        options: [
          '8KUHD',
          '4KUHD',
          '1080p',
          '720p',
          '480p',
        ],
      },
      // eslint-disable-next-line max-len
      tooltip: 'Any Resolution larger than this will become this Resolution same as the bitrate if the Res is lower than the selected it will use the res of the file as to not cause bloating of file size.',
    },
    {
      name: 'Container',
      type: 'string',
      defaultValue: 'mkv',
      inputUI: {
        type: 'dropdown',
        options: [
          'mp4',
          'mkv',
        ],
      },
      tooltip: ` Container Type \\n\\n
          mkv or mp4.\\n`,
    },
    {
      name: 'AudioType',
      type: 'string',
      defaultValue: 'AAC',
      inputUI: {
        type: 'dropdown',
        options: [
          'AAC',
          'EAC3',
          'MP3',
          'Vorbis',
          'Flac16',
          'Flac24',
        ],
      },
      // eslint-disable-next-line max-len
      tooltip: 'Set Audio container type that you want to use',
    },
    {
      name: 'FrameRate',
      type: 'string',
      defaultValue: '24',
      inputUI: {
        type: 'text',
      },
      // eslint-disable-next-line max-len
      tooltip: 'If the files framerate is higher than 24 and you want to maintain that framerate you can do so here',
    },
  ],
});
const MediaInfo = {
  videoHeight: '',
  videoWidth: '',
  videoFPS: '',
  videoBR: '',
  videoBitDepth: '',
  overallBR: '',
  videoResolution: '',
}; // var MediaInfo
// Easier for our functions if response has global scope.
const response = {
  processFile: false,
  preset: '',
  container: '.mkv',
  handBrakeMode: true,
  FFmpegMode: false,
  reQueueAfter: true,
  infoLog: '',
}; // var response
// Finds the first video stream and populates some useful variables
function getMediaInfo(file) {
  let videoIdx = -1;
  for (let i = 0; i < file.ffProbeData.streams.length; i += 1) {
    const strstreamType = file.ffProbeData.streams[i].codec_type.toLowerCase();
    // Looking For Video
    // Check if stream is a video.
    if (videoIdx === -1 && strstreamType === 'video') {
      videoIdx = i;
      // get video streams resolution
      MediaInfo.videoResolution = `${file.ffProbeData.streams[i].height}x${file.ffProbeData.streams[i].width}`;
      MediaInfo.videoHeight = Number(file.ffProbeData.streams[i].height);
      MediaInfo.videoWidth = Number(file.ffProbeData.streams[i].width);
      MediaInfo.videoFPS = Number(file.mediaInfo.track[i + 1].FrameRate) || 25;
      // calulate bitrate from dimensions and fps of file
      MediaInfo.videoBR = (MediaInfo.videoHeight * MediaInfo.videoWidth * MediaInfo.videoFPS * 0.08).toFixed(0);
    }
  }
} // end  getMediaInfo()
// define resolution order from ResolutionSelection from biggest to smallest
const resolutionOrder = ['8KUHD', '4KUHD', '1080p', '720p', '480p'];
// define the width and height of each resolution from the resolution order
const resolutionsdimensions = {
  '8KUHD': '--width 7680 --height 4320',
  '4KUHD': '--width 3840 --height 2160',
  '1080p': '--width 1920 --height 1080',
  '720p': '--width 1280 --height 720',
  '480p': '--width 640 --height 480',
};
// eslint-disable-next-line no-unused-vars
const plugin = (file, librarySettings, inputs) => {
  // eslint-disable-next-line no-unused-vars
  const importFresh = require('import-fresh');
  // eslint-disable-next-line no-unused-vars
  const library = importFresh('../methods/library.js');
  // eslint-disable-next-line no-unused-vars
  const lib = require('../methods/lib')();
  // Get the selected resolution from the 'ResolutionSelection' variable
  const selectedResolution = inputs.ResolutionSelection;
  getMediaInfo(file);
  // use mediainfo to match height and width to a resolution on resolutiondimensions
  let dimensions = resolutionsdimensions[selectedResolution];
  // if the file is smaller than the selected resolution then use the file resolution
  if (MediaInfo.videoHeight < dimensions.split(' ')[3] || MediaInfo.videoWidth < dimensions.split(' ')[1]) {
    dimensions = `--width ${MediaInfo.videoWidth} --height ${MediaInfo.videoHeight}`;
    // eslint-disable-next-line brace-style
  }
  // read the bitrate of the video stream
  let videoBitRate = MediaInfo.videoBR;
  // if videoBitrate is over 1000000 devide by 100 to get the bitrate in Kbps
  if (videoBitRate > 1000000) {
    videoBitRate /= 100;
  } else { videoBitRate /= 1000; }
  // if VideoBitrate is smaller than selected bitrate then use the videoBitrate
  if (videoBitRate < inputs.BitRate) {
    // eslint-disable-next-line no-param-reassign
    inputs.BitRate = videoBitRate;
    // eslint-disable-next-line brace-style
  }
  // if VideoBitrate is larger than selected bitrate then use the selected bitrate
  else {
    // eslint-disable-next-line no-self-assign, no-param-reassign
    inputs.BitRate = inputs.BitRate;
  }

  //Skip Transcoding if File is already AV1
  if (file.ffProbeData.streams[0].codec_name === 'av1') {
    response.processFile = false;
    response.infoLog += 'File is already AV1 \n';
    return response;
  }
  // eslint-disable-next-line no-constant-condition
  if ((true) || file.forceProcessing === true) {
    // eslint-disable-next-line max-len
    response.preset = `--encoder svt_av1 -b ${inputs.BitRate} -r ${inputs.FrameRate} -E ${inputs.AudioType} -f ${inputs.Container} --no-optimize ${dimensions} --crop 0:0:0:0`;
    response.container = `.${inputs.Container}`;
    response.handbrakeMode = true;
    response.ffmpegMode = false;
    response.processFile = true;
    response.infoLog += `File is being transcoded at ${inputs.BitRate} Kbps to ${dimensions} as ${inputs.Container} \n`;
    return response;
  }
  response.infoLog += 'File is being transcoded using custom arguments \n';
  return response;
};
  };

module.exports.details = details;
module.exports.plugin = plugin;


    


    Tried transcoding 4k files down to 1080p but it fails due to that undefined error. All Res 1080p and lower that I have tried work correctly

    


    EDIT : I used Console.log and got this back

    


    [2023-05-24T23:29:51.001] [ERROR] Tdarr_Server - Error running MediaInfo 1&#xA;[2023-05-24T23:29:51.004] [ERROR] Tdarr_Server - RangeError: Maximum call stack size exceeded&#xA;    at x (<anonymous>:wasm-function[381]:0x15c4d)&#xA;    at <anonymous>:wasm-function[46]:0x5dc0&#xA;    at <anonymous>:wasm-function[652]:0x21cb9&#xA;    at <anonymous>:wasm-function[1023]:0x47018&#xA;    at <anonymous>:wasm-function[853]:0x37827&#xA;    at <anonymous>:wasm-function[3684]:0xf4884&#xA;    at <anonymous>:wasm-function[3516]:0xeb5b7&#xA;    at <anonymous>:wasm-function[1061]:0x487c9&#xA;    at <anonymous>:wasm-function[795]:0x3006d&#xA;    at <anonymous>:wasm-function[3628]:0xf01cc&#xA;[2023-05-24T23:29:51.006] [ERROR] Tdarr_Server - Error running MediaInfo 2&#xA;[2023-05-24T23:29:51.006] [ERROR] Tdarr_Server - RangeError: Maximum call stack size exceeded&#xA;    at x (<anonymous>:wasm-function[381]:0x15c4d)&#xA;    at <anonymous>:wasm-function[46]:0x5dc0&#xA;    at <anonymous>:wasm-function[652]:0x21cb9&#xA;    at <anonymous>:wasm-function[1023]:0x47018&#xA;    at <anonymous>:wasm-function[853]:0x37827&#xA;    at <anonymous>:wasm-function[3684]:0xf4884&#xA;    at <anonymous>:wasm-function[3516]:0xeb5b7&#xA;    at <anonymous>:wasm-function[1061]:0x487c9&#xA;    at <anonymous>:wasm-function[795]:0x3006d&#xA;    at <anonymous>:wasm-function[3628]:0xf01cc&#xA;[2023-05-24T23:29:58.220] [ERROR] Tdarr_Server - Error running MediaInfo 1&#xA;[2023-05-24T23:29:58.223] [ERROR] Tdarr_Server - RangeError: Maximum call stack size exceeded&#xA;    at x (<anonymous>:wasm-function[381]:0x15c4d)&#xA;    at <anonymous>:wasm-function[46]:0x5dc0&#xA;    at <anonymous>:wasm-function[652]:0x21cb9&#xA;    at <anonymous>:wasm-function[1023]:0x47018&#xA;    at <anonymous>:wasm-function[853]:0x37827&#xA;    at <anonymous>:wasm-function[3684]:0xf4884&#xA;    at <anonymous>:wasm-function[3516]:0xeb5b7&#xA;    at <anonymous>:wasm-function[1061]:0x487c9&#xA;    at <anonymous>:wasm-function[795]:0x3006d&#xA;    at <anonymous>:wasm-function[3628]:0xf01cc&#xA;[2023-05-24T23:29:58.224] [ERROR] Tdarr_Server - Error running MediaInfo 2&#xA;[2023-05-24T23:29:58.224] [ERROR] Tdarr_Server - RangeError: Maximum call stack size exceeded&#xA;    at x (<anonymous>:wasm-function[381]:0x15c4d)&#xA;    at <anonymous>:wasm-function[46]:0x5dc0&#xA;    at <anonymous>:wasm-function[652]:0x21cb9&#xA;    at <anonymous>:wasm-function[1023]:0x47018&#xA;    at <anonymous>:wasm-function[853]:0x37827&#xA;    at <anonymous>:wasm-function[3684]:0xf4884&#xA;    at <anonymous>:wasm-function[3516]:0xeb5b7&#xA;    at <anonymous>:wasm-function[1061]:0x487c9&#xA;    at <anonymous>:wasm-function[795]:0x3006d&#xA;    at <anonymous>:wasm-function[3628]:0xf01cc&#xA;</anonymous></anonymous></anonymous></anonymous></anonymous></anonymous></anonymous></anonymous></anonymous></anonymous></anonymous></anonymous></anonymous></anonymous></anonymous></anonymous></anonymous></anonymous></anonymous></anonymous></anonymous></anonymous></anonymous></anonymous></anonymous></anonymous></anonymous></anonymous></anonymous></anonymous></anonymous></anonymous></anonymous></anonymous></anonymous></anonymous></anonymous></anonymous></anonymous></anonymous>

    &#xA;

  • Flask app using OpenCv crash when i start recording

    17 mai 2023, par Mulham Darwish

    I build this flask app to live stream security cameras and the live stream works with the screenshot function but when start recording it crash but few times same code it worked and saved the video here the code. with the html file using js.

    &#xA;

    from flask import Flask, render_template, Response, request&#xA;import cv2&#xA;import os&#xA;import time&#xA;import threading&#xA;import requests&#xA;&#xA;app = Flask(__name__)&#xA;&#xA;# Define the IP cameras&#xA;cameras = [&#xA;    {&#x27;url&#x27;: &#x27;rtsp://****:*****@******&#x27;, &#x27;name&#x27;: &#x27;Camera 1&#x27;},&#xA;    {&#x27;url&#x27;: &#x27;rtsp://****:*****@******&#x27;, &#x27;name&#x27;: &#x27;Camera 2&#x27;},&#xA;    {&#x27;url&#x27;: &#x27;rtsp://****:*****@******&#x27;, &#x27;name&#x27;: &#x27;Camera 3&#x27;},&#xA;    {&#x27;url&#x27;: &#x27;rtsp://****:*****@******&#x27;, &#x27;name&#x27;: &#x27;Camera 4&#x27;}&#xA;]&#xA;&#xA;# Create a VideoCapture object for each camera&#xA;capture_objs = [cv2.VideoCapture(cam[&#x27;url&#x27;]) for cam in cameras]&#xA;stop_events = {i: threading.Event() for i in range(len(cameras))}&#xA;# Define the directory to save the recorded videos&#xA;recording_dir = os.path.join(os.getcwd(), &#x27;recordings&#x27;)&#xA;&#xA;# Ensure the recording directory exists&#xA;if not os.path.exists(recording_dir):&#xA;    os.makedirs(recording_dir)&#xA;&#xA;# Define the function to capture and save a video&#xA;def record_video(camera_index, stop_recording):&#xA;    # Define the codec and file extension&#xA;    fourcc = cv2.VideoWriter_fourcc(*&#x27;mp4v&#x27;)&#xA;    file_extension = &#x27;.mp4&#x27;&#xA;&#xA;    # Get the current timestamp for the filename&#xA;    timestamp = time.strftime("%Y%m%d-%H%M%S")&#xA;&#xA;    # Define the filename and path&#xA;    filename = f&#x27;{cameras[camera_index]["name"]}_{timestamp}{file_extension}&#x27;&#xA;    filepath = os.path.join(recording_dir, filename)&#xA;&#xA;    # Create a VideoWriter object to save the video&#xA;    width = int(capture_objs[camera_index].get(cv2.CAP_PROP_FRAME_WIDTH))&#xA;    height = int(capture_objs[camera_index].get(cv2.CAP_PROP_FRAME_HEIGHT))&#xA;    fps = int(capture_objs[camera_index].get(cv2.CAP_PROP_FPS))&#xA;    video_writer = cv2.VideoWriter(filepath, fourcc, fps, (width, height))&#xA;&#xA;    # Capture frames and write them to the file&#xA;    while True:&#xA;        if stop_recording.is_set():&#xA;            break  # stop recording if stop_recording is set&#xA;        ret, frame = capture_objs[camera_index].read()&#xA;        if ret:&#xA;            video_writer.write(frame)&#xA;        else:&#xA;            break&#xA;&#xA;    # Release the VideoWriter object and the VideoCapture object&#xA;    video_writer.release()&#xA;    capture_objs[camera_index].release()&#xA;&#xA;@app.route(&#x27;/&#x27;)&#xA;def index():&#xA;    # Render the index page with the list of cameras&#xA;    return render_template(&#x27;index.html&#x27;, cameras=cameras)&#xA;&#xA;def generate(camera_index):&#xA;    # Generate frames from the video feed&#xA;    while True:&#xA;        ret, frame = capture_objs[camera_index].read()&#xA;        if not ret:&#xA;            break&#xA;&#xA;        # Encode the frame as JPEG&#xA;        _, jpeg = cv2.imencode(&#x27;.jpg&#x27;, frame)&#xA;&#xA;        # Yield the frame as a Flask response&#xA;        yield (b&#x27;--frame\r\n&#x27;&#xA;               b&#x27;Content-Type: image/jpeg\r\n\r\n&#x27; &#x2B; jpeg.tobytes() &#x2B; b&#x27;\r\n&#x27;)&#xA;&#xA;@app.route(&#x27;/video_feed&#x27;)&#xA;def video_feed():&#xA;    # Get the camera index from the request arguments&#xA;    camera_index = int(request.args.get(&#x27;camera_index&#x27;))&#xA;&#xA;    # Generate the video feed&#xA;    return Response(generate(camera_index),&#xA;                    mimetype=&#x27;multipart/x-mixed-replace; boundary=frame&#x27;)&#xA;&#xA;@app.route(&#x27;/record&#x27;, methods=[&#x27;POST&#x27;])&#xA;def record():&#xA;    # Get the camera index from the request form&#xA;    camera_index = int(request.form[&#x27;camera_index&#x27;])&#xA;&#xA;    stop_recording = stop_events[camera_index]  # get the stop_recording event for the camera&#xA;    thread = threading.Thread(target=record_video, args=(camera_index, stop_recording))&#xA;    thread.start()  # start a thread to record video&#xA;&#xA;    # Return a response indicating that the recording has started&#xA;    return &#x27;Recording started.&#x27;&#xA;&#xA;@app.route(&#x27;/stop_record&#x27;, methods=[&#x27;POST&#x27;])&#xA;def stop_record():&#xA;    # Get the camera index from the request form&#xA;    camera_index = int(request.form[&#x27;camera_index&#x27;])&#xA;&#xA;    # Set the stop_recording event for the corresponding camera thread&#xA;    stop_events[camera_index].set()&#xA;&#xA;    # Return a response indicating that recording has been stopped&#xA;    return &#x27;Recording stopped.&#x27;&#xA;&#xA;@app.route(&#x27;/screenshot&#x27;, methods=[&#x27;POST&#x27;])&#xA;def take_screenshot():&#xA;    # Take a screenshot of the video stream and save it as a file&#xA;    camera = capture_objs[int(request.form[&#x27;camera_id&#x27;])]&#xA;    success, frame = camera.read()&#xA;    if success:&#xA;        timestamp = time.strftime("%Y%m%d-%H%M%S")&#xA;        filename = f&#x27;screenshot_{timestamp}.jpg&#x27;&#xA;        cv2.imwrite(filename, frame)&#xA;        return &#x27;Screenshot taken and saved&#x27;&#xA;    else:&#xA;        return &#x27;Failed to take screenshot&#x27;&#xA;&#xA;if __name__ == &#x27;__main__&#x27;:&#xA;    app.run()&#xA;

    &#xA;

    I tried to update ffmpeg to the latest version and installed pip install opencv-python-headless and installed pip install opencv-python but most of the time i come to this crash code

    &#xA;

    * Serving Flask app &#x27;run&#x27;&#xA;* Debug mode: off&#xA;WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead.&#xA; * Running on http://127.0.0.1:5000&#xA;Press CTRL&#x2B;C to quit&#xA;127.0.0.1 - - [17/May/2023 13:24:11] "GET / HTTP/1.1" 200 -&#xA;127.0.0.1 - - [17/May/2023 13:24:11] "GET /video_feed?camera_index=0 HTTP/1.1" 200 -&#xA;127.0.0.1 - - [17/May/2023 13:24:11] "GET /video_feed?camera_index=1 HTTP/1.1" 200 -&#xA;127.0.0.1 - - [17/May/2023 13:24:11] "GET /video_feed?camera_index=2 HTTP/1.1" 200 -&#xA;127.0.0.1 - - [17/May/2023 13:24:11] "GET /video_feed?camera_index=3 HTTP/1.1" 200 -&#xA;127.0.0.1 - - [17/May/2023 13:24:44] "GET / HTTP/1.1" 200 -&#xA;127.0.0.1 - - [17/May/2023 13:24:45] "GET /video_feed?camera_index=3 HTTP/1.1" 200 -&#xA;127.0.0.1 - - [17/May/2023 13:24:45] "GET /video_feed?camera_index=0 HTTP/1.1" 200 -&#xA;127.0.0.1 - - [17/May/2023 13:24:45] "GET /video_feed?camera_index=1 HTTP/1.1" 200 -&#xA;127.0.0.1 - - [17/May/2023 13:24:45] "GET /video_feed?camera_index=2 HTTP/1.1" 200 -&#xA;[h264 @ 0x5605285fc5c0] error while decoding MB 28 29, bytestream -9&#xA;[h264 @ 0x560529110040] error while decoding MB 15 37, bytestream -6&#xA;[h264 @ 0x560528624980] error while decoding MB 45 45, bytestream -23&#xA;[h264 @ 0x5605286f1900] error while decoding MB 50 34, bytestream -7&#xA;[h264 @ 0x5605285fc5c0] error while decoding MB 25 9, bytestream -17&#xA;[h264 @ 0x5605292b0080] error while decoding MB 28 41, bytestream -5&#xA;[h264 @ 0x560528660040] error while decoding MB 101 45, bytestream -17&#xA;[h264 @ 0x5605285fc5c0] error while decoding MB 42 44, bytestream -5&#xA;[h264 @ 0x5605286f1900] error while decoding MB 118 42, bytestream -9&#xA;[h264 @ 0x560529110040] error while decoding MB 92 43, bytestream -5&#xA;[h264 @ 0x560528660040] error while decoding MB 99 34, bytestream -11&#xA;[h264 @ 0x56052932b0c0] error while decoding MB 92 36, bytestream -13&#xA;[h264 @ 0x560528667ac0] error while decoding MB 44 54, bytestream -5&#xA;[h264 @ 0x560529110040] error while decoding MB 93 33, bytestream -7&#xA;[h264 @ 0x5605286dd880] error while decoding MB 27 37, bytestream -19&#xA;[h264 @ 0x560528660040] error while decoding MB 66 56, bytestream -9&#xA;127.0.0.1 - - [17/May/2023 13:36:45] "POST /record HTTP/1.1" 200 -&#xA;Assertion fctx->async_lock failed at libavcodec/pthread_frame.c:175&#xA;Aborted (core dumped)&#xA;

    &#xA;