Dernièrement, j’ai travaillé sur un programme de partage d’écran simple.
En réalité, le programme fonctionne sur un TCP protocol
et utilise l’ API de duplication de bureau , un service génial qui prend en charge la capture d’écran très rapide et fournit également des informations sur MovedRegions
(les zones qui ont seulement changé de position à l’écran mais qui existent toujours) et UpdatedRegions
(zones modifiées). .
La duplication du bureau a 2 propriétés improtantes: des tableaux de 2 octets, un tableau pour les NewPixels
previouspixels
et un tableau NewPixels
. Tous les 4 octets représentent un pixel sous la forme RGBA . Par exemple, si mon écran est de 1920 x 1080, la taille de la mémoire tampon est de 1920 x 1080 * 4.
Vous trouverez ci-dessous les points saillants de ma stratégie.
À partir de maintenant, j’itère sur les UpdatedRegions (c’est un tableau de rectangles) et j’envoie les limites des régions et Xo’r les pixels qu’il contient, comme ceci:
writer.Position = 0; var n = frame._newPixels; var w = 1920 * 4; //frame boundaries. var p = frame._previousPixels; foreach (var region in frame.UpdatedRegions) { writer.WriteInt(region.Top); writer.WriteInt(region.Height); writer.WriteInt(region.Left); writer.WriteInt(region.Width); for (int y = region.Top, yOffset = y * w; y < region.Bottom; y++, yOffset += w) { for (int x = region.Left, xOffset = x * 4, i = yOffset + xOffset; x < region.Right; x++, i += 4) { writer.WriteByte(n[i] ^ p[i]); //'n' is the newpixels buffer and 'p' is the previous.xoring for differences. writer.WriteByte(n[i+1] ^ p[i+1]); writer.WriteByte(n[i + 2] ^ p[i + 2]); } } }
‘writer’ est une instance de la classe ‘QuickBinaryWriter’ que j’ai écrite (simplement pour réutiliser le même tampon).
public class QuickBinaryWriter { private readonly byte[] _buffer; private int _position; public QuickBinaryWriter(byte[] buffer) { _buffer = buffer; } public int Position { get { return _position; } set { _position = value; } } public void WriteByte(byte value) { _buffer[_position++] = value; } public void WriteInt(int value) { byte[] arr = BitConverter.GetBytes(value); for (int i = 0; i < arr.Length; i++) WriteByte(arr[i]); } }
De nombreuses mesures ont montré que les données envoyées sont vraiment énormes, et parfois, pour une mise à jour unique, les données pouvaient atteindre 200 Ko (après compression!). Soyons honnêtes – 200 Ko n’est vraiment rien, mais si je veux diffuser l’écran en douceur et pouvoir regarder en FPS, je dois travailler un peu dessus pour minimiser le trafic réseau et l’utilisation de la bande passante .
Je recherche des suggestions et des idées créatives pour améliorer l’efficacité du programme – principalement les données envoyées sur la partie réseau (en les emballant d’une autre manière ou de toute autre idée). J’apprécierai votre aide et vos idées. Merci.
Pour votre écran de 1920 x 1080, avec une couleur de 4 octets, vous recherchez environ 8 Mo par image. Avec 20 images par seconde, vous avez 160 Mo / s. Passer de 8 Mo à 200 Ko (4 Mo / s à 20 IPS) représente donc une amélioration considérable.
J’aimerais attirer votre attention sur certains aspects sur lesquels je ne suis pas sûr que vous vous concensortingez, et j’espère que cela aidera.
newpixels
et previouspixels
. Inutile de dire que l’écran original et l’écran diff seront tous compressés / décompressés avec LZ4. De temps en temps, vous devriez envoyer le tableau complet au lieu du diff, si vous utilisez un algorithme avec perte pour compresser le diff. Les idées ci-dessus peuvent être appliquées les unes sur les autres pour une meilleure expérience utilisateur. En fin de compte, cela dépend des spécificités de votre application et des utilisateurs finaux.
MODIFIER:
La quantification des couleurs peut être utilisée pour réduire le nombre de bits utilisés pour une couleur. Vous trouverez ci-dessous des liens vers des implémentations concrètes de Color Quantization
Habituellement, les couleurs quantifiées sont stockées dans une palette de couleurs et seul l’index de cette palette est atsortingbué à la logique de décodage.
Slashy,
Étant donné que vous utilisez des images haute résolution et que vous souhaitez obtenir une bonne cadence, vous envisagez probablement l’encodage H.264. J’ai travaillé sur des vidéos de diffusion HD / SDI qui dépendent totalement de H.264 et qui évoluent un peu en H.265. La plupart des bibliothèques utilisées en broadcast sont écrites en C ++ pour plus de rapidité.
Je suggérerais de regarder quelque chose comme ceci: https://msdn.microsoft.com/en-us/library/windows/desktop/dd797816(v=vs.85).aspx