|
Корректен ли хедер?
|
|
| DarkDemon | Дата: Понедельник, 19.01.2026, 19:05 | Сообщение # 1 |
|
Генерал-майор
Группа: Друзья
Сообщений: 285
Статус: Online
| Хедер "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 |
|
Генерал-майор
Группа: Друзья
Сообщений: 285
Статус: Online
| Пример вот отсюда: 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 |
|
Генерал-майор
Группа: Друзья
Сообщений: 285
Статус: Online
| Код попробуй вначале записать эти хедеры:
А где можно подсмотреть зависимости всех хедеров? Это спрашиваю чтобы не создавать в будущем подобных тем. Или это где-то есть в 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 |
|
Генерал-майор
Группа: Друзья
Сообщений: 285
Статус: Online
| Понятно, спасибо!
|
| |
|
|
| zamabuvaraeu | Дата: Среда, 21.01.2026, 07:04 | Сообщение # 9 |
|
Полковник
Группа: Друзья
Сообщений: 186
Статус: Offline
| Виндовые заголовочники требуют подключить "windows.bi". Если кто‐то говорит что это не так — не верьте. Всегда на первое место ставьте "windows.bi". Перед всякими "win\что‐то там" необходимо указывать "windows.bi".
|
| |
|
|
| DarkDemon | Дата: Среда, 21.01.2026, 09:42 | Сообщение # 10 |
|
Генерал-майор
Группа: Друзья
Сообщений: 285
Статус: Online
| Цитата 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 | Дата: Среда, 21.01.2026, 18:42 | Сообщение # 11 |
|
Полковник
Группа: Друзья
Сообщений: 186
Статус: Offline
| Цитата Ну и бонусом, ради веселья тестирую новую идеологию поэтапной инициализации, SELECT CASE внутри DO, выходит интересно, т.е. вместо портянок IF-ELSE или самопальных функций контроля ошибки имеем чёткую цепь действий. А вот это подробнее, пожалуйста
|
| |
|
|
| DarkDemon | Дата: Четверг, 22.01.2026, 11:54 | Сообщение # 12 |
|
Генерал-майор
Группа: Друзья
Сообщений: 285
Статус: Online
| Цитата 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 |
| |
|
|
| sashasold | Дата: Пятница, 23.01.2026, 16:53 | Сообщение # 13 |
|
Лейтенант
Группа: Пользователи
Сообщений: 50
Статус: Offline
| насколько я помню, для того чтобы правильно завершалась программа, из любого места, есть Sub Destructor. Который выполняется перед закрытием программы. Я не сталкивался, но часто мелькает про утечку памяти и ресурсов. Вот вписываем туда закрытие файлов, сохранение чего надо, и освобождение ресурсов. Тогда должно срабатывать и от End в любом месте.Добавлено (23.01.2026, 16:54) --------------------------------------------- А по поводу программы для Вебки, я искал в инете, потом уже думал код найти, ни то не другое не помогло. самая простая функция а как оказалось фиг свищи, моя камера не работала как надо от сторонних утилиток, с родной logitec проблемы были какие. Даже забросил затею с вебкой. Итог со временем увидел возможность в OBS, мощная штука все работает.
А хотел просто записывать видео с камеры на ПК. Требуется сохранение в h.264, а лучше h.265 (возможно с некоторыми настройками качества сжатия). Если сможешь доделать до этого состояния буду рад.
|
| |
|
|
| DarkDemon | Дата: Пятница, 23.01.2026, 18:13 | Сообщение # 14 |
|
Генерал-майор
Группа: Друзья
Сообщений: 285
Статус: Online
| Не использую ООП принципиально. Предпочитаю всё контролить руками.
Цитата sashasold (  ) Требуется сохранение в h.264, а лучше h.265 Давным давно Стас бросал код, где через OpenGL рендерился треугольник, который потом захватывался и сохранялся в любой формат(там выплывал стандартный диалог кодеков винды). Так вот отдельно я видел как минимум XVid кодеки, но по сути можно найти любые и использовать тот код, в т.ч. h264\h265. Код был исключительно сложный, колупать долго, но при сильном желании расколупать можно.
Вебку расколупал. Но повторюсь, работает как говно. А про нюансы расскажу:
Во-первых, окно создающееся через capCreateCaptureWindow. Требует обработчик очереди сообщений, иначе нихрена ничего не работает.
Во-вторых, последовательность для превью: capCreateCaptureWindow capDriverConnect capPreviewRate capPreview
дальше цикл.
В-трьетих, блочит к хренам всё(осн. цикл), поэтому строго вешать на отдельный поток. Однако хорошие новости - ЦП при этом не жрёт, т.е. взаимодействие с шиной корректное, поэтому отдельный поток - нормальное решение.
В-четвёртых: грабить кадр можно через capGrabFrame, потом capEditCopy (в буфер обмена), а оттуда уже получаем через GetClipboardData(CF_DIB). В интернете это всё ищется.
В-пятых: есть чек того, какие системные меню настроек оно поддерживает и тут есть дерьмо. То меню что я выше показывал из OBS - является системным, при вызове capDlgVideoSource появляется что-то схожее, немного отличающееся, но нихрена не оказывающее влияние на работу вебки. Тут я пока не расколупал. Сколько не гуглил, инфы по этой функции - ноль. Моя вебка через OBS работает нормально, до 30 к/с, самопальной прогой - кадров 5-6. Дерьмовое дело! Говорят надо DirectShow - но там сущий геморрой, какие-то графы эффектов и прочая дрисня, к тому же это е**чий COM, поэтому лезть туда - исключительно себе дороже. С COM мне хватает колупания с дизасмом на x64, там очень весело, особенно со стеком...
Для записи и стримов OBS является идеальным вариантом. Встаёт вопрос зачем оно мне. Так вот прошерщивая интернет я нифига не нашёл нормального аналога Net Speakerphone. Сам спикер мне не совсем нравится, и если бы у меня было всё необходимое, то попробовал бы написать нормальный аналог, прям максимально простой без идиотии. В свете последних событий - довольно актуально. Скоро такой варик связи со своей семьёй в другом городе может остаться чуть ли не единственным. Но рвать жопу разумеется не буду, всё делается тихо спокойно да и вообще если прогресс с девайсами пойдёт.
|
| |
|
|
| zamabuvaraeu | Дата: Суббота, Вчера, 10:36 | Сообщение # 15 |
|
Полковник
Группа: Друзья
Сообщений: 186
Статус: Offline
| Тогда проще через For всё делать:
Код Function Initialize() As Boolean
Dim CurrentStep As Integer For i As Integer = 0 To InitStepsMaximum Select Case i Case 0 ' создать память p = Allocate(...) If p = 0 Then ' ошибка CurrentStep = i Exit For End If Case 1 ' Создать Handle h = CreateEvent(NULL, TRUE, FALSE, NULL) If h = NULL Then ' ошибка CurrentStep = i Exit For End If Case 2 ' создать окно w = CreateWindowEx(...) If w = NULL Then ' ошибка CurrentStep = i Exit For End If Case 3 ' создать файл f = CreateFile(...) If f = INVALID_HANDLE_VALUE Then ' ошибка CurrentStep = i Exit For End If Case Else ' Инициализация пройдена ' возвращаем успех Return True End Select Next
' Очистка в обратном порядке: For i As Integer = CurrentStep - 1 To 0 Step -1 Select Case i Case 2 ' удалить окно DestroyWindow(w) Case 1 ' Удалить HANDLE CloseHandle(h) Case 0 ' Уничтожить память Deallocate(p) End Select Next
' Ошибка Return False
End Function
Пример можно доработать для возвращения не только True|False, но и определённого кода ошибки через GetLastError(). Вместо единичек, двоек и троек лучше бы ввести именованные константы INITSTAGE_MEMORY, INITSTAGE_WINDOW или INITSTAGE_FILE, чтобы понятно было из текста какой сейчас шаг инициализации (а не циферки запоминать).
Сообщение отредактировал zamabuvaraeu - Суббота, 24.01.2026, 10:42 |
| |
|
|
|