我正在尝试使用FFMPEG创建一个可以使用OpenGl显示帧的播放器。 player
类有三个线程:一个用于渲染(运行runloop并处理每N ms触发的渲染事件。) - 它获取存储在pictureQueue中的GLKTextureInfo
并渲染。
一个用于从VideoStream读取数据包并将它们放入videoQueue中,第三个从videoQueue获取数据包并对其进行解码并创建GLKTextureInfo
并将其存储在pictureQueue中。
案例1:
player
类子类GLKView
并创建EAGLContext
将其设置为其上下文,并将其设置为呈现线程中的currentContext(它是第一个启动的线程)。
EAGLContext *mycontext = [self createBestEaglContext];
if (!self.mycontext || ![EAGLContext setCurrentContext:mycontext]) {
NSLog(@"Could not create Base EAGLContext");
return;
}
[self setContext:mycontext];
然后启动stream decoding thread
,如果找到视频流,则Video Packet Decoding Thread
会启动// set's the params for the GLKBaseEffect
// set's up VBO's
// run's runloop
。然后
Video Packet Decoding Thread
EAGLContext
还会创建EAGLSharegroup
,共享先前创建的上下文self.videoPacketDecodeThreadContext = [self createEaglContextForOtherThread];
if (!self.videoPacketDecodeThreadContext || ![EAGLContext setCurrentContext:self.videoPacketDecodeThreadContext])
{
NSLog(@"Could not create video packet decode thread context");
}
。
UIImage* image = [self ImageFromAVPicture:*(AVPicture*)pFrameRGB width:self.is.video_stream->codec->width height:self.is.video_stream->codec->height];
NSError *error = nil;
GLKTextureInfo *textureInfo = [GLKTextureLoader textureWithCGImage:image.CGImage
options:nil
error:&error];
if (error)
{
NSLog(@"Texture loading Error: %@\n", error.description);
//return -1;
}
else
{
[self.is.pictQueue_lock lock];
[self.is.pictQueue enqueue:textureInfo];
[self.is.pictQueue_lock unlock];
}
纹理部分
Failed to bind EAGLDrawable: <CAEAGLLayer: 0x156f7e50> to GL_RENDERBUFFER 1
我收到错误:Failed to make complete framebuffer object 8cd6
和glerror 1280
以及Player
。
案例2 GLKView
不是子类GLKView
,而是将其设置为故事板中创建的-(void)initPlayerWithView:(GLKView*)v
{
self.view = v;
}
的委托。
self.view
并将everyThing设置为上述(将mycontext
上下文设置为-(void)drawRect:(CGRect)rect
)一切正常。
-(void)glkView:(GLKView *)view drawInRect:(CGRect)rect
而且Rendering Thread
都在 {
[self.is.pictQueue_lock lock];
GLKTextureInfo *textureInfo = (GLKTextureInfo*)[self.is.pictQueue dequeue];
[self.is.pictQueue_lock unlock];
// delete the previous texture
GLuint index = self.baseEffect.texture2d0.name;
glDeleteTextures(1, &index);
self.baseEffect.texture2d0.name = textureInfo.name;
self.baseEffect.texture2d0.target = textureInfo.target;
[self.baseEffect prepareToDraw];
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
// Enable vertex buffer
glVertexAttribPointer(GLKVertexAttribPosition, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), 0);
glEnableVertexAttribArray(GLKVertexAttribPosition);
//Enable texture buffer
glVertexAttribPointer(GLKVertexAttribTexCoord0, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), (GLvoid*)offsetof(Vertex, textureCoords));
glEnableVertexAttribArray(GLKVertexAttribTexCoord0);
glDrawElements(GL_TRIANGLES, sizeof(Indices)/sizeof(Indices[0]), GL_UNSIGNED_BYTE, 0);
}
上被调用。渲染代码:
request.Method = "POST /sample.xml";
如何解决案例1中的错误?此外,如果他们是我可以以不同的方式做的其他事情,请建议如:
答案 0 :(得分:0)
我不是关于GLKView,我在OSX中编写了一个使用NSOpenGLView的播放器,子类化在那里工作得很好,但我让它为我创建了上下文。
我使用过很多线程吗?
默认情况下,对于大多数编解码器,ffmpeg使用frame multithreading,这意味着主解码线程不执行任何操作,它会创建子线程并等待它们完成解码帧。 (对于实时通信,你也可以使用切片多线程,这可以减少延迟,但缩放得不太好,并且需要比特流支持。)如果你没有做任何具体的事情来告诉它,ffmpeg使用帧多线程,你的帧解码线程什么也没做。所以你不需要它。播放器线程可以直接解码视频。
我正在将解码后的帧转换为 UIImage,然后从中创建纹理。它能做到吗? 不同吗?
UIImage是RGB格式,大多数视频解码器输出YUV,因此这表明其他一些代码正在进行软件YUV-RGB转换。这种RGB转换速度很慢,非常慢。
相反,请考虑openGL可以直接绘制YUV。所以我不会使用UIImage,而是使用着色器直接绘制YUV平面,在硬件内部进行YUV-RGB转换。