2015-07-27 4 views
0

J'essaie actuellement de recueillir des données audio décodées (à partir de plusieurs formats) pour effectuer certaines manipulations audio (en utilisant un fichier * .wav pour les tests).Recueillir l'audio décodé de libav en double

J'ai une classe qui gère tout le décodage via FFmpeg libav. Si j'extraire les données comme unit8_t dans un vecteur, et

for (int i = 0; i < bytevector.size(); i++) { 
    fwrite(&bytevector[i], sizeof (uint8_t), 1, outfile2); 
} 

à un fichier brut et jouer via play -t raw -r 44100 -b16 -c 1 -e signed sound.raw ça sonne parfaitement bien.

Cependant, comment est-il possible d'avoir toutes les informations correctes en double lorsque le fichier est par exemple 2 octets par échantillon et que uint8_t reçoit des informations frame->data? Les fichiers wav que j'ai testés sont 44100/16bits/1 canal. (J'ai déjà un code qui va changer uint8_t * en un double)

Ouvrir les mêmes fichiers avec Scilab montrera la moitié de la taille du vecteur d'octets en double.

fichier wav dans Scilab comme un tableau de doubles montre:
-0,1, -0,099, -0,098, ..., 0,099, +0,1

par rapport octet vecteur:
51, 243, 84, 243, 117, 243, ...

Can 51 et 243 forment-ils réellement un double? Des suggestions sur la façon de surmonter ce problème?

code ci-dessous pour référence:

while ((av_read_frame(formatContext, &readingPacket)) == 0) { 
     if (readingPacket.stream_index == audioStreamIdx) { 
      AVPacket decodingPacket = readingPacket; 

      while (decodingPacket.size > 0) { 
       int gotFrame = 0; 
       int result = avcodec_decode_audio4(context, frame, &gotFrame, &decodingPacket); 

       if (result < 0) { 
        break; 
       } 

       decoded = FFMIN(result, decodingPacket.size); 

       if (gotFrame) { 
        data_size = (av_get_bytes_per_sample(context->sample_fmt)); 
        if (data_size < 0) { 
        } 

        // Only for 1 channel temporarily 
        for (int i = 0; i < frame->nb_samples; i++) { 
         for (int ch = 0; ch < context->channels; ch++) { 
          for (int j = 0; j < data_size; j++) { 
           bytevector.push_back(*(frame->data[ch] + data_size * i + j)); 
          } 
         } 
        } 
       } else { 
        decodingPacket.size = 0; 
        decodingPacket.data = NULL; 
       } 
       decodingPacket.size -= result; 
       decodingPacket.data += result; 
      } 
     } 
     av_free_packet(&readingPacket); 
    } 
+0

'double'? C'est probablement 52 bits de précision, 11 bits de gamme dynamique ou 6000 dB. C'est fou. Et '-b16' dans votre ligne de commande signifie 16 bits, ** pas ** 8 bits. – MSalters

+0

Double est définitivement exagéré pour ce qui est fait à l'audio. J'ai été découragé par le fait que Scilab affiche les valeurs en "double" lorsque le tableau est ouvert dans la visionneuse. Mais oui, ci-dessous est la réponse sur la façon de représenter les données de deux uint8_t (ou 2 octets) de la même manière que Scilab (allant de -1.0 à +1.0). Merci. – gapc

+0

@MSalters - les applications DAW les plus décentes utilisent un traitement interne 64 bits, de cette façon vous perdez moins de précision, même si vous continuez à produire un master 24 bits. – dtech

Répondre

0

moyen rapide pour transformer deux octets en un flottant:

byte bits[] = {195,255}; //first sample in the test s16 wav file 
int16_t sample; 
memcpy(&sample,&bits,sizeof(bits)); 
std::cout<<sample*(1.0f/32768.0f)<<std::endl; 

Ce rendement de code -0.001861572265625 lors de l'impression (avec SetPrecision plus de précision (xx);) qui est le premier numéro donné par Scilab avec le même fichier. J'espère que cela aidera n'importe qui avec des problèmes similaires.

0

Les données audio sont stockées dans de nombreux formats différents. Que vous obtenez un tableau uint8_t[] signifie plutôt peu. Ce n'est pas un octet par tableau. Au lieu de cela, vous devez connaître le format. Ici -b16 me dit que les données uint8_t[] sont en fait des données codées en PCM de 16 bits, c'est-à-dire sur une échelle de -32768 à +32767. Scilab semble préférer une échelle à virgule flottante, et se divise donc par 32768.0. C'est juste un changement de représentation; il réduit juste l'échelle à -1,0, +1,0.

Comparez-le aux angles: un angle droit est de 90 degrés sur pi/2 radians; le nombre exact n'a pas d'importance mais les deux sont 1/4 du cercle complet.