Decomprimere e decodificare un file mp3 con le funzioni esterne del API di AVbin

Da Gambas-it.org - Wikipedia.

AVbin è una libreria di decodifica multimediale audio/video multipiattaforma che intende garantire alle applicazioni la compatibilità binaria a lungo termine.

La documentazione di AVbin può essere trovata:
- nel codice sorgente: "/usr/include/avbin.h;
- nel API online di riferimento |2|


Per poter fruire delle risorse di Avbin è necessario utilizzare nelle applicazioni Gambas la libreria (nella sua attuale versione): libavbin.so.0.0.7


Il seguente esempio provvede a decomprimere e decodificare un file audio mp3, nonché successivamente a creare mediante i dati grezzi - ottenuti dalla decodificazione - un file audio wav con frequenza di campionamento hz 44100, risoluzione 16bit e 2 canali d'uscita:

Public Struct AVbinStreamInfo
  structure_size As Long        ' Size of this structure, in bytes.
  type As Integer               ' The type of stream; either audio or video.
  sample_format As Integer      ' The sample format for audio data.
  sample_rate As Integer        ' Number of samples per second, in Hz.
  sample_bits As Integer        ' Number of bits per sample; typically 8 or 16.
  channels As Integer           ' Number of interleaved audio channels.
End Struct

Public Struct AVbinPacket
  structure_size As Long        ' Size of this structure, in bytes.
  timestamp As Long             ' Point in time, or a time range; given in microseconds
  stream_index As Integer
  data As Pointer
  size As Long
End Struct


Library "libavbin:0.0.7"

Private Enum AVBIN_RESULT_ERROR = -1, AVBIN_RESULT_OK
Private Enum AVBIN_STREAM_TYPE_UNKNOWN = 0, AVBIN_STREAM_TYPE_VIDEO, AVBIN_STREAM_TYPE_AUDIO
 
' AVbinResult avbin_init()
' Initialise AVbin.
Private Extern avbin_init() As Integer

' AVbinFile *avbin_open_filename(const char *filename)
' Open a media file given its filename.
Private Extern avbin_open_filename(filename As String) As Pointer

' AVbinResult avbin_stream_info(AVbinFile *file, int stream_index, AVbinStreamInfo *info)
' Get information about a stream within the file.
Private Extern avbin_stream_info(avfile As Pointer, strindex As Integer, infoFlux As AVbinStreamInfo) As Integer

' AVbinStream *avbin_open_stream(AVbinFile *file, int stream_index)
' Open a stream for decoding.
Private Extern avbin_open_stream(avfile As Pointer, stream_index As Integer) As Pointer

' AVbinResult avbin_read(AVbinFile *file, AVbinPacket *packet)
' Read a packet from the file.
Private Extern avbin_read(avfile As Pointer, pack As AVbinPacket) As Integer

' int64_t avbin_get_audio_buffer_size()
' Get the minimum audio buffer size, in bytes.
Private Extern avbin_get_audio_buffer_size() As Long

' int avbin_decode_audio(AVbinStream *stream, uint8_t *data_in, int64_t size_in, uint8_t *data_out, int *size_out)
' Decode some audio data. You must ensure that data_out is at least as big as the minimum audio buffer size.
Private Extern avbin_decode_audio(avst As Pointer, data_in As Pointer, size_in As Long, data_out As Byte[], size_out As Pointer) As Integer
 
' void avbin_close_stream(AVbinStream *stream)
' Close a file stream.
Private Extern avbin_close_stream(avst As Pointer)

' void avbin_close_file(AVbinFile *file)
' Close a media file.
Private Extern avbin_close_file(avfile As Pointer)


Public Sub Main()

 Dim err, stream_index, bytesread, bytesleft, bytesout, nrBytes As Integer
 Dim percorsoFile As String
 Dim media, audio_stream As Pointer
 Dim streaminfo As New AVbinStreamInfo   ' Opaque open stream handle
 Dim packet As New AVbinPacket
 Dim audio_buffer As New Short[]
 Dim audio_data As Byte[]
 Dim fl As File
 Dim bh As Byte[] = [&52, &49, &46, &46, &00, &00, &00, &00, &57, &41, &56, &45, &66, &6D, &74, &20, &10, &00, &00, &00, &01, &00, &02, &00,
                   &44, &AC, &00, &00, &10, &B1, &02, &00, &04, &00, &10, &00, &64, &61, &74, &61, &00, &00, &00, &00]   ' blocco d'intestazione del file wav futuro: 2 canali, 16 bit, hz 44100
 

  percorsoFile = "/percorso/del/file.mp3"
 
  err = avbin_init()
  If err = AVBIN_RESULT_ERROR Then Error.Raise("Impossibile inizializzare la libreria 'libavbin' !")
   
  media = avbin_open_filename(percorsoFile)
  If IsNull(media) Then Error.Raise("Impossibile aprire il file " & File.Name(percorsoFile))

 ' E' assolutamente necessario passare al membro ".structure_size" la dimensione della Struttura di appartenenza:
  streaminfo.structure_size = Object.SizeOf(streaminfo)

  err = avbin_stream_info(media, stream_index, streaminfo)
  If err = AVBIN_RESULT_ERROR Then Error.Raise("Errore alla funzione 'avbin_stream_info()' !")
   
  If streaminfo.type = AVBIN_STREAM_TYPE_VIDEO Then
    Print "ATTENZIONE: Il file caricato è un file 'Video' !\nQui intendiamo invece verificare solo file mpeg audio."
  Else
    If streaminfo.sample_rate + streaminfo.sample_bits + streaminfo.channels = 44118 Then
      Print "\nCaratteristiche del flusso audio:"
      Print "- Frequenza di campionamento: "; streaminfo.sample_rate; " hertz"
      Print "- Risoluzione: "; streaminfo.sample_bits; " bit"
      Print "- Canali di uscita: "; streaminfo.channels
    Else
      Error.Raise("Il file mp3 caricato non ha le caratteristiche richieste: 'Hz 44100', '16bit', '2 canali' !")
    Endif
  Endif

' Crea il futuro file wav:
  fl = Open "/tmp/audio.wav" For Create

' Inizia la scrittura del blocco d'intestazione del file wav:
  bh.Write(fl)

  audio_stream = avbin_open_stream(media, 0)
  If IsNull(audio_stream) Then Error.Raise("Impossibile creare un flusso audio !")

  packet.structure_size = Object.SizeOf(packet)

  While Not avbin_read(media, packet)

    audio_buffer = New Byte[8192]
    bytesleft = audio_buffer.Count
    bytesout = bytesleft
    audio_data = New Byte[audio_buffer.Count]
 
    bytesread = avbin_decode_audio(audio_stream, packet.data, packet.size, audio_data, VarPtr(bytesout))

    While bytesread > 0
      packet.data += bytesread
      packet.size -= bytesread
      audio_data.Resize(audio_data.Count + bytesout)
      bytesleft -= bytesout
      bytesout = bytesleft
      bytesread = avbin_decode_audio(audio_stream, packet.data, packet.size, audio_data, VarPtr(bytesout))
    Wend
 
    nrBytes = audio_data.Count - audio_buffer.Count

' Scrive dunque i dati audio grezzi decompressi nel file wav:
    audio_data.Write(fl, 0, nrBytes)

  Wend

  
' Va in chiusura:
  fl.Close
  avbin_close_stream(audio_stream)
  avbin_close_file(media)

End


Riferimenti

[1] Il sito di Avbin
[2] Il sito del API di Avbin