TMediaPlayer, Videobild Capture als Bitmap speichern, Lösung!



  • Hallo Leute,

    ich habe hier mal was für euch, in Sachen TMediaPlayer.
    Heute Mittag erhielt ich eine Anfrage per Email, wie
    man ein Videobild Capturen kann, mit anderen Worten:
    Abspeichern des aktuellen Frames eines Videos als Bitmap.

    Wer so eine Funktion schon hat, der hat sicherlich wie ich
    eine Ableitung der Klasse TMediaPlayer erstellt und die
    Funktion "Paint()" umgeschrieben 😉

    Für alle die aber eine möglichst einfache Methode suchen, und
    auch für den Fragenden, habe ich mir heute mal eine Lösung überlegt.

    Der Einfachste Weg ist, wenn wir ein Display für den MediaPlayer wählen
    auf dessen Canvas wir Problemlos zugreifen können, dazu kommt das übliche
    Panel nicht in Frage, aber unsere Form schon.
    Leider wird das nicht Unterstützt das man die Form zur Entwurfzeit als
    Display wählen kann, daher lassen wir dieses Proberty offen.

    Hier mal die Reihenfolge:
    1. Form und MediaPlayer erstellen nach eigenem ermessen
    2. Ein Button, der bei seiner OnClick Auslösung das Frame speichern soll.
    3. SaveDialog nicht vergessen 😉
    4. Display proberty beim MediaPlayer offen lassen!

    5. Im FormShow Event der Form folgendes Eintragen:

    MediaPlayer1->Display = Form1; // Die Form als Display zuweisen
    

    6. Erzeugt eine Globale Variable namens VideoRect

    TRect VideoRect;
    

    7. Im OnClick Event eures Buttons zum speichern des Videobildes schreibt ihr folgendes:

    bool PlayGo = false;                      //Video nicht weiter spielen
            VideoRect = MediaPlayer1->DisplayRect;    //Videobild Größe hollen
            if (MediaPlayer1->Mode != mpPaused) {     //frage ob MediaPlayer Pausiert wurde
                    PlayGo = true;                    //wenn nicht dann weiter spielen ja (true)
                    MediaPlayer1->Pause();            //MediaPlayer Pausieren
            }
            if (SaveDialog1->Execute()) {             //SaveDialog aufrufen
                    Graphics::TBitmap *bild = new Graphics::TBitmap;     // neue Bitmap erstellen
                    bild->Width = VideoRect.Right;                       //Bitmap die Videobreite zuordnen
                    bild->Height = VideoRect.Bottom;                     //das Gleiche mit der Höhe
                    bild->Canvas->CopyRect(VideoRect,Form1->Canvas,VideoRect);   // Videobild in Bitmap kopieren
                    bild->SaveToFile(SaveDialog1->FileName);                     // Bitmap abspeichern
                    delete bild;                                                 // bild Zeiger löschen;
            }
            if (PlayGo) {                                                        // wenn Video weiterspielen
                    MediaPlayer1->Resume();                                      // Video weiterspielen
            }
    

    8. Versucht diese Vorgehensweise zu Verstehen und den Code entsprechen euren
    Vorstellungen anzugleichen, vergesst aber bitte auch nicht try-catch um Exeptions
    abzufangen, und und...
    Wenn euch TRect nicht bekannt ist, so macht euch über die Hilfe und Suchfunktion im
    Forum etwas schlau, so werdet ihr schnell dazu fähig sein das Videobild in der Mitte
    der Form anzuzeigen, bzw. an einer beliebigen Stelle. Dafür Zuständig ist das Proberty
    "MediaPlayer1->DisplayRect;"
    Damit kann man auch das Videobild verkleinern oder vergrößern.

    Für weitere Fragen bin ich gerne offen.

    gruß Micha

    PS:
    Wenn das Interesse Besteht, würde ich mir auch die Mühe machen einige Tutorials
    zum TMediaPlayer zu schreiben, vorallem was "guttes" Fullscreen angeht (und
    nicht wie im Verweiß der FAQ), sowie unterschidliche Darstellungsgrößen, Datentypen, Fehlerbehandlung und und und ...



  • promicha schrieb:

    Der Einfachste Weg ist, wenn wir ein Display für den MediaPlayer wählen
    auf dessen Canvas wir Problemlos zugreifen können, dazu kommt das übliche
    Panel nicht in Frage[...]

    Wo ist das Problem beim Panel?

    TCanvas *canv = new TCanvas();
      canv->Handle = GetDC(Panel1->Handle);
      Image1->Canvas->CopyRect(Panel1->ClientRect, canv, Panel1->ClientRect);
      ...
    

    vorallem was "guttes" Fullscreen angeht (und
    nicht wie im Verweiß der FAQ)

    Was genau ist "gutes Fullscreen", bzw. was ist am FAQ-Link schlecht?



  • Das Problem beim Panel ist, das ich nur Graues BtnFace im
    Bild erhalte, ich habe es so versucht und normalerweise
    müßte es auch Funktionieren, tut es aber nicht. Ich habe
    das gleiche auch mit anderen möglichen Komponenten versucht,
    ohne Erfolg, das Einzige was bei mir Funktioniert ist die
    Form.

    Fullscreen, schon mal einen Player geschrieben mit Verwendung
    des FAQ-Link Beispiels? (Der Link)

    Der Reihe nach:

    // Get a handle to the MediaPlayer display window 
    // may be "AVIWnd32" for WinNT 
    HDisplayWindow = FindWindow("AVIWnd", NULL);
    

    Also erst mal Prüfen auf welches System der Player läuft,
    oder alle Fenster abfragen und das nehmen welches mit AVIWnd
    beginnt.
    und man sollte es schon so Schreiben:

    HWND HDisplayWindow = FindWindow("AVIWnd", NULL);
    

    sonst weiss der Compiler nicht was HDisplayWindow sein soll.
    Ist ja auch nur ein Schönheitsfehler, somit übersehbar.

    Das Funktioniert soweit ganz gut, aber wie Steuer ich jetzt
    den Player? Ich kann dem AVIwindow doch kein Popup-Menu zuordnen
    (Mit einfachen Mitteln wärend der Entwurfzeit).
    Und ich möchte gerne per OnMouseMove feststellen ob die Maus im
    unteren Bildschirmrand sitzt, damit ich dort die Steuerbuttons
    einblenden kann.
    Wir haben bei dieser Methode leider ein fremdes Fenster, welches
    wir nicht wärend der Entwurfzeit Bearbeiten können, nützen wir
    aber unsere Form als Display, so haben wir die Möglichkeiten die
    ich oben erwähnte.
    Und mit:

    SetWindowPos(Form1->Handle, HWND_TOPMOST, 0, 0, Screen->Width, Screen->Height, NULL);
    

    bekommen wir unsere Form auch in Fullscreen. Sollte man jetzt sagen das wir
    genauso gut dieses AVI Fenster unseren Vorstellungen anpassen können, dann
    hat das nichts mehr mit der IDE und VCL zu tun, das ist dann WinAPI.

    Als Zusatz sei noch gesagt, das Capturen aus diesem Player-Fenster
    funktioniert auch tadellos, habs getestet.

    Graphics::TBitmap *bild = new Graphics::TBitmap;
    bild->Width = MediaPlayer1->DisplayRect.Right;
    bild->Height = MediaPlayer1->DisplayRect.Bottom;
    TCanvas *Capture = new TCanvas();
    Capture->Handle = GetDC(HDisplayWindow);
    if (Capture->Handle)
    	bild->Canvas->CopyRect(MediaPlayer1->DisplayRect, Capture, MediaPlayer1->DisplayRect);
    
    delete Capture;
    bild->SaveToFile(SaveDialog1->FileName);
    delete bild;
    

    gruß Micha


Anmelden zum Antworten