2 * Copyright (C) 2003-2006 Gabest
3 * http://www.gabest.org
5 * This Program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2, or (at your option)
10 * This Program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with GNU Make; see the file COPYING. If not, write to
17 * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
18 * http://www.gnu.org/copyleft/gpl.html
22 // ConvertDlg.cpp : implementation file
28 #include "..\..\filters\filters.h"
29 #include "..\..\..\include\moreuuids.h"
30 #include "FGManager.h"
31 #include "ConvertPropsDlg.h"
32 #include "ConvertResDlg.h"
33 #include "ConvertChapDlg.h"
34 #include "ConvertDlg.h"
36 // TODO: subtitle source filter for vobsub
40 CConvertDlg::CConvertDlg(CWnd
* pParent
/*=NULL*/)
41 : CResizableDialog(CConvertDlg::IDD
, pParent
)
46 CConvertDlg::~CConvertDlg()
50 void CConvertDlg::AddFile(CString fn
)
54 int i
= fn
.Find(_T("://"));
57 CString url
= fn
.Mid(i
);
58 CPath
path(fn
.Left(i
));
60 protocol
= (LPCTSTR
)path
;
61 fn
= (LPCTSTR
)path
+ url
;
64 CComPtr
<IBaseFilter
> pBF
;
65 if(FAILED(m_pGB
->AddSourceFilter(CStringW(fn
), CStringW(fn
), &pBF
)))
69 BeginEnumPins(pBF
, pEP
, pPin
)
70 if(S_OK
== m_pGB
->ConnectFilter(pPin
, m_pMux
)) nConnected
++;
72 if(!nConnected
) {MessageBeep(-1); DeleteFilter(pBF
); return;}
74 if(m_tree
.GetCount() == 0)
76 if(CComQIPtr
<IDSMPropertyBag
> pPB
= m_pMux
)
77 pPB
->DelAllProperties();
79 CString
ext(_T(".dsm"));
81 if(!protocol
.IsEmpty())
83 m_fn
= protocol
+ ext
;
88 if(ext
.CompareNoCase(p
.GetExtension()) == 0)
89 ext
= _T(" (remuxed)") + ext
;
91 m_fn
= (LPCTSTR
)p
+ ext
;
97 CTreeItemFile
* t
= new CTreeItemFile(fn
, pBF
, m_tree
, NULL
);
101 m_tree
.Expand(*t
, TVE_EXPAND
);
102 m_tree
.EnsureVisible(*t
);
105 bool CConvertDlg::ConvertFile(LPCTSTR fn
, IPin
* pPin
)
108 if(!m_pMC
|| FAILED(m_pMC
->GetState(0, &fs
)) || fs
!= State_Stopped
)
111 m_pGB
->NukeDownstream(m_pMux
);
113 CComPtr
<IBaseFilter
> pFW
;
114 pFW
.CoCreateInstance(CLSID_FileWriter
);
115 CComQIPtr
<IFileSinkFilter2
> pFSF
= pFW
;
119 CComQIPtr
<IBaseMuxerRelatedPin
> pRP
= pPin
;
120 if(!pRP
) return false;
122 pPin
= pRP
->GetRelatedPin();
126 pPin
= GetFirstPin(m_pMux
, PINDIR_OUTPUT
);
130 || FAILED(m_pGB
->AddFilter(pFW
, NULL
))
131 || FAILED(pFSF
->SetFileName(CStringW(fn
), NULL
))
132 || FAILED(pFSF
->SetMode(AM_FILE_OVERWRITE
))
133 || FAILED(m_pGB
->ConnectDirect(pPin
, GetFirstPin(pFW
), NULL
)))
135 m_pGB
->RemoveFilter(pFW
);
142 m_pMS
->SetPositions(&pos
, AM_SEEKING_AbsolutePositioning
, NULL
, AM_SEEKING_NoPositioning
);
145 if(CComQIPtr
<IDSMPropertyBag
> pPB
= m_pMux
)
147 pPB
->SetProperty(L
"APPL", L
"Media Player Classic");
150 if(CComQIPtr
<IDSMResourceBag
> pRB
= m_pMux
)
152 pRB
->ResRemoveAll(0);
153 POSITION pos
= m_pTIs
.GetHeadPosition();
156 if(CTreeItemResource
* t2
= dynamic_cast<CTreeItemResource
*>((CTreeItem
*)m_pTIs
.GetNext(pos
)))
158 t2
->m_res
.name
, t2
->m_res
.desc
, t2
->m_res
.mime
,
159 t2
->m_res
.data
.GetData(), t2
->m_res
.data
.GetCount(),
164 if(CComQIPtr
<IDSMChapterBag
> pCB
= m_pMux
)
166 pCB
->ChapRemoveAll();
167 POSITION pos
= m_pTIs
.GetHeadPosition();
170 if(CTreeItemChapter
* t2
= dynamic_cast<CTreeItemChapter
*>((CTreeItem
*)m_pTIs
.GetNext(pos
)))
171 pCB
->ChapAppend(t2
->m_chap
.rt
, t2
->m_chap
.name
);
175 if(FAILED(m_pMC
->Run()))
178 m_tree
.EnableWindow(FALSE
);
183 void CConvertDlg::AddFilter(HTREEITEM hTIParent
, IBaseFilter
* pBFParent
)
185 BeginEnumPins(pBFParent
, pEP
, pPin
)
187 CComPtr
<IPin
> pPinTo
;
188 CComPtr
<IBaseFilter
> pBF
;
189 if(S_OK
!= m_pGB
->IsPinDirection(pPin
, PINDIR_OUTPUT
)
190 || FAILED(pPin
->ConnectedTo(&pPinTo
)) || !pPinTo
191 || !(pBF
= GetFilterFromPin(pPinTo
)))
198 t
= new CTreeItemPin(pPin
, m_tree
, hTIParent
);
202 t
= new CTreeItemFilter(pBF
, m_tree
, hTIParent
);
208 if(CComQIPtr
<IDSMPropertyBag
> pPB
= pBFParent
)
211 if(FAILED(pPB
->CountProperties(&props
)))
214 for(ULONG i
= 0; i
< props
; i
++)
217 memset(&PropBag
, 0, sizeof(PropBag
));
218 ULONG cPropertiesReturned
= 0;
219 if(FAILED(pPB
->GetPropertyInfo(i
, 1, &PropBag
, &cPropertiesReturned
)))
224 if(SUCCEEDED(pPB
->Read(1, &PropBag
, NULL
, &var
, &hr
)) && SUCCEEDED(hr
))
226 CComQIPtr
<IDSMPropertyBag
> pPBMux
= m_pMux
;
228 if(pPBMux
&& FAILED(pPBMux
->GetProperty(PropBag
.pstrName
, &value
)))
229 pPBMux
->SetProperty(PropBag
.pstrName
, var
.bstrVal
);
232 CoTaskMemFree(PropBag
.pstrName
);
236 CTreeItem
* t2
= new CTreeItemResourceFolder(m_tree
, hTIParent
);
237 if(CComQIPtr
<IDSMResourceBag
> pRB
= pBFParent
)
239 for(DWORD i
= 0, cnt
= pRB
->ResGetCount(); i
< cnt
; i
++)
241 CComBSTR name
, mime
, desc
;
244 if(FAILED(pRB
->ResGet(i
, &name
, &desc
, &mime
, &pData
, &len
, NULL
)))
249 m_pTIs
.AddTail(new CTreeItemResource(CDSMResource(name
, desc
, mime
, pData
, len
), m_tree
, *t2
));
252 CoTaskMemFree(pData
);
255 m_tree
.Expand(*t2
, TVE_EXPAND
);
257 CTreeItem
* t3
= new CTreeItemChapterFolder(m_tree
, hTIParent
);
258 if(CComQIPtr
<IDSMChapterBag
> pCB
= pBFParent
)
260 for(DWORD i
= 0, cnt
= pCB
->ChapGetCount(); i
< cnt
; i
++)
264 if(FAILED(pCB
->ChapGet(i
, &rt
, &name
)))
267 m_pTIs
.AddTail(new CTreeItemChapter(CDSMChapter(rt
, name
), m_tree
, *t3
));
270 m_tree
.Expand(*t3
, TVE_EXPAND
);
272 m_tree
.Expand(hTIParent
, TVE_EXPAND
);
275 void CConvertDlg::DeleteFilter(IBaseFilter
* pBF
)
277 BeginEnumPins(pBF
, pEP
, pPin
)
279 CComPtr
<IPin
> pPinTo
;
280 CComPtr
<IBaseFilter
> pBF
;
281 if(S_OK
!= m_pGB
->IsPinDirection(pPin
, PINDIR_OUTPUT
)
282 || FAILED(pPin
->ConnectedTo(&pPinTo
)) || !pPinTo
283 || !(pBF
= GetFilterFromPin(pPinTo
)))
286 if(pBF
!= m_pMux
) DeleteFilter(pBF
);
290 m_pGB
->RemoveFilter(pBF
);
293 void CConvertDlg::DeleteItem(HTREEITEM hTI
)
299 CTreeItem
* t
= (CTreeItem
*)m_tree
.GetItemData(hTI
);
300 if(POSITION pos
= m_pTIs
.Find(t
)) m_pTIs
.RemoveAt(pos
);
302 m_tree
.DeleteItem(hTI
);
305 void CConvertDlg::DeleteChildren(HTREEITEM hTI
)
309 if(m_tree
.ItemHasChildren(hTI
))
311 HTREEITEM hChildItem
= m_tree
.GetChildItem(hTI
);
313 while(hChildItem
!= NULL
)
315 HTREEITEM hNextItem
= m_tree
.GetNextItem(hChildItem
, TVGN_NEXT
);
316 DeleteItem(hChildItem
);
317 hChildItem
= hNextItem
;
322 HTREEITEM
CConvertDlg::HitTest(CPoint
& sp
, CPoint
& cp
)
324 sp
= CPoint((LPARAM
)GetMessagePos());
326 m_tree
.ScreenToClient(&cp
);
328 HTREEITEM hTI
= m_tree
.HitTest(cp
, &flags
);
329 return hTI
&& (flags
&TVHT_ONITEM
) ? hTI
: NULL
;
332 void CConvertDlg::ShowPopup(CPoint p
)
338 m
.AppendMenu(MF_STRING
, i
++, ResStr(IDS_CONVERT_ADDFILE
));
339 m
.AppendMenu(MF_SEPARATOR
);
340 m
.AppendMenu(MF_STRING
, i
++, ResStr(IDS_CONVERT_PROPERTIES
));
342 switch((int)m
.TrackPopupMenu(TPM_LEFTBUTTON
|TPM_RETURNCMD
, p
.x
, p
.y
, this))
346 CFileDialog
fd(TRUE
, NULL
, m_fn
,
347 OFN_EXPLORER
|OFN_ENABLESIZING
|OFN_HIDEREADONLY
|OFN_NOVALIDATE
,
348 _T("Media files|*.*||"), this, 0);
349 if(fd
.DoModal() == IDOK
) AddFile(fd
.GetPathName());
353 EditProperties(CComQIPtr
<IDSMPropertyBag
>(m_pMux
));
358 void CConvertDlg::ShowFilePopup(HTREEITEM hTI
, CPoint p
)
360 CTreeItemFile
* t
= dynamic_cast<CTreeItemFile
*>((CTreeItem
*)m_tree
.GetItemData(hTI
));
367 m
.AppendMenu(MF_STRING
, i
++, ResStr(IDS_CONVERT_REMOVE
));
369 switch((int)m
.TrackPopupMenu(TPM_LEFTBUTTON
|TPM_RETURNCMD
, p
.x
, p
.y
, this))
372 DeleteFilter(t
->m_pBF
);
378 void CConvertDlg::ShowPinPopup(HTREEITEM hTI
, CPoint p
)
380 CTreeItemPin
* t
= dynamic_cast<CTreeItemPin
*>((CTreeItem
*)m_tree
.GetItemData(hTI
));
383 if(!t
->m_pPin
) return;
385 CComPtr
<IPin
> pPinTo
;
386 t
->m_pPin
->ConnectedTo(&pPinTo
);
389 if(pPinTo
) t
->m_pPin
->ConnectionMediaType(&mt
);
391 CAtlArray
<CMediaType
> mts
;
392 BeginEnumMediaTypes(t
->m_pPin
, pEMT
, pmt
)
394 EndEnumMediaTypes(pmt
)
399 int i
= 1, mtbase
= 1000, mti
= mtbase
;
401 m
.AppendMenu(MF_STRING
, i
++, !pPinTo
? ResStr(IDS_CONVERT_ENABLESTREAM
) : ResStr(IDS_CONVERT_DISABLESTREAM
));
402 m
.AppendMenu(MF_STRING
| (!pPinTo
? MF_GRAYED
: 0), i
++, ResStr(IDS_CONVERT_DEMUXSTREAM
));
404 if(mts
.GetCount() > 1)
406 m
.AppendMenu(MF_SEPARATOR
);
407 for(int i
= 0; i
< mts
.GetCount(); i
++)
408 m
.AppendMenu(MF_STRING
| (mts
[i
] == mt
? MF_CHECKED
: 0), mti
++, CMediaTypeEx(mts
[i
]).ToString());
411 m
.AppendMenu(MF_SEPARATOR
);
412 m
.AppendMenu(MF_STRING
| (!pPinTo
? MF_GRAYED
: 0), i
++, ResStr(IDS_CONVERT_PINPROPERTIES
));
414 switch(i
= (int)m
.TrackPopupMenu(TPM_LEFTBUTTON
|TPM_RETURNCMD
, p
.x
, p
.y
, this))
417 if(pPinTo
) {m_pGB
->Disconnect(pPinTo
); m_pGB
->Disconnect(t
->m_pPin
);}
418 else if(pPinTo
= GetFirstDisconnectedPin(m_pMux
, PINDIR_INPUT
)) m_pGB
->ConnectDirect(t
->m_pPin
, pPinTo
, NULL
);
425 CString ext
= _T("raw");
427 if(mt
.subtype
== MEDIASUBTYPE_AAC
) ext
= _T("aac");
428 else if(mt
.subtype
== MEDIASUBTYPE_MP3
) ext
= _T("mp3");
429 else if(mt
.subtype
== FOURCCMap(WAVE_FORMAT_MPEG
)) ext
= _T("m1a");
430 else if(mt
.subtype
== MEDIASUBTYPE_MPEG2_AUDIO
) ext
= _T("m2a");
431 else if(mt
.subtype
== MEDIASUBTYPE_WAVE_DOLBY_AC3
|| mt
.subtype
== MEDIASUBTYPE_DOLBY_AC3
) ext
= _T("ac3");
432 else if(mt
.subtype
== MEDIASUBTYPE_WAVE_DTS
|| mt
.subtype
== MEDIASUBTYPE_DTS
) ext
= _T("dts");
433 else if((mt
.subtype
== FOURCCMap('1CVA') || mt
.subtype
== FOURCCMap('1cva')) && mt
.formattype
== FORMAT_MPEG2_VIDEO
) ext
= _T("h264");
434 else if(mt
.subtype
== FOURCCMap('GEPJ') || mt
.subtype
== FOURCCMap('gepj')) ext
= _T("jpg");
435 else if(mt
.majortype
== MEDIATYPE_Video
&& mt
.subtype
== MEDIASUBTYPE_MPEG2_VIDEO
) ext
= _T("m2v");
436 else if(mt
.majortype
== MEDIATYPE_Video
&& mt
.subtype
== MEDIASUBTYPE_MPEG1Payload
) ext
= _T("m1v");
437 else if(mt
.subtype
== MEDIASUBTYPE_UTF8
|| mt
.majortype
== MEDIATYPE_Text
) ext
= _T("srt");
438 else if(mt
.subtype
== MEDIASUBTYPE_SSA
) ext
= _T("ssa");
439 else if(mt
.subtype
== MEDIASUBTYPE_ASS
|| mt
.subtype
== MEDIASUBTYPE_ASS2
) ext
= _T("ass");
440 else if(mt
.subtype
== MEDIASUBTYPE_SSF
) ext
= _T("ssf");
441 else if(mt
.subtype
== MEDIASUBTYPE_VOBSUB
) ext
= _T("sub");
442 else if(mt
.subtype
== MEDIASUBTYPE_PCM
|| mt
.subtype
== MEDIASUBTYPE_DVD_LPCM_AUDIO
|| mt
.subtype
== FOURCCMap(WAVE_FORMAT_EXTENSIBLE
) || mt
.subtype
== FOURCCMap(WAVE_FORMAT_IEEE_FLOAT
)) ext
= _T("wav");
446 path
.RenameExtension('.' + ext
);
448 CFileDialog
fd(FALSE
, NULL
, (LPCTSTR
)path
,
449 OFN_EXPLORER
|OFN_ENABLESIZING
|OFN_HIDEREADONLY
,
450 _T("Media files|*.*||"), this, 0);
451 if(fd
.DoModal() == IDOK
)
453 if(!ConvertFile(fd
.GetPathName(), pPinTo
))
455 AfxMessageBox(_T("Failed to start conversion"));
461 EditProperties(CComQIPtr
<IDSMPropertyBag
>(pPinTo
));
465 if(i
>= 0 && i
< mts
.GetCount())
467 if(pPinTo
) {m_pGB
->Disconnect(pPinTo
); m_pGB
->Disconnect(t
->m_pPin
);}
468 else {pPinTo
= GetFirstDisconnectedPin(m_pMux
, PINDIR_INPUT
);}
469 HRESULT hr
= m_pGB
->ConnectDirect(t
->m_pPin
, pPinTo
, &mts
[i
]);
472 AfxMessageBox(_T("Reconnection attempt failed!"));
473 if(mt
.majortype
!= GUID_NULL
)
474 hr
= m_pGB
->ConnectDirect(t
->m_pPin
, pPinTo
, &mt
);
482 void CConvertDlg::ShowResourceFolderPopup(HTREEITEM hTI
, CPoint p
)
484 CTreeItemResourceFolder
* t
= dynamic_cast<CTreeItemResourceFolder
*>((CTreeItem
*)m_tree
.GetItemData(hTI
));
491 m
.AppendMenu(MF_STRING
, i
++, ResStr(IDS_CONVERT_ADDRESOURCE
));
492 if(m_tree
.ItemHasChildren(*t
))
494 m
.AppendMenu(MF_SEPARATOR
);
495 m
.AppendMenu(MF_STRING
, i
++, ResStr(IDS_CONVERT_REMOVEALL
));
498 switch((int)m
.TrackPopupMenu(TPM_LEFTBUTTON
|TPM_RETURNCMD
, p
.x
, p
.y
, this))
502 CFileDialog
fd(TRUE
, NULL
, NULL
,
503 OFN_EXPLORER
|OFN_ENABLESIZING
|OFN_HIDEREADONLY
,
504 _T("All files|*.*||"), this, 0);
505 if(fd
.DoModal() == IDOK
)
507 CString fn
= fd
.GetPathName();
508 if(FILE* f
= _tfopen(fn
, _T("rb")))
514 res
.name
= (LPCTSTR
)path
;
518 ULONG len
= countof(mime
);
519 if(ERROR_SUCCESS
== key
.Open(HKEY_CLASSES_ROOT
, path
.GetExtension().MakeLower(), KEY_READ
)
520 && ERROR_SUCCESS
== key
.QueryStringValue(_T("Content Type"), mime
, &len
))
523 CTreeItemResource
* t
= new CTreeItemResource(res
, m_tree
, hTI
);
529 long size
= ftell(f
);
531 t
->m_res
.data
.SetCount(size
);
532 for(BYTE
* ptr
= t
->m_res
.data
.GetData(),* end
= ptr
+ size
;
533 size
> 0 && end
- ptr
>= size
&& fread(ptr
, min(size
, 1024), 1, f
) > 0;
534 ptr
+= 1024, size
-= 1024);
544 AfxMessageBox(_T("Cannot open file!"));
555 void CConvertDlg::ShowResourcePopup(HTREEITEM hTI
, CPoint p
)
557 CTreeItemResource
* t
= dynamic_cast<CTreeItemResource
*>((CTreeItem
*)m_tree
.GetItemData(hTI
));
564 m
.AppendMenu(MF_STRING
, i
++, ResStr(IDS_CONVERT_REMOVE
));
565 m
.AppendMenu(MF_STRING
, i
++, ResStr(IDS_CONVERT_SAVEAS
));
566 if(AfxGetAppSettings().fEnableWebServer
) m
.AppendMenu(MF_STRING
, 1000, ResStr(IDS_CONVERT_LAUNCHINBROWSER
));
567 m
.AppendMenu(MF_SEPARATOR
);
568 m
.AppendMenu(MF_STRING
, i
++, ResStr(IDS_CONVERT_RESOURCEPROPERTIES
));
570 switch((int)m
.TrackPopupMenu(TPM_LEFTBUTTON
|TPM_RETURNCMD
, p
.x
, p
.y
, this))
577 CFileDialog
fd(FALSE
, NULL
, CString(t
->m_res
.name
),
578 OFN_EXPLORER
|OFN_ENABLESIZING
|OFN_HIDEREADONLY
|OFN_OVERWRITEPROMPT
,
579 _T("All files|*.*||"), this, 0);
580 if(fd
.DoModal() == IDOK
)
582 if(FILE* f
= _tfopen(fd
.GetPathName(), _T("wb")))
584 fwrite(t
->m_res
.data
.GetData(), 1, t
->m_res
.data
.GetCount(), f
);
596 url
.Format(_T("http://localhost:%d/convres.html?id=%x"), AfxGetAppSettings().nWebServerPort
, (DWORD
)&t
->m_res
);
597 ShellExecute(NULL
, _T("open"), url
, NULL
, NULL
, SW_SHOWDEFAULT
);
603 bool CConvertDlg::EditProperties(IDSMPropertyBag
* pPB
)
605 CConvertPropsDlg
dlg(!!CComQIPtr
<IPin
>(pPB
), this);
608 if(FAILED(pPB
->CountProperties(&props
)))
611 for(ULONG i
= 0; i
< props
; i
++)
614 memset(&PropBag
, 0, sizeof(PropBag
));
615 ULONG cPropertiesReturned
= 0;
616 if(FAILED(pPB
->GetPropertyInfo(i
, 1, &PropBag
, &cPropertiesReturned
)))
621 if(SUCCEEDED(pPB
->Read(1, &PropBag
, NULL
, &var
, &hr
)) && SUCCEEDED(hr
))
622 dlg
.m_props
[CString(PropBag
.pstrName
)] = CString(var
);
624 CoTaskMemFree(PropBag
.pstrName
);
627 if(IDOK
!= dlg
.DoModal())
630 pPB
->DelAllProperties();
632 POSITION pos
= dlg
.m_props
.GetStartPosition();
636 dlg
.m_props
.GetNextAssoc(pos
, key
, value
);
637 pPB
->SetProperty(CStringW(key
), CStringW(value
));
643 bool CConvertDlg::EditResource(CTreeItemResource
* t
)
645 CConvertResDlg
dlg(this);
647 dlg
.m_name
= t
->m_res
.name
;
648 dlg
.m_mime
= t
->m_res
.mime
;
649 dlg
.m_desc
= t
->m_res
.desc
;
651 if(IDOK
!= dlg
.DoModal())
654 t
->m_res
.name
= dlg
.m_name
;
655 t
->m_res
.mime
= dlg
.m_mime
;
656 t
->m_res
.desc
= dlg
.m_desc
;
663 void CConvertDlg::ShowChapterFolderPopup(HTREEITEM hTI
, CPoint p
)
665 CTreeItemChapterFolder
* t
= dynamic_cast<CTreeItemChapterFolder
*>((CTreeItem
*)m_tree
.GetItemData(hTI
));
672 m
.AppendMenu(MF_STRING
, i
++, ResStr(IDS_CONVERT_ADDCHAPTER
));
673 if(m_tree
.ItemHasChildren(*t
))
675 m
.AppendMenu(MF_SEPARATOR
);
676 m
.AppendMenu(MF_STRING
, i
++, ResStr(IDS_CONVERT_REMOVEALL
));
679 switch((int)m
.TrackPopupMenu(TPM_LEFTBUTTON
|TPM_RETURNCMD
, p
.x
, p
.y
, this))
684 CTreeItemChapter
* t
= new CTreeItemChapter(CDSMChapter(0, L
""), m_tree
, hTI
);
696 void CConvertDlg::ShowChapterPopup(HTREEITEM hTI
, CPoint p
)
698 CTreeItemChapter
* t
= dynamic_cast<CTreeItemChapter
*>((CTreeItem
*)m_tree
.GetItemData(hTI
));
705 m
.AppendMenu(MF_STRING
, i
++, ResStr(IDS_CONVERT_REMOVE
));
706 m
.AppendMenu(MF_SEPARATOR
);
707 m
.AppendMenu(MF_STRING
, i
++, ResStr(IDS_CONVERT_CHAPTERPROPERTIES
));
709 switch((int)m
.TrackPopupMenu(TPM_LEFTBUTTON
|TPM_RETURNCMD
, p
.x
, p
.y
, this))
720 bool CConvertDlg::EditChapter(CTreeItemChapter
* t
)
722 CConvertChapDlg
dlg(this);
724 int h
= (int)(t
->m_chap
.rt
/10000000/60/60);
725 int m
= (int)(t
->m_chap
.rt
/10000000/60%60);
726 int s
= (int)(t
->m_chap
.rt
/10000000%60);
727 int ms
= (int)(t
->m_chap
.rt
/10000%1000);
729 dlg
.m_name
= t
->m_chap
.name
;
730 dlg
.m_time
.Format(_T("%02d:%02d:%02d.%03d"), h
, m
, s
, ms
);
732 if(IDOK
!= dlg
.DoModal())
736 if(_stscanf(dlg
.m_time
, _T("%d%c%d%c%d%c%d"), &h
, &c
, &m
, &c
, &s
, &c
, &ms
) != 7)
739 t
->m_chap
.name
= dlg
.m_name
;
740 t
->m_chap
.rt
= ((((__int64
)h
*60+m
)*60+s
)*1000+ms
)*10000;
747 void CConvertDlg::DoDataExchange(CDataExchange
* pDX
)
749 __super::DoDataExchange(pDX
);
750 DDX_Control(pDX
, IDC_TREE1
, m_tree
);
751 DDX_Text(pDX
, IDC_EDIT1
, m_fn
);
754 BOOL
CConvertDlg::PreTranslateMessage(MSG
* pMsg
)
756 if(pMsg
->message
== WM_KEYDOWN
&& pMsg
->wParam
== VK_ESCAPE
)
759 return __super::PreTranslateMessage(pMsg
);
762 BOOL
CConvertDlg::OnInitDialog()
764 __super::OnInitDialog();
766 SetIcon(AfxGetApp()->LoadIcon(IDR_MAINFRAME
), TRUE
);
767 SetIcon(AfxGetApp()->LoadIcon(IDR_MAINFRAME
), FALSE
);
769 AddAnchor(IDC_TREE1
, TOP_LEFT
, BOTTOM_RIGHT
);
770 AddAnchor(IDC_EDIT1
, BOTTOM_LEFT
, BOTTOM_RIGHT
);
771 AddAnchor(IDC_BUTTON1
, BOTTOM_RIGHT
);
772 AddAnchor(IDC_HLINE
, BOTTOM_LEFT
, BOTTOM_RIGHT
);
773 AddAnchor(IDC_BUTTON2
, BOTTOM_CENTER
);
774 AddAnchor(IDC_BUTTON3
, BOTTOM_CENTER
);
775 AddAnchor(IDC_BUTTON4
, BOTTOM_CENTER
);
780 m_streamtypesbm
.LoadBitmap(IDB_STREAMTYPES
);
781 m_streamtypes
.Create(16, 18, ILC_MASK
|ILC_COLOR32
, 0, 4);
782 m_streamtypes
.Add(&m_streamtypesbm
, 0xffffff);
783 m_tree
.SetImageList(&m_streamtypes
, TVSIL_NORMAL
);
785 GetWindowText(m_title
);
786 m_nIDEventStatus
= SetTimer(1, 1000, NULL
);
789 m_pMux
= new CDSMMuxerFilter(NULL
, &hr
, false, false);
791 m_pGB
= new CFGManagerMuxer(_T("CFGManagerMuxer"), NULL
);
794 if(FAILED(m_pGB
->AddFilter(m_pMux
, L
"Mux"))
795 || !(m_pMC
= m_pGB
) || !(m_pME
= m_pGB
) || !(m_pMS
= m_pMux
)
796 || FAILED(m_pME
->SetNotifyWindow((OAHWND
)m_hWnd
, WM_GRAPHNOTIFY
, 0)))
799 SendMessage(WM_CLOSE
);
803 return TRUE
; // return TRUE unless you set the focus to a control
804 // EXCEPTION: OCX Property Pages should return FALSE
807 void CConvertDlg::OnOK()
811 BEGIN_MESSAGE_MAP(CConvertDlg
, CResizableDialog
)
812 ON_MESSAGE(WM_GRAPHNOTIFY
, OnGraphNotify
)
815 ON_NOTIFY(NM_CLICK
, IDC_TREE1
, OnNMClickTree1
)
816 ON_NOTIFY(NM_RCLICK
, IDC_TREE1
, OnNMRclickTree1
)
817 ON_NOTIFY(NM_DBLCLK
, IDC_TREE1
, OnNMDblclkTree1
)
818 ON_BN_CLICKED(IDC_BUTTON1
, OnBnClickedButton1
)
819 ON_UPDATE_COMMAND_UI(IDC_BUTTON1
, OnUpdateButton1
)
821 ON_BN_CLICKED(IDC_BUTTON2
, OnBnClickedButton2
)
822 ON_UPDATE_COMMAND_UI(IDC_BUTTON2
, OnUpdateButton2
)
823 ON_BN_CLICKED(IDC_BUTTON3
, OnBnClickedButton3
)
824 ON_UPDATE_COMMAND_UI(IDC_BUTTON3
, OnUpdateButton3
)
825 ON_BN_CLICKED(IDC_BUTTON4
, OnBnClickedButton4
)
826 ON_UPDATE_COMMAND_UI(IDC_BUTTON4
, OnUpdateButton4
)
829 // CConvertDlg message handlers
831 LRESULT
CConvertDlg::OnGraphNotify(WPARAM wParam
, LPARAM lParam
)
835 LONG evCode
, evParam1
, evParam2
;
836 while(m_pME
&& SUCCEEDED(m_pME
->GetEvent(&evCode
, (LONG_PTR
*)&evParam1
, (LONG_PTR
*)&evParam2
, 0)))
838 hr
= m_pME
->FreeEventParams(evCode
, evParam1
, evParam2
);
842 if(EC_COMPLETE
== evCode
)
846 else if(EC_ERRORABORT
== evCode
)
852 if(FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER
|FORMAT_MESSAGE_FROM_SYSTEM
|FORMAT_MESSAGE_IGNORE_INSERTS
,
853 NULL
, hr
, MAKELANGID(LANG_NEUTRAL
, SUBLANG_DEFAULT
), (LPTSTR
)&lpMsgBuf
, 0, NULL
))
855 errmsg
= (LPCTSTR
)lpMsgBuf
;
860 str
.Format(_T("Could not complete conversion, the output file is most likely unusable.\n\nError code: 0x%08x"), evParam1
);
861 if(!errmsg
.IsEmpty()) str
+= _T(" (") + errmsg
+ _T(")");
862 AfxMessageBox(str
, MB_OK
);
868 m_tree
.EnableWindow(TRUE
);
875 void CConvertDlg::OnDropFiles(HDROP hDropInfo
)
877 for(int i
= 0, j
= DragQueryFile(hDropInfo
, 0xffffffff, 0, 0); i
< j
; i
++)
880 fn
.ReleaseBufferSetLength(DragQueryFile(hDropInfo
, i
, fn
.GetBuffer(MAX_PATH
), MAX_PATH
));
885 __super::OnDropFiles(hDropInfo
);
888 void CConvertDlg::OnClose()
890 HTREEITEM hTI
= m_tree
.GetRootItem();
893 HTREEITEM hTINext
= m_tree
.GetNextSiblingItem(hTI
);
898 m_pGB
->RemoveFromROT();
904 void CConvertDlg::OnNMClickTree1(NMHDR
* pNMHDR
, LRESULT
* pResult
)
907 HTREEITEM hTI
= HitTest(sp
, cp
);
909 m_tree
.SelectItem(hTI
);
914 void CConvertDlg::OnNMRclickTree1(NMHDR
* pNMHDR
, LRESULT
* pResult
)
917 HTREEITEM hTI
= HitTest(sp
, cp
);
921 m_tree
.SelectItem(hTI
);
923 CTreeItem
* t
= (CTreeItem
*)m_tree
.GetItemData(hTI
);
925 if(dynamic_cast<CTreeItemPin
*>(t
))
926 ShowPinPopup(hTI
, sp
);
927 else if(dynamic_cast<CTreeItemFile
*>(t
))
928 ShowFilePopup(hTI
, sp
);
929 else if(dynamic_cast<CTreeItemResourceFolder
*>(t
))
930 ShowResourceFolderPopup(hTI
, sp
);
931 else if(dynamic_cast<CTreeItemResource
*>(t
))
932 ShowResourcePopup(hTI
, sp
);
933 else if(dynamic_cast<CTreeItemChapterFolder
*>(t
))
934 ShowChapterFolderPopup(hTI
, sp
);
935 else if(dynamic_cast<CTreeItemChapter
*>(t
))
936 ShowChapterPopup(hTI
, sp
);
946 void CConvertDlg::OnNMDblclkTree1(NMHDR
*pNMHDR
, LRESULT
*pResult
)
949 HTREEITEM hTI
= HitTest(sp
, cp
);
953 CTreeItem
* t
= (CTreeItem
*)m_tree
.GetItemData(hTI
);
955 if(CTreeItemPin
* t2
= dynamic_cast<CTreeItemPin
*>(t
))
957 CComPtr
<IPin
> pPinTo
;
958 t2
->m_pPin
->ConnectedTo(&pPinTo
);
960 if(CComQIPtr
<IDSMPropertyBag
> pPB
= pPinTo
)
963 else if(CTreeItemResource
* t2
= dynamic_cast<CTreeItemResource
*>(t
))
967 else if(CTreeItemChapter
* t2
= dynamic_cast<CTreeItemChapter
*>(t
))
976 void CConvertDlg::OnBnClickedButton1()
980 CFileDialog
fd(FALSE
, _T(".dsm"), m_fn
,
981 OFN_EXPLORER
|OFN_ENABLESIZING
|OFN_HIDEREADONLY
|OFN_OVERWRITEPROMPT
,
982 _T("DirectShow Media file|*.dsm|All files|*.*|"), this, 0);
984 if(fd
.DoModal() == IDOK
)
986 m_fn
= fd
.GetPathName();
991 void CConvertDlg::OnUpdateButton1(CCmdUI
* pCmdUI
)
994 pCmdUI
->Enable(m_pMC
&& SUCCEEDED(m_pMC
->GetState(0, &fs
)) && fs
== State_Stopped
);
997 void CConvertDlg::OnTimer(UINT nIDEvent
)
999 if(nIDEvent
== m_nIDEventStatus
&& m_pMS
&& m_pMC
)
1002 if(SUCCEEDED(m_pMC
->GetState(0, &fs
)) && fs
!= State_Stopped
)
1005 m_pMS
->GetTimeFormat(&tf
);
1007 REFERENCE_TIME rtCur
, rtDur
;
1008 HRESULT hr
= m_pMS
->GetDuration(&rtDur
);
1009 m_pMS
->GetCurrentPosition(&rtCur
);
1012 if(hr
== S_OK
&& rtDur
!= 0) str
.Format(_T("%.2f%%"), 1.0 * (rtCur
* 100) / rtDur
);
1013 else if(hr
== S_OK
&& rtDur
== 0) str
= _T("Live");
1014 else if(tf
== TIME_FORMAT_BYTE
) str
.Format(_T("%.2fKB"), 1.0 * rtCur
/ 1024);
1015 else if(tf
== TIME_FORMAT_MEDIA_TIME
) str
.Format(_T("%02d:%02d:%02d"), int(rtCur
/3600000000)%60, int(rtCur
/60000000)%60, int(rtCur
/1000000)%60);
1016 else str
= _T("Please Wait");
1018 SetWindowText(_T("Converting - ") + str
);
1022 SetWindowText(m_title
);
1026 __super::OnTimer(nIDEvent
);
1029 void CConvertDlg::OnBnClickedButton2()
1032 if(FAILED(m_pMC
->GetState(0, &fs
)))
1035 if(fs
!= State_Stopped
)
1043 if(!ConvertFile(m_fn
))
1045 AfxMessageBox(_T("Failed to start conversion"));
1049 void CConvertDlg::OnUpdateButton2(CCmdUI
* pCmdUI
)
1051 int nIn
, nOut
, nInC
, nOutC
;
1052 CountPins(m_pMux
, nIn
, nOut
, nInC
, nOutC
);
1055 pCmdUI
->Enable(nInC
> 0 && GetDlgItem(IDC_EDIT1
)->GetWindowTextLength() > 0
1056 && m_pMS
&& m_pMC
&& SUCCEEDED(m_pMC
->GetState(0, &fs
)) && fs
!= State_Running
);
1059 void CConvertDlg::OnBnClickedButton3()
1061 if(m_pMC
) m_pMC
->Pause();
1064 void CConvertDlg::OnUpdateButton3(CCmdUI
* pCmdUI
)
1067 pCmdUI
->Enable(m_pMC
&& SUCCEEDED(m_pMC
->GetState(0, &fs
)) && fs
== State_Running
);
1070 void CConvertDlg::OnBnClickedButton4()
1072 if(m_pMC
) m_pMC
->Stop();
1073 m_tree
.EnableWindow(TRUE
);
1076 void CConvertDlg::OnUpdateButton4(CCmdUI
* pCmdUI
)
1079 pCmdUI
->Enable(m_pMC
&& SUCCEEDED(m_pMC
->GetState(0, &fs
)) && fs
!= State_Stopped
);
1086 CFilterTreeCtrl::CFilterTreeCtrl()
1090 void CFilterTreeCtrl::PreSubclassWindow()
1092 EnableToolTips(TRUE
);
1094 __super::PreSubclassWindow();
1097 INT_PTR
CFilterTreeCtrl::OnToolHitTest(CPoint p
, TOOLINFO
* pTI
) const
1100 HTREEITEM hTI
= HitTest(p
, &nFlags
);
1101 if(nFlags
& TVHT_ONITEM
)
1104 GetItemRect(hTI
, r
, TRUE
);
1106 pTI
->uId
= (UINT
)hTI
;
1107 pTI
->lpszText
= LPSTR_TEXTCALLBACK
;
1115 BEGIN_MESSAGE_MAP(CFilterTreeCtrl
, CTreeCtrl
)
1116 ON_NOTIFY_EX_RANGE(TTN_NEEDTEXTW
, 0, 0xFFFF, OnToolTipText
)
1117 ON_NOTIFY_EX_RANGE(TTN_NEEDTEXTA
, 0, 0xFFFF, OnToolTipText
)
1120 BOOL
CFilterTreeCtrl::OnToolTipText(UINT id
, NMHDR
* pNMHDR
, LRESULT
* pResult
)
1122 TOOLTIPTEXTA
* pTTTA
= (TOOLTIPTEXTA
*)pNMHDR
;
1123 TOOLTIPTEXTW
* pTTTW
= (TOOLTIPTEXTW
*)pNMHDR
;
1125 UINT nID
= pNMHDR
->idFrom
;
1127 if(nID
== (UINT
)m_hWnd
1128 && (pNMHDR
->code
== TTN_NEEDTEXTA
&& (pTTTA
->uFlags
& TTF_IDISHWND
)
1129 || pNMHDR
->code
== TTN_NEEDTEXTW
&& (pTTTW
->uFlags
& TTF_IDISHWND
)))
1132 ::SendMessage(pNMHDR
->hwndFrom
, TTM_SETMAXTIPWIDTH
, 0, (LPARAM
)(INT
)1000);
1134 HTREEITEM hTI
= (HTREEITEM
)nID
;
1137 static CStringA m_strTipTextA
;
1138 static CStringW m_strTipTextW
;
1140 CConvertDlg::CTreeItem
* t
= (CConvertDlg::CTreeItem
*)GetItemData(hTI
);
1141 if(!t
|| !t
->ToolTip(str
)) return FALSE
;
1143 m_strTipTextA
= str
;
1144 m_strTipTextW
= str
;
1146 if(pNMHDR
->code
== TTN_NEEDTEXTA
) pTTTA
->lpszText
= (LPSTR
)(LPCSTR
)m_strTipTextA
;
1147 else pTTTW
->lpszText
= (LPWSTR
)(LPCWSTR
)m_strTipTextW
;
1151 return TRUE
; // message was handled
1155 // CConvertDlg::CTreeItem*
1158 CConvertDlg::CTreeItem::CTreeItem(CTreeCtrl
& tree
, HTREEITEM hTIParent
)
1161 m_hTI
= m_tree
.InsertItem(_T(""), hTIParent
);
1162 m_tree
.SetItemData(m_hTI
, (DWORD_PTR
)this);
1166 CConvertDlg::CTreeItem::~CTreeItem()
1170 void CConvertDlg::CTreeItem::SetLabel(LPCTSTR label
)
1172 m_tree
.SetItemText(m_hTI
, label
);
1175 void CConvertDlg::CTreeItem::SetImage(int nImage
, int nSelectedImage
)
1177 m_tree
.SetItemImage(m_hTI
, nImage
, nSelectedImage
);
1182 CConvertDlg::CTreeItemFilter::CTreeItemFilter(IBaseFilter
* pBF
, CTreeCtrl
& tree
, HTREEITEM hTIParent
)
1183 : CTreeItem(tree
, hTIParent
)
1189 void CConvertDlg::CTreeItemFilter::Update()
1191 SetLabel(CString(GetFilterName(m_pBF
)));
1196 CConvertDlg::CTreeItemFile::CTreeItemFile(CString fn
, IBaseFilter
* pBF
, CTreeCtrl
& tree
, HTREEITEM hTIParent
)
1197 : CTreeItemFilter(pBF
, tree
, hTIParent
)
1203 void CConvertDlg::CTreeItemFile::Update()
1210 bool CConvertDlg::CTreeItemFile::ToolTip(CString
& str
)
1218 CConvertDlg::CTreeItemPin::CTreeItemPin(IPin
* pPin
, CTreeCtrl
& tree
, HTREEITEM hTIParent
)
1219 : CTreeItem(tree
, hTIParent
)
1225 void CConvertDlg::CTreeItemPin::Update()
1227 if(!m_pPin
) {ASSERT(0); return;}
1229 CString label
= GetPinName(m_pPin
);
1230 if(!IsConnected()) label
= _T("[D] ") + label
;
1234 if(S_OK
== m_pPin
->ConnectionMediaType(&mt
))
1236 if(mt
.majortype
== MEDIATYPE_Video
) SetImage(1, 1);
1237 else if(mt
.majortype
== MEDIATYPE_Audio
) SetImage(2, 2);
1238 else if(mt
.majortype
== MEDIATYPE_Text
|| mt
.majortype
== MEDIATYPE_Subtitle
) SetImage(3, 3);
1242 bool CConvertDlg::CTreeItemPin::ToolTip(CString
& str
)
1245 if(FAILED(m_pPin
->ConnectionMediaType(&mt
))) return false;
1246 str
= mt
.ToString(m_pPin
);
1250 bool CConvertDlg::CTreeItemPin::IsConnected()
1252 CComPtr
<IPin
> pPinTo
;
1253 return m_pPin
&& SUCCEEDED(m_pPin
->ConnectedTo(&pPinTo
)) && pPinTo
;
1258 CConvertDlg::CTreeItemResourceFolder::CTreeItemResourceFolder(CTreeCtrl
& tree
, HTREEITEM hTIParent
)
1259 : CTreeItem(tree
, hTIParent
)
1264 void CConvertDlg::CTreeItemResourceFolder::Update()
1266 SetLabel(_T("Resources"));
1269 bool CConvertDlg::CTreeItemResourceFolder::ToolTip(CString
& str
)
1271 if(!m_tree
.ItemHasChildren(m_hTI
))
1277 HTREEITEM hChildItem
= m_tree
.GetChildItem(m_hTI
);
1279 while(hChildItem
!= NULL
)
1281 HTREEITEM hNextItem
= m_tree
.GetNextItem(hChildItem
, TVGN_NEXT
);
1282 if(CTreeItemResource
* t
= dynamic_cast<CTreeItemResource
*>((CTreeItem
*)m_tree
.GetItemData(hChildItem
)))
1283 size
+= t
->m_res
.data
.GetCount(), files
++;
1284 hChildItem
= hNextItem
;
1288 if(size
< 1024) str
.Format(_T("%d file(s), %.2f KB"), files
, size
);
1289 else str
.Format(_T("%d file(s), %.2f MB"), files
, size
/1024);
1296 CConvertDlg::CTreeItemResource::CTreeItemResource(const CDSMResource
& res
, CTreeCtrl
& tree
, HTREEITEM hTIParent
)
1297 : CTreeItem(tree
, hTIParent
)
1303 CConvertDlg::CTreeItemResource::~CTreeItemResource()
1307 void CConvertDlg::CTreeItemResource::Update()
1309 SetLabel(CString(m_res
.name
));
1311 CStringW mime
= m_res
.mime
;
1314 if(mime
== L
"application/x-truetype-font") SetImage(4, 4);
1315 else if(mime
.Find(L
"text/") == 0) SetImage(5, 5);
1316 else SetImage(6, 6);
1319 bool CConvertDlg::CTreeItemResource::ToolTip(CString
& str
)
1321 if(!m_res
.mime
.IsEmpty()) str
= CString(m_res
.mime
) + _T("\r\n\r\n");
1322 if(!m_res
.desc
.IsEmpty()) str
+= CString(m_res
.desc
);
1329 CConvertDlg::CTreeItemChapterFolder::CTreeItemChapterFolder(CTreeCtrl
& tree
, HTREEITEM hTIParent
)
1330 : CTreeItem(tree
, hTIParent
)
1335 void CConvertDlg::CTreeItemChapterFolder::Update()
1337 SetLabel(_T("Chapters"));
1342 CConvertDlg::CTreeItemChapter::CTreeItemChapter(const CDSMChapter
& chap
, CTreeCtrl
& tree
, HTREEITEM hTIParent
)
1343 : CTreeItem(tree
, hTIParent
)
1349 void CConvertDlg::CTreeItemChapter::Update()
1351 REFERENCE_TIME rt
= m_chap
.rt
;
1353 int ms
= (int)(rt
%1000);
1355 int s
= (int)(rt
%60);
1357 int m
= (int)(rt
%60);
1362 label
.Format(_T("%02d:%02d:%02d.%03d - %s"), h
, m
, s
, ms
, CString(m_chap
.name
));