Compare commits

...

2 Commits

Author SHA1 Message Date
72a7042ab9 - allow AMR-NB/WB BWE profiles in rtp_decode 2026-02-24 10:48:03 +03:00
b5fe9e59c4 - fix AMR-WB decoder 2026-02-24 10:47:38 +03:00
6 changed files with 43 additions and 30 deletions

View File

@@ -535,16 +535,16 @@ Codec::EncodeResult AmrWbCodec::encode(std::span<const uint8_t> input, std::span
#define L_FRAME 160 #define L_FRAME 160
#define AMR_BITRATE_DTX 15 #define AMR_BITRATE_DTX 15
int AmrWbCodec::decodeIuup(std::span<const uint8_t> input, std::span<uint8_t> output) Codec::DecodeResult AmrWbCodec::decodeIuup(std::span<const uint8_t> input, std::span<uint8_t> output)
{ {
IuUP::Frame frame; IuUP::Frame frame;
if (!IuUP::parse2(input.data(), input.size(), frame)) if (!IuUP::parse2(input.data(), input.size(), frame))
return 0; return {.mDecoded = 0};
if (!frame.mHeaderCrcOk || !frame.mPayloadCrcOk) if (!frame.mHeaderCrcOk || !frame.mPayloadCrcOk)
{ {
ICELogInfo(<< "CRC check failed."); ICELogInfo(<< "CRC check failed.");
return 0; return {.mDecoded = 0};
} }
// Reserve space // Reserve space
@@ -559,15 +559,15 @@ int AmrWbCodec::decodeIuup(std::span<const uint8_t> input, std::span<uint8_t> ou
frameType = ftIndex; frameType = ftIndex;
if (frameType == 0xFF) if (frameType == 0xFF)
return 0; return {.mDecoded = 0, .mIsCng = true};
dataToDecode.mutableData()[0] = (frameType << 3) | (1 << 2); dataToDecode.mutableData()[0] = (frameType << 3) | (1 << 2);
D_IF_decode(mDecoderCtx, (const unsigned char*)dataToDecode.data(), (short*)output.data(), 0); D_IF_decode(mDecoderCtx, (const unsigned char*)dataToDecode.data(), (short*)output.data(), 0);
return pcmLength(); return {.mDecoded = (size_t)pcmLength()};
} }
int AmrWbCodec::decodePlain(std::span<const uint8_t> input, std::span<uint8_t> output) Codec::DecodeResult AmrWbCodec::decodePlain(std::span<const uint8_t> input, std::span<uint8_t> output)
{ {
AmrPayloadInfo info; AmrPayloadInfo info;
info.mCurrentTimestamp = mCurrentDecoderTimestamp; info.mCurrentTimestamp = mCurrentDecoderTimestamp;
@@ -586,7 +586,7 @@ int AmrWbCodec::decodePlain(std::span<const uint8_t> input, std::span<uint8_t> o
{ {
GAmrWbStatistics.mNonParsed++; GAmrWbStatistics.mNonParsed++;
ICELogDebug(<< "Failed to decode AMR payload"); ICELogDebug(<< "Failed to decode AMR payload");
return 0; return {.mDecoded = 0};
} }
// Save current timestamp // Save current timestamp
mCurrentDecoderTimestamp = info.mCurrentTimestamp; mCurrentDecoderTimestamp = info.mCurrentTimestamp;
@@ -595,22 +595,22 @@ int AmrWbCodec::decodePlain(std::span<const uint8_t> input, std::span<uint8_t> o
if (ap.mDiscardPacket) if (ap.mDiscardPacket)
{ {
GAmrWbStatistics.mDiscarded++; GAmrWbStatistics.mDiscarded++;
return 0; return {.mDecoded = 0};
} }
// Find the required output capacity // Find the required output capacity
size_t capacity = 0; size_t capacity = 0;
for (AmrFrame& frame: ap.mFrames) for (AmrFrame& frame: ap.mFrames)
capacity += frame.mMode == 0xFF /* CNG */ ? pcmLength() * 8 : pcmLength(); capacity += frame.mMode == 0xFF /* CNG */ ? pcmLength() : pcmLength();
if (output.size() < capacity) if (output.size() < capacity)
return 0; return {.mDecoded = 0};
short* dataOut = (short*)output.data(); short* dataOut = (short*)output.data();
size_t dataOutSizeInBytes = 0; size_t dataOutSizeInBytes = 0;
for (AmrFrame& frame: ap.mFrames) for (AmrFrame& frame: ap.mFrames)
{ {
size_t frameOutputSize = frame.mMode == 0xFF ? pcmLength() * 8 : pcmLength(); size_t frameOutputSize = frame.mMode == 0xFF ? pcmLength() : pcmLength();
memset(dataOut, 0, frameOutputSize); memset(dataOut, 0, frameOutputSize);
if (frame.mData) if (frame.mData)
@@ -624,17 +624,16 @@ int AmrWbCodec::decodePlain(std::span<const uint8_t> input, std::span<uint8_t> o
dataOutSizeInBytes += frameOutputSize; dataOutSizeInBytes += frameOutputSize;
} }
} }
return dataOutSizeInBytes; return {.mDecoded = dataOutSizeInBytes,
.mIsCng = ap.mFrames.size() == 1 ? (ap.mFrames.front().mMode == 0xFF) : false};
} }
Codec::DecodeResult AmrWbCodec::decode(std::span<const uint8_t> input, std::span<uint8_t> output) Codec::DecodeResult AmrWbCodec::decode(std::span<const uint8_t> input, std::span<uint8_t> output)
{ {
if (mConfig.mIuUP) if (mConfig.mIuUP)
return {.mDecoded = (size_t)decodeIuup(input, output)}; return decodeIuup(input, output);
else else
return {.mDecoded = (size_t)decodePlain(input, output)}; return decodePlain(input, output);
return {.mDecoded = 0};
} }
size_t AmrWbCodec::plc(int lostFrames, std::span<uint8_t> output) size_t AmrWbCodec::plc(int lostFrames, std::span<uint8_t> output)

View File

@@ -85,8 +85,8 @@ protected:
int mPreviousPacketLength; int mPreviousPacketLength;
int decodeIuup(std::span<const uint8_t> input, std::span<uint8_t> output); DecodeResult decodeIuup(std::span<const uint8_t> input, std::span<uint8_t> output);
int decodePlain(std::span<const uint8_t> input, std::span<uint8_t> output); DecodeResult decodePlain(std::span<const uint8_t> input, std::span<uint8_t> output);
public: public:
class CodecFactory: public Factory class CodecFactory: public Factory

View File

@@ -681,8 +681,9 @@ AudioReceiver::DecodeResult AudioReceiver::decodePacketTo(Audio::DataWindow& out
else else
{ {
// Decode frame by frame // Decode frame by frame
auto r = mCodec->decode({rtp.GetPayloadData() + i * mCodec->rtpLength(), (size_t)frameLength}, auto codecInput = std::span{rtp.GetPayloadData() + i * mCodec->rtpLength(), (size_t)frameLength};
{(uint8_t*)mDecodedFrame, sizeof mDecodedFrame}); auto codecOutput = std::span{(uint8_t*)mDecodedFrame, sizeof mDecodedFrame};
auto r = mCodec->decode(codecInput, codecOutput);
mDecodedLength = r.mDecoded; mDecodedLength = r.mDecoded;
if (mDecodedLength > 0) if (mDecodedLength > 0)
processDecoded(output, options); processDecoded(output, options);

View File

@@ -52,17 +52,19 @@ public:
int mPcmLength = 0; // In bytes int mPcmLength = 0; // In bytes
int mFrameTime = 0; // In milliseconds int mFrameTime = 0; // In milliseconds
int mRtpLength = 0; // In bytes int mRtpLength = 0; // In bytes
float mTimestampUnit = 0.0f;
}; };
// Returns information about this codec instance // Returns information about this codec instance
virtual Info info() = 0; virtual Info info() = 0;
// Helper functions to return information - they are based on info() method // Helper functions to return information - they are based on info() method
int pcmLength() { return info().mPcmLength; } int pcmLength() { return info().mPcmLength; }
int rtpLength() { return info().mRtpLength; } int rtpLength() { return info().mRtpLength; }
int channels() { return info().mChannels; } int channels() { return info().mChannels; }
int samplerate() { return info().mSamplerate; } int samplerate() { return info().mSamplerate; }
int frameTime() { return info().mFrameTime; } int frameTime() { return info().mFrameTime; }
std::string name() { return info().mName; } std::string name() { return info().mName; }
float timestampUnit() { return info().mTimestampUnit == 0.0f ? 1.0f / info().mSamplerate : info().mTimestampUnit; }
Audio::Format getAudioFormat() { Audio::Format getAudioFormat() {
return Audio::Format(this->info().mSamplerate, this->info().mChannels); return Audio::Format(this->info().mSamplerate, this->info().mChannels);

View File

@@ -1,6 +1,10 @@
cmake_minimum_required(VERSION 3.20)
project(rtp_decode)
set (CMAKE_CXX_STANDARD 20) set (CMAKE_CXX_STANDARD 20)
set (CMAKE_CXX_STANDARD_REQUIRED ON) set (CMAKE_CXX_STANDARD_REQUIRED ON)
add_executable(rtp_decode main.cpp)
add_subdirectory(../../src build_rtphone) add_subdirectory(../../src build_rtphone)
add_executable(rtp_decode main.cpp)
target_link_libraries(rtp_decode PRIVATE rtphone) target_link_libraries(rtp_decode PRIVATE rtphone)

View File

@@ -29,7 +29,8 @@ static void usage(const char* progname)
fprintf(stderr, fprintf(stderr,
"Usage: %s <input.rtp> <output.wav> --codec <name> [--pt <N>] [--rate <N>] [--channels <N>]\n" "Usage: %s <input.rtp> <output.wav> --codec <name> [--pt <N>] [--rate <N>] [--channels <N>]\n"
"\n" "\n"
"Codecs: pcmu pcma g722 g729 opus gsm gsmhr gsmefr amrnb amrwb evs ilbc20 ilbc30 isac16 isac32\n" "Codecs: pcmu pcma g722 g729 opus gsm gsmhr gsmefr\n"
" amrnb amrwb amrnb-bwe amrwb-bwe evs ilbc20 ilbc30 isac16 isac32\n"
"\n" "\n"
"Options:\n" "Options:\n"
" --codec <name> Codec name (required)\n" " --codec <name> Codec name (required)\n"
@@ -65,8 +66,10 @@ static const CodecDefaults kCodecTable[] = {
{ "g729", 18, false }, { "g729", 18, false },
{ "gsm", 3, false }, { "gsm", 3, false },
{ "opus", 106, false }, { "opus", 106, false },
{ "amrnb", -1, true }, { "amrnb", -1, true },
{ "amrwb", -1, true }, { "amrwb", -1, true },
{ "amrnb-bwe", -1, true },
{ "amrwb-bwe", -1, true },
{ "gsmhr", -1, true }, { "gsmhr", -1, true },
{ "gsmefr", 126, false }, { "gsmefr", 126, false },
{ "evs", 127, false }, { "evs", 127, false },
@@ -104,6 +107,10 @@ static MT::CodecList::Settings buildSettings(const std::string& codecName, int p
s.mAmrNbOctetPayloadType.insert(pt); s.mAmrNbOctetPayloadType.insert(pt);
} else if (codecName == "amrwb") { } else if (codecName == "amrwb") {
s.mAmrWbOctetPayloadType.insert(pt); s.mAmrWbOctetPayloadType.insert(pt);
} else if (codecName == "amrnb-bwe") {
s.mAmrNbPayloadType.insert(pt);
} else if (codecName == "amrwb-bwe") {
s.mAmrWbPayloadType.insert(pt);
} else if (codecName == "evs") { } else if (codecName == "evs") {
MT::CodecList::Settings::EvsSpec ev; MT::CodecList::Settings::EvsSpec ev;
ev.mPayloadType = pt; ev.mPayloadType = pt;