Example #1
0
VDStringW VDGetLocalAppDataPath() {
	int csidl = CSIDL_APPDATA;

	HMODULE hmodShell32 = VDLoadSystemLibraryW32("shell32");

	if (hmodShell32) {
		typedef HRESULT (CALLBACK *tpDllGetVersion)(DLLVERSIONINFO *);

		DLLVERSIONINFO dvi = {sizeof(DLLVERSIONINFO)};

		tpDllGetVersion pDllGetVersion = (tpDllGetVersion)GetProcAddress(hmodShell32, "DllGetVersion");
		if (pDllGetVersion && NOERROR == pDllGetVersion(&dvi)) {
			if (dvi.dwMajorVersion >= 5)
				csidl = CSIDL_LOCAL_APPDATA;
		}

		FreeLibrary(hmodShell32);
	}

	if (VDIsWindowsNT()) {
		wchar_t pathW[MAX_PATH];

		if (!SHGetSpecialFolderPathW(NULL, pathW, csidl, FALSE))
			return VDGetProgramPath();

		return VDStringW(pathW);
	} else {
		char pathA[MAX_PATH];

		if (!SHGetSpecialFolderPathA(NULL, pathA, csidl, FALSE))
			return VDGetProgramPath();

		return VDTextAToW(pathA);
	}
}
Example #2
0
void JobAddConfiguration(const DubOptions *opt, const wchar_t *szFileInput, const wchar_t *pszInputDriver, const wchar_t *szFileOutput, bool fCompatibility, List2<InputFilenameNode> *pListAppended, long lSpillThreshold, long lSpillFrameThreshold, bool bIncludeEditList) {
	JobScriptOutput output;

	JobAddConfigurationInputs(output, szFileInput, pszInputDriver, pListAppended);
	JobCreateScript(output, opt, bIncludeEditList);
	JobAddReloadMarker(output);

	// Add actual run option
	if (lSpillThreshold)
		output.addf("VirtualDub.SaveSegmentedAVI(\"%s\", %d, %d);", strCify(VDTextWToU8(VDStringW(szFileOutput)).c_str()), lSpillThreshold, lSpillFrameThreshold);
	else
		output.addf("VirtualDub.Save%sAVI(\"%s\");", fCompatibility ? "Compatible" : "", strCify(VDTextWToU8(VDStringW(szFileOutput)).c_str()));

	JobAddClose(output);

	///////////////////

	vdautoptr<VDJob> vdj(new VDJob);
	vdj->SetInputFile(szFileInput);
	vdj->SetOutputFile(szFileOutput);

	const JobScriptOutput::Script& script = output.getscript();
	vdj->SetScript(script.data(), script.size(), true);
	g_VDJobQueue.Add(vdj.release(), false);
}
Example #3
0
void JobAddConfigurationImages(const DubOptions *opt, const wchar_t *szFileInput, const wchar_t *pszInputDriver, const wchar_t *szFilePrefix, const wchar_t *szFileSuffix, int minDigits, int imageFormat, int quality, List2<InputFilenameNode> *pListAppended) {
	JobScriptOutput output;

	JobAddConfigurationInputs(output, szFileInput, pszInputDriver, pListAppended);
	JobCreateScript(output, opt);
	JobAddReloadMarker(output);

	// Add actual run option
	VDStringA s(strCify(VDTextWToU8(VDStringW(szFilePrefix)).c_str()));

	output.addf("VirtualDub.SaveImageSequence(\"%s\", \"%s\", %d, %d, %d);", s.c_str(), strCify(VDTextWToU8(VDStringW(szFileSuffix)).c_str()), minDigits, imageFormat, quality);

	JobAddClose(output);

	///////////////////

	vdautoptr<VDJob> vdj(new VDJob);
	vdj->SetInputFile(szFileInput);
	VDStringW outputFile;
	outputFile.sprintf(L"%ls*%ls", szFilePrefix, szFileSuffix);
	vdj->SetOutputFile(outputFile.c_str());

	const JobScriptOutput::Script& script = output.getscript();
	vdj->SetScript(script.data(), script.size(), true);
	g_VDJobQueue.Add(vdj.release(), false);
}
Example #4
0
void VDRegistryProviderMemory::Value::SetBinary(const void *p, size_t len) {
	if (mType != kTypeBinary) {
		mString.swap(VDStringW());
		mType = kTypeBinary;
	}

	mRawData.assign((char *)p, (char *)p + len);
}
Example #5
0
VDStringW VDGetSystemPathNT() {
    wchar_t path[MAX_PATH];

    if (!GetSystemDirectoryW(path, MAX_PATH))
        throw MyWin32Error("Cannot locate system directory: %%s", GetLastError());

    return VDStringW(path);
}
Example #6
0
void VDRegistryProviderMemory::Value::SetInt(sint32 v) {
	if (mType != kTypeInt) {
		mString.swap(VDStringW());
		mRawData.swap(vdfastvector<char>());
		mType = kTypeInt;
	}

	mInt = v;
}
Example #7
0
VDStringW VDFileGetRelativePath(const wchar_t *basePath, const wchar_t *pathToConvert, bool allowAscent) {
    VDParsedPath base(basePath);
    VDParsedPath path(pathToConvert);

    // Fail if either path is relative.
    if (base.IsRelative() || path.IsRelative())
        return VDStringW();

    // Fail if the roots don't match.
    if (vdwcsicmp(base.GetRoot(), path.GetRoot()))
        return VDStringW();

    // Figure out how many components are in common.
    size_t n1 = base.GetComponentCount();
    size_t n2 = path.GetComponentCount();
    size_t nc = 0;

    while(nc < n1 && nc < n2 && !vdwcsicmp(base.GetComponent(nc), path.GetComponent(nc)))
        ++nc;

    // Check how many extra components are in the base; these need to become .. identifiers.
    VDParsedPath relPath;

    if (n1 > nc) {
        if (!allowAscent)
            return VDStringW();

        while(n1 > nc) {
            relPath.AddComponent(L"..");
            --n1;
        }
    }

    // Append extra components from path.
    while(nc < n2) {
        relPath.AddComponent(path.GetComponent(nc++));
    }

    // Copy stream.
    relPath.SetStream(path.GetStream());

    return relPath.ToString();
}
Example #8
0
VDStringW VDGetFullPath(const wchar_t *partialPath) {
    static tpGetFullPathNameW spGetFullPathNameW = (tpGetFullPathNameW)GetProcAddress(GetModuleHandle("kernel32.dll"), "GetFullPathNameW");

    union {
        char		a[MAX_PATH];
        wchar_t		w[MAX_PATH];
    } tmpBuf;

    if (spGetFullPathNameW && !(GetVersion() & 0x80000000)) {
        LPWSTR p;

        tmpBuf.w[0] = 0;
        DWORD count = spGetFullPathNameW(partialPath, MAX_PATH, tmpBuf.w, &p);

        if (count < MAX_PATH)
            return VDStringW(tmpBuf.w);

        VDStringW tmp(count);

        DWORD newCount = spGetFullPathNameW(partialPath, count, (wchar_t *)tmp.data(), &p);
        if (newCount < count)
            return tmp;

        return VDStringW(partialPath);
    } else {
        LPSTR p;
        VDStringA pathA(VDTextWToA(partialPath));

        tmpBuf.a[0] = 0;
        DWORD count = GetFullPathNameA(pathA.c_str(), MAX_PATH, tmpBuf.a, &p);

        if (count < MAX_PATH)
            return VDStringW(VDTextAToW(tmpBuf.a));

        VDStringA tmpA(count);

        DWORD newCount = GetFullPathNameA(pathA.c_str(), count, (char *)tmpA.data(), &p);
        if (newCount < count)
            return VDTextAToW(tmpA);

        return VDStringW(partialPath);
    }
}
Example #9
0
void VDShowHelp(HWND hwnd, const wchar_t *filename) {
	try {
		VDStringW helpFile(VDGetHelpPath());

		if (!VDDoesPathExist(helpFile.c_str()))
			throw MyError("Cannot find help file: %ls", helpFile.c_str());

		// If we're on Windows NT, check for the ADS and/or network drive.
		if (VDIsWindowsNT()) {
			VDStringW helpFileADS(helpFile);
			helpFileADS += L":Zone.Identifier";
			if (VDDoesPathExist(helpFileADS.c_str())) {
				int rv = MessageBox(hwnd, "VirtualDub has detected that its help file, VirtualDub.chm, has an Internet Explorer download location marker on it. This may prevent the help file from being displayed properly, resulting in \"Action canceled\" errors being displayed. Would you like to remove it?", "VirtualDub warning", MB_YESNO|MB_ICONEXCLAMATION);

				if (rv == IDYES)
					DeleteFileW(helpFileADS.c_str());
			}
		}

		if (filename) {
			helpFile.append(L"::/");
			helpFile.append(filename);
		}

		VDStringW helpCommand(VDStringW(L"\"hh.exe\" \"") + helpFile + L'"');

		PROCESS_INFORMATION pi;
		BOOL retval;

		// CreateProcess will actually modify the string that it gets, soo....
		if (VDIsWindowsNT()) {
			STARTUPINFOW si = {sizeof(STARTUPINFOW)};
			std::vector<wchar_t> tempbufW(helpCommand.size() + 1, 0);
			helpCommand.copy(&tempbufW[0], tempbufW.size());
			retval = CreateProcessW(NULL, &tempbufW[0], NULL, NULL, FALSE, CREATE_DEFAULT_ERROR_MODE, NULL, NULL, &si, &pi);
		} else {
			STARTUPINFOA si = {sizeof(STARTUPINFOA)};
			VDStringA strA(VDTextWToA(helpCommand));
			std::vector<char> tempbufA(strA.size() + 1, 0);
			strA.copy(&tempbufA[0], tempbufA.size());
			retval = CreateProcessA(NULL, &tempbufA[0], NULL, NULL, FALSE, CREATE_DEFAULT_ERROR_MODE, NULL, NULL, &si, &pi);
		}

		if (retval) {
			CloseHandle(pi.hThread);
			CloseHandle(pi.hProcess);
		} else
			throw MyWin32Error("Cannot launch HTML Help: %%s", GetLastError());
	} catch(const MyError& e) {
		e.post(hwnd, g_szError);
	}
}
Example #10
0
void JobAddConfigurationInputs(JobScriptOutput& output, const wchar_t *szFileInput, const wchar_t *pszInputDriver, List2<InputFilenameNode> *pListAppended) {
	do {
		const VDStringA filename(strCify(VDTextWToU8(VDStringW(szFileInput)).c_str()));

		if (g_pInputOpts) {
			int req = g_pInputOpts->write(NULL, 0);

			vdfastvector<char> srcbuf(req);

			int srcsize = g_pInputOpts->write(srcbuf.data(), req);

			if (srcsize) {
				vdfastvector<char> encbuf((srcsize + 2) / 3 * 4 + 1);
				membase64(encbuf.data(), srcbuf.data(), srcsize);

				const VDStringA filename(strCify(VDTextWToU8(VDStringW(szFileInput)).c_str()));

				output.addf("VirtualDub.Open(\"%s\",\"%s\",0,\"%s\");", filename.c_str(), pszInputDriver?strCify(VDTextWToU8(VDStringW(pszInputDriver)).c_str()):"", encbuf.data());
				break;
			}
		}

		output.addf("VirtualDub.Open(\"%s\",\"%s\",0);", filename.c_str(), pszInputDriver?strCify(VDTextWToU8(VDStringW(pszInputDriver)).c_str()):"");

	} while(false);

	if (pListAppended) {
		InputFilenameNode *ifn = pListAppended->AtHead(), *ifn_next;

		if (ifn = ifn->NextFromHead())
			while(ifn_next = ifn->NextFromHead()) {
				output.addf("VirtualDub.Append(\"%s\");", strCify(VDTextWToU8(VDStringW(ifn->name)).c_str()));
				ifn = ifn_next;
			}
	}
}
Example #11
0
VDStringW VDMakePath(const wchar_t *base, const wchar_t *file) {
    if (!*base)
        return VDStringW(file);

    VDStringW result(base);

    const wchar_t c = result[result.size() - 1];

    if (c != L'/' && c != L'\\' && c != L':')
        result += L'\\';

    result.append(file);

    return result;
}
Example #12
0
VDStringW VDFileGetRootPath(const wchar_t *path) {
    static tpGetVolumePathNameW spGetVolumePathNameW = (tpGetVolumePathNameW)GetProcAddress(GetModuleHandle("kernel32.dll"), "GetVolumePathNameW");
    static tpGetFullPathNameW spGetFullPathNameW = (tpGetFullPathNameW)GetProcAddress(GetModuleHandle("kernel32.dll"), "GetFullPathNameW");

    VDStringW fullPath(VDGetFullPath(path));

    // Windows 2000/XP path
    if (spGetVolumePathNameW) {
        vdblock<wchar_t> buf(std::max<size_t>(fullPath.size() + 1, MAX_PATH));

        if (spGetVolumePathNameW(path, buf.data(), buf.size()))
            return VDStringW(buf.data());
    }

    // Windows 95/98/ME/NT4 path
    const wchar_t *s = fullPath.c_str();
    VDStringW root(s, VDFileSplitRoot(s) - s);
    VDFileFixDirPath(root);
    return root;
}
Example #13
0
VDStringW VDGetWindowTextW32(HWND hwnd) {
	union {
		wchar_t w[256];
		char a[512];
	} buf;

	if (VDIsWindowsNT()) {
		int len = GetWindowTextLengthW(hwnd);

		if (len > 255) {
			vdblock<wchar_t> tmp(len + 1);
			len = GetWindowTextW(hwnd, tmp.data(), tmp.size());

			VDStringW text(tmp.data(), len);
			return text;
		} else if (len > 0) {
			len = GetWindowTextW(hwnd, buf.w, 256);

			VDStringW text(buf.w, len);
			return text;
		}
	} else {
		int len = GetWindowTextLengthA(hwnd);

		if (len > 511) {
			vdblock<char> tmp(len + 1);
			len = GetWindowTextA(hwnd, tmp.data(), tmp.size());

			VDStringW text(VDTextAToW(tmp.data(), len));
			return text;
		} else if (len > 0) {
			len = GetWindowTextA(hwnd, buf.a, 512);

			VDStringW text(VDTextAToW(buf.a, len));
			return text;
		}
	}

	return VDStringW();
}
Example #14
0
void VDRemoveDirectory(const wchar_t *path) {
    VDStringW::size_type l(wcslen(path));

    if (l) {
        const wchar_t c = path[l-1];

        if (c == L'/' || c == L'\\') {
            VDCreateDirectory(VDStringW(path, l-1).c_str());
            return;
        }
    }

    BOOL succeeded;

    if (!(GetVersion() & 0x80000000)) {
        succeeded = RemoveDirectoryW(path);
    } else {
        succeeded = RemoveDirectoryA(VDTextWToA(path).c_str());
    }

    if (!succeeded)
        throw MyWin32Error("Cannot remove directory: %%s", GetLastError());
}
Example #15
0
void JobAddConfigurationSaveAudio(const DubOptions *opt, const wchar_t *srcFile, const wchar_t *srcInputDriver, List2<InputFilenameNode> *pListAppended, const wchar_t *dstFile, bool raw, bool includeEditList) {
	JobScriptOutput output;

	JobAddConfigurationInputs(output, srcFile, srcInputDriver, pListAppended);
	JobCreateScript(output, opt, includeEditList);
	JobAddReloadMarker(output);

	// Add actual run option
	output.addf("VirtualDub.Save%s(\"%s\");", raw ? "RawAudio" : "WAV", strCify(VDTextWToU8(VDStringW(dstFile)).c_str()));

	JobAddClose(output);

	///////////////////

	vdautoptr<VDJob> vdj(new VDJob);
	vdj->SetInputFile(srcFile);
	vdj->SetOutputFile(dstFile);

	const JobScriptOutput::Script& script = output.getscript();
	vdj->SetScript(script.data(), script.size(), true);
	g_VDJobQueue.Add(vdj.release(), false);
}
Example #16
0
VDStringW VDFileResolvePath(const wchar_t *basePath, const wchar_t *pathToResolve) {
    if (VDFileIsRelativePath(pathToResolve))
        return VDFileGetCanonicalPath(VDMakePath(basePath, pathToResolve).c_str());

    return VDStringW(pathToResolve);
}
Example #17
0
void JobCreateScript(JobScriptOutput& output, const DubOptions *opt, bool bIncludeEditList = true, bool bIncludeTextInfo = true) {
	char *mem= NULL;
	char buf[4096];
	long l;

	int audioSourceMode = g_project->GetAudioSourceMode();

	switch(audioSourceMode) {

	case kVDAudioSourceMode_External:
		{
			const VDStringA& encodedFileName = VDEncodeScriptString(VDStringW(g_szInputWAVFile));
			const VDStringA& encodedDriverName = VDEncodeScriptString(VDTextWToU8(g_project->GetAudioSourceDriverName(), -1));

			// check if we have options to write out
			const InputFileOptions *opts = g_project->GetAudioSourceOptions();
			if (opts) {
				int l;
				char buf[256];

				l = opts->write(buf, (sizeof buf)/7*3);

				if (l) {
					membase64(buf+l, (char *)buf, l);

					output.addf("VirtualDub.audio.SetSource(\"%s\", \"%s\", \"%s\");", encodedFileName.c_str(), encodedDriverName.c_str(), buf+l);
					break;
				}
			}

			// no options
			output.addf("VirtualDub.audio.SetSource(\"%s\", \"%s\");", encodedFileName.c_str(), encodedDriverName.c_str());
		}
		break;

	default:
		if (audioSourceMode >= kVDAudioSourceMode_Source) {
			int index = audioSourceMode - kVDAudioSourceMode_Source;

			if (!index)
				output.addf("VirtualDub.audio.SetSource(1);");
			else
				output.addf("VirtualDub.audio.SetSource(1,%d);", index);
			break;
		}
		// fall through
	case kVDAudioSourceMode_None:
		output.addf("VirtualDub.audio.SetSource(0);");
		break;
	
	}

	output.addf("VirtualDub.audio.SetMode(%d);", opt->audio.mode);

	output.addf("VirtualDub.audio.SetInterleave(%d,%d,%d,%d,%d);",
			opt->audio.enabled,
			opt->audio.preload,
			opt->audio.interval,
			opt->audio.is_ms,
			opt->audio.offset);

	output.addf("VirtualDub.audio.SetClipMode(%d,%d);",
			opt->audio.fStartAudio,
			opt->audio.fEndAudio);

	output.addf("VirtualDub.audio.SetConversion(%d,%d,%d,0,%d);",
			opt->audio.new_rate,
			opt->audio.newPrecision,
			opt->audio.newChannels,
			opt->audio.fHighQuality);

	if (opt->audio.mVolume >= 0.0f)
		output.addf("VirtualDub.audio.SetVolume(%d);", VDRoundToInt(256.0f * opt->audio.mVolume));
	else
		output.addf("VirtualDub.audio.SetVolume();");

	if (g_ACompressionFormat) {
		if (g_ACompressionFormat->mExtraSize) {
			mem = (char *)allocmem(((g_ACompressionFormat->mExtraSize+2)/3)*4 + 1);
			if (!mem) throw MyMemoryError();

			membase64(mem, (char *)(g_ACompressionFormat+1), g_ACompressionFormat->mExtraSize);
			output.addf("VirtualDub.audio.SetCompressionWithHint(%d,%d,%d,%d,%d,%d,%d,\"%s\",\"%s\");"
						,g_ACompressionFormat->mTag
						,g_ACompressionFormat->mSamplingRate
						,g_ACompressionFormat->mChannels
						,g_ACompressionFormat->mSampleBits
						,g_ACompressionFormat->mDataRate
						,g_ACompressionFormat->mBlockSize
						,g_ACompressionFormat->mExtraSize
						,mem
						,VDEncodeScriptString(g_ACompressionFormatHint).c_str()
						);

			freemem(mem);
		} else
			output.addf("VirtualDub.audio.SetCompressionWithHint(%d,%d,%d,%d,%d,%d,\"%s\");"
						,g_ACompressionFormat->mTag
						,g_ACompressionFormat->mSamplingRate
						,g_ACompressionFormat->mChannels
						,g_ACompressionFormat->mSampleBits
						,g_ACompressionFormat->mDataRate
						,g_ACompressionFormat->mBlockSize
						,VDEncodeScriptString(g_ACompressionFormatHint).c_str()
						);
	} else
		output.addf("VirtualDub.audio.SetCompression();");

	output.addf("VirtualDub.audio.EnableFilterGraph(%d);", opt->audio.bUseAudioFilterGraph);

	output.addf("VirtualDub.video.SetInputFormat(%d);", opt->video.mInputFormat);
	output.addf("VirtualDub.video.SetOutputFormat(%d);", opt->video.mOutputFormat);

	output.addf("VirtualDub.video.SetMode(%d);", opt->video.mode);
	output.addf("VirtualDub.video.SetSmartRendering(%d);", opt->video.mbUseSmartRendering);
	output.addf("VirtualDub.video.SetPreserveEmptyFrames(%d);", opt->video.mbPreserveEmptyFrames);

	output.addf("VirtualDub.video.SetFrameRate2(%u,%u,%d);",
			opt->video.mFrameRateAdjustHi,
			opt->video.mFrameRateAdjustLo,
			opt->video.frameRateDecimation);

	if (opt->video.frameRateTargetLo) {
		output.addf("VirtualDub.video.SetTargetFrameRate(%u,%u);",
				opt->video.frameRateTargetHi,
				opt->video.frameRateTargetLo);
	}

	output.addf("VirtualDub.video.SetIVTC(0, 0, 0, 0);");

	if ((g_Vcompression.dwFlags & ICMF_COMPVARS_VALID) && g_Vcompression.fccHandler) {
		output.addf("VirtualDub.video.SetCompression(0x%08lx,%d,%d,%d);",
				g_Vcompression.fccHandler,
				g_Vcompression.lKey,
				g_Vcompression.lQ,
				g_Vcompression.lDataRate);

		l = ICGetStateSize(g_Vcompression.hic);

		if (l>0) {
			mem = (char *)allocmem(l + ((l+2)/3)*4 + 1);
			if (!mem) throw MyMemoryError();

			if (ICGetState(g_Vcompression.hic, mem, l)<0) {
				freemem(mem);
//				throw MyError("Bad state data returned from compressor");

				// Fine then, be that way.  Stupid Pinnacle DV200 driver.
				mem = NULL;
			}

			if (mem) {
				membase64(mem+l, mem, l);
				// urk... Windows Media 9 VCM uses a very large configuration struct (~7K pre-BASE64).
				sprintf(buf, "VirtualDub.video.SetCompData(%d,\"", l);

				VDStringA line(buf);
				line += (mem+l);
				line += "\");";
				output.adds(line.c_str());
				freemem(mem);
			}
		}

	} else
		output.addf("VirtualDub.video.SetCompression();");

	output.addf("VirtualDub.video.filters.Clear();");

	// Add video filters

	FilterInstance *fa = (FilterInstance *)g_listFA.tail.next, *fa_next;
	int iFilter = 0;

	while(fa_next = (FilterInstance *)fa->next) {
		output.addf("VirtualDub.video.filters.Add(\"%s\");", strCify(fa->GetName()));

		if (fa->IsCroppingEnabled()) {
			const vdrect32& cropInsets = fa->GetCropInsets();

			output.addf("VirtualDub.video.filters.instance[%d].SetClipping(%d,%d,%d,%d%s);"
						, iFilter
						, cropInsets.left
						, cropInsets.top
						, cropInsets.right
						, cropInsets.bottom
						, fa->IsPreciseCroppingEnabled() ? "" : ",0"
						);
		}

		VDStringA scriptStr;
		if (fa->GetScriptString(scriptStr))
			output.addf("VirtualDub.video.filters.instance[%d].%s;", iFilter, scriptStr.c_str());

		if (!fa->IsEnabled())
			output.addf("VirtualDub.video.filters.instance[%d].SetEnabled(false);", iFilter);

		VDParameterCurve *pc = fa->GetAlphaParameterCurve();
		if (pc) {
			output.addf("declare curve = VirtualDub.video.filters.instance[%d].AddOpacityCurve();", iFilter);

			const VDParameterCurve::PointList& pts = pc->Points();
			for(VDParameterCurve::PointList::const_iterator it(pts.begin()), itEnd(pts.end()); it!=itEnd; ++it) {
				const VDParameterCurvePoint& pt = *it;

				output.addf("curve.AddPoint(%g, %g, %d);", pt.mX, pt.mY, pt.mbLinear);
			}
		}

		++iFilter;
		fa = fa_next;
	}

	// Add audio filters

	{
		VDAudioFilterGraph::FilterList::const_iterator it(g_audioFilterGraph.mFilters.begin()), itEnd(g_audioFilterGraph.mFilters.end());
		int connidx = 0;
		int srcfilt = 0;

		output.addf("VirtualDub.audio.filters.Clear();");

		for(; it!=itEnd; ++it, ++srcfilt) {
			const VDAudioFilterGraph::FilterEntry& fe = *it;

			output.addf("VirtualDub.audio.filters.Add(\"%s\");", strCify(VDTextWToU8(fe.mFilterName).c_str()));

			for(unsigned i=0; i<fe.mInputPins; ++i) {
				const VDAudioFilterGraph::FilterConnection& conn = g_audioFilterGraph.mConnections[connidx++];
				output.addf("VirtualDub.audio.filters.Connect(%d, %d, %d, %d);", conn.filt, conn.pin, srcfilt, i);
			}

			VDPluginConfig::const_iterator itc(fe.mConfig.begin()), itcEnd(fe.mConfig.end());

			for(; itc!=itcEnd; ++itc) {
				const unsigned idx = (*itc).first;
				const VDPluginConfigVariant& var = (*itc).second;

				switch(var.GetType()) {
				case VDPluginConfigVariant::kTypeU32:
					output.addf("VirtualDub.audio.filters.instance[%d].SetInt(%d, %d);", srcfilt, idx, var.GetU32());
					break;
				case VDPluginConfigVariant::kTypeS32:
					output.addf("VirtualDub.audio.filters.instance[%d].SetInt(%d, %d);", srcfilt, idx, var.GetS32());
					break;
				case VDPluginConfigVariant::kTypeU64:
					output.addf("VirtualDub.audio.filters.instance[%d].SetLong(%d, %I64d);", srcfilt, idx, var.GetU64());
					break;
				case VDPluginConfigVariant::kTypeS64:
					output.addf("VirtualDub.audio.filters.instance[%d].SetLong(%d, %I64d);", srcfilt, idx, var.GetS64());
					break;
				case VDPluginConfigVariant::kTypeDouble:
					output.addf("VirtualDub.audio.filters.instance[%d].SetDouble(%d, %g);", srcfilt, idx, var.GetDouble());
					break;
				case VDPluginConfigVariant::kTypeAStr:
					output.addf("VirtualDub.audio.filters.instance[%d].SetString(%d, \"%s\");", srcfilt, idx, strCify(VDTextWToU8(VDTextAToW(var.GetAStr())).c_str()));
					break;
				case VDPluginConfigVariant::kTypeWStr:
					output.addf("VirtualDub.audio.filters.instance[%d].SetString(%d, \"%s\");", srcfilt, idx, strCify(VDTextWToU8(var.GetWStr(), -1).c_str()));
					break;
				case VDPluginConfigVariant::kTypeBlock:
					output.addf("VirtualDub.audio.filters.instance[%d].SetBlock(%d, %d, \"%s\");", srcfilt, idx, var.GetBlockLen(), VDEncodeBase64A(var.GetBlockPtr(), var.GetBlockLen()).c_str());
					break;
				}
			}
		}
	}

	// Add subset information

	if (bIncludeEditList) {
		const FrameSubset& fs = g_project->GetTimeline().GetSubset();

		output.addf("VirtualDub.subset.Clear();");

		for(FrameSubset::const_iterator it(fs.begin()), itEnd(fs.end()); it!=itEnd; ++it)
			output.addf("VirtualDub.subset.Add%sRange(%I64d,%I64d);", it->bMask ? "Masked" : "", it->start, it->len);

		// Note that this must be AFTER the subset (we used to place it before, which was a bug).
		if (g_project->IsSelectionPresent()) {
			output.addf("VirtualDub.video.SetRangeFrames(%I64d,%I64d);",
				g_project->GetSelectionStartFrame(),
				g_project->GetSelectionEndFrame());
		} else {
			output.addf("VirtualDub.video.SetRange();");
		}
	}

	// Add text information
	if (bIncludeTextInfo) {
		typedef std::list<std::pair<uint32, VDStringA> > tTextInfo;
		const tTextInfo& textInfo = g_project->GetTextInfo();

		output.addf("VirtualDub.project.ClearTextInfo();");
		for(tTextInfo::const_iterator it(textInfo.begin()), itEnd(textInfo.end()); it!=itEnd; ++it) {
			char buf[5]={0};
			
			memcpy(buf, &(*it).first, 4);

			output.addf("VirtualDub.project.AddTextInfo(\"%s\", \"%s\");", buf, VDEncodeScriptString((*it).second).c_str());
		}
	}
}