[J2ME] Problème flux mjpeg

Problème flux mjpeg [J2ME] - Java - Programmation

Marsh Posté le 17-06-2007 à 16:36:26    

Salut à tous !
 
Bon voila, j'exploite une caméra IP AXIS qui transmet du flux MJPEG, sur l'émulateur WTK2.5 ca marche nikel, mais une fois sur le mobile ecran blanc ! et pourtant le flux est existant avec ethereal en passant par mon telephone, ca fais quelques jours que je galère avec ça je n'ais plus d'idée , et en plus avec le cout du Ko pour tester ca dans les conditions réel ca n'arrange pas les choses ...
 
// 1er fichier

Code :
  1. package photo;
  2. import javax.microedition.midlet.*;
  3. import javax.microedition.lcdui.*;
  4. import java.io.IOException;
  5. import java.io.*;
  6. import javax.microedition.*;
  7. import javax.microedition.io.HttpConnection;
  8. import javax.microedition.io.Connector;
  9. import java.*;
  10. import java.io.InputStream;
  11. import java.io.OutputStream;
  12. public class PhotoAlbum
  13.     extends MIDlet
  14.     implements CommandListener, ItemStateListener
  15. {
  16.  
  17.     private Display display;
  18.     public String imageName;
  19.     MJPEGParserA parser;
  20.     private PhotoFrame canvas;
  21.     HttpConnection c = null;
  22.     InputStream is = null;
  23.     OutputStream os = null;
  24.   class MJPEGParserA {
  25.    private  final byte[] JPEG_START = new byte[] { (byte) 0xFF, (byte) 0xD8 };
  26.    private final int INITIAL_BUFFER_SIZE = 4096;
  27.    InputStream in;
  28.    byte[] boundary;
  29.    byte[] segment;
  30.    byte[] buf;
  31.    int cur, len;
  32.    boolean canceled = false;
  33.    public boolean isCanceled() {
  34.     return canceled;
  35.    }
  36.    public void setCanceled(boolean canceled) {
  37.     this.canceled = canceled;
  38.     if (canceled) {
  39.      try {
  40.       in.close();
  41.              System.exit(0);
  42.      } catch (IOException e) {
  43.      }
  44.     }
  45.    }
  46.    public MJPEGParserA(InputStream in, String boundary) {
  47.    this.in = in;
  48.     this.boundary = boundary.getBytes();
  49.     buf = new byte[INITIAL_BUFFER_SIZE];
  50.     cur = 0;
  51.     len = INITIAL_BUFFER_SIZE;
  52.    }
  53.    public void parse() throws IOException {
  54.     int b;
  55.     while ((b = in.read()) != -1) {
  56.      append(b);
  57.      if (checkBoundary()) {
  58.       processSegment();
  59.       cur = 0;
  60.      }
  61.     }
  62.    }
  63.  
  64.    protected void processSegment() {
  65.         Image source;
  66.     boolean found = false;
  67.        
  68.     int i;
  69.     for (i = 0; i < cur - JPEG_START.length; i++) {
  70.      if (segmentsEqual(buf, i, JPEG_START, 0, JPEG_START.length)) {
  71.       found = true;
  72.       break;
  73.      }
  74.     }
  75.     if (found) {
  76.     int segLength = cur - boundary.length - i;
  77.     segment = new byte[segLength];
  78.     System.arraycopy(buf, i, segment, 0, segLength);
  79.     source = Image.createImage(segment, 0, segLength);
  80.     canvas.drawImage(source);     
  81.     display.setCurrent(canvas);
  82.     }
  83.    }
  84.    public byte[] getSegment() {
  85.     return segment;
  86.    }
  87.    protected boolean segmentsEqual(byte[] b1, int b1Start, byte[] b2, int b2Start, int len) {
  88.     if (b1Start < 0 || b2Start < 0 || b1Start + len > b1.length || b2Start + len > b2.length) {
  89.      return false;
  90.     } else {
  91.      for (int i = 0; i < len; i++) {
  92.       if (b1[b1Start + i] != b2[b2Start + i]) {
  93.        return false;
  94.       }
  95.      }
  96.      return true;
  97.     }
  98.    }
  99.    protected boolean checkBoundary() {
  100.     return segmentsEqual(buf, cur - boundary.length, boundary, 0, boundary.length);
  101.    }
  102.    public int getBufferSize() {
  103.     return len;
  104.    }
  105.    protected void append(int i) {
  106.     if (cur >= len) {
  107.      byte[] newBuf = new byte[len * 2];
  108.      System.arraycopy(buf, 0, newBuf, 0, len);
  109.      buf = newBuf;
  110.      len = len * 2;
  111.     }
  112.     buf[cur++] = (byte) i;
  113.    }
  114.   }
  115. void postViaHttpConnection(String url) throws IOException {
  116.        
  117.          String boundary = "--myboundary";
  118.        
  119.      
  120.          try {
  121.             c = (HttpConnection)Connector.open(url);
  122.             is = c.openInputStream();
  123.             parser = new MJPEGParserA(is, boundary);
  124.             parser.parse();
  125.          } catch (ClassCastException e) {
  126.              throw new IllegalArgumentException("Not an HTTP URL" );
  127.          } finally {
  128.              if (is != null)
  129.                  is.close();
  130.              if (os != null)
  131.                  os.close();
  132.              if (c != null)
  133.                  c.close();
  134.          }
  135.      }
  136. public PhotoAlbum() {
  137.      display = Display.getDisplay(this);
  138.      canvas = new PhotoFrame(this);
  139.      canvas.setCommandListener(this);
  140. }
  141. protected void startApp() {
  142.   try {
  143.   postViaHttpConnection("http://217.128.151.33/axis-cgi/mjpg/video.cgi?camera=1@fps=25@resolution=160x120" );
  144.     }
  145.      catch(IOException e)
  146.    {
  147.      }
  148. }
  149. protected void pauseApp() {
  150. }
  151. protected void destroyApp(boolean unconditional) {
  152. }
  153.   public void commandAction(Command c, Displayable s) {
  154. }
  155. public void itemStateChanged(Item item) {
  156. }
  157. }


 
 
 
 
 
 
 
 
// 2eme fichier

Code :
  1. package photo;
  2. import javax.microedition.lcdui.*;
  3. import javax.microedition.lcdui.game.*;
  4. import javax.microedition.midlet.*;
  5. public class PhotoFrame extends GameCanvas implements Runnable {
  6.  
  7.     private Thread thread;
  8.     private Graphics g;
  9.     public PhotoFrame(MIDlet midlet) {
  10.    
  11.         super(false);
  12.          g = getGraphics();
  13.      
  14.     }
  15.      void drawImage(Image pic) {
  16.         g.drawImage(pic, 0, 0,
  17.                 Graphics.TOP|Graphics.LEFT);
  18.  
  19.     }
  20.  
  21.     public void destroy() {
  22.         hideNotify();
  23.     }
  24.     public void paint(Graphics g) {
  25.         flushGraphics();
  26.     }
  27.     protected void showNotify() {
  28.         thread = new Thread(this);
  29.         thread.start();
  30.     }
  31.     protected void hideNotify() {
  32.         thread = null;
  33.     }
  34.     public void run() {
  35.          Thread mythread = Thread.currentThread();
  36.         while (mythread == thread) {
  37.             if (mythread == thread) {
  38.                 flushGraphics();
  39.             }
  40.             try {
  41.                 mythread.sleep(5);
  42.             }
  43.             catch (InterruptedException ie) {
  44.             }
  45.             catch (Exception e) {
  46.                 e.printStackTrace();
  47.             }
  48.         }
  49.     }
  50. }


 
Oui je sais c'est pas petit ...

Reply

Marsh Posté le 17-06-2007 à 16:36:26   

Reply

Marsh Posté le 20-06-2007 à 10:06:05    

salut Zymoplex,
 
j'aime beaucoup dans l'url le 'fps=25' : effet garanti en J2ME  :love:  
 
Y'a deux trois trucs que j'ai pas bien compris:
A quoi sert ta String Boundary ?
Que se passe-t-il lorsque chacune des frames dépasse la taille du buffer (je crois voir que c'est prévu, réallocation d'un nvo buffer dans append(int) )?
{ (byte) 0xFF, (byte) 0xD8 } est la chaine qui permet d'identifier le début d'un nvo JPEG, c ça ?
 
Quelle est l'utilité de ton Thread.sleep(5) ?
 
Bon, moi dans WapcamLet, un client de surveillance de caméras et autres fournisseurs de JPEG, j'utilise un mode console en appuyant sur '*' qui me permet d'afficher des infos, comme p.ex. les data qui sont téléchargées. Dans ton cas, vu que ton flux fait 160x120, il doit te rester de la place sur l'écran, profites en pour afficher ce que tu télécharges (format, taille).
 
Tiens, tant que j'y pense: tu es sur que  ton tel supporte le JPEG?vérifie que ton Image.createImage ne lève pas une exception. J'ai mis du temps avt de comprendre que mon tel la JVM de mon tel (sous WM5 qd ^m) ne supportais pas le JPEG. J'ai donc fait un contournement à base de PNG (10 à 15x plus lourd pour les images réelles), ce qui a eu pour effet de porter ma conso GPRS à presque 100 mb. Heureusement j'ai un forfait illimité, le bonheur quoi  :pt1cable:  
 
Voilà, sinon ton code est bien interessant, y'a des choses que j'aurais fait auterment, notamment l'affichage, mais bon rien de choquant. Juste sur le découpages des frames dans le flux, c'est bien standard tt ça ? (SI oui, merci bcp pr l'info)


---------------
Voir les RAW sous Android: https://market.android.com/details? [...] .RawVision Blog Photo: http://photouch.me Applications mobiles: http://caketuzz.com Wapcam Project: http://wapcam.mobi
Reply

Marsh Posté le 20-06-2007 à 10:42:37    

Pfff t'as pas honte de bosser si tu es au bord de la mer ? :o


---------------
Voir les RAW sous Android: https://market.android.com/details? [...] .RawVision Blog Photo: http://photouch.me Applications mobiles: http://caketuzz.com Wapcam Project: http://wapcam.mobi
Reply

Marsh Posté le 20-06-2007 à 21:19:58    

Salut wapcamer,
 
Ouais c'est vrai 25IPS c'est de la sience fiction...  :ange:  
 
Alors le String Boundary en fait c'est le délimiteur de debut de séquence en mjpeg qui est normalement "--myboundary", pour certaines caméras des fois ca change...
Si le JPEG dépasse oui ya réalocation, FFD8 début de l'entete JPEG.
Le Thread.sleep(5) sert pas grand chose en fait c'est des tests j'ai juste oublié de le zapper  :na:  
 
Tous les tests de compatibilité de JPEG etc ... ca fonction no prb.
 
J'avais déja vu ton site et même essayé ton prog qui marche tres bien,tu fais du rafraichissement de JPEG ( je crois ).?
 
Pour ce qui est du procédé de l'analyse du flux je sais pas trop si c'est standard mais ça m'as jamais posé de prb ...  
 
Bon depuis mon post j'ai localisé le prb ( sûr à 95% ) :
 
 
En fait j'ai fais un petit prg C destiné à etre executé sur mon PC, sur lequel je simule l'envoi d'une seule image JPEG mais sans metre fin à la socket, donc pas de SEQ de FIN.
Resultat pas d'image.
 
Mais une fois que j'envoie la SEQ de FIN, l'image apparait sur mon portable , comme si le prog bloquait sur cette ligne " while ((b = in.read()) != -1) " et n'en resortait qu'à la fin de la CNX .... Et j'ai testé ca sur plusieur mobile c'est la meme chose .... le mystère persiste ....

Reply

Marsh Posté le 20-06-2007 à 23:28:18    

Merci pour les eclaircissements sur le boundary et l'en-tête JPEG: ca peut toujours servir.
 

Citation :

J'avais déja vu ton site et même essayé ton prog qui marche tres bien


 :jap:  :sol:  :jap:  hey je suis connu, la classe!!!  ;)  
Effectivement, ma midlet fait du rafraichissement de JPEG (ou PNG, c selon), c pour moi la solution la plus simple et universelle car a priori toutes les cameras (et mon serveur de webcam) fournissent des snapshots. Finalement c'est comme du MJPEG mis à part l'overhead des requetes HTTP.
 
Pour ton pb, j'aurais dit que tu as donné toi-même la réponse, mais en regardant mieux le code, j'ai l'impression que c'est qd m correct ce que tu as fait.
En effet, tu sembles analyser les données au fur et à mesure qu'elles arrivent dans ton while( in.read()!=-1).
Le problème vient pt-ê de l'algorithme qui suit dans checkBoundary() et processSegment().
Mais là je suis désolé, ça devient un peu trop difficile pr moi pr le comprendre rapidement (en - de 5 min quoi  :D ), mais en gros l'idée c de repérer l'en-tête de début de la Frame N, puis l'en-tête de début de la frame N+1, puis d'extraire les data entre les deux dans ton buffer et créer l'image qui va bien - bon je ne doute pas que c ce que tu as essayé de faire.
 
Puisque tu disposes de ton simulateur de MJPEG en mode pas-à-pas, profites-en pour tester ta logique d'extraction de frame: p.ex. tu px envoyer ta premiere image en 3 morceaux, sachant que tu t'attends à ce que la midlet affiche une image au bout du troisième paquet. Ce 3e paquet devra aussi comporter le début de la seconde image. Répète l'exercice 2 3 fois, et si ca tient la route, ton algo devrait être bon.
 
Pour info, j'ai testé ta midlet ce matin et si je vois bien le flux ds mon navigateur, en revanche la midlet (sur l'ému du WTK) n'a jamais rien afiché.
 
@++ :hello:  


---------------
Voir les RAW sous Android: https://market.android.com/details? [...] .RawVision Blog Photo: http://photouch.me Applications mobiles: http://caketuzz.com Wapcam Project: http://wapcam.mobi
Reply

Marsh Posté le 21-06-2007 à 08:15:28    

Salut !
 
Au niveau fonctionnement c'est Ok, puisque chez moi dans le WTK ca fonctionne sans problème ... et toi tu me dis que ca ne fonctionne pas dans le tiens ?? tu peux me donner ta version ?
 
Je te donne les liens pour les fichiers compilé réessai les stp ..
 
http://pat.bevilacqua.free.fr/Photoalbum.jad
http://pat.bevilacqua.free.fr/Photoalbum.jar
 
++

Reply

Marsh Posté le 22-06-2007 à 13:50:25    

Salut,
désolé j'ai pas pu te répondre directement, un pb d'alim de mon PC à changer  :pt1cable:  
 
Mon WTK je crois que c le 2.1, mais je pense pas que ca change quoi que ce soit vu que tu n'utilises que des classes MIDP 1.
 
Alors j'ai pt-ê merdé ma compil (bon j'en doute) donc je vais essayer ton jar et te tiens au courant dès que possible.
 
@+


---------------
Voir les RAW sous Android: https://market.android.com/details? [...] .RawVision Blog Photo: http://photouch.me Applications mobiles: http://caketuzz.com Wapcam Project: http://wapcam.mobi
Reply

Marsh Posté le 23-06-2007 à 08:52:49    

Salut !
 
Ok, j'attends ton test !
 
++

Reply

Marsh Posté le 23-06-2007 à 12:30:01    

Bon ben, ca marche décidément pas:
 
Quand je fais Run Midlet: j'indique le jad, tt va bien, le jar est à côté. On arrive sur le menu ds l'émulateur avec les midlets installées. J'essaye de lancer la tienne: J'ai le msg comme quoi il demande l'autorisation pour aller sur le net, normal.
Puis avant de faire quoi que ce soit on retourne( ou on reste) sur la page avec les midlets à lancer.
J'ai pas le Sysytem.out avec cette méthode dc je sais pas ce qui cloche (je l'ai par contre qd je lancel'ému depuis mon env. de dev.)
 
Voilà c'est un peu bizzarre si ca marche si bien chez toi.
 
Est-ce que tu es sur le même réseau local que la caméra?
 
Je vais essayer d'investiguer un peu +.
 
@++


---------------
Voir les RAW sous Android: https://market.android.com/details? [...] .RawVision Blog Photo: http://photouch.me Applications mobiles: http://caketuzz.com Wapcam Project: http://wapcam.mobi
Reply

Marsh Posté le 23-06-2007 à 13:26:31    

Eh bah, c'est vraiment étrange ca ...
 
Non je ne suis pas sur le reseau local de la caméra ..
 
 
++

Reply

Marsh Posté le 23-06-2007 à 13:26:31   

Reply

Marsh Posté le 23-06-2007 à 16:23:04    

Je confirme :
 
après installation de WTK2.1 ca ne marche pas, meme prb que toi ....
 
On dirait qu'il rempli sont buffer jusq'uà sa limite et il attend.


Message édité par zymoplex le 23-06-2007 à 16:25:41
Reply

Marsh Posté le 23-06-2007 à 20:31:40    

Alors là, je crois halluciner: qu'ils changent l'implémentation de l'émulateur d'une HttpConnection (MIDP 1 donc) entre le WTK2.1 et le WTK2.5 est vraiment bizarre. D'ailleurs il ne peut pas être si vieux que ca le WTK2.1: ce PC (le mien) a moins de trois ans et je faisais deja du j2me bien avant.
 
Peut-être qu'ils ont juste amélioré la tolérance pour faciliter les dev.
 
MAis dans ce cas j'aurais tendance à penser que les terminaux seront plus proches du WTK21 que 25, vu que les implémentations de JVM sont tjs un peu pourries qq part.
 
Est-ce que tu px placer des System.out dans ta boucle de lecture pour voir si tu peux deja arriver à traiter des paquets à la volée. Pq un gros pb qui se pose là, c'est la possibilité de faire du vrai multithreading avec la connexion wap. Ca m'étonnerait pas que le thread Connection machin bloque les autres threads tant qu'il n'a pas aboutit. Et ca doit être qqch de très variable selon les téléphones.
 
Bon je vais essayer de regarder encore peu, voire pt-ê aussi passer au WTK25, il faudra bien y venir un jour  ;)  
 
 :hello:


---------------
Voir les RAW sous Android: https://market.android.com/details? [...] .RawVision Blog Photo: http://photouch.me Applications mobiles: http://caketuzz.com Wapcam Project: http://wapcam.mobi
Reply

Marsh Posté le 25-06-2007 à 13:23:32    

Lut !
 
Je comprends pas le WTK2.1 c'est du MIDP 2.0 ? ou MIDP 1.0 ?
 
Bon j'ai un prb de gestion d'affichage avec le WTK2.1, mais sinon les donnees passent, j'ai mis un system.out , mais ca m'a l'air d'etre différent sur le vrai mobile, tjrs le meme prb dessus avec la ligne "read" ...


Message édité par zymoplex le 25-06-2007 à 13:24:16
Reply

Marsh Posté le 25-06-2007 à 16:20:41    

WTK2.1 est MIDP2 (ou 1 au choix mais le standard est supporté)
Et de tte façon ton code est MIDP1 donc ca devrait pas poser de pbs.
 
Ce qui change avec les nelles versions du WTK, c'est le support de nouveaux JSR et éventuellement des corrections de bugs. C'est pour ça que je n'ai pas éprouvé le besoin de passer à une version supérieure.
 
Et oui il ya souvent divergence entre le comportement de l'émulateur et celui du (des !) terminal. Pour moi, évidemment, il n'y a que le test en vrai sur le téléphone qui fait foi, car c'est clair qu'un PC est bcp plus puissant qu'un téléphone.
Comme je t'ai dit, il y a surement des pb dues à la gestion des threads et l'utilisation de la stack GPRS ou réseau. Je te conseillerai d'ailleur s de faire gérer l'affichage dans le thread principal et la connexion HTTP dans un thread secondaire, plutôt que l'inverse.
 
Il est aussi possible que in.read() ne retourne pas tant que tout n'est pas lu, or comme ton flux ne s'arrête jamais -> problème.
Tu px essayer de faire un read seulement de la taille d'un buffer prédéfini genre "in.read(byte[] b) "


---------------
Voir les RAW sous Android: https://market.android.com/details? [...] .RawVision Blog Photo: http://photouch.me Applications mobiles: http://caketuzz.com Wapcam Project: http://wapcam.mobi
Reply

Marsh Posté le 25-06-2007 à 19:15:31    

Wé bonne idée pour le buffer prédéfini je vais regarder ca ..
 
Merci

Reply

Marsh Posté le 25-06-2007 à 22:01:50    

Bon , ca marche pas il reste tjrs bloqué sur cette P....N de ligne jusqu'à la fin de la communication, ca commence à me courrir ce truc !  :pt1cable:

Message cité 1 fois
Message édité par zymoplex le 25-06-2007 à 22:02:08
Reply

Marsh Posté le 25-06-2007 à 23:31:58    

Ben là je crains que malheureusement ...
 
C quoi ton téléphone? est-ce que tu en as un autre sous la main ( de préférence de chez nokia) pour faire le test ?


---------------
Voir les RAW sous Android: https://market.android.com/details? [...] .RawVision Blog Photo: http://photouch.me Applications mobiles: http://caketuzz.com Wapcam Project: http://wapcam.mobi
Reply

Marsh Posté le 26-06-2007 à 13:04:21    

C'est un siemens CX75, Non pas d'autre sous la main, mais j'ai testé avec un V800 sony ericsson mais même probleme


Message édité par zymoplex le 26-06-2007 à 13:04:46
Reply

Marsh Posté le 26-06-2007 à 22:10:08    

zymoplex a écrit :

il reste tjrs bloqué sur cette ligne jusqu'à la fin de la communication :pt1cable:


 
Là je crains qu'il va falloir que tu changes de méthode, parce que je ne vois pas comment contourner ce genre de problèmes malheureusement.
Après il y a le shot par shot comme le fait WapcamLet, mais bon là encore tu risques de te heurter à d'autres problèmes.
 
Si quelqu'un d'autre a une idée, il est le bienvenu, mais moi je sèche, sorry.


---------------
Voir les RAW sous Android: https://market.android.com/details? [...] .RawVision Blog Photo: http://photouch.me Applications mobiles: http://caketuzz.com Wapcam Project: http://wapcam.mobi
Reply

Marsh Posté le 27-06-2007 à 00:15:38    

Bon,
 
Je crois que je vais réfléchir à une tout autre méthode.., Je te remercie de tes efforts. !
 
@++

Reply

Marsh Posté le 07-08-2007 à 23:57:04    

Hello Zymo,
je te relance car depuis, j'implémente le flux MJPEG sur mon serveur de webcam.
 
Hors en le testant depuis mon gsm, et bien je me rends compte que ça ne marhce pas (évidemment) et j'ai une autre piste de reflexion.
Les connexions GPRS, je suppose que c'est ce que tu utilises, en tout cas moi oui, passent par un GGSN qui est une gateway/proxy. J'ai donc l'impression au vu de mes essais qu'aucune donnée n'arrive sur mon portable. Je pense donc que le GGSN attend la fin de la réponse du serveur MJPEG pour envoyer le résultat sur le mobile. Comme le flux MJPEG est ininterrompu, et bien il ne renvoie jamais les images (qui sont bien émises cependant) vers le mobile.
 
De ton côté, as-tu pu avancer sur le sujet? as-tu trouvé des contournements?


---------------
Voir les RAW sous Android: https://market.android.com/details? [...] .RawVision Blog Photo: http://photouch.me Applications mobiles: http://caketuzz.com Wapcam Project: http://wapcam.mobi
Reply

Marsh Posté le 07-08-2007 à 23:59:46    

ah, je viens de voir sur ton thread developpez.com que ca marche sur d'autres mobiles.
 
Au temps pour moi alors.
 
Ben de mon côté mon problème persiste - je suis sur i320 (WM5) et j'utilise TCPMP comme lecteur.
 
@+


---------------
Voir les RAW sous Android: https://market.android.com/details? [...] .RawVision Blog Photo: http://photouch.me Applications mobiles: http://caketuzz.com Wapcam Project: http://wapcam.mobi
Reply

Marsh Posté le 19-08-2007 à 21:30:59    

L'algo que tu utilise pour parser le flux (trouvé ici : http://forum.java.sun.com/thread.j [...] ID=4042430 ) est tres mal codé et surtout ABSOLUMENT pas optimisé.
Vu comment il rame sur mon C2D, j'ose même pas imaginer les perf sur un téléphone portable (en général a 40/50Mhz).
 
Bref, J'ai commencé a réimplementer l'algo plus proprement mais parser (correctement) un flux mjpeg n'est pas chose facile :/
 
 
J'ai fais quelques essais de "streaming jpeg" il y a quelques temps sur téléphone (hein wapcamer ;) ) et le mieux que j'ai réussi a tenir c'est 10fps (limité par la bande passante) mais il faut épargner ton pauvre téléphone : ne lui laisser aucun traitement a faire.
 
En gros tu dois lui envoyer les images jpeg dans la resolution de l'ecran du téléphone les unes a la suite des autres avec un header (2 octets) indiquant la taille de l'image qui suit.
 
Tu trouvera plus d'infos ici : http://www.psykokwak.com/blog/inde [...] n-foxboard


Message édité par azubal le 10-03-2008 à 09:44:02
Reply

Marsh Posté le    

Reply

Sujets relatifs:

Leave a Replay

Make sure you enter the(*)required information where indicate.HTML code is not allowed