/*******************************************************************
           Killer Tomate - MPEG-2 VIDEO VFAPI Plug-In
 *******************************************************************/
#include <windows.h>
#include <string.h>
#include <stdio.h>

#include "vfapi.h"
#include "mpeg2video.h"

HRESULT _stdcall vfGetPluginInfo(LPVF_PluginInfo info);
HRESULT _stdcall vfGetPluginFunc(LPVF_PluginFunc func);

HRESULT _stdcall open_file(char *path, LPVF_FileHandle out);
HRESULT _stdcall close_file(VF_FileHandle p);
HRESULT _stdcall get_file_info(VF_FileHandle in, LPVF_FileInfo out);
HRESULT _stdcall get_stream_info(VF_FileHandle in, DWORD s, void *out);
HRESULT _stdcall read_data(VF_FileHandle in, DWORD s, void *out);

HRESULT _stdcall vfGetPluginInfo(LPVF_PluginInfo info)
{
	if(info == NULL){
		return VF_ERROR;
	}

	if(info->dwSize != sizeof(VF_PluginInfo)){
		return VF_ERROR;
	}

	info->dwAPIVersion = 1;
	info->dwVersion = 1;
	info->dwSupportStreamType = VF_STREAM_VIDEO;

	strcpy(info->cPluginInfo, "MPEG-2 VIDEO Plug-In");
	strcpy(info->cFileType, "MPEG-2 VIDEO Stream (*.m2v)|*.m2v");

	return VF_OK;
}

HRESULT _stdcall vfGetPluginFunc(LPVF_PluginFunc func)
{
	if(func == NULL){
		return VF_ERROR;
	}

	if(func->dwSize != sizeof(VF_PluginFunc)){
		return VF_ERROR;
	}

	func->OpenFile = open_file;
	func->CloseFile = close_file;
	func->GetFileInfo = get_file_info;
	func->GetStreamInfo = get_stream_info;
	func->ReadData = read_data;

	return VF_OK;
}

HRESULT _stdcall open_file(char *path, LPVF_FileHandle out)
{
	MPEG2VIDEO **w;

	w = (MPEG2VIDEO **)out;
	
	*w = (MPEG2VIDEO *)malloc(sizeof(MPEG2VIDEO));
	if(*w == NULL){
		return VF_ERROR;
	}

	if(! open_mpeg2video(path, *w)){
		free(*w);
		*w = NULL;
		return VF_ERROR;
	}

	return VF_OK;
}

HRESULT _stdcall close_file(VF_FileHandle p)
{
	MPEG2VIDEO *w;

	w = (MPEG2VIDEO *)p;

	close_mpeg2video(w);

	return VF_OK;
}

HRESULT _stdcall get_file_info(VF_FileHandle in, LPVF_FileInfo out)
{
	if(out == NULL){
		return VF_ERROR;
	}

	if(out->dwSize != sizeof(VF_FileInfo)){
		return VF_ERROR;
	}

	out->dwHasStreams = VF_STREAM_VIDEO;

	return VF_OK;
}

HRESULT _stdcall get_stream_info(VF_FileHandle in, DWORD s, void *out)
{
	MPEG2VIDEO *w;
	LPVF_StreamInfo_Video r;
	
	if(s != VF_STREAM_VIDEO){
		return VF_ERROR;
	}

	w = (MPEG2VIDEO *)in;
	r = (LPVF_StreamInfo_Video)out;

	if(r == NULL){
		return VF_ERROR;
	}
	
	if(r->dwSize != sizeof(VF_StreamInfo_Video)){
		return VF_ERROR;
	}

	r->dwLength = w->total;
	r->dwRate = w->rate;
	r->dwScale = w->scale;
	r->dwWidth = w->seq.h_size;
	r->dwHeight = w->seq.v_size;
	r->dwBitCount = 24;

	return VF_OK;
}
	
HRESULT _stdcall read_data(VF_FileHandle in, DWORD s, void *out)
{
	int i;
	size_t n;

	unsigned char *buf;
	unsigned char *dst;
	MPEG2VIDEO *w;
	LPVF_ReadData_Video r;

	if(s != VF_STREAM_VIDEO){
		return VF_ERROR;
	}

	w = (MPEG2VIDEO *)in;
	r = (LPVF_ReadData_Video)out;

	if(r == NULL){
		return VF_ERROR;
	}
	
	if(r->dwSize != sizeof(VF_ReadData_Video)){
		return VF_ERROR;
	}

	if(! read_frame(w, &buf, r->dwFrameNumber) ){
		return VF_ERROR;
	}

	n = w->seq.h_size * 3;

	dst = (unsigned char *)r->lpData;
	for(i=0;i<w->seq.v_size;i++){
		memcpy(dst + (i * r->lPitch), buf + (i * n), n);
	}

	return VF_OK;
}