![]() |
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: ![]() 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; |
AW: Bass.dll Internet Radio - wie die letzten 5 Minuten bekommen, ohne Aufnahme stopp
Hi!
Zitat:
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; |
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:
schreibt er ja den Buffer in die Datei, richtig ?
FileStream.Write(buffer^, len);
Und der FileStream entspricht der gesamten Datei ? Sprich mit
Delphi-Quellcode:
komme ich an den Anfang der gesamten Aufnahme ?
FileStream.Position := 0;
Ich bitte um Lektüre :-D Gruß Julian |
AW: Bass.dll Internet Radio - wie die letzten 5 Minuten bekommen, ohne Aufnahme stopp
Zitat:
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... |
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:
Danke und Gruß, Julian :stupid:
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; |
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 ![]()
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; |
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. |
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 |
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: |
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:
Code:
Ist so aus dem Kopf niedergeschrieben, sollte aber passen..
procedure Kopieren(Stream_A, Stream_B: TMemoryStream);
begin Stream_A.Position := 1; Stream_B.CopyFrom(Stream_A, 6); end; |
AW: Bass.dll Internet Radio - wie die letzten 5 Minuten bekommen, ohne Aufnahme stopp
Zitat:
|
AW: Bass.dll Internet Radio - wie die letzten 5 Minuten bekommen, ohne Aufnahme stopp
Also ich weiß nicht, ob der Ringbuffer das richtige ist. Konnte jetzt mit diesem Code testweise 1 Minute in einen 'normalen' memorystream ms aufnehmen, dann 20 sec mp3 ab der Mitte von ms in einen zweiten Memorystream ms2 kopieren und diesen auf die Platte schreiben. Ich werde weiter rumprobieren..
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<=1474560 then //angabe in byte, entsprechend 1 Minuten bei 192kbit/s Stream ms.Write(buffer^, len) //schreibe memorystream voll else // wenn memorystream 1min beinhaltet, dann kopiere einen teil davon in ms2 begin ms.Position:=round(ms.Size/2);//ab der hälfte von ms kopieren ms2:= TMemoryStream.Create; ms2.CopyFrom(ms,500000); //500000 Byte=20 sec ms2.Position:=0; ms2.savetofile('memorystream.mp3'); application.terminate; //nur damit es erst mal keine Fehlermeldungen gibt, wenn das Programm weiter läuft end; end; end; Gruß Julian :thumb: |
AW: Bass.dll Internet Radio - wie die letzten 5 Minuten bekommen, ohne Aufnahme stopp
So, OSI Layer 8 Problem scheinbar behoben. So wie es aussieht benötigt es zwei Streams weil man nicht einen Stream versetzt in sich selbst kopieren kann.
Da ich auf keinen Fall vergessen möchte, meine derzeitige (sicher nicht optimale, aber scheinbar funktionierende) Lösung zu veröffentlichen, hier der Code:
Delphi-Quellcode:
procedure TForm1.FormCreate(Sender: TObject); begin nextbufferisb:=true; end; procedure StatusProc(buffer: Pointer; len, user: DWORD); stdcall; begin if (msa = nil) then begin msa:= TMemoryStream.Create; msb:= TMemoryStream.Create; end;// create the stream if (buffer = nil) then begin msa.Free; msb.Free; // finished downloading else begin // Ab hier geänderter Code if msa.Size< 14745600 then //wenn die Aufnahme noch <10 Minuten ist (bei 192kbit/s) msa.Write(buffer^, len) //Stream A vollschreiben bis er 10 Min beinhaltet else if nextbufferisb then // wenn Stream A voll ist, kopiere in Stream B begin msa.position:=len; //Schneidet den Anfang von A ab, denn der ist älter als 10 Minuten msb.position:=0; //Setzt die Einfügeposition von Stream B an den Anfang msb.copyfrom(msa,msa.size-len); //kopiert Stream A ohne den Anfang in Stream b msb.Write(buffer^, len); //Fügt den neuesten Teil des Internetstreams ans ende von Stream B nextbufferisb:=false //das nächste mal wird anders rum kopiert, von Stream B nach Stream A end else begin //Das gleiche nur umgekehrt msb.position:=len; msa.position:=0; msa.copyfrom(msb,msb.size-len); msa.Write(buffer^, len); nextbufferisb:=true; end; end; end; procedure TForm1.Button4Click(Sender: TObject); begin msa.SaveToFile('msa.mp3'); //hier könnte man noch abfragen ob Stream A oder B der neueste ist, ist aber fast egal end; Das ganze frisst nun relativ viel Arbeitsspeicher, weil dauerhaft die letzten 10 Minuten Internetradio 2x im Ram gehalten werden. (Ich glaube ca. 50MB) aber wenn beide Streams erst mal voll sind, steigt die Größe nicht mehr weiter an, und das ist für mich das wichtige, damit ich dauerhaft aufnehmen kann. Nur wenn der Button geklickt wird, werden die letzen 10 Minuten dann auf die Platte geschrieben, sonst nichts. Vielen Dank für eure Hilfe ! Für weitere Verbesserungsvorschläge bin ich natürlich nicht abgeneigt, aber an sich bin ich erst mal zufrieden dass es funktioniert :) |
Alle Zeitangaben in WEZ +1. Es ist jetzt 17:47 Uhr. |
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