2017-07-05 5 views
1

Ich versuche, Video-Streaming-Server mit Indy Http Server zu erstellen. Ich verwende Entfernungsanfragen, um große Dateien zu senden. Ein Datenblock ist 10 MB lang. Wenn die Videodatei, die den Client anfordert, kleiner als 10 Mb ist, ist alles in Ordnung und es wird Vido abgespielt. Aber wenn die Dateigröße länger als 10 MB ist, gebe ich den ersten Datenblock zurück. Dann fragt mich der Client nach einem weiteren Datenblock vom Ende der Datei und dann sagt mein Client, dass es ein nicht erkennbares Videoformat ist. Kann mir jemand sagen, wo das Problem in meinem Code ist?Erstellen Sie Video-Streaming-Server in Indy

mein Servercode

procedure TForm1.Button1Click(Sender: TObject); 
begin 
    Caption := 'Running'; 
    FServer := TIdHTTPServer.Create(Self); 
    FServer.DefaultPort := 7070; 
    FServer.OnCommandGet:[email protected]_Get; 
    FServer.Active := True; 
end; 

procedure TForm1.External_Get(AContext: TIdContext; 
    ARequestInfo: TIdHTTPRequestInfo; AResponseInfo: TIdHTTPResponseInfo); 
var 
    FS: TFileStream; 
    Ranges: TIdEntityRanges; 
    Range: TIdEntityRange; 
begin 
    Ranges := ARequestInfo.Ranges; 
    Range := Ranges.Ranges[0]; 

    FS := TFileStream.Create('/home/user/Desktop/large_file.mp4', fmOpenRead or fmShareDenyWrite); 
    AResponseInfo.ContentType := 'video/mp4'; 
    AResponseInfo.AcceptRanges := 'bytes'; 
    AResponseInfo.ContentStream := TIdHTTPRangeStream.Create(
    FS, 
    Range.StartPos, 
    Range.StartPos + 1024*1024*10, 
    True 
); 
    AResponseInfo.FreeContentStream := True; 

    AResponseInfo.ContentRangeStart := TIdHTTPRangeStream(AResponseInfo.ContentStream).RangeStart; 
    AResponseInfo.ContentRangeEnd := TIdHTTPRangeStream(AResponseInfo.ContentStream).RangeEnd; 
    AResponseInfo.ContentRangeInstanceLength := AResponseInfo.ContentRangeEnd - Range.StartPos + 1; 
    AResponseInfo.ContentLength := FS.Size; 
    AResponseInfo.ResponseNo := 206; 
end; 

Und hier ist mein Client-Code (ich benutze Firefox):

<!DOCTYPE html> 
<html> 
<head> 
    <meta content="text/html;charset=utf-8" http-equiv="Content-Type"> 
    <meta content="utf-8" http-equiv="encoding"> 
</head> 
<body> 

<video width="400" controls> 
    <source src="http://localhost:7070/test38.mp4" type="video/mp4"> 
    Your browser does not support HTML5 video. 
</video> 

</body> 
</html> 
+0

Wenn Seite geladen http5 Videosteuerung automatisch Anfrage sendet. Client ist eine gültige HTML-Seite. Und ich möchte alle großen Dateien als Bereichsanforderungen senden. –

Antwort

4

Es gibt mehrere Fehler in der Server-Code.

Sie bestätigen nicht, dass ein Bereich tatsächlich angefordert wird, oder respektieren sogar einen Endbereich, wenn einer vorhanden ist.

Sie setzen die Eigenschaft AResponseInfo.ContentLength auf die volle Größe der Datei, auch wenn Sie nicht die gesamte Datei gleichzeitig senden. Dieser Wert gehört stattdessen in die Eigenschaft AResponseInfo.ContentRangeInstanceLength, wenn eine Entfernungsantwort gesendet wird. Sie müssen ContentLength auf die Größe der Daten festlegen, die tatsächlich in der Antwort gesendet werden. In diesem Fall handelt es sich um den aktuellen Bereichsblock. Es ist am besten, die ContentLength überhaupt nicht zu setzen, Sie können den Server für Sie basierend auf dem zugewiesenen ContentStream berechnen lassen.

Sie setzen die Eigenschaft AResponseInfo.ResponseNo unbedingt auf 206, auch wenn ein Bereich überhaupt nicht angefordert wird oder der angeforderte Bereich nicht erfüllt werden kann. TIdHTTPRangeStream führt Validierungen in seinem Konstruktor durch und legt seine ResponseCode-Eigenschaft entsprechend fest. Das ist der Wert, den Sie ResponseNo zuweisen sollten.

etwas ähnlich stattdessen versuchen:

procedure TForm1.External_Get(AContext: TIdContext; 
    ARequestInfo: TIdHTTPRequestInfo; AResponseInfo: TIdHTTPResponseInfo); 
var 
    FS: TFileStream; 
    Range: TIdEntityRange; 
    StartPos, EndPos: Int64; 
begin 
    if not FileExists('/home/user/Desktop/large_file.mp4') then 
    begin 
    AResponseInfo.ResponseNo := 404; 
    Exit; 
    end; 

    try 
    FS := TFileStream.Create('/home/user/Desktop/large_file.mp4', fmOpenRead or fmShareDenyWrite); 
    except 
    AResponseInfo.ResponseNo := 500; 
    Exit; 
    end; 

    AResponseInfo.ContentType := 'video/mp4'; 
    AResponseInfo.AcceptRanges := 'bytes'; 

    if ARequestInfo.Ranges.Count = 1 then 
    begin 
    Range := ARequestInfo.Ranges.Ranges[0]; 

    StartPos := Range.StartPos; 
    EndPos := Range.EndPos; 

    if StartPos >= 0 then 
    begin 
     // requesting prefix range from BOF 
     if EndPos >= 0 then 
     EndPos := IndyMin(EndPos, StartPos + (1024*1024*10) - 1) 
     else 
     EndPos := StartPos + (1024*1024*10) - 1; 
    end else 
    begin 
     // requesting suffix range from EOF 
     if EndPos >= 0 then 
     EndPos := IndyMin(EndPos, 1024*1024*10) 
     else 
     EndPos := (1024*1024*10); 
    end; 

    AResponseInfo.ContentStream := TIdHTTPRangeStream.Create(FS, StartPos, EndPos); 
    AResponseInfo.ResponseNo := TIdHTTPRangeStream(AResponseInfo.ContentStream).ResponseCode; 

    if AResponseInfo.ResponseNo = 206 then 
    begin 
     AResponseInfo.ContentRangeStart := TIdHTTPRangeStream(AResponseInfo.ContentStream).RangeStart; 
     AResponseInfo.ContentRangeEnd := TIdHTTPRangeStream(AResponseInfo.ContentStream).RangeEnd; 
     AResponseInfo.ContentRangeInstanceLength := FS.Size; 
    end; 
    end else 
    begin 
    AResponseInfo.ContentStream := FS; 
    AResponseInfo.ResponseNo := 200; 
    end; 
end; 
+0

Das einzige Problem ist bisher, dass der Player in Firefox nur nach einem Datenblock fragt, aber auf Chrome einwandfrei funktioniert. Aber ich denke, das ist kein Problem deines Codes –