![]() |
Video aus (Teil-)Stream abspielen
Hallo,
ich suche eine Möglichkeit, ein Video aus einem Stream heraus abzuspielen. Ich habe eine Datei, in der mehrere Videos hintereinander angehängt sind, die unterschiedliche Formate und Codexe haben, aus der ich nun zB Video Nr 3 abspielen will. Erste Frage: gibt es Komponenten, die ein Abspielen aus einem Stream heraus ermöglichen? Ein Vor-/Zurückspulen bzw an eine bestimmte Position springen sollten möglich sein. Zweite Frage: mit welchem Stream mache ich das am besten? Weil ein TFileStream geht ja über die komplette Datei, ich will aber nur einen Teil davon als eigenständigen Stream betrachten, und ein TMemoryStream kopiert ja den Inhalt in den Speicher, was ich bei Videos und den damit verbundenen Dantenmengen vermeiden will. Vielen Dank für eure Antworten Dominik |
Re: Video aus (Teil-)Stream abspielen
Mal was Billiges:
Delphi-Quellcode:
Type TStreamPart = Class(TStream)
Private _Stream: TStream; _Offset, _Len: Int64; Protected Function GetSize: Int64; Override; Procedure SetSize(NewSize: LongInt); Overload; Override; Procedure SetSize(Const NewSize: Int64); Overload; Override; Public Constructor Create(Stream: TStream; Const Start, Length: Int64); Function Read(Var Buffer; Count: LongInt): LongInt; Override; Function Write(Const Buffer; Count: LongInt): LongInt; Override; Function Seek(Offset: LongInt; Origin: Word): LongInt; Overload; Override; Function Seek(Const Offset: Int64; Origin: TSeekOrigin): Int64; Overload; Override; End; Function TStreamPart.GetSize: Int64; Begin Result := Min(Max(_Stream.Size - _Offset, 0), _Len); End; Procedure TStreamPart.SetSize(NewSize: LongInt); Begin SetSize(Int64(NewSize)); End; Procedure TStreamPart.SetSize(Const NewSize: Int64); Begin Raise Exception.Create('read only'); End; Constructor TStreamPart.Create(Stream: TStream; Const Start, Length: Int64); Begin _Stream := Stream; _Offset := Start; _Len := Length; End; Function TStreamPart.Read(Var Buffer; Count: LongInt): LongInt; Begin Result := _Stream.Read(Buffer, Min(Int64(Count), Size - Position)); End; Function TStreamPart.Write(Const Buffer; Count: LongInt): LongInt; Begin Result := _Stream.Write(Buffer, Min(Int64(Count), Size - Position)); End; Function TStreamPart.Seek(Offset: LongInt; Origin: Word): LongInt; Begin Result := _Stream.Seek(LongInt(Min(Max(Int64(Offset), 0) + _Offset, MaxInt)), Origin); End; Function TStreamPart.Seek(Const Offset: Int64; Origin: TSeekOrigin): Int64; Begin Result := _Stream.Seek(Max(Offset, 0) + _Offset, Origin); End;
Delphi-Quellcode:
Und schon hat man einen neuen Stream, welcher einen Teil eines anderen Streams liefert.
Var X: TStream;
X := TStreamPart.Create(MyFileStream, 1000, 10); In diesem Fall z.B. die Bytes 1000 bis 1009 von einem FileStream. (falls ich mich jetzt nicht verdacht hab) |
Re: Video aus (Teil-)Stream abspielen
Hallo himitsu,
vielen Dank für deine Hilfe. Ich habe mir den Code von dir mal genauer angeschaut und glaube, bei dir hat sich ein Fehler eingeschlichen. Für .Read und .Write benutzt du .Size und .Position der Basisklasse, außerdem wird bei .Seek der Offset falsch berechnet.
Delphi-Quellcode:
So müsste das stimmen, oder? :gruebel:
Function TStreamPart.Read(Var Buffer; Count: LongInt): LongInt;
Begin Result := _Stream.Read(Buffer, Min(Int64(Count), _Len - (_Stream.Position - _Offset))); End; Function TStreamPart.Write(Const Buffer; Count: LongInt): LongInt; Begin Result := _Stream.Write(Buffer, Min(Int64(Count), _Len - (_Stream.Position - _Offset))); End; Function TStreamPart.Seek(Offset: LongInt; Origin: Word): LongInt; Begin case TSeekOrigin(Origin) of soBeginning: Result := _Stream.Seek(LongInt(Min(Max(Int64(Offset), 0) + _Offset, MaxInt)), Origin); soCurrent: Result := _Stream.Seek(LongInt(Min(Max(Int64(Offset), 0) , MaxInt)), Origin); soEnd: Result := _Stream.Seek(LongInt(Min(Max(Int64(Offset), 0) + _Stream.Size - (_Offset + _Len), MaxInt)), Origin); end; End; Function TStreamPart.Seek(Const Offset: Int64; Origin: TSeekOrigin): Int64; Begin case Origin of soBeginning: Result := _Stream.Seek(LongInt(Min(Max(Offset, 0) + _Offset, MaxInt)), Origin); soCurrent: Result := _Stream.Seek(LongInt(Min(Max(Offset, 0) , MaxInt)), Origin); soEnd: Result := _Stream.Seek(LongInt(Min(Max(Offset, 0) + _Stream.Size - (_Offset + _Len), MaxInt)), Origin); end; End; Und hat jemand eine Idee, wie ich diesen Stream nun wiedergeben kann? |
Re: Video aus (Teil-)Stream abspielen
Mit dem Seek hast du Recht, obwohl ich jetzt auf die Schnelle nicht sagen kann, ob es so nun stimmt,
aber ich hat so das Gefühlt, daß dem leider nicht so ist. Beim Read und Write war es schon richtig, daß die Grenzen des abgeleiteten Streams genutzt wurden. Dieses Wochenende hab ich kaum Zeit, so werd' ich wohl erst nächste Woche nochmal genauer nachsehn können. Zitat:
|
Re: Video aus (Teil-)Stream abspielen
Aber ob das bei einem Video Stream klappt, halte ich für fraglich, da die Headerdaten fehlen. Er müsste dann noch die passenden Headerdaten für den Teilstream generieren, um ihn abspielen zu können.
|
Re: Video aus (Teil-)Stream abspielen
Danke, himitsu, ich werde das mal testen. Aber .Position und .Size von der Basisklasse wird doch überhaupt nicht initialisiert, oder verstehe ich das falsch? Wir leiten ja nur von TStream ab, damit sich die Klasse "Stream" nennen darf.
Zitat:
|
Re: Video aus (Teil-)Stream abspielen
Ach so, das ist natürlich was anderes. Das sind schon aneinander gehangene einzelne Videos?
|
Re: Video aus (Teil-)Stream abspielen
Size kommt über GetSize, welches auf dem QuellStream die Größe ausließt und begrenzt.
Position wird über Seek berechnet ... dort führt der TStream einen Seek(0) auf die aktuelle Position aus und Seek liefert ja dann als Ergebnis die Position, auf welche verschoben wurde, also die aktuelle Position, da ja nicht wirklich verschoben wurde. |
Re: Video aus (Teil-)Stream abspielen
Soo, ich glaub jetzt dürfte es soweit stimmen.
'ne Positionsprüfung bei Read- und Write-Zugriffen gibt's nun, denn der Zugriff über den "Hauptstream" existiert ja weiterhin, so daß von dort aus auch was geändert werden könnte, welches so jetzt abgefangen wird. In .Create wird der Hauptstream absichtlich nicht geprüft, denn Assigned(Stream) würde nur den einen Fall eines NIL-Pointers abgefangen, aber eine ungültige Objektvariable kann einfach nicht mit Sicherheit erkannt werden. Die Streamgröße kann nun auch geändert werden, aber nur wenn der TeilStream am Ende des Hauptstreams liegt und somit nichts Nachfolgendes gelöscht werden könnte. Und das Wichtigste: Das fehlerhafte Seek/Position wurde überarbeitet.
Delphi-Quellcode:
Unit StreamPart;
Interface Uses SysUtils, Classes, Math; Type TStreamPart = Class(TStream) Private _Stream: TStream; _Offset, _MaxLen: Int64; Protected Function GetSize: Int64; Override; Procedure SetSize(NewSize: LongInt); Overload; Override; Procedure SetSize(Const NewSize: Int64); Overload; Override; Public Constructor Create(Stream: TStream; Const Offset, MaxLength: Int64); Function Read(Var Buffer; Count: LongInt): LongInt; Override; Function Write(Const Buffer; Count: LongInt): LongInt; Override; Function Seek(Offset: LongInt; Origin: Word): LongInt; Overload; Override; Function Seek(Const Offset: Int64; Origin: TSeekOrigin): Int64; Overload; Override; End; Implementation Function TStreamPart.GetSize: Int64; Begin Result := Min(Max(_Stream.Size - _Offset, 0), _MaxLen); End; Procedure TStreamPart.SetSize(NewSize: LongInt); Begin SetSize(Int64(NewSize)); End; Procedure TStreamPart.SetSize(Const NewSize: Int64); Begin If _Stream.Size <= _Offset + _MaxLen Then _Stream.Size := _Offset + NewSize Else Raise Exception.Create('The StreamPart must lie at the ' + 'end of the main stream to change its size to be allowed.'); End; Constructor TStreamPart.Create(Stream: TStream; Const Offset, MaxLength: Int64); Begin _Stream := Stream; _Offset := Offset; _MaxLen := MaxLength; End; Function TStreamPart.Read(Var Buffer; Count: LongInt): LongInt; Var Pos: Int64; Begin Pos := _Stream.Position; If (Pos < _Offset) or (Pos >= _Offset + _MaxLen) Then Raise Exception.Create('The .Position is out of range.'); Result := _Stream.Read(Buffer, Min(Int64(Count), _Stream.Size - Pos)); End; Function TStreamPart.Write(Const Buffer; Count: LongInt): LongInt; Var Pos: Int64; Begin Pos := _Stream.Position; If (Pos < _Offset) or (Pos >= _Offset + _MaxLen) Then Raise Exception.Create('The .Position is out of range.'); Result := _Stream.Write(Buffer, Min(Int64(Count), _Stream.Size - Pos)); End; Function TStreamPart.Seek(Offset: LongInt; Origin: Word): LongInt; Begin Result := Seek(Int64(Offset), TSeekOrigin(Origin)); End; Function TStreamPart.Seek(Const Offset: Int64; Origin: TSeekOrigin): Int64; Begin Case Origin of soEnd: Offset := _Offset + _MaxLen + Offset; soCurrent: Offset := _Stream.Position + Offset; Else Offset := _Offset + Offset; End; Result := _Stream.Seek(Min(Max(Offset, _Offset), _Offset + _MaxLen), soBeginning); End; End. |
Re: Video aus (Teil-)Stream abspielen
Wow, danke, himitsu! Funktioniert wie ne Eins :)
Zitat:
Jetzt brauche ich nur noch eine Möglichkeit diesen Stream wiederzugeben. Als Erweiterung zur Bass.dll gibts die BassVideo.dll ( ![]() Die Demos, die dabei sind, spielen die Videos einfach nicht ab... Anzeigebereich bleibt einfach schwarz. Kann das jemand mit einer Delphi-Version unter 2009 bestätigen? Ich habe mir schon überlegt, selbst über DirectX (DirectShow) die Videos wiederzugeben... wenn ich das hinbekomme :mrgreen: Kennt jemand sonst ne Komponente die Videos aus Streams wiedergeben kann? |
Alle Zeitangaben in WEZ +1. Es ist jetzt 22:58 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