2010-08-06 5 views
11

Sto lavorando alla riproduzione di audio da un flusso audio utilizzando VC++ con la libreria QtMultimedia. Dal momento che non sono troppo sperimentato con le librerie di Qt ho iniziato con la lettura in un file wav e la scrittura di un buffer:Riprodurre dati audio utilizzando QIODevice (Qt4.6 con VC++)

ifstream wavFile; 
char* file = "error_ex.wav"; 
wavFile.open(file, ios::binary); 

Dopo di che, ho usato la funzione di ifstream .read() e scrivere tutti i dati in un buffer Dopo che il buffer è scritto è espulso allo scrittore audio che lo prepara per Qt:

QByteArray fData; 

for(int i = 0; i < (int)data.size(); ++i) 
{ 
    fData.push_back(data.at(i)); 
} 

m_pBuffer->open(QIODevice::ReadWrite); 
m_pBuffer->write(fData); 

m_pBuffer->close(); 

(m_pBuffer è di tipo QBuffer)

Una volta che il QBuffer è pronto tento di giocare il buffer:

QIODevice* ioDevice = m_pAudioOut->start(); 
ioDevice->write(m_pBuffer->buffer()); 

(m_pAudioOut è di tipo QAudioOutput)

Questo si traduce in un piccolo pop dagli altoparlanti e poi si interrompe la riproduzione. Tutte le idee perché?

Esecuzione di Visual Studios 2008 su Windows XP SP2 utilizzando la libreria Qt 4.6.3.

risposta

12

Come ha sottolineato Frank, se il requisito è semplicemente quello di riprodurre i dati audio da un file, un'API di livello superiore farebbe il lavoro e semplificherebbe il codice dell'applicazione. Phonon sarebbe una opzione; in alternativa, il progetto QtMobility fornisce l'API QMediaPlayer per casi d'uso di alto livello.

Dato che la domanda riguarda specificamente l'uso di QIODevice e che hai detto che la lettura da un file WAV era solo il tuo approccio iniziale, suppongo che tu abbia effettivamente bisogno di un'API di streaming, cioè una che permetta al client di controlla il buffering, piuttosto che consegnare questo controllo a un'astrazione di livello superiore come Phonon.

QAudioOutput può essere utilizzato in due modi diversi, a seconda di quale sovraccarico start() si chiama:

  • "modalità pull": void QAudioOutput::start(QIODevice *)

    In questa modalità, QAudioOutput estrarrà i dati dalla dotazione QIODispositivo senza ulteriore intervento da parte del cliente. È una buona scelta se il QIODevice utilizzato è uno fornito da Qt (ad esempio QFile, QAbstractSocket ecc.).

  • "modalità Push": QIODevice* QAudioOutput::start()

    In questo modo, il cliente deve spingere QAudioOutput modalità per il dispositivo audio chiamando QIODevice::write(). Questo dovrà essere fatto in un ciclo, qualcosa come:

    qint64 dataRemaining = ... // assign correct value here 
    while (dataRemaining) { 
        qint64 bytesWritten = audioOutput->write(buffer, dataRemaining); 
        dataRemaining -= bytesWritten; 
        buffer += bytesWritten; 
        // Then wait for a short time 
    } 
    

    Come l'attesa è implementato dipenderà dal contesto dell'applicazione - se l'audio è stato scritto da un thread dedicato, potrebbe semplicemente sleep(). In alternativa, se l'audio viene scritto dal thread principale, probabilmente vorrai che la scrittura venga attivata da un QTimer.

    Dato che non si parla di utilizzare un ciclo intorno alle chiamate write() nella propria app, sembra che ciò che sta accadendo sia che si scrive una breve parte di dati (che viene riprodotta come un pop), quindi don non scrivere più

È possibile visualizzare il codice utilizzando entrambe le modalità nell'applicazione esempi/multimedia/audiooutput fornita con Qt.

+0

Ah! Grazie questa è una fonte d'informazione molto migliore della semplice documentazione Qt. Sto "clonando" il codice di esempio che è rilevante per le mie esigenze. Ho incontrato due problemi però. Quando tento di utilizzare la modalità pull, ottengo lo stesso risultato di prima insieme a qualche avvertimento QObject su come i QTimers devono essere avviati in una discussione. Quindi, quando utilizzo la modalità push, la chiamata di lettura restituisce -1 (errore). Il che mi porta a credere che qualcosa con il mio buffer sia sbagliato. Continuerò a lavorare su questo. Grazie per l'aiuto. – Tony

+0

Quindi sto esaminando il metodo pull. Il mio metodo "play" apre semplicemente QBuffer e poi QAudioOutput lo avvia (segue l'esempio insieme alla documentazione Qt). Sembra che suoni la prima nota e poi si fermi. Questo metodo non dovrebbe richiedere a me di verificare manualmente che riproduca tutti i pacchetti. Idee? – Tony

+0

La mia impressione era giusta. L'esecuzione in un'applicazione a riga di comando ha causato la chiusura del programma e la chiusura dell'output audio quasi istantaneamente. Ho aggiunto il mio codice a un'applicazione GUI e ha funzionato! Grazie per l'aiuto! – Tony

2

Sei sicuro di utilizzare l'API corretta (di alto livello)? Sarebbe strano se dovessi gestire manualmente i flussi di dati e il buffering. Inoltre, QIODevice :: write() non scrive necessariamente l'intero buffer ma potrebbe fermarsi dopo n byte, proprio come POSIX write() (ecco perché si dovrebbe sempre controllare il valore restituito).

Non ho ancora controllato QtMultimedia, ma utilizzando il Phonon più maturo, l'uscita video e audio ha funzionato bene per me in passato. Funziona in questo modo:

  1. Creare un oggetto Phonon :: AudioOutput
  2. Creare un oggetto Phonon :: mediaobject
  3. Phonon :: createPath (mediaobject, audioObject)
  4. mediaObject-> setCurrentSource (Phonon: : MediaSource (percorso));
  5. mediaObject-> play();

Ci sono anche esempi in Qt.

+1

Frank, ho esaminato Phonon per primo perché sosteneva di supportare i flussi di riproduzione. Tuttavia, ogni volta che si imposta l'origine su un URL di flusso, ad esempio rtp: //@123.123.12.1: 8080, non riproduce il flusso. Phonon dipende anche dal sistema su cui stai lavorando poiché non implementa il proprio back-end (secondo la documentazione di Qt). Ad esempio, su Windows Phonon utilizza il supporto back-end da DirectShow e su Linux, GStreamer. – Tony

+1

@Tony: sia Phonon che QtMultimedia richiedono un back-end, che utilizza le API native appropriate per implementare l'API Qt pubblica. Al momento, il backend 'QAudio *' è compilato staticamente in QtMultimedia.dll mentre i backend Phonon sono costruiti come DLL separate e caricati tramite il meccanismo del plugin Qt. Ma dal punto di vista del design, sia Phonon che QtMultimedia consistono in un'implementazione generica, un'interfaccia di backend e molteplici implementazioni back-end specifiche per piattaforma. –