Есть 2 проблемы:
Не могу понять - почему не работает функция pVideoWindow.put_FullScreenMode(longbool(true)) интерфейса IVideoWindow? Она просто не работает - ничего не менятся, ошибок не появляется. Остальные функции этого интерфейса работают нормально (put_Owner, put_WindowStyle, put_Visible).
И ещё вопрос - как сделать так, чтобы перетаскивать видеоокно за любую точку, а не за Caption?
У видеоокна могу вытащить handle. Может как-то можно перехватить сообщения этого окна?
Вобщем, пока нарыл вот что:
1) FullScreen
Искусственно создаём его так: SetWindowPos(Form1.Handle,HWND_TOP, -4 , -4 , GetSystemMetrics( SM_CXSCREEN )+8, GetSystemMetrics( SM_CYSCREEN )+8,0);
т.е. растягиваем наше окошко и рамки окна получаются за пределами видимости. Окно есессно StayOnTop.
2) Обработчик сообщений видеоокна.
Перетаскиваем видеоокно за любую точку изображения, а не только за Caption:
// глобальные переменные
var
Form1: TForm1;
hMovie:HWND; // handle видеоокна
m_RectDlg:TRect;
m_bMoveWindow:bool;
Point,m_MouseInDlg: TPoint;
OldWindowProc : Pointer; {Variable for the old windows proc}
//==========================
// Этот кусок можно прописать, например, в TForm1.FormCreate
// Задаем Caption видеоокна:
pVideoWindow.put_Caption('!*Das_Rainstuff_movie*!');
// находим наше видеоокно (оно прикреплено к панели Panel1)
hMovie:=FindWindowEx(Panel1.Handle,0,nil,PChar('!*Das_Rainstuff_movie*!'));
if hMovie<>0 then begin
//Устанавливаем новый обработчик окна, а старый запоминаем:
OldWindowProc := Pointer(SetWindowLong(hnd,
GWL_WNDPROC,
LongInt(@NewWindowProc)));
end;
//==========================
function NewWindowProc(WindowHandle : hWnd;
TheMessage : LongInt;
ParamW : LongInt;
ParamL : LongInt) : LongInt stdcall;
begin
if TheMessage=WM_LBUTTONDOWN then begin
// выставим флажок - пошло перетаскивание
m_bMoveWindow:= TRUE;
// все сообщения от мыши - к нашему окну, независимо от координат
// чтобы мышь не улетала с окна при быстром движении
SetCapture(hMovie);
// сохраняем координаты окна
GetWindowRect(Form1.Handle,m_RectDlg);
// сохраняем положение мышки внутри окна программы
point.X:=LOWORD(ParamL);
point.Y:=HIWORD(ParamL);
// логики мало, но именно так работает верно:
m_MouseInDlg.Y:=point.X;
m_MouseInDlg.X:=point.Y;
end;
if TheMessage=WM_MOUSEMOVE then begin
if (m_bMoveWindow) // надо тащить
then
begin
point.X:=HIWORD(ParamL);
point.Y:=LOWORD(ParamL);
// двигаем окно в соответствии с новыми координатами мыши
SetWindowPos(Form1.Handle,HWND_TOP,
Form1.Left +(point.y- m_MouseInDlg.y),
Form1.Top +(point.x- m_MouseInDlg.x),
m_RectDlg.right - m_RectDlg.left,
m_RectDlg.bottom - m_RectDlg.top,
SWP_SHOWWINDOW);
end;
end;
if TheMessage=WM_LBUTTONUP then begin
// перетаскивание закончилось
m_bMoveWindow:= FALSE;
// "отпускаем" мышку
ReleaseCapture();
end;
{Вызываем оригинальный обработчик}
Result := CallWindowProc(OldWindowProc,
WindowHandle,
TheMessage,
ParamW,
ParamL);
end;
Видел извратные реализации с таймерами, подменой сообщений Windows, но такой способ, мне кажется, корректней и элегантней:)
Ещё по поводу FullScreen- оказывается надо было так:
pVideoWindow.put_Owner(0);
pVideoWindow.put_FullScreenMode(longbool(-1));
добавлено спустя 15 минут
Столкнулся ещё с одной проблемой: Aspect Ratio
На компе по-умолчанию в свойствах Renderer'а выставляется по умолчанию галочка напротив Maintain Aspect Ratio. Причём так интересно - у одного и того же Renderer'а на ноутбуке по умолчанию галочка стоит, а на компе - нет. На компе разрешение видеоокна тюнера 768x576 и растягивается на полное окно без чёрных полосок, даже если выставлено 4:3. А вот у тюнера на ноутбуке максимальное разрешение 720x576. Соответственно, на полный экран оно не растягивается и по краям чёрные полоски.
Это решается, если в свойствах Renderer'a убрать галку Maintain Aspect Ratio. Но после перезапуска моего приложения эта галка опять сбрасывается в "по умолчанию".
Вопрос:
Можно ли как-нибудь выставить Aspect Ratio или отменить его программным путём или в реестре?
Вот есть, например, интерфейс IVMRAspectRatioControl, но никаких ссылок на него в реестре я не нашёл... Соотесно он и не пашет. Пробовал через IAMStreamConfig, но там просто разрешение удалось задать, а не соотношения сторон. Пробовал через IVMRWindowlessControl::SetAspectRatioMode , но там нужно задать VMRMode_Windowless режим, а выставить не получается - вылетает с ошибкой.
Не подскажешь, через какой интерфейс точно задаётся?
или может до этого чекбокса можно через свойства программно добраться?
Я посмотрел , в SDK то же самое. А я на Delphi пишу...
Использую рендер по умолчанию - Video Render.
В системе есть ещё Video Mixing Render 9, но с ним запросить этот интерфейс не получается - пишет ошибку. Хотя, если не запрашивать - всё нормально работает.
Функцию SetAspectRatioMode я описывал как
TVMR_ASPECT_RATIO_MODE=(VMR_ARMODE_NONE,VMR_ARMODE_LETTER_BOX);
SetAspectRatioMode(dwmode: TVMR_ASPECT_RATIO_MODE):HRESULT
Если ставить как в SDK тип у dwmode - DWORD, то не воспринимается константа VMR_ARMODE_LETTER_BOX - не соответствие типов.
Если всё таки выставить DWORD и при передаче в функцию писать 0,1,2 ..... то то же самое.
Ещё такой вопрос - в свойствах Video Renderer'a есть кнопка SnapShot, по нажатию на которой картинка пишется в файл (по умолчанию в папку C:\Documents and Settings\<User>\Мои документы\Мои рисунки\VMRImageXXX.bmp).
У рендерера есть интерфейс для захвата картинок или нужно через ISampleGrabber, т.е. добавлять новый фильтр?
Спасибо!
Если кому интересно, то нужно делать так:
Во-первых, правильно описываем функцию интерфейса IBaseVideo
(ни в одном Delphi-описании DShow не нашёл верного и из-за этого не работало!!!)
function GetCurrentImage(var BufferSize: Longint; pDIBImage: Pointer):HResult; stdcall;
Сама функция снятия screenshot'а. Пишу на Delphi c использованием библиотеки KOL, но смысл, думаю будет понятен:
procedure TForm1.Button4Click(Sender: PObj);
var
hr:integer;
pGetIm:IBasicVideo;
Buff:longint;
pMC: IMediaControl;
BFH: TBITMAPFILEHEADER;
lpbf: array of byte;
Stream: PStream;
begin
//========
//Создаём новый поток:
Stream:=NewMemoryStream;
//Запрашиваем интерфейс для управления видеопотоком IMediaControl
hr := pFilterGraph.QueryInterface(IID_IMediaControl, pMC);
if (hr <> NOERROR) then raise Exception.Create(e_Abort,'Unable create instance of IMediaControl');
//Приостанвливаем видеопоток
pMC.Pause; // или pMC.Stop;
// Запрашиваем интерфейс IBasicVideo у нашего рендерера:
hr:=pVideoRender.QueryInterface(IID_IBasicVideo, pGetIm);
if(hr <> NOERROR) then raise Exception.Create(e_Abort,'Unable create instance of IBasicVideo');
Buff:=0;
//Получаем размер изображения, для этого вторым параметром передаём nil;
hr:=pGetIm.GetCurrentImage(Buff,nil);
if(hr <> NOERROR) then raise Exception.Create(e_Abort,'Unable get size of image!');
//Задаём размер буфера и снова вызываем функцию
SetLength(lpbf,Buff);
hr:=pGetIm.GetCurrentImage(Buff,lpbf);
if(hr <> NOERROR) then raise Exception.Create(e_Abort,'Unable get Dib image!');
//Заполняем хедер нашего изображеия
BFH.bfType := $4d42; // BM - тип изображения
BFH.bfSize := sizeof(TBITMAPFILEHEADER) + Buff; // размер изображения
BFH.bfReserved1 := 0;
BFH.bfReserved2 := 0;
BFH.bfOffBits := sizeof(TBITMAPFILEHEADER); // смещение, после которого заканчивается хедер и начинается изображение
// Пишем это всё последовательно в наш поток, а потом в файл:
Stream.Write(BFH, SizeOf(TBITMAPFILEHEADER));
Stream.Write(lpbf[0],Buff);
Stream.Position :=0;
Stream.SaveToFile('c:\myshot.bmp',0,Buff+sizeof(TBITMAPFILEHEADER));
// Запускаем видеопоток:
pMC.Run;
//Пуск и остановка видеопотока, в принципе, не обязательны - GetCurrentImage отрабатывает и без них.
end;
Вобщем-то да, согласен:) Хотя, большой разницы нет.
Просто когда я форматы вывода выставлял - AspectRatio, разрешение... без остановки потока не хотело работать... Тут тоже на автомате поставил:)
Здравствуйте Ув. программисты!
У маня тюнер Aver 509. Моник LG227 16:10, естественно смотреть как 4:3 расягивается на полный экран не могу.
Перепробовал разных прог., в т.ч. родных разных версий - ни чем не смог сделать нормальный FullScreen, чтобы картинка вписывалась по горизонтали и выходила за пределы верхнего и нижнего краев.
Помогите каким-либо файликом или настройками, а то не волоку в программировании.
Спасибо все, кто ответит!
Всем Облатателям ТВ-тюнеров AverMedia!!!
Есть решение. У меня тюнер Aver 509UA RDS, AverTV было 6.2
Очень долго мучался проблемой Fullscreen на мониторе 16:10 - как-то не прикольно когда все растянуто.
Прошивал в Бихолдер разных версий, ТВ настроил - там много разных плагинов по растяжке экрана. Однако FM радио молчало и прога не закрывалась с пульта.
И вот случайно наткнулся на решение моей проблемы родным софтом!!!
Наконец-то вышел софт версии AverTV 6.3 с 17 дровами. Та м "настройке канала" можно подрегулировать картинку, чтобы в Fullscreen на 16:10 былоо как 4:3. С плюсов можно отметить передачу звука по шине PCI (наконец-то выкинул шнурок с тюнера во вход звуковой карты).
Ну и без минусов не обошлось: если выключить программу с пульта кнопкой Power и сразу включить пишет ошибку, поэтому нужно ждать секунд 10; ФМ каналы пришлось настраивать вручную - он мне ничего не нашел, и еще придумали какой-то магический растягиватель экрана - какое-то уродство.
Ну а так все Ок!
Качать всем:
Устанавливайте сначала драйвер (нижним пунктом удаляем все свой, верхним ставим новый) и ставим AverTV 6.3
Всем удачи! Можнообойтись и без BeholderTV!
function VideoWndProc(hwnd:HWND;uMsg:UINT;wParam:WPARAM;
lParam:LPARAM):LRESULT;stdcall;
var
Cp:TPoint;
begin
case uMsg of
WM_NCHITTEST: Result:=HTTRANSPARENT;
...............................................
WM_MOUSEFIRST..WM_MOUSELAST:
begin
if uMsg=WM_LBUTTONDOWN then SetFocus(hwnd);
Cp:=Point($FFFF and LPARAM,LPARAM shr 16);
ClientToScreen(hFrameWnd,Cp);
with Cp do
PostMessage(hMainWnd,(uMsg and $F) or $A0,HTCAPTION,MakeLParam(X,Y));
Result:=0;
end;
Да, прикольно - работает:)
Только пришлось убрать WM_NCHITTEST и заменить DefWindowProc на CallWindowProc
OldWindowProc := Pointer(SetWindowLong(hnd,
GWL_WNDPROC,
LongInt(@NewWindowProc)));
// hnd - хэндл видеоокна.
function NewWindowProc(WindowHandle : hWnd;
TheMessage : LongInt;
ParamW : LongInt;
ParamL : LongInt) : LongInt stdcall;
var
hMainWnd : HRESULT ;
Cp:TPoint;
begin
case TheMessage of
WM_LBUTTONDOWN:
begin
// fullflag - признак разворачивания на полный экран.
if (not fullflag) then begin
hMainWnd:= Form1.Form.GetWindowHandle;
SetFocus(WindowHandle);
Cp:=MakePoint($FFFF and PARAML,PARAML shr 16);
ClientToScreen(hMainWnd,Cp);
with Cp do
PostMessage(hMainWnd,(TheMessage and $F) or $A0,HTCAPTION,MakeLParam(X,Y));
end;
Result:=0;
end;
..................................
else
Result := CallWindowProc(OldWindowProc,
WindowHandle,
TheMessage,
ParamW,
ParamL);
end;
Кстати, может кто в курсе - как сделать так, чтобы видео было вместо wallpaper'а на рабочем столе.
Установкой parent'a тут явно не обойтись... Пытался копать DSPack, но пока безуспешно - там есть такая функция, но я пока не понял как она работает...
Может кто-нить делал нечто подобное без DSPack'а?
Если есть примерчик на Делфи или С++ , буду чрезвычайно благодарен:)