mirror of
https://github.com/odrling/Aegisub
synced 2025-04-11 22:56:02 +02:00
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
@ -408,7 +408,7 @@ GLuint OpenGLWrapper::CreateYV12PixelShader() {
|
|||||||
|
|
||||||
/////////////////////////////////////
|
/////////////////////////////////////
|
||||||
// Create YV12->RGB32 Shader Program
|
// Create YV12->RGB32 Shader Program
|
||||||
GLuint OpenGLWrapper::CreateYV12Shader(float tw,float th) {
|
GLuint OpenGLWrapper::CreateYV12Shader(float tw,float th,float tws) {
|
||||||
// Create vertex shader
|
// Create vertex shader
|
||||||
GLuint ver = OpenGLWrapper::CreateStandardVertexShader();
|
GLuint ver = OpenGLWrapper::CreateStandardVertexShader();
|
||||||
if (glGetError() != 0) throw _T("Error creating generic vertex shader");
|
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");
|
address = glGetUniformLocationARB(program,"off1");
|
||||||
glUniform2fARB(address, 0.0f, th);
|
glUniform2fARB(address, 0.0f, th);
|
||||||
address = glGetUniformLocationARB(program,"off2");
|
address = glGetUniformLocationARB(program,"off2");
|
||||||
glUniform2fARB(address, tw*0.5f, th);
|
glUniform2fARB(address, tws, th);
|
||||||
|
|
||||||
// Return shader
|
// Return shader
|
||||||
return program;
|
return program;
|
||||||
|
@ -66,5 +66,5 @@ public:
|
|||||||
static bool ShadersAvailable();
|
static bool ShadersAvailable();
|
||||||
static void SetShader(GLuint i);
|
static void SetShader(GLuint i);
|
||||||
static void DestroyShaderProgram(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
|
// Load image data into texture
|
||||||
int height = frame.h;
|
int height = frame.h;
|
||||||
if (frame.format == FORMAT_YV12) height = height * 3 / 2;
|
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);
|
int th = SmallestPowerOf2(height);
|
||||||
texW = float(frame.w)/float(tw);
|
texW = float(frame.w)/float(tw);
|
||||||
texH = float(frame.h)/float(th);
|
texH = float(frame.h)/float(th);
|
||||||
@ -469,12 +469,12 @@ GLuint VideoContext::GetFrameAsTexture(int n) {
|
|||||||
|
|
||||||
// Create shader if necessary
|
// Create shader if necessary
|
||||||
if (frame.format == FORMAT_YV12 && yv12shader == 0) {
|
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
|
// 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");
|
if (glGetError() != 0) throw _T("Error uploading primary plane");
|
||||||
|
|
||||||
// UV planes for YV12
|
// UV planes for YV12
|
||||||
@ -485,9 +485,9 @@ GLuint VideoContext::GetFrameAsTexture(int n) {
|
|||||||
u = 2;
|
u = 2;
|
||||||
v = 1;
|
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.");
|
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.");
|
if (glGetError() != 0) throw _T("Error uploadinv V plane.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -49,7 +49,7 @@ void AegiVideoFrame::Reset() {
|
|||||||
memSize = 0;
|
memSize = 0;
|
||||||
w = 0;
|
w = 0;
|
||||||
h = 0;
|
h = 0;
|
||||||
format = FORMAT_RGB24;
|
format = FORMAT_NONE;
|
||||||
flipped = false;
|
flipped = false;
|
||||||
cppAlloc = true;
|
cppAlloc = true;
|
||||||
invertChannels = true;
|
invertChannels = true;
|
||||||
@ -85,10 +85,20 @@ AegiVideoFrame::AegiVideoFrame(int width,int height,VideoFrameFormat fmt) {
|
|||||||
////////////
|
////////////
|
||||||
// Allocate
|
// Allocate
|
||||||
void AegiVideoFrame::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
|
// Get size
|
||||||
int height = h;
|
int height = h;
|
||||||
unsigned int size;
|
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;
|
else size = pitch[0] * height;
|
||||||
|
|
||||||
// Reallocate, if necessary
|
// Reallocate, if necessary
|
||||||
@ -104,11 +114,12 @@ void AegiVideoFrame::Allocate() {
|
|||||||
// Planar
|
// Planar
|
||||||
if (format == FORMAT_YV12) {
|
if (format == FORMAT_YV12) {
|
||||||
data[1] = data[0] + (pitch[0]*height);
|
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
|
// Video Frame format
|
||||||
enum VideoFrameFormat {
|
enum VideoFrameFormat {
|
||||||
|
FORMAT_NONE,
|
||||||
FORMAT_RGB24,
|
FORMAT_RGB24,
|
||||||
FORMAT_RGB32,
|
FORMAT_RGB32,
|
||||||
FORMAT_YUY2,
|
FORMAT_YUY2,
|
||||||
|
@ -419,34 +419,25 @@ void DirectShowVideoProvider::ReadFrame(long long timestamp, unsigned format, un
|
|||||||
df->frame.w = width;
|
df->frame.w = width;
|
||||||
df->frame.h = height;
|
df->frame.h = height;
|
||||||
df->frame.pitch[0] = stride;
|
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.cppAlloc = false;
|
||||||
df->frame.invertChannels = true;
|
df->frame.invertChannels = true;
|
||||||
|
|
||||||
// Planar
|
// Set format
|
||||||
if (format == IVS_YUY2) {
|
if (format == IVS_RGB24) df->frame.format = FORMAT_RGB24;
|
||||||
df->frame.format = FORMAT_YUY2;
|
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
|
// Allocate and copy data
|
||||||
else {
|
df->frame.Allocate();
|
||||||
// Set format
|
memcpy(df->frame.data[0],src,df->frame.pitch[0]*height + (df->frame.pitch[1]+df->frame.pitch[2])*height/2);
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -85,6 +85,7 @@ LAVCVideoProvider::LAVCVideoProvider(wxString filename,double fps) {
|
|||||||
validFrame = false;
|
validFrame = false;
|
||||||
|
|
||||||
// Load
|
// Load
|
||||||
|
SetCacheMax(8);
|
||||||
LoadVideo(filename,fps);
|
LoadVideo(filename,fps);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -389,21 +390,24 @@ const AegiVideoFrame LAVCVideoProvider::DoGetFrame(int n) {
|
|||||||
switch (format) {
|
switch (format) {
|
||||||
case PIX_FMT_BGR24: final.invertChannels = true;
|
case PIX_FMT_BGR24: final.invertChannels = true;
|
||||||
case PIX_FMT_RGB24: final.format = FORMAT_RGB24; break;
|
case PIX_FMT_RGB24: final.format = FORMAT_RGB24; break;
|
||||||
|
#ifdef __WINDOWS__
|
||||||
case PIX_FMT_BGR32: final.invertChannels = true;
|
case PIX_FMT_BGR32: final.invertChannels = true;
|
||||||
|
#endif
|
||||||
case PIX_FMT_RGB32: final.format = FORMAT_RGB32; break;
|
case PIX_FMT_RGB32: final.format = FORMAT_RGB32; break;
|
||||||
case PIX_FMT_YUYV422: final.format = FORMAT_YUY2; break;
|
case PIX_FMT_YUYV422: final.format = FORMAT_YUY2; break;
|
||||||
case PIX_FMT_YUV420P: final.format = FORMAT_YV12; break;
|
case PIX_FMT_YUV420P: final.format = FORMAT_YV12; break;
|
||||||
|
default: throw _T("ffmpeg returned an unknown frame format.");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Allocate
|
// Allocate
|
||||||
final.pitch[0] = final.w * final.GetBpp();
|
for (int i=0;i<4;i++) final.pitch[i] = frame->linesize[i];
|
||||||
final.Allocate();
|
final.Allocate();
|
||||||
|
|
||||||
// Copy data
|
// Copy data
|
||||||
if (final.format == FORMAT_YV12) {
|
if (final.format == FORMAT_YV12) {
|
||||||
memcpy(final.data[0],frame->data[0],final.w * final.h);
|
memcpy(final.data[0],frame->data[0],frame->linesize[0] * final.h);
|
||||||
memcpy(final.data[1],frame->data[1],final.w * final.h / 4);
|
memcpy(final.data[1],frame->data[1],frame->linesize[1] * final.h / 2);
|
||||||
memcpy(final.data[2],frame->data[2],final.w * final.h / 4);
|
memcpy(final.data[2],frame->data[2],frame->linesize[2] * final.h / 2);
|
||||||
}
|
}
|
||||||
else memcpy(final.data[0],frame->data[0],size);
|
else memcpy(final.data[0],frame->data[0],size);
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user