2010-08-06 7 views
11

Pracuję nad odtwarzaniem audio ze strumienia audio przy użyciu VC++ z biblioteką QtMultimedia. Ponieważ nie jestem zbyt doświadczony z bibliotek Qt Zacząłem od czytania w pliku .wav i zapisie do bufora:Odtwarzaj dane audio za pomocą QIODevice (Qt4.6 z VC++)

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

potem użyłem funkcji ifstream za .read() i zapisywać wszystkie dane do bufor. Po bufor jest napisane to wysłany do nagrywarki audio, które przygotowuje ją do 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 jest typu QBuffer)

Po QBuffer jest gotowy próbuję odtworzyć bufor:

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

(m_pAudioOut jest typu QAudioOutput)

wynika to w małym pop z głośników, a potem przestaje grać. Jakieś pomysły, dlaczego?

Uruchamianie Visual Studios 2008 w systemie Windows XP SP2 przy użyciu biblioteki Qt 4.6.3.

Odpowiedz

12

Jak zauważył Frank, jeśli twoim wymaganiem jest po prostu odtwarzanie danych dźwiękowych z pliku, to API wyższego poziomu wykonałoby to zadanie i uprościłoby kod aplikacji. Phonon byłaby jedną z opcji; alternatywnie, projekt QtMobility zapewnia interfejs API QMediaPlayer dla przypadków użycia na wysokim poziomie. Biorąc pod uwagę, że pytanie dotyczy konkretnie korzystania z numeru , i że wspomniałeś, że czytanie z pliku WAV było tylko twoim wstępnym podejściem, zakładam, że faktycznie potrzebujesz API do przesyłania strumieniowego, czyli takiego, który pozwala klientowi kontrolować buforowanie, zamiast przekazywać tę kontrolę do abstrakcji wyższego poziomu, takiej jak Phonon.

QAudioOutput może być używany w dwóch różnych trybach, w zależności od przeciążenia start() nazywa się:

  • "tryb Pull": void QAudioOutput::start(QIODevice *)

    W tym trybie QAudioOutput będzie ciągnąć dane z dołączoną QIODevice bez dalszej interwencji ze strony klienta. Jest to dobry wybór, jeśli używana QIODevice jest używana przez Qt (np. QFile, QAbstractSocket itd.).

  • "tryb push": QIODevice* QAudioOutput::start()

    W tym trybie klient QAudioOutput musi tryb push urządzenia audio poprzez wywołanie QIODevice::write(). To musi być zrobione w pętli, coś jak:

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

    Jak czekanie jest realizowany będzie zależeć od kontekstu aplikacji - jeśli dźwięk jest zapisywany z dedykowanym wątku, to może po prostu sleep(). Alternatywnie, jeśli audio jest zapisywane z głównego wątku, prawdopodobnie będziesz chciał, aby zapis został wywołany przez QTimer.

    Ponieważ nic nie wspominasz o używaniu pętli wokół wywołań write() w aplikacji, wygląda na to, że dzieje się tak, że piszesz krótki segment danych (który gra jako pop), a następnie nie pisz więcej.

Możesz zobaczyć kod za pomocą obu trybów w aplikacji examples/multimedia/audiooutput, która jest dostarczana z Qt.

+0

Ah! Dzięki temu jest znacznie lepszym źródłem informacji niż tylko dokumentacja Qt. "Klonuję" przykładowy kod, który odpowiada moim potrzebom. Wpadłem jednak na dwie kwestie. Kiedy próbuję użyć trybu pull, otrzymuję taki sam wynik jak poprzednio wraz z ostrzeżeniem QObject o tym, jak należy uruchamiać QTimers w wątku. Następnie, gdy używam trybu push, wywołanie odczytu zwraca -1 (błąd). Co prowadzi mnie do przekonania, że ​​coś z moim buforem jest złe. Będę kontynuować pracę nad tym. Dzięki za pomoc. – Tony

+0

Więc patrzę bardziej na metodę pull. Moja metoda "play" po prostu otwiera QBuffer, a następnie uruchamia QAudioOutput (jest to zgodne z przykładem wraz z dokumentacją Qt). Brzmi, jakby zagrał pierwszą nutę, a potem przestał. Ta metoda nie powinna wymagać ode mnie ręcznego upewnienia się, że odtwarza wszystkie pakiety. Pomysły? – Tony

+0

Moje przeczucie było słuszne. Uruchomienie go w aplikacji linii poleceń spowodowało, że program zakończył się i niemal natychmiast zabił dźwięk. Dodałem swój kod do aplikacji GUI i zadziałało! Dzięki za pomoc! – Tony

2

Czy na pewno używasz właściwego API (wysokiego poziomu)? Byłoby dziwne, gdybyś musiał ręcznie obsługiwać strumienie danych i buforowanie. Ponadto, QIODevice :: write() niekoniecznie zapisuje cały bufor, ale może zatrzymać się po n bajtach, podobnie jak POSIX write() (dlatego zawsze należy sprawdzić zwracaną wartość).

Jeszcze nie zaglądałem do QtMultimedia, ale używając bardziej dojrzałego Phonona, wyjścia wideo i audio działały dla mnie dobrze w przeszłości. To działa tak:

  1. Tworzenie obiektu Phonon :: AudioOutput
  2. Tworzenie obiektu Phonon :: mediaobject
  3. Phonon :: createPath (mediaobject, audioObject)
  4. mediaObject-> setCurrentSource (Phonona: : MediaSource (ścieżka));
  5. mediaObject-> play();

Istnieją również przykłady w Qt.

+1

Frank, najpierw zajrzałem do Phonona, ponieważ twierdził, że wspiera strumienie gier. Jednak zawsze, gdy ustawiam źródło na URL strumienia, tj. Rtp: //@123.123.12.1: 8080, nie odtwarza on strumienia. Phonon jest także zależny od systemu, nad którym pracujesz, ponieważ nie implementuje własnego zaplecza (zgodnie z dokumentacją Qt). Na przykład w systemie Windows Phonon używa obsługi backendu z DirectShow i Linux, GStreamer. – Tony

+1

@ Ton: zarówno Phonon, jak i QtMultimedia wymagają backendu, który wykorzystuje odpowiedni natywny interfejs API do implementacji publicznego API Qt. Obecnie backend 'QAudio *' jest statycznie wkompilowany w QtMultimedia.dll, natomiast backendy Phonona są budowane jako osobne biblioteki DLL i ładowane za pośrednictwem mechanizmu wtyczki Qt. Jednak z punktu widzenia projektu, zarówno Phonon, jak i QtMultimedia składają się z ogólnej implementacji, interfejsu backendu i wielu implementacji backendu specyficznych dla platformy. –

Powiązane problemy