From c722ce974146d82ad3bee27fa397eeeca5b58147 Mon Sep 17 00:00:00 2001 From: Rodrigo Braz Monteiro Date: Tue, 27 Mar 2007 22:29:35 +0000 Subject: [PATCH] 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. --- aegisub/gl_wrap.cpp | 4 ++-- aegisub/gl_wrap.h | 2 +- aegisub/video_context.cpp | 10 ++++----- aegisub/video_frame.cpp | 21 +++++++++++++----- aegisub/video_frame.h | 1 + aegisub/video_provider_dshow.cpp | 37 ++++++++++++-------------------- aegisub/video_provider_lavc.cpp | 12 +++++++---- 7 files changed, 47 insertions(+), 40 deletions(-) diff --git a/aegisub/gl_wrap.cpp b/aegisub/gl_wrap.cpp index 9369ebadb..d230acc25 100644 --- a/aegisub/gl_wrap.cpp +++ b/aegisub/gl_wrap.cpp @@ -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; diff --git a/aegisub/gl_wrap.h b/aegisub/gl_wrap.h index 8daa998de..121fc8b40 100644 --- a/aegisub/gl_wrap.h +++ b/aegisub/gl_wrap.h @@ -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); }; diff --git a/aegisub/video_context.cpp b/aegisub/video_context.cpp index a014cef0d..8dc224b6f 100644 --- a/aegisub/video_context.cpp +++ b/aegisub/video_context.cpp @@ -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."); } diff --git a/aegisub/video_frame.cpp b/aegisub/video_frame.cpp index 282558c57..95161511a 100644 --- a/aegisub/video_frame.cpp +++ b/aegisub/video_frame.cpp @@ -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; + } } diff --git a/aegisub/video_frame.h b/aegisub/video_frame.h index a33603b69..e0c3dea84 100644 --- a/aegisub/video_frame.h +++ b/aegisub/video_frame.h @@ -40,6 +40,7 @@ ////////////////////// // Video Frame format enum VideoFrameFormat { + FORMAT_NONE, FORMAT_RGB24, FORMAT_RGB32, FORMAT_YUY2, diff --git a/aegisub/video_provider_dshow.cpp b/aegisub/video_provider_dshow.cpp index 7b4107ae3..1fc7a7edc 100644 --- a/aegisub/video_provider_dshow.cpp +++ b/aegisub/video_provider_dshow.cpp @@ -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); } diff --git a/aegisub/video_provider_lavc.cpp b/aegisub/video_provider_lavc.cpp index eea6ffcc9..c9b42a611 100644 --- a/aegisub/video_provider_lavc.cpp +++ b/aegisub/video_provider_lavc.cpp @@ -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); }