ffmpeg video provider now works as expected, except that it leaks memory. This fix should also help with certain videos being loaded with other providers. Also added some asserts and clean up to video frame class.
Originally committed to SVN as r954.
This commit is contained in:
parent
d7a6ca1d76
commit
c722ce9741
7 changed files with 47 additions and 40 deletions
|
@ -408,7 +408,7 @@ GLuint OpenGLWrapper::CreateYV12PixelShader() {
|
|||
|
||||
/////////////////////////////////////
|
||||
// Create YV12->RGB32 Shader Program
|
||||
GLuint OpenGLWrapper::CreateYV12Shader(float tw,float th) {
|
||||
GLuint OpenGLWrapper::CreateYV12Shader(float tw,float th,float tws) {
|
||||
// Create vertex shader
|
||||
GLuint ver = OpenGLWrapper::CreateStandardVertexShader();
|
||||
if (glGetError() != 0) throw _T("Error creating generic vertex shader");
|
||||
|
@ -431,7 +431,7 @@ GLuint OpenGLWrapper::CreateYV12Shader(float tw,float th) {
|
|||
address = glGetUniformLocationARB(program,"off1");
|
||||
glUniform2fARB(address, 0.0f, th);
|
||||
address = glGetUniformLocationARB(program,"off2");
|
||||
glUniform2fARB(address, tw*0.5f, th);
|
||||
glUniform2fARB(address, tws, th);
|
||||
|
||||
// Return shader
|
||||
return program;
|
||||
|
|
|
@ -66,5 +66,5 @@ public:
|
|||
static bool ShadersAvailable();
|
||||
static void SetShader(GLuint i);
|
||||
static void DestroyShaderProgram(GLuint i);
|
||||
static GLuint CreateYV12Shader(float tw,float th);
|
||||
static GLuint CreateYV12Shader(float tw,float th,float tws);
|
||||
};
|
||||
|
|
|
@ -452,7 +452,7 @@ GLuint VideoContext::GetFrameAsTexture(int n) {
|
|||
// Load image data into texture
|
||||
int height = frame.h;
|
||||
if (frame.format == FORMAT_YV12) height = height * 3 / 2;
|
||||
int tw = SmallestPowerOf2(frame.w);
|
||||
int tw = SmallestPowerOf2(MAX(frame.pitch[0],frame.pitch[1]+frame.pitch[2]));
|
||||
int th = SmallestPowerOf2(height);
|
||||
texW = float(frame.w)/float(tw);
|
||||
texH = float(frame.h)/float(th);
|
||||
|
@ -469,12 +469,12 @@ GLuint VideoContext::GetFrameAsTexture(int n) {
|
|||
|
||||
// Create shader if necessary
|
||||
if (frame.format == FORMAT_YV12 && yv12shader == 0) {
|
||||
yv12shader = OpenGLWrapper::CreateYV12Shader(texW,texH);
|
||||
yv12shader = OpenGLWrapper::CreateYV12Shader(texW,texH,float(frame.pitch[1])/float(tw));
|
||||
}
|
||||
}
|
||||
|
||||
// Load texture data
|
||||
glTexSubImage2D(GL_TEXTURE_2D,0,0,0,frame.w,frame.h,format,GL_UNSIGNED_BYTE,frame.data[0]);
|
||||
glTexSubImage2D(GL_TEXTURE_2D,0,0,0,frame.pitch[0],frame.h,format,GL_UNSIGNED_BYTE,frame.data[0]);
|
||||
if (glGetError() != 0) throw _T("Error uploading primary plane");
|
||||
|
||||
// UV planes for YV12
|
||||
|
@ -485,9 +485,9 @@ GLuint VideoContext::GetFrameAsTexture(int n) {
|
|||
u = 2;
|
||||
v = 1;
|
||||
}
|
||||
glTexSubImage2D(GL_TEXTURE_2D,0,0,frame.h,frame.w/2,frame.h/2,format,GL_UNSIGNED_BYTE,frame.data[u]);
|
||||
glTexSubImage2D(GL_TEXTURE_2D,0,0,frame.h,frame.pitch[1],frame.h/2,format,GL_UNSIGNED_BYTE,frame.data[u]);
|
||||
if (glGetError() != 0) throw _T("Error uploading U plane.");
|
||||
glTexSubImage2D(GL_TEXTURE_2D,0,frame.w/2,frame.h,frame.w/2,frame.h/2,format,GL_UNSIGNED_BYTE,frame.data[v]);
|
||||
glTexSubImage2D(GL_TEXTURE_2D,0,frame.pitch[1],frame.h,frame.pitch[2],frame.h/2,format,GL_UNSIGNED_BYTE,frame.data[v]);
|
||||
if (glGetError() != 0) throw _T("Error uploadinv V plane.");
|
||||
}
|
||||
|
||||
|
|
|
@ -49,7 +49,7 @@ void AegiVideoFrame::Reset() {
|
|||
memSize = 0;
|
||||
w = 0;
|
||||
h = 0;
|
||||
format = FORMAT_RGB24;
|
||||
format = FORMAT_NONE;
|
||||
flipped = false;
|
||||
cppAlloc = true;
|
||||
invertChannels = true;
|
||||
|
@ -85,10 +85,20 @@ AegiVideoFrame::AegiVideoFrame(int width,int height,VideoFrameFormat fmt) {
|
|||
////////////
|
||||
// Allocate
|
||||
void AegiVideoFrame::Allocate() {
|
||||
// Check consistency
|
||||
wxASSERT(pitch[0] > 0 && pitch[0] < 10000);
|
||||
wxASSERT(w > 0 && w < 10000);
|
||||
wxASSERT(h > 0 && h < 10000);
|
||||
wxASSERT(format != FORMAT_NONE);
|
||||
|
||||
// Get size
|
||||
int height = h;
|
||||
unsigned int size;
|
||||
if (format == FORMAT_YV12) size = pitch[0] * height * 3 / 2;
|
||||
if (format == FORMAT_YV12) {
|
||||
wxASSERT(pitch[1] > 0 && pitch[1] < 10000);
|
||||
wxASSERT(pitch[2] > 0 && pitch[2] < 10000);
|
||||
size = pitch[0]*height + (pitch[1]+pitch[2])*height/2;
|
||||
}
|
||||
else size = pitch[0] * height;
|
||||
|
||||
// Reallocate, if necessary
|
||||
|
@ -104,11 +114,12 @@ void AegiVideoFrame::Allocate() {
|
|||
// Planar
|
||||
if (format == FORMAT_YV12) {
|
||||
data[1] = data[0] + (pitch[0]*height);
|
||||
data[2] = data[0] + (pitch[0]*height*5/4);
|
||||
data[2] = data[0] + (pitch[0]*height+pitch[1]*height/2);
|
||||
}
|
||||
}
|
||||
|
||||
cppAlloc = true;
|
||||
// Flag as allocated by C++
|
||||
cppAlloc = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -40,6 +40,7 @@
|
|||
//////////////////////
|
||||
// Video Frame format
|
||||
enum VideoFrameFormat {
|
||||
FORMAT_NONE,
|
||||
FORMAT_RGB24,
|
||||
FORMAT_RGB32,
|
||||
FORMAT_YUY2,
|
||||
|
|
|
@ -419,34 +419,25 @@ void DirectShowVideoProvider::ReadFrame(long long timestamp, unsigned format, un
|
|||
df->frame.w = width;
|
||||
df->frame.h = height;
|
||||
df->frame.pitch[0] = stride;
|
||||
if (format == IVS_YV12) {
|
||||
df->frame.pitch[1] = stride/2;
|
||||
df->frame.pitch[2] = stride/2;
|
||||
}
|
||||
df->frame.cppAlloc = false;
|
||||
df->frame.invertChannels = true;
|
||||
|
||||
// Planar
|
||||
if (format == IVS_YUY2) {
|
||||
df->frame.format = FORMAT_YUY2;
|
||||
// Set format
|
||||
if (format == IVS_RGB24) df->frame.format = FORMAT_RGB24;
|
||||
else if (format == IVS_RGB32) df->frame.format = FORMAT_RGB32;
|
||||
else if (format == IVS_YV12) {
|
||||
df->frame.format = FORMAT_YV12;
|
||||
df->frame.invertChannels = true;
|
||||
}
|
||||
else if (format == IVS_YUY2) df->frame.format = FORMAT_YUY2;
|
||||
|
||||
// Interleaved
|
||||
else {
|
||||
// Set format
|
||||
if (format == IVS_RGB24) df->frame.format = FORMAT_RGB24;
|
||||
else if (format == IVS_RGB32) df->frame.format = FORMAT_RGB32;
|
||||
else if (format == IVS_YV12) df->frame.format = FORMAT_YV12;
|
||||
|
||||
// Allocate
|
||||
unsigned int datalen = stride*height;
|
||||
df->frame.Allocate();
|
||||
|
||||
// Prepare data for YV12
|
||||
if (format == IVS_YV12) {
|
||||
datalen = datalen * 3 / 2;
|
||||
df->frame.invertChannels = true;
|
||||
}
|
||||
|
||||
// Copy
|
||||
memcpy(df->frame.data[0],src,datalen);
|
||||
}
|
||||
// Allocate and copy data
|
||||
df->frame.Allocate();
|
||||
memcpy(df->frame.data[0],src,df->frame.pitch[0]*height + (df->frame.pitch[1]+df->frame.pitch[2])*height/2);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -85,6 +85,7 @@ LAVCVideoProvider::LAVCVideoProvider(wxString filename,double fps) {
|
|||
validFrame = false;
|
||||
|
||||
// Load
|
||||
SetCacheMax(8);
|
||||
LoadVideo(filename,fps);
|
||||
}
|
||||
|
||||
|
@ -389,21 +390,24 @@ const AegiVideoFrame LAVCVideoProvider::DoGetFrame(int n) {
|
|||
switch (format) {
|
||||
case PIX_FMT_BGR24: final.invertChannels = true;
|
||||
case PIX_FMT_RGB24: final.format = FORMAT_RGB24; break;
|
||||
#ifdef __WINDOWS__
|
||||
case PIX_FMT_BGR32: final.invertChannels = true;
|
||||
#endif
|
||||
case PIX_FMT_RGB32: final.format = FORMAT_RGB32; break;
|
||||
case PIX_FMT_YUYV422: final.format = FORMAT_YUY2; break;
|
||||
case PIX_FMT_YUV420P: final.format = FORMAT_YV12; break;
|
||||
default: throw _T("ffmpeg returned an unknown frame format.");
|
||||
}
|
||||
|
||||
// Allocate
|
||||
final.pitch[0] = final.w * final.GetBpp();
|
||||
for (int i=0;i<4;i++) final.pitch[i] = frame->linesize[i];
|
||||
final.Allocate();
|
||||
|
||||
// Copy data
|
||||
if (final.format == FORMAT_YV12) {
|
||||
memcpy(final.data[0],frame->data[0],final.w * final.h);
|
||||
memcpy(final.data[1],frame->data[1],final.w * final.h / 4);
|
||||
memcpy(final.data[2],frame->data[2],final.w * final.h / 4);
|
||||
memcpy(final.data[0],frame->data[0],frame->linesize[0] * final.h);
|
||||
memcpy(final.data[1],frame->data[1],frame->linesize[1] * final.h / 2);
|
||||
memcpy(final.data[2],frame->data[2],frame->linesize[2] * final.h / 2);
|
||||
}
|
||||
else memcpy(final.data[0],frame->data[0],size);
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue