IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Réseau C Discussion :

Lire et enregistrer du streaming http


Sujet :

Réseau C

  1. #1
    Membre chevronné

    Homme Profil pro
    .
    Inscrit en
    Janvier 2006
    Messages
    703
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : .

    Informations forums :
    Inscription : Janvier 2006
    Messages : 703
    Points : 1 950
    Points
    1 950
    Par défaut Lire et enregistrer du streaming http
    Bonsoir,

    Je cherche depuis quelques temps un moyen de lire et enregistrer une webradio. Je souhaite donc me réaliser un petit programme qui puisse se connecter à la webradio et d'enregistrer les mp3 au fur et à mesure. Je tiens à dire que je fais ça juste pour apprendre. Ce n'est donc pas la finalité du téléchargement qui m'intéresse, mais la manière de faire. Je précise que je suis sous linux, mais que j'aimerais bien que mon programme soit portable sous windows.

    Tout d'abord, il s'agit de la radio suivante : http://208.122.59.30:7024 qui émet via le protocole HTTP un flux mp3 encodé en aac. Ou via un fichier .pls http://www.di.fm/mp3/chillout.pls

    J'ai éssayé un certain nombre de pistes sans vraiment trouver ce que je voulais jusque là:

    licurl
    J'ai essayé de me connecter au serveur en HTTP avec la libcurl avec un petit programme en C, et je reçois bien les informations. Mais c'est encodé et donc illisible et ça défile à l'infini. Je n'ai pas trouvé de moyen de décoder les données.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    #include <stdlib.h>
    #include <stdio.h>
    #include <curl/curl.h>
     
    int main(int argc, char** argv) {
     
    	CURL *curl;
        CURLcode res;
     
        curl = curl_easy_init();
     
        if(curl) {
          curl_easy_setopt(curl, CURLOPT_URL, "http://208.122.59.30:7024");
          res = curl_easy_perform(curl);
     
     
          curl_easy_cleanup(curl);
        }
     
    	return 0;
    }
    les sockets
    J'ai essayé de bosser ça avec les sockets mais je n'arrive pas à récupérer de données. Ca plante au niveau du recv et m'affiche "Reçu :" sans information.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    #if defined (WIN32)
    #include <winsock2.h>
    #elif defined (linux)
    #include <sys/types.h>
    #include <sys/socket.h>
    #include <netinet/in.h>
    #include <arpa/inet.h>
    #include <unistd.h>
    #define INVALID_SOCKET -1
    #define SOCKET_ERROR -1
    #define closesocket(s) close(s)
    typedef int SOCKET;
    typedef struct sockaddr_in SOCKADDR_IN;
    typedef struct sockaddr SOCKADDR;
    #endif
     
    #include <stdio.h>
    #include <stdlib.h>
    #include <errno.h>
     
    #define PORT 7024
     
    int main(void)
    {
        #if defined (WIN32)
            WSADATA WSAData;
            int erreur = WSAStartup(MAKEWORD(2,0), &WSAData);
        #else
            int erreur = 0;
        #endif
     
        SOCKET sock;
        SOCKADDR_IN sin;
        char buffer[3200] = "";
     
        /* Si les sockets Windows fonctionnent */
        if(!erreur)
        {
            /* Création de la socket */
            sock = socket(AF_INET, SOCK_STREAM, 0);
     
            /* Configuration de la connexion */
     
            sin.sin_addr.s_addr = inet_addr("208.122.59.30");
            sin.sin_family = AF_INET;
            sin.sin_port = htons(PORT);
     
            /* Si l'on a réussi à se connecter */
     
            if(connect(sock, (SOCKADDR *)&sin, sizeof(sin)) != SOCKET_ERROR) {
            	printf("Ca marche");
     
            	if(recv(sock, buffer, 3200, MSG_TRUNC) != SOCKET_ERROR) {
                    printf("Recu : %s\n", buffer);
            	} else {
            		printf("erreur");
            	}
            } else {
            	printf("erreur");	
            }
     
            /* On ferme la socket */
            closesocket(sock);
     
            #if defined (WIN32)
                WSACleanup();
            #endif
        }
     
        /* On attend que l'utilisateur tape sur une touche, puis on ferme */
        getchar();
     
        return EXIT_SUCCESS;
    }
    Requête HTTP sous linux
    J'ai exécuté la commande suivante
    echo -en 'GET /\r\n\r\n' | nc 208.122.59.30 7024 | cat -v | head -n 11
    et je reçois
    ICY 200 OK^M
    icy-notice1:<BR>This stream requires <a href="http://www.winamp.com/">Winamp</a><BR>^M
    icy-notice2:SHOUTcast Distributed Network Audio Server/Linux v1.9.8<BR>^M
    icy-name I G I T A L L Y - I M P O R T E D - Chillout - ambient psy chillout, check out our trippy flavors!^M
    icy-genre:Chillout Ambient Psy^M
    icy-url:http://www.di.fm^M
    content-type:audio/aacp^M
    icy-pub:1^M
    icy-br:24^M
    ^M
    M-)M-&^AM-^MM-OM ......... à l'infini si je ne précise pas le nombre de lignes
    wget sous linux
    Avec la commande wget j'ai essayé de me connecter à la webradio qui émet en HTTP. J'ai reçu un fichier html qui grossit à l'infini et qui contient les infos suivantes. Je reçois la même chose que envoyant la requête HTTP sauf que ça s'enregistre dans un fichier index.html qui grossit à l'infini. Donc ici encore je reçois les données, mais je ne sais pas comment les décoder et les enregistrer.

    mplayer sous linux
    Avec mplayer je peux lire mon flux mp3. Ce dernier me lit la webradio et je remarque que je reçois à chaque changement de musique des informations de ce type:

    ICY Info: StreamTitle='Boards Of Canada - Happy Cycling';StreamUrl='';
    La bibliothèque gstreamer
    J'ai découvert la bibliothèque gstreamer qui est pas mal utilisée sous linux (http://gstreamer.freedesktop.org/) Mais j'ai un mal fou à l'utiliser et surtout à savoir comment me connecter à un flux distant. J'arrive à lire un fichier ogg sur mon PC avec quelques lignes de code en C, mais le streaming je n'y arrive pas ...

    Donc voilà, je débute encore beaucoup en programmation en C, mais j'aimerais vraiment me faire la main sur un petit programme sympa histoire de vraiment saisir le fonctionnement du streaming. Donc si jamais vous aviez la moindre idée pour réaliser ce que je cherche à faire ça m'intéresserait énormément

    En vous remerciant d'avance !
    A+

  2. #2
    vic
    vic est déconnecté
    Membre confirmé

    Profil pro
    Inscrit en
    Août 2002
    Messages
    431
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Août 2002
    Messages : 431
    Points : 498
    Points
    498
    Par défaut
    Salut,

    d'abord les données encodées que tu reçois c'est simplement le flux AAC. Tu as d'abord quelques lignes de header HTTP (ce que tu vois en faisant le GET à la main), puis ensuite vient directement le flux.

    Tu peux donc enregistrer directement la sortie du flux dans un fichier, il sera lisible. La difficulté est de savoir comment découper les morceaux. En effet aucune information sur les morceaux n'est donnée, c'est simplement un flux continu. Il faut donc décoder le flux MP3/AAC ou autre en audio, trouver les blancs entre les morceaux et faire le découpage sur cette base. Loin d'être évident. De plus de nombreuses radio font un effet de fondu entre les morceaux ce qui fait qu'il n'y a pas de blanc.

    Il existe également des métadata incluses dans le flux et qui permettent aux lecteurs de donner le titre des morceaux. Voir plus d'infos pour les flux MP3 sur le site suivant :
    http://www.smackfu.com/stuff/programming/shoutcast.html
    Pour les flux en AAC, je n'ai pas d'infos.

    Il existe un outil pour faire ce que tu recherches, qui arrive relativement bien à découper et renommer les morceaux, il s'agit de streamripper :
    http://streamripper.sourceforge.net/
    J'ignore s'il fonctionne avec les flux AAC. Bon courage !

  3. #3
    Membre chevronné

    Homme Profil pro
    .
    Inscrit en
    Janvier 2006
    Messages
    703
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : .

    Informations forums :
    Inscription : Janvier 2006
    Messages : 703
    Points : 1 950
    Points
    1 950
    Par défaut
    Salut vic !
    Merci beaucoup pour ta réponse ! En fait j'aurais dû poster ici depuis longtemps

    Mais en fait j'ai réussi à faire en partie ce que je cherchais juste après avoir posté sur le forum samedi soir. J'ai poussé un peu du côté de curl et j'ai réussi à enregistrer le mp3 dans un fichier. Ô joie, cela marche. Cela revient donc bien à faire ce que tu me dis après coup

    Donc j'ai cherché un bon moment comment récupérer le titre, et je suis tombé sur le site que tu m'as donné. J'ai également trouvé ceux-ci:

    - http://ample.sourceforge.net/developers.shtml#shoutmeta
    - http://forums.radiotoolbox.com/viewtopic.php?t=74

    Donc après avoir cherché, bidouillé, j'ai réussi à isoler le header du flux mp3. J'ai également réussi à repérer le titre des musiques dans les metadata qui se baladent dans le flux (après avoir forcé leur envoi).

    Donc, j'arrive à repérer les chaînes du style:
    StreamTitle='A suivre: Renan Luce - La lettre';StreamUrl='';
    qui se baladent en faisant un simple:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    if(strstr(buffer, "Stream") != NULL) {
            printf("StreamTitle HOURRRRAAAA\n");
        }
    Mais je n'arrive pas "physiquement" à isoler les metadata comme indiqué dans les docs. Je commence à compter dès le premier octet qui suit le header (à savoir \r\n\r\n) Quand j'arrive à N octets avec N qui vaut la valeur metaint de la radio, je prends l'octet qui suit et je le regarde a valeur. Ce dernier devrait alors avoir soit une valeur à 0, soit une valeur correspondant à la taille de la trame metadata qui suit, le tout divisé par 16. Or ça plante complètement chez moi. Mon programme ne me retourne rien ou 0. J'ai vraiment du mal à comprendre ce qui ne va pas. Pourtant je suis très proche du but...
    Et le problème qui arrive aussi c'est que je n'arrive pas à détecter les metadata donc elles finissent dans le flux mp3 enregistré et j'ai des trous + bruit dans la musique ce qui n'est pas des plus agréables.

    Sinon voici mon code, cela pourra peut être aider quelqu'un a comprendre mon problème.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    #include <stdlib.h>
    #include <stdio.h>
    #include <curl/curl.h>
    #include <curl/easy.h>
    #include <string.h>
    #include <math.h>
     
    #include <regex.h>
     
    size_t write_data(void *ptr, size_t size, size_t nmemb, void *stream);
     
    const int METAINT = 32768;
     
    int databytes = 0;
    int totaldatabytes = 0;
     
    int max = 500;
    int count = 0;
     
    int MetaDataStatut = 0;
    int MetaDataLength = 0;
    int MetaDataCurseur = 0;
     
    int complete_header = 0;
    int curseur_lecture = 0; // vaut 0 si c'est du data mp3 et 1 si c'est du metadata
     
    int main(int argc, char** argv) {
     
        CURL *curl;
        CURLcode res;
     
          FILE *fichiersortie;
     
          fichiersortie = fopen("toto.mp3","w");
     
        curl = curl_easy_init();
     
        //int i=0;
     
        if(curl) {
     
     
            struct curl_slist *headers=NULL;
               headers = curl_slist_append(headers, "Icy-MetaData:1"); // On force la récupération des metadata
     
            curl_easy_setopt(curl, CURLOPT_URL, "http://stream-hautdebit.frequence3.net:8000");
     
            curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
     
            curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_data);
     
            curl_easy_setopt(curl,   CURLOPT_WRITEDATA ,fichiersortie);
     
            res = curl_easy_perform(curl);
     
            curl_slist_free_all(headers);
     
            curl_easy_cleanup(curl);
        }
     
        return 0;
    }
     
    size_t write_data(void *ptr, size_t size, size_t nmemb, void *stream)
    {
     
        int curseur = 0;
     
        char *buffer = (char*)malloc(nmemb);
     
        char *Databuffer = (char*)malloc(nmemb);
        char *MetaDatabuffer = (char*)malloc(nmemb);
     
        int i;
     
        for (i=0;i<nmemb;i++)
        {
     
              buffer[i]=((char*)ptr)[i];
     
              if( buffer[i-4] == '\r' && buffer[i-3] == '\n' && buffer[i-2] == '\r' && buffer[i-1] == '\n' ) {
                  complete_header = 1;
                  printf("Le header est terminé, on passe au flux mp3\r\n");
              }
     
              if (complete_header)
              {
     
                  /*
                  databytes++;
                  totaldatabytes += databytes; // On totalise le nombre d'octets (bytes) reçus
                  
                  if (!curseur_lecture) { // Si on est en données 0
                      
                      // On rentre dans la trame de donnée mp3
                      
                      printf("On est en data et databytes vaut %d \n", databytes);
                      // On ajoute l'octet à la chaine de data mp3 a sauvegarder
                      
                      if(databytes == METAINT) {
                          
                          printf("On passe en METADATA\n");
                          
                          curseur_lecture = 1; // On passe en metadata
                          databytes = 0; // On réinitialise le compteur
                      }
                  } 
                  
                  if (curseur_lecture) { // Si on est en metadata 1
                    
                    // On rentre dans la trame de metadata
                    
                    if (MetaDataStatut == 0) {
                        
                        MetaDataLength = abs((int)buffer[i]) * 16;
                        printf("Taille de la trame = %d\n", MetaDataLength);
                        MetaDataStatut = 1; // On passe à la récupération de données
                        
                    }
                    
                    MetaDataCurseur++;
                    
                    if(MetaDataCurseur == MetaDataLength) {
                        curseur_lecture = 0; // On passe au flux mp3
                    }
                  }
     
                  */
              }
     
        }
     
        if(strstr(buffer, "Stream") != NULL) {
            printf("Stream HOURRRRAAAA\n");
     
            printf(ptr);
            printf("\n");
            return nmemb;
        } else {
            if( complete_header ) {
                int written = fwrite(ptr, size, nmemb, (FILE *)stream);
                return written;
            } else {
                return nmemb;
            }
        }
    }
    Sinon un second problème qui m'arrive également doit être aussi lié, quand je me connecte à la radio, je n'ai pas tout de suite le titre de la musique. J'ai beau sniffer toutes les données qui passent à la recherche d'une chaine "Stream" ou "Title" mais rien ne passe. C'est juste au bout d'un moment que ça arrive (dès fois c'est très rapide, dès fois très long). Or quand je lance ma radio sur un autre logiciel style mplayer sous linux ou winamp sous windows j'ai tout de suite le nom de la musique. Alors pour le coup je ne comprends vraiment pas comment ils font pour récupérer les données avant qu'une trame metadata arrive. Ou alors j'ai manqué un truc.

    Pour le découpage de mp3, je n'en suis pas encore là, mais je pense qu'en prenant les données du flux mp3 qui suivent la metadata contenant le nom de la nouvelle musique ça devrait aller, nan ? A moins que ça ne soit pas synchrone avec le changement de musique, auquel cas je suis bon pour analyser et découper le flux comme tu me l'indiques ...

    Je suis tombé également sur streamripper, j'ai regardé hier les sources. Et c'est pas simple du tout ... Je vais essayer de me plonger un peu plus dedans.

    Donc un grand merci d'avance si jamais quelqu'un a la moindre idée de la raison de mon problème. Je pense être proche du but ... il manque peu de choses.

  4. #4
    vic
    vic est déconnecté
    Membre confirmé

    Profil pro
    Inscrit en
    Août 2002
    Messages
    431
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Août 2002
    Messages : 431
    Points : 498
    Points
    498
    Par défaut
    Dans le protocole HTTP, le header est composé des premières lignes du flux. Ensuite vient une ligne vide, et le contenu vient juste après. Donc pour détecter le début tu peux chercher deux sauts de ligne à la suite.

    Le premier octet du flux n'est pas \r\n\r\n, mais celui juste après (ok c'est ce que tu fais dans ton code )

    Pour ton programme, j'ai un peu de mal à débogger du C de tête, mais quelques remarques :
    • J'ai l'impression que l'intervalle entre les trames de métadata est en dur dans le code, il faudrait lire le header envoyé par le serveur
    • N'oublie pas que le metaint est l'intervalle entre trames de métadonnées. Si la trame fait 30 octets et que metaint = 16000, la prochaine trame sera à l'offset N+16030. Une trame vide fait quand même 1 octet.
    • Essaie peut-être avec des buffers d'unsigned char au lieu de char.
    • Si tu utilises strstr, le buffer ne contient peut-être pas la trame de metadata en entier. Il est tout à fait possible que la trame soit en plusieurs paquets, il faut reconstruire les trames dans le code client. Tu rates peut-être beaucoup de trames à cause de ça.
    • Effectivement les metadata ne sont pas synchronisées avec les morceaux, et l'intervalle peut être relativement long, en tous cas ça ne me paraît pas assez fiable pour l'utiliser pour faire le découpage
    • Certaines webradios ont un 2ème port spécial métadata. Cependant ce n'est presque pas documenté et seul winamp et consorts peuvent lire ces données.

    Si tu cherches du code à lire, j'ai écris il y a quelques années une webradio hyper basique en perl. Voir sur mon site en dessous Il se peut même qu'elle supporte les metadonnées, je ne me rapelle plus trop

  5. #5
    Membre chevronné

    Homme Profil pro
    .
    Inscrit en
    Janvier 2006
    Messages
    703
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : .

    Informations forums :
    Inscription : Janvier 2006
    Messages : 703
    Points : 1 950
    Points
    1 950
    Par défaut
    Merci beaucoup vic pour tes conseils

    Je regarderai tout ça ce soir. Effectivement tu as raison, si les metadata sont coupées pile au milieu du titre je ne peux pas le détecter avec ma méthode actuelle. Donc faut que je mette le tout bout à bout et que je trouve un système pour bien repérer chaque trame.

    Mais ma méthode n'est pas bonne, je pense qu'il faut vraiment que je repère l'octet de la taille de trame metadata et que je récupère les N octets qui suivent dans un buffer.

    Sinon je vais essayer tout ce que tu me dis ce soir Merci beaucoup.

    Sinon pour la radio effectivement ça ne serait cool d'avoir un port spécial metadata, mais il faudrait:
    - le trouver
    - savoir comment l'exploiter.

    Le truc c'est qu'il n'y a pas de blancs entre les musiques des webradios que j'écoute. C'est assez embêtant en effet. Déjà je vais essayer de bien repérer les trames metadata et ensuite je verrai si je peux découper les mp3 après chaque metadata de début de piste. Ca doit dépendre des radios je pense. Et pusi si ce n'est pas assez fiable, j'essayerai de trouver une autre méthode.

    En tout cas merci bien pour ton aide
    Je reviendrai certainement d'ici peu, je pense que ça ne va pas être si simple

  6. #6
    Membre chevronné

    Homme Profil pro
    .
    Inscrit en
    Janvier 2006
    Messages
    703
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : .

    Informations forums :
    Inscription : Janvier 2006
    Messages : 703
    Points : 1 950
    Points
    1 950
    Par défaut
    Me revoilà !

    J'ai avancé, mais j'ai un petit soucis, je pense que c'est un problème de C de base, j'ai je n'arrive pas à trouver mon problème, je fais donc appel à votre aide. Sans doute que quelqu'un ce plus expérimenté que moi trouvera le problème en 30 secondes

    J'ai l'impression que l'intervalle entre les trames de métadata est en dur dans le code, il faudrait lire le header envoyé par le serveur
    Oui tu as raison, c'est fait exprès. Je n'ai pas encore cherché à analyser le résultat de la requête HTTP. Pour me faciliter la tâche dans un premier temps j'ai mis la valeur en dur dans mon code étant donné que celle ci est propre à chaque radio et ne change pas au cours du temps.

    Donc pour résumer, j'ai réussi à bien découper mes metadata (enfin je pense ^^) et j'essaie d'enregistrer dans mon fichier le flux mp3 ôté des trames metadata. Mais c'est là que ça coince. J'essaye d'enregistrer le buffer de mes données mp3. Et ça ne marche pas. Mais quand je balance toutes les données (metadata comprises) j'ai bien la musique d'enregistrée, mais celle-ci est pleine de bruit désagréables et de trous.

    Voici mon code.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    182
    183
    184
    185
    186
    187
    188
    189
    190
    191
    192
    193
    194
    195
    196
    197
    198
    199
    200
    201
    202
    203
    204
    205
    206
    207
    208
    209
    210
    211
    212
    213
    214
    215
    216
    217
    218
    #include <stdlib.h>
    #include <stdio.h>
    #include <curl/curl.h>
    #include <curl/easy.h>
    #include <string.h>
    #include <math.h>
     
    #include <unistd.h> // linux
     
    #include <regex.h>
     
    size_t write_data(void *ptr, size_t size, size_t nmemb, void *stream);
     
    const int METAINT = 32768;
     
    // 8192 pour DI
    // 32768 pour frequence 3
     
    int databytes = 0;
    int totaldatabytes = 0;
     
    int max = 500;
    int count = 0;
     
    int MetaDataStatut = 0;
    int MetaDataLength = 0;
    int DataCurseur = 0;
     
    char MetaDatabuffer[5000] = {0};
     
    int complete_header = 0;
    int curseur_lecture = 0; // vaut 0 si c'est du data mp3 et 1 si c'est du metadata
     
    int remplissage_buffer_metadata = 0;
    int remplissage_buffer_mp3 = 0;
    int nmemb_mp3 = 0;
     
    int main(int argc, char** argv) {
     
    	CURL *curl;
        CURLcode res;
     
      	FILE *fichiersortie;
     
      	fichiersortie = fopen("toto.mp3","w");
     
        curl = curl_easy_init();
     
        if(curl) {
     
     
    		struct curl_slist *headers=NULL;
       		headers = curl_slist_append(headers, "Icy-MetaData:1"); // On force la récupération des metadata
     
    		curl_easy_setopt(curl, CURLOPT_URL, "http://stream-hautdebit.frequence3.net:8000");
     
     
    		curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
     
    		curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_data);
     
    		curl_easy_setopt(curl, CURLOPT_WRITEDATA, fichiersortie);
     
    		res = curl_easy_perform(curl);
     
    		curl_slist_free_all(headers);
     
    		curl_easy_cleanup(curl);
    	}
     
    	return 0;
    }
     
    size_t write_data(void *ptr, size_t size, size_t nmemb, void *stream)
    {
    	char* buffer = (char*)malloc(nmemb);
     
    	char* Databuffer = (char*)malloc(nmemb);
     
    	int ecriture = 0;
    	int DataCurseur = 0;
     
    	int i;
     
    	for (i=0;i<nmemb;i++)
    	{
     
      		buffer[i]=((char*)ptr)[i];
     
      		if( buffer[i-4] == '\r' && buffer[i-3] == '\n' && buffer[i-2] == '\r' && buffer[i-1] == '\n' ) {
      			complete_header = 1;
      			printf("Le header est terminé, on passe au flux mp3, on en est à %d octets du paquet HTTP\n", i);
      		}
     
      		if (complete_header)
      		{
      			// Si le header est terminé
     
      			databytes++;
      			totaldatabytes += databytes; // On totalise le nombre d'octets (bytes) reçus
     
      			switch (curseur_lecture) {
     
      				case 0: // On rentre dans la trame de donnée mp3
     
    	  				// On ajoute l'octet à la chaine de data mp3 a sauvegarder
     
    	  				Databuffer[DataCurseur] = ((char*)buffer)[i];
    					nmemb_mp3 = DataCurseur;
     
    	  				if(databytes == METAINT) {
     
    	  					// On arrive en fin de données MP3
     
    	  					curseur_lecture = 1; // On passe en metadata
    	  					databytes = 0; // On réinitialise le compteur
    	  					DataCurseur = 0;
     
     
    	  				} else {
    	  					// DataCurseur n'est pas incrémenté si on est en bout d'entête HTTP 
    	  					if(i != nmemb-1) { 
    	  						DataCurseur++;	
    	  					}
    	  				}
     
    	  				ecriture = 1;
     
    	  				break;
     
    	  			case 1:
     
    					switch (MetaDataStatut) {
     
    						case 0:
     
    							// On rentre dans la trame de metadata
     
    							DataCurseur = 0;
     
    							MetaDataLength = abs((int)buffer[i]) * 16;
     
    							MetaDataStatut = 1; // On passe à la récupération de données
     
    							if(MetaDataLength == 0) {
     
    								curseur_lecture = 0;
    								MetaDataStatut = 0;
    								DataCurseur = 0;
    								databytes = 0;
    								remplissage_buffer_metadata = 0;
    							} else {
    								//printf("Taille de la trame = %d / %d\n", MetaDataLength, nmemb);
    								DataCurseur++;
    							}
    							break;
     
    						case 1:
     
    							// On continue dans la trame metadata
     
    							// Si on arrive au bout de la trame
     
    							if (DataCurseur == MetaDataLength) {
     
    								// On passe au flux mp3
     
    								if(strstr(MetaDatabuffer, "Stream") != NULL) {	
    									printf("%s\n", MetaDatabuffer);
    								}
     
    								curseur_lecture = 0;
    								MetaDataStatut = 0;
    								DataCurseur = 0;
    								databytes = 0;
     
    								remplissage_buffer_metadata = 0;
     
    							} else {
     
    								if (remplissage_buffer_metadata>=5000) {
    									printf("ERREUR\n");
    								} else {
     
    									MetaDatabuffer[remplissage_buffer_metadata] = ((char*)buffer)[i];
    									DataCurseur++;
    									remplissage_buffer_metadata++;
    								}
    							}
     
    							break;
     
    					}
    	  			break;
    			}
      		}
     
    	}
     
    	if( complete_header && nmemb_mp3 !=0 && nmemb_mp3 != 0 && ecriture ) {
     
    		printf("DataCurseur = %d, sizeof(Databuffer) = %d\n", DataCurseur, nmemb_mp3);
     
     
    		int written = fwrite(ptr, size, nmemb, (FILE *)stream);
     
    		printf("written = %d\n", written);
     
    		nmemb_mp3 = 0;
    		DataCurseur = 0;
    		return written;
     
    	} else {
     
    		return nmemb;
    	}
     
    }
    Et donc en gros à la place de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    int written = fwrite(ptr, size, nmemb, (FILE *)stream);
    qui fonctionne, j'aimerais mettre
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    int written = fwrite(Databuffer, size, nmemb_mp3, (FILE *)stream);
    Ce qui correspond au flux mp3 sans metadata alors que ptr contient les metadata.
    Les valeurs sont pourtant correctes il me semble, mais ça n'enregistre pas, et je récupère ça:
    Le header est terminé, on passe au flux mp3, on en est à 246 octets du paquet HTTP
    DataCurseur = 1213, sizeof(Databuffer) = 1213
    written = 1213
    Il doit y avoir un problème avec mon buffer mais je n'arrive pas à trouver le problème ... Si jamais quelqu'un a une idée, je lui en serais très reconnaissant. Je bosse dessus depuis 4 jours sans trouver la solution...

    Merci d'avance

  7. #7
    vic
    vic est déconnecté
    Membre confirmé

    Profil pro
    Inscrit en
    Août 2002
    Messages
    431
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Août 2002
    Messages : 431
    Points : 498
    Points
    498
    Par défaut
    Hello,

    Je ne sais pas si c'est le problème, mais tu mets DataCurseur à zero quand tu entres dans les metadata au lieu d'arrêter de l'incrémenter. Du coup après chaque trame de metadata tu écrases les donnée précédentes.

    Si ton problème s'éloigne du sujet du post initial, essaie de créer un nouveau thread, ça attirera plus de lecteurs.

  8. #8
    Membre chevronné

    Homme Profil pro
    .
    Inscrit en
    Janvier 2006
    Messages
    703
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : .

    Informations forums :
    Inscription : Janvier 2006
    Messages : 703
    Points : 1 950
    Points
    1 950
    Par défaut
    Bonsoir,

    Je me suis remis à mon petit programme avec toujours l'intention de le faire marcher, mais hélas je me suis encore arraché les cheveux toute l'après midi.

    Pour résumer la situation, je souhaite enregistrer un flux mp3 venant de serveurs émettant grâce au protocole shoutcast (www.shoutcast.com). Je redirige le flux directement dans un fichier mp3. Cela fonctionne très bien, mais j'ai droit à quelques parasites très gênants sur le mp3 créé. Ces derniers sont dus aux metadata qui sont les trames d'information (nom de la musique, nom de la radio, etc.) transitant sur le flux. Tout le problème réside dans la lecture de ces trames puis leur suppression du flux musical.

    J'ai donc simplifié mon code (par rapport à la dernière fois) de façon à ce qu'il ne s'occupe que le flux mp3. Lorsqu'une trame metadata arrive, on saute par dessus sans la lire et on reprend l'enregistrement du mp3 juste après la trame.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    #include <stdlib.h>
    #include <stdio.h>
    #include <curl/curl.h>
    #include <curl/easy.h>
    #include <string.h>
     
    #include <unistd.h> // linux
     
    #include <regex.h>
     
     
    size_t write_data(void *ptr, size_t size, size_t nmemb, void *stream);
     
    const int METAINT = 32768;
     
    int http_header 	= 0; 			// Définit si l'entête HTTP est passée ou non
    int CompteurOctets 	= 0; 			// Compte le nombre d'octets de données MP3 vus depuis le dernier metadata
    int MetaDataLength 	= 0;			// Longueur de la trame METADATA
    int TypeDonnees 	= 0;			// Définit si la lecture se fait en MP3 ou METADATA
    									// 0 : MP3 et 1 : METADATA
    int StatutMetadata 	= 0;			// Définit si on est au début ou au milieu des données METADATA
    									// 0 : début et 1 : milieu
     
    char MetaDatabuffer[5000] = {0};
     
    int main(int argc, char** argv)
    {
    	CURL *curl;
    	CURLcode res;
     
      	FILE *fichiersortie;
     
      	fichiersortie = fopen("toto.mp3","wb");
     
    	curl = curl_easy_init();
     
    	printf("============================================\nDEBUT DU PROGRAMME\n============================================\n");
     
        if (curl)
        {
    		struct curl_slist *headers = NULL;
       		headers = curl_slist_append(headers, "Icy-MetaData:1"); // On force la récupération des metadata
    		curl_easy_setopt(curl, CURLOPT_URL, "http://91.121.175.141:80");
    		curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
    		curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_data);
    		curl_easy_setopt(curl, CURLOPT_WRITEDATA, fichiersortie);
    		res = curl_easy_perform(curl);
    		curl_slist_free_all(headers);
    		curl_easy_cleanup(curl);
    	}
     
    	fclose(fichiersortie);
     
    	return 0;
    }
     
    size_t write_data(void *ptr, size_t size, size_t nmemb, void *stream)
    {
    	char* DataBuffer = (char*)malloc(nmemb);
     
    	int DataBufferIndice     = 0;
    	int MetaDataBufferIndice = 0;
     
    	int i=0;
     
    	// On parcourt tous les octets du paquet HTTP reçu
    	for (i;i<nmemb;i++)
    	{
      		// Si on rencontre un double retour à la ligne, l'entête HTTP est terminée
      		if ( http_header == 0 && i>3 &&
      			 ((char*)ptr)[i-4] == '\r' &&
      			 ((char*)ptr)[i-3] == '\n' &&
      			 ((char*)ptr)[i-2] == '\r' &&
      			 ((char*)ptr)[i-1] == '\n' )
      		{ 			
    			http_header = 1;
      		}
     
      		// Dès que l'entête est passée, on peut commencer à enregistrer
      		if (http_header)
      		{
      			CompteurOctets++; // On avance d'un octet dans le MP3
     
      			switch (TypeDonnees)
    			{
      				// Si on est en lecture MP3
      				case 0:
     
    					// Si on est arrivé au length byte
    	  				if (CompteurOctets == METAINT)
    	  				{
    	  					TypeDonnees = 1; // On passe en METADATA
    	  					CompteurOctets = 0;
    	  				}
    	  				else
    					{					
    						DataBuffer[DataBufferIndice] = ((char*)ptr)[i];
    	  					if (i != nmemb-1) DataBufferIndice++;
    	  				}
     
    	  				break;
     
    	  			case 1:				
    					// On est dans les données metadata
     
    					// On récupère la valeur du length byte
    					MetaDataLength = abs((int)((char*)ptr)[i]) * 16;
     
    					// On saute le metadata
    					i += MetaDataLength;
     
    					TypeDonnees 			= 0; // On passe en MP3
    					CompteurOctets 			= 0;
    					MetaDataBufferIndice 	= 0;
     
    	  				break;
    			}
      		} else printf("%c",((char*)ptr)[i]); // On affiche le header HTTP renvoyé par le serveur
    	}
     
    	// On est à la fin du paquet HTTP
    	if (http_header)
    	{		
    		if (DataBufferIndice != 0)
    		{
    			free(DataBuffer);
    			fwrite(DataBuffer, 1, DataBufferIndice+1, (FILE *)stream);
    			return nmemb;
    		} else {
    			free(DataBuffer);
    			return nmemb;
    		}
    	} else {
    		free(DataBuffer);
    		return nmemb;
    	}
    }
    Et le makefile pour les gens qui seraient prets à m'aider
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    CC 	   	   = gcc
    INCLUDES   = -I/usr/include
    CFLAGS	   = -W -Wall -g
    LDFLAGS	   =
    LIBS	   = -L/usr/lib -lcurl
     
    PROG = mp3stream
    OBJS = main.o
     
    all: $(PROG)
     
    main.o: main.c
    	$(CC) -o main.o -c main.c $(INCLUDES) $(CFLAGS)
     
    $(PROG): $(OBJS)
    	$(CC) -o $(PROG) main.o $(LDFLAGS) $(LIBS)
     
    clean:
    	rm -f $(PROG) $(OBJS)
    	rm *.mp3
    Donc, en "théorie", ça devrait passer sans problème et le mp3 final ne devrait pas présenter de parasites. Mais je n'arrive pas à retirer ces derniers. Cela vient certainement d'une erreur de code ou d'une mauvaise interprétation du protocole Shoutcast (mais celui ci, étant propriétaire, on a pas de rfc à se mettre sous la dent pour en savoir plus hélas...)

    Donc encore une fois, si jamais quelqu'un a la moindre idée pour me mettre sur la voie, ça serait vraiment génial. Je travaille sur ce programme depuis des mois sans arriver à me débloquer...

    Un grand merci d'avance

Discussions similaires

  1. [VB6] Comment faire pour lire un fichier en streaming ?
    Par MegaBigBoss dans le forum VB 6 et antérieur
    Réponses: 2
    Dernier message: 20/04/2006, 17h56
  2. Lire un fichier txt par http (C sous Linux)
    Par sleg dans le forum Réseau
    Réponses: 4
    Dernier message: 18/10/2005, 11h07
  3. Réponses: 3
    Dernier message: 01/10/2005, 21h26
  4. Impossible de lire les enregistrements
    Par Bowen dans le forum ASP
    Réponses: 2
    Dernier message: 04/08/2005, 11h33
  5. Comment enregistrer un stream de longueur fixe ?
    Par Alcarbone dans le forum MFC
    Réponses: 5
    Dernier message: 13/04/2003, 20h14

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo