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:
Rodrigo Braz Monteiro 2007-03-27 22:29:35 +00:00
parent d7a6ca1d76
commit c722ce9741
7 changed files with 47 additions and 40 deletions

View File

@ -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;

View File

@ -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);
};

View File

@ -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.");
}

View File

@ -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;
}
}

View File

@ -40,6 +40,7 @@
//////////////////////
// Video Frame format
enum VideoFrameFormat {
FORMAT_NONE,
FORMAT_RGB24,
FORMAT_RGB32,
FORMAT_YUY2,

View File

@ -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);
}

View File

@ -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);
}