Programmation.c : Gestion STDIN + pilotage Mplayer
Posté par phentex () le 06 juin 2007
0
Bonjour à tous, amis linuxiens,J'essaie de réaliser un programme sous linux, et je suis dans l'embarras.
Mon programme se lance.
Il fork pour lancer une video Vboucle en boucle dans mplayer. Cette vidéo qui tourne à l'infini est celle qui sert de video d'"attente".
En effet, j'ai un lecteur de codes barres sur port usb. Lorsque j'appuie sur le bouton du lecteur/douchette, le code en caractères correspondant au code barre exposé au lecteur est transmis à STDIN, exactement comme si je l'avais tapé manuellement au clavier. Mon programme doit récupérer la chaine de caractères donnée par le lecteur de code barre.
En fonction du code barre reçu. Une autre vidéo (Vrésultat) est lancée dans mplayer (l'ancien mplayer est alors killé): pas en boucle cette fois, elle est jouée une fois et une seule, puis c'est reparti pour la vidéo d'attente en boucle.
Pendant que la vidéo Vrésultat est en cours de lecture, je compte inhiber le lecteur de code barre (ça je sais pas encore comment), et le réactiver une fois que Vboucle tourne à nouveau.
Mon gros problème:
A partir du moment ou je fork et que j'execl mplayer pour lire la video en boucle, c'est mplayer qui récupère les pressions au clavier, et lorsque je lis un codebarre avec ma douchette, c'est mplayer qui récupère tout, et donc ça va pas du tout du tout (c'est comme si lors d'une lecture de vidéo dans mplayer, vous appuyiez un peu partout sur le clavier dont certaines touches sont affectées à des fonctions diverses).
J'ai consulté de l'aide ça et là, on m'a dit que:
- le processus enfant (qui spawn mplayer par la suite) hérite du stdin de son père (mon programme). On m'a conseillé dans un premier temps de rediriger STDIN du processus fils vers /dev/null à l'aide de dup2. Pas concluant du tout, mplayer continue à récupérer les évènements clavier (et donc le code barre).
- on m'a conseiller d'essayer les paramètres -noconsoleinputs (ou un truc du genre, j'ai pas mon code sous les yeux au moment où je vous écris) --> pas concluant non plus.
- on m'a conseiller d'essayer le mode -slave. --> pas concluant non plus.
Lorsque dans Gnome, je lance mplayer depuis un shell en ligne de commande, je remarque que d'une part il écrit dans le terminal. Mais que d'autre part une fenetre graphique est ouverte, celle-là même dans laquelle est affichée la vidéo. Cette fenêtre graphique récupère le focus de la part de X (donc clavier + souris), et je me demande si ça viendrait pas de là.
Me souvenant que mplayer n'a pas forcément besoin du serveur X pour pouvoir afficher de la video plein écran, j'ai récupéré le fichier de configuration mplayer.conf de GeexBox, pour lancer par la suite mon programme depuis TTY1 (ctrl+alt+F1) en root, et voir ce que ça donne avec un mplayer qui n'ouvre plus une fenetre de window manager, mais écrit directement dans le framebuffer. Manque de pot, sous ubuntu, avec mes drivers ATI proprio, il parait que j'ai pas de framebuffer (on m'a fait lancer un ptit programme qui écrit directement en FBO,et ça m'affiche des "A" rouge plein l'écran).
Très alambiqué tout cela. Mon problème se résume à vouloir lancer un programme d'une part réceptionne des codesbarres de STDIN, et d'autre part pilote mplayer, SANS que mplayer soit sensible à aucun évènement clavier.
Ah oui, dernière chose, on peut effectivement configurer mplayer pour mapper les fonctions qu'on veut, aux touches qu'on veut. j'ai essayé de virer tous les mappages, mais même sans mapping, les touches sont interceptées quand même.
J'aimerai que mon programme garde en somme l'"exclusivité" sur STDIN. Non de dieu!!!
Merci d'avance de votre aide!
> Lire le message (8 commentaires, moyenne: 1,4).
Vous avez demandé le commentaire #839436.



Piloter stdin et stdout d'un fils
Pour piloter le stdin et le stdout d'un fils, il faut, juste après le fork(), fermer stdin et stdout et faire un dup() de deux descripteurs de fichier au préalable défini sur respectivement stdin et stdout. Les deux descripteurs de fichier étant connu du père, en écrivant dessus, on pilote mplayer (avec de préférence -slave mais pas obligé).
Exemple de code repompé d'un d'un de mes vieux projets (le programme à lancer s'appelait apt, rien à voir avec Debian) par flemme de chercher dans Google:
#include <stdio.h> #include <unistd.h> #include <stdlib.h> // exit() #include <string.h> // memset(), strcat()... #include "apt.h" #include "msg.h" #include "init.h" #include "parse.h" #define STDIN 0 #define STDOUT 1 #define STDERR 2 /* The size should be around 500, because of the mvts answer */ #define APT_OUTPUT_LINE_MAX_LENGTH 1000 extern config* current_configuration; int APTIN_K,APTOUT_K; FILE* STREAM_IN; FILE* STREAM_OUT; void APTlaunch(const char *apt_path,int* aptin_k,int* aptout_k){ int childPid; int pipefdin[2],pipefdout[2]; /* Pipes init */ if( pipe(pipefdin) == -1 || pipe(pipefdout) == -1 ){ perror("Creating apt communication pipes"); exit(1); } childPid = fork(); if( !childPid ){ // son, so we launch apt and we connect // its standards channels to pipes // close unused channels close(pipefdin[1]); close(pipefdout[0]); // Duplicate stdin to our pipe close(STDIN); if( dup(pipefdin[0]) == -1 ){ perror("duplicating apt stdin"); exit(1); } // Duplicate stdout to our pipe close(STDOUT); if( dup(pipefdout[1]) == -1 ){ perror("duplicating apt stdout"); exit(1); } // Duplicate stderr to the same pipe as stdout close(STDERR); if( dup(pipefdout[1]) == -1 ){ perror("duplicating apt stderr"); exit(1); } // Launch apt if( execl(apt_path,apt_path,NULL) == -1 ){ perror("can't find apt"); exit(1); } }else{ // father, this process, continues execution // Close unusable channels close(pipefdin[0]); close(pipefdout[1]); // Return the right values to control the apt *aptin_k = pipefdin[1]; *aptout_k = pipefdout[0]; } } void APTstart(const char* apt_path){ // Launch the apt upon the connection APTlaunch(apt_path,&APTIN_K,&APTOUT_K); // Use stdio to manipulate the commands STREAM_IN = fdopen(APTIN_K,"w"); STREAM_OUT = fdopen(APTOUT_K,"r"); } void APTstop(){ write(APTIN_K,"q\n",2); } int APTloadDataFile(const char* filename){ int written; written = fprintf(STREAM_IN,"load %s%s\n",current_configuration->apt_data_path ,filename); fflush(STREAM_IN); return written; } int APTsendCommand(const char* cmd){ int written; written = fprintf(STREAM_IN,"%s\n",cmd); fflush(STREAM_IN); return written; } char* APTgetNextLine(){ char* line; line = (char*)malloc(APT_OUTPUT_LINE_MAX_LENGTH*sizeof(char)); fgets(line,APT_OUTPUT_LINE_MAX_LENGTH,STREAM_OUT); // Careful, the \n is still in line return line; } char* APTgetOutputTillEmptyLine(){ char* buffer; lineList* acftList = (lineList*)malloc(sizeof(lineList)); lineList* otherLines; int byteCounter = 0; acftList->line = APTgetNextLine(); acftList->nextLines = NULL; otherLines = acftList; if( acftList->line[0] != '\n' ){ buffer = APTgetNextLine(); while( buffer[0] != '\n' ){ byteCounter += strlen(buffer); otherLines = addToLineList(otherLines,buffer); buffer = APTgetNextLine(); } } buffer = lineList2string(acftList,byteCounter); freeLineList(acftList); return buffer; } void APTflushOutput(){ char* line = APTgetNextLine(); while( strcmp(line,"\n") ){ free(line); line = APTgetNextLine(); } free(line); }[^]Re: Piloter stdin et stdout d'un fils
Je ne cherche pas vraiment à "piloter" mplayer, tout ce que je souhaite, c'est lancer une vidéo en plein écran:
en forkant/execl on dit à mplayer de lire la vidéo en boucle, dans quel cas suffit d'envoyer un signal à mplayer pour le faire taire par la suite. Pendant ce temps je veux pouvoir faire ma petite cuisine avec la douchette code barre sur STDIN. Je veux que MPLAYER ME FOUTE LA PAIX, Qu'il ne soit PAS sensible à aucune pression clavier. Je me sers juste de Mplayer comme "afficheur de vidéo", that's all.
L'autre cas plus simple est la lecture d'une vidéo une seule fois, dans quel cas, mon programme fait juste un waitpid() pour attendre que mplayer quitte à la fin de la lecture.
Dans tous les cas, mon problème est que Mplayer me laisse tranquille et que mon programme garde la main sur STDIN.
SVP, vous là, oui, vous, je suis sûr que vous savez comment résoudre mon problème. Ayez pitié :°)
ggggnnnnnnnnnnnnnnnnn (interprétation libre)
[^]Re: Piloter stdin et stdout d'un fils
Et pourquoi donc ne fermes-tu pas stdin après avoir forké vers mplayer (comme fait dans l'exemple que je te donne)?
[^]Re: Piloter stdin et stdout d'un fils
Salut,
Je le fais déjà en fait. Mais cela ne résoud pas le problème. Lorsqu'on lance mplayer, utilise non seulement stdin/stdout, mais il ouvre également sa propre fenêtre pour afficher la vidéo. Lorsque cette fenêtre est créée, elle prend le focus dans X qui la branche sur les évènements clavier+souris (!=stdin). Même en atomisant stdin de mplayer, la fenêtre affichant la vidéo reste encore et toujours sensible aux pressions clavier (& donc à la lecture d'un code barre).... :/
ggggnnnnnnnnnnnnnnnnn (interprétation libre)