The Great Colorspace Reworking of '09, part 2 of ???: change all video providers to always output RGB32, and remove the formatMask parameter of GetFrame(). This may break the dshow video provider but I have no way of testing it and AFAIK nobody else does either. If someone actually uses it, they can fix it themselves. Updates #926.

Originally committed to SVN as r3185.
This commit is contained in:
Karl Blomster 2009-07-20 03:50:25 +00:00
parent e7f2dc00f7
commit d1762c5270
17 changed files with 52 additions and 185 deletions

View File

@ -52,7 +52,7 @@ public:
virtual ~VideoProvider() {}
// Override this method to actually get frames
virtual const AegiVideoFrame GetFrame(int n, int formatMask)=0;
virtual const AegiVideoFrame GetFrame(int n)=0;
// Override the following methods to get video information:
virtual int GetPosition()=0; // Get the number of the last frame loaded

View File

@ -140,7 +140,7 @@ void SubtitlesPreview::UpdateBitmap(int w,int h) {
// Get AegiVideoFrame
if (!vid) vid = new DummyVideoProvider(0.0,10,w,h,backColour,true);
AegiVideoFrame frame;
frame.CopyFrom(vid->GetFrame(0,FORMAT_RGB32));
frame.CopyFrom(vid->GetFrame(0));
// Try to get subtitles provider
SubtitlesProvider *provider = NULL;

View File

@ -85,7 +85,7 @@ void DVDSubtitleFormat::GetSubPictureList(std::vector<SubPicture> &pics) {
int w = 720;
int h = 480;
VideoProvider *video = new DummyVideoProvider(10,1,w,h,wxColour(255,0,0),false);
AegiVideoFrame srcFrame = video->GetFrame(0,FORMAT_RGB32);
AegiVideoFrame srcFrame = video->GetFrame(0);
delete video;
// Count and index lines

View File

@ -492,11 +492,8 @@ AegiVideoFrame VideoContext::GetFrame(int n,bool raw) {
// Current frame if -1
if (n == -1) n = frame_n;
// Get available formats
int formats = FORMAT_RGB32;
// Get frame
AegiVideoFrame frame = provider->GetFrame(n,formats);
AegiVideoFrame frame = provider->GetFrame(n);
// Raster subtitles if available/necessary
if (!raw && subsProvider) {
@ -532,18 +529,9 @@ GLuint VideoContext::GetFrameAsTexture(int n) {
if (glGetError() != 0) throw _T("Error enabling texture.");
// Image type
GLenum format = GL_LUMINANCE;
if (frame.format == FORMAT_RGB32) {
if (frame.invertChannels) format = GL_BGRA_EXT;
else format = GL_RGBA;
}
else if (frame.format == FORMAT_RGB24) {
if (frame.invertChannels) format = GL_BGR_EXT;
else format = GL_RGB;
}
else if (frame.format == FORMAT_YV12) {
format = GL_LUMINANCE;
}
GLenum format;
if (frame.invertChannels) format = GL_BGRA_EXT;
else format = GL_RGBA;
isInverted = frame.flipped;
if (lastTex == 0) {
@ -569,7 +557,6 @@ GLuint VideoContext::GetFrameAsTexture(int n) {
// Allocate texture
int height = frame.h;
if (frame.format == FORMAT_YV12) height = height * 3 / 2;
int tw = SmallestPowerOf2(MAX(frame.pitch[0]/frame.GetBpp(0),frame.pitch[1]+frame.pitch[2]));
int th = SmallestPowerOf2(height);
glTexImage2D(GL_TEXTURE_2D,0,GL_RGBA8,tw,th,0,format,GL_UNSIGNED_BYTE,NULL);
@ -599,20 +586,6 @@ GLuint VideoContext::GetFrameAsTexture(int n) {
glTexSubImage2D(GL_TEXTURE_2D,0,0,0,frame.pitch[0]/frame.GetBpp(0),frame.h,format,GL_UNSIGNED_BYTE,frame.data[0]);
if (glGetError() != 0) throw _T("Error uploading primary plane");
// UV planes for YV12
if (frame.format == FORMAT_YV12) {
int u = 1;
int v = 2;
if (frame.invertChannels) {
u = 2;
v = 1;
}
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.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.");
}
// Return texture number
return lastTex;
}

View File

@ -40,12 +40,16 @@
//////////////////////
// Video Frame format
// All formats use 8 bits per sample.
enum VideoFrameFormat {
FORMAT_NONE = 0,
FORMAT_RGB24 = 1,
FORMAT_RGB32 = 2,
FORMAT_YUY2 = 4,
FORMAT_YV12 = 8
FORMAT_NONE = 0x0000,
FORMAT_RGB24 = 0x0001, // RGB, interleaved
FORMAT_RGB32 = 0x0002, // RGBA, interleaved
FORMAT_YUY2 = 0x0004, // YCbCr 4:2:2, planar
FORMAT_YV12 = 0x0008, // YCbCr 4:2:0, planar
FORMAT_YUV444 = 0x0010, // YCbCr 4:4:4, planar
FORMAT_YUV444A = 0x0020, // YCbCr 4:4:4 plus alpha, planar
FORMAT_YUVMONO = 0x0040, // Y only (greyscale)
};
@ -58,13 +62,13 @@ private:
public:
unsigned char *data[4]; // Pointers to the data planes. Interleaved formats only use data[0]
VideoFrameFormat format; // Data format, one of FORMAT_RGB24, FORMAT_RGB32, FORMAT_YUY2 and FORMAT_YV12
VideoFrameFormat format; // Data format
unsigned int w; // Width in pixels
unsigned int h; // Height in pixels
unsigned int pitch[4]; // Pitch, that is, the number of bytes used by each row.
bool flipped; // First row is actually the bottom one
bool invertChannels; // Invert Red and Blue channels or U and V planes
bool invertChannels; // Swap Red and Blue channels or U and V planes (controls RGB versus BGR ordering etc)
bool cppAlloc; // Allocated with C++'s "new" operator, instead of "malloc"
AegiVideoFrame();

View File

@ -341,7 +341,7 @@ PClip AvisynthVideoProvider::OpenVideo(Aegisub::String _filename, bool mpeg2dec3
////////////////////////
// Actually get a frame
const AegiVideoFrame AvisynthVideoProvider::GetFrame(int _n,int formatMask) {
const AegiVideoFrame AvisynthVideoProvider::GetFrame(int _n) {
// Transform n if overriden
int n = _n;
if (frameTime.Count()) {
@ -365,25 +365,12 @@ const AegiVideoFrame AvisynthVideoProvider::GetFrame(int _n,int formatMask) {
final.invertChannels = false;
// Format
if (vi.IsRGB32()) {
final.format = FORMAT_RGB32;
final.flipped = true;
final.invertChannels = true;
}
else if (vi.IsRGB24()) {
final.format = FORMAT_RGB24;
final.flipped = true;
final.invertChannels = true;
}
else if (vi.IsYV12()) final.format = FORMAT_YV12;
else if (vi.IsYUY2()) final.format = FORMAT_YUY2;
final.format = FORMAT_RGB32;
final.flipped = true;
final.invertChannels = true;
// Set size properties
int uvpitch = 0;
if (final.format == FORMAT_YV12) uvpitch = frame->GetPitch(PLANAR_U);
final.pitch[0] = frame->GetPitch();
final.pitch[1] = uvpitch;
final.pitch[2] = uvpitch;
final.w = frame->GetRowSize() / Bpp;
final.h = frame->GetHeight();
@ -393,13 +380,6 @@ const AegiVideoFrame AvisynthVideoProvider::GetFrame(int _n,int formatMask) {
// Copy
memcpy(final.data[0],frame->GetReadPtr(),final.pitch[0] * final.h);
// Copy second and third planes for YV12
if (final.format == FORMAT_YV12) {
int uvh = frame->GetHeight(PLANAR_U);
memcpy(final.data[1],frame->GetReadPtr(PLANAR_U),uvpitch * uvh);
memcpy(final.data[2],frame->GetReadPtr(PLANAR_V),uvpitch * uvh);
}
// Set last number
last_fnum = n;
return final;

View File

@ -73,7 +73,7 @@ public:
AvisynthVideoProvider(Aegisub::String _filename);
~AvisynthVideoProvider();
const AegiVideoFrame GetFrame(int n,int formatMask);
const AegiVideoFrame GetFrame(int n);
void GetFloatFrame(float* Buffer, int n);
// properties

View File

@ -55,13 +55,12 @@ VideoProviderCache::VideoProviderCache(VideoProvider *parent) {
VideoProviderCache::~VideoProviderCache() {
delete master;
ClearCache();
tempRGBFrame.Clear();
}
/////////////
// Get frame
const AegiVideoFrame VideoProviderCache::GetFrame(int n,int format) {
const AegiVideoFrame VideoProviderCache::GetFrame(int n) {
// See if frame is cached
CachedFrame cached;
for (std::list<CachedFrame>::iterator cur=cache.begin();cur!=cache.end();cur++) {
@ -74,20 +73,9 @@ const AegiVideoFrame VideoProviderCache::GetFrame(int n,int format) {
}
// Not cached, retrieve it
const AegiVideoFrame frame = master->GetFrame(n, format);
const AegiVideoFrame frame = master->GetFrame(n);
const AegiVideoFrame *srcFrame = &frame;
// Convert to compatible format
if (!(frame.format & format)) {
if (format & FORMAT_RGB32) tempRGBFrame.format = FORMAT_RGB32;
else throw _T("Unable to negotiate video frame format.");
tempRGBFrame.w = frame.w;
tempRGBFrame.h = frame.h;
tempRGBFrame.pitch[0] = frame.w * 4;
tempRGBFrame.ConvertFrom(frame);
srcFrame = &tempRGBFrame;
}
// Cache frame
pos = n;
Cache(n,*srcFrame);
@ -98,7 +86,7 @@ const AegiVideoFrame VideoProviderCache::GetFrame(int n,int format) {
////////////////
// Get as float
void VideoProviderCache::GetFloatFrame(float* buffer, int n) {
const AegiVideoFrame frame = GetFrame(n,FORMAT_RGB32);
const AegiVideoFrame frame = GetFrame(n);
frame.GetFloat(buffer);
}

View File

@ -60,7 +60,6 @@ private:
VideoProvider *master;
unsigned int cacheMax;
std::list<CachedFrame> cache;
AegiVideoFrame tempRGBFrame;
int pos;
void Cache(int n,const AegiVideoFrame frame);
@ -74,7 +73,7 @@ protected:
public:
// Base methods
void GetFloatFrame(float* Buffer, int n); // Get frame as float
const AegiVideoFrame GetFrame(int n, int formatMask);
const AegiVideoFrame GetFrame(int n);
VideoProviderCache(VideoProvider *master);
virtual ~VideoProviderCache();

View File

@ -271,14 +271,6 @@ HRESULT DirectShowVideoProvider::OpenVideo(wxString _filename) {
// Get video duration
if (FAILED(hr = ms->GetDuration(&duration))) return hr;
// Set pixel type
//switch (type) {
// case IVS_RGB32: m_vi.pixel_type = VideoInfo::CS_BGR32; break;
// case IVS_YUY2: m_vi.pixel_type = VideoInfo::CS_YUY2; break;
// case IVS_YV12: m_vi.pixel_type = VideoInfo::CS_YV12; break;
// default: return E_FAIL;
//}
// Set FPS and frame duration
if (defd == 0) defd = 417083;
if (fps != 0.0) defd = int64_t (10000000.0 / fps) + 1;
@ -398,21 +390,11 @@ void DirectShowVideoProvider::ReadFrame(int64_t timestamp, unsigned format, unsi
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;
// 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;
df->frame.format = FORMAT_RGB32;
// Allocate and copy data
df->frame.Allocate();
@ -473,7 +455,7 @@ int DirectShowVideoProvider::NextFrame(DF &df,int &_fn) {
/////////////
// Get frame
const AegiVideoFrame DirectShowVideoProvider::GetFrame(int n,int formatMask) {
const AegiVideoFrame DirectShowVideoProvider::GetFrame(int n) {
// Normalize frame number
if (n >= (signed) num_frames) n = num_frames-1;
if (n < 0) n = 0;

View File

@ -110,7 +110,7 @@ public:
void RefreshSubtitles();
const AegiVideoFrame GetFrame(int n, int formatMask);
const AegiVideoFrame GetFrame(int n);
void GetFloatFrame(float* Buffer, int n);
int GetPosition() { return last_fnum; };

View File

@ -206,7 +206,7 @@ wxString DummyVideoProvider::MakeFilename(double fps, int frames, int _width, in
/////////////
// Get frame
const AegiVideoFrame DummyVideoProvider::GetFrame(int n,int formatMask) {
const AegiVideoFrame DummyVideoProvider::GetFrame(int n) {
lastFrame = n;
return frame;
}

View File

@ -64,7 +64,7 @@ public:
DummyVideoProvider(double fps, int frames, int _width, int _height, const wxColour &colour, bool pattern);
~DummyVideoProvider();
const AegiVideoFrame GetFrame(int n, int formatMask);
const AegiVideoFrame GetFrame(int n);
static wxString MakeFilename(double fps, int frames, int _width, int _height, const wxColour &colour, bool pattern);
int GetPosition();

View File

@ -70,8 +70,6 @@ FFmpegSourceVideoProvider::FFmpegSourceVideoProvider(Aegisub::String filename) {
// clean up variables
VideoSource = NULL;
DstFormat = FFMS_GetPixFmt("none");
LastDstFormat = FFMS_GetPixFmt("none");
KeyFramesLoaded = false;
FrameNumber = -1;
MsgSize = sizeof(FFMSErrMsg);
@ -217,6 +215,11 @@ void FFmpegSourceVideoProvider::LoadVideo(Aegisub::String filename) {
// load video properties
VideoInfo = FFMS_GetVideoProperties(VideoSource);
if (FFMS_SetOutputFormatV(VideoSource, 1 << FFMS_GetPixFmt("bgra"), VideoInfo->Width, VideoInfo->Height, FFMS_RESIZER_BICUBIC, FFMSErrMsg, MsgSize)) {
ErrorMsg.Append(wxString::Format(_T("Failed to set output format: %s"), FFMSErrMsg));
throw ErrorMsg;
}
// get frame info data
FFTrack *FrameData = FFMS_GetTrackFromVideo(VideoSource);
if (FrameData == NULL)
@ -268,8 +271,6 @@ void FFmpegSourceVideoProvider::Close() {
FFMS_DestroyVideoSource(VideoSource);
VideoSource = NULL;
DstFormat = FFMS_GetPixFmt("none");
LastDstFormat = FFMS_GetPixFmt("none");
KeyFramesLoaded = false;
KeyFramesList.clear();
TimecodesVector.clear();
@ -280,7 +281,7 @@ void FFmpegSourceVideoProvider::Close() {
///////////////
// Get frame
const AegiVideoFrame FFmpegSourceVideoProvider::GetFrame(int _n, int FormatType) {
const AegiVideoFrame FFmpegSourceVideoProvider::GetFrame(int _n) {
// don't try to seek to insane places
int n = _n;
if (n < 0)
@ -297,31 +298,6 @@ const AegiVideoFrame FFmpegSourceVideoProvider::GetFrame(int _n, int FormatType)
// this is what we'll return eventually
AegiVideoFrame &DstFrame = CurFrame;
// choose output format
if (FormatType & FORMAT_RGB32) {
DstFormat = FFMS_GetPixFmt("bgra");
DstFrame.format = FORMAT_RGB32;
} else if (FormatType & FORMAT_RGB24) {
DstFormat = FFMS_GetPixFmt("bgr24");
DstFrame.format = FORMAT_RGB24;
} else if (FormatType & FORMAT_YV12) {
DstFormat = FFMS_GetPixFmt("yuv420p");
DstFrame.format = FORMAT_YV12;
} else if (FormatType & FORMAT_YUY2) {
DstFormat = FFMS_GetPixFmt("yuyv422"); // may or may not work
DstFrame.format = FORMAT_YUY2;
} else
throw _T("FFmpegSource video provider: upstream provider requested unknown or unsupported pixel format");
// requested format was changed since last time we were called, (re)set output format
if (LastDstFormat != DstFormat) {
if (FFMS_SetOutputFormatV(VideoSource, 1 << DstFormat, w, h, FFMS_RESIZER_BICUBIC, FFMSErrMsg, MsgSize)) {
ErrorMsg.Append(wxString::Format(_T("Failed to set output format: %s"), FFMSErrMsg));
throw ErrorMsg;
}
LastDstFormat = DstFormat;
}
// decode frame
const FFAVFrame *SrcFrame = FFMS_GetFrame(VideoSource, n, FFMSErrMsg, MsgSize);
if (SrcFrame == NULL) {
@ -330,13 +306,11 @@ const AegiVideoFrame FFmpegSourceVideoProvider::GetFrame(int _n, int FormatType)
}
// set some properties
DstFrame.w = w;
DstFrame.h = h;
DstFrame.format = FORMAT_RGB32;
DstFrame.w = VideoInfo->Width;
DstFrame.h = VideoInfo->Height;
DstFrame.flipped = false;
if (DstFrame.format == FORMAT_RGB32 || DstFrame.format == FORMAT_RGB24)
DstFrame.invertChannels = true;
else
DstFrame.invertChannels = false;
DstFrame.invertChannels = true;
// allocate destination
for (int i = 0; i < 4; i++)
@ -345,13 +319,6 @@ const AegiVideoFrame FFmpegSourceVideoProvider::GetFrame(int _n, int FormatType)
// copy data to destination
memcpy(DstFrame.data[0], SrcFrame->Data[0], DstFrame.pitch[0] * DstFrame.h);
// if we're dealing with YUV formats we need to copy the U and V planes as well
if (DstFrame.format == FORMAT_YUY2 || DstFrame.format == FORMAT_YV12) {
// YV12 has half the vertical U/V resolution too because of the subsampling
int UVHeight = DstFrame.format == FORMAT_YUY2 ? DstFrame.h : DstFrame.h / 2;
memcpy(DstFrame.data[1], SrcFrame->Data[1], DstFrame.pitch[1] * UVHeight);
memcpy(DstFrame.data[2], SrcFrame->Data[2], DstFrame.pitch[2] * UVHeight);
}
return DstFrame;
}

View File

@ -56,8 +56,6 @@ private:
std::vector<int> TimecodesVector;
FrameRate Timecodes;
int DstFormat;
int LastDstFormat;
AegiVideoFrame CurFrame;
char FFMSErrMsg[1024];
@ -75,7 +73,7 @@ public:
FFmpegSourceVideoProvider(Aegisub::String filename);
~FFmpegSourceVideoProvider();
const AegiVideoFrame GetFrame(int n, int formatType);
const AegiVideoFrame GetFrame(int n);
int GetPosition();
int GetFrameCount();

View File

@ -346,7 +346,7 @@ int YUV4MPEGVideoProvider::IndexFile() {
}
const AegiVideoFrame YUV4MPEGVideoProvider::GetFrame(int n, int desired_fmts) {
const AegiVideoFrame YUV4MPEGVideoProvider::GetFrame(int n) {
// don't try to seek to insane places
if (n < 0)
n = 0;
@ -356,40 +356,20 @@ const AegiVideoFrame YUV4MPEGVideoProvider::GetFrame(int n, int desired_fmts) {
cur_fn = n;
VideoFrameFormat src_fmt, dst_fmt;
dst_fmt = FORMAT_RGB32;
int uv_width, uv_height;
switch (pixfmt) {
case Y4M_PIXFMT_420JPEG:
case Y4M_PIXFMT_420MPEG2:
case Y4M_PIXFMT_420PALDV:
src_fmt = FORMAT_YV12; break;
src_fmt = FORMAT_YV12; uv_width = w / 2; uv_height = h / 2; break;
case Y4M_PIXFMT_422:
src_fmt = FORMAT_YUY2; break;
src_fmt = FORMAT_YUY2; uv_width = w / 2; uv_height = h; break;
// TODO: add support for more pixel formats
default:
throw wxString(_T("YUV4MPEG video provider: GetFrame: Unsupported source colorspace"));
}
// TODO: fix this terrible piece of crap and implement colorspace conversions
// (write a function to select best output format)
if ((desired_fmts & FORMAT_YV12) && src_fmt == FORMAT_YV12)
dst_fmt = FORMAT_YV12;
else if ((desired_fmts & FORMAT_YUY2) && src_fmt == FORMAT_YUY2)
dst_fmt = FORMAT_YUY2;
else if ((desired_fmts & FORMAT_RGB32) && src_fmt == FORMAT_YV12)
dst_fmt = FORMAT_RGB32;
else
throw wxString(_T("YUV4MPEG video provider: GetFrame: Upstream video provider requested unknown or unsupported color format"));
int uv_width, uv_height;
// TODO: ugh, fix this
switch (src_fmt) {
case FORMAT_YV12:
uv_width = w / 2; uv_height = h / 2; break;
case FORMAT_YUY2:
uv_width = w / 2; uv_height = h; break;
default:
throw wxString(_T("YUV4MPEG video provider: GetFrame: sanity check failed"));
}
AegiVideoFrame tmp_frame;
tmp_frame.format = src_fmt;
@ -415,13 +395,9 @@ const AegiVideoFrame YUV4MPEGVideoProvider::GetFrame(int n, int desired_fmts) {
dst_frame.format = dst_fmt;
dst_frame.w = w;
dst_frame.h = h;
if (dst_fmt == FORMAT_RGB32) {
dst_frame.invertChannels = true;
dst_frame.pitch[0] = w * 4;
dst_frame.ConvertFrom(tmp_frame);
}
else
dst_frame.CopyFrom(tmp_frame);
dst_frame.invertChannels = true;
dst_frame.pitch[0] = w * 4;
dst_frame.ConvertFrom(tmp_frame);
tmp_frame.Clear();

View File

@ -121,7 +121,7 @@ public:
YUV4MPEGVideoProvider(Aegisub::String filename);
~YUV4MPEGVideoProvider();
const AegiVideoFrame GetFrame(int n, int formatType);
const AegiVideoFrame GetFrame(int n);
int GetPosition();
int GetFrameCount();