Delphi-PRAXiS
Seite 6 von 9   « Erste     456 78     Letzte »    

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Software-Projekte der Mitglieder (https://www.delphipraxis.net/26-software-projekte-der-mitglieder/)
-   -   Mp3FileUtils (https://www.delphipraxis.net/71449-mp3fileutils.html)

DeddyH 12. Aug 2011 19:55

AW: Mp3FileUtils
 
Ich bin zwar nicht Gausi, aber das klingt danach, als ob Du immer wieder Objekte erzeugst, ohne sie anschließend freizugeben. Wie sieht denn Dein Code aus?

wicht 13. Aug 2011 09:39

AW: Mp3FileUtils
 
DeddyH könnte da gut recht haben, danach hört es sich an. Benutzt du evtl. FastMM mit den Einstellungen zum Debuggen auf aktiv? Solche Effekte bekomme ich damit nämlich zustande, auch wenn ich alles Freigebe. Hast du es mal mit ReportMemoryLeaksOnShutdown probiert? Damit würdest du eventuelle Leaks vermutlich schnell finden.

MW97 13. Aug 2011 20:04

AW: Mp3FileUtils
 
Hier ist mein Code:

Delphi-Quellcode:
  //Typendeklaration für Bibliothek
  type
    TLibrary=record
      Files             :TStringList;//Damit ordne ich den Titelinfos die pfade zu
      Cols:Array[1..3] of TStringList;//Col[1] für Titel, Col[2] für Interpret, Col[3] für Spiellänge
      //...
  end;
 
  type
    TMainConfig=record
      Lib:TLibrary;
      //...
  end;
 
  //Typendeklaration für Titelinformationen
  type
    TAudioInf=record;
      Interpret: string;
      Titel   : string;
      Pfad    : string;
      Album   : string;
      Jahr    : string;
      Dauer   : integer;
  end;

  //Unit mit Prozeduren zum Auslesen der Infos (aus dem Delphitreff)
  unit UAudioInf;

  interface

  uses
   UTypes;

  procedure GetAudioInfo(FileName: string);
  procedure GetMp3Info;
  procedure GetWmaInfo;
  procedure SetUnknown;
  function GetPlaylistTitel:string;

var
  AudioInf: TAudioInf;

implementation

uses
  SysUtils, Mp3FileUtils, ATL_WMAfile, Classes;


//Hauptprozedur für Titelinformationen
procedure GetAudioInfo(FileName: string);
begin
  AudioInf.Pfad := filename;
  if (AnsiLowerCase(ExtractFileExt(FileName)) = '.mp3') then
    GetMp3Info
  else
    if AnsiLowerCase(ExtractFileExt(FileName)) = '.wma' then
      GetWMAInfo
    else
      SetUnknown;
  if AudioInf.Interpret='' then AudioInf.Interpret:='Unbekannter Interpret';
  if AudioInf.Album=''    then AudioInf.Album:='Unbekanntes Album';
  if AudioInf.Jahr=''     then AudioInf.Jahr:='unbekanntes Jahr';
end;

//Prozedur für Titelinformationen von MP3-Dateien
procedure GetMp3Info;
var
  MpegInfo: TMpegInfo;
  ID3v2Tag: TID3V2Tag;
  ID3v1tag: TID3v1Tag;
  Stream: TFileStream;
begin

  // Daten mit MP3FileUtils auslesen
  Mpeginfo:=TMpegInfo.Create;
  ID3v2Tag:=TID3V2Tag.Create;
  ID3v1tag:=TID3v1Tag.Create;
  Stream := TFileStream.Create(AudioInf.Pfad, fmOpenRead or fmShareDenyWrite);
  try
  id3v1tag.ReadFromStream(Stream);
  Stream.Seek(0, sobeginning);
  Id3v2tag.ReadFromStream(Stream);
  if Not id3v2Tag.exists then
    Stream.Seek(0, sobeginning)
  else
    Stream.Seek(id3v2tag.size, soFromBeginning);
  Mpeginfo.LoadFromStream(Stream);
  Stream.free;
  //Daten übertragen
  if mpeginfo.FirstHeaderPosition >- 1 then
  begin
    if id3v2tag.artist <> '' then
      AudioInf.Interpret := id3v2tag.artist
    else
      AudioInf.Interpret := id3v1tag.artist;
    if id3v2tag.Album <> '' then
      AudioInf.Album :=id3v2tag.Album
    else
      AudioInf.Album:=id3v1tag.Album;
    if id3v2tag.Year<> '' then
      AudioInf.Jahr:=id3v2tag.Year
    else
      AudioInf.Jahr:=id3v1tag.Year;
    if id3v2tag.title <> '' then
      AudioInf.Titel := id3v2tag.title
    else
      if id3v1tag.title <> '' then
        AudioInf.Titel := id3v1tag.title
      else
        AudioInf.Titel := ExtractFileName(AudioInf.Pfad);
    AudioInf.Dauer  := mpeginfo.dauer;
  end else
    SetUnknown;
  finally
  MpegInfo.Free;
  Id3v2Tag.Free;
  Id3v1Tag.Free;
  end;
end;

//Prozedur für Titelinformationen von WMA-Dateien
procedure GetWmaInfo;
var
  wmaFile: TWMAfile;
begin
  if Not FileExists(AudioInf.Pfad) then
  begin
    SetUnknown;
    exit;
  end;
  try
  wmaFile := TWMAFile.create;
  if wmaFile.ReadFromFile(AudioInf.Pfad) then
  begin
    if wmaFile.Title <> '' then
      AudioInf.Titel := wmaFile.Title
    else
      AudioInf.Titel := ExtractFilename(AudioInf.Pfad);
      AudioInf.Interpret := wmaFile.Artist;
      AudioInf.Dauer := Round(wmaFile.Duration);
      AudioInf.Album :=wmaFile.Album;
      AudioInf.Jahr :=wmaFile.Year;
  end else
    SetUnknown;
  finally
  wmaFile.Free;
  end;
end;

//Prozedur für Titelinformationen von unbekannten Dateien
procedure SetUnknown;
begin
  AudioInf.Titel := ExtractFileName(AudioInf.Pfad);
  AudioInf.Interpret := '';
  AudioInf.Dauer := 0;
end;

//Prozedur für Titelinformationen nach %Interpret%-%Titel%
function GetPlaylistTitel:string;
begin
  if Trim(AudioInf.Interpret)='' then
    result := AudioInf.Titel
  else
    result := AudioInf.Interpret + ' - ' + AudioInf.Titel;
end;
in meiner haupunit habe ich dann unter private ein TMainConfig-Objekt deklariert(ProConfig). Beim Programmstart werden die StringListen erstelt uns aus Dateien geladen.

Bei dieser Prozedur steigt dann der Speicherbedarf enorm an:
Delphi-Quellcode:
//Titelinformationen aktualisieren
procedure TForm1.LibRefreshInf(const Visualize: boolean);
var
  i, a, b: integer;
  Edited: boolean;
begin
  Edited:=false;
  if Visualize then
  begin
    Application.CreateForm(TFrmMakeUp, FrmMakeUp);
    FrmMakeUp.Show;
    FrmMakeUp.ChangesDone:=false;
  end;
  if ProConfig.Lib.Files.Count>0 then
  begin
    if Visualize then
    begin
      FrmMakeUp.ProgressBar1.Max:=ProConfig.Lib.Files.Count;
      FrmMakeUp.ProgressBar1.Position:=0;
    end;
    a:=0;
    for i:=ProConfig.Lib.Files.Count-1  downto 0 do
    begin
      if Visualize then
      begin
        inc(a);
        FrmMakeUp.ProgressBar1.Position:=a;
        FrmMakeUp.MainFile:=ProConfig.Lib.Files[i];
      end
      else
        Application.ProcessMessages;
      if FileExists(ProConfig.Lib.Files[i]) then
      begin
                  GetAudioInfo(ProConfig.Lib.Files[i]);
          if AudioInf.Titel<>ProConfig.Lib.Cols[1][i] then
          begin
            Edited:=true;
            ProConfig.Lib.Cols[1][i]:=AudioInf.Titel;
          end;
          if AudioInf.Interpret<>ProConfig.Lib.Cols[2][i] then
          begin
            Edited:=true;
            ProConfig.Lib.Cols[2][i]:=AudioInf.Interpret;
          end;
          if MsToMinuteSecond(AudioInf.Dauer*1000)<>ProConfig.Lib.Cols[3][i] then //MsToMinuteSecond wandelt
          begin                                                                  //Sekunden in Minute:Sekunde um
            Edited:=true;
            ProConfig.Lib.Cols[3][i]:=MsToMinuteSecond(AudioInf.Dauer*1000);
          end;
          end;
      if not FileExists(ProConfig.Lib.Files[i]) then
      begin
        ProConfig.Lib.Files.Delete(i);
        for b:=1 to 3 do
          ProConfig.Lib.Cols[b].Delete(i);
      end;
    end;
  end;
  if Visualize then
  begin
    FrmMakeUp.ChangesDone:=true;
    FrmMakeUp.Close;
  end;
end;
Wenn ich der Prozedur true übergebe zeigt sie mir eine kleine form, die den status anzeigt, aber auch wenn ich das ganze im hintergrund machen lasse (false übergeben) steigt der bedarf.

EDIT:Ich habe gerade einen sehr eigenartigen Effekt festgestellt: Wenn ich in der Bibliothek meines Player 224 Elemente habe(Count der Stringlisten=224, Bedarf beim Start~1,8MB) dann steigt der Bedarf der Anwendung beim ausführen der Prozedur LibRefreshInf nicht. Wenn es aber 1014 Titel sind(Bedraf bei Start ~2,5 MB), dann steigt auf auf 182 MB. ???

Luckie 13. Aug 2011 22:29

AW: Mp3FileUtils
 
Also ich würde als erste dem Code ein Refactoring unterwerfen. So, wie ich das sehen kann, scheint alles in der Unit des Formulares zu stecken. Dazu kommen anscheinend noch globale Variablen und globale Datenstrukturen, weil du da noch einfache Prozeduren und Funktionen hast, die nicht Methoden deiner Klasse sind. Ich würde das erst mal alles sauber in eine oder eventuell sogar mehrere Klassen kapseln und so die GUI von der Datenverarbeitung trennen. Das hilft später bei der Erweiterung, der Überarbeitung und auch jetzt beim Finden von Fehlern und Speicherlecks. Eventuell verschwindet er ja schon beim Refactoring, wenn du wieder mehr Übersicht über deinen Code hast. Weil das ist doch nicht alles oder wird nicht alles bleiben oder?

MW97 14. Aug 2011 11:34

AW: Mp3FileUtils
 
Nein, das ist nicht alles. Die Prozeduren zum Auslesen der Infos habe ich in eine eigene Klasse gepckt. Sie waren schon vorher in einer eigenen Unit. Aber es hat nichts geändert.

DeddyH 14. Aug 2011 11:37

AW: Mp3FileUtils
 
Wird Action im OnClose von FrmMakeUp auf caFree gestellt?

MW97 16. Aug 2011 14:01

AW: Mp3FileUtils
 
Ja, das ist so. Und er zeigt mir die Form ja auch nur an, wenn ich der Prozedur true übergebe. Wenn ich false übergebe, steigt der Speicherbedarf auch.

DeddyH 16. Aug 2011 14:02

AW: Mp3FileUtils
 
Wird noch an anderer Stelle dynamisch Speicher angefordert?

MW97 16. Aug 2011 14:09

AW: Mp3FileUtils
 
Ich habe in dem Programm einige andere kleine Formen, aber ich erstelle alle mit Application.CreateForm und bei OnClose ist Action überall auf caFree. Den record TAudioInf habe ich in eine Klasse umgeschrieben und die Prozeduren GetAudioInfo... dareingepackt. Ich habe dann in der Prozedur ein TAudioInf deklariert, es erstellt und gebe es mit try...finally und Free wieder frei.

DeddyH 16. Aug 2011 14:16

AW: Mp3FileUtils
 
Dann würde ich gern mal die Klasse TAudioInf sehen.


Alle Zeitangaben in WEZ +1. Es ist jetzt 02:18 Uhr.
Seite 6 von 9   « Erste     456 78     Letzte »    

Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz