Autor Beitrag
Kasko
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 126
Erhaltene Danke: 1

Win 10
C# C++ (VS 2017/19), (Java, PHP)
BeitragVerfasst: Fr 15.06.18 11:49 
Ich habe eine CustomControl, die sich PlaylistView nennt. In ihr werden Elemente in einer Playlist mit Namen und Thumbnail angezeigt. Die Methode DisplayPlaylist sorgt dafür, dass ein Thread gestartet wird, in dem die einzelnen Elemente nacheinander hinzugefügt werden und die Thumbnails (30. Frame) ausgelesen werden:

ausblenden volle Höhe C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
public void DisplayPlaylist(Playlist playlist)
{
    Thread thread = new Thread(() => DisplayElements(playlist));
    thread.Start();
}

private void DisplayElements(Playlist playlist)
{
    for (int i = 0; i < playlist.elements.Count; i++)
        DisplayElement(playlist.elements[i], i);
}

private void DisplayElement(IPlayable element, int index)
{
    VideoSelect videoSelect = null;

    if (element is Audio)
        //
    else if (element is Video)
        videoSelect = new VideoSelect(index, element.name, GetThumbnail(element.path, SystemData.thumbnailFrame));

    videoSelect.Location = GetElementsPosition(index);

    panel_List.BeginInvoke(new Action(() => 
    {
        panel_List.Controls.Add(videoSelect);
    }));
}

private Bitmap GetThumbnail(string path, int frame)
{
    VideoFileReader reader = new VideoFileReader();
    try
    {
        reader.Open(path);

        for (int i = 1; i < frame; i++)
            reader.ReadVideoFrame();

        return reader.ReadVideoFrame();
    }
    catch
    {
        return null;
    }
}


Dabei gibt es aber einige Probleme

1. Die erfolgt viel zu langsam (ca. 10 Elemente/sek). Bei einer Playlistlänge von 614 müsste man also mehr als eine Minute warten bis alle angezeigt werden. Bei jeder Veränderung der Playlist wie bei hinzufügen oder löschen eines Elementes startet das Prozedere ab dem Element von neuen. Bei hinzufügen vom 2 oder mehr wird es noch komplizierter.

2. Die Speichernutzung ist alles andere als elegant. Die ausgelesenen Thumbnails landen alle im Prozessspeicher und treiben ihn bei 54 Elementen bereits auf 2 GB hoch(laut meiner IDE) Nach ca. 230 Elementen werden gar keine Thumbnails mehr angezeigt. Zudem werden beim Playlistwechsel alle Elemente gelöscht und die neue Playlist dargestellt. Beim erneuten Wechsel auf die alte Playlist müssen also wieder alle 614 Thumbnails erneut ausgelesen werden und landen im Prozessspeicher.

Meine Frage ist jetzt wie ich die Schnelligkeit der Darstellung elegant erhöhen kann, sodass der Benutzer nicht so lange warten muss und, und das ist das größere Problem, wie ich mit den Thumbnail effektiv umgehen kann, sie nicht immer wieder neu auslesen muss und sie nicht in den Prozessspeicher zu setzen und trotzdem noch mit ihnen arbeiten kann.
Th69
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Moderator
Beiträge: 4764
Erhaltene Danke: 1052

Win10
C#, C++ (VS 2017/19/22)
BeitragVerfasst: Fr 15.06.18 12:08 
Bzgl. der Speichernutzung solltest du den VideoFileReader nach Benutzung auch wieder schließen (Close() bzw. Dispose()), am besten per
ausblenden C#-Quelltext
1:
2:
3:
4:
using (VideoFileReader reader = new VideoFileReader())
{
  // ...
}

Und merke dir am besten die Thumbnails in einem Dictionary<string, Bitmap> (Cache), so daß du vorher abfragst, ob der Thumbnail schon ausgelesen wurde.
Kasko Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 126
Erhaltene Danke: 1

Win 10
C# C++ (VS 2017/19), (Java, PHP)
BeitragVerfasst: Fr 15.06.18 13:10 
Die Nutzung von Caches ist schonmal ein guter Ansatz ;) Aber ich denke die ganze Zeit über ein Problem nach. Wenn man im Windows Explorer zwei Videos gleich nennt und dann beide Pfade auslesen möchte. Könnte es dann nicht passieren dass nicht beide Videos ausgelesen werden sondern zweimal das erste, da beide ja den selben Pfad haben.

Dies könnte dann doch auch bei den Caches passieren sodass für ein Video das falsche Thumbnail gewählt wird.
Th69
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Moderator
Beiträge: 4764
Erhaltene Danke: 1052

Win10
C#, C++ (VS 2017/19/22)
BeitragVerfasst: Fr 15.06.18 14:20 
Dann speichere doch Pfad+Dateiname im Dictionary ab.
Kasko Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 126
Erhaltene Danke: 1

Win 10
C# C++ (VS 2017/19), (Java, PHP)
BeitragVerfasst: Fr 15.06.18 14:34 
Das meine ich ja. Der Pfad ist sowieso directorypath + dateiname, aber wenn man zwei Dateien gleich nennt dann kommt es ja zu Komplikationen
Th69
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Moderator
Beiträge: 4764
Erhaltene Danke: 1052

Win10
C#, C++ (VS 2017/19/22)
BeitragVerfasst: Fr 15.06.18 14:40 
Häh? In einem Verzeichnis (Pfad) kann es keine 2 Dateien gleichen Namens geben.
Kasko Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 126
Erhaltene Danke: 1

Win 10
C# C++ (VS 2017/19), (Java, PHP)
BeitragVerfasst: Fr 15.06.18 15:01 
Tut mir leid. Hab es mit der Benennung von Dateien unterschiedlichen Typs verwechselt. Da kann man zwei Dateien gleich benennen allerdings unterscheiden sie sich dann in den Endungen ;) Sorry, massiver Denkfehler :shock:
Kasko Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 126
Erhaltene Danke: 1

Win 10
C# C++ (VS 2017/19), (Java, PHP)
BeitragVerfasst: Mo 18.06.18 23:43 
In Bezug auf Schnelligkeit hatte ich jetzt den Ansatz mehrere Threads zu verwenden und die Anzahl der dafür genutzten Threads vom Benutzer vorgeben zu lassen (1 bis max 10). Die Umsetzung im Code sieht im Moment wie folgt aus (nur geänderte Teile im Vergleich zum oben bereits geposteten Code)

ausblenden C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
public void DisplayPlaylist(Playlist playlist)
{
    for (int i = 0; i < SystemData.usedDisplayingThreads; i++)
    {
        Thread thread = new Thread(() => DisplayElements(playlist, i));
        thread.Start();
    }
}

private void DisplayElements(Playlist playlist, int startIndex)
{
    for (int i = startIndex; i < playlist.elements.Count; i += SystemData.usedDisplayingThreads)
        DisplayElement(playlist.elements[i], i);
}


Das Problem liegt darin dass jetzt sehr oft null durch die Funktion GetThumbnail zurückgegeben wird also ein Fehler auftritt. Zudem wird sehr oft eine System.AccessViolationException ausgeworfen.

Den Grund darin sehe ich in dem Vorhandensein mehrerer, gleichzeitig aktiver VideoFileReader. Was das Problem jedoch konkret auslöst, weiß ich nicht und kann deshalb auch keine Lösungsansätze präsentieren. Vielleicht wisst ihr ja was der konkrete Auslöser ist und wie man das Problem beheben kann oder vielleicht kennt ihr ja auch weitere Methoden zur Schnelligkeitsverbesserung, welche vielleicht sogar eleganter sind.

LG Kasko
Kasko Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 126
Erhaltene Danke: 1

Win 10
C# C++ (VS 2017/19), (Java, PHP)
BeitragVerfasst: Di 19.06.18 22:26 
Keiner ne Idee?


Zuletzt bearbeitet von Kasko am Mi 20.06.18 22:50, insgesamt 2-mal bearbeitet
Th69
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Moderator
Beiträge: 4764
Erhaltene Danke: 1052

Win10
C#, C++ (VS 2017/19/22)
BeitragVerfasst: Mi 20.06.18 08:23 
Dann scheint wohl die VideoFileReader-Klasse nicht multithread-fähig zu sein. System.AccessViolationException: .NET Runtime Error c# worker thread [with VideoFileReader] hat wohl dieselbe Ursache.

Statt direkt mit Threads zu arbeiten, könntest du ja mal versuchen die TPL zu verwenden, d.h. Tasks oder Parallel.For/ForEach:
Gewusst wie: Schreiben einer einfachen Parallel.For-Schleife (Links sind weitere Beispiele)
Tasks and Task Parallel Library (TPL) : Multi-threading made easy

Ob das jedoch diese Fehler beseitigt, bezweifle ich eher.
Ansonsten mal direkt bei AForge bzgl. der Multithreadfähigkeit nachschauen bzw. hinterherfragen.


Zuletzt bearbeitet von Th69 am Do 21.06.18 09:16, insgesamt 1-mal bearbeitet
Kasko Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 126
Erhaltene Danke: 1

Win 10
C# C++ (VS 2017/19), (Java, PHP)
BeitragVerfasst: Mi 20.06.18 22:15 
Wie du schon richtig geahnt hast, hat das leider nicht das Problem gelöst, da es nur andere Möglichkeiten sind etwas mehr oder weniger parallel laufen zu lassen.

In der Dokumentation von AForge findet sich leider auch nichts :/
OlafSt
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 486
Erhaltene Danke: 99

Win7, Win81, Win10
Tokyo, VS2017
BeitragVerfasst: Do 21.06.18 09:22 
Dann ist zwingend davon auszugehen, das da nix mit Multithreading ist. Deine Probleme zeigen das ja auch schon deutlich an.

_________________
Lies, was da steht. Denk dann drüber nach. Dann erst fragen.
Ralf Jansen
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 4700
Erhaltene Danke: 991


VS2010 Pro, VS2012 Pro, VS2013 Pro, VS2015 Pro, Delphi 7 Pro
BeitragVerfasst: Do 21.06.18 13:09 
Ich vermute mal hinter AForge, oder wie es scheinbar jetzt heißt Accord, steckt vermutlich FFmpeg. Das das nicht Multithreading fähig ist fände ich ziemlich merkwürdig. Warum sollten sich verschiedene VideoFileReader Instanzen die sich auf verschiedene Dateien beziehen ein Problem miteinander haben :gruebel:

Aber wie auch immer; da du scheinbar Thumbnails für Videos erstellen willst incl. Caching und das am sinnvollsten ins Filesystem biete sich eigentlich an, das wenn Multithreading nicht geht, das durch Multiprocessing zu ersetzen. Also ein simple Konsolenanwendung der man Quellpfad(Video), Zielpfad(Thumbnail) und den gewünschten Frame übergibt und die dann den Thumbnail erzeugt.

Beim dem Gedanken bin ich dann über diesen Beitrag gestolpert der andeutet das das mit ffmpeg schon direkt geht ohne das man irgendwas programmieren muss (die nicht akzeptierte Antwort).
Nebenbei die akzeptierte Antwort zeigt wie man VideoFileReader in ASP.NET einsetzt. Da fällt es mir noch schwerer vorzustellen das Multithreading nicht geht.