--- trunk/xvidcore/dshow/src/CXvidDecoder.cpp 2004/04/01 11:11:28 1397 +++ trunk/xvidcore/dshow/src/CXvidDecoder.cpp 2010/10/16 12:20:30 1896 @@ -1,9 +1,10 @@ /***************************************************************************** * * XVID MPEG-4 VIDEO CODEC - * - XviD Decoder part of the DShow Filter - + * - Xvid Decoder part of the DShow Filter - * - * Copyright(C) 2002-2004 Peter Ross + * Copyright(C) 2002-2010 Peter Ross + * 2003-2010 Michael Militzer * * This program is free software ; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -19,7 +20,7 @@ * along with this program ; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * - * $Id: CXvidDecoder.cpp,v 1.3 2004-04-01 11:11:28 suxen_drol Exp $ + * $Id: CXvidDecoder.cpp,v 1.19 2010-10-16 12:20:30 Isibaar Exp $ * ****************************************************************************/ @@ -36,14 +37,14 @@ place these paths at the top of the Tools|Options|Directories list headers: - C:\DXVCSDK\include - C:\DXVCSDK\samples\Multimedia\DirectShow\BaseClasses + C:\DX90SDK\Include + C:\DX90SDK\Samples\C++\DirectShow\BaseClasses - libraries (optional): - C:\DXVCSDK\samples\Multimedia\DirectShow\BaseClasses\Release + C:\DX90SDK\Samples\C++\DirectShow\BaseClasses\Release + C:\DX90SDK\Samples\C++\DirectShow\BaseClasses\Debug */ - +//#define XVID_USE_TRAYICON #include @@ -55,7 +56,11 @@ #endif #include // VIDEOINFOHEADER2 -#include // XviD API +#include + +#include // Xvid API + +#include "resource.h" #include "IXvidDecoder.h" #include "CXvidDecoder.h" @@ -82,6 +87,7 @@ { &MEDIATYPE_Video, &CLSID_DX50 }, { &MEDIATYPE_Video, &CLSID_DX50_UC }, { &MEDIATYPE_Video, &CLSID_MP4V }, + { &MEDIATYPE_Video, &CLSID_MP4V_UC }, }; const AMOVIESETUP_MEDIATYPE sudOutputPinTypes[] = @@ -148,10 +154,41 @@ }; - /* note: g_cTemplates must be global; used by strmbase.lib(dllentry.cpp,dllsetup.cpp) */ int g_cTemplates = sizeof(g_Templates) / sizeof(CFactoryTemplate); +#ifdef XVID_USE_TRAYICON +extern HINSTANCE g_xvid_hInst; + +static int GUI_Page = 0; +extern "C" void CALLBACK Configure(HWND hWndParent, HINSTANCE hInstParent, LPSTR lpCmdLine, int nCmdShow ); + +LRESULT CALLBACK msg_proc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + switch ( uMsg ) + { + case WM_ICONMESSAGE: + switch(lParam) + { + case WM_LBUTTONDBLCLK: + if (!GUI_Page) { + GUI_Page = 1; + Configure(hwnd, g_xvid_hInst, "", 1); + GUI_Page = 0; + } + break; + default: + return DefWindowProc(hwnd, uMsg, wParam, lParam); + }; + break; + + default: + return DefWindowProc(hwnd, uMsg, wParam, lParam); + } + + return TRUE; /* ok */ +} +#endif STDAPI DllRegisterServer() { @@ -204,39 +241,65 @@ #define XVID_DLL_NAME "xvidcore.dll" CXvidDecoder::CXvidDecoder(LPUNKNOWN punk, HRESULT *phr) : - CVideoTransformFilter(NAME("CXvidDecoder"), punk, CLSID_XVID) + CVideoTransformFilter(NAME("CXvidDecoder"), punk, CLSID_XVID), m_hdll (NULL) { DPRINTF("Constructor"); + xvid_decore_func = NULL; // Hmm, some strange errors appearing if I try to initialize... + xvid_global_func = NULL; // ...this in constructor's init-list. So, they assigned here. + +#ifdef XVID_USE_TRAYICON + MSG_hwnd = NULL; +#endif + + LoadRegistryInfo(); + + *phr = OpenLib(); +} + +HRESULT CXvidDecoder::OpenLib() +{ + DPRINTF("OpenLib"); + + if (m_hdll != NULL) + return E_UNEXPECTED; // Seems, that library already opened. + xvid_gbl_init_t init; memset(&init, 0, sizeof(init)); init.version = XVID_VERSION; - ar_x = ar_y = 0; - m_hdll = LoadLibrary(XVID_DLL_NAME); if (m_hdll == NULL) { DPRINTF("dll load failed"); - MessageBox(0, XVID_DLL_NAME " not found","Error", 0); - return; + MessageBox(0, XVID_DLL_NAME " not found","Error", MB_TOPMOST); + return E_FAIL; } xvid_global_func = (int (__cdecl *)(void *, int, void *, void *))GetProcAddress(m_hdll, "xvid_global"); if (xvid_global_func == NULL) { - MessageBox(0, "xvid_global() not found", "Error", 0); - return; + FreeLibrary(m_hdll); + m_hdll = NULL; + MessageBox(0, "xvid_global() not found", "Error", MB_TOPMOST); + return E_FAIL; } xvid_decore_func = (int (__cdecl *)(void *, int, void *, void *))GetProcAddress(m_hdll, "xvid_decore"); if (xvid_decore_func == NULL) { - MessageBox(0, "xvid_decore() not found", "Error", 0); - return; + xvid_global_func = NULL; + FreeLibrary(m_hdll); + m_hdll = NULL; + MessageBox(0, "xvid_decore() not found", "Error", MB_TOPMOST); + return E_FAIL; } if (xvid_global_func(0, XVID_GBL_INIT, &init, NULL) < 0) { - MessageBox(0, "xvid_global() failed", "Error", 0); - return; + xvid_global_func = NULL; + xvid_decore_func = NULL; + FreeLibrary(m_hdll); + m_hdll = NULL; + MessageBox(0, "xvid_global() failed", "Error", MB_TOPMOST); + return E_FAIL; } memset(&m_create, 0, sizeof(m_create)); @@ -246,8 +309,6 @@ memset(&m_frame, 0, sizeof(m_frame)); m_frame.version = XVID_VERSION; - LoadRegistryInfo(); - USE_IYUV = false; USE_YV12 = false; USE_YUY2 = false; @@ -285,27 +346,67 @@ USE_RGB32 = true; break; } -} - - -/* destructor */ + switch (g_config.aspect_ratio) + { + case 0: + case 1: + break; + case 2: + ar_x = 4; + ar_y = 3; + break; + case 3: + ar_x = 16; + ar_y = 9; + break; + case 4: + ar_x = 47; + ar_y = 20; + break; + } + + return S_OK; +} -CXvidDecoder::~CXvidDecoder() +void CXvidDecoder::CloseLib() { - DPRINTF("Destructor"); + DPRINTF("CloseLib"); - if (m_create.handle != NULL) + if ((m_create.handle != NULL) && (xvid_decore_func != NULL)) { xvid_decore_func(m_create.handle, XVID_DEC_DESTROY, 0, 0); m_create.handle = NULL; } - if (m_hdll != NULL) - { + if (m_hdll != NULL) { FreeLibrary(m_hdll); m_hdll = NULL; } + xvid_decore_func = NULL; + xvid_global_func = NULL; +} + +/* destructor */ + +CXvidDecoder::~CXvidDecoder() +{ + DPRINTF("Destructor"); + CloseLib(); + +#ifdef XVID_USE_TRAYICON + if (MSG_hwnd != NULL) { + NOTIFYICONDATA nid; + nid.cbSize = sizeof(NOTIFYICONDATA); + nid.hWnd = MSG_hwnd; + nid.uID = 100; + + Shell_NotifyIcon(NIM_DELETE, &nid); + + DestroyWindow(MSG_hwnd); + MSG_hwnd = NULL; + } +#endif } @@ -316,35 +417,86 @@ { DPRINTF("CheckInputType"); BITMAPINFOHEADER * hdr; + + ar_x = ar_y = 0; if (*mtIn->Type() != MEDIATYPE_Video) { DPRINTF("Error: Unknown Type"); + CloseLib(); return VFW_E_TYPE_NOT_ACCEPTED; } + if (m_hdll == NULL) + { + HRESULT hr = OpenLib(); + + if (FAILED(hr) || (m_hdll == NULL)) // Paranoid checks. + return VFW_E_TYPE_NOT_ACCEPTED; + } + if (*mtIn->FormatType() == FORMAT_VideoInfo) { VIDEOINFOHEADER * vih = (VIDEOINFOHEADER *) mtIn->Format(); hdr = &vih->bmiHeader; - /* PAR (x:y) is (1/ppm_X):(1/ppm_Y) where ppm is pixels-per-meter - which is equal to ppm_Y:ppm_X */ - ar_x = vih->bmiHeader.biYPelsPerMeter * abs(hdr->biWidth); - ar_y = vih->bmiHeader.biXPelsPerMeter * abs(hdr->biHeight); - DPRINTF("VIDEOINFOHEADER PAR: %d:%d -> AR %d:%d", - vih->bmiHeader.biYPelsPerMeter,vih->bmiHeader.biXPelsPerMeter, ar_x, ar_y); } else if (*mtIn->FormatType() == FORMAT_VideoInfo2) { VIDEOINFOHEADER2 * vih2 = (VIDEOINFOHEADER2 *) mtIn->Format(); hdr = &vih2->bmiHeader; - ar_x = vih2->dwPictAspectRatioX; - ar_y = vih2->dwPictAspectRatioY; + if (g_config.aspect_ratio == 0 || g_config.aspect_ratio == 1) { + ar_x = vih2->dwPictAspectRatioX; + ar_y = vih2->dwPictAspectRatioY; + } DPRINTF("VIDEOINFOHEADER2 AR: %d:%d", ar_x, ar_y); } + else if (*mtIn->FormatType() == FORMAT_MPEG2Video) { + MPEG2VIDEOINFO * mpgvi = (MPEG2VIDEOINFO*)mtIn->Format(); + VIDEOINFOHEADER2 * vih2 = &mpgvi->hdr; + hdr = &vih2->bmiHeader; + if (g_config.aspect_ratio == 0 || g_config.aspect_ratio == 1) { + ar_x = vih2->dwPictAspectRatioX; + ar_y = vih2->dwPictAspectRatioY; + } + DPRINTF("VIDEOINFOHEADER2 AR: %d:%d", ar_x, ar_y); + + /* haali media splitter reports VOL information in the format header */ + + if (mpgvi->cbSequenceHeader>0) { + + xvid_dec_stats_t stats; + memset(&stats, 0, sizeof(stats)); + stats.version = XVID_VERSION; + + if (m_create.handle == NULL) { + if (xvid_decore_func == NULL) + return E_FAIL; + if (xvid_decore_func(0, XVID_DEC_CREATE, &m_create, 0) < 0) { + DPRINTF("*** XVID_DEC_CREATE error"); + return E_FAIL; + } + } + + m_frame.general = 0; + m_frame.bitstream = (void*)mpgvi->dwSequenceHeader; + m_frame.length = mpgvi->cbSequenceHeader; + m_frame.output.csp = XVID_CSP_NULL; + + int ret = 0; + if ((ret=xvid_decore_func(m_create.handle, XVID_DEC_DECODE, &m_frame, &stats)) >= 0) { + /* honour video dimensions reported in VOL header */ + if (stats.type == XVID_TYPE_VOL) { + hdr->biWidth = stats.data.vol.width; + hdr->biHeight = stats.data.vol.height; + } + } + if (ret == XVID_ERR_MEMORY) return E_FAIL; + } + } else { DPRINTF("Error: Unknown FormatType"); + CloseLib(); return VFW_E_TYPE_NOT_ACCEPTED; } @@ -358,15 +510,24 @@ switch(hdr->biCompression) { - + case FOURCC_mp4v: case FOURCC_MP4V: - if (!(g_config.supported_4cc & SUPPORT_MP4V)) return VFW_E_TYPE_NOT_ACCEPTED; + if (!(g_config.supported_4cc & SUPPORT_MP4V)) { + CloseLib(); + return VFW_E_TYPE_NOT_ACCEPTED; + } break; case FOURCC_DIVX : - if (!(g_config.supported_4cc & SUPPORT_DIVX)) return VFW_E_TYPE_NOT_ACCEPTED; + if (!(g_config.supported_4cc & SUPPORT_DIVX)) { + CloseLib(); + return VFW_E_TYPE_NOT_ACCEPTED; + } break; case FOURCC_DX50 : - if (!(g_config.supported_4cc & SUPPORT_DX50)) return VFW_E_TYPE_NOT_ACCEPTED; + if (!(g_config.supported_4cc & SUPPORT_DX50)) { + CloseLib(); + return VFW_E_TYPE_NOT_ACCEPTED; + } case FOURCC_XVID : break; @@ -378,8 +539,12 @@ (hdr->biCompression>>8)&0xff, (hdr->biCompression>>16)&0xff, (hdr->biCompression>>24)&0xff); + CloseLib(); return VFW_E_TYPE_NOT_ACCEPTED; } + + m_create.fourcc = hdr->biCompression; + return S_OK; } @@ -408,11 +573,12 @@ if (ar_x != 0 && ar_y != 0) { vih->dwPictAspectRatioX = ar_x; vih->dwPictAspectRatioY = ar_y; + forced_ar = true; } else { // just to be safe vih->dwPictAspectRatioX = m_create.width; vih->dwPictAspectRatioY = abs(m_create.height); - } - + forced_ar = false; + } } else { VIDEOINFOHEADER * vih = (VIDEOINFOHEADER *) mtOut->ReallocFormatBuffer(sizeof(VIDEOINFOHEADER)); @@ -520,19 +686,24 @@ /* (internal function) change colorspace */ +#define CALC_BI_STRIDE(width,bitcount) ((((width * bitcount) + 31) & ~31) >> 3) HRESULT CXvidDecoder::ChangeColorspace(GUID subtype, GUID formattype, void * format) { + DWORD biWidth; + if (formattype == FORMAT_VideoInfo) { VIDEOINFOHEADER * vih = (VIDEOINFOHEADER * )format; - m_frame.output.stride[0] = (((vih->bmiHeader.biWidth * vih->bmiHeader.biBitCount) + 31) & ~31) >> 3; + biWidth = vih->bmiHeader.biWidth; + m_frame.output.stride[0] = CALC_BI_STRIDE(vih->bmiHeader.biWidth, vih->bmiHeader.biBitCount); rgb_flip = (vih->bmiHeader.biHeight < 0 ? 0 : XVID_CSP_VFLIP); } else if (formattype == FORMAT_VideoInfo2) { VIDEOINFOHEADER2 * vih2 = (VIDEOINFOHEADER2 * )format; - m_frame.output.stride[0] = (((vih2->bmiHeader.biWidth * vih2->bmiHeader.biBitCount) + 31) & ~31) >> 3; + biWidth = vih2->bmiHeader.biWidth; + m_frame.output.stride[0] = CALC_BI_STRIDE(vih2->bmiHeader.biWidth, vih2->bmiHeader.biBitCount); rgb_flip = (vih2->bmiHeader.biHeight < 0 ? 0 : XVID_CSP_VFLIP); } else @@ -545,14 +716,14 @@ DPRINTF("IYUV"); rgb_flip = 0; m_frame.output.csp = XVID_CSP_I420; - m_frame.output.stride[0] = (m_frame.output.stride[0] * 2) / 3; /* planar format fix */ + m_frame.output.stride[0] = CALC_BI_STRIDE(biWidth, 8); /* planar format fix */ } else if (subtype == MEDIASUBTYPE_YV12) { DPRINTF("YV12"); rgb_flip = 0; m_frame.output.csp = XVID_CSP_YV12; - m_frame.output.stride[0] = (m_frame.output.stride[0] * 2) / 3; /* planar format fix */ + m_frame.output.stride[0] = CALC_BI_STRIDE(biWidth, 8); /* planar format fix */ } else if (subtype == MEDIASUBTYPE_YUY2) { @@ -625,9 +796,80 @@ HRESULT CXvidDecoder::CheckTransform(const CMediaType *mtIn, const CMediaType *mtOut) { DPRINTF("CheckTransform"); + + return S_OK; +} + +/* input/output pin connection complete */ + +HRESULT CXvidDecoder::CompleteConnect(PIN_DIRECTION direction, IPin *pReceivePin) +{ + DPRINTF("CompleteConnect"); + +#ifdef XVID_USE_TRAYICON + if ((direction == PINDIR_OUTPUT) && (MSG_hwnd == NULL)) + { + WNDCLASSEX wc; + + wc.cbSize = sizeof(WNDCLASSEX); + wc.lpfnWndProc = msg_proc; + wc.style = CS_HREDRAW | CS_VREDRAW; + wc.cbWndExtra = 0; + wc.cbClsExtra = 0; + wc.hInstance = (HINSTANCE) g_xvid_hInst; + wc.hbrBackground = (HBRUSH) GetStockObject(NULL_BRUSH); + wc.lpszMenuName = NULL; + wc.lpszClassName = "XVID_MSG_WINDOW"; + wc.hIcon = NULL; + wc.hIconSm = NULL; + wc.hCursor = NULL; + RegisterClassEx(&wc); + + MSG_hwnd = CreateWindowEx(0, "XVID_MSG_WINDOW", NULL, 0, CW_USEDEFAULT, + CW_USEDEFAULT, 0, 0, HWND_MESSAGE, NULL, (HINSTANCE) g_xvid_hInst, NULL); + + /* display the tray icon */ + NOTIFYICONDATA nid; + + nid.cbSize = sizeof(NOTIFYICONDATA); + nid.hWnd = MSG_hwnd; + nid.uID = 100; + nid.uVersion = NOTIFYICON_VERSION; + nid.uCallbackMessage = WM_ICONMESSAGE; + nid.hIcon = LoadIcon(g_xvid_hInst, MAKEINTRESOURCE(IDI_ICON)); + strcpy_s(nid.szTip, 19, "Xvid Video Decoder"); + nid.uFlags = NIF_MESSAGE | NIF_ICON | NIF_TIP; + + Shell_NotifyIcon(NIM_ADD, &nid); + } +#endif + return S_OK; } +/* input/output pin disconnected */ +HRESULT CXvidDecoder::BreakConnect(PIN_DIRECTION direction) +{ + DPRINTF("BreakConnect"); + +#ifdef XVID_USE_TRAYICON + if ((direction == PINDIR_OUTPUT) && (MSG_hwnd != NULL)) { + NOTIFYICONDATA nid; + + nid.cbSize = sizeof(NOTIFYICONDATA); + nid.hWnd = MSG_hwnd; + nid.uID = 100; + nid.uVersion = NOTIFYICON_VERSION; + + if(Shell_NotifyIcon(NIM_DELETE, &nid) == TRUE) { + DestroyWindow(MSG_hwnd); + MSG_hwnd = NULL; + } + } +#endif + + return S_OK; +} /* alloc output buffer */ @@ -676,10 +918,13 @@ if (m_create.handle == NULL) { + if (xvid_decore_func == NULL) + return E_FAIL; + if (xvid_decore_func(0, XVID_DEC_CREATE, &m_create, 0) < 0) { DPRINTF("*** XVID_DEC_CREATE error"); - return S_FALSE; + return E_FAIL; } } @@ -713,17 +958,20 @@ m_frame.general = XVID_LOWDELAY; if (pIn->IsDiscontinuity() == S_OK) - m_frame.general = XVID_DISCONTINUITY; + m_frame.general |= XVID_DISCONTINUITY; if (g_config.nDeblock_Y) m_frame.general |= XVID_DEBLOCKY; if (g_config.nDeblock_UV) m_frame.general |= XVID_DEBLOCKUV; -/* - if (g_config.nDering) - m_frame.general |= XVID_DERING; -*/ + + if (g_config.nDering_Y) + m_frame.general |= XVID_DERINGY; + + if (g_config.nDering_UV) + m_frame.general |= XVID_DERINGUV; + if (g_config.nFilmEffect) m_frame.general |= XVID_FILMEFFECT; @@ -732,16 +980,48 @@ m_frame.output.csp &= ~XVID_CSP_VFLIP; m_frame.output.csp |= rgb_flip^(g_config.nFlipVideo ? XVID_CSP_VFLIP : 0); + // Paranoid check. + if (xvid_decore_func == NULL) + return E_FAIL; + + + repeat : if (pIn->IsPreroll() != S_OK) { length = xvid_decore_func(m_create.handle, XVID_DEC_DECODE, &m_frame, &stats); - - if (length < 0) + + if (length == XVID_ERR_MEMORY) + return E_FAIL; + else if (length < 0) { DPRINTF("*** XVID_DEC_DECODE"); return S_FALSE; + } else + if (g_config.aspect_ratio == 0 || g_config.aspect_ratio == 1 && forced_ar == false) { + + if (stats.type != XVID_TYPE_NOTHING) { /* dont attempt to set vmr aspect ratio if no frame was returned by decoder */ + // inspired by minolta! works for VMR 7 + 9 + IMediaSample2 *pOut2 = NULL; + AM_SAMPLE2_PROPERTIES outProp2; + if (SUCCEEDED(pOut->QueryInterface(IID_IMediaSample2, (void **)&pOut2)) && + SUCCEEDED(pOut2->GetProperties(FIELD_OFFSET(AM_SAMPLE2_PROPERTIES, tStart), (PBYTE)&outProp2))) + { + CMediaType mtOut2 = m_pOutput->CurrentMediaType(); + VIDEOINFOHEADER2* vihOut2 = (VIDEOINFOHEADER2*)mtOut2.Format(); + + if (*mtOut2.FormatType() == FORMAT_VideoInfo2 && + vihOut2->dwPictAspectRatioX != ar_x && vihOut2->dwPictAspectRatioY != ar_y) + { + vihOut2->dwPictAspectRatioX = ar_x; + vihOut2->dwPictAspectRatioY = ar_y; + pOut2->SetMediaType(&mtOut2); + m_pOutput->SetMediaType(&mtOut2); + } + pOut2->Release(); + } + } } } else @@ -754,11 +1034,13 @@ /* Disable postprocessing to speed-up seeking */ m_frame.general &= ~XVID_DEBLOCKY; m_frame.general &= ~XVID_DEBLOCKUV; -/* m_frame.general &= ~XVID_DERING; */ + /*m_frame.general &= ~XVID_DERING;*/ m_frame.general &= ~XVID_FILMEFFECT; length = xvid_decore_func(m_create.handle, XVID_DEC_DECODE, &m_frame, &stats); - if (length < 0) + if (length == XVID_ERR_MEMORY) + return E_FAIL; + else if (length < 0) { DPRINTF("*** XVID_DEC_DECODE"); return S_FALSE; @@ -769,7 +1051,7 @@ } if (stats.type == XVID_TYPE_NOTHING && length > 0) { - DPRINTF("B-Frame decoder lag"); + DPRINTF(" B-Frame decoder lag"); return S_FALSE; } @@ -782,10 +1064,23 @@ DPRINTF("TODO: auto-resize"); return S_FALSE; } - -// pOut->SetDiscontinuity(TRUE); + pOut->SetSyncPoint(TRUE); + if (g_config.aspect_ratio == 0 || g_config.aspect_ratio == 1) { /* auto */ + int par_x, par_y; + if (stats.data.vol.par == XVID_PAR_EXT) { + par_x = stats.data.vol.par_width; + par_y = stats.data.vol.par_height; + } else { + par_x = PARS[stats.data.vol.par-1][0]; + par_y = PARS[stats.data.vol.par-1][1]; + } + + ar_x = par_x * stats.data.vol.width; + ar_y = par_y * stats.data.vol.height; + } + m_frame.bitstream = (BYTE*)m_frame.bitstream + length; m_frame.length -= length; goto repeat;