Willkommen auf myCSharp.de! Anmelden | kostenlos registrieren
 | Suche | FAQ

Hauptmenü
myCSharp.de
» Startseite
» Forum
» Suche
» Regeln
» Wie poste ich richtig?

Mitglieder
» Liste / Suche
» Wer ist online?

Ressourcen
» FAQ
» Artikel
» C#-Snippets
» Jobbörse
» Microsoft Docs

Team
» Kontakt
» Cookies
» Spenden
» Datenschutz
» Impressum

  • »
  • Community
  • |
  • Diskussionsforum
Bitmaps effizient(!) als Video abspielen
digi333
myCSharp.de - Member



Dabei seit:
Beiträge: 302

Themenstarter:

Bitmaps effizient(!) als Video abspielen

beantworten | zitieren | melden

Ich suche eine schnellere Variante als meine aktuelle Lösung für das Problem ein C++ Pointer eines Bildes (FFMPEG) in einer Oberfläche (Panel) darzustellen. Vielleicht habt ihr ja eine Idee.

Meine Variante:


IntPtr bgr;
bgr = new IntPtr(ff.decodeNextFrame());
bgr = new IntPtr(ff.decodeNextFrame());
byte[] buffer = new byte[3*ff.height()*ff.width()];
Marshal.Copy(bgr, buffer, 0, buffer.Length);
Bitmap tmp_bmp = BGR2Bitmap(ff.height(), ff.width(), buffer);
DrawBitmap(tmp_bmp, panel_player);




public static Bitmap BGR2Bitmap(int height, int width, byte[] bgr)
        {
            if (height ≤ 0 || width ≤ 0)
                return new Bitmap(1, 1);

            Bitmap toreturn = new Bitmap(width, height, System.Drawing.Imaging.PixelFormat.Format24bppRgb);
            Rectangle rect = new Rectangle(0, 0, width, height);
            System.Drawing.Imaging.BitmapData bmpData =
                toreturn.LockBits(rect, ImageLockMode.ReadWrite, System.Drawing.Imaging.PixelFormat.Format24bppRgb);
            IntPtr ptr = bmpData.Scan0;
            int bytes = bmpData.Stride * toreturn.Height;

            if (bgr.Length == bytes)
            {
                Marshal.Copy(bgr, 0, ptr, bytes);
            }
            else
            {
                byte[] retBGR = new byte[bytes];
                for (int i = 0; i < toreturn.Height; i++)
                    Array.Copy(bgr, i * 3 * toreturn.Width, retBGR, i * bmpData.Stride, toreturn.Width * 3);
                System.Runtime.InteropServices.Marshal.Copy(retBGR, 0, ptr, bytes);

            }
            toreturn.UnlockBits(bmpData);
            return toreturn;
        }

        private void DrawBitmap(System.Drawing.Image bmp, Panel panel)
        {
            Graphics g = panel.CreateGraphics();
            g.DrawImage(bmp, 0, 0, panel_player.Width, panel_player.Height);
        }
Dieser Beitrag wurde 2 mal editiert, zum letzten Mal von digi333 am .
private Nachricht | Beiträge des Benutzers
chilic
myCSharp.de - Experte



Dabei seit:
Beiträge: 2112

beantworten | zitieren | melden

Ins Panel zeichnen sollte man während dem Paint Ereignis. Sonst ist das gezeichnete vielleicht schnell wieder weg.

Du führst zweimal Copy aus, einmal in BRR2Bitmap und einmal außerhalb. Da kann man eins streichen.

Wie viel LockBits und UnlockBits an Zeit braucht kann ich nicht sagen. Das könntest du mal messen und bei Bedarf nach Alternativen suchen.
private Nachricht | Beiträge des Benutzers
digi333
myCSharp.de - Member



Dabei seit:
Beiträge: 302

Themenstarter:

beantworten | zitieren | melden

Gibt es etwas besseres als ein Panel? Gibt es etwas in DirectX? Die Geschwindigkeit des Panels ist abhängig von seiner Größe. Ein kleines Panel ist sehr schnell bei der Darstellung, aber ein großes Panel wird dagegen schon sehr langsam.
private Nachricht | Beiträge des Benutzers
MrSparkle
myCSharp.de - Team

Avatar #avatar-2159.gif


Dabei seit:
Beiträge: 5963
Herkunft: Leipzig

beantworten | zitieren | melden

Hi digi333,

natürlich dauert das Zeichnen eines größeren Bereichs länger als das Zeichnen in einen kleinen Bereich. Und natürlich gibt es auch eine Lösung, die DirectX verwendet, da brauchst du nur mal die Forensuche zu verwenden.

Aber wie schon gesagt, ist deine Herangehensweise alles andere als effizient. Das hat chillic schon erwähnt, und es steht auch so in [Tutorial] Zeichnen in Windows-Forms-Programmen (Paint/OnPaint, PictureBox).

Wenn du allerdings deine Frames jeweils aus einer Bitmap-Datei vom Laufwerk liest, dann kann es sein, daß das Lesen der Daten wesentlich länger dauert als das eigentliche Anzeigen. Da solltest du mal den Profiler verwenden, um herauszufinden, was eigentlich am längsten dauert, und wo man ansetzen müßte, um die Performance zu verbessern.

Christian
Weeks of programming can save you hours of planning
private Nachricht | Beiträge des Benutzers
digi333
myCSharp.de - Member



Dabei seit:
Beiträge: 302

Themenstarter:

beantworten | zitieren | melden

Ich bin scheinbar bei DirectX etwas überfordert. Kann mir vielleicht jemand etwas helfen wie ich das Folgende in einer "Box" zeichne?


IntPtr bgr;
bgr = new IntPtr(ff.decodeNextFrame());
byte[] buffer = new byte[3*ff.height()*ff.width()];
private Nachricht | Beiträge des Benutzers
herbivore
myCSharp.de - Experte

Avatar #avatar-2627.gif


Dabei seit:
Beiträge: 52329
Herkunft: Berlin

beantworten | zitieren | melden

Hallo digi333,

bevor wir jetzt in die Details von DirectX einsteigen, beherzige bitte zunächst den Rat, z.B. mit einem Profiler oder auch mit der Stopwatch-Klasse festzustellen, wo überhaupt der Flaschenhals ist. Ohne eine Analyse ist das nur Stochern im Nebel. Und wenn man fälschlich einen bereits ausreichend effizienten Code-Teil optimiert, ändern sich an der Performance-Problematik gar nichts.

herbivore
private Nachricht | Beiträge des Benutzers
Roland_K
myCSharp.de - Member

Avatar #avatar-4146.jpg


Dabei seit:
Beiträge: 38
Herkunft: Weiden i. d. Opf.

beantworten | zitieren | melden

Hallo zusammen,

für so etwas einfaches würde ich jetzt auch nicht gleich auf DirectX zurückgreifen. Das ist fast wie mit Kanonen auf Spatzen schießen.. Vor allem, wenn man von DX noch keine Ahnung hat, kann das schnell ein sehr aufwändiger Weg werden.

Nutze doch den Performance-Profiler in Visual Studio, um deine Engpässe zu finden.

Spontan würde ich folgendes Untersuchen:
  • Wie schnell bekommst du die Bilder überhaupt aus der Quelle (=> ist die überhaupt schnell genug)
  • Wie effizient ist deine Konvertierung in ein Bitmap?
  • Wie schnell ist dein Draw? (auch hier kannst du optimieren)


Viele Grüße
Roland
private Nachricht | Beiträge des Benutzers
digi333
myCSharp.de - Member



Dabei seit:
Beiträge: 302

Themenstarter:

beantworten | zitieren | melden

Der "Engpass" liegt beim Zeichnen in das Panel. Bei mir also in der Funktion DrawPanel(). Ziehe ich es größer wird das Abspielen sehr langsam. Ein sehr kleines Panel (400x200) schafft 12ms pro Frame. Bei DVD-Auflösung werden es dann schon 50ms pro Frame.
private Nachricht | Beiträge des Benutzers
herbivore
myCSharp.de - Experte

Avatar #avatar-2627.gif


Dabei seit:
Beiträge: 52329
Herkunft: Berlin

beantworten | zitieren | melden

Hallo digi333,

das klingt so, als würde das (jeweils aktuelle) Bild auf die Größe des Panels skaliert gezeichnet. Das kostet natürlich viel mehr als ein unskaliertes Zeichnen. Möglicherweise wird beim Skalieren ein unnötig aufwändiges Verfahren benutzt.

Wie man bei einem Graphics-Objekt das Skalierungsverfahren einstellt, steht in [gelöst] Bitmap-Randproblem beim Verkleinern mit InterpolationMode.HighQualityBilinear. Versuchs mal mit InterpolationMode.NearestNeighbor.

herbivore
private Nachricht | Beiträge des Benutzers