web (HbbTV, VDR*ELEC), Milestone 1 erreicht

  • Irgendwo gehen noch Daten verloren. Ich habe noch weiter analysiert und sehe folgendes im Log wenn der Film stockt:

    Code
    Aug 11 14:51:47 Odroid vdr[6475]: [6517] ERROR: skipped 132 bytes to sync on start of TS packet at device.c/PlayTs(1611)
    Aug 11 14:51:48 Odroid kernel: 0: frame number gap error
    Aug 11 14:51:48 Odroid kernel: 0: frame number gap error
    Aug 11 14:51:48 Odroid kernel: 0: reference list error 1 frame count 3748 to skip 0 reflist_error_count 1

    Das kommt durchaus öfter vor:

    Wenn ich den gleichen Steam herunterlade mit ffmpeg konvertiere und dann vom vdr als Aufzeichnung abspiele dann passiert das nicht.

    Da scheinen Daten auf dem Weg zwischen ffmpeg - webplugin - vdr verloren zu gehen und dann bemerkt der vdr das der TS Startcode fehlt und resynct.


    PS:

    das passiert auch wenn ich erzwinge das meine Buffer ausreichend gefüllt sind.

  • Wo genau das Problem liegt kann ich leider nicht finden. Dafür ist mir der Datenfluss zu unklar :)

    Aber diese Änderung ist auf jeden Fall notwendig:

    PlayTs returned die verarbeiteten Bytes, aber nicht notwenigerweise alle.


    Das Problem ist aber das PlayPacket mit einer Länge aufgerufen wird die nicht multiblen TS Paketen entspricht. An der Stelle verlieren sich aber meine Datenflusskentnisse :)

  • Und hier die "finale" Version

  • Kann das es dann ein Problem mit den Sockets sein, wenn cefbrowser und remotrans nicht in einem Terminal laufen?

    Alle 3 Komponenten (browser, transcoder und das Plugin) nutzen exakt dieselbe Library. Der einzige Unterschied ist der zu verwendende Port. Und VDR bzw. das Plugin haben keine Probleme mit dem Start? Ich muss mal schauen, ob ich an mehr Informationen komme, warum der Listen schief.


    Zabrimus Ich habe nun mal das kurze Stottern des Bildes analysiert und es sieht so aus das mein Videopuffer leerläuft. D.h. die Buffer werden nicht genug gefüllt.

    Puhhh... Ich habe gerade das genaue gegenteilige Problem mit dem Puffer. Im syslog sieht es so aus, als ob die Puffer vollaufen und dadurch nur ein Standbild angezeigt wird. Ich arbeite gerade an den Privatsendern (s1p7) und da sind noch zuviele offene Punkte, als das ich meinem Problem weitere Beachtung schenken kann. Unklar ist noch, ob es an den Sendern bzw. dem Browser liegt.

    Und es bleibt das Problem mit den 48 KHz Audio-Filmen, die auch der Parameter -t codecs.ini nicht löst.

    Das vestehe ich nicht. Bekommst du 48 KHZ und es macht Probleme, oder bekommst du etwas anderes als 48 KHZ? Für den Audiotranscode gibt es verschiedene Varianten.

    Wie genau sieht dein audio/codec_copy und audio/transcode in der codecs.ini aus und welches Zielformat funktioniert ohne Probleme?

    Und hier die "finale" Version

    Ich hätte bis gerade Stein und Bein geschworen, daß der 188-Byte Puffer-Größen-Check entweder im Browser oder dem Plugin vorhanden ist. Unklar ist nur, wann und wo ich das verloren habe.

    Ich habe deine Version 1:1 übernommen. Danke!

  • Das vollaufen der Buffer sollte kein Problem sein wenn du sauberes Buffermangement hast. D.h. das die Queue bis zurück zum ffmpeg stehen bleiben muss wenn die Buffer vollgelaufen sind. Ich weiss nicht ob man ein Fifo auf grösse einstellen kann. Aber das wäre hier notwendig.


    Ich hatte gestern abend das Problem das der Stream abriss und damit der VDR den Player zugemacht hat. Oder hier

    Code
       vdrServer.Post("/ProcessTSPacket", [](const httplib::Request &req, httplib::Response &res) {
            const std::string body = req.body;
    
            if (body.empty()) {
                res.status = 404;
            } else {
                /*
                FILE* f = fopen("test.ts", "a");
    
    ....

    ein empty body zurück kommt weil der ffmpeg nicht schnell genug Daten liefert. Und damit dann der Stream abgebrochen wird.


    Ich muss mir nochmal anschauen wie der VDR einen neuen stream ankündigt. Ich denke da kommt erst ein SetPlayMode 0 und dann ein SetPlayMode 1.

    Das führt dazu das ich intern die Buffer lösche und bei SetPlayMode 1 erst die Buffer wieder auffülle bevor ich den Stream abspiele. Sendest du auch die SetPlayModes ? Ich schau es mir auch nochmal an.

  • Ich habe sowohl den Browser, als auch den Transcoder erweitert, so daß beide direkt gestoppt werden, wenn das Listen fehlschlägt. Zusätzlich sollte eine Fehlermeldung ausgegeben werden, mit dem hoffentlich die Ursache ermittelt werden kann.


    Wo genau das Problem liegt kann ich leider nicht finden. Dafür ist mir der Datenfluss zu unklar :)

    Das ist eigentlich ganz simpel:


    Der Reader-Thread im Transcoder liest alles aus dem FIFO aus:

    Code
    if ((bytes = read(fifo, buffer, sizeof(buffer))) > 0) {
        if (!client->ProcessTSPacket(std::string(buffer, bytes))) {

    Der Transcoder ruft folgendes auf

    Code
    bool BrowserClient::ProcessTSPacket(std::string packet)
    -> client->Post("/ProcessTSPacket", packet, "text/plain")

    Im Browser werden die Pakete empfangen

    Code
    // called by transcoder
    svr.Post("/ProcessTSPacket", [&vdrRemoteClient, &transcoderRemoteClient](const httplib::Request &req, httplib::Response &res) {

    und dann direkt an VDR weitergeleitet

    Code
    vdrRemoteClient.ProcessTSPacket(std::string(body.c_str(), body.length())

    Das Plugin empfängt das Paket

    Code
    vdrServer.Post("/ProcessTSPacket", [](const httplib::Request &req, httplib::Response &res)

    und schiebt es dann Richtung Ausgabedevice

    Code
    videoPlayer->PlayPacket((uint8_t *) body.c_str(), (int) body.length());

    Also wird alles, was der Transcoder von FFmpeg aus dem FIFO bekommt 1:1 im Plugin bzw. Ausgabedevice landen. Dazwischen findet keine Umwandlung oder sonstige Manipulation statt.

  • Ich muss mir nochmal anschauen wie der VDR einen neuen stream ankündigt. Ich denke da kommt erst ein SetPlayMode 0 und dann ein SetPlayMode 1.

    Das führt dazu das ich intern die Buffer lösche und bei SetPlayMode 1 erst die Buffer wieder auffülle bevor ich den Stream abspiele. Sendest du auch die SetPlayModes ? Ich schau es mir auch nochmal an.

    PlayModes? Vielleicht passiert das intern, aber aktiv mache ich das nicht.


    Es gibt 2 Möglichkeiten ein Video abzuspielen:

    1. Frisches Video: Aus dem Live-TV wird ein Video ausgewählt

    Das passiert in

    vdrServer.Get("/StartVideo", [](const httplib::Request &req, httplib::Response &res)

    Ein Player wird konstruiert und an das Device attached.

    2. Ein Video soll abgespielt werden, während der Player noch aktiv ist. Also wenn z.B. ein Video abgespielt wird und man direkt das nächste aussucht oder automatisch abgespielt werden soll.

    Das passiert in

    vdrServer.Get("/ResetVideo", [](const httplib::Request &req, httplib::Response &res)

    Hier rufe ich videoPlayer->ResetVideo(); auf, was dann intern in

    cPlayer::DeviceClear(); mündet.

  • So nächstes Problem: Wenn ich nun das Film pausiere dann nimmt der vdr keine Daten mehr entgegen und das PlayPacket bleibt hängen und returned nicht mehr weil es die Daten nicht mehr los wird. D.h. es muss bei Pause unbedingt verhindert werden das PlayPacket noch aufgerufen wird.

    Ich habe da nun mal einen timeout eingebaut und returne nach 50ms wenn keine Daten mehr abgenommen werden, aber das ist nicht die Lösung.

  • Zabrimus Danke für das lösen der Pause.

    Nächstes Problem: Nach einiger Zeit im Film wird er abgebrochen. Da passiert immer nach ca. 2 min und folgendes ist im Log

    Code
    Aug 14 10:52:24 Odroid vdr[4862]: [4862] [vdrweb] Destruct WebOSDPage, osdMode 1
    Aug 14 10:52:24 Odroid kernel: fb: clear: osd 0
    Aug 14 10:52:25 Odroid vdr[4862]: [4862] [vdrweb] Delete Player...
    Aug 14 10:52:25 Odroid vdr[4862]: [4862] [vdrweb] Activate video player: Nein
    Aug 14 10:52:25 Odroid vdr[4862]: [4862] [softhddev]SetPlayMode: 0

    Könnte das eine Folge des Destruct WebOSDPage sein ? Zumindest sieht es danach aus wenn ich mir das hier anschaue

    Code
    void cPluginWeb::MainThreadHook() {
        // Perform actions in the context of the main program thread.
        // WARNING: Use with great care - see PLUGINS.html!
    
        if (WebOSDPage::Get() == nullptr && videoPlayer != nullptr) {
            delete videoPlayer;
            videoPlayer = nullptr;
        }
    }
  • Nächstes Problem: Nach einiger Zeit im Film wird er abgebrochen. Da passiert immer nach ca. 2 min und folgendes ist im Log

    Passiert das tatsächlich bei jedem Film? Immer? Startest du das Plugin mit '-o' oder ohne?

    Aug 14 10:52:24 Odroid vdr[4862]: [4862] [vdrweb] Destruct WebOSDPage, osdMode 1

    osdMode 1 ist der Player. Damit wird der Player auf nullptr gesetzt und im MainMenuHook dann final geschlossen.

    Oder meinst du daß während der Pause der Player auf einmal geschlossen wird?


    Edit:

    Ich konnte das nachstellen. Die Pause wird tatsächlich durch den Browser beendet. Bzw. irgendwas bringt den Browser dazu, den Context zu schliessen und damit auch ein StopVideo an VDR zu senden.

    Ich muss versuchen, ob ich an die Javascript-Console Ausgaben ran komme um zu sehen, ob da etwas geloggt wird. Der Chrome-Debugger verliert die Ausgaben genau in dem Moment, in dem es spannend wird.

  • Ich starte das Plugin mit '-o' und der Browser ist unschuldig. Der Trigger zum Schließen kommt aus dem VDR oder dem Plugin.

    Das OSD versuche ich offen zu halten (triggerActivityThread in WebOsdPage). Der Player bekommt während der Pause auch keine Events mehr, muss dieser auch irgendwie offen gehalten werden?

    Ich fürchte da müssen ein paar Debug-Meldungen ins Plugin und der VDR Code mal wieder gelesen werden.

  • Hmm... Das Dummy-OSD wird automatisch geschlossen und damit beginnt die Kaskade

    Entweder das das DummyOSD noch zu sehr dummy, oder der Mechanismus zum offenhalten funktioniert noch nicht richtig.

  • Ich frage mich schon die ganze Zeit, wieso Du das OSD überhaupt offen halten musst. Normalerweise geht das nicht von alleine zu. Ich nutze z.B. auch ein eigenes OSD in tvguide und da muss ich nichts spezielles machen, damit das stundenlang offen bleibt. Du leitest ja auch von cOsdObject ab und nicht von cOsdMenu, nur bei einem Menü sollte das Timeout wirken.


    Grüße

    kamel5

    VDR 2.6.6: ASUS Prime X470-PRO, Ryzen 7 5700X, 64GB, 6TB HD, GT1030, Fedora 39 Kernel 6.8 X86_64, Devicebonding 2 x 1 auf 2, TT6400, DVBSky S952 V3

    Git-Repo: gitlab.com/kamel5

  • Ich frage mich schon die ganze Zeit, wieso Du das OSD überhaupt offen halten musst.

    Ich hatte kurz Zweifel. Aber wenn ich im Plugin das cRemote::TriggerLastActivity(); entferne, dann schließt sich das WebOsd nach 2 Minuten selbstständig. Mit dem Trigger bleibt das OSD offen und man kann weiter auf der Seite navigieren.

    Das automatische Schließen hat den Nachteil, daß man erst wieder über das Menu das OSD öffnen muss und evt. wieder zum Ziel navigieren muss.


    Also muss in TVGuide noch irgendwas anders sein.


    Edit:

    Nach einem weiteren Check, habe ich eine Möglichkeit gefunden, auf den Trigger-Thread zu verzichten. Das schaffe ich heute nicht mehr, aber dann fliegt eine ungeliebte Funktionalität aus dem Plugin :) Dann muss ich nur noch schauen, ob das auch Auswirkungen auf die Pause hat.

    Einmal editiert, zuletzt von Zabrimus () aus folgendem Grund: Edit: Lösung gefunden

Jetzt mitmachen!

Sie haben noch kein Benutzerkonto auf unserer Seite? Registrieren Sie sich kostenlos und nehmen Sie an unserer Community teil!