void guiPositionInitFromStream(IVDPositionControl *pc) { if (!inputVideoAVI) return; const VDFraction videoRate(inputVideoAVI->getRate()); pc->SetRange(inputVideoAVI->getStart(), inputVideoAVI->getEnd()); pc->SetFrameRate(videoRate); }
VDPosition guiPositionHandleCommand(WPARAM wParam, IVDPositionControl *pc) { if (!inputVideo) return -1; IVDStreamSource *pVSS = inputVideo->asStream(); switch(HIWORD(wParam)) { case PCN_START: pc->SetPosition(pVSS->getStart()); return pVSS->getStart(); case PCN_BACKWARD: { VDPosition pos = pc->GetPosition(); if (pos > pVSS->getStart()) { pc->SetPosition(pos - 1); return pos - 1; } } break; case PCN_FORWARD: { VDPosition pos = pc->GetPosition(); if (pos < pVSS->getEnd()) { pc->SetPosition(pos + 1); return pos + 1; } } break; case PCN_END: pc->SetPosition(pVSS->getEnd()); return pVSS->getEnd(); case PCN_KEYPREV: { VDPosition lSample = inputVideo->prevKey(pc->GetPosition()); if (lSample < 0) lSample = pVSS->getStart(); pc->SetPosition(lSample); return lSample; } break; case PCN_KEYNEXT: { VDPosition lSample = inputVideo->nextKey(pc->GetPosition()); if (lSample < 0) lSample = pVSS->getEnd(); pc->SetPosition(lSample); return lSample; } break; } return -1; }
void AppendAVI(const wchar_t *pszFile) { if (inputAVI) { IVDStreamSource *pVSS = inputVideo->asStream(); VDPosition lTail = pVSS->getEnd(); if (inputAVI->Append(pszFile)) { g_project->BeginTimelineUpdate(); FrameSubset& s = g_project->GetTimeline().GetSubset(); s.insert(s.end(), FrameSubsetNode(lTail, pVSS->getEnd() - lTail, false, 0)); g_project->EndTimelineUpdate(); } } }
void guiPositionInitFromStream(IVDPositionControl *pc) { if (!inputVideo) return; IVDStreamSource *pVSS = inputVideo->asStream(); const VDFraction videoRate(pVSS->getRate()); pc->SetRange(pVSS->getStart(), pVSS->getEnd()); pc->SetFrameRate(videoRate); }
int VideoSourceImages::_read(VDPosition lStart, uint32 lCount, void *lpBuffer, uint32 cbBuffer, uint32 *plBytesRead, uint32 *plSamplesRead) { if (plBytesRead) *plBytesRead = 0; if (plSamplesRead) *plSamplesRead = 0; const wchar_t *buf = mpParent->ComputeFilename(mPathBuf, lStart); // Check if we already have the file handle cached. If not, open the file. if (lStart == mCachedHandleFrame) { mCachedFile.seek(0); } else{ mCachedHandleFrame = -1; mCachedFile.closeNT(); mCachedFile.open(buf, nsVDFile::kRead | nsVDFile::kDenyWrite | nsVDFile::kOpenExisting); mCachedHandleFrame = lStart; } // Replace uint32 size = (uint32)mCachedFile.size(); if (size > 0x3fffffff) throw MyError("VideoSourceImages: File \"%s\" is too large (>1GB).", VDTextWToA(buf).c_str()); if (!lpBuffer) { if (plBytesRead) *plBytesRead = size; if (plSamplesRead) *plSamplesRead = 1; return 0; } if (size > cbBuffer) { if (plBytesRead) *plBytesRead = size; return IVDStreamSource::kBufferTooSmall; } mCachedFile.read(lpBuffer, size); if (plBytesRead) *plBytesRead = size; if (plSamplesRead) *plSamplesRead = 1; return 0; }
void guiPositionBlit(HWND hWndClipping, VDPosition lFrame, int w, int h) { if (lFrame<0) return; try { BITMAPINFOHEADER *dcf; if (!inputVideo) SendMessage(hWndClipping, CCM_BLITFRAME2, 0, (LPARAM)NULL); else { dcf = (BITMAPINFOHEADER *)inputVideo->getDecompressedFormat(); IVDStreamSource *pVSS = inputVideo->asStream(); if (lFrame < pVSS->getStart() || lFrame >= pVSS->getEnd()) SendMessage(hWndClipping, CCM_BLITFRAME2, 0, (LPARAM)NULL); else { Pixel32 *tmpmem; const void *pFrame = inputVideo->getFrame(lFrame); int dch = abs(dcf->biHeight); if (w>0 && h>0 && w!=dcf->biWidth && h != dch && (tmpmem = new Pixel32[((w+1)&~1)*h + ((dcf->biWidth+1)&~1)*dch])) { VBitmap vbt(tmpmem, w, h, 32); VBitmap vbs(tmpmem+((w+1)&~1)*h, dcf->biWidth, dch, 32); VBitmap srcbm((void *)pFrame, dcf); vbs.BitBlt(0, 0, &srcbm, 0, 0, -1, -1); vbt.StretchBltBilinearFast(0, 0, w, h, &vbs, 0, 0, vbs.w, vbs.h); VDPixmap px(VDAsPixmap(vbt)); SendMessage(hWndClipping, CCM_BLITFRAME2, 0, (LPARAM)&px); delete[] tmpmem; } else SendMessage(hWndClipping, CCM_BLITFRAME2, 0, (LPARAM)&inputVideo->getTargetFormat()); } } } catch(const MyError&) { _RPT0(0,"Exception!!!\n"); } }
void AppendAVI(const wchar_t *pszFile) { if (inputAVI) { VDPosition lTail = inputAVI->videoSrc->getEnd(); if (inputAVI->Append(pszFile)) { g_project->BeginTimelineUpdate(); FrameSubset& s = g_project->GetTimeline().GetSubset(); s.insert(s.end(), FrameSubsetNode(lTail, inputAVI->videoSrc->getEnd() - lTail, false, 0)); g_project->EndTimelineUpdate(); } } }
LRESULT Frameserver::SessionFrame(LPARAM lParam, WPARAM original_frame) { FrameserverSession *fs = SessionLookup(lParam); if (!fs) return VDSRVERR_BADSESSION; try { const VDPixmapLayout& output = filters.GetOutputLayout(); if (fs->arena_size < ((output.w*3+3)&-4)*output.h) return VDSRVERR_TOOBIG; VDPosition pos = mVideoFrameMap[original_frame].mSourceFrame; if (pos < 0) return VDSRVERR_FAILED; vdrefptr<IVDFilterFrameClientRequest> creq; filters.RequestFrame(pos, 0, ~creq); while(!creq->IsCompleted()) { if (filters.Run(NULL, false) == FilterSystem::kRunResult_Running) continue; switch(mpVideoFrameSource->RunRequests(NULL)) { case IVDFilterFrameSource::kRunResult_Running: case IVDFilterFrameSource::kRunResult_IdleWasActive: case IVDFilterFrameSource::kRunResult_BlockedWasActive: continue; } filters.Block(); } VDPixmap pxdst(VDPixmapFromLayout(mFrameLayout, fs->arena)); VDFilterFrameBuffer *buf = creq->GetResultBuffer(); VDPixmapBlt(pxdst, VDPixmapFromLayout(filters.GetOutputLayout(), (void *)buf->LockRead())); buf->Unlock(); } catch(const MyError&) { return VDSRVERR_FAILED; } return VDSRVERR_OK; }
bool VDDialogEditAccelerators::OnLoaded() { VDSetDialogDefaultIcons(mhdlg); GetWindowRect(mhdlg, &mrInitial); mpHotKeyControl = VDGetUIHotKeyExControl((VDGUIHandle)GetControl(IDC_HOTKEY)); if (mpHotKeyControl) mpHotKeyControl->OnChange() += mDelegateHotKeyChanged(this, &VDDialogEditAccelerators::OnHotKeyChanged); mResizer.Init(mhdlg); mResizer.Add(IDOK, VDDialogResizerW32::kBR); mResizer.Add(IDCANCEL, VDDialogResizerW32::kBR); mResizer.Add(IDC_ADD, VDDialogResizerW32::kBR); mResizer.Add(IDC_REMOVE, VDDialogResizerW32::kBR); mResizer.Add(IDC_RESET, VDDialogResizerW32::kBL); mResizer.Add(IDC_HOTKEY, VDDialogResizerW32::kBC); mResizer.Add(IDC_STATIC_QUICKSEARCH, VDDialogResizerW32::kBL); mResizer.Add(IDC_STATIC_SHORTCUT, VDDialogResizerW32::kBL); mResizer.Add(IDC_STATIC_AVAILABLECOMMANDS, VDDialogResizerW32::kAnchorX2_C); mResizer.Add(IDC_STATIC_BOUNDCOMMANDS, VDDialogResizerW32::kAnchorX1_C | VDDialogResizerW32::kAnchorX2_R); mResizer.Add(IDC_AVAILCOMMANDS, VDDialogResizerW32::kAnchorX2_C | VDDialogResizerW32::kAnchorY2_B); mResizer.Add(IDC_BOUNDCOMMANDS, VDDialogResizerW32::kAnchorX1_C | VDDialogResizerW32::kAnchorX2_R | VDDialogResizerW32::kAnchorY2_B ); mResizer.Add(IDC_FILTER, VDDialogResizerW32::kAnchorY1_B | VDDialogResizerW32::kAnchorX2_C | VDDialogResizerW32::kAnchorY2_B); mResizer.Add(IDC_HOTKEY, VDDialogResizerW32::kBC); AddProxy(&mListViewBoundCommands, IDC_BOUNDCOMMANDS); mListViewBoundCommands.SetFullRowSelectEnabled(true); mListViewBoundCommands.InsertColumn(0, L"Command", 50); mListViewBoundCommands.InsertColumn(1, L"Shortcut", 50); mListViewBoundCommands.AutoSizeColumns(); RefilterCommands("*"); VDDialogFrameW32::OnLoaded(); SetFocusToControl(IDC_FILTER); return true; }
void VDDialogEditAccelerators::OnItemSelectionChanged(VDUIProxyListView *source, int index) { if (index < 0 || mbBlockCommandUpdate) return; const BoundCommand& bcmd = *mBoundCommands[index]; if (mpHotKeyControl) mpHotKeyControl->SetAccelerator(bcmd.mAccel); uint32 n = mFilteredCommands.size(); int cmdSelIndex = -1; for(uint32 i=0; i<n; ++i) { const VDAccelToCommandEntry& cent = *mFilteredCommands[i]; if (!_stricmp(cent.mpName, bcmd.mpCommand)) { cmdSelIndex = i; break; } } LBSetSelectedIndex(IDC_AVAILCOMMANDS, cmdSelIndex); }
int VDVideoSourceFLM::_read(VDPosition lStart, uint32 lCount, void *lpBuffer, uint32 cbBuffer, uint32 *lBytesRead, uint32 *lSamplesRead) { if (lCount > 1) lCount = 1; int ret = 0; if (lCount > 0) { if (lpBuffer) { if (mVisibleFrameSize > cbBuffer) ret = IVDStreamSource::kBufferTooSmall; else { mpParent->ReadSpan((uint64)mFrameSize * lStart, lpBuffer, mVisibleFrameSize); // Swizzle the frame now. Easier this way. We need to go from RGBA to BGRA. uint8 *p = (uint8 *)lpBuffer; uint32 count = mVisibleFrameSize >> 2; do { uint8 r = p[0]; uint8 b = p[2]; p[0] = b; p[2] = r; p += 4; } while(--count); } } } if (lBytesRead) *lBytesRead = mVisibleFrameSize; if (lSamplesRead) *lSamplesRead = lCount; return ret; }
void AppendAVIAutoscan(const wchar_t *pszFile) { wchar_t buf[MAX_PATH]; wchar_t *s = buf, *t; int count = 0; if (!inputAVI) return; IVDStreamSource *pVSS = inputVideo->asStream(); VDPosition originalCount = pVSS->getEnd(); wcscpy(buf, pszFile); t = VDFileSplitExt(VDFileSplitPath(s)); if (t>buf) --t; try { for(;;) { if (!VDDoesPathExist(buf)) break; if (!inputAVI->Append(buf)) break; ++count; s = t; for(;;) { if (s<buf || !isdigit(*s)) { memmove(s+2, s+1, sizeof(wchar_t) * wcslen(s)); s[1] = L'1'; ++t; } else { if (*s == L'9') { *s-- = L'0'; continue; } ++*s; } break; } } } catch(const MyError& e) { // if the first segment failed, turn the warning into an error if (!count) throw; // log append errors, but otherwise eat them VDLog(kVDLogWarning, VDTextAToW(e.gets())); } guiSetStatus("Appended %d segments (stopped at \"%s\")", 255, count, VDTextWToA(buf).c_str()); if (count) { FrameSubset& s = g_project->GetTimeline().GetSubset(); g_project->BeginTimelineUpdate(); s.insert(s.end(), FrameSubsetNode(originalCount, pVSS->getEnd() - originalCount, false, 0)); g_project->EndTimelineUpdate(); } }
void SetSelectionEnd(long ms) { if (!inputVideoAVI) return; g_project->SetSelectionEnd(g_project->GetFrameCount() - inputVideoAVI->msToSamples(ms)); }
void SetSelectionStart(long ms) { if (!inputVideoAVI) return; g_project->SetSelectionStart(inputVideoAVI->msToSamples(ms)); }
const void *VideoSourceImages::streamGetFrame(const void *inputBuffer, uint32 data_len, bool is_preroll, VDPosition frame_num, VDPosition target_sample) { // We may get a zero-byte frame if we already have the image. if (!data_len) return getFrameBuffer(); int w, h; bool bHasAlpha; bool bIsPNG = false; bool bIsJPG = false; bool bIsBMP = false; bool bIsIFF = false; bool bIsTGA = false; bIsPNG = VDDecodePNGHeader(inputBuffer, data_len, w, h, bHasAlpha); if (!bIsPNG) { bIsJPG = VDIsJPEGHeader(inputBuffer, data_len); if (!bIsJPG) { bIsBMP = DecodeBMPHeader(inputBuffer, data_len, w, h, bHasAlpha); if (!bIsBMP) { bIsIFF = VDIsMayaIFFHeader(inputBuffer, data_len); if (!bIsIFF) bIsTGA = DecodeTGAHeader(inputBuffer, data_len, w, h, bHasAlpha); } } } if (!bIsBMP && !bIsTGA && !bIsJPG && !bIsPNG && !bIsIFF) throw MyError("Image file must be in PNG, Windows BMP, truecolor TARGA format, MayaIFF, or sequential JPEG format."); if (bIsJPG) { if (!mpJPEGDecoder) mpJPEGDecoder = VDCreateJPEGDecoder(); mpJPEGDecoder->Begin(inputBuffer, data_len); mpJPEGDecoder->DecodeHeader(w, h); } VDPixmap pxIFF; if (bIsIFF) { if (!mpIFFDecoder) mpIFFDecoder = VDCreateImageDecoderIFF(); pxIFF = mpIFFDecoder->Decode(inputBuffer, data_len); w = pxIFF.w; h = pxIFF.h; } // Check image header. VDAVIBitmapInfoHeader *pFormat = getImageFormat(); if (getFrameBuffer()) { if (w != pFormat->biWidth || h != pFormat->biHeight) { vdfastvector<wchar_t> errBuf; throw MyError("Image \"%ls\" (%dx%d) doesn't match the image dimensions of the first image (%dx%d)." , mpParent->ComputeFilename(errBuf, frame_num), w, h, pFormat->biWidth, pFormat->biHeight); } } else { if (!AllocFrameBuffer(w * h * 4)) throw MyMemoryError(); pFormat->biSize = sizeof(BITMAPINFOHEADER); pFormat->biWidth = w; pFormat->biHeight = h; pFormat->biPlanes = 1; pFormat->biCompression = 0xFFFFFFFFUL; pFormat->biBitCount = 0; pFormat->biSizeImage = 0; pFormat->biXPelsPerMeter = 0; pFormat->biYPelsPerMeter = 0; pFormat->biClrUsed = 0; pFormat->biClrImportant = 0; // special case for initial read in constructor return NULL; } if (bIsJPG) { int format; switch(mvbFrameBuffer.depth) { case 16: format = IVDJPEGDecoder::kFormatXRGB1555; break; case 24: format = IVDJPEGDecoder::kFormatRGB888; break; case 32: format = IVDJPEGDecoder::kFormatXRGB8888; break; } mpJPEGDecoder->DecodeImage((char *)mvbFrameBuffer.data + mvbFrameBuffer.pitch * (mvbFrameBuffer.h - 1), -mvbFrameBuffer.pitch, format); mpJPEGDecoder->End(); } if (bIsIFF) VDPixmapBlt(getTargetFormat(), pxIFF); if (bIsBMP) DecodeBMP(inputBuffer, data_len, mvbFrameBuffer); if (bIsTGA) DecodeTGA(inputBuffer, data_len, mvbFrameBuffer); if (bIsPNG) { if (!mpPNGDecoder) mpPNGDecoder = VDCreateImageDecoderPNG(); PNGDecodeError err = mpPNGDecoder->Decode(inputBuffer, data_len); if (err) { if (err == kPNGDecodeOutOfMemory) throw MyMemoryError(); vdfastvector<wchar_t> errBuf; throw MyError("Error decoding \"%ls\": %ls\n", mpParent->ComputeFilename(errBuf, frame_num), VDLoadString(0, kVDST_PNGDecodeErrors, err)); } VDPixmapBlt(VDAsPixmap(mvbFrameBuffer), mpPNGDecoder->GetFrameBuffer()); } mCachedFrame = frame_num; return mpFrameBuffer; }
bool VDDialogEditAccelerators::OnCommand(uint32 id, uint32 extcode) { if (id == IDC_FILTER) { if (extcode == EN_CHANGE) { VDStringA s("*"); s += VDTextWToA(GetControlValueString(id)).c_str(); s += '*'; RefilterCommands(s.c_str()); return true; } } else if (id == IDC_ADD) { VDUIAccelerator accel; int selIdx = LBGetSelectedIndex(IDC_AVAILCOMMANDS); if ((size_t)selIdx < mFilteredCommands.size()) { const VDAccelToCommandEntry *ace = mFilteredCommands[selIdx]; if (mpHotKeyControl) { mpHotKeyControl->GetAccelerator(accel); // Look for a conflicting command. for(BoundCommands::iterator it(mBoundCommands.begin()), itEnd(mBoundCommands.end()); it != itEnd; ++it) { BoundCommand *obc = *it; if (obc->mAccel == accel) { VDStringW keyName; VDUIGetAcceleratorString(accel, keyName); VDStringA msg; msg.sprintf("The key %ls is already bound to %hs. Rebind it to %hs?", keyName.c_str(), obc->mpCommand, ace->mpName); if (IDOK != MessageBox(mhdlg, msg.c_str(), g_szWarning, MB_OKCANCEL | MB_ICONEXCLAMATION)) return true; mBoundCommands.erase(it); obc->Release(); } } vdrefptr<BoundCommand> bc(new_nothrow BoundCommand); if (bc) { bc->mpCommand = ace->mpName; bc->mCommandId = ace->mId; bc->mAccel = accel; mBoundCommands.push_back(bc.release()); RefreshBoundList(); } } } return true; } else if (id == IDC_REMOVE) { int selIdx = mListViewBoundCommands.GetSelectedIndex(); if ((unsigned)selIdx < mBoundCommands.size()) { BoundCommand *bc = mBoundCommands[selIdx]; mBoundCommands.erase(mBoundCommands.begin() + selIdx); bc->Release(); RefreshBoundList(); } return true; } else if (id == IDC_RESET) { if (IDOK == MessageBox(mhdlg, "Really reset?", g_szWarning, MB_OKCANCEL | MB_ICONEXCLAMATION)) LoadTable(mBoundCommandsDefault); return true; } return false; }
void Frameserver::Go(IVDubServerLink *ivdsl, char *name) { int server_index = -1; lpszFsname = name; // prepare the sources... if (!vSrc->setTargetFormat(g_dubOpts.video.mInputFormat)) if (!vSrc->setTargetFormat(nsVDPixmap::kPixFormat_XRGB8888)) if (!vSrc->setTargetFormat(nsVDPixmap::kPixFormat_RGB888)) if (!vSrc->setTargetFormat(nsVDPixmap::kPixFormat_XRGB1555)) if (!vSrc->setTargetFormat(nsVDPixmap::kPixFormat_Pal8)) throw MyError("The decompression codec cannot decompress to an RGB format. This is very unusual. Check that any \"Force YUY2\" options are not enabled in the codec's properties."); IVDStreamSource *pVSS = vSrc->asStream(); FrameSubset videoset(mSubset); const VDFraction frameRateTimeline(g_project->GetTimelineFrameRate()); VDPosition startFrame; VDPosition endFrame; VDConvertSelectionTimesToFrames(*opt, mSubset, frameRateTimeline, startFrame, endFrame); InitVideoStreamValuesStatic(vInfo, vSrc, aSrc, opt, &mSubset, &startFrame, &endFrame); const VDPixmap& px = vSrc->getTargetFormat(); const VDFraction& srcFAR = vSrc->getPixelAspectRatio(); filters.prepareLinearChain(&g_filterChain, px.w, px.h, px.format, vInfo.mFrameRatePreFilter, -1, srcFAR); mpVideoFrameSource = new VDFilterFrameVideoSource; mpVideoFrameSource->Init(vSrc, filters.GetInputLayout()); filters.SetVisualAccelDebugEnabled(false); filters.SetAccelEnabled(VDPreferencesGetFilterAccelEnabled()); filters.SetAsyncThreadCount(VDPreferencesGetFilterThreadCount()); filters.initLinearChain(NULL, 0, &g_filterChain, mpVideoFrameSource, px.w, px.h, px.format, px.palette, vInfo.mFrameRatePreFilter, -1, srcFAR); filters.ReadyFilters(); InitVideoStreamValuesStatic2(vInfo, opt, &filters, frameRateTimeline); InitAudioStreamValuesStatic(aInfo, aSrc, opt); vdfastvector<IVDVideoSource *> vsrcs(1, vSrc); mVideoFrameMap.Init(vsrcs, vInfo.start_src, vInfo.mFrameRateTimeline / vInfo.mFrameRate, &mSubset, vInfo.end_dst, opt->video.mbUseSmartRendering, opt->video.mode == DubVideoOptions::M_NONE, opt->video.mbPreserveEmptyFrames, &filters, false, false); if (opt->audio.fEndAudio) videoset.deleteRange(endFrame, videoset.getTotalFrames()); if (opt->audio.fStartAudio) videoset.deleteRange(0, startFrame); VDDEBUG("Video subset:\n"); videoset.dump(); if (aSrc) AudioTranslateVideoSubset(audioset, videoset, vInfo.mFrameRateTimeline, aSrc->getWaveFormat(), !opt->audio.fEndAudio && (videoset.empty() || videoset.back().end() == pVSS->getEnd()) ? aSrc->getEnd() : 0, NULL); VDDEBUG("Audio subset:\n"); audioset.dump(); if (aSrc) { audioset.offset(aSrc->msToSamples(-opt->audio.offset)); lAudioSamples = VDClampToUint32(audioset.getTotalFrames()); } else lAudioSamples = 0; lVideoSamples = VDClampToUint32(mVideoFrameMap.size()); vSrc->streamBegin(true, false); const VDPixmapLayout& outputLayout = filters.GetOutputLayout(); mFrameSize = VDPixmapCreateLinearLayout(mFrameLayout, nsVDPixmap::kPixFormat_RGB888, outputLayout.w, outputLayout.h, 4); VDPixmapLayoutFlipV(mFrameLayout); if (aSrc) aSrc->streamBegin(true, false); // usurp the window VDUIFrame *pFrame = VDUIFrame::GetFrame(hwnd); mpUIFrame = pFrame; pFrame->Attach(this); guiSetTitle(hwnd, IDS_TITLE_FRAMESERVER); // create dialog box mbExit = false; if (hwndStatus = CreateDialogParam(g_hInst, MAKEINTRESOURCE(IDD_SERVER), hwnd, Frameserver::StatusDlgProc, (LPARAM)this)) { // hide the main window ShowWindow(hwnd, SW_HIDE); // create the frameserver server_index = ivdsl->CreateFrameServer(name, hwnd); if (server_index>=0) { // kick us into high priority SetPriorityClass(GetCurrentProcess(), HIGH_PRIORITY_CLASS); // enter window loop { MSG msg; while(!mbExit) { BOOL result = GetMessage(&msg, NULL, 0, 0); if (result == (BOOL)-1) break; if (!result) { PostQuitMessage(msg.wParam); break; } TranslateMessage(&msg); DispatchMessage(&msg); } } // return to normal priority SetPriorityClass(GetCurrentProcess(), HIGH_PRIORITY_CLASS); ivdsl->DestroyFrameServer(server_index); } if (IsWindow(hwndStatus)) DestroyWindow(hwndStatus); // show the main window ShowWindow(hwnd, SW_SHOW); } // unsubclass pFrame->Detach(); if (vSrc) { IVDStreamSource *pVSS = vSrc->asStream(); pVSS->streamEnd(); } if (server_index<0) throw MyError("Couldn't create frameserver"); }