Mostly working DirectShow Video Provider

Originally committed to SVN as r664.
This commit is contained in:
Rodrigo Braz Monteiro 2006-12-31 05:01:01 +00:00
parent f0938ca9f9
commit 0fc5a75ac8
2 changed files with 219 additions and 16 deletions

View file

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

View file

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