Beiträge von LordJaxom

    Ich habe mich jetzt mal ans streamdev gewagt und teste das ganze auf einem RPI2 als Client und einem PC mit Tunern als Server. Patch folgt noch.


    Ich kann nur schonmal sagen, wenn das Handling mit Timern, Recordings, Kanälen und Schedules etwas komplexer wird, kann man da durchaus etwas mehr Hirnschmalz reinstecken als "nur" die Makros an den Anfang eines Blocks zu setzen. Es braucht sich also niemand zu schämen, wenn die eigenen Anpassungsversuche nicht gleich beim ersten Mal fruchten :-)


    kls :
    Sorry für meinen kurzen Ausbruch, ich habe garnicht gesehen, dass die Makros genau das machen, was ich bemängelt hatte - Löschen am Ende des Blocks. Deinen Vorschlag werde ich beizeiten trotzdem nochmal ausprobieren, da man so einen StateKey auch an ein kurzlebiges Objekt hängen kann ohne im Destruktor StateKey.Remove aufrufen zu müssen.

    Weiss jemand ob Alexander Pipelka noch aktiv ist? Sonst würde ich mich morgen mal mit XVDR befassen...


    kls :
    Sehr, sehr schön, dass Du konkurrierende Zugriffe auf Timers, Schedules und Recordings abzusichern ermöglichst, aber warum in Gottes Namen muss ich auf StateKey Remove aufrufen und bekomme einen Abbruch, wenn ich das bis zum Destruktor von cStateKey noch nicht gemacht habe? Warum wird Remove nicht einfach im Destruktor aufgerufen? Genau dafür ist ein Destruktor doch da?!?!?!?

    Wenn man weiß, dass es sich um ein cPixmapMemory-Objekt handelt, reicht auch ein static_cast. Der dynamic_cast führt zusätzlich Runtime-Typechecks durch und gibt nullptr zurück, wenn es sich nicht um ein solches handelt. Ist nicht tragisch, verbrät aber potentiell ein klitzekleines bisschen Leistung, die nicht verbraten werden müsste.

    Aktuell ist es so, dass der Aufrufer allokiert und den Zeiger an die Queue übergibt. Die Queue gibt in q_free_node auch den übergebenen Bereich frei, die q_pop-Funktionen geben diesen Bereich aber nach dem free zurück. In diesem Fall müssten die pop-Funktionen in jedem Fall void (oder einen Status) zurückgeben, da mit einem Zeiger nach dem free nichts mehr anzufangen ist.


    Wenn der Aufrufer den Speicher verwaltet, könnte man sich bei push/pop noch darauf einigen, dass pop die Daten zurückgibt (ungefreed) und diese freigegeben werden müssen, für das Löschen der gesamten Queue könnte man aber keine Funktion mehr anbieten.

    Code
    1. void* data = malloc(...);
    2. q_push(queue, data);
    3. ...
    4. void* data = q_pop(queue);
    5. free(data);


    Wenn die Queue den Speicher allein verwaltet (Übergabe von Zeiger und Größe) handelt man sich immer eine potentiell unnötige Kopie ein, der Aufrufer würde eine gefüllte Struktur übergeben und die Queue neuen Speicher allokieren und den Inhalt kopieren.


    Ein Kompromiss wäre, der Queue die Möglichkeit zu spendieren, eine Deallokationsfunktion zu übergeben, die dann in der Node gespeichert wird. Damit könnte die Queue auch komplexe Strukturen verwalten, der Aufrufer hat die Kontrolle und würde auch den Speicher freigeben (indirekt zwar, weil durch die Queue angestoßen, aber unter eigener Kontrolle). Die Deallokationsfunktion könnte man mit einem Default versehen. Beispiel:


    Wenn das allerdings zu kompliziert wird, ist auch nichts gewonnen. Dann sollte man im Zweifel einfach vertraglich vereinbaren, dass der an q_push übergebene Speicher mit malloc oder calloc allokiert sein muss. Dann gib aber wenigstens den Zeiger nicht nach dem free aus q_pop zurück ;)

    Kurz zur letzten Frage (den Rest beantworte ich in der Mittagspause):
    Eigentlich ist sizeof(void) in C nicht erlaubt (weil void = nichts), ich habe aber herausgefunden, dass gcc hierfür 1 zurückliefert. Da Du mit int (4 Byte) als Datentyp getestet hast und ein 32- oder 64-bit Rechner Spericherblöcke immer auf mindestens 4 bzw. 8 Byte aufrundet, hat es wohl "zufällig" funktioniert.


    EDIT:
    Das ist das fiese an C. Wenn Du Quatsch machst ist das Ergebnis meist nur "undefiniert", was genauso bedeuten kann, dass es funktioniert, wie dass es abstürzt, wie dass es einfach irgendwas anderes kaputt macht was Du erst viel später in einem völlig unabhängigen Programmzweig merkst.

    Dass sich die Adressen von dem gepushten task und dem "extrahierten" unterscheiden, ist doch klar: Du allokierst vor dem extrahieren neuen Speicher mit calloc und übergibst diesen an die Funktion q_extract_head.


    Zunächst mal kann das so nicht funktionieren, da in der Funktion q_extract_head sizeof(void) genommen wird. Mich wundert, dass der Compiler das überhaupt zulässt. Jedenfalls wird dieser sizeof nicht das zurückgeben, was Du haben möchtest, und somit nicht den kompletten Task aus der Queue nach data kopieren. Warum hier überhaupt neuen Speicher allokieren?


    Wenn sichergestellt ist, dass der Task nicht von einem anderen Thread zwischen q_peek und q_pop gelöscht wird, einfach:

    Code
    1. task_t *task_p = q_peek_head(queue);
    2. // ...
    3. q_pop_head(queue);


    Wenn wirklich eine Kopie nötig ist, musst Du die Größe an q_extract_head mit übergeben. Dann wunder Dich aber auch nicht, dass die Adresse des neu allokierten und kopierten Tasks anders ist :D


    Wenn (wie ich vermute) immer nur ein Thread an einem Ende der Queue löscht und ein anderer am anderen Ende einfügt, schmeiss die q_extract Funktionen besser ganz weg.


    Abgesehen davon, dass q_extract "broken" ist, prüfst Du nicht (wie in dem #else Zweig), ob die Queue überhaupt Daten enthält. Du forderst mit calloc Speicher für task_p an, beschreibst diesen in q_extract (wobei diese Funktion zurückkehrt, wenn task_p NULL ist, also calloc fehlgeschlagen ist) und arbeitest dann mit task_p weiter, ungeachtet dessen, ob q_extract überhaupt ein Element kopieren konnte. Das data = NULL in q_extract bewirkt nicht, wie Du vielleicht glaubst, dass task_p nach dem Aufruf NULL ist. Änderungen an lokalen Variablen sind beim Aufrufer nicht sichtbar, da in C alles call-by-value ist. Entweder Du übergibst einen Zeiger auf den Zeiger, damit q_extract den Zeiger selbst ändern kann, oder Du zeigst den Erfolg der Funktion mit einem Rückgabewert an (wobei ich da die zweitere Variante bevorzugen würde).


    Zum Schluss noch ein kleiner Hinweis auf etwas, was ich als schlechten Stil bezeichnen würde: Den Speicher für data allokiert bei dieser Queue der Aufrufer, freigeben tut aber die Queue (in q_node_free). Eigentlich sollte sich um die Freigabe immer derjenige kümmern, der den Speicher auch angefordert hat. So nimmst Du Dir die Möglichkeit, jemals etwas in die Queue zu packen, was nicht mit malloc/calloc allokiert wurde.

    Ok now my next review:


    I had to re-install my system since I didn't manage to combine yaVDR 0.5 with versions recent enough to use VA-API, so now I am using gen2vdr with the following versions:


    xf86-intel-driver 2.9.917
    libva 1.5.0
    libva-intel-driver git
    ffmpeg 1.2.6-r1
    Mesa 10.2.8


    ...and softhddevice from Antti's master branch (no libavfilter support) with va-api-glx


    ...on ASRock Q1900-ITX (Intel Celeron I1900 BayTrail)


    All field orders are set to 2/1. Resolutions 576i and 720p are running pretty perfectly with HQ / Anamorphic (what's the difference?) scaling and MADI. With MCDI I notice interlace bars and juddering with N24 newsticker, MADI looks very, very good here.


    I am having problems displaying 1080i smoothly. With every deinterlacer except Weave, I have video running just a tick too slow, which causes A/V sync getting lost and resynchronization accompanied with a glitch every ten or so seconds. Is the I1900 just too slow to handle proper deinterlacing with 1080i or is there anything I can tune / provide as information to debug? I am afraid I can't run intel_gpu_top (see output below), but CPU usage is around 35%.


    Code
    1. intel_gpu_top: .../intel-gpu-tools-1.3/lib/instdone.c:329: init_instdone_definitions: Assertion `(devid == 0x3577 || devid == 0x2562 || devid == 0x3582 || devid == 0x2572)' failed.


    But even without proper 1080i deinterlacing I now have a really quite cheap and low-power HD-VDR. Thanks for and keep up the good work!


    EDIT: Display is running at 1920x1080@50

    Da fehlt erstmal nichts, die Versionen sind nur unterschiedlich. Das gleiche Problem hatte ich mit meiner TBS 6982.


    Das passiert, wenn Du voneinander abhängige Treiber des Kernels und des media_build mischt, da in media_build einige Module des Originalkernels neu gebaut werden.


    Konkret:
    Bei mir war das Problem, dass ich die Module dvb_core.ko, rc_core.ko und die Module der saa716x nach dem Installieren des media_build doppelt hatte, einmal aus dem originalen Kernel-Tree und einmal aus dem make install des media_build. Ein modprobe saa716x_tbs_dvb hat dann versucht dvb_core zu laden, aber dabei das alte Modul erwischt, welches von der Symbolversion her nicht passt. Ich habe dann einfach die alten Module gelöscht und nur die neuen verwendet. Da IR-Empfänger der Karten aus dem media_build sich an die Module des Original-Kernels dranhängen, hatte das bei mir allerdings zur Folge, dass ich auch lirc_serial aus dem media_build nehmen musste (neues rc_core für die Karte -> altes lirc_serial passte nicht mehr zu rc_core usw.)

    Now I have replaced board and CPU with a Celeron J1900, with the following observations (versions same as above):


    - va-api-glx crashes at startup with an Xorg error message suggesting low resources, but was ok with the old board
    - 576i and 720p now both run with HQ scaling (no surprise) and MADI/MCDI, but with MCDI I see stripes in N24's newsticker. Field order has to be set to 2/1, otherwise the picture is juddering pretty badly
    - 1080i yet untested
    - micro juddering is now negligible, though still present, visible only with very slow motion
    - now XBMC crashes (reason yet unknown)

    Just a short summary before upgrading:


    Currently I am running the whole thing on a pre-sandybridge system with following versions:
    xf86-video-intel 2.99.911 (after 912 XBMC keeps crashing on startup)
    libva master
    libva-intel-driver master
    ffmpeg 2.4.3 (I find the version numbers pretty confusing here, since rofa mentions 1.2.6)


    Runs pretty good up to 720p, HQ scaling being only available on 576i. The platform only provides Bob deinterlacer, which is a great improvement compared to no deinterlacing ;) but still lots of micro juddering.


    EDIT: 1080i is playing back too slow, loses a/v sync after a few seconds


    Tomorrow I will replace the old board with an AsRock Q1900-ITX, and report back what's working there and how.

    Wenn die Schüssel nicht gerade ausser Reichweite und Kabelziehen unmöglich ist, würde ich das LNB einfach durch ein Quad (nicht Quattro!) ersetzen. Das kann ohne Multischalter direkt vier Tuner versorgen und dürfte wesentlich günstiger kommen als die Einkabellösung.

    Das Problem ist ein anderes: Das Literal 'c' ist in C vom Typ int, nicht vom Typ char. In C++ ist es vom Typ char. Der Compiler darf also garkeine Warnung ausgeben.


    Und bei einer Zuweisung int(-Literal) an char meckert er auch nicht, solange das Literal in den Wertebereich von char passt.


    Code
    1. #include <stdio.h>
    2. int main()
    3. {
    4. printf( "I am C%s\n", sizeof( 'a' ) == sizeof( char ) ? "++" : "" );
    5. }

    Ah, ich sehe es sind noch weitere C++ Verfechter anwesend :D


    Ein gekapseltes Array wäre z.B. ein std:.vector (variable Größe, also "reallokierbar") oder std::tr1::array (ab gcc 4.2 glaube ich, feste Größe wie []).


    Code
    1. {
    2. std::vector<char> puffer(8192);
    3. char* ptr = &puffer[0];
    4. // Mit ptr wie mit einem malloc Array verfahren
    5. } // free vergessen :)


    Ganz allgemein nennt sich diese Technik RAII (Google). Man koppelt alles, was freigegeben werden muss, direkt an ein Objekt, welches das Freigeben im Destruktor erledigt. Hat auch den Vorteil, dass es egal ist, ob der Block durch }, return, break, throw oder sonstwie verlassen wird (was man in C oft durch etwas wie das unbeliebte "goto error_exit" gelöst hat).


    EDIT:
    moviemax:

    Zitat


    inline char* get_c_String(
    return m_string.c_str();


    )


    Zeiger nur gültig sollange object::m_string existiert und nicht geändert wird!


    Zudem muss die Rückgabe Zeiger-auf-const sein, da c_str's Rückgabetyp es auch ist. Ein "wegcasten" des const und schreibender Zugriff auf den Speicher ist zudem undefiniert. Für so etwas s.o.

    Kleiner Offtopic-Hinweis: Mit std::string würdest Du Dir das strdup'e und das (potentiell vergessbare) ge'free'e sparen ;)


    EDIT:
    Ich sehe gerade, die Strings sind nicht-konstant. Falls die Arrays nach dem Einlesen geändert werden, vergiss meinen Hinweis.


    EDIT2:
    In dem Fall würde ein gekapseltes Array das strdup'e und ge'free'e sparen.

    Man sieht, dass der obere "PCI-Slot" etwas nach rechts verschoben ist ggü. den anderen PCI-Slots. Damit kann das eigentlich nur ein AGP oder PEG (PCI-Express x16) Slot sein. Da eine TV-Karte mit AGP unwahrscheinlich ist, gehe ich von PEG aus.


    Damit dürfte die Karte einen PCI-Express x1 Anschluss besitzen. Denn diesen kann man auch in einen PCI-Express x16-Slot einstecken, dann sieht's halt so aus als wäre der Anschluss zu kurz, wie hier im Bild.

    Zitat

    Original von blehnert
    14400min : (60min/h) = 240h
    14400min / 60 = 4h


    14400 min : (60 min/h)
    = 14400 min : (60 min / 60 min)
    = 14400 min : 1
    = 14400 min


    Also, wenn dann richtig (konfus), gell? :D