2013-02-11 220 views
5

我在這裏問,我怎樣才能將AVFrame轉換爲opengl紋理。實際上,我創建了渲染器,輸出音頻(音頻正在工作)和視頻,但視頻不輸出。這裏是我的代碼:FFMPEG到OpenGL紋理

紋理製作:

glGenTextures(1,&_texture); 
glBindTexture(GL_TEXTURE_2D,_texture); 
glPixelStorei(GL_UNPACK_ALIGNMENT, 1); 

glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); 
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); 

代碼信息:_texture變量是保持紋理ID

該功能可以獲取AVFrame並將其轉換爲OpenGL的紋理GLuint :

int VideoGL::NextVideoFrame(){ 
// Get a packet from the queue 
AVPacket *videopacket = this->DEQUEUE(VIDEO); 
int frameFinished; 
if(videopacket!=0){ 
    avcodec_decode_video2(_codec_context_video, _std_frame,&frameFinished,videopacket); 

    if(frameFinished){ 

     sws_scale(sws_ctx, _std_frame->data, _std_frame->linesize, 0, _codec_context_video->height, _rgb_frame->data, _rgb_frame->linesize); 

     if(_firstrendering){ 
     glBindTexture(GL_TEXTURE_2D,_texture); 
     glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, _codec_context_video->width,_codec_context_video->height,0,GL_RGB,GL_UNSIGNED_BYTE,_rgb_frame->data[0]); 

     _firstrendering = false; 

     }else{ 

      glActiveTexture(_texture); 
      glBindTexture(GL_TEXTURE_2D,_texture); 
      glTexSubImage2D(GL_TEXTURE_2D,0,0,0,_codec_context_video->width,_codec_context_video->height,GL_RGB,GL_UNSIGNED_BYTE,_rgb_frame->data[0]); 

     } 
     av_free_packet(videopacket); 
     return 0; 
    }else{ 

     av_free_packet(videopacket); 
     return -1; 
    } 

}else{ 
    return -1; 
} 
return 0; 
} 

代碼信息:有一個隊列在一個線程存儲AVFrames的地方,這個函數經常被調用來獲取AVFrames,直到它獲得一個NULL,它就停止被調用。

這實際上不起作用。 (我試圖看看堆棧溢出中的一些問題,但它仍然不起作用) 任何示例或幫助我糾正錯誤的人?

其他數據:我試圖改變GL_RGB到GL_RGBA並開始與格式的播放,反正它崩潰當我嘗試GL_RGBA(因爲寬度和高度都是非常大的,反正我試圖調整它們的大小)。我曾嘗試將尺寸更改爲Power Of 2,但仍無法正常工作。

1編輯:

線程函數:

DWORD WINAPI VideoGL::VidThread(LPVOID myparam){ 

VideoGL * instance = (VideoGL*) myparam; 
instance->wave_audio->Start(); 

int quantity=0; 

AVPacket packet; 
while(av_read_frame(instance->_format_context,&packet) >= 0){ 
    if(packet.stream_index==instance->videoStream){ 
     instance->ENQUEUE(VIDEO,&packet); 
    } 
    if(packet.stream_index==instance->audioStream){ 
     instance->ENQUEUE(AUDIO,&packet); 
    } 
} 

instance->ENQUEUE(AUDIO,NULL); 
instance->ENQUEUE(VIDEO,NULL); 

return 0; 
} 

線程創建函數:

CreateThread(NULL, 0, VidThread, this, NULL, NULL); 

如果這是指包含NextVideoFrame類和_texture成員。

解決:

我跟着一些datenwolf提示,現在的視頻與音頻/視頻正確顯示:

Screenshot took

+0

'NextVideoFrame()'是否在您提到的輔助線程或主線程上運行? – genpfault 2013-02-11 21:42:05

+0

我將發佈CreateThread和線程,它更好地隱藏它看代碼 – Spamdark 2013-02-11 21:43:27

+0

輔助線程只將AVFrame存儲到隊列中,NextVideoFrame在另一個地方被調用,該功能用NextVideoFrame更新紋理,然後把它畫到屏幕上(opengl) – Spamdark 2013-02-11 21:46:43

回答

5

OpenGL的多線程是有點棘手。每個線程只有一個或沒有活動的OpenGL上下文給定的OpenGL上下文一次只能在一個線程中處於活動狀態。在線程之間遷移上下文是可能的,但不應該在線程之間播放熱門的OpenGL-context-potato。

有兩種可能的方式:

  • 使用存儲器映射的像素緩衝器中的對象(圖中一個線程,更新在其他)

  • 使用輔助OpenGL上下文,與共享其紋理其他。然後將一個上下文綁定到每個線程(您可以使用相同的drawable,即Windows上的HDC)。然後,您可以在一個線程中更新紋理,而另一個線程繪製紋理。紋理更新引入了線程之間的同步點,所以在繪製時不會意外寫入紋理。

+0

好主意!我最近在[stackoverflow question](http://stackoverflow.com/questions/6495523/ffmpeg-video-to-opengl-texture)上看過你的答案之一,它幫了我很多。這是一個截圖!現在工作正常! [截圖](http://oi45.tinypic.com/71ldh3.jpg) – Spamdark 2013-02-11 23:13:47

+0

介意與我們分享你的代碼,現在你已經修復了它? – 2014-04-24 07:56:14

+0

@MikeVersteeg:那是針對我還是Spamdark?如果以後你必須在用戶名前添加一個'@'來通知他/她。 – datenwolf 2014-04-24 09:43:48