Videoplayer für Raw-Format - Performance Problem

Alles rund um die Programmierung mit Qt
Antworten
Hol_den_Wagen
Beiträge: 7
Registriert: 12. Januar 2010 18:39

Videoplayer für Raw-Format - Performance Problem

Beitrag von Hol_den_Wagen »

Hallo zusammen,

ich schreibe im moment einen Videoplayer, welcher im Raw-Format vorliegende Videofiles mit bis zu 60 Hz bei bis zu Full-HD-Auflösung abspielen können soll. Raw-Format heißt: in den Videofiles liegen die Farbinformationen der Bildpunkte unkodiert ein Frame nach dem anderen in einem header-losen File. Ein File enthält also nacheinander die Rot-Werte aller Pixel eines Frames, dann die Grün Werte aller Pixel eines Frames und dann die Blau-Werte aller Pixel eines Frames. Dann folgt das nächste Frame usw...


Um das ganze abzuspielen muss mein Programm also das File byte-weise auslesen, aus einer durch die Auflösung der Frames festgelegten Anzahl an Bytes ein Bild erstellen, an den Farbwerten dieser Bilder noch ein paar Transformationen vornehmen und die Bilder mit einer festgelegten Framerate anzeigen. Leider habe ich dabei bereits bei niedrigen Auflösungen große Performance-Probleme und kann das Video nichtmehr ruckelfrei darstellen, weshalb ich mich nun hilfesuchend an euch wende.

Ich versuche kurz zu erklären was ich bisher mache:

Zuerst wird ein Handle auf das abzuspielende File erzeugt

Code: Alles auswählen

videoFile = new QFile(fileParameters->Name);
if (!videoFile->open(QIODevice::ReadOnly)) {
    deviceReady = 0;
    return;
}
Um das File nicht komplett in den Speicher laden zu müssen (das wäre bei Full-HD-Videos ab einer etwas umfangreicheren Länge einfach zu viel) verwende ich ein selbst-erstelltes Buffersystem, in welchem meiner Meinung nach auch mein Performance-Problem liegt. Mein Buffer ist eine QList, welche fertige Frames in Form von QImages enthält. Die QImages werden dann per QLabel::setPixmap(QPixmap::fromImage(Qimage)) mit der gegebenen Framerate angezeigt werden. Das füllen des Buffers wird von einem eigenen Thread übernommen und ist somit vom GUI entkoppelt. Da ich wie gesagt vor dem Anzeigen die Farbwerte der Pixel einer Transformation unterziehe, erstelle ich die QImages nicht direkt aus den Daten des Files, sondern speichere die gelesenen Werte der einzelnen Farbkomponenten erst in eigenen Buffern, d.h. für jede Farbkomponente einen eigenen Buffer. Diese Buffer sind Listen, welche Frames mit nur einer Farbkomponte enthalten. Die Frames werden wiederrum von Listen repräsentiert, welche die Zeilen eines Frames enthalten. Die Zeilen eines Frames werden dann ebenfalls durch Listen repräsentiert, welche die Werte der jeweiligen Farbkomponente der Pixel enthalten. Die Farbkomponenten-Buffer haben also den Typ QList<QList<QList<char *> > >.

Ich hoffe das war soweit verständlich. :?

Das füllen der Buffer dürfte nun der performance-lastige Teil sein:
Ich poste hier mal den Code wie ich das mache exemplarisch nur für eine Komponente. Erst springe ich im File per QFile::seek() zur richtigen Position. Dann lese ich Pixel für Pixel aus und hänge die Werte an meine BufferListe für diese Komponente an. Nachdem das für alle Komponenten aller Pixel eines Frames geschehen ist wird die Transformation vorgenommen und anschließend ein QImage erstellt, welches ein meinen Haupt-Buffer gehängt wird.

Hier der Code dazu:

Code: Alles auswählen

videoFile->seek(frameNumber * fileParameters->ResolutionX * fileParameters->ResolutionY * 3);
for (j = 0; j < fileParameters->ResolutionY; j++) {
    for (k = 0; k < fileParameters->ResolutionX; k++) {
        videoFile->read(oneByte, 1);         //oneByte ist vom Typ char*
        RedBufferList->last()[j][k] = oneByte;
}
// selbe Prozedur für G- und B-Komponenten
this->Color-Conversion();
this->buildImageFromComponents();
this->addImageToImagebuffer();
}
Leider dauert das befüllen des Buffers viel zu lange. Wenn ich mit dem Start des Videos warte bis 20 fertige Frames im Buffer liegen und dann während des Abspielens des Videos im Buffer-Thread unabhängig vom Abspiel-Thread den Buffer weiter fülle, beginnt das Video nach ca. 60 Frames zu ruckeln, dann muss der Abspiel-Thread also auf den Buffer-Thread warten weil keine weiteren Frames mehr im Buffer liegen. Ich finde leider seit einigen Tagen keinen Weg dieses Problem zu lösen. Würde mich sehr freuen wenn jemand einen Tipp für mich hätte.

Viele Grüße,
HdW
kater
Beiträge: 306
Registriert: 29. Dezember 2009 01:13
Wohnort: Darmstadt

Beitrag von kater »

Ich würde für den Performace Teil ganz auf Qt verzichten. Auch nur das anzeigen eins QImage oder QPixmax in einem QLabel dauert lange (für meine Verhältnisse). Aber was anderes bleibt einem ja nicht übrig wenn man kein OpenGL verwendet.

Eine Liste hat immer ein Overhead. Versuch doch mal es ohne zu machen.

Und nun eine wirklich ernst gemeinte Frage: Ist die Festplatte überhaupt schnell genug um bei RAW FullHD bei 60HZ die Daten zu liefern?

1920x1080 Pixel mal 3 Farben (für jede Farbe ein Byte) sind sagen wir mal 6.2MB. Für ein Bild. Und du willst jetzte 60 in der Sekunde. 373MB in der Sekunde. Meine Festplatte macht etwa 20MB/s. Neuere 80MB/s. SSD Festplatten mehr als 100. Ok? :)
Hol_den_Wagen
Beiträge: 7
Registriert: 12. Januar 2010 18:39

Beitrag von Hol_den_Wagen »

Danke für die Antwort. Ich sollte also zur Darstellung besser openGL verwenden? Allerdings klappt die Darstellung bisher problemlos, nur das buffern dauert zu lange. Solange sich Frames im Buffer befinden werden diese auch ruckelfrei angezeigt, nur das buffern eines Frames dauert dermaßen viel länger als das wiedergeben, dass schon nach 60 Frames (wenn sich vor Beginn der Wiedergabe bereits 20 Frames im Buffer befunden haben) der Darstell-Thread pausieren muss und warten muss bis ein neues Frame in den Buffer kommt. Ich werde mal deinen Rat befolgen und versuchen mir was ohne Liste zu überlegen.

Zum Thema Datenrate: Ein Full-HD Video mit 60 Hz und vollen 8bit Farbauflösung ist sicherlich extrem und dürfte auf gängier Hardware nicht realisierbar sein. Es ist sowieso fraglich ob dieser Fall jemals eintreten wird, deswegen lasse ich das vorerst außen vor. Auch bei 30 Hz ist es grenzwertig, aber dafür gibt es ja den Buffer. Der muss dann eben vor Beginn der Wiedergabe bereits weit genug gefüllt werden, damit bis zum Ende des Videos durchgängig aus dem Buffer gelesen werden kann wenn während der Wiedergabe ein zweiter Thread neue Frames an den Buffer dranhängt.

Aber mein Problem beginnt leider viel früher. Selbst meine kleinsten Testvideos (Auflösung 352 x 288 bei 30 Hz, das gibt nicht ganz 9 MB/s) werden nicht kontinuierlich dargestellt. Und das sollte locker jede Festplatte packen :-(
Antworten