FreeBasic
Главная
Вход
Регистрация
Четверг, 22.01.2026, 16:12Приветствую Вас Гость | RSS
[ Новые сообщения · Участники · Правила форума · Поиск · RSS ]
  • Страница 1 из 1
  • 1
Корректен ли хедер?
DarkDemonДата: Понедельник, 19.01.2026, 19:05 | Сообщение # 1
Генерал-майор
Группа: Друзья
Сообщений: 280
Репутация: -1
Статус: Offline
Хедер "win\vfw.bi".

Хотел портировать код, чтобы получать кадры с вебки, но хедер не заводится при подключении.
Обычно это означает что либо хедер просто порченный, либо что-то надо подключить дополнительно.

FBC 1.10.1 x64, винда.

А там как назло куча макросов, абстрагирование которых уходит корнями в бесконечность...


Сообщение отредактировал DarkDemon - Понедельник, 19.01.2026, 19:07
 
haavДата: Вторник, 20.01.2026, 06:07 | Сообщение # 2
Генералиссимус
Группа: Администраторы
Сообщений: 1448
Репутация: 50
Статус: Offline
Сложно судить без примера или ошибок компиляции. Я попробовал один из примеров с vfw.bi , запустился.

Вы сохраняете власть над людьми покуда оставляете им что-то…Отберите у человека все, и этот человек уже будет неподвластен вам…
 
DarkDemonДата: Вторник, 20.01.2026, 07:42 | Сообщение # 3
Генерал-майор
Группа: Друзья
Сообщений: 280
Репутация: -1
Статус: 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
Репутация: 50
Статус: 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
Репутация: 50
Статус: 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
Репутация: -1
Статус: Offline
Код
попробуй вначале записать эти хедеры:

А где можно подсмотреть зависимости всех хедеров? Это спрашиваю чтобы не создавать в будущем подобных тем.
Или это где-то есть в windows.bi?

Добавлено (20.01.2026, 09:48)
---------------------------------------------

Код
Так что , правильно или неправильно работает , не знаю.

По идее реботает, просто моя вебка не поддерживает необходимый формат и прога пишет "sorry this example needs RGB format!"
 
haavДата: Вторник, 20.01.2026, 10:16 | Сообщение # 7
Генералиссимус
Группа: Администраторы
Сообщений: 1448
Репутация: 50
Статус: Offline
Так увидел функцию или константу , которую не может распознать компилятор , сразу ищи ее в хедере. Как найдешь , подключай нужный хедер , или вытаскивай ее определение оттуда. Если нет такой функции , то искать в MSDN и декларировать вручную.

Вы сохраняете власть над людьми покуда оставляете им что-то…Отберите у человека все, и этот человек уже будет неподвластен вам…
 
DarkDemonДата: Вторник, 20.01.2026, 11:32 | Сообщение # 8
Генерал-майор
Группа: Друзья
Сообщений: 280
Репутация: -1
Статус: Offline
Понятно, спасибо!
 
zamabuvaraeuДата: Среда, Вчера, 07:04 | Сообщение # 9
Полковник
Группа: Друзья
Сообщений: 184
Репутация: 5
Статус: Offline
Виндовые заголовочники требуют подключить "windows.bi". Если кто‐то говорит что это не так — не верьте. Всегда на первое место ставьте "windows.bi". Перед всякими "win\что‐то там" необходимо указывать "windows.bi".
 
DarkDemonДата: Среда, Вчера, 09:42 | Сообщение # 10
Генерал-майор
Группа: Друзья
Сообщений: 280
Репутация: -1
Статус: 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)
---------------------------------------------
Если что, советов пока не прошу, сейчас есть азарт расколупать это дело самостоятельно по манам, тестам и документации.
Это так, скорее побурчать, создать движуху.
К сожалению, вебка у меня всего одна и довольно голимая, что, разумеется, не даёт никакой полной картины тест кейзов.

Прикрепления: 7802515.png (21.0 Kb)
 
zamabuvaraeuДата: Среда, Вчера, 18:42 | Сообщение # 11
Полковник
Группа: Друзья
Сообщений: 184
Репутация: 5
Статус: Offline

Цитата
Ну и бонусом, ради веселья тестирую новую идеологию поэтапной инициализации, SELECT CASE внутри DO,
выходит интересно, т.е. вместо портянок IF-ELSE или самопальных функций контроля ошибки имеем
чёткую цепь действий.
А вот это подробнее, пожалуйста
 
DarkDemonДата: Четверг, Сегодня, 11:54 | Сообщение # 12
Генерал-майор
Группа: Друзья
Сообщений: 280
Репутация: -1
Статус: 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
 
  • Страница 1 из 1
  • 1
Поиск: