[英]Streaming Audio with OpenAL and FFMPEG
好吧,基本上我正在研究一個簡單的視頻播放器,我可能會問另一個關於滯后視頻\\同步到音頻的問題,但是現在我遇到了音頻問題。 我設法做的是瀏覽視頻的所有音頻幀並將它們添加到矢量緩沖區,然后使用OpenAL從該緩沖區播放音頻。
這是低效率和內存占用,所以我需要能夠使用我猜稱為旋轉緩沖區的流。 我遇到了一些問題,一個是關於OpenAL流媒體的信息不多,更不用說使用FFMPEG解碼音頻並將其傳輸到OpenAL的正確方法了。 我甚至不太習慣使用矢量作為我的緩沖區,因為我真的不知道矢量在C ++中是如何工作的,但我有些人設法從我的頭腦中拉出一些東西來使其工作。
目前我有一個如下所示的Video類:
class Video
{
public:
Video(string MOV);
~Video();
bool HasError();
string GetError();
void UpdateVideo();
void RenderToQuad(float Width, float Height);
void CleanTexture();
private:
string FileName;
bool Error;
int videoStream, audioStream, FrameFinished, ErrorLevel;
AVPacket packet;
AVFormatContext *pFormatCtx;
AVCodecContext *pCodecCtx, *aCodecCtx;
AVCodec *pCodec, *aCodec;
AVFrame *pFrame, *pFrameRGB, *aFrame;
GLuint VideoTexture;
struct SwsContext* swsContext;
ALint state;
ALuint bufferID, sourceID;
ALenum format;
ALsizei freq;
vector <uint8_t> bufferData;
};
底部的私有變量是相關的。 目前我正在將類構造函數中的音頻解碼為AVFrame,並將數據添加到bufferData,如下所示:
av_init_packet(&packet);
alGenBuffers(1, &bufferID);
alGenSources(1, &sourceID);
alListener3f(AL_POSITION, 0.0f, 0.0f, 0.0f);
int GotFrame = 0;
freq = aCodecCtx->sample_rate;
if (aCodecCtx->channels == 1)
format = AL_FORMAT_MONO16;
else
format = AL_FORMAT_STEREO16;
while (av_read_frame(pFormatCtx, &packet) >= 0)
{
if (packet.stream_index == audioStream)
{
avcodec_decode_audio4(aCodecCtx, aFrame, &GotFrame, &packet);
bufferData.insert(bufferData.end(), aFrame->data[0], aFrame->data[0] + aFrame->linesize[0]);
av_free_packet(&packet);
}
}
av_seek_frame(pFormatCtx, audioStream, 0, AVSEEK_FLAG_BACKWARD);
alBufferData(bufferID, format, &bufferData[0], static_cast<ALsizei>(bufferData.size()), freq);
alSourcei(sourceID, AL_BUFFER, bufferID);
在我的UpdateVideo()中,我通過視頻流將視頻解碼為OpenGL紋理,因此我可以在那里解碼我的音頻並對其進行流式處理:
void Video::UpdateVideo()
{
alGetSourcei(sourceID, AL_SOURCE_STATE, &state);
if (state != AL_PLAYING)
alSourcePlay(sourceID);
if (av_read_frame(pFormatCtx, &packet) >= 0)
{
if (packet.stream_index == videoStream)
{
avcodec_decode_video2(pCodecCtx, pFrame, &FrameFinished, &packet);
if (FrameFinished)
{
sws_scale(swsContext, pFrame->data, pFrame->linesize, 0, pCodecCtx->height, pFrameRGB->data, pFrameRGB->linesize);
av_free_packet(&packet);
}
}
else if (packet.stream_index == audioStream)
{
/*
avcodec_decode_audio4(aCodecCtx, aFrame, &FrameFinishd, &packet);
if (FrameFinished)
{
//Update Audio and rotate buffers here!
}
*/
}
glGenTextures(1, &VideoTexture);
glBindTexture(GL_TEXTURE_2D, VideoTexture);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexImage2D(GL_TEXTURE_2D, 0, 3, pCodecCtx->width, pCodecCtx->height, 0, GL_RGB, GL_UNSIGNED_BYTE, pFrameRGB->data[0]);
}
else
{
av_seek_frame(pFormatCtx, videoStream, 0, AVSEEK_FLAG_BACKWARD);
}
}
所以我想最重要的問題是我該怎么辦? 我一點也不清楚。 任何幫助表示贊賞,謝謝!
首先,您需要創建OpenAL流式聲源。 此外,您需要緩沖池來讀取流式數據並通過OpenAL排隊等待播放。
在open時,你需要從pull中填充一些緩沖區並將它們添加到源隊列(alSourceQueueBuffers)。 在更新過程中,您需要排隊已經播放的緩沖區
int processed = 0;
ALuint bufID = 0;
// ...
alGetSourcei(source_handle, AL_BUFFERS_PROCESSED, &processed);
while (processed--) {
alGetError();
alSourceUnqueueBuffers(source_handle, 1, &bufID);
// return buffId to buffers pool;
}
然后你需要從池中獲取空緩沖區並用緩沖區id調用你的bufferData代碼。
在bufferData中,您不需要創建源 - 將其作為參數傳遞。 您也不需要設置源參數。 只需將現有緩沖區排隊到現有源。 而不是alSourcei(sourceID,AL_BUFFER,bufferID)你需要使用alSourceQueueBuffers(sourceID,1,&bufferID)
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.