I am trying to stream raw h264 video packets from a (IcsOverbyte) Server (TWSocketServer) to a Client(TWSocket) however I've been having some trouble trying to properly assemble the messages.
Before going into my question I just wanted to say that I've confirmed that the .h264 data is valid, after I serialize my message I deserialize it and save the video-packet data part into a file and play it with VLC, the file is playable with no issues. That way I also confirmed that my Serialize/Deserialize routine is correct (both server and client have the same source for the types and ser/des routine).
My message is like so ->
TMessageHeader = packed record
MessageID: UInt32;
TotalSize: UInt32; {Meaning HeaderSize Payload}
end;
TMediaDataMessage = record
Header: TMessageHeader;
Channel: UInt32;
Stream: UInt32;
MediaType: Byte; {0 - Video, 1 - Audio}
Data: TArray<Byte>;
function FromBytes(pBytes: TArray<Byte>): Boolean;
function ToBytes: TArray<Byte>;
function GetSize: UInt32;
end;
On the client-side I have a message assembly routine like this...
procedure TfrmMain.HandleDataAvailable(pSender: TObject; ErrCode: Word);
var
vRcvdCount: Integer;
vBytes: TBytes;
vMessageTotalSize: UInt32;
vOffset: UInt32;
begin
{$POINTERMATH ON}
if ErrCode <> 0 then
Exit;
if pSender = nil then
Exit;
SetLength(vBytes, 65536);
vRcvdCount := fTCPClient.Receive(@vBytes[0], 65536);
vOffset := 0;
try
if fRemainingDataSize > 0 then
begin
if vRcvdCount >= fRemainingDataSize then
begin
fCurrentBuf.Write(vBytes[vOffset], fRemainingDataSize);
Inc(vOffset, fRemainingDataSize);
Dec(vRcvdCount, fRemainingDataSize);
fRemainingDataSize := 0;
SetHandleMessage(fIdx.ToString 'Sync');
end
else
begin
fCurrentBuf.Write(vBytes[vOffset], vRcvdCount);
Dec(fRemainingDataSize, vRcvdCount);
end;
end;
except
reLog.Lines.Add('Error sync');
end;
try
while (vRcvdCount > 0) do
begin
vMessageTotalSize := PUInt32(@vBytes[vOffset 4])^;
if vRcvdCount >= vMessageTotalSize then
begin
fCurrentBuf.Write(vBytes[vOffset], vMessageTotalSize);
Inc(vOffset, vMessageTotalSize);
Dec(vRcvdCount, vMessageTotalSize);
SetHandleMessage('Loop');
end
else
begin
fCurrentBuf.Write(vBytes[vOffset], vRcvdCount);
fRemainingDataSize := vMessageTotalSize - vRcvdCount;
vRcvdCount := 0;
end;
end;
except
reLog.Lines.Add('Loop');
end;
//fTcpClient.Flush;
end;
FYI the exceptions never occur.
And this is the SetHandleMessage procedure
procedure TfrmMain.SetHandleMessage(pSort: string);
var
vMsgBytes: TArray<Byte>;
vMessageID: UInt32;
begin
fCurrentBuf.Position := 0;
SetLength(vMsgBytes, fCurrentBuf.Size);
fCurrentBuf.Read(vMsgBytes[0], fCurrentBuf.Size);
fCurrentBuf.Clear;
vMessageID := PUInt32(@vMsgBytes[0])^;
HandleMessage(vMessageID, vMsgBytes, pSort);
end;
I've been chasing my own tail for a while now I can't seem to pinpoint what is the issue.
I've also tried just streaming the raw .h264 to the client and save it to file and it works as well...
It seems the only thing that could be wrong is the message assembly routine.
Edit:. Decided to add the serialization functions.
function TMediaDataMessage.FromBytes(pBytes: TArray<Byte>): Boolean;
var
vLen: Integer;
vOffset: Integer;
vArrSize: UInt32;
begin
vOffset := 0;
Move(pBytes[vOffset], PByte(@Header.MessageId)[0], Sizeof(Header.MessageID));
Inc(vOffset, Sizeof(Header.MessageID));
Move(pBytes[vOffset], PByte(@Header.TotalSize)[0], Sizeof(Header.TotalSize));
Inc(vOffset, Sizeof(Header.TotalSize));
Move(pBytes[vOffset], PByte(@Channel)[0], Sizeof(Channel));
Inc(vOffset, Sizeof(Channel));
Move(pBytes[vOffset], PByte(@Stream)[0], Sizeof(Stream));
Inc(vOffset, Sizeof(Stream));
Move(pBytes[vOffset], PByte(@MediaType)[0], Sizeof(MediaType));
Inc(vOffset, Sizeof(MediaType));
Move(pBytes[vOffset], PByte(@vArrSize)[0], Sizeof(vArrSize));
Inc(vOffset, Sizeof(vArrSize));
if vArrSize <> 0 then
begin
SetLength(Data, vArrSize);
Move(pBytes[vOffset], Data[0], vArrSize);
end;
Exit(True);
end;
function TMediaDataMessage.GetSize: UInt32;
begin
Result := (Sizeof(uInt32) *2) Sizeof(Channel) Sizeof(Stream)
Sizeof(MediaType) Sizeof(UInt32) Length(Data);
end;
function TMediaDataMessage.ToBytes: TArray<Byte>;
var
vSize: UInt32;
vOffset: UInt32;
vLen: UInt32;
begin
vSize := Self.GetSize;
SetLength(Result, vSize);
vOffset := 0;
Move(Self.Header.MessageID, Result[vOffset], Sizeof(Self.Header.MessageID));
Inc(vOffset, Sizeof(Self.Header.MessageID));
Move(Self.Header.TotalSize, Result[vOffset], Sizeof(Self.Header.TotalSize));
Inc(vOffset, Sizeof(Self.Header.TotalSize));
Move(Self.Channel, Result[vOffset], Sizeof(Self.Channel));
Inc(vOffset, Sizeof(Self.Channel));
Move(Self.Stream, Result[vOffset], Sizeof(Self.Stream));
Inc(vOffset, Sizeof(Self.Stream));
Move(Self.MediaType, Result[vOffset], Sizeof(Self.MediaType));
Inc(vOffset, Sizeof(Self.MediaType));
vLen := Length(Self.Data);
Move(vLen, Result[vOffset], Sizeof(UInt32));
Inc(vOffset, Sizeof(UInt32));
if vLen > 0 then
Move(Self.Data[0], Result[vOffset], vLen);
end;
CodePudding user response:
I figured it out... I had to set vRcvdCount to 0 in the first else statement.
Looks like this now ->
procedure TfrmMain.HandleDataAvailable(pSender: TObject; ErrCode: Word);
var
vRcvdCount: Integer;
vBytes: TBytes;
vMessageTotalSize: UInt32;
vOffset: UInt32;
begin
{$POINTERMATH ON}
if ErrCode <> 0 then
Exit;
if pSender = nil then
Exit;
SetLength(vBytes, 65536);
vRcvdCount := fTCPClient.Receive(@vBytes[0], 65536);
vOffset := 0;
try
if fRemainingDataSize > 0 then
begin
if vRcvdCount >= fRemainingDataSize then
begin
fCurrentBuf.Write(vBytes[vOffset], fRemainingDataSize);
Inc(vOffset, fRemainingDataSize);
Dec(vRcvdCount, fRemainingDataSize);
fRemainingDataSize := 0;
SetHandleMessage(fIdx.ToString 'Sync');
end
else
begin
fCurrentBuf.Write(vBytes[vOffset], vRcvdCount);
Dec(fRemainingDataSize, vRcvdCount);
vRcvdCount := 0; \\ Add this here!!!
end;
end;
except
reLog.Lines.Add('Error sync');
end;
try
while (vRcvdCount > 0) do
begin
vMessageTotalSize := PUInt32(@vBytes[vOffset 4])^;
if vRcvdCount >= vMessageTotalSize then
begin
fCurrentBuf.Write(vBytes[vOffset], vMessageTotalSize);
Inc(vOffset, vMessageTotalSize);
Dec(vRcvdCount, vMessageTotalSize);
SetHandleMessage('Loop');
end
else
begin
fCurrentBuf.Write(vBytes[vOffset], vRcvdCount);
fRemainingDataSize := vMessageTotalSize - vRcvdCount;
vRcvdCount := 0;
end;
end;
except
reLog.Lines.Add('Loop');
end;
//fTcpClient.Flush;
end;