|
Корректен ли хедер?
|
|
| DarkDemon | Дата: Понедельник, 19.01.2026, 19:05 | Сообщение # 1 |
|
Генерал-майор
Группа: Друзья
Сообщений: 280
Статус: Offline
| Хедер "win\vfw.bi".
Хотел портировать код, чтобы получать кадры с вебки, но хедер не заводится при подключении. Обычно это означает что либо хедер просто порченный, либо что-то надо подключить дополнительно.
FBC 1.10.1 x64, винда.
А там как назло куча макросов, абстрагирование которых уходит корнями в бесконечность...
Сообщение отредактировал DarkDemon - Понедельник, 19.01.2026, 19:07 |
| |
|
|
| haav | Дата: Вторник, 20.01.2026, 06:07 | Сообщение # 2 |
 Генералиссимус
Группа: Администраторы
Сообщений: 1448
Статус: Offline
| Сложно судить без примера или ошибок компиляции. Я попробовал один из примеров с vfw.bi , запустился.
Вы сохраняете власть над людьми покуда оставляете им что-то…Отберите у человека все, и этот человек уже будет неподвластен вам…
|
| |
|
|
| DarkDemon | Дата: Вторник, 20.01.2026, 07:42 | Сообщение # 3 |
|
Генерал-майор
Группа: Друзья
Сообщений: 280
Статус: Offline
| Пример вот отсюда: https://www.freebasic-portal.de/code-be....46.html
Код: Код ' Grab_webcam.bas by Volta ' auf FB020 nur unter ME getestet! #INCLUDE ONCE "win\vfw.bi" 'die vfw.bi includet die windows.bi
DECLARE SUB CamCap_init DECLARE SUB CamCap_off (i AS INTEGER= 1) DECLARE FUNCTION GRAB_FRAME2Image(BYVAL hWin AS INTEGER _ , BYVAL lpHeader AS VIDEOHDR PTR) AS INTEGER
TYPE RGB32 FIELD = 1 AS BYTE b,g,r,a END TYPE
DIM SHARED AS INTEGER cam_breite, cam_hoehe, CamPosX, CamPosY DIM SHARED AS INTEGER PTR cap_image DIM SHARED AS HWND hCapture DIM SHARED AS BITMAPINFOHEADER biheader
DIM ik AS STRING SCREEN 18,32 CamPosX=0 CamPosY=19 CamCap_init SCREENRES cam_breite,cam_hoehe+20,32 WIDTH cam_breite\8,(cam_hoehe+20)\16 cap_image = IMAGECREATE(cam_breite,cam_hoehe) DO LOCATE 1,2 : ? TIME capGrabFrame(hCapture) SCREENLOCK PUT (CamPosX,CamPosY),cap_image,PSET SCREENUNLOCK SLEEP 1 Ik = INKEY LOOP UNTIL Ik = CHR(3) OR Ik = CHR(27) OR Ik = CHR(255,107)
CamCap_off 0 END
FUNCTION GRAB_FRAME2Image(BYVAL hWin AS INTEGER _ , BYVAL lpHeader AS VIDEOHDR PTR) AS INTEGER DIM AS INTEGER picsize, zeile, x, y, j DIM AS RGB32 PTR lpScreen picsize = lpHeader->dwBytesUsed\3 IF picsize = cam_breite * cam_hoehe THEN 'Byte für Byte in das Image schaufeln zeile = cam_breite * (cam_hoehe-1) lpScreen = CPTR(RGB32 PTR,(cap_image))+8 FOR y = 0 TO cam_hoehe-1 FOR x = 0 TO cam_breite-1 lpScreen[zeile+x].b = lpHeader->lpData [j]lpScreen[zeile+x].g = lpHeader->lpData[j+1] lpScreen[zeile+x].r = lpHeader->lpData[j+2] j+ = 3 NEXT zeile -= cam_breite NEXT ELSE RETURN 0 END IF RETURN 1 END FUNCTION
SUB CamCap_off (i AS INTEGER) capDriverDisconnect(hCapture) IF cap_image<>0 THEN IMAGEDESTROY cap_image IF i THEN SLEEP END END SUB
SUB CamCap_init hCapture = capCreateCaptureWindow(@"Voltas Grab_Cam_Picture" _ , &H40000000, 0, 0, 0, 0, FindWindow(0, 0), 0) IF hCapture = 0 THEN ? "error: can't create capture window !" CamCap_off 1 END IF
IF capDriverConnect(hCapture, 0) <> 1 THEN 'für die erste WebCam, ' sonst (hCapture, n) n =1,2,3 ... ? "error: can't connect the driver !" CamCap_off 1 END IF
capGetVideoFormat(hCapture, @biHeader, SIZEOF(BITMAPINFOHEADER)) IF (biHeader.biCompression <> 0) THEN ?"error: sorry this example needs RGB format!" CamCap_off 1 END IF
cam_breite = biHeader.biWidth cam_hoehe = biHeader.biHeight capSetCallbackOnFrame(hCapture, @GRAB_FRAME2Image) END SUB
Код вроде бы понятный, через функции ставится коллбек, куда уходит параметр структуры, в этой структуре лежит питч и указатель на пиксели. С остальным(организацией окон) можно разобраться...
Проблема в том, что просто подключение vfw.bi уже даёт ошибки, что странно в другом хедере в mmsystem.bi. И фраза от компилятора "Too many errors, exiting" говорит о том, что это не 1 ошибка, а неперелопачиваемое кол-во.
При подключении перед ним "windows.bi" появляется 6 ошибок вида
Код D:\Programs\FreeBasics\FreeBasic\FBC\inc\win\vfw.bi(1742) error 59: Illegal specification, at parameter 1 (lpofn) of GetOpenFileNamePreviewA() in 'declare function GetOpenFileNamePreviewA(byval lpofn as LPOPENFILENAMEA) as WINBOOL'
Из опыта знаю, что править такое говно бесполезно, будут вылезать новые. Поэтому сейчас я занят пересборкой этого кода с возможностью подключения Windows.bi, но без vfw.bi. Пытаюсь задекларировать необходимые функции руками и убрать говно в виде макросов
Код #define AVICapSM(hwnd, m, w, l) iif(IsWindow(hwnd), SendMessage(hwnd, m, w, l), 0) Для этого я нашёл код на делфе:
https://drkb.ru/multimedia/audio/extract_track/ed7dcb6994c641e4
Там функции capDriverConnect, capGetVideoFormat, capSetCallbackOnFrame выполнены понятным языком:
Код 'function capDriverConnect(hwnd: HWND; i: INT): BOOL; 'begin ' Result := AVICapSM(hwnd, WM_CAP_DRIVER_CONNECT, i, 0) <> 0; 'end;
'function capGetVideoFormat(hwnd: HWND; s: PVOID; wSize: WORD): DWORD; 'begin ' Result := AVICapSM(hwnd, WM_CAP_GET_VIDEOFORMAT, wSize, LPARAM(s)); 'end;
Это по итогу превращается во что-то типа:
Код FUNCTION capDriverConnect(hwnd AS HWND, i AS INTEGER) AS BOOLEAN
IF IsWindow(hwnd) <> 0 THEN SendMessage(hwnd, WM_CAP_DRIVER_CONNECT, i, 0) END IF
END FUNCTION
И если честно, я не знаю хватит ли мне терпения сделать даже это, т.к. на каждую, сука, переменную надо лезть в хедер, смотреть тип, а там один тип ссылается на другой тип и другой на третий и всё в разных хедерах. Короче п.....ц... Но я хочу убрать ужасающие портянки CAST-ов... те, что нагородили в хедере FB, это ужас просто...
И это ситуация "без прекрас", реально чем приходится заниматься человеку на FB... причём постоянно на это напарываюсь 99% возьни именно с этим.
Сообщение отредактировал DarkDemon - Вторник, 20.01.2026, 07:47 |
| |
|
|
| haav | Дата: Вторник, 20.01.2026, 08:29 | Сообщение # 4 |
 Генералиссимус
Группа: Администраторы
Сообщений: 1448
Статус: Offline
| Цитата Illegal specification, at parameter 1 (lpofn) of GetOpenFileNamePreviewA()
не хватает хедера: commdlg.bi
попробуй вначале записать эти хедеры:
Код #INCLUDE ONCE "windows.bi" #INCLUDE ONCE "win\commdlg.bi" #INCLUDE ONCE "win\vfw.bi"
Вы сохраняете власть над людьми покуда оставляете им что-то…Отберите у человека все, и этот человек уже будет неподвластен вам…
|
| |
|
|
| haav | Дата: Вторник, 20.01.2026, 09:00 | Сообщение # 5 |
 Генералиссимус
Группа: Администраторы
Сообщений: 1448
Статус: Offline
| Вот компилируется и запускается. Изучать дальше лень. Так что , правильно или неправильно работает , не знаю.
Код #include once "windows.bi" #include once "win\commdlg.bi" #INCLUDE ONCE "win\vfw.bi"
DECLARE SUB CamCap_init DECLARE SUB CamCap_off (i AS INTEGER= 1) DECLARE FUNCTION GRAB_FRAME2Image(BYVAL hWin AS INTEGER _ , BYVAL lpHeader AS VIDEOHDR PTR) AS INTEGER
TYPE RGB32 FIELD = 1 AS BYTE b,g,r,a END TYPE
DIM SHARED AS INTEGER cam_breite, cam_hoehe, CamPosX, CamPosY DIM SHARED AS INTEGER PTR cap_image DIM SHARED AS HWND hCapture DIM SHARED AS BITMAPINFOHEADER biheader
DIM ik AS STRING SCREEN 18,32 CamPosX=0 CamPosY=19 CamCap_init SCREENRES cam_breite,cam_hoehe+20,32 WIDTH cam_breite\8,(cam_hoehe+20)\16 cap_image = IMAGECREATE(cam_breite,cam_hoehe) DO LOCATE 1,2 : ? TIME dim as WinBOOL wRes = capGrabFrame(hCapture) SCREENLOCK PUT (CamPosX,CamPosY),cap_image,PSET SCREENUNLOCK SLEEP 1 Ik = INKEY LOOP UNTIL Ik = CHR(3) OR Ik = CHR(27) OR Ik = CHR(255,107)
CamCap_off 0 END
FUNCTION GRAB_FRAME2Image(BYVAL hWin AS INTEGER _ , BYVAL lpHeader AS VIDEOHDR PTR) AS INTEGER DIM AS INTEGER picsize, zeile, x, y, j DIM AS RGB32 PTR lpScreen picsize = lpHeader->dwBytesUsed\3 IF picsize = cam_breite * cam_hoehe THEN zeile = cam_breite * (cam_hoehe-1) lpScreen = CPTR(RGB32 PTR,(cap_image))+8 FOR y = 0 TO cam_hoehe-1 FOR x = 0 TO cam_breite-1 lpScreen[zeile+x].b = lpHeader->lpData[j] lpScreen[zeile+x].g = lpHeader->lpData[j+1] lpScreen[zeile+x].r = lpHeader->lpData[j+2] j+ = 3 NEXT zeile -= cam_breite NEXT ELSE RETURN 0 END IF RETURN 1 END FUNCTION
SUB CamCap_off (i AS INTEGER) dim as WinBOOL wRes = capDriverDisconnect(hCapture) IF cap_image<>0 THEN IMAGEDESTROY cap_image IF i THEN SLEEP END END SUB
SUB CamCap_init hCapture = capCreateCaptureWindow(@"Voltas Grab_Cam_Picture" _ , &H40000000, 0, 0, 0, 0, FindWindow(0, 0), 0) IF hCapture = 0 THEN ? "error: can't create capture window !" CamCap_off 1 END IF
IF capDriverConnect(hCapture, 0) <> 1 THEN ? "error: can't connect the driver !" CamCap_off 1 END IF
dim as WinBOOL wRes = capGetVideoFormat(hCapture, @biHeader, SIZEOF(BITMAPINFOHEADER)) IF (biHeader.biCompression <> 0) THEN ?"error: sorry this example needs RGB format!" CamCap_off 1 END IF
cam_breite = biHeader.biWidth cam_hoehe = biHeader.biHeight wRes = capSetCallbackOnFrame(hCapture, @GRAB_FRAME2Image) END SUB
Вы сохраняете власть над людьми покуда оставляете им что-то…Отберите у человека все, и этот человек уже будет неподвластен вам…
|
| |
|
|
| DarkDemon | Дата: Вторник, 20.01.2026, 09:43 | Сообщение # 6 |
|
Генерал-майор
Группа: Друзья
Сообщений: 280
Статус: Offline
| Код попробуй вначале записать эти хедеры:
А где можно подсмотреть зависимости всех хедеров? Это спрашиваю чтобы не создавать в будущем подобных тем. Или это где-то есть в windows.bi?Добавлено (20.01.2026, 09:48) ---------------------------------------------
Код Так что , правильно или неправильно работает , не знаю.
По идее реботает, просто моя вебка не поддерживает необходимый формат и прога пишет "sorry this example needs RGB format!"
|
| |
|
|
| haav | Дата: Вторник, 20.01.2026, 10:16 | Сообщение # 7 |
 Генералиссимус
Группа: Администраторы
Сообщений: 1448
Статус: Offline
| Так увидел функцию или константу , которую не может распознать компилятор , сразу ищи ее в хедере. Как найдешь , подключай нужный хедер , или вытаскивай ее определение оттуда. Если нет такой функции , то искать в MSDN и декларировать вручную.
Вы сохраняете власть над людьми покуда оставляете им что-то…Отберите у человека все, и этот человек уже будет неподвластен вам…
|
| |
|
|
| DarkDemon | Дата: Вторник, 20.01.2026, 11:32 | Сообщение # 8 |
|
Генерал-майор
Группа: Друзья
Сообщений: 280
Статус: Offline
| Понятно, спасибо!
|
| |
|
|
| zamabuvaraeu | Дата: Среда, Вчера, 07:04 | Сообщение # 9 |
|
Полковник
Группа: Друзья
Сообщений: 184
Статус: Offline
| Виндовые заголовочники требуют подключить "windows.bi". Если кто‐то говорит что это не так — не верьте. Всегда на первое место ставьте "windows.bi". Перед всякими "win\что‐то там" необходимо указывать "windows.bi".
|
| |
|
|
| DarkDemon | Дата: Среда, Вчера, 09:42 | Сообщение # 10 |
|
Генерал-майор
Группа: Друзья
Сообщений: 280
Статус: Offline
| Цитата zamabuvaraeu (  ) Виндовые заголовочники требуют подключить "windows.bi". Если кто‐то говорит что это не так — не верьте. Всегда на первое место ставьте "windows.bi". Перед всякими "win\что‐то там" необходимо указывать "windows.bi". Да Windows.bi то понятно зачем, когда про него говорил это была цель консолидации с другими программами, которые его явно требуют(большинство), нечасто пытаюсь уйти от его использования. Так то вижу функции в коде, которые вызываются.
Вебку кстати завёл, но работает всё это дело как говно. У моей вебки есть своя менюшка настроек, т.е. она даже с дефолтным драйвером винды есть. Вот такая:

И что забавно, когда использую OBS - всё нормально, эти настройки сохраняются в системе, НО после запуска моей проги, эти настройки сбрасываются. Наверное чего-то не знаю, буду колупать дальше. Коллбеки работают крайне странно и скорее не работают, поэтому пример с немецкого сайта после тестов могу смело назвать нерабочим на моей вебке, т.к. коллбек там попросту не будет вызываться(ему нужны какие-то доп команды и настройки вне коллбека, ещё пишут что надо внутри коллбека обрабатывать сообщения через PeekMessage\TranslateMessage\DispatchMessage что надо сказать - очень странно), а я хотел использовать FBGfx у которого свой обработчик, который сам начинает это всё делать(из-за того что ему приходится создавать окно и он полагает, что оно основное, т.е. даёт на него фокус) и ну вы понимаете. Нормальных советов и исходников нигде нет, переколупал десятки ресурсов. Короче полный каламбур и веселуха. Люди пишут что надо делать через DirectShow, а я туда точно не полезу, думал простыми средствами получится. Хотя все другие исходники которые видел - в них используются все те же функции.
Ну и бонусом, ради веселья тестирую новую идеологию поэтапной инициализации, SELECT CASE внутри DO, выходит интересно, т.е. вместо портянок IF-ELSE или самопальных функций контроля ошибки имеем чёткую цепь действий.Добавлено (21.01.2026, 10:12) --------------------------------------------- Если что, советов пока не прошу, сейчас есть азарт расколупать это дело самостоятельно по манам, тестам и документации. Это так, скорее побурчать, создать движуху. К сожалению, вебка у меня всего одна и довольно голимая, что, разумеется, не даёт никакой полной картины тест кейзов.
|
| |
|
|
| zamabuvaraeu | Дата: Среда, Вчера, 18:42 | Сообщение # 11 |
|
Полковник
Группа: Друзья
Сообщений: 184
Статус: Offline
| Цитата Ну и бонусом, ради веселья тестирую новую идеологию поэтапной инициализации, SELECT CASE внутри DO, выходит интересно, т.е. вместо портянок IF-ELSE или самопальных функций контроля ошибки имеем чёткую цепь действий. А вот это подробнее, пожалуйста
|
| |
|
|
| DarkDemon | Дата: Четверг, Сегодня, 11:54 | Сообщение # 12 |
|
Генерал-майор
Группа: Друзья
Сообщений: 280
Статус: Offline
| Цитата zamabuvaraeu (  ) А вот это подробнее, пожалуйста Вкратце:
Код InitStage = 1 LastStage = 3
DO ' Шаги инициализации SELECT CASE InitStage ' Деинициализация устройства\модуля при неудаче ' И рестарт инициализации CASE 0 Try = Try + 1 ' Кол-во попыток IF Try = MaxTry THEN EXIT DO ' Выход если все попытки сделали InitStage = 1
' Шаги инициализации CASE 1 CASE 2 CASE 3 END SELECT ' Следующий шаг IF InitStage > 0 THEN InitStage += 1
LOOP UNTIL InitStage > LastStage
Где-то видел что люди заводят процедуру, внутри неё проверка на ошибку и END. Ставят её после каждого шага, это подход грубый, чаще всего завершать прогу нельзя, надо чтобы она работала "сквозь" любые ошибки. Поэтому неудачный инит должен быть сопровождён деинициализацией и уничтожением заведённых ресурсов. Другие используют GOTO чтобы отпрыгивать в конец для деиниц ресурсов. Тоже его использовал до поры до времени, но портянки проверок IF, отступами двигающиеся вправо и выходящие за экран - задирают. А тут пришла идея организовать всё в CASE-ы, структурно. В любой момент можно выпрыгнуть из инита через EXIT DO и с шага инита через EXIT SELECT, кол-во попыток контролируется сразу после деиниц в одном из первых CASE-ов. Логику после CASE-a можно усложнить, если шагов деинициализации больше одного(нет смысла этим заниматься в коде сразу после неудачного шага инициализации).
В общем это небольшой апгрейд своего стиля кодирования. Не знаю полезен ли он кому-то. Т.к. пишу сугубо на 3GL то мне это принесёт небольшой профит. Кода станет немного меньше(из-за компактности организации данной логики), и всё будет +/- структурно, возможно возрастёт читаемость при вбивании себе в голову этого шаблона.
Сообщение отредактировал DarkDemon - Четверг, 22.01.2026, 11:58 |
| |
|
|
|