Videoplayer für Raw-Format - Performance Problem
Verfasst: 22. März 2010 13:01
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
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:
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
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;
}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();
}Viele Grüße,
HdW