ARDeskTop上で動画再生(その2)

OpenCVのcvCaptureFromFile関数では動画の音声トラックは再生されないので、試しにDirectShowでも同時に再生してみた。まあ、あたりまえだが、そのままでは音と映像がズレてしまう。
で、DirectShowのGetPositions関数で現在の再生位置を取得して、それに合わせて動画を再生してみた。
同期成功!

ちなみに、FLV Splitterをインストールするとfpsが30くらいまでのならflvファイルがDirectShowでも再生できるようになる。
http://www.gigafree.net/media/codec/flvsplitter.html

あとは、このままではDirectShowの別ウインドウでも動画が再生されてしまうので、音声のみを再生できるようにすれば終了。

int CCVVideoManager::Animate(void)
{
	if(!capture) return(1);
	if(!CAnimeManager::Animate()) return(1);

	int n;

	if(fps > 40.0f) {
		if(elapsedTimeMS * fps < counter) return(1);
		n = elapsedTimeMS * fps - counter + 1;
	} else {
		//DirectShowから現在の再生位置を取得して何フレーム進めるか決める
		LONGLONG pCurrent, pStop;
		pMediaSeeking->GetPositions(&pCurrent, &pStop);
		float current = pCurrent * 0.0000001;

		if(current * fps < counter) return(1);
		n = current * fps - counter + 1;
	}

	IplImage* image;

	for(int i = 0; i < n; i++) {
		image = cvQueryFrame(capture);
		if(!image) {
			Stop();
			return(0);
		}
	}

	counter += n;

	if(!frame) frame = cvCreateImage(cvSize(image->width / 3, image->height / 3), IPL_DEPTH_8U, 3);
	cvResize(image, frame, CV_INTER_CUBIC);
	((CCVPicture*) component)->SetTexture(image);

	return(0);
}


bool CCVVideoManager::OpenVideoFile(wchar_t* pFileName, double size)
{
	char cFileName[256];

	setlocale(LC_ALL, "ja");
	wcstombs(cFileName, pFileName, 256);

	//OpenCV
	capture = cvCaptureFromFile(cFileName);
	if(!capture) {
		return(false);
	}

	fps = (float) cvGetCaptureProperty(capture, CV_CAP_PROP_FPS);

	//DirectShow
	if(fps <= 40.0f) {
		IMediaPosition*		pMediaPosition;

		//DirectShowの初期化は本当はここでやったらダメだろうな。
		CoInitialize(NULL);
		CoCreateInstance(CLSID_FilterGraph, NULL, CLSCTX_INPROC, IID_IGraphBuilder, (LPVOID*) &pGraphBuilder);
		pGraphBuilder->QueryInterface(IID_IMediaControl, (LPVOID*) &pMediaControl);
		pGraphBuilder->QueryInterface(IID_IMediaPosition, (LPVOID*) &pMediaPosition);
		pGraphBuilder->QueryInterface(IID_IMediaSeeking, (LPVOID*) &pMediaSeeking);

		pGraphBuilder->RenderFile((BSTR) pFileName, NULL);

		//再生時間取得
		REFTIME length;
		pMediaPosition->get_Duration(&length);
		animetionTimeMS	= (float) length;
		pMediaPosition->Release();

		pMediaControl->Run();
	} else { //DirectShowでは再生不可能
		animetionTimeMS = 1000.0f; //適当
	}

	Play();
	Animate();


	return(true);
}

参考サイト:
Geekなぺーじ : DirectShowプログラミング [VC++]
http://www.geekpage.jp/programming/directshow/