forked from mia/Aegisub
Mostly working DirectShow Video Provider
Originally committed to SVN as r664.
This commit is contained in:
parent
f0938ca9f9
commit
0fc5a75ac8
2 changed files with 219 additions and 16 deletions
|
@ -36,11 +36,10 @@
|
||||||
|
|
||||||
///////////
|
///////////
|
||||||
// Headers
|
// Headers
|
||||||
#include <wx/wxprec.h>
|
|
||||||
#include "setup.h"
|
#include "setup.h"
|
||||||
#ifdef __WINDOWS__
|
|
||||||
#if USE_DIRECTSHOW == 1
|
#if USE_DIRECTSHOW == 1
|
||||||
#pragma warning(disable: 4995)
|
#pragma warning(disable: 4995)
|
||||||
|
#include <wx/wxprec.h>
|
||||||
#include <wx/image.h>
|
#include <wx/image.h>
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
#include <tchar.h>
|
#include <tchar.h>
|
||||||
|
@ -65,6 +64,7 @@ DirectShowVideoProvider::DirectShowVideoProvider(wxString _filename, wxString _s
|
||||||
//////////////
|
//////////////
|
||||||
// Destructor
|
// Destructor
|
||||||
DirectShowVideoProvider::~DirectShowVideoProvider() {
|
DirectShowVideoProvider::~DirectShowVideoProvider() {
|
||||||
|
CloseVideo();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -204,9 +204,10 @@ HRESULT DirectShowVideoProvider::OpenVideo(wxString _filename) {
|
||||||
if (!sink2) return E_NOINTERFACE;
|
if (!sink2) return E_NOINTERFACE;
|
||||||
|
|
||||||
// Set allowed types for sink
|
// Set allowed types for sink
|
||||||
sink->SetAllowedTypes(IVS_RGB32|IVS_YV12|IVS_YUY2);
|
//sink->SetAllowedTypes(IVS_RGB32|IVS_YV12|IVS_YUY2);
|
||||||
|
sink->SetAllowedTypes(IVS_RGB32);
|
||||||
|
|
||||||
// I have no clue
|
// Pass the event to sink, so it gets set when a frame is available
|
||||||
ResetEvent(m_hFrameReady);
|
ResetEvent(m_hFrameReady);
|
||||||
sink2->NotifyFrame(m_hFrameReady);
|
sink2->NotifyFrame(m_hFrameReady);
|
||||||
|
|
||||||
|
@ -233,7 +234,7 @@ HRESULT DirectShowVideoProvider::OpenVideo(wxString _filename) {
|
||||||
// Connect pins
|
// Connect pins
|
||||||
if (FAILED(hr = pG->Connect(pO, pI))) return hr;
|
if (FAILED(hr = pG->Connect(pO, pI))) return hr;
|
||||||
|
|
||||||
// Add control stuff to graph
|
// Query the control interfaces from the graph
|
||||||
CComQIPtr<IMediaControl> mc(pG);
|
CComQIPtr<IMediaControl> mc(pG);
|
||||||
CComQIPtr<IMediaSeeking> ms(pG);
|
CComQIPtr<IMediaSeeking> ms(pG);
|
||||||
|
|
||||||
|
@ -251,7 +252,6 @@ HRESULT DirectShowVideoProvider::OpenVideo(wxString _filename) {
|
||||||
if (WaitForSingleObject(m_hFrameReady, 5000) != WAIT_OBJECT_0) return E_FAIL;
|
if (WaitForSingleObject(m_hFrameReady, 5000) != WAIT_OBJECT_0) return E_FAIL;
|
||||||
|
|
||||||
// Get frame format
|
// Get frame format
|
||||||
long long defd;
|
|
||||||
unsigned type, arx, ary;
|
unsigned type, arx, ary;
|
||||||
if (FAILED(hr = sink2->GetFrameFormat(&type, &width, &height, &arx, &ary, &defd))) return hr;
|
if (FAILED(hr = sink2->GetFrameFormat(&type, &width, &height, &arx, &ary, &defd))) return hr;
|
||||||
|
|
||||||
|
@ -260,7 +260,7 @@ HRESULT DirectShowVideoProvider::OpenVideo(wxString _filename) {
|
||||||
if (FAILED(hr = ms->GetDuration(&duration))) return hr;
|
if (FAILED(hr = ms->GetDuration(&duration))) return hr;
|
||||||
|
|
||||||
// Length of each frame? (??)
|
// Length of each frame? (??)
|
||||||
if (defd == 0) defd = 400000;
|
if (defd == 0) defd = 417083;
|
||||||
|
|
||||||
// No clue, either
|
// No clue, either
|
||||||
int avgf = 0;
|
int avgf = 0;
|
||||||
|
@ -275,8 +275,9 @@ HRESULT DirectShowVideoProvider::OpenVideo(wxString _filename) {
|
||||||
//}
|
//}
|
||||||
|
|
||||||
// Set number of frames and fps
|
// Set number of frames and fps
|
||||||
|
last_fnum = -1;
|
||||||
num_frames = duration / defd;
|
num_frames = duration / defd;
|
||||||
fps = double(10000000) / double(defd);
|
fps = 10000000.0 / double(defd);
|
||||||
|
|
||||||
// Set frame length
|
// Set frame length
|
||||||
//m_avgframe = defd;
|
//m_avgframe = defd;
|
||||||
|
@ -289,15 +290,203 @@ HRESULT DirectShowVideoProvider::OpenVideo(wxString _filename) {
|
||||||
// Flag frame as ready?
|
// Flag frame as ready?
|
||||||
SetEvent(m_hFrameReady);
|
SetEvent(m_hFrameReady);
|
||||||
|
|
||||||
// No idea
|
// Register graph with Running Objects Table for remote graphedit connection
|
||||||
RegROT();
|
RegROT();
|
||||||
|
|
||||||
|
//NextFrame();
|
||||||
|
|
||||||
// Set frame count
|
// Set frame count
|
||||||
//m_f.SetCount(m_vi.num_frames);
|
//m_f.SetCount(m_vi.num_frames);
|
||||||
return hr;
|
return hr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
///////////////
|
||||||
|
// Close video
|
||||||
|
void DirectShowVideoProvider::CloseVideo() {
|
||||||
|
CComQIPtr<IVideoSink2> pVS2(m_pR);
|
||||||
|
if (pVS2) pVS2->NotifyFrame(NULL);
|
||||||
|
|
||||||
|
UnregROT();
|
||||||
|
|
||||||
|
m_pR.Release();
|
||||||
|
m_pGC.Release();
|
||||||
|
m_pGS.Release();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/////////////////////////
|
||||||
|
// Read DirectShow frame
|
||||||
|
void DirectShowVideoProvider::ReadFrame(long long timestamp, unsigned format, unsigned bpp, const unsigned char *frame, unsigned width, unsigned height, unsigned stride, unsigned arx, unsigned ary, void *arg) {
|
||||||
|
// Set frame
|
||||||
|
DF *df = (DF*) arg;
|
||||||
|
df->timestamp = timestamp;
|
||||||
|
int w_cp = width;
|
||||||
|
int h_cp = height;
|
||||||
|
|
||||||
|
// Create data
|
||||||
|
unsigned char *data;
|
||||||
|
data = new unsigned char[width*height*bpp];
|
||||||
|
int dstride = width*bpp;
|
||||||
|
|
||||||
|
// Read RGB32 data
|
||||||
|
if (format == IVS_RGB32) {
|
||||||
|
unsigned char *dst = data + h_cp*dstride;
|
||||||
|
w_cp *= bpp;
|
||||||
|
for (int y = 0; y < h_cp; ++y) {
|
||||||
|
dst -= dstride;
|
||||||
|
memcpy(dst, frame, w_cp);
|
||||||
|
frame += stride;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create bitmap out of data
|
||||||
|
df->frame = wxBitmap((const char*) data, width, height, bpp*8);
|
||||||
|
delete data;
|
||||||
|
|
||||||
|
//else if (format == IVS_YV12 && vi->pixel_type == VideoInfo::CS_YV12) {
|
||||||
|
// // plane Y
|
||||||
|
// BYTE *dp = df->frame->GetWritePtr(PLANAR_Y);
|
||||||
|
// const unsigned char *sp = frame;
|
||||||
|
// int dstride = df->frame->GetPitch(PLANAR_Y);
|
||||||
|
|
||||||
|
// for (int y = 0; y < h_cp; ++y) {
|
||||||
|
// memcpy(dp, sp, w_cp);
|
||||||
|
// sp += stride;
|
||||||
|
// dp += dstride;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// // UV
|
||||||
|
// dstride >>= 1;
|
||||||
|
// stride >>= 1;
|
||||||
|
// w_cp >>= 1;
|
||||||
|
// h_cp >>= 1;
|
||||||
|
|
||||||
|
// // plane V
|
||||||
|
// dp = df->frame->GetWritePtr(PLANAR_V);
|
||||||
|
// sp = frame + height * stride * 2;
|
||||||
|
// dstride = df->frame->GetPitch(PLANAR_V);
|
||||||
|
|
||||||
|
// for (int y = 0; y < h_cp; ++y) {
|
||||||
|
// memcpy(dp, sp, w_cp);
|
||||||
|
// sp += stride;
|
||||||
|
// dp += dstride;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// // plane U
|
||||||
|
// dp = df->frame->GetWritePtr(PLANAR_U);
|
||||||
|
// sp = frame + height * stride * 2 + (height >> 1) * stride;
|
||||||
|
// dstride = df->frame->GetPitch(PLANAR_U);
|
||||||
|
|
||||||
|
// for (int y = 0; y < h_cp; ++y) {
|
||||||
|
// memcpy(dp, sp, w_cp);
|
||||||
|
// sp += stride;
|
||||||
|
// dp += dstride;
|
||||||
|
// }
|
||||||
|
//}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/////////////////////
|
||||||
|
// Get Next DS Frame
|
||||||
|
bool DirectShowVideoProvider::NextFrame(DF &_df,int &_fn) {
|
||||||
|
// Keep reading until it gets a good frame
|
||||||
|
while (true) {
|
||||||
|
if (WaitForSingleObject(m_hFrameReady, INFINITE) != WAIT_OBJECT_0) return false;
|
||||||
|
|
||||||
|
// Set object to receive data
|
||||||
|
DF df;
|
||||||
|
|
||||||
|
// Read frame
|
||||||
|
HRESULT hr = m_pR->ReadFrame(ReadFrame, &df);
|
||||||
|
if (FAILED(hr)) return false;
|
||||||
|
|
||||||
|
// End of file
|
||||||
|
if (hr == S_FALSE) return false;
|
||||||
|
|
||||||
|
// Valid timestamp
|
||||||
|
if (df.timestamp >= 0) {
|
||||||
|
// Frame number
|
||||||
|
int frameno = (int)((double)df.timestamp / defd + 0.5);
|
||||||
|
|
||||||
|
// Got a good one
|
||||||
|
if (frameno >= 0 && frameno < (signed) num_frames) {
|
||||||
|
_fn = frameno;
|
||||||
|
_df = df;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/////////////
|
||||||
|
// Get frame
|
||||||
|
wxBitmap DirectShowVideoProvider::GetFrame(int n) {
|
||||||
|
// Current
|
||||||
|
if (n == last_fnum) return rdf.frame;
|
||||||
|
|
||||||
|
// Variables
|
||||||
|
DF df;
|
||||||
|
int fn;
|
||||||
|
|
||||||
|
// Not the next, seek first
|
||||||
|
if (n != last_fnum + 1) {
|
||||||
|
// Reset and seek
|
||||||
|
ResetEvent(m_hFrameReady);
|
||||||
|
REFERENCE_TIME cur = defd * (n-1) - 10001; // -1ms, account for typical timestamps rounding
|
||||||
|
if (cur < 0) cur = 0;
|
||||||
|
|
||||||
|
// Failed
|
||||||
|
if (FAILED(m_pGS->SetPositions(&cur, AM_SEEKING_AbsolutePositioning, NULL, AM_SEEKING_NoPositioning))) return wxBitmap(width,height);
|
||||||
|
|
||||||
|
// Set time
|
||||||
|
rdf.timestamp = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Is next
|
||||||
|
else {
|
||||||
|
NextFrame(df,fn);
|
||||||
|
last_fnum = n;
|
||||||
|
rdf.frame = df.frame;
|
||||||
|
return rdf.frame;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Actually get data
|
||||||
|
while (true) {
|
||||||
|
// Get frame
|
||||||
|
DF df;
|
||||||
|
int fn;
|
||||||
|
NextFrame(df,fn);
|
||||||
|
|
||||||
|
// Preroll
|
||||||
|
if (fn < n) continue;
|
||||||
|
|
||||||
|
// Right frame
|
||||||
|
if (fn == n) {
|
||||||
|
// we want this frame, compare timestamps to account for decimation
|
||||||
|
// we see this for the first time
|
||||||
|
if (rdf.timestamp < 0) rdf.timestamp = df.timestamp;
|
||||||
|
|
||||||
|
// early, ignore
|
||||||
|
if (df.timestamp < rdf.timestamp) continue;
|
||||||
|
|
||||||
|
// this is the frame we want
|
||||||
|
rdf.frame = df.frame;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
else {
|
||||||
|
return wxBitmap(width,height);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return frame
|
||||||
|
last_fnum = n;
|
||||||
|
return rdf.frame;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
////////////////
|
////////////////
|
||||||
// Refresh subs
|
// Refresh subs
|
||||||
void DirectShowVideoProvider::RefreshSubtitles() {
|
void DirectShowVideoProvider::RefreshSubtitles() {
|
||||||
|
@ -323,4 +512,3 @@ void DirectShowVideoProvider::GetFloatFrame(float* Buffer, int n) {
|
||||||
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
#endif
|
|
||||||
|
|
|
@ -39,12 +39,11 @@
|
||||||
|
|
||||||
///////////
|
///////////
|
||||||
// Headers
|
// Headers
|
||||||
#include <wx/wxprec.h>
|
|
||||||
#ifdef __WINDOWS__
|
|
||||||
#include "setup.h"
|
#include "setup.h"
|
||||||
#if USE_DIRECTSHOW == 1
|
#if USE_DIRECTSHOW == 1
|
||||||
#include "video_provider.h"
|
#include "video_provider.h"
|
||||||
#pragma warning(disable: 4995)
|
#pragma warning(disable: 4995)
|
||||||
|
#include <wx/wxprec.h>
|
||||||
#include <dshow.h>
|
#include <dshow.h>
|
||||||
#include <atlbase.h>
|
#include <atlbase.h>
|
||||||
#include <atlcom.h>
|
#include <atlcom.h>
|
||||||
|
@ -56,6 +55,17 @@
|
||||||
///////////////////////////////////
|
///////////////////////////////////
|
||||||
// DirectShow Video Provider class
|
// DirectShow Video Provider class
|
||||||
class DirectShowVideoProvider: public VideoProvider {
|
class DirectShowVideoProvider: public VideoProvider {
|
||||||
|
struct DF {
|
||||||
|
public:
|
||||||
|
REFERENCE_TIME timestamp; // DS timestamp that we used for this frame
|
||||||
|
wxBitmap frame;
|
||||||
|
|
||||||
|
DF() : timestamp(-1) { }
|
||||||
|
DF(wxBitmap f) : timestamp(-1), frame(f) { }
|
||||||
|
DF(const DF& f) { operator=(f); }
|
||||||
|
DF& operator=(const DF& f) { timestamp = f.timestamp; frame = f.frame; return *this; }
|
||||||
|
};
|
||||||
|
|
||||||
private:
|
private:
|
||||||
wxString subfilename;
|
wxString subfilename;
|
||||||
|
|
||||||
|
@ -64,6 +74,7 @@ private:
|
||||||
unsigned int height;
|
unsigned int height;
|
||||||
unsigned int num_frames;
|
unsigned int num_frames;
|
||||||
double fps;
|
double fps;
|
||||||
|
long long defd;
|
||||||
|
|
||||||
int depth;
|
int depth;
|
||||||
double dar;
|
double dar;
|
||||||
|
@ -72,13 +83,18 @@ private:
|
||||||
unsigned char* data;
|
unsigned char* data;
|
||||||
wxBitmap last_frame;
|
wxBitmap last_frame;
|
||||||
|
|
||||||
wxBitmap GetFrame(int n, bool force);
|
void AttachOverlay(SubtitleProvider::Overlay *overlay) {}
|
||||||
void AttachOverlay(SubtitleProvider::Overlay *_overlay) {}
|
|
||||||
HRESULT OpenVideo(wxString _filename);
|
HRESULT OpenVideo(wxString _filename);
|
||||||
|
void CloseVideo();
|
||||||
|
|
||||||
|
static void ReadFrame(long long timestamp, unsigned format, unsigned bpp, const unsigned char *frame, unsigned width, unsigned height, unsigned stride, unsigned arx, unsigned ary, void *arg);
|
||||||
|
bool NextFrame(DF &df,int &fn);
|
||||||
|
|
||||||
void RegROT();
|
void RegROT();
|
||||||
void UnregROT();
|
void UnregROT();
|
||||||
|
|
||||||
|
DF rdf;
|
||||||
CComPtr<IVideoSink> m_pR;
|
CComPtr<IVideoSink> m_pR;
|
||||||
CComPtr<IMediaControl> m_pGC;
|
CComPtr<IMediaControl> m_pGC;
|
||||||
CComPtr<IMediaSeeking> m_pGS;
|
CComPtr<IMediaSeeking> m_pGS;
|
||||||
|
@ -94,7 +110,7 @@ public:
|
||||||
void SetDAR(double _dar);
|
void SetDAR(double _dar);
|
||||||
void SetZoom(double _zoom);
|
void SetZoom(double _zoom);
|
||||||
|
|
||||||
wxBitmap GetFrame(int n) { return wxBitmap(64,64); };
|
wxBitmap GetFrame(int n);
|
||||||
void GetFloatFrame(float* Buffer, int n);
|
void GetFloatFrame(float* Buffer, int n);
|
||||||
|
|
||||||
int GetPosition() { return last_fnum; };
|
int GetPosition() { return last_fnum; };
|
||||||
|
@ -110,4 +126,3 @@ public:
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
#endif
|
|
||||||
|
|
Loading…
Reference in a new issue