c# udp windows-phone-7.1 asyncsocket

c# - La alimentación de la cámara de Windows Phone a través de UDP es "terriblemente" lenta



windows-phone-7.1 asyncsocket (2)

He estado trabajando en un proyecto privado en el que quería aprender a programar en un teléfono con Windows, y en un momento empecé a juguetear con tomas de corriente y la cámara, y me vino a la cabeza una gran idea (me molesta incluso intentarlo). )

pero ahora estoy aquí, tengo algo que funciona bien, funciona como un amuleto, pero un Lumia 800 no puede atravesar el bucle for suficientemente rápido. Envía un fotograma por ejemplo, digamos 7-8 segundos, algo que creo que es extraño ya que, bueno, debería ser lo suficientemente fuerte. Parece y se ve como ver porno en un módem de 56k sin pornografía.

También me di cuenta de que un fotograma tiene 317000 píxeles y que sumaría aproximadamente 1 MB por fotograma. También estoy enviando coordenadas xy, por lo que el mío ocupa 2,3 MB por fotograma y sigue trabajando de una manera diferente para solucionarlo y mantenerlo inactivo. así que supongo que tendré que hacer magia domo para obtener valores de posición y de píxeles de un tamaño aceptable. dado que el cajero lo alcanzaría a una velocidad aceptable requeriría al menos 60 MB / s para obtener algo así como 30 fps, pero eso es un problema para otro día.

//How many pixels to send per burst (1000 seems to be the best) const int PixelPerSend = 1000; int bSize = 7 * PixelPerSend; //Comunication thread UDP feed private void EthernetComUDP() //Runs in own thread { //Connect to Server clientUDP = new SocketClientUDP(); int[] ImageContent = new int[(int)cam.PreviewResolution.Height * (int)cam.PreviewResolution.Width]; byte[] PacketContent = new byte[bSize]; string Pixel,l; while (SendingData) { cam.GetPreviewBufferArgb32(ImageContent); int x = 1, y = 1, SenderCount = 0; //In dire need of a speedup for (int a = 0; a < ImageContent.Length; a++) //this loop { Pixel = Convert.ToString(ImageContent[a], 2).PadLeft(32, ''0''); //A - removed to conserve bandwidth //PacketContent[SenderCount] = Convert.ToByte(Pixel.Substring(0, 8), 2);//0 //R PacketContent[SenderCount] = Convert.ToByte(Pixel.Substring(8, 8), 2);//8 //G PacketContent[SenderCount + 1] = Convert.ToByte(Pixel.Substring(16, 8), 2);//16 //B PacketContent[SenderCount + 2] = Convert.ToByte(Pixel.Substring(24, 8), 2);//24 //Coordinates //X l = Convert.ToString(x, 2).PadLeft(16, ''0''); //X bit(1-8) PacketContent[SenderCount + 3] = Convert.ToByte(l.Substring(0, 8), 2); //X bit(9-16) PacketContent[SenderCount + 4] = Convert.ToByte(l.Substring(8, 8), 2); //Y l = Convert.ToString(y, 2).PadLeft(16, ''0''); //Y bit(1-8) PacketContent[SenderCount + 5] = Convert.ToByte(l.Substring(0, 8), 2); //Y bit(9-16) PacketContent[SenderCount + 6] = Convert.ToByte(l.Substring(8, 8), 2); x++; if (x == cam.PreviewResolution.Width) { y++; x = 1; } SenderCount += 7; if (SenderCount == bSize) { clientUDP.Send(ConnectToIP, PORT + 1, PacketContent); SenderCount = 0; } } } //Close on finish clientUDP.Close(); }

He intentado por simplicidad simplemente enviar los píxeles utilizando Indvidialy

BitConverter.GetBytes(ImageContent[a]);

en lugar del lío de análisis de cadenas que he creado (para solucionarlo solo quería una prueba de concepto), pero hacer el simple BitConverter no lo aceleraba demasiado.

así que ahora estoy en mi última idea: el socket del emisor UDP es bastante idéntico al de la biblioteca de msdn.

public string Send(string serverName, int portNumber, byte[] payload) { string response = "Operation Timeout"; // We are re-using the _socket object that was initialized in the Connect method if (_socket != null) { // Create SocketAsyncEventArgs context object SocketAsyncEventArgs socketEventArg = new SocketAsyncEventArgs(); // Set properties on context object socketEventArg.RemoteEndPoint = new DnsEndPoint(serverName, portNumber); // Inline event handler for the Completed event. // Note: This event handler was implemented inline in order to make this method self-contained. socketEventArg.Completed += new EventHandler<SocketAsyncEventArgs>(delegate(object s, SocketAsyncEventArgs e) { response = e.SocketError.ToString(); // Unblock the UI thread _clientDone.Set(); }); socketEventArg.SetBuffer(payload, 0, payload.Length); // Sets the state of the event to nonsignaled, causing threads to block _clientDone.Reset(); // Make an asynchronous Send request over the socket _socket.SendToAsync(socketEventArg); // Block the UI thread for a maximum of TIMEOUT_MILLISECONDS milliseconds. // If no response comes back within this time then proceed _clientDone.WaitOne(TIMEOUT_MILLISECONDS); } else { response = "Socket is not initialized"; } return response; }

En general, terminé con 3 soluciones

  1. Acepta la derrota (pero eso no sucederá así que veamos 2)

  2. Bajar la cantidad de datos enviados (destruye la calidad 640x480 es lo suficientemente pequeño, creo)

  3. Encuentra el problema obvio (Google y amigos se quedaron sin buenas ideas, por eso estoy aquí)


El problema es casi seguro que se trata de jugar con los datos. Convertir un megabyte de datos binarios en varios megabytes de texto y luego extraer y enviar caracteres individuales agregará una sobrecarga masiva por byte de datos fuente. Hacer un bucle a través de píxeles individuales para crear un búfer de envío llevará (en términos relativos) escalas de tiempo geológicas.

La forma más rápida de hacerlo es tomar un búfer de datos binarios de la cámara y enviarlo con una escritura UDP. Solo procese o divida los datos en el teléfono si es necesario y tenga cuidado de acceder a los datos binarios originales directamente; no convierta todo en cadenas y vuelva a ser binario. Cada llamada a un método adicional que agregue a este proceso solo agregará sobrecarga. Si tiene que usar un bucle, intente calcular previamente todo lo que pueda fuera del bucle para minimizar el trabajo que se realiza en cada iteración.


Me vienen a la mente un par de cosas: # 1 Divida la matriz de imágenes sin procesar en pedazos para enviar por el cable. No estoy seguro si Linq está disponible en Windows Phone, pero algo como esto .
# 2 La conversión de int a string a byte será muy ineficiente debido al tiempo de procesamiento y el uso de la memoria. Un mejor enfoque sería copiar en bloque trozos de la matriz int a una matriz de byte directamente. Ejemplo