Delphi-PRAXiS
Seite 1 von 2  1 2      

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Multimedia (https://www.delphipraxis.net/16-multimedia/)
-   -   Bass.dll Internet Radio - wie die letzten 5 Minuten bekommen, ohne Aufnahme stoppen ? (https://www.delphipraxis.net/187884-bass-dll-internet-radio-wie-die-letzten-5-minuten-bekommen-ohne-aufnahme-stoppen.html)

Julian M. 12. Jan 2016 14:10

Bass.dll Internet Radio - wie die letzten 5 Minuten bekommen, ohne Aufnahme stoppen ?
 
Hallo ihr lieben,

Folgende Annahme:Ich zeichne mit der Bass.dll und unten angefügtem Code einen Internetradio-MP3 Stream dauerhaft auf.
Den code habe ich von hier: http://www.delphipraxis.net/57338-ba...aufnehmen.html
Nun möchte ich mir bestimmte Lieder inkl. Anfang raus schneiden, d.h. ich will zu einem bestimmten Zeitpunkt die vergangenen 5 Minuten bis 5 Minuten in die Zukunft als MP3 abspeichern. Die Aufzeichnung des Streams soll aber nicht gestoppt werden. Wie stelle ich das an ? Die MP3-Datei in welche die laufende Aufnahme geschrieben wird, ist gesperrt. Ich möchte auch nicht stückeln und z.B. die Aufnahme alle 30 Minuten neu starten nur damit ich an die Daten ran komme. Meine Idee wäre, den Buffer so groß zu machen, dass er 5 Minuten beinhaltet. Dann könnte ich zum Zeitpunkt x sagen: speichere mir den Buffer in Datei x. Geht das ? Wie ? Freue mich über Hilfe! Gruß Julian :-D
P.S: Ich benutze FreePascal/Lazarus v1.4.4

Delphi-Quellcode:

function OpenURL(url: PChar): Integer;
begin
  FileName:= 'd:\record.mp3';
  Result := 0;
  BASS_StreamFree(Form1.chan); // close old stream
  Form1.chan := BASS_StreamCreateURL(url, 0, BASS_STREAM_META or BASS_STREAM_STATUS, @StatusProc, 0);
  if (Form1.chan = 0) then
    Error('Can''t play the stream')
  else
    BASS_ChannelPlay(Form1.chan,FALSE);
  Form1.cthread := 0;
end;    


procedure StatusProc(buffer: Pointer; len, user: DWORD); stdcall;
begin
  if (FileName = '') then
    exit;
  if (FileStream = nil) then
      FileStream:= TFileStream.Create(FileName, fmCreate); // create the file
  if (buffer = nil) then
      FileStream.Free // finished downloading
   else
      FileStream.Write(buffer^, len);
end;



procedure TForm1.Button1Click(Sender: TObject);
var
  ThreadId: Cardinal;
begin
    cthread := BeginThread(nil, 0, @OpenURL, PChar('http://webstream.mp3'), 0, ThreadId);
end;

wicht 13. Jan 2016 07:56

AW: Bass.dll Internet Radio - wie die letzten 5 Minuten bekommen, ohne Aufnahme stopp
 
Hi!

Zitat:

Wie stelle ich das an ? Die MP3-Datei in welche die laufende Aufnahme geschrieben wird, ist gesperrt.
Mag sein, dass sie gesperrt ist, aber das liegt ja hier (zum Glück) in deiner Verantwortung, weil du den FileStream ja erstellst. Du könntest den Stream also so erstellen, dass die Datei nicht gesperrt ist, oder du machst deine Verarbeitung direkt in der StatusProc, was wohl sauberer wäre, hier ein Beispiel:

Code:
procedure StatusProc(buffer: Pointer; len, user: DWORD); stdcall;
var
  BPS: Integer;
begin
  if (FileName = '') then
    exit;
  if (FileStream = nil) then
    FileStream:= TFileStream.Create(FileName, fmCreate); // create the file
  if (buffer = nil) then
    FileStream.Free // finished downloading
  else
  // Ab hier geänderter Code
  begin
    FileStream.Write(buffer^, len);
 
    // An den Anfang gehen
    FileStream.Position := 0;

    // Sachen machen...
    // [...]

    // Und wieder ans Ende gehen
    FileStream.Position := FileStream.Size - 1;
  end;
end;

Julian M. 13. Jan 2016 08:40

AW: Bass.dll Internet Radio - wie die letzten 5 Minuten bekommen, ohne Aufnahme stopp
 
Vielen Dank,

hab jetzt schon mit "fmCreate or fmShareDenyWrite" die Möglichkeit, an die Datei ran zu kommen.
Aber du hast natürlich recht, sauberer wäre es direkt in der StatusProc zu lösen. Kannst du mit dort noch ein wenig auf die Sprünge helfen ? Wie wahrscheinlich zu erkennen ist, habe ich von FileStreams leider keine Ahnung :oops:


Mit
Delphi-Quellcode:
  FileStream.Write(buffer^, len);
schreibt er ja den Buffer in die Datei, richtig ?
Und der FileStream entspricht der gesamten Datei ? Sprich mit
Delphi-Quellcode:
FileStream.Position := 0;
komme ich an den Anfang der gesamten Aufnahme ?


Ich bitte um Lektüre :-D


Gruß Julian

wicht 13. Jan 2016 10:23

AW: Bass.dll Internet Radio - wie die letzten 5 Minuten bekommen, ohne Aufnahme stopp
 
Zitat:

Mit FileStream.Write(buffer^, len); schreibt er ja den Buffer in die Datei, richtig ?
Und der FileStream entspricht der gesamten Datei ? Sprich mit FileStream.Position := 0; komme ich an den Anfang der gesamten Aufnahme ?
Ja und ja :).
Wichtig ist, dass die Position vor jedem .Write() mit neuen Daten immer am Ende des Streams ist, sonst überschreibt .Write() Daten. Ich schreibe das hier extra, weil ich das schon ein paar Mal vergessen habe, und es dauern kann, den Fehler zu finden...

Julian M. 13. Jan 2016 19:57

AW: Bass.dll Internet Radio - wie die letzten 5 Minuten bekommen, ohne Aufnahme stopp
 
Kannst du mir nochmals helfen ? Ich wollte nun "einfach" die letzten 10 Minuten immer in einem MemoryStream festhalten und diesen bei Bedarf abspeichern. Leider ist die erstellte Datei 0 KB groß, d.h. er schreibt nichts in den Memorystream.


Delphi-Quellcode:
procedure StatusProc(buffer: Pointer; len, user: DWORD); stdcall;
begin
  if (ms = nil) then ms:= TMemoryStream.Create; // create the stream
  if (buffer = nil) then ms.Free // finished downloading
  else
  begin // Ab hier geänderter Code
    if ms.Size<=14745600 then //angabe in bit, entsprechend 10 Minuten bei 192kbit/s Stream
    ms.Write(buffer^, len) //schreibe memorystream voll
    else // wenn memorystream 10min beinhaltet, dann lösche den anfang und füge den buffer ans ende.
    begin
      ms.Position:=len;//anfangsposition um die größe des buffers nach hinten setzen
      ms.CopyFrom(ms,(ms.Size-1)-len); //den "verschobenen" teil des streams neu abspeichern
      ms.Write(buffer^, len); //den buffer wieder ans ende schreiben
    end;
    ms.Position := ms.Size - 1;
  end;
end;  



procedure TForm1.Button4Click(Sender: TObject);
begin
  ms.SaveToFile('memorystream.mp3');
end;
Danke und Gruß, Julian :stupid:

Julian M. 13. Jan 2016 22:03

AW: Bass.dll Internet Radio - wie die letzten 5 Minuten bekommen, ohne Aufnahme stopp
 
Könnte es sein, dass ein Ringbuffer genau das ist, was ich suche ?
himitsu hat hier http://www.delphipraxis.net/861255-post7.html eine Tmemoryringbuffer geschrieben, mein code sähe dann so aus ? Beim Abspeichern passiert leider wieder nichts.


Delphi-Quellcode:
procedure StatusProc(buffer: Pointer; len, user: DWORD); stdcall;
begin
  if (rb = nil) then rb:=TMemoryringbuffer.create(14745600); // create the stream
  if (buffer = nil) then rb.Free // finished downloading
  else
  begin // Ab hier geänderter Code
    rb.Write(buffer^, len) //füge den buffer ans ende
  end;
end;  



procedure TForm1.Button4Click(Sender: TObject);
begin
  rb.SaveToFile('memorystream.mp3');
end;

himitsu 14. Jan 2016 12:46

AW: Bass.dll Internet Radio - wie die letzten 5 Minuten bekommen, ohne Aufnahme stopp
 
SaveToFile funktioniert da zufällig nicht. (das schreibt nur den gesamten Ring-Speicher in die Datei, so wie er im RAM liegt ... ist wohl ein kleiner Bug)
Du könntest einen FileStream erstellen und dort über FileStream.CopyFrom oder CopyTo die entsprechenden Bytes (RingStream.DataSize) reinkopieren.

Aber bei einer MP3 kannst du das eh alles vergessen, da du so oder so nur einen Teil der MP3-Datei bekommst, die absolut nicht funktionsfähig ist.

Julian M. 14. Jan 2016 13:06

AW: Bass.dll Internet Radio - wie die letzten 5 Minuten bekommen, ohne Aufnahme stopp
 
Danke für deine Antwort, Erfahrungen nach interessiert es die meisten Player nicht, ob die MP3 ein wenig abgehackt ist.
Ich ging allerdings davon aus, dass der von Bass.dll gelieferte Buffer immer ein Frame inkl. Header ist.

Aber: mein Hauptproblem ist, dass ich mit Streams immer noch nicht klar komme.:!:

Also sagen wir Stream_A enthält:ABCDEFG
wie kopiere ich nun korrekt 'BCDEFG' in Stream B ?


Gruß Julian

himitsu 14. Jan 2016 13:21

AW: Bass.dll Internet Radio - wie die letzten 5 Minuten bekommen, ohne Aufnahme stopp
 
Grade nochmal nachgesehn:

SaveToFile sollte funktionieren.
In den Ringpuffer wird alles reingeschrieben und wenn X Bytes ausgelesen wurde, dann liegt der Anfang dieses Puffers nun auf Position X+1 und ab dieser Stelle würd auch SaveToFile speichern.

Statt Read und Write solltest du immer ReadBuffer und WriteBuffer verwenden, außer du wertest das Result aus.

Wenn per Write/WriteBuffer A bis G rein geschrieben und über Read/ReadBuffer/Seek das A ausgelesen wurde, dann sind noch B bis G drin.

Dieser RingPuffer muß auch manuell geleert werden, denn wenn er voll ist, passt nix mehr rein, da nichts automatisch gelöscht wird.



Und bezüglich Vererbung sollte ich mich für diese Klasse steinigen lassen. :oops:

wicht 14. Jan 2016 14:50

AW: Bass.dll Internet Radio - wie die letzten 5 Minuten bekommen, ohne Aufnahme stopp
 
Funktioniert es denn mittlerweile, überhaupt irgendwie Daten auf die Festplatte zu speichern mit dem SaveToFile()? Die ganze Sache sieht ausserdem gefährlich aus, weil StatusProc() glaube ich nicht im Hauptthread läuft, der SaveToFile()-Aufruf aber schon. Du müsstest den Zugriff dann synchronisieren (siehe TCriticalSection).

Zitat:

Also sagen wir Stream_A enthält:ABCDEFG
wie kopiere ich nun korrekt 'BCDEFG' in Stream B ?
Code:
procedure Kopieren(Stream_A, Stream_B: TMemoryStream);
begin
  Stream_A.Position := 1;
  Stream_B.CopyFrom(Stream_A, 6);
end;
Ist so aus dem Kopf niedergeschrieben, sollte aber passen..


Alle Zeitangaben in WEZ +1. Es ist jetzt 11:09 Uhr.
Seite 1 von 2  1 2      

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