000
18.06.2005, 14:39 Uhr
sonetta
|
Hallo,
seit einiger Zeit versuche ich audiodaten aus einem avi oder mpeg-videostream herauszubekommen. Ich nutze DirectShow dafür. Abspielen usw funzt ganz gut, nur das Grabben von AudioSamples aus dem laufenden Video macht mich irre. Ich möchte diese für einen VU-meter nutzen. Zum Grabben nehme ich die Methode BufferCB( double dblSampleTime, BYTE * pBuffer, long lBufferSize ) der ISampleGrabber-Klasse. Und ich bekomme auch eine Ausgabe! Aber: ich bekomme auch Wert ausgegeben, wenn das Video definitiv keinen Ton hat, habs mit GraphEdit überprüft. ( Jetzt bin ich mir schon nicht mehr sicher, ob das, was ich da bekomme, wirklich Audiodaten sind (heul) Bei der Codemenge ist das wirklich schwer für dritte darzustellen.Versuchs trotzdem mal:
Hier die Klasse mit der Callback-Methode, hier geb ich die Samples auch testweise aus.
C++: |
class CFakeCallback : public ISampleGrabberCB { public: BYTE *m_Buffer; STDMETHODIMP_(ULONG) AddRef() { return 2; } STDMETHODIMP_(ULONG) Release() { return 1; }
STDMETHODIMP QueryInterface(REFIID riid, void ** ppv) { if (riid == IID_ISampleGrabberCB || riid == IID_IUnknown) { *ppv = (void *) static_cast<ISampleGrabberCB *>(this); return NOERROR; } return E_NOINTERFACE; }
STDMETHODIMP SampleCB( double SampleTime, IMediaSample * pSample ) { static long counter = 0;
return 0; } //Grabben, kopieren in glob. Struktur und Ausgabe STDMETHODIMP BufferCB( double dblSampleTime, BYTE * pBuffer, long lBufferSize ) { CString out = _T(""); CString complete = _T(""); if (!pBuffer) return E_POINTER; if( cbInfo.lBufferSize < lBufferSize ) { delete [] cbInfo.pBuffer; cbInfo.pBuffer = NULL; cbInfo.lBufferSize = 0; }
cbInfo.dblSampleTime = dblSampleTime; if (!cbInfo.pBuffer) { cbInfo.pBuffer = new BYTE[lBufferSize]; cbInfo.lBufferSize = lBufferSize; } memcpy(cbInfo.pBuffer, pBuffer, cbInfo.lBufferSize); //liefert immer 1492 oder 19812 Werte //Zahlen zwischen 0 und 255, sieht plausibel aus for(int n=0; n<cbInfo.lBufferSize; n++) { out.Format("%d",(short)cbInfo.pBuffer[n]); AfxMessageBox(out); } return 0; } };
CFakeCallback pCallbackA; //globales Object
|
Hier die globale Struktur um die Sample-Daten irgendwie in der App weiter zu verarbeiten:
C++: |
typedef struct _callbackinfo { double dblSampleTime; long lBufferSize; BYTE *pBuffer; } CALLBACKINFO;
CALLBACKINFO cbInfo={0};
|
Die Struktur der DirectShow-Interfaces:
C++: |
struct STREAM { IGraphBuilder *GB; //Rendern IMediaControl *MC; //Play/Stop IBasicAudio *BA; //Audiointerface IMediaSeeking *MS; //Position IVideoWindow *VW; //Video Window IMediaEventEx *ME; //MediaEvent IBaseFilter *pGrabberF; ISampleGrabber *pGrabber; };
|
Die Methode meiner MainFrame-Klasse die das Video lädt, initialisiert usw, wo der mittlere Teil wohl interessant ist:
C++: |
STREAM* CMainFrame::Load(CString name) // name = filename des videos { ms = new STREAM; //member-Streamobjekt HRESULT hres; WCHAR wFile[MAX_PATH]; RECT rc; int width; int height; MediaDlg = new CDSWindow(); BOOL ret = MediaDlg->Create(IDD_DIALOG5,this); //Dialogfenster für Video ModifyStyle(MediaDlg->GetSafeHwnd(), NULL, WS_THICKFRAME, NULL); MultiByteToWideChar(CP_ACP,0,name,-1,wFile,MAX_PATH);
//Init interfaces and graphs hres = CoCreateInstance(CLSID_SampleGrabber, NULL, CLSCTX_INPROC_SERVER, IID_IBaseFilter, (void**)&ms->pGrabberF); if (FAILED(hres)) AfxMessageBox("ERROR - Could not create the Sample Grabber.");
hres =ms->pGrabberF->QueryInterface(IID_ISampleGrabber, (void**)&ms->pGrabber); if (FAILED(hres)) AfxMessageBox("ERROR - Could not create ISampleGrabber interface.");
hres = CoCreateInstance(CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER, IID_IGraphBuilder, (void **)&ms->GB); if (FAILED(hres)) AfxMessageBox("ERROR - Could not create the Filter Graph Manager.");
hres = ms->GB->AddFilter(ms->pGrabberF, L"Sample Grabber"); if (FAILED(hres)) AfxMessageBox("ERROR - Could not add Sample Grabber filter to graph.");
hres = ms->GB->RenderFile(wFile,NULL); if (FAILED(hres)) AfxMessageBox("ERROR"); hres = ms->GB->QueryInterface(IID_IMediaControl,(void **)&ms->MC); if (FAILED(hres)) AfxMessageBox("ERROR"); hres = ms->GB->QueryInterface(IID_IMediaSeeking,(void **)&ms->MS); if (FAILED(hres)) AfxMessageBox("ERROR"); hres = ms->GB->QueryInterface(IID_IBasicAudio,(void **)&ms->BA); if (FAILED(hres)) AfxMessageBox("ERROR"); hres = ms->GB->QueryInterface(IID_IVideoWindow, (void **)&ms->VW); if (FAILED(hres)) AfxMessageBox("ERROR"); hres = ms->GB->QueryInterface(IID_IMediaEventEx, (void**)&ms->ME); if (FAILED(hres)) AfxMessageBox("ERROR"); hres = ms->pGrabber->SetOneShot(FALSE); if (FAILED(hres)) AfxMessageBox("ERROR - Could not set one shot for pSampleGrabber.");
hres = ms->pGrabber->SetBufferSamples(FALSE); if (FAILED(hres)) AfxMessageBox("ERROR - Could not set buffer samples for pSampleGrabber."); AM_MEDIA_TYPE smt; ZeroMemory(&smt, sizeof(AM_MEDIA_TYPE)); smt.majortype = MEDIATYPE_Audio; smt.formattype = FORMAT_WaveFormatEx; smt.subtype = MEDIASUBTYPE_PCM; hres = ms->pGrabber->SetMediaType(&smt);
CComQIPtr< ISampleGrabberCB, &IID_ISampleGrabberCB > pCBa( &pCallbackA ); hres = ms->pGrabber->SetCallback(pCBa, 1); if (FAILED(hres)) AfxMessageBox("ERROR - Could not set Callback");
//Fensterstyles und Notity ms->VW->put_AutoShow(OAFALSE); ms->VW->put_Owner((OAHWND)MediaDlg->GetSafeHwnd()); ms->VW->put_WindowStyle(WS_CHILD); hres=ms->ME->SetNotifyWindow((OAHWND)GetSafeHwnd(), WM_GRAPHNOTIFY, 0); if(hres!=S_OK) return NULL;
//Anfangsfenster einpassen MediaDlg->GetClientRect(&rc); width = rc.right - rc.left; height = rc.bottom - rc.top; ms->VW->SetWindowPosition(rc.left, rc.top+50, width, height); ms->VW->put_Visible(OATRUE); ms->VW->SetWindowForeground(OATRUE);
//Videodialog anzeigen MediaDlg->ShowWindow(SW_SHOW); MediaDlg->RedrawWindow(NULL, NULL, RDW_UPDATENOW); //init sliders pSlider2->SetRange( 0, (int)GetEndPos() ); //Seeking HWND hWnd = m_DlgBarAuswahl.GetSafeHwnd(); CWnd *pBar = CWnd::FromHandle(hWnd); CProgressCtrl *pProgress = (CProgressCtrl*)pBar->GetDlgItem(IDC_PROGRESS1); pProgress->SetRange32( 0, (int)GetEndPos() ); //Progressing pProgress1->SetRange( 0, 100 ); //Volume
return ms; }
|
Der Graph wird dann mit Run() in einer anderen Methode gestartet, das Event-Management von Directshow ist auch ausgelagert und funzt einwandfrei.
Sowie einige globale Hilfsmethoden wie GetUnconnectedPin, ConnectFilters, ConnectFilters MyFreeMediaType, die aber funzen sollten, sonst bekäme ich ja Fehler oder gar keine Ausgabe.
Mir ist klar, dass das nicht unbedingt trivial ist - aber darum bin ich ja hier. Wenn mir hier keiner helfen kann, geb ichs wohl auf ;(( In netz gibt es ne menge beispiele, um bitmaps aus video zu grabben - aber Audiodaten? leider sehr dürftig ! Hab mir deshalb die Videobeispiele für Audio angepasst, aber irgendwie ...
Bitte lasst Hirn regnen. Wäre Klasse wenn mir jemand auf die Sprünge helfen könnte.
Liebe Grüsse sonetta |