2017-07-05 1 views
1

J'essaie de créer un serveur de streaming vidéo en utilisant le serveur HTTP Indy. J'utilise des requêtes à distance pour envoyer de gros fichiers. Un morceau de données a une longueur de 10 Mo. Si le fichier vidéo qui demande le client est inférieur à 10 Mo alors tout est OK et vido est joué. Mais si la taille du fichier est supérieure à 10 Mo, je renvoie le premier bloc de données. Ensuite, le client me demande un autre morceau de données à la fin du fichier, puis mon client dit que c'est un format vidéo méconnaissable. Quelqu'un peut-il me dire où est le problème dans mon code.Créer un serveur de streaming vidéo en indy

mon code serveur

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; 

Et voici mon code client (j'utilise 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

Lorsque les charges de page http5 contrôle vidéo envoie automatiquement une demande. Le client est une page html valide. Et je veux envoyer tous les fichiers volumineux comme demandes de distance. –

Répondre

4

Il y a plusieurs erreurs dans votre code serveur.

Vous ne validez pas qu'une plage est réellement demandée, ou même que vous respectez une plage de fin si elle est présente.

Vous définissez la propriété AResponseInfo.ContentLength sur la taille maximale du fichier, même si vous n'envoyez pas le fichier complet en même temps. Cette valeur appartient à la propriété AResponseInfo.ContentRangeInstanceLength au lieu d'envoyer une réponse à distance. Vous devez définir ContentLength à la taille des données réellement envoyées dans la réponse, qui dans ce cas est votre tronçon de plage actuel. Il est préférable de ne pas définir le ContentLength, vous pouvez laisser le serveur le calculer pour vous en fonction du ContentStream affecté.

Vous définissez la propriété AResponseInfo.ResponseNo sur 206 inconditionnellement, même si aucune plage n'est demandée ou si la plage demandée ne peut pas être satisfaite. TIdHTTPRangeStream effectue des validations dans son constructeur et définit sa propriété ResponseCode en conséquence. C'est la valeur que vous devriez attribuer à ResponseNo.

Essayez quelque chose comme ceci:

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

Seul le problème à ce jour est que dans Firefox joueur demande seulement un morceau de données, mais fonctionne parfaitement sur le chrome. Mais je pense que ce n'est pas un problème de votre code –