Recherche avancée

Médias (91)

Autres articles (50)

  • Les autorisations surchargées par les plugins

    27 avril 2010, par

    Mediaspip core
    autoriser_auteur_modifier() afin que les visiteurs soient capables de modifier leurs informations sur la page d’auteurs

  • Librairies et binaires spécifiques au traitement vidéo et sonore

    31 janvier 2010, par

    Les logiciels et librairies suivantes sont utilisées par SPIPmotion d’une manière ou d’une autre.
    Binaires obligatoires FFMpeg : encodeur principal, permet de transcoder presque tous les types de fichiers vidéo et sonores dans les formats lisibles sur Internet. CF ce tutoriel pour son installation ; Oggz-tools : outils d’inspection de fichiers ogg ; Mediainfo : récupération d’informations depuis la plupart des formats vidéos et sonores ;
    Binaires complémentaires et facultatifs flvtool2 : (...)

  • Support audio et vidéo HTML5

    10 avril 2011

    MediaSPIP utilise les balises HTML5 video et audio pour la lecture de documents multimedia en profitant des dernières innovations du W3C supportées par les navigateurs modernes.
    Pour les navigateurs plus anciens, le lecteur flash Flowplayer est utilisé.
    Le lecteur HTML5 utilisé a été spécifiquement créé pour MediaSPIP : il est complètement modifiable graphiquement pour correspondre à un thème choisi.
    Ces technologies permettent de distribuer vidéo et son à la fois sur des ordinateurs conventionnels (...)

Sur d’autres sites (10192)

  • Overlaying a text stream on a video stream with ffmpeg in Node.js

    16 mai 2023, par Tchoune

    I am creating a streaming system with Node.js that uses ffmpeg to send video and text streams to a local RTMP server, then combines those streams and sends them to Twitch.

    


    I'm using canvas to create a text image with a transparent background, and I need to change that text every time a new video in the playlist starts.

    


    Currently in stream I see only the video stream of my video and not the text. But if I go via VLC to see each more separate, I see them

    


    However, I'm running into a problem where the text stream doesn't appear in the final video stream on Twitch. In addition, I get the following error message :

    


    Combine stderr: [NULL @ 0x1407069f0] Unable to find a suitable output format for 'rtmp://live.twitch.tv/app/streamKey'
rtmp://live.twitch.tv/app/streamKey: Invalid argument


    


    Here is my current Node.js code :

    


    
const createTextImage = (runner) => {
    return new Promise((resolve, reject) => {
        const canvas = createCanvas(1920, 1080);
        const context = canvas.getContext('2d');

        // Fill the background with transparency
        context.fillStyle = 'rgba(0,0,0,0)';
        context.fillRect(0, 0, canvas.width, canvas.height);

        // Set the text options
        context.fillStyle = '#ffffff';
        context.font = '24px Arial';
        context.textAlign = 'start';
        context.textBaseline = 'middle';

        // Draw the text
        context.fillText(`Speedrun by ${runner}`, canvas.width / 2, canvas.height / 2);

        // Define the images directory
        const imagesDir = path.join(__dirname, 'images', 'runners');

        // Ensure the images directory exists
        fs.mkdirSync(imagesDir, { recursive: true });

        // Define the file path
        const filePath = path.join(imagesDir, runner + '.png');

        // Create the write stream
        const out = fs.createWriteStream(filePath);

        // Create the PNG stream
        const stream = canvas.createPNGStream();

        // Pipe the PNG stream to the write stream
        stream.pipe(out);

        out.on('finish', () => {
            console.log('The PNG file was created.');
            resolve();
        });

        out.on('error', reject);
    });
}
const streamVideo = (video) => {
    ffmpegLibrary.ffprobe(video.video, function (err, metadata) {
        if (err) {
            console.error(err);
            return;
        }
        currentVideoDuration = metadata.format.duration;

        // Annulez le délai précédent avant d'en créer un nouveau
        if (nextVideoTimeoutId) {
            clearTimeout(nextVideoTimeoutId);
        }

        // Déplacez votre appel setTimeout ici
        nextVideoTimeoutId = setTimeout(() => {
            console.log('Fin de la vidéo, passage à la suivante...');
            nextVideo();
        }, currentVideoDuration * 1000 + 10000);
    })


    ffmpegVideo = childProcess.spawn('ffmpeg', [
        '-nostdin', '-re', '-f', 'concat', '-safe', '0', '-i', 'playlist.txt',
        '-vcodec', 'libx264',
        '-s', '1920x1080',
        '-r', '30',
        '-b:v', '5000k',
        '-acodec', 'aac',
        '-preset', 'veryfast',
        '-f', 'flv',
        `rtmp://localhost:1935/live/video` // envoie le flux vidéo au serveur rtmp local
    ]);

    createTextImage(video.runner).then(() => {
        ffmpegText = childProcess.spawn('ffmpeg', [
            '-nostdin', '-re',
            '-loop', '1', '-i', `images/runners/${video.runner}.png`, // Utilise l'image créée par Puppeteer
            '-vcodec', 'libx264rgb', // Utilise le codec PNG pour conserver la transparence
            '-s', '1920x1080',
            '-r', '30',
            '-b:v', '5000k',
            '-acodec', 'aac',
            '-preset', 'veryfast',
            '-f', 'flv',
            `rtmp://localhost:1935/live/text` // envoie le flux de texte au serveur rtmp local
        ]);

        ffmpegText.stdout.on('data', (data) => {
            console.log(`text stdout: ${data}`);
        });

        ffmpegText.stderr.on('data', (data) => {
            console.error(`text stderr: ${data}`);
        });
    }).catch(error => {
        console.error(`Erreur lors de la création de l'image de texte: ${error}`);
    });

    ffmpegCombine = childProcess.spawn('ffmpeg', [
        '-i', 'rtmp://localhost:1935/live/video',
        '-i', 'rtmp://localhost:1935/live/text',
        '-filter_complex', '[0:v][1:v]overlay=main_w-overlay_w:0',
        '-s', '1920x1080',
        '-r', '30',
        '-vcodec', 'libx264',
        '-b:v', '5000k',
        '-acodec', 'aac',
        '-preset', 'veryfast',
        '-f', 'flv',
        `rtmp://live.twitch.tv/app/${twitchStreamKey}` // envoie le flux combiné à Twitch
    ]);

    ffmpegVideo.stdout.on('data', (data) => {
        console.log(`video stdout: ${data}`);
    });

    ffmpegVideo.stderr.on('data', (data) => {
        console.error(`video stderr: ${data}`);
    });

    ffmpegCombine.stdout.on('data', (data) => {
        console.log(`Combine stdout: ${data}`);
    });

    ffmpegCombine.stderr.on('data', (data) => {
        console.error(`Combine stderr: ${data}`);
    });

    ffmpegCombine.on('close', (code) => {
        console.log(`ffmpeg exited with code ${code}`);
        if (currentIndex >= playlist.length) {
            console.log('End of playlist');
            currentIndex = 0;
        }
    });
}



    


    Locally I use nginx with rtmp module to manage multi-streams and combined into one to send to twitch

    


    In NGINX it's my nginx.conf for module :

    


    rtmp {
    server {
        listen 1935; # le port pour le protocole RTMP
        
        application live {
            live on; # active le streaming en direct
            record off; # désactive l'enregistrement du flux
    
            # définit l'endroit où les flux doivent être envoyés
            push rtmp://live.twitch.tv/app/liveKey;
        }
    
        application text {
            live on; # active le streaming en direct
            record off; # désactive l'enregistrement du flux
        }
    }
}


    


    I have checked that the codecs, resolution and frame rate are the same for both streams. I am also overlaying the text stream on top of the video stream with the -filter_complex command, but I am not sure if it works correctly.

    


    Does each stream have to have the same parameters ?

    


    I would like to know if anyone has any idea what could be causing this problem and how to fix it. Should I use a different format for the output stream to Twitch ? Or is there another approach I should consider for layering a dynamic text stream over a video stream ?

    


    Also, I'm wondering if I'm handling updating the text stream correctly when the video changes. Currently, I create a new text image with Canvas every time the video changes, then create a new ffmpeg process for the text stream. Is this the right approach, or is there a better way to handle this ?

    


    Thanks in advance for any help or advice.

    


  • Failed to decode h264 key frame with DXVA2.0 because returned buffer is to small

    16 mai 2023, par grill2010

    I hava a strange problem on Windows with DXVA2 h264 decoding. I recently figured out a ffmpeg decoding limitation for DXVA2 and D3D11VA on Windows and how to solve it, this solution completly fixes the problem with D3D11VA but DXVA2 still has some problems with certain keyframes. Upon further investigation it turned out that the decoding of these certain keyframes fail because the buffer returned from the IDirectXVideoDecoder_GetBuffer function was too small. FFmpeg is printing out these logs when the decoding fails :

    


    Error: [h264 @ 0000028b2e5796c0] Buffer for type 5 was too small. size: 58752, dxva_size: 55296
Error: [h264 @ 0000028b2e5796c0] Failed to add bitstream or slice control buffer
Error: [h264 @ 0000028b2e5796c0] hardware accelerator failed to decode picture


    


    Why is this returned buffer too low ? What kind of factors inside ffmpeg do have an effect on this buffer size or is this a limitation of DXVA2 in general ? All other decoders like Cuvid, D3D11VA or the software decoder are not affected by this problem and can decode all keyframes.

    


    I have an example javacv project on github that can reproduce the problem. I also provide the source code of the main class here. The keyframe example data with prepended SPS and PPS in hex form can be downloaded here.

    


    import javafx.application.Application;&#xA;import javafx.scene.Scene;&#xA;import javafx.scene.layout.Pane;&#xA;import javafx.scene.layout.StackPane;&#xA;import javafx.stage.Stage;&#xA;import org.bytedeco.ffmpeg.avcodec.AVCodec;&#xA;import org.bytedeco.ffmpeg.avcodec.AVCodecContext;&#xA;import org.bytedeco.ffmpeg.avcodec.AVCodecHWConfig;&#xA;import org.bytedeco.ffmpeg.avcodec.AVPacket;&#xA;import org.bytedeco.ffmpeg.avutil.AVBufferRef;&#xA;import org.bytedeco.ffmpeg.avutil.AVDictionary;&#xA;import org.bytedeco.ffmpeg.avutil.AVFrame;&#xA;import org.bytedeco.ffmpeg.avutil.LogCallback;&#xA;import org.bytedeco.javacpp.BytePointer;&#xA;import org.bytedeco.javacpp.IntPointer;&#xA;import org.bytedeco.javacpp.Pointer;&#xA;import org.tinylog.Logger;&#xA;&#xA;import java.io.IOException;&#xA;import java.io.InputStream;&#xA;import java.nio.charset.StandardCharsets;&#xA;import java.util.Objects;&#xA;import java.util.function.Consumer;&#xA;&#xA;import static org.bytedeco.ffmpeg.avcodec.AVCodecContext.FF_THREAD_SLICE;&#xA;import static org.bytedeco.ffmpeg.global.avcodec.*;&#xA;import static org.bytedeco.ffmpeg.global.avutil.*;&#xA;&#xA;public class App extends Application {&#xA;&#xA;    /**** decoder variables ****/&#xA;&#xA;    private AVHWContextInfo hardwareContext;&#xA;&#xA;    private AVCodec decoder;&#xA;    private AVCodecContext m_VideoDecoderCtx;&#xA;&#xA;    private AVCodecContext.Get_format_AVCodecContext_IntPointer formatCallback;&#xA;&#xA;    private final int streamResolutionX = 1920;&#xA;    private final int streamResolutionY = 1080;&#xA;&#xA;    // AV_HWDEVICE_TYPE_CUDA // example works with cuda&#xA;    // AV_HWDEVICE_TYPE_DXVA2 // producing Invalid data found on keyframe&#xA;    // AV_HWDEVICE_TYPE_D3D11VA // producing Invalid data found on keyframe&#xA;    private static final int HW_DEVICE_TYPE = AV_HWDEVICE_TYPE_DXVA2;&#xA;&#xA;    private static final boolean USE_HW_ACCEL = true;&#xA;&#xA;    private static final boolean USE_AV_EF_EXPLODE = true;&#xA;&#xA;    public static void main(final String[] args) {&#xA;        //System.setProperty("prism.order", "d3d,sw");&#xA;        System.setProperty("prism.vsync", "false");&#xA;        Application.launch(App.class);&#xA;    }&#xA;&#xA;    @Override&#xA;    public void start(final Stage primaryStage) {&#xA;        final Pane dummyPane = new Pane();&#xA;        dummyPane.setStyle("-fx-background-color: black");&#xA;        final Scene scene = new Scene(dummyPane, this.streamResolutionX, this.streamResolutionY);&#xA;        primaryStage.setScene(scene);&#xA;        primaryStage.show();&#xA;        primaryStage.setMinWidth(480);&#xA;        primaryStage.setMinHeight(360);&#xA;&#xA;        this.initializeFFmpeg(result -> {&#xA;            if (!result) {&#xA;                Logger.error("FFmpeg could not be initialized correctly, terminating program");&#xA;                System.exit(1);&#xA;                return;&#xA;            }&#xA;            scene.setRoot(new StackPane());&#xA;            this.performTestFramesFeeding();&#xA;        });&#xA;    }&#xA;&#xA;    private void initializeFFmpeg(final Consumer<boolean> finishHandler) {&#xA;        FFmpegLogCallback.setLevel(AV_LOG_DEBUG); // Increase log level until the first frame is decoded&#xA;        FFmpegLogCallback.set();&#xA;        Pointer pointer = new Pointer((Pointer) null);&#xA;        AVCodec c;&#xA;        while ((c = av_codec_iterate(pointer)) != null) {&#xA;            if (av_codec_is_decoder(c) > 0)&#xA;                Logger.debug("{}:{} ", c.name().getString(), c.type());&#xA;        }&#xA;&#xA;        this.decoder = avcodec_find_decoder(AV_CODEC_ID_H264); // usually decoder name is h264 and without hardware support it&#x27;s yuv420p otherwise nv12&#xA;        if (this.decoder == null) {&#xA;            Logger.error("Unable to find decoder for format {}", "h264");&#xA;            finishHandler.accept(false);&#xA;            return;&#xA;        }&#xA;        Logger.info("Current decoder name: {}, {}", this.decoder.name().getString(), this.decoder.long_name().getString());&#xA;&#xA;        if (true) {&#xA;            for (; ; ) {&#xA;                this.m_VideoDecoderCtx = avcodec_alloc_context3(this.decoder);&#xA;                if (this.m_VideoDecoderCtx == null) {&#xA;                    Logger.error("Unable to find decoder for format AV_CODEC_ID_H264");&#xA;                    if (this.hardwareContext != null) {&#xA;                        this.hardwareContext.free();&#xA;                        this.hardwareContext = null;&#xA;                    }&#xA;                    continue;&#xA;                }&#xA;&#xA;                if (App.USE_HW_ACCEL) {&#xA;                    this.hardwareContext = this.createHardwareContext();&#xA;                    if (this.hardwareContext != null) {&#xA;                        Logger.info("Set hwaccel support");&#xA;                        this.m_VideoDecoderCtx.hw_device_ctx(this.hardwareContext.hwContext()); // comment to disable hwaccel&#xA;                    }&#xA;                } else {&#xA;                    Logger.info("Hwaccel manually disabled");&#xA;                }&#xA;&#xA;                // Always request low delay decoding&#xA;                this.m_VideoDecoderCtx.flags(this.m_VideoDecoderCtx.flags() | AV_CODEC_FLAG_LOW_DELAY);&#xA;&#xA;                // Allow display of corrupt frames and frames missing references&#xA;                this.m_VideoDecoderCtx.flags(this.m_VideoDecoderCtx.flags() | AV_CODEC_FLAG_OUTPUT_CORRUPT);&#xA;                this.m_VideoDecoderCtx.flags2(this.m_VideoDecoderCtx.flags2() | AV_CODEC_FLAG2_SHOW_ALL);&#xA;&#xA;                if (App.USE_AV_EF_EXPLODE) {&#xA;                    // Report decoding errors to allow us to request a key frame&#xA;                    this.m_VideoDecoderCtx.err_recognition(this.m_VideoDecoderCtx.err_recognition() | AV_EF_EXPLODE);&#xA;                }&#xA;&#xA;                // Enable slice multi-threading for software decoding&#xA;                if (this.m_VideoDecoderCtx.hw_device_ctx() == null) { // if not hw accelerated&#xA;                    this.m_VideoDecoderCtx.thread_type(this.m_VideoDecoderCtx.thread_type() | FF_THREAD_SLICE);&#xA;                    this.m_VideoDecoderCtx.thread_count(2/*AppUtil.getCpuCount()*/);&#xA;                } else {&#xA;                    // No threading for HW decode&#xA;                    this.m_VideoDecoderCtx.thread_count(1);&#xA;                }&#xA;&#xA;                this.m_VideoDecoderCtx.width(this.streamResolutionX);&#xA;                this.m_VideoDecoderCtx.height(this.streamResolutionY);&#xA;                this.m_VideoDecoderCtx.pix_fmt(this.getDefaultPixelFormat());&#xA;&#xA;                this.formatCallback = new AVCodecContext.Get_format_AVCodecContext_IntPointer() {&#xA;                    @Override&#xA;                    public int call(final AVCodecContext context, final IntPointer pixelFormats) {&#xA;                        final boolean hwDecodingSupported = context.hw_device_ctx() != null &amp;&amp; App.this.hardwareContext != null;&#xA;                        final int preferredPixelFormat = hwDecodingSupported ?&#xA;                                App.this.hardwareContext.hwConfig().pix_fmt() :&#xA;                                context.pix_fmt();&#xA;                        int i = 0;&#xA;                        while (true) {&#xA;                            final int currentSupportedFormat = pixelFormats.get(i&#x2B;&#x2B;);&#xA;                            System.out.println("Supported pixel formats " &#x2B; currentSupportedFormat);&#xA;                            if (currentSupportedFormat == AV_PIX_FMT_NONE) {&#xA;                                break;&#xA;                            }&#xA;                        }&#xA;&#xA;                        i = 0;&#xA;                        while (true) {&#xA;                            final int currentSupportedFormat = pixelFormats.get(i&#x2B;&#x2B;);&#xA;                            if (currentSupportedFormat == preferredPixelFormat) {&#xA;                                Logger.info("[FFmpeg]: pixel format in format callback is {}", currentSupportedFormat);&#xA;                                return currentSupportedFormat;&#xA;                            }&#xA;                            if (currentSupportedFormat == AV_PIX_FMT_NONE) {&#xA;                                break;&#xA;                            }&#xA;                        }&#xA;&#xA;                        i = 0;&#xA;                        while (true) { // try again and search for yuv&#xA;                            final int currentSupportedFormat = pixelFormats.get(i&#x2B;&#x2B;);&#xA;                            if (currentSupportedFormat == AV_PIX_FMT_YUV420P) {&#xA;                                Logger.info("[FFmpeg]: Not found in first match so use {}", AV_PIX_FMT_YUV420P);&#xA;                                return currentSupportedFormat;&#xA;                            }&#xA;                            if (currentSupportedFormat == AV_PIX_FMT_NONE) {&#xA;                                break;&#xA;                            }&#xA;                        }&#xA;&#xA;                        i = 0;&#xA;                        while (true) { // try again and search for nv12&#xA;                            final int currentSupportedFormat = pixelFormats.get(i&#x2B;&#x2B;);&#xA;                            if (currentSupportedFormat == AV_PIX_FMT_NV12) {&#xA;                                Logger.info("[FFmpeg]: Not found in second match so use {}", AV_PIX_FMT_NV12);&#xA;                                return currentSupportedFormat;&#xA;                            }&#xA;                            if (currentSupportedFormat == AV_PIX_FMT_NONE) {&#xA;                                break;&#xA;                            }&#xA;                        }&#xA;&#xA;                        Logger.info("[FFmpeg]: pixel format in format callback is using fallback {}", AV_PIX_FMT_NONE);&#xA;                        return AV_PIX_FMT_NONE;&#xA;                    }&#xA;                };&#xA;                this.m_VideoDecoderCtx.get_format(this.formatCallback);&#xA;&#xA;                final AVDictionary options = new AVDictionary(null);&#xA;                final int result = avcodec_open2(this.m_VideoDecoderCtx, this.decoder, options);&#xA;                if (result &lt; 0) {&#xA;                    Logger.error("avcodec_open2 was not successful");&#xA;                    finishHandler.accept(false);&#xA;                    return;&#xA;                }&#xA;                av_dict_free(options);&#xA;                break;&#xA;            }&#xA;        }&#xA;&#xA;        if (this.decoder == null || this.m_VideoDecoderCtx == null) {&#xA;            finishHandler.accept(false);&#xA;            return;&#xA;        }&#xA;        finishHandler.accept(true);&#xA;    }&#xA;&#xA;    private AVHWContextInfo createHardwareContext() {&#xA;        AVHWContextInfo result = null;&#xA;        for (int i = 0; ; i&#x2B;&#x2B;) {&#xA;            final AVCodecHWConfig config = avcodec_get_hw_config(this.decoder, i);&#xA;            if (config == null) {&#xA;                break;&#xA;            }&#xA;&#xA;            if ((config.methods() &amp; AV_CODEC_HW_CONFIG_METHOD_HW_DEVICE_CTX) &lt; 0) {&#xA;                continue;&#xA;            }&#xA;            final int device_type = config.device_type();&#xA;            if (device_type != App.HW_DEVICE_TYPE) {&#xA;                continue;&#xA;            }&#xA;            final AVBufferRef hw_context = av_hwdevice_ctx_alloc(device_type);&#xA;            if (hw_context == null || av_hwdevice_ctx_create(hw_context, device_type, (String) null, null, 0) &lt; 0) {&#xA;                Logger.error("HW accel not supported for type {}", device_type);&#xA;                av_free(config);&#xA;                av_free(hw_context);&#xA;            } else {&#xA;                Logger.info("HW accel created for type {}", device_type);&#xA;                result = new AVHWContextInfo(config, hw_context);&#xA;            }&#xA;            break;&#xA;        }&#xA;&#xA;        return result;&#xA;    }&#xA;&#xA;    @Override&#xA;    public void stop() {&#xA;        this.releaseNativeResources();&#xA;    }&#xA;&#xA;    /*****************************/&#xA;    /*** test frame processing ***/&#xA;    /*****************************/&#xA;    &#xA;    private void performTestFramesFeeding() {&#xA;        final AVPacket pkt = av_packet_alloc();&#xA;        if (pkt == null) {&#xA;            return;&#xA;        }&#xA;        try (final BytePointer bp = new BytePointer(65_535 * 15)) {&#xA;&#xA;&#xA;            for (int i = 0; i &lt; 1; i&#x2B;&#x2B;) {&#xA;                final byte[] frameData = AVTestFrames.h264KeyTestFrame;&#xA;&#xA;                bp.position(0);&#xA;&#xA;                bp.put(frameData);&#xA;                bp.limit(frameData.length);&#xA;&#xA;                pkt.data(bp);&#xA;                pkt.capacity(bp.capacity());&#xA;                pkt.size(frameData.length);&#xA;                pkt.position(0);&#xA;                pkt.limit(frameData.length);&#xA;                //pkt.flags(AV_PKT_FLAG_KEY);&#xA;                final AVFrame avFrame = av_frame_alloc();&#xA;                System.out.println("frameData.length " &#x2B; frameData.length);&#xA;&#xA;                final int err = avcodec_send_packet(this.m_VideoDecoderCtx, pkt); //fill_scaling_lists&#xA;                if (err &lt; 0) {&#xA;                    final BytePointer buffer = new BytePointer(512);&#xA;                    av_strerror(err, buffer, buffer.capacity());&#xA;                    final String string = buffer.getString();&#xA;                    System.out.println("Error on decoding test frame " &#x2B; err &#x2B; " message " &#x2B; string);&#xA;                    av_frame_free(avFrame);&#xA;                    return;&#xA;                }&#xA;&#xA;                final int result = avcodec_receive_frame(this.m_VideoDecoderCtx, avFrame);&#xA;                final AVFrame decodedFrame;&#xA;                if (result == 0) {&#xA;                    if (this.m_VideoDecoderCtx.hw_device_ctx() == null) {&#xA;                        decodedFrame = avFrame;&#xA;                        System.out.println("SUCESS with SW decoding");&#xA;                    } else {&#xA;                        final AVFrame hwAvFrame = av_frame_alloc();&#xA;                        if (av_hwframe_transfer_data(hwAvFrame, avFrame, 0) &lt; 0) {&#xA;                            System.out.println("Failed to transfer frame from hardware");&#xA;                            av_frame_unref(hwAvFrame);&#xA;                            decodedFrame = avFrame;&#xA;                        } else {&#xA;                            av_frame_unref(avFrame);&#xA;                            decodedFrame = hwAvFrame;&#xA;                            System.out.println("SUCESS with HW decoding");&#xA;                        }&#xA;                    }&#xA;&#xA;                    av_frame_unref(decodedFrame);&#xA;                } else {&#xA;                    final BytePointer buffer = new BytePointer(512);&#xA;                    av_strerror(result, buffer, buffer.capacity());&#xA;                    final String string = buffer.getString();&#xA;                    System.out.println("error " &#x2B; result &#x2B; " message " &#x2B; string);&#xA;                    av_frame_free(avFrame);&#xA;                }&#xA;            }&#xA;        } finally {&#xA;            if (pkt.stream_index() != -1) {&#xA;                av_packet_unref(pkt);&#xA;            }&#xA;            pkt.releaseReference();&#xA;        }&#xA;    }&#xA;&#xA;    final Object releaseLock = new Object();&#xA;    private volatile boolean released = false;&#xA;&#xA;    private void releaseNativeResources() {&#xA;        if (this.released) {&#xA;            return;&#xA;        }&#xA;        this.released = true;&#xA;        synchronized (this.releaseLock) {&#xA;            // Close the video codec&#xA;            if (this.m_VideoDecoderCtx != null) {&#xA;                avcodec_free_context(this.m_VideoDecoderCtx);&#xA;                this.m_VideoDecoderCtx = null;&#xA;            }&#xA;&#xA;            // close the format callback&#xA;            if (this.formatCallback != null) {&#xA;                this.formatCallback.close();&#xA;                this.formatCallback = null;&#xA;            }&#xA;&#xA;            // close hw context&#xA;            if (this.hardwareContext != null) {&#xA;                this.hardwareContext.free();&#xA;            }&#xA;        }&#xA;    }&#xA;&#xA;    private int getDefaultPixelFormat() {&#xA;        return AV_PIX_FMT_YUV420P; // Always return yuv420p here&#xA;    }&#xA;&#xA;&#xA;    /*********************/&#xA;    /*** inner classes ***/&#xA;    /*********************/&#xA;&#xA;    public static final class HexUtil {&#xA;&#xA;        private HexUtil() {&#xA;        }&#xA;&#xA;        public static byte[] unhexlify(final String argbuf) {&#xA;            final int arglen = argbuf.length();&#xA;            if (arglen % 2 != 0) {&#xA;                throw new RuntimeException("Odd-length string");&#xA;            } else {&#xA;                final byte[] retbuf = new byte[arglen / 2];&#xA;&#xA;                for (int i = 0; i &lt; arglen; i &#x2B;= 2) {&#xA;                    final int top = Character.digit(argbuf.charAt(i), 16);&#xA;                    final int bot = Character.digit(argbuf.charAt(i &#x2B; 1), 16);&#xA;                    if (top == -1 || bot == -1) {&#xA;                        throw new RuntimeException("Non-hexadecimal digit found");&#xA;                    }&#xA;&#xA;                    retbuf[i / 2] = (byte) ((top &lt;&lt; 4) &#x2B; bot);&#xA;                }&#xA;&#xA;                return retbuf;&#xA;            }&#xA;        }&#xA;    }&#xA;&#xA;    public static final class AVHWContextInfo {&#xA;        private final AVCodecHWConfig hwConfig;&#xA;        private final AVBufferRef hwContext;&#xA;&#xA;        private volatile boolean freed = false;&#xA;&#xA;        public AVHWContextInfo(final AVCodecHWConfig hwConfig, final AVBufferRef hwContext) {&#xA;            this.hwConfig = hwConfig;&#xA;            this.hwContext = hwContext;&#xA;        }&#xA;&#xA;        public AVCodecHWConfig hwConfig() {&#xA;            return this.hwConfig;&#xA;        }&#xA;&#xA;        public AVBufferRef hwContext() {&#xA;            return this.hwContext;&#xA;        }&#xA;&#xA;        public void free() {&#xA;            if (this.freed) {&#xA;                return;&#xA;            }&#xA;            this.freed = true;&#xA;            av_free(this.hwConfig);&#xA;            av_free(this.hwContext);&#xA;        }&#xA;&#xA;&#xA;        @Override&#xA;        public boolean equals(Object o) {&#xA;            if (this == o) return true;&#xA;            if (o == null || getClass() != o.getClass()) return false;&#xA;            AVHWContextInfo that = (AVHWContextInfo) o;&#xA;            return freed == that.freed &amp;&amp; Objects.equals(hwConfig, that.hwConfig) &amp;&amp; Objects.equals(hwContext, that.hwContext);&#xA;        }&#xA;&#xA;        @Override&#xA;        public int hashCode() {&#xA;            return Objects.hash(hwConfig, hwContext, freed);&#xA;        }&#xA;&#xA;        @Override&#xA;        public String toString() {&#xA;            return "AVHWContextInfo[" &#x2B;&#xA;                    "hwConfig=" &#x2B; this.hwConfig &#x2B; ", " &#x2B;&#xA;                    "hwContext=" &#x2B; this.hwContext &#x2B; &#x27;]&#x27;;&#xA;        }&#xA;    }&#xA;&#xA;    public static final class AVTestFrames {&#xA;&#xA;        private AVTestFrames() {&#xA;&#xA;        }&#xA;&#xA;        static {&#xA;            InputStream inputStream = null;&#xA;            try {&#xA;                inputStream = AVTestFrames.class.getClassLoader().getResourceAsStream("h264_test_key_frame.txt");&#xA;                final byte[] h264TestFrameBuffer = inputStream == null ? new byte[0] : inputStream.readAllBytes();&#xA;                final String h264TestFrame = new String(h264TestFrameBuffer, StandardCharsets.UTF_8);&#xA;                AVTestFrames.h264KeyTestFrame = HexUtil.unhexlify(h264TestFrame);&#xA;            } catch (final IOException e) {&#xA;                Logger.error(e, "Could not parse test frame");&#xA;            } finally {&#xA;                if (inputStream != null) {&#xA;                    try {&#xA;                        inputStream.close();&#xA;                    } catch (final IOException e) {&#xA;                        Logger.error(e, "Could not close test frame input stream");&#xA;                    }&#xA;                }&#xA;            }&#xA;        }&#xA;&#xA;        public static byte[] h264KeyTestFrame;&#xA;    }&#xA;&#xA;    public static class FFmpegLogCallback extends LogCallback {&#xA;&#xA;        private static final org.bytedeco.javacpp.tools.Logger logger = org.bytedeco.javacpp.tools.Logger.create(FFmpegLogCallback.class);&#xA;&#xA;        static final FFmpegLogCallback instance = new FFmpegLogCallback().retainReference();&#xA;&#xA;        public static FFmpegLogCallback getInstance() {&#xA;            return instance;&#xA;        }&#xA;&#xA;        /**&#xA;         * Calls {@code avutil.setLogCallback(getInstance())}.&#xA;         */&#xA;        public static void set() {&#xA;            setLogCallback(getInstance());&#xA;        }&#xA;&#xA;        /**&#xA;         * Returns {@code av_log_get_level()}.&#xA;         **/&#xA;        public static int getLevel() {&#xA;            return av_log_get_level();&#xA;        }&#xA;&#xA;        /**&#xA;         * Calls {@code av_log_set_level(level)}.&#xA;         **/&#xA;        public static void setLevel(int level) {&#xA;            av_log_set_level(level);&#xA;        }&#xA;&#xA;        @Override&#xA;        public void call(int level, BytePointer msg) {&#xA;            switch (level) {&#xA;                case AV_LOG_PANIC, AV_LOG_FATAL, AV_LOG_ERROR -> logger.error(msg.getString());&#xA;                case AV_LOG_WARNING -> logger.warn(msg.getString());&#xA;                case AV_LOG_INFO -> logger.info(msg.getString());&#xA;                case AV_LOG_VERBOSE, AV_LOG_DEBUG, AV_LOG_TRACE -> logger.debug(msg.getString());&#xA;                default -> {&#xA;                    assert false;&#xA;                }&#xA;            }&#xA;        }&#xA;    }&#xA;}&#xA;</boolean>

    &#xA;

  • 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.&#xA;Everything works fine until a 4k file tries to get transcoded and it fails with this log

    &#xA;

    2023-05-24T19:09:54.906Z ZoBKWMMKG:Node\[hidden-hog\]:Worker\[tall-tuna\]:{"pluginInputs":{"BitRate":"4000","ResolutionSelection":"1080p","Container":"mkv","AudioType":"AAC","FrameRate":"24"}}&#xA;&#xA;2023-05-24T19:09:54.907Z ZoBKWMMKG:Node\[hidden-hog\]:Worker\[tall-tuna\]:Error TypeError: Cannot read property &#x27;1&#x27; of undefined&#xA;

    &#xA;

    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&#xA;The plugin Code is here

    &#xA;

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

    &#xA;

    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

    &#xA;

    EDIT : I used Console.log and got this back

    &#xA;

    [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;