web-dev-qa-db-fra.com

FFmpeg ignore le rendu des images

Pendant que j'extrais des images d'une vidéo, j'ai remarqué que ffmpeg ne finirait pas de rendre certaines images. Le problème a fini par être un "remplissage" d'octet entre deux images jpeg. Si ma taille de mémoire tampon est 4096 et que cette mémoire tampon contient des octets de l'image précédente et de l'image suivante et qu'ils ne sont pas séparés par un nombre quelconque d'octets, l'image suivante n'est pas restituée correctement. Pourquoi donc?

-i path -f image2pipe -c:v mjpeg -q:v 2 -vf fps=25 pipe:1

 enter image description here

Cadre rendu:

 enter image description here

Exemple de code:

public void ExtractFrames()
{
    string FFmpegPath = "Path...";
    string Arguments = $"-i { VideoPath } -f image2pipe -c:v mjpeg -q:v 2 -vf fps=25/1 pipe:1";
    using (Process cmd = GetProcess(FFmpegPath, Arguments))
    {
        cmd.Start();
        FileStream fStream = cmd.StandardOutput.BaseStream as FileStream;

        bool Add = false;
        int i = 0, n = 0, BufferSize = 4096;
        byte[] buffer = new byte[BufferSize + 1];

        MemoryStream mStream = new MemoryStream();

        while (true)
        {
            if (i.Equals(BufferSize))
            {
                i = 0;
                buffer[0] = buffer[BufferSize];
                if (fStream.Read(buffer, 1, BufferSize) == 0)
                    break;
            }

            if (buffer[i].Equals(255) && buffer[i + 1].Equals(216))
            {
                Add = true;
            }

            if (buffer[i].Equals(255) && buffer[i + 1].Equals(217))
            {
                n++;
                Add = false;
                mStream.Write(new byte[] { 255, 217 }, 0, 2);
                File.WriteAllBytes($@"C:\Path...\{n}.jpg", mStream.ToArray());
                mStream = new MemoryStream();
            }

            if (Add)
                mStream.WriteByte(buffer[i]);

            i++;
        }
        cmd.WaitForExit();
        cmd.Close();
    }
}

private Process GetProcess(string FileName, string Arguments)
{
    return new Process
    {
        StartInfo = new ProcessStartInfo
        {
            FileName = FileName,
            Arguments = Arguments,
            UseShellExecute = false,
            RedirectStandardOutput = true,
            CreateNoWindow = false,
        }
    };
}

Un échantillon vidéo (> 480p) d'une durée de 60 secondes ou plus doit être utilisé à des fins de test.

12
Srdjan M.

Ce problème se produit globalement, pour référence extraite du site Adobe: 

La réponse est là: le rendu par défaut est décompressé, qui donne des débits de données si élevés, même les ordinateurs les plus robustes ne le seront jamais être capable de le lire en douceur.

La chose ici est simple: vous obtenez des débits de données élevés, même avec une qualité médiocre. La taille maximale de la mémoire tampon pour ce cas est bien, 4096. Si dans cette mémoire tampon se trouvent des octets des images précédente et suivante et que SONT ne sont pas séparés par une virgule, FFmpeg ne peut pas décider quelle image restituer. suggère quel cadre rafraîchir. 

Si vous séparez les octets par des virgules, vous aidez FFmpeg à lier les octets des images précédentes et suivantes, ce qui permet de distinguer plus facilement le cadre à restituer, évitant ainsi le saut. 

3
Barr J