Torna indietro   Hardware Upgrade Forum > Software > Programmazione

Apple MacBook Air M3: chi deve davvero comprarlo? La recensione
Apple MacBook Air M3: chi deve davvero comprarlo? La recensione
A distanza di circa 8 mesi arriva l’importante aggiornamento dei MacBook Air: nessun cambiamento estetico, ma una revisione hardware interna con l’upgrade al processore M3. Le prestazioni migliorano rispetto alle generazioni precedenti, e questo fa sorgere una domanda spontanea: a chi è rivolto oggi questo laptop? Cerchiamo di capirlo nella nostra recensione 
ASUS ROG Swift OLED PG49WCD: quando QD-OLED e ultrawide si fondono
ASUS ROG Swift OLED PG49WCD: quando QD-OLED e ultrawide si fondono
Da ASUS un monitor particolare ma molto completo: principalmente indirizzato al videogiocatore, può essere sfruttato con efficacia anche per attività creative e di produzione multimediale
Dreame L10s Pro Ultra Heat: la pulizia di casa tutta sostanza
Dreame L10s Pro Ultra Heat: la pulizia di casa tutta sostanza
Il nuovo robot aspirapolvere domestico di Dreame abbina funzionalità complete a un moccio flottante che raggiunge al meglio gli angoli delle pareti. Un prodotto tutto in uno semplice da utilizzare ma molto efficace, in grado di rispondere al meglio alle necessità di pulizia della casa
Tutti gli articoli Tutte le news

Vai al Forum
Rispondi
 
Strumenti
Old 14-11-2018, 11:21   #1
fano
Senior Member
 
Iscritto dal: Nov 2005
Messaggi: 2095
Qt 5.6.1 / Linux Streaming MJPEG in plug browser

Ho un problema che mi sta davvero facendo impazzire... ho una telecamera tipo "video sorveglianza" che mi invia via HTTP uno stream mjpeg che qualsiasi browser del mondo sa leggere semplicemente aprendo la pagina, ma ovviamente QWebkit no! Il meglio che ho ottenuto è che lo stampasse come testo

La cosa più ovvia visto che sto "browser" a stento supporta HTML4 era di usare un plugin, ma Flash no perché la gente ha paura di lui (?), così avevo pensato al plugin di VLC, ma tutto quello che ho ottenuto era un cubetto con un bel '?' dentro!

Ora sto provando a fare il mio plugin ed ero tutto contento perché questo funziona pure: http://doc.qt.io/archives/qt-4.8/qt-...n-example.html!

Così ho pensato di usare QMediaplayer, ma sembra la solita cosa non finita... come plugin va addirittura in SIGABORT (!), l'applicazione standalone mi mostrava uno schermo nero

I codec credo di averceli ho messo gstreamer-ffmpeg che dovrebbe supportare qualunque cosa, ma nulla!

Come ultimo tentativo ho deciso di farlo "a mano", in fondo uno stream MJPEG è piuttosto semplice da gestire sono tante JPEG una dietro l'altra e infatti l'applicazione standalone funziona!

Così stamane mi appropinquo a trasformarla in un plugin e... NON appare nulla!
Peggio ancora il segnale readyRead di QNetworkReply manco avviene!

Questo è il plugin factory, molto simile all'esempio di fatto:

Codice:
QObject *mediaPlayerFactory::create(const QString &mimeType, const QUrl &url,
                                    const QStringList &argumentNames,
                                    const QStringList &argumentValues) const
{
    if (mimeType != "video/mjpeg")
        return 0;

    mediaPlayerView *view = new mediaPlayerView(url);

    QNetworkRequest request(url);
    QNetworkReply *reply = manager->get(request);
    connect(reply, SIGNAL(readyRead()), view, SLOT(onReadyRead(reply)));
    connect(reply,SIGNAL(error(QNetworkReply::NetworkError)),
            view,SLOT(onError(QNetworkReply::NetworkError)));

    //connect(reply, SIGNAL(finished()), reply, SLOT(deleteLater()));

    return view;
}
E questo è il costruttore di mediaPlayerView:

Codice:
mediaPlayerView::mediaPlayerView(const QUrl &url, QWidget *parent)
    : QWidget(parent)
{
    this->url = url;

    Log("Getting MJPEG stream from url: " + url.toString());

    label = new QLabel(this);

    label->setWindowFlags(label->windowFlags() | Qt::FramelessWindowHint);
    label->show();

    Log("Ready to stream!");
}
onReadyRead() è relativamente banale legge tutto il pacchetto vede se è un'immagine completa e lo disegna... sono sicuro al 100% che se venisse chiamato funzionerebbe pure!

Ho settato ovviamente che i plugin siano abilitati e che possano accedere alla rete:

Codice:
    QWebSettings::globalSettings()->setAttribute(QWebSettings::PluginsEnabled,
                                                 true);

     QWebSettings::globalSettings()->setAttribute(QWebSettings::LocalContentCanAccessRemoteUrls, true);
Qualche idea?

Il prossimo tentativo sarebbe qualcosa di davvero troppo anche per Linux: far partire VLC frameless ed embeddare la sua finestra dentro la pagina web
__________________
Cosmos C# Open Source Managed Operating System
Cosmos Thread Ufficiale
Cosmos Official Site Vuoi collaborare allo sviluppo? Unisciti alla chat!
fano è offline   Rispondi citando il messaggio o parte di esso
Old 14-11-2018, 12:25   #2
fano
Senior Member
 
Iscritto dal: Nov 2005
Messaggi: 2095
L'ho trovato! ... ed è imbarazzante quello che Qt fa...

Per chi non conosce come funziona l'animale Qt per nascondere l'indubbio casino che sono i thread in C++ usa un meccanismo di segnali / slot così - per esempio - quando il thread che si occupa di leggere dal socket ha il buffer pieno mi notifica con readyRead() che ha qualcosa da leggere ed io mi "aggancio" ad esso con il mio slot onReadyRead().

Peccato che per far questo - in realtà - non si usa "realmente" C++ ma una sorta di dialetto, infatti file .cpp Qt è compilato in un'equivalente .moc in cui le "orrende" macchine a stati / switch appaiono robe orride tipo:

Codice:
void mediaPlayerView::qt_static_metacall(QObject *_o, QMetaObject::Call _c, int _id, void **_a)
{
    if (_c == QMetaObject::InvokeMetaMethod) {
        mediaPlayerView *_t = static_cast<mediaPlayerView *>(_o);
        Q_UNUSED(_t)
        switch (_id) {
        case 0: _t->notifyLog((*reinterpret_cast< BrowserApp::LogLevel(*)>(_a[1])),(*reinterpret_cast< QString(*)>(_a[2]))); break;
        case 1: _t->onReadyRead(); break;
        case 2: _t->onError((*reinterpret_cast< QNetworkReply::NetworkError(*)>(_a[1]))); break;
        case 3: _t->onFinished(); break;
        default: ;
Bello vero?

Peccato che io avevo fatto un piccolo errorino... gli slot devono essere definiti esattamente con lo stesso prototipo dei segnali, ma ci volevo passare "reply"!!!
Tutto compilava perfettamente, i moc erano creati e compilati e l'applicazione girava perfettamente peccato che non si vedeva una favonza...

Finché non ho letto cosa era scritto sullo stderr e sorpresona:

Codice:
QObject::connect: No such slot mediaPlayerView:onReadyRead(reply) in src/mediaPlayerFactory.cpp:25
vedete? Come fosse javascript un errore di "sintassi" e ce ne accorgiamo a runtime

Cambiato onReadyRead() per non prendere argomenti e fatto un'orrido "dynamic cast" con oggetto che esiste per "miracolo" chiamato sender e...

Codice:
void mediaPlayerView::onReadyRead()
{
    QNetworkReply *reply = static_cast<QNetworkReply *>(sender());

    if (reply->error() != QNetworkReply::NoError) {
        Log(BrowserApp::Error, "reply is an Error!");
        return;
    }
  
    [...]
Mah... a me pare che async di C# sia un po' meglio!
Anche se devo dire che se qualcuno ha mai programmato in BeOS la loro soluzione al problema dei "thread" era migliore avevano inventato un tipo BMessage e semplicemente per ricevere i messaggi uno doveva implementare un metodo MessageReceived() e poi
se li "puppava" con il classico switch e via...

A volte quando le cose sono troppo "magiche" è molto difficile ragionarci sopra

Voi cosa ne pensate?
__________________
Cosmos C# Open Source Managed Operating System
Cosmos Thread Ufficiale
Cosmos Official Site Vuoi collaborare allo sviluppo? Unisciti alla chat!
fano è offline   Rispondi citando il messaggio o parte di esso
Old 15-11-2018, 10:22   #3
carsco
Senior Member
 
L'Avatar di carsco
 
Iscritto dal: Oct 2009
Messaggi: 519
Nel 99% dei casi quella camera invia anche uno stream RTP o RTSP: perche' non lo apri con VLC direttamente conoscendo indirizzo, nome stream e porta?

Perche' scomodare uno strato in piu'?
carsco è offline   Rispondi citando il messaggio o parte di esso
Old 16-11-2018, 09:57   #4
fano
Senior Member
 
Iscritto dal: Nov 2005
Messaggi: 2095
Perché lo devo mostrare dentro la pagina web... sono ancora in HTML4 (QWebKit non supporta HTML5 o almeno non supporta tutti i tag) e comunque il tag video non supporta MJPEG.

Avevo provato - infatti - ad usare VLC plugin, ma non c'è stato verso... ottenevo un cubetto con dentro '?', la cosa strana è che Flash funzionava! Credo che alla fine supporti solo i "suoi" e Flash (c'è un bel hardcoding da qualche parte?)...

Comunque ora sto impazzendo con sto meccanismo dei segnali... si sconnette mi arriva il segnale "finished()", fai abort() (close del socket?) e poi mi arriva di nuovo il segnale finished()? Ed io mi inlooppo a stecca...
__________________
Cosmos C# Open Source Managed Operating System
Cosmos Thread Ufficiale
Cosmos Official Site Vuoi collaborare allo sviluppo? Unisciti alla chat!
fano è offline   Rispondi citando il messaggio o parte di esso
Old 16-11-2018, 10:03   #5
mally
Senior Member
 
Iscritto dal: Mar 2016
Messaggi: 1974
io sono vincolato ad usare ancora Qt 4.7 e non vedo l'ora di fare il salto a versioni 5.xxx proprio per migliorare alcuni strati a thread ma vedo che la soluzione non funziona alla grandissima...
__________________
fanboy del mio portafoglio...
mally è offline   Rispondi citando il messaggio o parte di esso
Old 17-11-2018, 00:58   #6
carsco
Senior Member
 
L'Avatar di carsco
 
Iscritto dal: Oct 2009
Messaggi: 519
Quote:
Originariamente inviato da fano Guarda i messaggi
Credo che alla fine supporti solo i "suoi" e Flash
Ma secondo te, dentro lo stream che ti manda sul browser, cosa c'e'? C'e' lo stream MJPEG (o H264 se la camera e' piu' recente)!

La camera potrebbe anche mettere a disposizione un indirizzo con una JPG che si aggiorna svariate volte al secondo (quindi, M-Jpeg, ma che lo dico a fare?).

Sappiamo marca e modello della camera?
Non andiamoci a caso.
Ti posso aiutare.
carsco è offline   Rispondi citando il messaggio o parte di esso
Old 17-11-2018, 16:34   #7
pabloski
Senior Member
 
Iscritto dal: Jan 2008
Messaggi: 8406
Comunque, siccome si sta parlando di Qt 5, faccio notare che QtWebkit è deprecato ed è stato sostituito da QtWebEngine.

Riguardo il meccanismo degli slot/signals ( che vista l'epoca era rivoluzionario e ha dato vita ai framework basati su bindings ), in qml sono stati sostituiti dai bindings.
pabloski è offline   Rispondi citando il messaggio o parte di esso
Old 20-11-2018, 13:01   #8
fano
Senior Member
 
Iscritto dal: Nov 2005
Messaggi: 2095
Purtroppo il lavoro che sto facendo deve anche funzionare su un Centos 5.4 (!) quindi Qt 4.6 (o 4.8) dove sicuramente QtWebEngine non esiste... e sinceramente visto che l'applicazione esiste da più di 10 anni ho paura a cambiare Engine chissà quante incompatibilità ci saranno

La telecamera è una HIK e ha 2 modi per fornire lo streaming MJPEG:

1. Via HTPP...funziona benissimo con Firefox... il nostro browser basato su QWebKit ovviamente non è in grado. Stranamente anche VLC non è in grado di aprirlo
2. Via RSTP questo lo apre VLC, ma non Firefox... bah!

Il mio mediaplayer "fatto a mano" funziona pure, il problema è che il modo per disegnare 30 immagini / s su una QLabel, X mi occupa il 95% di CPU (+25% imputabili al mio software)!

vlc chiamato da terminale ovviamente occupa solo il 14%

Le performance sono proprie pietose... non credo se l'avessi potuto scrivere in C# sarebbe stato così lento.

Questo è il codice che uso per disegnare:

Codice:
    QImage image;
    bool isValid;

    isValid = image.loadFromData(data, "JPG");

    if (!isValid) {
        Log(BrowserApp::Error, "Error image is not valid");
        return;
    }

    QPixmap pix = QPixmap();
    pix = pix.fromImage(image);
    pix = pix.scaled(this->size(), Qt::KeepAspectRatio);
    label->setPixmap(pix);
La mia impressione è che questo codice faccia una marea di memcpy(), ma credo sia il modo "consigliato" in Qt...

C'è un modo più efficiente per disegnare?
__________________
Cosmos C# Open Source Managed Operating System
Cosmos Thread Ufficiale
Cosmos Official Site Vuoi collaborare allo sviluppo? Unisciti alla chat!

Ultima modifica di fano : 20-11-2018 alle 13:04.
fano è offline   Rispondi citando il messaggio o parte di esso
Old 20-11-2018, 13:20   #9
pabloski
Senior Member
 
Iscritto dal: Jan 2008
Messaggi: 8406
Il metodo consigliato e' usare Phonon. In alternativa e' possibile sfruttare FFMPEG che e' pure cross-platform. Oppure piu' semplicemente si puo' usare OpenCV, trasformando i frame contenuti in una matrice OpenCV in immagine QImage. Si taglia la testa al toro e si usa pure la GPU se presente.
pabloski è offline   Rispondi citando il messaggio o parte di esso
Old 28-11-2018, 15:17   #10
fano
Senior Member
 
Iscritto dal: Nov 2005
Messaggi: 2095
Phonon non sembra più supportato da Qt5, le altre soluzioni sembrano davvero troppo complesse per risolvere un problema così banale come visualizzare uno stream MJPEG.

Alla fine visto che VLC era in grado di farlo (usando solo il 10% di CPU) ho usato la libvlc, l'API rigorosamente in C permette abbastanza semplicemente di farsi il "proprio" VLC:

https://wiki.videolan.org/LibVLC_Tut...le_LibVLC_Code

da quell'esempio è "banale" ottenere il famoso plugin VLC / QT che finalmente piace a QWebkit

Attenzione perché non è così banale ci sono 2 trappole:

1. Il pacchetto rpm VLC-Core della Centos 6 è - ovviamente - toppato e non include tra i video "plugins" quello che permette di sbattere VLC dentro una finestra X (ho passato 2 giorni prima di capirlo!). La "menata" è che si deve installare l'intero VLC che si porta dietro anche Qt4 ed altra bratta... dovrò fare un "RPM" a mano per mettere solo i plugins
2. Mentre il vero "VLC" ritenta se lo stream s'interrompe (banalmente si può simularlo staccando il cavo di rete dalla TLC), libVLC è "bacata" e semplicemente scrive che lo stream è finito! Per farlo correttamente si deve usare una callback per esempio nel posto dove viene gestito il "play":

Codice:
    libvlc_event_manager_t *event_manager = libvlc_media_player_event_manager 	(vlcPlayer); 	
    libvlc_event_attach(event_manager, libvlc_MediaPlayerEndReached, (libvlc_callback_t )&media_is_ended, this);
    libvlc_event_attach(event_manager, libvlc_MediaPlayerEncounteredError, (libvlc_callback_t )&media_is_ended, this);
In "media_is_ended()" fai semplicemente stop() / play(), se si vede qualcosa siete a cavallo altrimenti media_is_ended() sarà richiamato. Non preoccupatevi di non "stressare" la rete, vlc genera l'evento "libvlc_MediaPlayerEndReached" già a timeout.

Usando VLC ottengo altri 2 vantaggi:
  1. Se volessi potrei anche usare lo stream H264 in full HD!
  2. In caso di microinterruzioni lo stream continua ininterrotto perché - ovviamente - VLC fa buffering, con l'altra soluzione fatta "a mano" dovevo gestirmi anche questo caso...

Spero questo sarà utile a qualche altro povero sfigato che si trovi in questa situazione... imbarazzante
__________________
Cosmos C# Open Source Managed Operating System
Cosmos Thread Ufficiale
Cosmos Official Site Vuoi collaborare allo sviluppo? Unisciti alla chat!
fano è offline   Rispondi citando il messaggio o parte di esso
 Rispondi


Apple MacBook Air M3: chi deve davvero comprarlo? La recensione Apple MacBook Air M3: chi deve davvero comprarlo...
ASUS ROG Swift OLED PG49WCD: quando QD-OLED e ultrawide si fondono ASUS ROG Swift OLED PG49WCD: quando QD-OLED e ul...
Dreame L10s Pro Ultra Heat: la pulizia di casa tutta sostanza Dreame L10s Pro Ultra Heat: la pulizia di casa t...
HONOR Magic6 Pro: come funziona Magic Portal, il modo ''intelligente'' di condividere HONOR Magic6 Pro: come funziona Magic Portal, il...
L'innovazione richiede fiducia: Workday si propone come guida nell'era dell'IA L'innovazione richiede fiducia: Workday si propo...
Italia strategica per Oracle. Arriva la ...
Sam-Bankman Fried: 25 anni di reclusione...
Mobility Analytics di WINDTRE Business p...
Il lander lunare JAXA SLIM si è r...
Warframe conquista l'iPhone: senza soluz...
Marvel Rivals!, l'inaspettato shooter Pv...
Twitch aggiorna le linee guida sui conte...
Galaxy M55 ufficiale: la nuova fascia me...
Google corregge sette vulnerabilit&agrav...
IA: le imprese italiane sono in prima li...
Garmin Dash Cam 57: un'alleata perfetta ...
Elgato Facecam MK2: come rendere ancora ...
2 iRobot Roomba al prezzo più sco...
La tua connessione in fibra ottica potre...
Il controller DualSense per PS5 con un p...
Chromium
GPU-Z
OCCT
LibreOffice Portable
Opera One Portable
Opera One 106
CCleaner Portable
CCleaner Standard
Cpu-Z
Driver NVIDIA GeForce 546.65 WHQL
SmartFTP
Trillian
Google Chrome Portable
Google Chrome 120
VirtualBox
Tutti gli articoli Tutte le news Tutti i download

Strumenti

Regole
Non Puoi aprire nuove discussioni
Non Puoi rispondere ai messaggi
Non Puoi allegare file
Non Puoi modificare i tuoi messaggi

Il codice vB è On
Le Faccine sono On
Il codice [IMG] è On
Il codice HTML è Off
Vai al Forum


Tutti gli orari sono GMT +1. Ora sono le: 20:29.


Powered by vBulletin® Version 3.6.4
Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
Served by www2v