Commentaires

  1. Avatar de ericb2
    • |
    • permalink
    Citation Envoyé par MaximeCh
    merci
    Bonjour,

    C'est moi. Surtout, n'hésitez pas si vous avez des questions, car je ne suis pas certain d'avoir été très clair.

    Par ailleurs, j'attends un peu pour publier les parties suivantes (partie 3 à venir), parce que j'ai un peu l'impression de spammer le site ;-)
  2. Avatar de MaximeCh
    • |
    • permalink
    merci
  3. Avatar de ericb2
    • |
    • permalink
    Bonjour,

    Citation Envoyé par neuneutrinos
    Félicitation de proposer du contenu, moi je n'arrive pas à aller jusqu'au bout


    Tout d'abord, merci pour tes commentaires. En fait, c'est difficile de définir le bout d"un article. j'essaye de mettre à jour progressivement, et d'améliorer.





    Je vais revenir sur le code , et je te propose de mettre ton code dans un compilateur en ligne (ideone, repl.it par exemple)


    J'avoue ne pas avoir pensé à ça. ça marche même avec un Makefile ?






    Comme ça il sera plus simple de tester le code.

    Choisis entre l'anglais et le français pour les commentaires.


    Oui tu as raison : en fait j'ai assemblé du code que j'ai écrit pour d'autres projets, avec d'abord l'idée de réutiliser, et d'améliorer prochainement.






    scanf (fscanf , sscanf , etc ...) permettent la lecture formatée.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    float x;
    char txt[] = "4e-4";
    sscanf(txt,"%f",&x);
    printf("%f\n",x);//affichera 0.000400
    Donc pas besoin de le recoder (sauf format particulier)
    Il faudra simplement faire attention au retour et à l'encadrement de tes valeurs

    Ce qui simplifiera grandement ton saisie.c



    Je ne sais plus pourquoi je l'avais utilisé, mais il y avait une (plusieurs même) bonne raison (s). Il me semble que j'avais séparé en 2 : pour la saisie d'une chaîne de caractères => fgets() et pour la saisie d'un nombre (à vérifier ensuite) : sscanf

    Parce que les risques de dépassement sont réels avec sscanf().







    utils.h

    Voici ta fonction strlcpy
    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
    /*
     * Copy src to string dst of size siz.  At most siz-1 characters
     * will be copied.  Always NUL terminates (unless siz == 0).
     * Returns strlen(src); if retval >= siz, truncation occurred.
     */
    size_t strlcpy(char *dst, const char *src, size_t siz)
    {
            char *d = dst;
            const char *s = src;
            size_t n = siz;
    
            /* Copy as many bytes as will fit */
            if (n != 0 && --n != 0) {
                    do {
                            if ((*d++ = *s++) == 0)
                                    break;
                    } while (--n != 0);
            }
    
            /* Not enough room in dst, add NUL and traverse rest of src */
            if (n == 0) {
                    if (siz != 0)
                            *d = '\0';                /* NUL-terminate dst */
                    while (*s++)
                            ;
            }
    
            return(s - src - 1);        /* count does not include NUL */
    }
    Je te propose une forme plus épurée.
    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
    size_t strlcpy(char *dst, const char *src, size_t siz)
    {
      size_t destLen=siz;
      char *buf=dst;
      if(siz!=0)//siz==0 ? on ne fait rien
      {
        while(*src!='\0' && --siz > 0)//for(;*src!='\0' && --siz > 0;dst++,src++) mais peut être moins lisible
        {
          *dst=*src;
          dst++;
          src++;
        }
        *dst = '\0';
        destLen=destLen-siz;
        //-1 à cause de la troncature.
        if(siz==0)destLen--;
        
      }
      return destLen;
    }


    Comme indiqué dans les sources, c'est du code sous licence BSD et je l'ai repris tel quel, mais si tu as mieux, ça ne me dérange pas d'intégrer ta contribution :-)





    Si tu mets tous tes MENU_ENTRY_X dans une enum énuméré par défaut , alors ce serait plus simple à utiliser
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    enum MenuEntry
    {
     MENU_ENTRY_1,
     MENU_ENTRY_2,
     //...
     MENU_ENTRY_NB
    };
    //MENU_ENTRY_NB correspondra au nombre de MENU_ENTRY , si j'en ajoute , ça se changera tout seul !

    Oui, oui, c'est juste que je n'ai ai pas pensé sur le moment. J'avais aussi une autre solution, comme celle que j'ai utilisée dans OSS San Baguette (un projet d'élève, que j'ai pas mal suivi)





    L'utilisation d'enum permet de faire plus simple.
    Mais il y a encore mieux si on prévoit des ajouts dans le menu. On pourrait prévoir un tableau de "MenuItem" par exemple (et pointeurs de fonction pour éviter de hardcoder un gros switch par exemple).

    'HASH' tout en majuscule , est curieuse par rapport au reste de ton code.
    'Hash' ou bien 'hash' serait mieux.


    Oui, je vais changer, ce n'est pas très propre. Merci pour la remarque.






    Ensuite, ta hashTable ... est une liste , pourquoi ne pas la renommer hashList ?

    Le "singleton" est assez étrange, ne serait-il pas intéressant de permettre l'utilisation de plusieurs tables de hashage ?


    C'est parce que ce n'est qu'un exemple. En réalité, je ne l'aurais pas codé en C si j'en avais eu besoin, et j'aurais créé une vraie classe C++, et j'aurais créé une instance par table.





    Simplement InitHashTable(Hash* hashTable); par exemple ?
    d'ailleurs certaines fonctions n'utilisent pas ce fameux "singleton" comme push , pop , etc ...

    Question idiote ... il n'y a pas de fonction de hashage ?


    Pour parler de fonction de hachage, il aurait fallu que je définisse une relation entre la clé et la valeur. Ce n'était pas le but ici : la clé et la valeur sont simplement indépendantes. C'est plutôt un dictionnaire que j'ai présenté, dans l'esprit d'un TP de 2h pour être précis.






    Dans le cas où tu n'as pas de collision, une table de hashage doit te retourner/ajouter un élément en O(1) voir O(log(n)).
    Là on est en O(n)...


    Quand la clé est connue, c'est du 0(1)

    Si on cherche une clé, c'est bien du O(n) oui. Mais c'est une table basique, dont le but est de comprendre le principe, sans prétention.






    On ne profite pas des avantages que l'on attend d'une table de hashage (même naïve).
    On se retrouve avec une liste simplement chainée avec un identifiant pour chaque élément...


    La table, on la crée à la main (de façon dynamique). Et c'est même plutôt un dictionnaire.

    Le but, plutôt pédagogique, c'était de vérifier que les fonctions marchent bien et que le cahier des charges était respecté.






    https://jipe.developpez.com/articles.../?page=theorie

    Si tu souhaites un peu d'aide , ce serait avec plaisir

    Avec plaisir : j'apprendrai plein de choses, et le code ne s'en portera que mieux.

    Que préfères-tu : forker le dépôt complet et faire une PR, ou tu crées une issue, et tu attaches un diff (en précisant la licence), et je le commite en ton nom ?

  4. Avatar de neuneutrinos
    • |
    • permalink
    Félicitation de proposer du contenu, moi je n'arrive pas à aller jusqu'au bout

    Je vais revenir sur le code , et je te propose de mettre ton code dans un compilateur en ligne (ideone, repl.it par exemple)
    Comme ça il sera plus simple de tester le code.

    Choisis entre l'anglais et le français pour les commentaires.

    scanf (fscanf , sscanf , etc ...) permettent la lecture formatée.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    float x;
    char txt[] = "4e-4";
    sscanf(txt,"%f",&x);
    printf("%f\n",x);//affichera 0.000400
    Donc pas besoin de le recoder (sauf format particulier)
    Il faudra simplement faire attention au retour et à l'encadrement de tes valeurs

    Ce qui simplifiera grandement ton saisie.c

    utils.h

    Voici ta fonction strlcpy
    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
    /*
     * Copy src to string dst of size siz.  At most siz-1 characters
     * will be copied.  Always NUL terminates (unless siz == 0).
     * Returns strlen(src); if retval >= siz, truncation occurred.
     */
    size_t strlcpy(char *dst, const char *src, size_t siz)
    {
            char *d = dst;
            const char *s = src;
            size_t n = siz;
    
            /* Copy as many bytes as will fit */
            if (n != 0 && --n != 0) {
                    do {
                            if ((*d++ = *s++) == 0)
                                    break;
                    } while (--n != 0);
            }
    
            /* Not enough room in dst, add NUL and traverse rest of src */
            if (n == 0) {
                    if (siz != 0)
                            *d = '\0';                /* NUL-terminate dst */
                    while (*s++)
                            ;
            }
    
            return(s - src - 1);        /* count does not include NUL */
    }
    Je te propose une forme plus épurée.
    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
    size_t strlcpy(char *dst, const char *src, size_t siz)
    {
      size_t destLen=siz;
      char *buf=dst;
      if(siz!=0)//siz==0 ? on ne fait rien
      {
        while(*src!='\0' && --siz > 0)//for(;*src!='\0' && --siz > 0;dst++,src++) mais peut être moins lisible
        {
          *dst=*src;
          dst++;
          src++;
        }
        *dst = '\0';
        destLen=destLen-siz;
        //-1 à cause de la troncature.
        if(siz==0)destLen--;
        
      }
      return destLen;
    }
    Si tu mets tous tes MENU_ENTRY_X dans une enum énuméré par défaut , alors ce serait plus simple à utiliser
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    enum MenuEntry
    {
     MENU_ENTRY_1,
     MENU_ENTRY_2,
     //...
     MENU_ENTRY_NB
    };
    //MENU_ENTRY_NB correspondra au nombre de MENU_ENTRY , si j'en ajoute , ça se changera tout seul !
    L'utilisation d'enum permet de faire plus simple.
    Mais il y a encore mieux si on prévoit des ajouts dans le menu. On pourrait prévoir un tableau de "MenuItem" par exemple (et pointeurs de fonction pour éviter de hardcoder un gros switch par exemple).

    'HASH' tout en majuscule , est curieuse par rapport au reste de ton code.
    'Hash' ou bien 'hash' serait mieux.

    Ensuite, ta hashTable ... est une liste , pourquoi ne pas la renommer hashList ?

    Le "singleton" est assez étrange, ne serait-il pas intéressant de permettre l'utilisation de plusieurs tables de hashage ?
    Simplement InitHashTable(Hash* hashTable); par exemple ?
    d'ailleurs certaines fonctions n'utilisent pas ce fameux "singleton" comme push , pop , etc ...

    Question idiote ... il n'y a pas de fonction de hashage ?

    Dans le cas où tu n'as pas de collision, une table de hashage doit te retourner/ajouter un élément en O(1) voir O(log(n)).
    Là on est en O(n)...

    On ne profite pas des avantages que l'on attend d'une table de hashage (même naïve).
    On se retrouve avec une liste simplement chainée avec un identifiant pour chaque élément...

    https://jipe.developpez.com/articles.../?page=theorie

    Si tu souhaites un peu d'aide , ce serait avec plaisir
  5. Avatar de ericb2
    • |
    • permalink
    Citation Envoyé par lilivve
    Bonjour Eric,

    [Comme je te le disais ailleurs] j'ai trouvé difficile il y a quelques temps d'utiliser ffmpeg dans un projet en C++.

    Ma difficulté tenait à deux choses :
    - Utiliser une API en C, n'étant pas familier de la programmation en C. Même si c'est loin d'être insurmontable si on est habitué au C++, c'était quand même un peu déroutant.
    - Le manque de documentation concernant ffmpeg. J'ai peut-être raté quelque chose, mais je garde le souvenir d'avoir surtout trouvé des exemples (pas tant que cela) que j'essayais d'adapter, avec le sentiment d'être un peu dans l'obscurité. J'aurais aimé trouver une vue d'ensemble du fonctionnement et de la logique de ffmpeg sans avoir besoin de plonger direct dans son code. J'ai été très étonné de ne rien trouver de mieux, ffmpeg est un formidable outil, utilisé dans pas mal de logiciels, je me suis demandé comment s'en sortait les autres développeurs.

    J'ai l'impression que si un jour j'ai nouveau besoin de faire de l'encodage vidéo dans un programme ton wrapper pourra m"aider (je dis wrapper mais j'ai l'impression que c'est un peu plus non ?), d'autant plus qu'il est fourni avec de nombreux exemples. Je t'encourage donc à continuer, et merci pour ce partage.
    Pour être honnête, c'est surtout celui qui a créé ffmpeg-cpp qui a bien bossé. Mais la version Linux n'avançait pas (malgré les demandes) et le code n'est pas si clean (par exemple, pb de visibilité avec les contextes AVFormat, qui n'est toujours pas résolu , ce qui m'a forcé à utiliser 2 threads). Il reste aussi plein de warnings, avec des re-définitions excessives qui doivent encore causer quelques bugs.

    Mais tu as raison, ffmpeg est plus compliqué à utiliser sous forme C/C++ qu'en script. En ce qui me concerne, c'est en aidant plein de monde à corriger des warnings (par exemple : https://github.com/starkdg/phvideoca...8ac0520f86359c) et en faisant des essais que j'ai commencé à y voir plus clair. Remarque : ça fait quand même plus d'un an que je suis dedans.

    Et c'est le fait de pouvoir utiliser des "briques" pour extraire / associer du son, des images m'a décidé à l'utiliser, car quand on n'a plus à mettre les mains dans le cambouis, c'est un vrai plaisir.

    Si tu as besoin d'aide, pas de problème : attention, la plupart des démos fonctionnent bien, mais les résultats demandent quelques ajustement (en particulier MPEG2). En cas de besoin, tu ouvres une issue sur le framagit et je verrai si je peux aider. amha, le truc, c'est de bien définir ce que tu veux faire, et le reste, c'est normalement facile à faire.

    Ce qui m'impressionne le plus, ce sont les filtres :

    - rotation 90°, crop, zoom : ça fonctionne vraiment comme avec ffmpeg, mais dans le code (un vrai plaisir). Le gars qui a implémenté ça (ce n'est pas moi) a vraiment été bon.

    Pour la suite, je compte implémenter VAAPI : si j'ai bien compris, il me manque la création d'un contexte hardware, et l'accélération matérielle (Intel seulement) devrait fonctionner quasi directement, toujours avec les filtres.


    En tout cas, merci encore pour le retour et les encouragements :-)

    Edit : correction du lien
    Mis à jour 04/06/2020 à 18h03 par ericb2
  6. Avatar de lilivve
    • |
    • permalink
    Bonjour Eric,

    [Comme je te le disais ailleurs] j'ai trouvé difficile il y a quelques temps d'utiliser ffmpeg dans un projet en C++.

    Ma difficulté tenait à deux choses :
    - Utiliser une API en C, n'étant pas familier de la programmation en C. Même si c'est loin d'être insurmontable si on est habitué au C++, c'était quand même un peu déroutant.
    - Le manque de documentation concernant ffmpeg. J'ai peut-être raté quelque chose, mais je garde le souvenir d'avoir surtout trouvé des exemples (pas tant que cela) que j'essayais d'adapter, avec le sentiment d'être un peu dans l'obscurité. J'aurais aimé trouver une vue d'ensemble du fonctionnement et de la logique de ffmpeg sans avoir besoin de plonger direct dans son code. J'ai été très étonné de ne rien trouver de mieux, ffmpeg est un formidable outil, utilisé dans pas mal de logiciels, je me suis demandé comment s'en sortait les autres développeurs.

    J'ai l'impression que si un jour j'ai nouveau besoin de faire de l'encodage vidéo dans un programme ton wrapper pourra m"aider (je dis wrapper mais j'ai l'impression que c'est un peu plus non ?), d'autant plus qu'il est fourni avec de nombreux exemples. Je t'encourage donc à continuer, et merci pour ce partage.