#include "StdAfx.h"

#include <jni.h>
#include <jawt.h>
#include <win32\jawt_md.h>
#include <Wmsdk.h>
#include <dshow.h>
#include <D3d9.h>
#include <Vmr9.h>
#include <streams.h>
#include <Dvdmedia.h>
#include <Dmodshow.h>
#include "DirectShowVideoSystem.h"
#include "DSMediaCapture.h"


LPWSTR ToErrorMessage(HRESULT hRes)
{
	LPWSTR errMsg = NULL;
	FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, NULL, hRes, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),errMsg, 0, NULL);
	return errMsg;
}
JNIEXPORT jobject JNICALL Java_ips_media_jnm_impl_directshow_DSMediaCapture_init(JNIEnv *env, jobject obj){
	JavaVM *javaVm;
	env->GetJavaVM(&javaVm);
	// weak (can be garbage collected if object is gone) ref to Java object
	jweak objRef=env->NewWeakGlobalRef(obj);

	

	/*jclass cls=env->GetObjectClass(objRef);
	if(cls==NULL){
		printf("Could not find class\n");
		return NULL;
	}
	jmethodID mid = env->GetMethodID(cls, "render", "([B)V");
	if (mid == 0){
		printf("Could not find method ID\n");
		return NULL;
	}
	jweak renderMethodRef=env->NewWeakGlobalRef((jobject)mid);*/

	DSMediaCapture* mc=new DSMediaCapture(javaVm,objRef);
	//unsigned int nObjSize=sizeof(DSMediaCapture);
	unsigned int nObjSize=0;
	return env->NewDirectByteBuffer(mc,nObjSize);
}

/*
JNIEXPORT void JNICALL Java_ips_media_jnm_impl_directshow_DSMediaCapture_setAudioRenderer(JNIEnv *env, jobject obj,jobject nativeP,jobject jAudioRendererP){

	DSMediaCapture* mc=(DSMediacapture*)env->GetDirectBufferAddress(nativeP);
	JAudioRenderer* jap=(JAudioRenderer*)env->GetDirectBufferAddress(jAudioRendererP);
	mc->setAudioRenderer(jap);
}
*/
JNIEXPORT void JNICALL Java_ips_media_jnm_impl_directshow_DSMediaCapture_buildGraph(JNIEnv *env, jobject obj,jobject nativeP,jobject awtComponent){
	DSMediaCapture* mc=(DSMediaCapture*)env->GetDirectBufferAddress(nativeP);
	/*
	HRESULT hr;
	mc->getAWTSurface(env,awtComponent);
	HRESULT hr=mc->buildGraph();
	if(FAILED(hr)){
		mc->close();
		USES_CONVERSION;
		env->ThrowNew((jclass)exceptionClassRef,W2A(ToErrorMessage(hr)));
		return;
	}
	*/
}





JNIEXPORT void JNICALL Java_ips_media_jnm_impl_directshow_DSMediaCapture_open(JNIEnv *env, jobject obj,jobject nativeP,jstring mediaFilename){
	DSMediaCapture* mc=(DSMediaCapture*)env->GetDirectBufferAddress(nativeP);

	LPWSTR mediaFileNameWStr=NULL;

	if(mediaFilename!= NULL){
		mediaFileNameWStr=(LPWSTR)env->GetStringChars(mediaFilename,NULL);
		
		//printf("Media filename: %ls\n",mediaFileNameWStr);
		//fflush(stdout);
	}
	
	HRESULT hr=mc->open(mediaFileNameWStr);
	if(FAILED(hr)){
		mc->close();
		USES_CONVERSION;
		env->ThrowNew((jclass)exceptionClassRef,W2A(ToErrorMessage(hr)));
		return;
	}
	if(mediaFileNameWStr!=NULL){
		env->ReleaseStringChars(mediaFilename,(const jchar*)mediaFileNameWStr);
	}
}

JNIEXPORT jboolean JNICALL Java_ips_media_jnm_impl_directshow_DSMediaCapture_start(JNIEnv *env, jobject obj,jobject nativeP){
	DSMediaCapture* mdp=(DSMediaCapture*)env->GetDirectBufferAddress(nativeP);
	return mdp->start();
}
JNIEXPORT jboolean JNICALL Java_ips_media_jnm_impl_directshow_DSMediaCapture_stop(JNIEnv *env, jobject obj,jobject nativeP){
	DSMediaCapture* mdp=(DSMediaCapture*)env->GetDirectBufferAddress(nativeP);
	return mdp->stop();
}
JNIEXPORT void JNICALL Java_ips_media_jnm_impl_directshow_DSMediaCapture_close(JNIEnv *env, jobject obj,jobject nativeP){
	DSMediaCapture* mdp=(DSMediaCapture*)env->GetDirectBufferAddress(nativeP);
	return mdp->close();
}

JNIEXPORT void JNICALL Java_ips_media_jnm_impl_directshow_DSMediaCapture_release(JNIEnv *env, jobject obj,jobject nativeP){
	DSMediaCapture* mdp=(DSMediaCapture*)env->GetDirectBufferAddress(nativeP);
	mdp->release(env);
	mdp->~DSMediaCapture();
}




DSMediaCapture::DSMediaCapture(JavaVM* inJavaVm,jweak inJRef)
{
	javaVm=inJavaVm;
	objRef=inJRef;
	//renderMethodRef=renderMethodRefIn;
	pGraph=NULL;
	pControl = NULL;
	pEvent = NULL;
	hwndAWT=NULL;
	flushing=false;
	iBv=NULL;
	renderThreadID=0;
	renderEnv=NULL;
	//jvr=NULL;
	//jar=NULL;
	CoInitialize(0);
}
HRESULT DSMediaCapture::open(LPCWSTR lpwstrFile)
{

//	HRESULT hr;

	/*
	IEnumFilters *pEnum;
	pGraph->EnumFilters(&pEnum);
	IBaseFilter **filters=new IBaseFilter *[20];
	ULONG fetched;
	pEnum->Next(20,filters,&fetched);
	printf("Fetched filters: %d\n",fetched);
	for(unsigned int i=0;i<fetched;i++){
	CLSID clsId;
	filters[i]->GetClassID(&clsId);
	LPOLESTR className;
	StringFromCLSID(clsId,&className);
	FILTER_INFO pInfo;
	filters[i]->QueryFilterInfo(&pInfo);

	printf("Filter name: %ls class %ls\n",pInfo.achName,className);


	IEnumPins *pEnumPins;
	filters[i]->EnumPins(&pEnumPins);
	IPin       *pPin = NULL;
	//ULONG pinFetched;
	while(pEnumPins->Next(1,&pPin,0)==S_OK){
	PIN_DIRECTION PinDirThis;
	hr = pPin->QueryDirection(&PinDirThis);
	PIN_INFO pinInfo;
	pPin->QueryPinInfo(&pinInfo);
	printf("Pin: %ls\n",pinInfo.achName);
	}
	pEnumPins->Release();
	}
	pEnum->Release();
	*/
	

	return S_OK;
}

boolean DSMediaCapture::start()
{
	HRESULT hr=pControl->Run();

	// S_FALSE means it is  started but not yet running
	return (hr==S_OK || hr==S_FALSE);
	//return (hr==S_OK);
}

boolean DSMediaCapture::stop()
{
	HRESULT hr=pControl->Stop();
	return (hr==S_OK || hr==S_FALSE);
	//	return (hr==S_OK);
}
void DSMediaCapture::close()
{
	if(pControl!=NULL){
		pControl->Stop();
	}
	if(pGraph!=NULL){
		/*
		if(jvr!=NULL){
			pGraph->RemoveFilter(jvr);
		}
		
		if(jar!=NULL){
			pGraph->RemoveFilter(jar);
		}
		*/
		
		pGraph->Abort();
	}

	if(pWc!=NULL){
		pWc->Release();
	}
	/*
	if(iBv!=NULL){
	iBv->Release();
	}
	*/
	
	/*
	if(pEvent!=NULL){
	pEvent->Release();
	}
	*/

	if(pGraph!=NULL){
		pGraph->Release();
	}
	pGraph=NULL;
	pControl=NULL;
	
	if(pEvent!=NULL){
	
		pEvent->Release();
	}
	

}
void DSMediaCapture::release(JNIEnv *env)
{
	env->DeleteWeakGlobalRef(objRef);
}



DSMediaCapture::~DSMediaCapture(void)
{
}
