firemonkey 将 mp3 流转换为十六进制和反向

firemonkey convert mp3 stream to hex and reverse

我尝试将音频从 mobile microphone 保存到 Tmemorystream,然后使用此函数将其转换为十六进制:

function StreamToHexStr(AStream: TStream): string;
const
 HexArr: array[0..15] of char =
 ('0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F');
var
 AByte: Byte;
 i: Integer;
begin
 SetLength(Result, AStream.Size * 2);
 AStream.Position := 0;
 for i := 0 to AStream.Size - 1 do
 begin
   AStream.ReadBuffer(AByte, SizeOf(AByte));
   Result[i * 2 + 1] := HexArr[AByte shr 4];
   Result[i * 2 + 2] := HexArr[AByte and [=10=]F];
 end;
end;

输出为十六进制字符串

将它传输到第二个设备后,我必须将十六进制代码更改为 Tmemorystream 并使用此功能播放它:

Stream := TMemoryStream.Create;
try
  Writer := TBinaryWriter.Create(Stream);
  try
    Writer.Write(TEncoding.UTF8.GetBytes(ReciavedSTR));
  finally
    Writer.Free;
  end;
  Stream.SaveToFile( TPath.GetSharedMoviesPath()+'/record2.mp3' );

record2.mp3 无法播放,它只包含转换后的十六进制字符串

我的代码有什么问题?

当我使用此代码将录制的流保存到文件时进行简单测试

FOutputStream.SaveToFile( TPath.GetSharedMoviesPath()+'/record.mp3' );

效果很好。

更新项目概念:

硬件发送器从串口上的手机phone获取406个十六进制字符并将其传输到第二个设备,然后接收器将十六进制字符串传递给第二个手机phone,第二个phone必须加入字符串并将它们转换为可听到的声音。

base64 的示例输出流和流保存到文件

sample mp3 file

首先,让我回答你最初的问题

如何将流与 base16(也称为 ASCII-HEX)相互转换。

您转换为 base16 的代码是正确的,这是一个基本相同的版本:

function StreamToHexStr(const AStream: TStream): String;
const
  cMap : array[0..15] of Char = (
    '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 
    'A', 'B', 'C', 'D', 'E', 'F');
var
  lData: Byte;
  lPos: Integer;
begin
  Setlength(Result, AStream.Size * 2);
  AStream.Position := 0; 
  lPos := Low(Result);
  while AStream.ReadData(lData) = sizeof(lData) do begin
    Result[lPos]     := cMap[lData shr 4];
    Result[lPos + 1] := cMap[lData and [=10=]F];
    Inc(lPos, 2);
  end;
end;

要将字符串转换回流,试试这个:

procedure HexStrToStream(const AString: String; AStream: TStream);
const
  // Mapping vom ASCII-Code to value
  cMap: array['0'..'F'] of Byte  = (
    0, 1, 2, 3, 4, 5, 6, 7, 8, 9,  // .. / '0'..'9'
    100, 100, 100, 100, 100, 100, 100, //  A..
    10, 11, 12, 13, 14, 15); // .. / 'A'..'F'
var
  lPos: Integer;
begin
  lPos := Low(AString);
  while lPos < High(AString) do begin
    AStream.WriteData(UInt8(cMap[AString[lPos]] shl 4 + cMap[AString[lPos + 1]]));
    Inc(lPos, 2);
  end;
end;

要使用此代码,只需执行以下操作:

Base16String := StreamToHexStr(MP3Stream);

在发送者和接收者上做:

lRecvStream := TMemoryStream.Create();
try
  HexStrToStream(Base16RecvString, RecvStream);
  lRecvStream.SaveToFile('Record.mp3');
finally
  lRecvStream.Free();
end;

如何对 base64 做同样的事情

在发送方使用 TMemoryStream,您只需执行以下操作:

lString := TNetEncoding.Base64.EncodeBytesToString(lInStream.Memory, lInStream.Size);

并且在接收方使用 TBytesStream(它是 TMemoryStream 的后代):

lRecvStream := TBytesStream.Create(TNetEncoding.Base64.DecodeStringToBytes(lString));
try
  lRecvStream.SaveToFile('Record.mp3');
finally
  lRecvStream.Free();
end;

您可能会考虑的事项

在数据传输过程中,一些字节可能会被更改或丢失。有时不会收到整个数据包。根据您的要求,您的应用程序可能需要针对此类错误采取一些保护措施。