V4L2 enhanced (#766)

* fix v4l2 standard
* ignore v4l2 meta devices
* added resolution, framerate and device dropdown list to WebUI (thx to @Lord-Grey & @b1rdhous3)

* Fix for kernels prior to v4.16
* Device names added & WebUI adapted
This commit is contained in:
Paulchen Panther 2020-04-17 16:59:20 +02:00 committed by GitHub
parent b92af63cef
commit 10f11c2d89
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
20 changed files with 717 additions and 175 deletions

View File

@ -431,6 +431,7 @@
"edt_conf_enum_bbclassic": "Klasický", "edt_conf_enum_bbclassic": "Klasický",
"edt_conf_enum_bbosd": "OSD", "edt_conf_enum_bbosd": "OSD",
"edt_conf_enum_automatic": "", "edt_conf_enum_automatic": "",
"edt_conf_enum_custom": "",
"edt_conf_gen_heading_title": "Obecné nastavení", "edt_conf_gen_heading_title": "Obecné nastavení",
"edt_conf_gen_name_title": "Název konfigurace", "edt_conf_gen_name_title": "Název konfigurace",
"edt_conf_gen_name_expl": "Uživatelské jméno, které se používá k detekci Hyperionu. (Užitečné s více než jednou instancí Hyperion)", "edt_conf_gen_name_expl": "Uživatelské jméno, které se používá k detekci Hyperionu. (Užitečné s více než jednou instancí Hyperion)",
@ -492,6 +493,10 @@
"edt_conf_v4l2_device_expl": "Cesta k Zachycení/Graber usb.", "edt_conf_v4l2_device_expl": "Cesta k Zachycení/Graber usb.",
"edt_conf_v4l2_standard_title": "Video standard", "edt_conf_v4l2_standard_title": "Video standard",
"edt_conf_v4l2_standard_expl": "Vyberte standard videa pro vaši oblast.", "edt_conf_v4l2_standard_expl": "Vyberte standard videa pro vaši oblast.",
"edt_conf_v4l2_resolution_title": "",
"edt_conf_v4l2_resolution_expl": "",
"edt_conf_v4l2_framerate_title": "",
"edt_conf_v4l2_framerate_expl": "",
"edt_conf_v4l2_sizeDecimation_title": "Velikost decimace", "edt_conf_v4l2_sizeDecimation_title": "Velikost decimace",
"edt_conf_v4l2_sizeDecimation_expl": "Faktor velikosti decimace", "edt_conf_v4l2_sizeDecimation_expl": "Faktor velikosti decimace",
"edt_conf_v4l2_cropLeft_title": "Ořezat zleva", "edt_conf_v4l2_cropLeft_title": "Ořezat zleva",
@ -809,4 +814,4 @@
"edt_eff_ledtest_header_desc": "", "edt_eff_ledtest_header_desc": "",
"update_no_updates_for_branch": "", "update_no_updates_for_branch": "",
"general_speech_sv": "" "general_speech_sv": ""
} }

View File

@ -470,7 +470,7 @@
"edt_conf_enum_PAL": "PAL", "edt_conf_enum_PAL": "PAL",
"edt_conf_enum_NTSC": "NTSC", "edt_conf_enum_NTSC": "NTSC",
"edt_conf_enum_SECAM": "SECAM", "edt_conf_enum_SECAM": "SECAM",
"edt_conf_enum_NO_CHANGE": "Auto", "edt_conf_enum_NO_CHANGE": "Automatisch",
"edt_conf_enum_logsilent": "Stille", "edt_conf_enum_logsilent": "Stille",
"edt_conf_enum_logwarn": "Warnung", "edt_conf_enum_logwarn": "Warnung",
"edt_conf_enum_logverbose": "Ausführlich", "edt_conf_enum_logverbose": "Ausführlich",
@ -479,6 +479,7 @@
"edt_conf_enum_bbclassic": "Klassisch", "edt_conf_enum_bbclassic": "Klassisch",
"edt_conf_enum_bbosd": "OSD", "edt_conf_enum_bbosd": "OSD",
"edt_conf_enum_automatic": "Automatisch", "edt_conf_enum_automatic": "Automatisch",
"edt_conf_enum_custom": "Benutzerdefiniert",
"edt_conf_gen_heading_title": "Allgemeine Einstellungen", "edt_conf_gen_heading_title": "Allgemeine Einstellungen",
"edt_conf_gen_name_title": "Name der Konfiguration", "edt_conf_gen_name_title": "Name der Konfiguration",
"edt_conf_gen_name_expl": "Der Name wird verwendet, um Hyperion besser zu identifizieren. (Hilfreich bei mehreren Instanzen)", "edt_conf_gen_name_expl": "Der Name wird verwendet, um Hyperion besser zu identifizieren. (Hilfreich bei mehreren Instanzen)",
@ -539,9 +540,13 @@
"edt_conf_smooth_continuousOutput_expl": "Aktualisiere die LEDs, auch wenn das Bild sich nicht geändert hat.", "edt_conf_smooth_continuousOutput_expl": "Aktualisiere die LEDs, auch wenn das Bild sich nicht geändert hat.",
"edt_conf_v4l2_heading_title": "USB Aufnahme", "edt_conf_v4l2_heading_title": "USB Aufnahme",
"edt_conf_v4l2_device_title": "Gerät", "edt_conf_v4l2_device_title": "Gerät",
"edt_conf_v4l2_device_expl": "Der Pfad zum USB (v4l) Aufnahmegerät. Wähle 'auto' für automatische Erkennung. Beispiel: '/dev/video0'", "edt_conf_v4l2_device_expl": "Eine Liste von USB (v4l) Aufnahmegeräten. Wähle 'Automatisch' für automatische Erkennung. Benutzerdefiniert z.b.: '/dev/video0'",
"edt_conf_v4l2_standard_title": "Videoformat", "edt_conf_v4l2_standard_title": "Videoformat",
"edt_conf_v4l2_standard_expl": "Wähle das passende Videoformat deiner Region. Auf 'Auto' wird der gewählte Modus vom v4l interface beibehalten.", "edt_conf_v4l2_standard_expl": "Wähle das passende Videoformat deiner Region. Auf 'Automatisch' wird der gewählte Modus vom v4l interface beibehalten.",
"edt_conf_v4l2_resolution_title": "Auflösung",
"edt_conf_v4l2_resolution_expl": "Eine Liste von unterstützten Auflösungen des aktiven Gerätes. Auf 'Automatisch' wird der gewählte Modus vom v4l interface beibehalten.",
"edt_conf_v4l2_framerate_title": "Bilder pro Sekunde",
"edt_conf_v4l2_framerate_expl": "Die unterstützten Bilder pro Sekunde des aktiven Gerätes. Auf 'Automatisch' wird der gewählte Modus vom v4l interface beibehalten.",
"edt_conf_v4l2_sizeDecimation_title": "Bildverkleinerung Faktor", "edt_conf_v4l2_sizeDecimation_title": "Bildverkleinerung Faktor",
"edt_conf_v4l2_sizeDecimation_expl": "Der Faktor der Bildverkleinerung ausgehend von der ursprünglichen Größe, 1 bedeutet keine Änderung (originales Bild).", "edt_conf_v4l2_sizeDecimation_expl": "Der Faktor der Bildverkleinerung ausgehend von der ursprünglichen Größe, 1 bedeutet keine Änderung (originales Bild).",
"edt_conf_v4l2_cropLeft_title": "Entferne links", "edt_conf_v4l2_cropLeft_title": "Entferne links",
@ -570,9 +575,9 @@
"edt_conf_v4l2_sDHOffsetMax_expl": "Signal Erkennungs-Bereich horizontal maximum (0.0-1.0)", "edt_conf_v4l2_sDHOffsetMax_expl": "Signal Erkennungs-Bereich horizontal maximum (0.0-1.0)",
"edt_conf_instCapture_heading_title": "Instance Aufnahme", "edt_conf_instCapture_heading_title": "Instance Aufnahme",
"edt_conf_instC_systemEnable_title": "Aktiviere Plattform Aufnahme", "edt_conf_instC_systemEnable_title": "Aktiviere Plattform Aufnahme",
"edt_conf_instC_systemEnable_expl": "Aktiviert die Plattform Aufnahme für diese LED Hardware Instanz", "edt_conf_instC_systemEnable_expl": "Aktiviert die Plattform Aufnahme für diese LED Hardware Instanz.",
"edt_conf_instC_v4lEnable_title": "Aktiviere USB Aufnahme", "edt_conf_instC_v4lEnable_title": "Aktiviere USB Aufnahme",
"edt_conf_instC_v4lEnable_expl": "Aktiviert die USB Aufnahme für diese LED Hardware Instanz", "edt_conf_instC_v4lEnable_expl": "Aktiviert die USB Aufnahme für diese LED Hardware Instanz.",
"edt_conf_fg_heading_title": "Plattform Aufnahme", "edt_conf_fg_heading_title": "Plattform Aufnahme",
"edt_conf_fg_type_title": "Typ", "edt_conf_fg_type_title": "Typ",
"edt_conf_fg_type_expl": "Art der Plattform Aufnahme, standard ist 'auto'", "edt_conf_fg_type_expl": "Art der Plattform Aufnahme, standard ist 'auto'",

View File

@ -469,7 +469,7 @@
"edt_conf_enum_PAL" : "PAL", "edt_conf_enum_PAL" : "PAL",
"edt_conf_enum_NTSC" : "NTSC", "edt_conf_enum_NTSC" : "NTSC",
"edt_conf_enum_SECAM" : "SECAM", "edt_conf_enum_SECAM" : "SECAM",
"edt_conf_enum_NO_CHANGE" : "Auto", "edt_conf_enum_NO_CHANGE" : "Automatic",
"edt_conf_enum_logsilent" : "Silent", "edt_conf_enum_logsilent" : "Silent",
"edt_conf_enum_logwarn" : "Warning", "edt_conf_enum_logwarn" : "Warning",
"edt_conf_enum_logverbose" : "Verbose", "edt_conf_enum_logverbose" : "Verbose",
@ -478,6 +478,7 @@
"edt_conf_enum_bbclassic" : "Classic", "edt_conf_enum_bbclassic" : "Classic",
"edt_conf_enum_bbosd" : "OSD", "edt_conf_enum_bbosd" : "OSD",
"edt_conf_enum_automatic" : "Automatic", "edt_conf_enum_automatic" : "Automatic",
"edt_conf_enum_custom": "Custom",
"edt_conf_gen_heading_title" : "General Settings", "edt_conf_gen_heading_title" : "General Settings",
"edt_conf_gen_name_title" : "Configuration name", "edt_conf_gen_name_title" : "Configuration name",
"edt_conf_gen_name_expl" : "A user defined name which is used to identify Hyperion. (Helpful if you have more than one Hyperion instance)", "edt_conf_gen_name_expl" : "A user defined name which is used to identify Hyperion. (Helpful if you have more than one Hyperion instance)",
@ -538,9 +539,13 @@
"edt_conf_smooth_continuousOutput_expl" : "Update the leds even if there is no change in the picture.", "edt_conf_smooth_continuousOutput_expl" : "Update the leds even if there is no change in the picture.",
"edt_conf_v4l2_heading_title" : "USB Capture", "edt_conf_v4l2_heading_title" : "USB Capture",
"edt_conf_v4l2_device_title" : "Device", "edt_conf_v4l2_device_title" : "Device",
"edt_conf_v4l2_device_expl" : "The path to the USB capture interface. Set to 'auto' for automatic detection. Example: '/dev/video0'", "edt_conf_v4l2_device_expl" : "The path to the USB capture interface. Set to 'Automatic' for automatic detection. Example: '/dev/video0'",
"edt_conf_v4l2_standard_title" : "Video standard", "edt_conf_v4l2_standard_title" : "Video standard",
"edt_conf_v4l2_standard_expl" : "Select the video standard for your region. 'Auto' keeps the value chosen by the v4l2 interface", "edt_conf_v4l2_standard_expl" : "Select the video standard for your region. 'Automatic' keeps the value chosen by the v4l2 interface",
"edt_conf_v4l2_resolution_title" : "Device Resolution",
"edt_conf_v4l2_resolution_expl" : "A list of supported resolutions of the active device",
"edt_conf_v4l2_framerate_title": "Frames per second",
"edt_conf_v4l2_framerate_expl": "The supported frames per second of the active device",
"edt_conf_v4l2_sizeDecimation_title" : "Size decimation", "edt_conf_v4l2_sizeDecimation_title" : "Size decimation",
"edt_conf_v4l2_sizeDecimation_expl" : "The factor of size decimation. 1 means no decimation (keep original size)", "edt_conf_v4l2_sizeDecimation_expl" : "The factor of size decimation. 1 means no decimation (keep original size)",
"edt_conf_v4l2_cropLeft_title" : "Crop left", "edt_conf_v4l2_cropLeft_title" : "Crop left",

View File

@ -431,6 +431,7 @@
"edt_conf_enum_bbclassic": "Clásico", "edt_conf_enum_bbclassic": "Clásico",
"edt_conf_enum_bbosd": "OSD", "edt_conf_enum_bbosd": "OSD",
"edt_conf_enum_automatic": "Automático", "edt_conf_enum_automatic": "Automático",
"edt_conf_enum_custom": "",
"edt_conf_gen_heading_title": "Configuración General", "edt_conf_gen_heading_title": "Configuración General",
"edt_conf_gen_name_title": "Nombre de configuración", "edt_conf_gen_name_title": "Nombre de configuración",
"edt_conf_gen_name_expl": "Un nombre definido por el usuario que se utiliza para detectar Hyperion. (Útil con más de una instancia de Hyperion)", "edt_conf_gen_name_expl": "Un nombre definido por el usuario que se utiliza para detectar Hyperion. (Útil con más de una instancia de Hyperion)",
@ -492,6 +493,10 @@
"edt_conf_v4l2_device_expl": "La ruta a la captura USB.", "edt_conf_v4l2_device_expl": "La ruta a la captura USB.",
"edt_conf_v4l2_standard_title": "Estándar de vídeo", "edt_conf_v4l2_standard_title": "Estándar de vídeo",
"edt_conf_v4l2_standard_expl": "Selecciona el estándar de vídeo para tu región.", "edt_conf_v4l2_standard_expl": "Selecciona el estándar de vídeo para tu región.",
"edt_conf_v4l2_resolution_title": "",
"edt_conf_v4l2_resolution_expl": "",
"edt_conf_v4l2_framerate_title": "",
"edt_conf_v4l2_framerate_expl": "",
"edt_conf_v4l2_sizeDecimation_title": "Diezmación de tamaño", "edt_conf_v4l2_sizeDecimation_title": "Diezmación de tamaño",
"edt_conf_v4l2_sizeDecimation_expl": "El factor de diezmación del tamaño", "edt_conf_v4l2_sizeDecimation_expl": "El factor de diezmación del tamaño",
"edt_conf_v4l2_cropLeft_title": "Cortar izquierda", "edt_conf_v4l2_cropLeft_title": "Cortar izquierda",
@ -809,4 +814,4 @@
"edt_eff_ledtest_header_desc": "Salida giratoria: Rojo, Azul, Verde, Blanco, Negro", "edt_eff_ledtest_header_desc": "Salida giratoria: Rojo, Azul, Verde, Blanco, Negro",
"update_no_updates_for_branch": "", "update_no_updates_for_branch": "",
"general_speech_sv": "" "general_speech_sv": ""
} }

View File

@ -431,6 +431,7 @@
"edt_conf_enum_bbclassic": "Classico", "edt_conf_enum_bbclassic": "Classico",
"edt_conf_enum_bbosd": "OSD", "edt_conf_enum_bbosd": "OSD",
"edt_conf_enum_automatic": "Automatico", "edt_conf_enum_automatic": "Automatico",
"edt_conf_enum_custom": "",
"edt_conf_gen_heading_title": "impostazioni Generali", "edt_conf_gen_heading_title": "impostazioni Generali",
"edt_conf_gen_name_title": "Nome configurazione", "edt_conf_gen_name_title": "Nome configurazione",
"edt_conf_gen_name_expl": "Un nome definito dall'utente che viene utilizzato per riconoscere Hyperion. (Utile con più di un'istanza di Hyperion)", "edt_conf_gen_name_expl": "Un nome definito dall'utente che viene utilizzato per riconoscere Hyperion. (Utile con più di un'istanza di Hyperion)",
@ -492,6 +493,10 @@
"edt_conf_v4l2_device_expl": "Percorso del dispositivo di cattura usb.", "edt_conf_v4l2_device_expl": "Percorso del dispositivo di cattura usb.",
"edt_conf_v4l2_standard_title": "Standard video", "edt_conf_v4l2_standard_title": "Standard video",
"edt_conf_v4l2_standard_expl": "Seleziona lo standard video per la tua regione", "edt_conf_v4l2_standard_expl": "Seleziona lo standard video per la tua regione",
"edt_conf_v4l2_resolution_title": "",
"edt_conf_v4l2_resolution_expl": "",
"edt_conf_v4l2_framerate_title": "",
"edt_conf_v4l2_framerate_expl": "",
"edt_conf_v4l2_sizeDecimation_title": "Decimazione dimensione", "edt_conf_v4l2_sizeDecimation_title": "Decimazione dimensione",
"edt_conf_v4l2_sizeDecimation_expl": "Il fattore di decimazione della dimensione", "edt_conf_v4l2_sizeDecimation_expl": "Il fattore di decimazione della dimensione",
"edt_conf_v4l2_cropLeft_title": "Ritaglia sinistra", "edt_conf_v4l2_cropLeft_title": "Ritaglia sinistra",
@ -809,4 +814,4 @@
"edt_eff_ledtest_header_desc": "", "edt_eff_ledtest_header_desc": "",
"update_no_updates_for_branch": "", "update_no_updates_for_branch": "",
"general_speech_sv": "" "general_speech_sv": ""
} }

View File

@ -431,6 +431,7 @@
"edt_conf_enum_bbclassic": "", "edt_conf_enum_bbclassic": "",
"edt_conf_enum_bbosd": "", "edt_conf_enum_bbosd": "",
"edt_conf_enum_automatic": "", "edt_conf_enum_automatic": "",
"edt_conf_enum_custom": "",
"edt_conf_gen_heading_title": "", "edt_conf_gen_heading_title": "",
"edt_conf_gen_name_title": "", "edt_conf_gen_name_title": "",
"edt_conf_gen_name_expl": "", "edt_conf_gen_name_expl": "",
@ -492,6 +493,10 @@
"edt_conf_v4l2_device_expl": "", "edt_conf_v4l2_device_expl": "",
"edt_conf_v4l2_standard_title": "", "edt_conf_v4l2_standard_title": "",
"edt_conf_v4l2_standard_expl": "", "edt_conf_v4l2_standard_expl": "",
"edt_conf_v4l2_resolution_title": "",
"edt_conf_v4l2_resolution_expl": "",
"edt_conf_v4l2_framerate_title": "",
"edt_conf_v4l2_framerate_expl": "",
"edt_conf_v4l2_sizeDecimation_title": "", "edt_conf_v4l2_sizeDecimation_title": "",
"edt_conf_v4l2_sizeDecimation_expl": "", "edt_conf_v4l2_sizeDecimation_expl": "",
"edt_conf_v4l2_cropLeft_title": "", "edt_conf_v4l2_cropLeft_title": "",
@ -809,4 +814,4 @@
"edt_eff_ledtest_header_desc": "", "edt_eff_ledtest_header_desc": "",
"update_no_updates_for_branch": "", "update_no_updates_for_branch": "",
"general_speech_sv": "" "general_speech_sv": ""
} }

View File

@ -431,6 +431,7 @@
"edt_conf_enum_bbclassic": "", "edt_conf_enum_bbclassic": "",
"edt_conf_enum_bbosd": "", "edt_conf_enum_bbosd": "",
"edt_conf_enum_automatic": "", "edt_conf_enum_automatic": "",
"edt_conf_enum_custom": "",
"edt_conf_gen_heading_title": "", "edt_conf_gen_heading_title": "",
"edt_conf_gen_name_title": "", "edt_conf_gen_name_title": "",
"edt_conf_gen_name_expl": "", "edt_conf_gen_name_expl": "",
@ -492,6 +493,10 @@
"edt_conf_v4l2_device_expl": "", "edt_conf_v4l2_device_expl": "",
"edt_conf_v4l2_standard_title": "", "edt_conf_v4l2_standard_title": "",
"edt_conf_v4l2_standard_expl": "", "edt_conf_v4l2_standard_expl": "",
"edt_conf_v4l2_resolution_title": "",
"edt_conf_v4l2_resolution_expl": "",
"edt_conf_v4l2_framerate_title": "",
"edt_conf_v4l2_framerate_expl": "",
"edt_conf_v4l2_sizeDecimation_title": "", "edt_conf_v4l2_sizeDecimation_title": "",
"edt_conf_v4l2_sizeDecimation_expl": "", "edt_conf_v4l2_sizeDecimation_expl": "",
"edt_conf_v4l2_cropLeft_title": "", "edt_conf_v4l2_cropLeft_title": "",
@ -809,4 +814,4 @@
"edt_eff_ledtest_header_desc": "", "edt_eff_ledtest_header_desc": "",
"update_no_updates_for_branch": "", "update_no_updates_for_branch": "",
"general_speech_sv": "" "general_speech_sv": ""
} }

View File

@ -431,6 +431,7 @@
"edt_conf_enum_bbclassic": "", "edt_conf_enum_bbclassic": "",
"edt_conf_enum_bbosd": "", "edt_conf_enum_bbosd": "",
"edt_conf_enum_automatic": "", "edt_conf_enum_automatic": "",
"edt_conf_enum_custom": "",
"edt_conf_gen_heading_title": "", "edt_conf_gen_heading_title": "",
"edt_conf_gen_name_title": "", "edt_conf_gen_name_title": "",
"edt_conf_gen_name_expl": "", "edt_conf_gen_name_expl": "",
@ -492,6 +493,10 @@
"edt_conf_v4l2_device_expl": "", "edt_conf_v4l2_device_expl": "",
"edt_conf_v4l2_standard_title": "", "edt_conf_v4l2_standard_title": "",
"edt_conf_v4l2_standard_expl": "", "edt_conf_v4l2_standard_expl": "",
"edt_conf_v4l2_resolution_title": "",
"edt_conf_v4l2_resolution_expl": "",
"edt_conf_v4l2_framerate_title": "",
"edt_conf_v4l2_framerate_expl": "",
"edt_conf_v4l2_sizeDecimation_title": "", "edt_conf_v4l2_sizeDecimation_title": "",
"edt_conf_v4l2_sizeDecimation_expl": "", "edt_conf_v4l2_sizeDecimation_expl": "",
"edt_conf_v4l2_cropLeft_title": "", "edt_conf_v4l2_cropLeft_title": "",
@ -809,4 +814,4 @@
"edt_eff_ledtest_header_desc": "", "edt_eff_ledtest_header_desc": "",
"update_no_updates_for_branch": "", "update_no_updates_for_branch": "",
"general_speech_sv": "" "general_speech_sv": ""
} }

View File

@ -431,6 +431,7 @@
"edt_conf_enum_bbclassic": "Klassisk", "edt_conf_enum_bbclassic": "Klassisk",
"edt_conf_enum_bbosd": "OSD", "edt_conf_enum_bbosd": "OSD",
"edt_conf_enum_automatic": "Automatisk", "edt_conf_enum_automatic": "Automatisk",
"edt_conf_enum_custom": "",
"edt_conf_gen_heading_title": "Allmänna Inställningar", "edt_conf_gen_heading_title": "Allmänna Inställningar",
"edt_conf_gen_name_title": "Konfigurationsnamn", "edt_conf_gen_name_title": "Konfigurationsnamn",
"edt_conf_gen_name_expl": "Ett användardefinierat namn som används för att identifiera Hyperion. (Hjälpsamt om du har mer än en Hyperion-instans)", "edt_conf_gen_name_expl": "Ett användardefinierat namn som används för att identifiera Hyperion. (Hjälpsamt om du har mer än en Hyperion-instans)",
@ -492,6 +493,10 @@
"edt_conf_v4l2_device_expl": "Sökvägen till USB-fångstgränssnittet. Ställ in på 'auto' för automatisk upptäckt. Exempel: '/dev/video0'", "edt_conf_v4l2_device_expl": "Sökvägen till USB-fångstgränssnittet. Ställ in på 'auto' för automatisk upptäckt. Exempel: '/dev/video0'",
"edt_conf_v4l2_standard_title": "Videostandard", "edt_conf_v4l2_standard_title": "Videostandard",
"edt_conf_v4l2_standard_expl": "Välj videostandard för din region. 'Auto' behåller det värde som väljs av v4l2-gränssnittet", "edt_conf_v4l2_standard_expl": "Välj videostandard för din region. 'Auto' behåller det värde som väljs av v4l2-gränssnittet",
"edt_conf_v4l2_resolution_title": "",
"edt_conf_v4l2_resolution_expl": "",
"edt_conf_v4l2_framerate_title": "",
"edt_conf_v4l2_framerate_expl": "",
"edt_conf_v4l2_sizeDecimation_title": "Bildreduktionsfaktor", "edt_conf_v4l2_sizeDecimation_title": "Bildreduktionsfaktor",
"edt_conf_v4l2_sizeDecimation_expl": "Faktorn för bildminskning baserad på originalstorleken, 1 betyder ingen förändring (originalbild).", "edt_conf_v4l2_sizeDecimation_expl": "Faktorn för bildminskning baserad på originalstorleken, 1 betyder ingen förändring (originalbild).",
"edt_conf_v4l2_cropLeft_title": "Beskär vänster", "edt_conf_v4l2_cropLeft_title": "Beskär vänster",

View File

@ -4,39 +4,171 @@ $(document).ready( function() {
var conf_editor_fg = null; var conf_editor_fg = null;
var conf_editor_instCapt = null; var conf_editor_instCapt = null;
function hideEl(el) // Dynamic v4l2 enum schema
{ var v4l2_dynamic_enum_schema = {
for(var i = 0; i<el.length; i++) "available_devices":
{ {
$('[data-schemapath*="root.framegrabber.'+el[i]+'"]').toggle(false); "type": "string",
"title": "edt_conf_v4l2_device_title",
"propertyOrder" : 1,
"required" : true
},
"resolutions":
{
"type": "string",
"title": "edt_conf_v4l2_resolution_title",
"propertyOrder" : 4,
"required" : true
},
"framerates":
{
"type": "string",
"title": "edt_conf_v4l2_framerate_title",
"propertyOrder" : 7,
"required" : true
} }
};
// Build dynamic v4l2 enum schema parts
var buildSchemaPart = function(key, schema, device) {
if (schema[key]) {
var enumVals = [];
var enumTitelVals = [];
var v4l2_properties = JSON.parse(JSON.stringify(window.serverInfo.grabbers.v4l2_properties));
if (key === 'available_devices') {
for (var i = 0; i < v4l2_properties.length; i++) {
enumVals.push(v4l2_properties[i]['device']);
v4l2_properties[i].hasOwnProperty('name')
? enumTitelVals.push(v4l2_properties[i]['name'])
: enumTitelVals.push(v4l2_properties[i]['device']);
}
} else if (key == 'resolutions' || key == 'framerates') {
for (var i = 0; i < v4l2_properties.length; i++) {
if (v4l2_properties[i]['device'] == device) {
enumVals = enumTitelVals = v4l2_properties[i][key];
break;
}
}
}
window.schema.grabberV4L2.properties[key] = {
"type": schema[key].type,
"title": schema[key].title,
"enum": [].concat(["auto"], enumVals, ["custom"]),
"options" :
{
"enum_titles" : [].concat(["edt_conf_enum_automatic"], enumTitelVals, ["edt_conf_enum_custom"]),
},
"propertyOrder" : schema[key].propertyOrder,
"required" : schema[key].required
};
}
};
// Switch between visible states
function toggleOption(option, state) {
$('[data-schemapath*="root.grabberV4L2.'+option+'"]').toggle(state);
if (state) (
$('[data-schemapath*="root.grabberV4L2.'+option+'"]').addClass('col-md-12'),
$('label[for="root_grabberV4L2_'+option+'"]').css('left','10px'),
$('[id="root_grabberV4L2_'+option+'"]').css('left','10px')
);
} }
if(window.showOptHelp) // Watch all v4l2 dynamic fields
{ var setWatchers = function(schema) {
//fg var path = 'root.grabberV4L2.';
Object.keys(schema).forEach(function(key) {
conf_editor_v4l2.watch(path + key, function() {
var ed = conf_editor_v4l2.getEditor(path + key);
var val = ed.getValue();
if (key == 'available_devices') {
var V4L2properties = ['resolutions', 'framerates'];
if (val == 'custom') {
var grabberV4L2 = ed.parent;
V4L2properties.forEach(function(item) {
buildSchemaPart(item, v4l2_dynamic_enum_schema, 'none');
grabberV4L2.original_schema.properties[item] = window.schema.grabberV4L2.properties[item];
grabberV4L2.schema.properties[item] = window.schema.grabberV4L2.properties[item];
grabberV4L2.removeObjectProperty(item);
delete grabberV4L2.cached_editors[item];
grabberV4L2.addObjectProperty(item);
conf_editor_v4l2.getEditor(path + item).enable();
});
toggleOption('device', true);
} else if (val == 'auto') {
V4L2properties.forEach(function(item) {
conf_editor_v4l2.getEditor(path + item).setValue('auto');
conf_editor_v4l2.getEditor(path + item).disable();
});
(toggleOption('device', false), toggleOption('width', false),
toggleOption('height', false), toggleOption('fps', false));
} else {
var grabberV4L2 = ed.parent;
V4L2properties.forEach(function(item) {
buildSchemaPart(item, v4l2_dynamic_enum_schema, val);
grabberV4L2.original_schema.properties[item] = window.schema.grabberV4L2.properties[item];
grabberV4L2.schema.properties[item] = window.schema.grabberV4L2.properties[item];
grabberV4L2.removeObjectProperty(item);
delete grabberV4L2.cached_editors[item];
grabberV4L2.addObjectProperty(item);
conf_editor_v4l2.getEditor(path + item).enable();
});
toggleOption('device', false);
}
}
if (key == 'resolutions')
val != 'custom'
? (toggleOption('width', false), toggleOption('height', false))
: (toggleOption('width', true), toggleOption('height', true));
if (key == 'framerates')
val != 'custom'
? toggleOption('fps', false)
: toggleOption('fps', true);
});
});
};
// Insert dynamic v4l2 enum schema parts
Object.keys(v4l2_dynamic_enum_schema).forEach(function(key) {
buildSchemaPart(key, v4l2_dynamic_enum_schema, window.serverConfig.grabberV4L2.device);
});
if(window.showOptHelp) {
// Instance Capture
$('#conf_cont').append(createRow('conf_cont_instCapt')); $('#conf_cont').append(createRow('conf_cont_instCapt'));
$('#conf_cont_instCapt').append(createOptPanel('fa-camera', $.i18n("edt_conf_instCapture_heading_title"), 'editor_container_instCapt', 'btn_submit_instCapt')); $('#conf_cont_instCapt').append(createOptPanel('fa-camera', $.i18n("edt_conf_instCapture_heading_title"), 'editor_container_instCapt', 'btn_submit_instCapt'));
$('#conf_cont_instCapt').append(createHelpTable(window.schema.instCapture.properties, $.i18n("edt_conf_instCapture_heading_title"))); $('#conf_cont_instCapt').append(createHelpTable(window.schema.instCapture.properties, $.i18n("edt_conf_instCapture_heading_title")));
//fg // Framegrabber
$('#conf_cont').append(createRow('conf_cont_fg')); $('#conf_cont').append(createRow('conf_cont_fg'));
$('#conf_cont_fg').append(createOptPanel('fa-camera', $.i18n("edt_conf_fg_heading_title"), 'editor_container_fg', 'btn_submit_fg')); $('#conf_cont_fg').append(createOptPanel('fa-camera', $.i18n("edt_conf_fg_heading_title"), 'editor_container_fg', 'btn_submit_fg'));
$('#conf_cont_fg').append(createHelpTable(window.schema.framegrabber.properties, $.i18n("edt_conf_fg_heading_title"))); $('#conf_cont_fg').append(createHelpTable(window.schema.framegrabber.properties, $.i18n("edt_conf_fg_heading_title")));
//v4l // V4L2
$('#conf_cont').append(createRow('conf_cont_v4l')); $('#conf_cont').append(createRow('conf_cont_v4l'));
$('#conf_cont_v4l').append(createOptPanel('fa-camera', $.i18n("edt_conf_v4l2_heading_title"), 'editor_container_v4l2', 'btn_submit_v4l2')); $('#conf_cont_v4l').append(createOptPanel('fa-camera', $.i18n("edt_conf_v4l2_heading_title"), 'editor_container_v4l2', 'btn_submit_v4l2'));
$('#conf_cont_v4l').append(createHelpTable(window.schema.grabberV4L2.properties, $.i18n("edt_conf_v4l2_heading_title"))); $('#conf_cont_v4l').append(createHelpTable(window.schema.grabberV4L2.properties, $.i18n("edt_conf_v4l2_heading_title")));
} } else {
else
{
$('#conf_cont').addClass('row'); $('#conf_cont').addClass('row');
$('#conf_cont').append(createOptPanel('fa-camera', $.i18n("edt_conf_instCapture_heading_title"), 'editor_container_instCapt', 'btn_submit_instCapt')); $('#conf_cont').append(createOptPanel('fa-camera', $.i18n("edt_conf_instCapture_heading_title"), 'editor_container_instCapt', 'btn_submit_instCapt'));
$('#conf_cont').append(createOptPanel('fa-camera', $.i18n("edt_conf_fg_heading_title"), 'editor_container_fg', 'btn_submit_fg')); $('#conf_cont').append(createOptPanel('fa-camera', $.i18n("edt_conf_fg_heading_title"), 'editor_container_fg', 'btn_submit_fg'));
$('#conf_cont').append(createOptPanel('fa-camera', $.i18n("edt_conf_v4l2_heading_title"), 'editor_container_v4l2', 'btn_submit_v4l2')); $('#conf_cont').append(createOptPanel('fa-camera', $.i18n("edt_conf_v4l2_heading_title"), 'editor_container_v4l2', 'btn_submit_v4l2'));
} }
//instCapt
// Instance Capture
conf_editor_instCapt = createJsonEditor('editor_container_instCapt', { conf_editor_instCapt = createJsonEditor('editor_container_instCapt', {
instCapture: window.schema.instCapture instCapture: window.schema.instCapture
}, true, true); }, true, true);
@ -49,8 +181,7 @@ $(document).ready( function() {
requestWriteConfig(conf_editor_instCapt.getValue()); requestWriteConfig(conf_editor_instCapt.getValue());
}); });
// Framegrabber
//fg
conf_editor_fg = createJsonEditor('editor_container_fg', { conf_editor_fg = createJsonEditor('editor_container_fg', {
framegrabber: window.schema.framegrabber framegrabber: window.schema.framegrabber
}, true, true); }, true, true);
@ -63,7 +194,6 @@ $(document).ready( function() {
requestWriteConfig(conf_editor_fg.getValue()); requestWriteConfig(conf_editor_fg.getValue());
}); });
//vl4
conf_editor_v4l2 = createJsonEditor('editor_container_v4l2', { conf_editor_v4l2 = createJsonEditor('editor_container_v4l2', {
grabberV4L2 : window.schema.grabberV4L2 grabberV4L2 : window.schema.grabberV4L2
}, true, true); }, true, true);
@ -72,28 +202,80 @@ $(document).ready( function() {
conf_editor_v4l2.validate().length ? $('#btn_submit_v4l2').attr('disabled', true) : $('#btn_submit_v4l2').attr('disabled', false); conf_editor_v4l2.validate().length ? $('#btn_submit_v4l2').attr('disabled', true) : $('#btn_submit_v4l2').attr('disabled', false);
}); });
$('#btn_submit_v4l2').off().on('click',function() { conf_editor_v4l2.on('ready', function() {
requestWriteConfig(conf_editor_v4l2.getValue()); setWatchers(v4l2_dynamic_enum_schema);
if (window.serverConfig.grabberV4L2.available_devices == 'custom' && window.serverConfig.grabberV4L2.device != 'auto')
toggleOption('device', true);
if (window.serverConfig.grabberV4L2.device == 'auto')
conf_editor_v4l2.getEditor('root.grabberV4L2.available_devices').setValue('auto');
if (window.serverConfig.grabberV4L2.available_devices == 'auto') {
['resolutions', 'framerates'].forEach(function(item) {
conf_editor_v4l2.getEditor('root.grabberV4L2.' + item).setValue('auto');
conf_editor_v4l2.getEditor('root.grabberV4L2.' + item).disable();
});
}
if (window.serverConfig.grabberV4L2.resolutions == 'custom' && window.serverConfig.grabberV4L2.device != 'auto')
(toggleOption('width', true), toggleOption('height', true));
if (window.serverConfig.grabberV4L2.framerates == 'custom' && window.serverConfig.grabberV4L2.device != 'auto')
toggleOption('fps', true);
}); });
$('#btn_submit_v4l2').off().on('click',function() {
var v4l2Options = conf_editor_v4l2.getValue()
if (v4l2Options.grabberV4L2.available_devices != 'custom' && v4l2Options.grabberV4L2.available_devices != 'auto')
v4l2Options.grabberV4L2.device = v4l2Options.grabberV4L2.available_devices;
if (v4l2Options.grabberV4L2.available_devices == 'auto')
v4l2Options.grabberV4L2.device = 'auto';
if (v4l2Options.grabberV4L2.resolutions != 'custom' && v4l2Options.grabberV4L2.resolutions != 'auto' && v4l2Options.grabberV4L2.available_devices != 'auto')
(v4l2Options.grabberV4L2.width = parseInt(v4l2Options.grabberV4L2.resolutions.split('x')[0]),
v4l2Options.grabberV4L2.height = parseInt(v4l2Options.grabberV4L2.resolutions.split('x')[1]));
if (v4l2Options.grabberV4L2.resolutions == 'auto')
(v4l2Options.grabberV4L2.width = 0, v4l2Options.grabberV4L2.height = 0);
if (v4l2Options.grabberV4L2.framerates != 'custom' && v4l2Options.grabberV4L2.framerates != 'auto' && v4l2Options.grabberV4L2.available_devices != 'auto')
v4l2Options.grabberV4L2.fps = parseInt(v4l2Options.grabberV4L2.framerates);
if (v4l2Options.grabberV4L2.framerates == 'auto')
v4l2Options.grabberV4L2.fps = 15;
requestWriteConfig(v4l2Options);
});
//////////////////////////////////////////////////
//create introduction //create introduction
if(window.showOptHelp) if(window.showOptHelp) {
{
createHint("intro", $.i18n('conf_grabber_fg_intro'), "editor_container_fg"); createHint("intro", $.i18n('conf_grabber_fg_intro'), "editor_container_fg");
createHint("intro", $.i18n('conf_grabber_v4l_intro'), "editor_container_v4l2"); createHint("intro", $.i18n('conf_grabber_v4l_intro'), "editor_container_v4l2");
} }
function hideEl(el) {
for(var i = 0; i<el.length; i++) {
$('[data-schemapath*="root.framegrabber.'+el[i]+'"]').toggle(false);
}
}
//hide specific options //hide specific options
conf_editor_fg.on('ready',function() { conf_editor_fg.on('ready',function() {
var grabbers = window.serverInfo.grabbers.available; var grabbers = window.serverInfo.grabbers.available;
if(grabbers.indexOf('dispmanx') > -1) if (grabbers.indexOf('dispmanx') > -1)
hideEl(["device","pixelDecimation"]); hideEl(["device","pixelDecimation"]);
else if(grabbers.indexOf('x11') > -1) else if (grabbers.indexOf('x11') > -1)
hideEl(["device","width","height"]); hideEl(["device","width","height"]);
else if(grabbers.indexOf('osx') > -1 ) else if (grabbers.indexOf('osx') > -1 )
hideEl(["device","pixelDecimation"]); hideEl(["device","pixelDecimation"]);
else if(grabbers.indexOf('amlogic') > -1) else if (grabbers.indexOf('amlogic') > -1)
hideEl(["pixelDecimation"]); hideEl(["pixelDecimation"]);
}); });

View File

@ -216,7 +216,7 @@ private:
/// ///
void handleConfigCommand(const QJsonObject &message, const QString &command, const int tan); void handleConfigCommand(const QJsonObject &message, const QString &command, const int tan);
/// Handle an incoming JSON GetConfig message from handleConfigCommand() /// Handle an incoming JSON GetSchema message from handleConfigCommand()
/// ///
/// @param message the incoming message /// @param message the incoming message
/// ///
@ -297,4 +297,4 @@ private:
/// @brief Kill all signal/slot connections to stop possible data emitter /// @brief Kill all signal/slot connections to stop possible data emitter
/// ///
void stopDataConnections(void); void stopDataConnections(void);
}; };

View File

@ -8,6 +8,7 @@
#include <QObject> #include <QObject>
#include <QSocketNotifier> #include <QSocketNotifier>
#include <QRectF> #include <QRectF>
#include <QMap>
// util includes // util includes
#include <utils/PixelFormat.h> #include <utils/PixelFormat.h>
@ -40,6 +41,13 @@ class V4L2Grabber : public Grabber
Q_OBJECT Q_OBJECT
public: public:
struct DeviceProperties
{
QString name = QString();
QStringList resolutions = QStringList();
QStringList framerates = QStringList();
};
V4L2Grabber(const QString & device, V4L2Grabber(const QString & device,
const unsigned width, const unsigned width,
const unsigned height, const unsigned height,
@ -48,7 +56,7 @@ public:
PixelFormat pixelFormat, PixelFormat pixelFormat,
int pixelDecimation int pixelDecimation
); );
virtual ~V4L2Grabber(); ~V4L2Grabber() override;
QRectF getSignalDetectionOffset() QRectF getSignalDetectionOffset()
{ {
@ -63,44 +71,64 @@ public:
/// @brief set new PixelDecimation value to ImageResampler /// @brief set new PixelDecimation value to ImageResampler
/// @param pixelDecimation The new pixelDecimation value /// @param pixelDecimation The new pixelDecimation value
/// ///
virtual void setPixelDecimation(int pixelDecimation); void setPixelDecimation(int pixelDecimation) override;
/// ///
/// @brief overwrite Grabber.h implementation /// @brief overwrite Grabber.h implementation
/// ///
virtual void setSignalThreshold( void setSignalThreshold(
double redSignalThreshold, double redSignalThreshold,
double greenSignalThreshold, double greenSignalThreshold,
double blueSignalThreshold, double blueSignalThreshold,
int noSignalCounterThreshold = 50); int noSignalCounterThreshold = 50) override;
/// ///
/// @brief overwrite Grabber.h implementation /// @brief overwrite Grabber.h implementation
/// ///
virtual void setSignalDetectionOffset( void setSignalDetectionOffset(
double verticalMin, double verticalMin,
double horizontalMin, double horizontalMin,
double verticalMax, double verticalMax,
double horizontalMax); double horizontalMax) override;
/// ///
/// @brief overwrite Grabber.h implementation /// @brief overwrite Grabber.h implementation
/// ///
virtual void setSignalDetectionEnable(bool enable); void setSignalDetectionEnable(bool enable) override;
///
/// @brief overwrite Grabber.h implementation
///
virtual void setDeviceVideoStandard(QString device, VideoStandard videoStandard);
///
/// @brief overwrite Grabber.h implementation
///
virtual bool setFramerate(int fps);
/// ///
/// @brief overwrite Grabber.h implementation /// @brief overwrite Grabber.h implementation
/// ///
virtual bool setWidthHeight(int width, int height); void setDeviceVideoStandard(QString device, VideoStandard videoStandard) override;
///
/// @brief overwrite Grabber.h implementation
///
bool setFramerate(int fps) override;
///
/// @brief overwrite Grabber.h implementation
///
bool setWidthHeight(int width, int height) override;
///
/// @brief overwrite Grabber.h implementation
///
QStringList getV4L2devices() override;
///
/// @brief overwrite Grabber.h implementation
///
QString getV4L2deviceName(QString devicePath) override;
///
/// @brief overwrite Grabber.h implementation
///
QStringList getResolutions(QString devicePath) override;
///
/// @brief overwrite Grabber.h implementation
///
QStringList getFramerates(QString devicePath) override;
public slots: public slots:
@ -145,6 +173,8 @@ private:
int xioctl(int request, void *arg); int xioctl(int request, void *arg);
int xioctl(int fileDescriptor, int request, void *arg);
void throw_exception(const QString & error) void throw_exception(const QString & error)
{ {
Error(_log, "Throws error: %s", QSTRING_CSTR(error)); Error(_log, "Throws error: %s", QSTRING_CSTR(error));
@ -198,12 +228,13 @@ private:
private: private:
QString _deviceName; QString _deviceName;
std::map<QString,QString> _v4lDevices; std::map<QString, QString> _v4lDevices;
int _input; QMap<QString, V4L2Grabber::DeviceProperties> _deviceProperties;
VideoStandard _videoStandard; int _input;
io_method _ioMethod; VideoStandard _videoStandard;
int _fileDescriptor; io_method _ioMethod;
std::vector<buffer> _buffers; int _fileDescriptor;
std::vector<buffer> _buffers;
PixelFormat _pixelFormat; PixelFormat _pixelFormat;
int _pixelDecimation; int _pixelDecimation;
@ -225,4 +256,7 @@ private:
bool _initialized; bool _initialized;
bool _deviceAutoDiscoverEnabled; bool _deviceAutoDiscoverEnabled;
protected:
void enumFrameIntervals(QStringList &framerates, int fileDescriptor, int pixelformat, int width, int height);
}; };

View File

@ -20,7 +20,7 @@ class Grabber : public QObject
Q_OBJECT Q_OBJECT
public: public:
Grabber(QString grabberName, int width=0, int height=0, int cropLeft=0, int cropRight=0, int cropTop=0, int cropBottom=0); Grabber(QString grabberName = "", int width=0, int height=0, int cropLeft=0, int cropRight=0, int cropTop=0, int cropBottom=0);
virtual ~Grabber(); virtual ~Grabber();
/// ///
@ -42,14 +42,14 @@ public:
/// ///
/// @brief Apply new framerate (used from v4l) /// @brief Apply new framerate (used from v4l)
/// @param fps framesPerSecond /// @param fps framesPerSecond
/// ///
virtual bool setFramerate(int fps); virtual bool setFramerate(int fps);
/// ///
/// @brief Apply new pixelDecimation (used from x11 and qt) /// @brief Apply new pixelDecimation (used from x11 and qt)
/// ///
virtual void setPixelDecimation(int pixelDecimation) {}; virtual void setPixelDecimation(int pixelDecimation) {}
/// ///
/// @brief Apply new signalThreshold (used from v4l) /// @brief Apply new signalThreshold (used from v4l)
@ -58,7 +58,7 @@ public:
double redSignalThreshold, double redSignalThreshold,
double greenSignalThreshold, double greenSignalThreshold,
double blueSignalThreshold, double blueSignalThreshold,
int noSignalCounterThreshold = 50) {}; int noSignalCounterThreshold = 50) {}
/// ///
/// @brief Apply new SignalDetectionOffset (used from v4l) /// @brief Apply new SignalDetectionOffset (used from v4l)
/// ///
@ -66,43 +66,70 @@ public:
double verticalMin, double verticalMin,
double horizontalMin, double horizontalMin,
double verticalMax, double verticalMax,
double horizontalMax) {}; double horizontalMax) {}
/// ///
/// @brief Apply SignalDetectionEnable (used from v4l) /// @brief Apply SignalDetectionEnable (used from v4l)
/// ///
virtual void setSignalDetectionEnable(bool enable) {}; virtual void setSignalDetectionEnable(bool enable) {}
/// ///
/// @brief Apply device and videoStanded (used from v4l) /// @brief Apply device and videoStanded (used from v4l)
/// ///
virtual void setDeviceVideoStandard(QString device, VideoStandard videoStandard) {}; virtual void setDeviceVideoStandard(QString device, VideoStandard videoStandard) {}
/// ///
/// @brief Apply display index (used from qt) /// @brief Apply display index (used from qt)
/// ///
virtual void setDisplayIndex(int index) {}; virtual void setDisplayIndex(int index) {}
/// ///
/// @brief Apply path for device (used from framebuffer) /// @brief Apply path for device (used from framebuffer)
/// ///
virtual void setDevicePath(const QString& path) {}; virtual void setDevicePath(const QString& path) {}
/// ///
/// @brief get current resulting height of image (after crop) /// @brief get current resulting height of image (after crop)
/// ///
virtual int getImageWidth() { return _width; }; virtual int getImageWidth() { return _width; }
/// ///
/// @brief get current resulting width of image (after crop) /// @brief get current resulting width of image (after crop)
/// ///
virtual int getImageHeight() { return _height; }; virtual int getImageHeight() { return _height; }
/// ///
/// @brief Prevent the real capture implementation from capturing if disabled /// @brief Prevent the real capture implementation from capturing if disabled
/// ///
void setEnabled(bool enable); void setEnabled(bool enable);
///
/// @brief Get a list of all available V4L devices
/// @return List of all available V4L devices on success else empty List
///
virtual QStringList getV4L2devices() { return QStringList(); }
///
/// @brief Get the V4L device name
/// @param devicePath The device path
/// @return The name of the V4L device on success else empty String
///
virtual QString getV4L2deviceName(QString devicePath) { return QString(); }
///
/// @brief Get a list of supported device resolutions
/// @param devicePath The device path
/// @return List of resolutions on success else empty List
///
virtual QStringList getResolutions(QString devicePath) { return QStringList(); }
///
/// @brief Get a list of supported device framerates
/// @param devicePath The device path
/// @return List of framerates on success else empty List
///
virtual QStringList getFramerates(QString devicePath) { return QStringList(); }
protected: protected:
ImageResampler _imageResampler; ImageResampler _imageResampler;

View File

@ -32,6 +32,9 @@ public:
virtual ~GrabberWrapper(); virtual ~GrabberWrapper();
static GrabberWrapper* instance;
static GrabberWrapper* getInstance(){ return instance; }
/// ///
/// Starts the grabber wich produces led values with the specified update rate /// Starts the grabber wich produces led values with the specified update rate
/// ///
@ -47,6 +50,33 @@ public:
/// ///
virtual void stop(); virtual void stop();
///
/// @brief Get a list of all available V4L devices
/// @return List of all available V4L devices on success else empty List
///
virtual QStringList getV4L2devices();
///
/// @brief Get the V4L device name
/// @param devicePath The device path
/// @return The name of the V4L device on success else empty String
///
virtual QString getV4L2deviceName(QString devicePath);
///
/// @brief Get a list of supported device resolutions
/// @param devicePath The device path
/// @return List of resolutions on success else empty List
///
virtual QStringList getResolutions(QString devicePath);
///
/// @brief Get a list of supported device framerates
/// @param devicePath The device path
/// @return List of framerates on success else empty List
///
virtual QStringList getFramerates(QString devicePath);
static QStringList availableGrabbers(); static QStringList availableGrabbers();
public: public:

View File

@ -469,14 +469,51 @@ void JsonAPI::handleServerInfoCommand(const QJsonObject &message, const QString
QJsonObject grabbers; QJsonObject grabbers;
QJsonArray availableGrabbers; QJsonArray availableGrabbers;
QJsonObject availableProperties;
#if defined(ENABLE_DISPMANX) || defined(ENABLE_V4L2) || defined(ENABLE_FB) || defined(ENABLE_AMLOGIC) || defined(ENABLE_OSX) || defined(ENABLE_X11) #if defined(ENABLE_DISPMANX) || defined(ENABLE_V4L2) || defined(ENABLE_FB) || defined(ENABLE_AMLOGIC) || defined(ENABLE_OSX) || defined(ENABLE_X11)
// get available grabbers // get available grabbers
//grabbers["active"] = ????; //grabbers["active"] = ????;
for (auto grabber : GrabberWrapper::availableGrabbers()) for (auto grabber : GrabberWrapper::availableGrabbers())
{ {
availableGrabbers.append(grabber); availableGrabbers.append(grabber);
} }
#endif #endif
#if defined(ENABLE_V4L2)
QJsonArray availableV4L2devices;
for (auto devicePath : GrabberWrapper::getInstance()->getV4L2devices())
{
QJsonObject device;
device["device"] = devicePath;
device["name"] = GrabberWrapper::getInstance()->getV4L2deviceName(devicePath);
QJsonArray availableResolutions;
for (auto resolution : GrabberWrapper::getInstance()->getResolutions(devicePath))
{
availableResolutions.append(resolution);
}
device.insert("resolutions", availableResolutions);
QJsonArray availableFramerates;
for (auto framerate : GrabberWrapper::getInstance()->getFramerates(devicePath))
{
availableFramerates.append(framerate);
}
device.insert("framerates", availableFramerates);
availableV4L2devices.append(device);
}
grabbers["v4l2_properties"] = availableV4L2devices;
#endif
grabbers["available"] = availableGrabbers; grabbers["available"] = availableGrabbers;
info["videomode"] = QString(videoMode2String(_hyperion->getCurrentVideoMode())); info["videomode"] = QString(videoMode2String(_hyperion->getCurrentVideoMode()));
info["grabbers"] = grabbers; info["grabbers"] = grabbers;

View File

@ -26,6 +26,10 @@
#define CLEAR(x) memset(&(x), 0, sizeof(x)) #define CLEAR(x) memset(&(x), 0, sizeof(x))
#ifndef V4L2_CAP_META_CAPTURE
#define V4L2_CAP_META_CAPTURE 0x00800000 // Specified in kernel header v4.16. Required for backward compatibility.
#endif
V4L2Grabber::V4L2Grabber(const QString & device V4L2Grabber::V4L2Grabber(const QString & device
, const unsigned width , const unsigned width
, const unsigned height , const unsigned height
@ -84,13 +88,13 @@ void V4L2Grabber::uninit()
bool V4L2Grabber::init() bool V4L2Grabber::init()
{ {
if (! _initialized) if (!_initialized)
{ {
getV4Ldevices(); getV4Ldevices();
QString v4lDevices_str; QString v4lDevices_str;
// show list only once // show list only once
if ( ! QString(QSTRING_CSTR(_deviceName)).startsWith("/dev/") ) if (!QString(QSTRING_CSTR(_deviceName)).startsWith("/dev/"))
{ {
for (auto& dev: _v4lDevices) for (auto& dev: _v4lDevices)
{ {
@ -100,7 +104,7 @@ bool V4L2Grabber::init()
Info(_log, "available V4L2 devices:\n%s", QSTRING_CSTR(v4lDevices_str)); Info(_log, "available V4L2 devices:\n%s", QSTRING_CSTR(v4lDevices_str));
} }
if ( _deviceName == "auto" ) if (_deviceName == "auto")
{ {
_deviceAutoDiscoverEnabled = true; _deviceAutoDiscoverEnabled = true;
_deviceName = "unknown"; _deviceName = "unknown";
@ -108,20 +112,20 @@ bool V4L2Grabber::init()
for (auto& dev: _v4lDevices) for (auto& dev: _v4lDevices)
{ {
_deviceName = dev.first; _deviceName = dev.first;
if ( init() ) if (init())
{ {
Info(_log, "found usable v4l2 device: %s (%s)",QSTRING_CSTR(dev.first), QSTRING_CSTR(dev.second)); Info(_log, "found usable v4l2 device: %s (%s)",QSTRING_CSTR(dev.first), QSTRING_CSTR(dev.second));
_deviceAutoDiscoverEnabled = false; _deviceAutoDiscoverEnabled = false;
return _initialized; return _initialized;
} }
} }
Info( _log, "no usable device found" ); Info(_log, "no usable device found");
} }
else if ( ! _deviceName.startsWith("/dev/") ) else if (!_deviceName.startsWith("/dev/"))
{ {
for (auto& dev: _v4lDevices) for (auto& dev: _v4lDevices)
{ {
if ( _deviceName.toLower() == dev.second.toLower() ) if (_deviceName.toLower() == dev.second.toLower())
{ {
_deviceName = dev.first; _deviceName = dev.first;
Info(_log, "found v4l2 device with configured name: %s (%s)", QSTRING_CSTR(dev.second), QSTRING_CSTR(dev.first) ); Info(_log, "found v4l2 device with configured name: %s (%s)", QSTRING_CSTR(dev.second), QSTRING_CSTR(dev.first) );
@ -138,7 +142,7 @@ bool V4L2Grabber::init()
try try
{ {
// do not init with unknown device // do not init with unknown device
if(_deviceName != "unknown") if (_deviceName != "unknown")
{ {
if (open_device()) if (open_device())
{ {
@ -165,22 +169,96 @@ bool V4L2Grabber::init()
void V4L2Grabber::getV4Ldevices() void V4L2Grabber::getV4Ldevices()
{ {
QDirIterator it("/sys/class/video4linux/", QDirIterator::NoIteratorFlags); QDirIterator it("/sys/class/video4linux/", QDirIterator::NoIteratorFlags);
_deviceProperties.clear();
while(it.hasNext()) while(it.hasNext())
{ {
//_v4lDevices //_v4lDevices
QString dev = it.next(); QString dev = it.next();
if (it.fileName().startsWith("video")) if (it.fileName().startsWith("video"))
{ {
QString devName = "/dev/" + it.fileName();
int fd = open(QSTRING_CSTR(devName), O_RDWR | O_NONBLOCK, 0);
if (fd < 0)
{
throw_errno_exception("Cannot open '" + devName + "'");
continue;
}
struct v4l2_capability cap;
CLEAR(cap);
if (xioctl(fd, VIDIOC_QUERYCAP, &cap) < 0)
{
throw_errno_exception("'" + devName + "' is no V4L2 device");
close(fd);
continue;
}
if (cap.device_caps & V4L2_CAP_META_CAPTURE) // this device has bit 23 set (and bit 1 reset), so it doesn't have capture.
{
close(fd);
continue;
}
// get the current settings
struct v4l2_format fmt;
CLEAR(fmt);
fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
if (xioctl(fd, VIDIOC_G_FMT, &fmt) < 0)
{
close(fd);
continue;
}
V4L2Grabber::DeviceProperties properties;
// collect available device resolutions & frame rates
struct v4l2_frmsizeenum frmsizeenum;
CLEAR(frmsizeenum);
frmsizeenum.index = 0;
frmsizeenum.pixel_format = fmt.fmt.pix.pixelformat;
while (xioctl(fd, VIDIOC_ENUM_FRAMESIZES, &frmsizeenum) >= 0)
{
switch (frmsizeenum.type)
{
case V4L2_FRMSIZE_TYPE_DISCRETE:
{
properties.resolutions << QString::number(frmsizeenum.discrete.width) + "x" + QString::number(frmsizeenum.discrete.height);
enumFrameIntervals(properties.framerates, fd, fmt.fmt.pix.pixelformat, frmsizeenum.discrete.width, frmsizeenum.discrete.height);
}
break;
case V4L2_FRMSIZE_TYPE_CONTINUOUS:
case V4L2_FRMSIZE_TYPE_STEPWISE:
{
for(unsigned int y = frmsizeenum.stepwise.min_height; y <= frmsizeenum.stepwise.max_height; y += frmsizeenum.stepwise.step_height)
{
for(unsigned int x = frmsizeenum.stepwise.min_width; x <= frmsizeenum.stepwise.max_width; x += frmsizeenum.stepwise.step_width)
{
properties.resolutions << QString::number(x) + "x" + QString::number(y);
enumFrameIntervals(properties.framerates, fd, fmt.fmt.pix.pixelformat, x, y);
}
}
}
}
frmsizeenum.index++;
}
if (close(fd) < 0) continue;
QFile devNameFile(dev+"/name"); QFile devNameFile(dev+"/name");
QString devName; if (devNameFile.exists())
if ( devNameFile.exists())
{ {
devNameFile.open(QFile::ReadOnly); devNameFile.open(QFile::ReadOnly);
devName = devNameFile.readLine(); devName = devNameFile.readLine();
devName = devName.trimmed(); devName = devName.trimmed();
properties.name = devName;
devNameFile.close(); devNameFile.close();
} }
_v4lDevices.emplace("/dev/"+it.fileName(), devName); _v4lDevices.emplace("/dev/"+it.fileName(), devName);
_deviceProperties.insert("/dev/"+it.fileName(), properties);
} }
} }
} }
@ -237,6 +315,7 @@ void V4L2Grabber::stop()
uninit_device(); uninit_device();
close_device(); close_device();
_initialized = false; _initialized = false;
_deviceProperties.clear();
Info(_log, "Stopped"); Info(_log, "Stopped");
} }
} }
@ -409,6 +488,8 @@ void V4L2Grabber::init_userp(unsigned int buffer_size)
void V4L2Grabber::init_device(VideoStandard videoStandard, int input) void V4L2Grabber::init_device(VideoStandard videoStandard, int input)
{ {
struct v4l2_capability cap; struct v4l2_capability cap;
CLEAR(cap);
if (-1 == xioctl(VIDIOC_QUERYCAP, &cap)) if (-1 == xioctl(VIDIOC_QUERYCAP, &cap))
{ {
if (EINVAL == errno) if (EINVAL == errno)
@ -484,6 +565,8 @@ void V4L2Grabber::init_device(VideoStandard videoStandard, int input)
// set input if needed and supported // set input if needed and supported
struct v4l2_input v4l2Input; struct v4l2_input v4l2Input;
CLEAR(v4l2Input);
v4l2Input.index = input; v4l2Input.index = input;
if (input >= 0 && 0 == xioctl(VIDIOC_ENUMINPUT,&v4l2Input)) if (input >= 0 && 0 == xioctl(VIDIOC_ENUMINPUT,&v4l2Input))
@ -496,41 +579,46 @@ void V4L2Grabber::init_device(VideoStandard videoStandard, int input)
} }
// set the video standard if needed and supported // set the video standard if needed and supported
v4l2_std_id std_id; struct v4l2_standard standard;
if (-1 != xioctl(VIDIOC_ENUMSTD, &std_id)) CLEAR(standard);
if (-1 != xioctl(VIDIOC_ENUMSTD, &standard))
{ {
switch (videoStandard) switch (videoStandard)
{ {
case VIDEOSTANDARD_PAL: case VIDEOSTANDARD_PAL:
{ {
std_id = V4L2_STD_PAL; standard.id = V4L2_STD_PAL;
if (-1 == xioctl(VIDIOC_S_STD, &std_id)) if (-1 == xioctl(VIDIOC_S_STD, &standard.id))
{ {
throw_errno_exception("VIDIOC_S_STD"); throw_errno_exception("VIDIOC_S_STD");
break; break;
} }
Debug(_log, "Video standard=PAL");
} }
break; break;
case VIDEOSTANDARD_NTSC: case VIDEOSTANDARD_NTSC:
{ {
std_id = V4L2_STD_NTSC; standard.id = V4L2_STD_NTSC;
if (-1 == xioctl(VIDIOC_S_STD, &std_id)) if (-1 == xioctl(VIDIOC_S_STD, &standard.id))
{ {
throw_errno_exception("VIDIOC_S_STD"); throw_errno_exception("VIDIOC_S_STD");
break; break;
} }
Debug(_log, "Video standard=NTSC");
} }
break; break;
case VIDEOSTANDARD_SECAM: case VIDEOSTANDARD_SECAM:
{ {
std_id = V4L2_STD_SECAM; standard.id = V4L2_STD_SECAM;
if (-1 == xioctl(VIDIOC_S_STD, &std_id)) if (-1 == xioctl(VIDIOC_S_STD, &standard.id))
{ {
throw_errno_exception("VIDIOC_S_STD"); throw_errno_exception("VIDIOC_S_STD");
break; break;
} }
Debug(_log, "Video standard=SECAM");
} }
break; break;
@ -544,6 +632,7 @@ void V4L2Grabber::init_device(VideoStandard videoStandard, int input)
// get the current settings // get the current settings
struct v4l2_format fmt; struct v4l2_format fmt;
CLEAR(fmt); CLEAR(fmt);
fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
if (-1 == xioctl(VIDIOC_G_FMT, &fmt)) if (-1 == xioctl(VIDIOC_G_FMT, &fmt))
{ {
@ -581,42 +670,14 @@ void V4L2Grabber::init_device(VideoStandard videoStandard, int input)
break; break;
} }
// collect available device resolutions // set custom resolution for width and height if they are not zero
QString v4lDevice_res; if(_width && _height)
v4l2_frmsizeenum frmsizeenum;
CLEAR(frmsizeenum);
frmsizeenum.index = 0;
frmsizeenum.pixel_format = fmt.fmt.pix.pixelformat;
while (xioctl(VIDIOC_ENUM_FRAMESIZES, &frmsizeenum) >= 0)
{ {
switch (frmsizeenum.type) fmt.fmt.pix.width = _width;
{ fmt.fmt.pix.height = _height;
case V4L2_FRMSIZE_TYPE_DISCRETE:
v4lDevice_res += "\t"+ QString::number(frmsizeenum.discrete.width) + "x" + QString::number(frmsizeenum.discrete.height) + "\n";
break;
case V4L2_FRMSIZE_TYPE_CONTINUOUS:
case V4L2_FRMSIZE_TYPE_STEPWISE:
{
for(unsigned int y = frmsizeenum.stepwise.min_height; y <= frmsizeenum.stepwise.max_height; y += frmsizeenum.stepwise.step_height)
{
for(unsigned int x = frmsizeenum.stepwise.min_width; x <= frmsizeenum.stepwise.max_width; x += frmsizeenum.stepwise.step_width)
{
v4lDevice_res += "\t"+ QString::number(x) + "x" + QString::number(y) + "\n";
}
}
}
}
frmsizeenum.index++;
} }
// print available device resolutions in debug mode
if (!v4lDevice_res.isEmpty())
Debug(_log, "available V4L2 resolutions:\n%s", QSTRING_CSTR(v4lDevice_res));
// set the settings // set the settings
fmt.fmt.pix.width = _width;
fmt.fmt.pix.height = _height;
if (-1 == xioctl(VIDIOC_S_FMT, &fmt)) if (-1 == xioctl(VIDIOC_S_FMT, &fmt))
{ {
throw_errno_exception("VIDIOC_S_FMT"); throw_errno_exception("VIDIOC_S_FMT");
@ -633,30 +694,19 @@ void V4L2Grabber::init_device(VideoStandard videoStandard, int input)
// Trying to set frame rate // Trying to set frame rate
struct v4l2_streamparm streamparms; struct v4l2_streamparm streamparms;
CLEAR(streamparms); CLEAR(streamparms);
streamparms.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; streamparms.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
if (-1 == xioctl(VIDIOC_G_PARM, &streamparms)) // Check that the driver knows about framerate get/set
if (xioctl(VIDIOC_G_PARM, &streamparms) >= 0)
{ {
Debug(_log, "Frame rate settings not supported"); // Check if the device is able to accept a capture framerate set.
// continue
}
else
{
// Check the capability flag is set to V4L2_CAP_TIMEPERFRAME
if (streamparms.parm.capture.capability == V4L2_CAP_TIMEPERFRAME) if (streamparms.parm.capture.capability == V4L2_CAP_TIMEPERFRAME)
{ {
// Driver supports the feature. Set required framerate
CLEAR(streamparms);
streamparms.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
streamparms.parm.capture.timeperframe.numerator = 1; streamparms.parm.capture.timeperframe.numerator = 1;
streamparms.parm.capture.timeperframe.denominator = _fps; streamparms.parm.capture.timeperframe.denominator = _fps;
if(-1 == xioctl(VIDIOC_S_PARM, &streamparms)) (-1 == xioctl(VIDIOC_S_PARM, &streamparms))
{ ? Debug(_log, "Frame rate settings not supported.")
throw_errno_exception("VIDIOC_S_PARM"); : Debug(_log, "Set framerate to %d fps", streamparms.parm.capture.timeperframe.denominator);
// continue
}
else
// display the used framerate
Debug(_log, "Set framerate to %d fps", _fps);
} }
} }
@ -883,7 +933,11 @@ int V4L2Grabber::read_frame()
case EIO: /* Could ignore EIO, see spec. */ case EIO: /* Could ignore EIO, see spec. */
default: default:
{
throw_errno_exception("VIDIOC_DQBUF"); throw_errno_exception("VIDIOC_DQBUF");
stop();
getV4Ldevices();
}
return 0; return 0;
} }
} }
@ -916,7 +970,11 @@ int V4L2Grabber::read_frame()
case EIO: /* Could ignore EIO, see spec. */ case EIO: /* Could ignore EIO, see spec. */
default: default:
{
throw_errno_exception("VIDIOC_DQBUF"); throw_errno_exception("VIDIOC_DQBUF");
stop();
getV4Ldevices();
}
return 0; return 0;
} }
} }
@ -953,9 +1011,9 @@ bool V4L2Grabber::process_image(const void *p, int size)
{ {
// We do want a new frame... // We do want a new frame...
#ifdef HAVE_JPEG_DECODER #ifdef HAVE_JPEG_DECODER
if (size != _frameByteSize && _pixelFormat != PIXELFORMAT_MJPEG) if (size < _frameByteSize && _pixelFormat != PIXELFORMAT_MJPEG)
#else #else
if (size != _frameByteSize) if (size < _frameByteSize)
#endif #endif
{ {
Error(_log, "Frame too small: %d != %d", size, _frameByteSize); Error(_log, "Frame too small: %d != %d", size, _frameByteSize);
@ -1100,7 +1158,7 @@ void V4L2Grabber::process_image(const uint8_t * data, int size)
* ------------ END of JPEG decoder related code ------------ * ------------ END of JPEG decoder related code ------------
* --------------------------------------------------------*/ * --------------------------------------------------------*/
_imageResampler.processImage(data, _width, _height, _lineLength, _pixelFormat, image); _imageResampler.processImage(data, _width, _height, _lineLength, _pixelFormat, image);
if (_signalDetectionEnabled) if (_signalDetectionEnabled)
{ {
@ -1168,6 +1226,60 @@ int V4L2Grabber::xioctl(int request, void *arg)
return r; return r;
} }
int V4L2Grabber::xioctl(int fileDescriptor, int request, void *arg)
{
int r;
do
{
r = ioctl(fileDescriptor, request, arg);
}
while (r < 0 && errno == EINTR );
return r;
}
void V4L2Grabber::enumFrameIntervals(QStringList &framerates, int fileDescriptor, int pixelformat, int width, int height)
{
// collect available frame rates
struct v4l2_frmivalenum frmivalenum;
CLEAR(frmivalenum);
frmivalenum.index = 0;
frmivalenum.pixel_format = pixelformat;
frmivalenum.width = width;
frmivalenum.height = height;
while (xioctl(fileDescriptor, VIDIOC_ENUM_FRAMEINTERVALS, &frmivalenum) >= 0)
{
int rate;
switch (frmivalenum.type)
{
case V4L2_FRMSIZE_TYPE_DISCRETE:
{
if (frmivalenum.discrete.numerator != 0)
{
rate = frmivalenum.discrete.denominator / frmivalenum.discrete.numerator;
if (!framerates.contains(QString::number(rate)))
framerates.append(QString::number(rate));
}
}
break;
case V4L2_FRMSIZE_TYPE_CONTINUOUS:
case V4L2_FRMSIZE_TYPE_STEPWISE:
{
if (frmivalenum.stepwise.min.denominator != 0)
{
rate = frmivalenum.stepwise.min.denominator / frmivalenum.stepwise.min.numerator;
if (!framerates.contains(QString::number(rate)))
framerates.append(QString::number(rate));
}
}
}
frmivalenum.index++;
}
}
void V4L2Grabber::setSignalDetectionEnable(bool enable) void V4L2Grabber::setSignalDetectionEnable(bool enable)
{ {
if (_signalDetectionEnabled != enable) if (_signalDetectionEnabled != enable)
@ -1227,3 +1339,28 @@ bool V4L2Grabber::setWidthHeight(int width, int height)
} }
return false; return false;
} }
QStringList V4L2Grabber::getV4L2devices()
{
QStringList result = QStringList();
for (auto it = _deviceProperties.begin(); it != _deviceProperties.end(); ++it)
{
result << it.key();
}
return result;
}
QString V4L2Grabber::getV4L2deviceName(QString devicePath)
{
return _deviceProperties.value(devicePath).name;
}
QStringList V4L2Grabber::getResolutions(QString devicePath)
{
return _deviceProperties.value(devicePath).resolutions;
}
QStringList V4L2Grabber::getFramerates(QString devicePath)
{
return _deviceProperties.value(devicePath).framerates;
}

View File

@ -90,8 +90,8 @@ bool Grabber::setWidthHeight(int width, int height)
bool Grabber::setFramerate(int fps) bool Grabber::setFramerate(int fps)
{ {
if(fps > 0) if((fps > 0) && (_fps != fps))
_fps = fps; _fps = fps;
return fps > 0; return (fps > 0) && (_fps != fps);
} }

View File

@ -9,6 +9,8 @@
// qt // qt
#include <QTimer> #include <QTimer>
GrabberWrapper* GrabberWrapper::instance = nullptr;
GrabberWrapper::GrabberWrapper(QString grabberName, Grabber * ggrabber, unsigned width, unsigned height, const unsigned updateRate_Hz) GrabberWrapper::GrabberWrapper(QString grabberName, Grabber * ggrabber, unsigned width, unsigned height, const unsigned updateRate_Hz)
: _grabberName(grabberName) : _grabberName(grabberName)
, _timer(new QTimer(this)) , _timer(new QTimer(this))
@ -17,6 +19,8 @@ GrabberWrapper::GrabberWrapper(QString grabberName, Grabber * ggrabber, unsigned
, _ggrabber(ggrabber) , _ggrabber(ggrabber)
, _image(0,0) , _image(0,0)
{ {
GrabberWrapper::instance = this;
// Configure the timer to generate events every n milliseconds // Configure the timer to generate events every n milliseconds
_timer->setInterval(_updateInterval_ms); _timer->setInterval(_updateInterval_ms);
@ -89,7 +93,6 @@ QStringList GrabberWrapper::availableGrabbers()
return grabbers; return grabbers;
} }
void GrabberWrapper::setVideoMode(const VideoMode& mode) void GrabberWrapper::setVideoMode(const VideoMode& mode)
{ {
if (_ggrabber != nullptr) if (_ggrabber != nullptr)
@ -216,3 +219,35 @@ void GrabberWrapper::tryStart()
start(); start();
} }
} }
QStringList GrabberWrapper::getV4L2devices()
{
if(_grabberName.startsWith("V4L"))
return _ggrabber->getV4L2devices();
return QStringList();
}
QString GrabberWrapper::getV4L2deviceName(QString devicePath)
{
if(_grabberName.startsWith("V4L"))
return _ggrabber->getV4L2deviceName(devicePath);
return QString();
}
QStringList GrabberWrapper::getResolutions(QString devicePath)
{
if(_grabberName.startsWith("V4L"))
return _ggrabber->getResolutions(devicePath);
return QStringList();
}
QStringList GrabberWrapper::getFramerates(QString devicePath)
{
if(_grabberName.startsWith("V4L"))
return _ggrabber->getFramerates(devicePath);
return QStringList();
}

View File

@ -7,10 +7,14 @@
"device" : "device" :
{ {
"type" : "string", "type" : "string",
"title" : "edt_conf_v4l2_device_title", "title" : "edt_conf_enum_custom",
"default" : "auto", "default" : "auto",
"options" : {
"hidden":true
},
"required" : true, "required" : true,
"propertyOrder" : 1 "propertyOrder" : 2,
"comment" : "The 'available_device' settings are dynamically inserted into the WebUI under PropertyOrder '1'."
}, },
"standard" : "standard" :
{ {
@ -22,7 +26,7 @@
"enum_titles" : ["edt_conf_enum_NO_CHANGE", "edt_conf_enum_PAL", "edt_conf_enum_NTSC", "edt_conf_enum_SECAM"] "enum_titles" : ["edt_conf_enum_NO_CHANGE", "edt_conf_enum_PAL", "edt_conf_enum_NTSC", "edt_conf_enum_SECAM"]
}, },
"required" : true, "required" : true,
"propertyOrder" : 2 "propertyOrder" : 3
}, },
"width" : "width" :
{ {
@ -30,9 +34,13 @@
"title" : "edt_conf_fg_width_title", "title" : "edt_conf_fg_width_title",
"default" : 0, "default" : 0,
"minimum" : 0, "minimum" : 0,
"append" : "edt_append_pixel",
"options" : {
"hidden":true
},
"required" : true, "required" : true,
"access" : "expert", "propertyOrder" : 5,
"propertyOrder" : 3 "comment" : "The 'resolution' settings are dynamically inserted into the WebUI under PropertyOrder '4'."
}, },
"height" : "height" :
{ {
@ -40,19 +48,26 @@
"title" : "edt_conf_fg_height_title", "title" : "edt_conf_fg_height_title",
"default" : 0, "default" : 0,
"minimum" : 0, "minimum" : 0,
"append" : "edt_append_pixel",
"options" : {
"hidden":true
},
"required" : true, "required" : true,
"access" : "expert", "propertyOrder" : 6
"propertyOrder" : 4
}, },
"fps" : "fps" :
{ {
"type" : "integer", "type" : "integer",
"title" : "Framerate", "title" : "edt_conf_enum_custom",
"default" : 15, "default" : 15,
"minimum" : 1, "minimum" : 1,
"append" : "fps",
"options" : {
"hidden":true
},
"required" : true, "required" : true,
"access" : "expert", "propertyOrder" : 8,
"propertyOrder" : 5 "comment" : "The 'frames per second' setting is dynamically inserted into the WebUI under PropertyOrder '7'."
}, },
"sizeDecimation" : "sizeDecimation" :
{ {
@ -62,7 +77,7 @@
"maximum" : 30, "maximum" : 30,
"default" : 6, "default" : 6,
"required" : true, "required" : true,
"propertyOrder" : 6 "propertyOrder" : 9
}, },
"cropLeft" : "cropLeft" :
{ {
@ -72,7 +87,7 @@
"default" : 0, "default" : 0,
"append" : "edt_append_pixel", "append" : "edt_append_pixel",
"required" : true, "required" : true,
"propertyOrder" : 7 "propertyOrder" : 10
}, },
"cropRight" : "cropRight" :
{ {
@ -82,7 +97,7 @@
"default" : 0, "default" : 0,
"append" : "edt_append_pixel", "append" : "edt_append_pixel",
"required" : true, "required" : true,
"propertyOrder" : 8 "propertyOrder" : 11
}, },
"cropTop" : "cropTop" :
{ {
@ -92,7 +107,7 @@
"default" : 0, "default" : 0,
"append" : "edt_append_pixel", "append" : "edt_append_pixel",
"required" : true, "required" : true,
"propertyOrder" : 9 "propertyOrder" : 12
}, },
"cropBottom" : "cropBottom" :
{ {
@ -102,7 +117,7 @@
"default" : 0, "default" : 0,
"append" : "edt_append_pixel", "append" : "edt_append_pixel",
"required" : true, "required" : true,
"propertyOrder" : 10 "propertyOrder" : 13
}, },
"signalDetection" : "signalDetection" :
{ {
@ -110,7 +125,7 @@
"title" : "edt_conf_v4l2_signalDetection_title", "title" : "edt_conf_v4l2_signalDetection_title",
"default" : false, "default" : false,
"required" : true, "required" : true,
"propertyOrder" : 11 "propertyOrder" : 14
}, },
"redSignalThreshold" : "redSignalThreshold" :
{ {
@ -126,7 +141,7 @@
} }
}, },
"required" : true, "required" : true,
"propertyOrder" : 12 "propertyOrder" : 15
}, },
"greenSignalThreshold" : "greenSignalThreshold" :
{ {
@ -142,7 +157,7 @@
} }
}, },
"required" : true, "required" : true,
"propertyOrder" : 13 "propertyOrder" : 16
}, },
"blueSignalThreshold" : "blueSignalThreshold" :
{ {
@ -158,7 +173,7 @@
} }
}, },
"required" : true, "required" : true,
"propertyOrder" : 14 "propertyOrder" : 17
}, },
"sDVOffsetMin" : "sDVOffsetMin" :
{ {
@ -174,7 +189,7 @@
} }
}, },
"required" : true, "required" : true,
"propertyOrder" : 15 "propertyOrder" : 18
}, },
"sDVOffsetMax" : "sDVOffsetMax" :
{ {
@ -190,7 +205,7 @@
} }
}, },
"required" : true, "required" : true,
"propertyOrder" : 16 "propertyOrder" : 19
}, },
"sDHOffsetMin" : "sDHOffsetMin" :
{ {
@ -206,7 +221,7 @@
} }
}, },
"required" : true, "required" : true,
"propertyOrder" : 17 "propertyOrder" : 20
}, },
"sDHOffsetMax" : "sDHOffsetMax" :
{ {
@ -222,7 +237,7 @@
} }
}, },
"required" : true, "required" : true,
"propertyOrder" : 18 "propertyOrder" : 21
} }
}, },
"additionalProperties" : true "additionalProperties" : true

View File

@ -138,7 +138,7 @@ void QJsonSchemaChecker::validate(const QJsonValue & value, const QJsonObject &s
; // references have already been collected ; // references have already been collected
else if (attribute == "title" || attribute == "description" || attribute == "default" || attribute == "format" else if (attribute == "title" || attribute == "description" || attribute == "default" || attribute == "format"
|| attribute == "defaultProperties" || attribute == "propertyOrder" || attribute == "append" || attribute == "step" || attribute == "defaultProperties" || attribute == "propertyOrder" || attribute == "append" || attribute == "step"
|| attribute == "access" || attribute == "options" || attribute == "script" || attribute == "allowEmptyArray") || attribute == "access" || attribute == "options" || attribute == "script" || attribute == "allowEmptyArray" || attribute == "comment")
; // nothing to do. ; // nothing to do.
else else
{ {