From 23a1674ce0775b06b712f28234284c32ac289663 Mon Sep 17 00:00:00 2001 From: winlin Date: Wed, 18 Dec 2019 20:13:11 +0800 Subject: [PATCH] Improve coverage for RAW AVC protocol. --- trunk/src/protocol/srs_raw_avc.cpp | 31 ++-- trunk/src/utest/srs_utest.hpp | 4 + trunk/src/utest/srs_utest_avc.cpp | 241 ++++++++++++++++++++++++++++- 3 files changed, 253 insertions(+), 23 deletions(-) diff --git a/trunk/src/protocol/srs_raw_avc.cpp b/trunk/src/protocol/srs_raw_avc.cpp index 9ff69bcff..b09479a3a 100644 --- a/trunk/src/protocol/srs_raw_avc.cpp +++ b/trunk/src/protocol/srs_raw_avc.cpp @@ -141,9 +141,7 @@ srs_error_t SrsRawH264Stream::mux_sequence_header(string sps, string pps, uint32 // numOfPictureParameterSets, pictureParameterSetLength // Nbytes of pps: // pictureParameterSetNALUnit - int nb_packet = 5 - + 3 + (int)sps.length() - + 3 + (int)pps.length(); + int nb_packet = 5 + (3 + (int)sps.length()) + (3 + (int)pps.length()); char* packet = new char[nb_packet]; SrsAutoFreeA(char, packet); @@ -204,9 +202,8 @@ srs_error_t SrsRawH264Stream::mux_sequence_header(string sps, string pps, uint32 // TODO: FIXME: for more profile. // 5.3.4.2.1 Syntax, ISO_IEC_14496-15-AVC-format-2012.pdf, page 16 // profile_idc == 100 || profile_idc == 110 || profile_idc == 122 || profile_idc == 144 - - sh = ""; - sh.append(packet, nb_packet); + + sh = string(packet, nb_packet); return err; } @@ -236,9 +233,8 @@ srs_error_t SrsRawH264Stream::mux_ipb_frame(char* frame, int nb_frame, string& i stream.write_4bytes(NAL_unit_length); // NALUnit stream.write_bytes(frame, nb_frame); - - ibp = ""; - ibp.append(packet, nb_packet); + + ibp = string(packet, nb_packet); return err; } @@ -409,7 +405,7 @@ srs_error_t SrsRawAacStream::adts_demux(SrsBuffer* stream, char** pframe, int* p codec.channel_configuration = channel_configuration; codec.frame_length = frame_length; - // @see srs_audio_write_raw_frame(). + // The aac sampleing rate defined in srs_aac_srates. // TODO: FIXME: maybe need to resample audio. codec.sound_format = 10; // AAC if (sampling_frequency_index <= 0x0c && sampling_frequency_index > 0x0a) { @@ -465,27 +461,24 @@ srs_error_t SrsRawAacStream::mux_sequence_header(SrsRawAacStreamCodec* codec, st break; } - sh = ""; - - char ch = 0; + char chs[2]; // @see ISO_IEC_14496-3-AAC-2001.pdf // AudioSpecificConfig (), page 33 // 1.6.2.1 AudioSpecificConfig // audioObjectType; 5 bslbf - ch = (audioObjectType << 3) & 0xf8; + chs[0] = (audioObjectType << 3) & 0xf8; // 3bits left. // samplingFrequencyIndex; 4 bslbf - ch |= (samplingFrequencyIndex >> 1) & 0x07; - sh += ch; - ch = (samplingFrequencyIndex << 7) & 0x80; + chs[0] |= (samplingFrequencyIndex >> 1) & 0x07; + chs[1] = (samplingFrequencyIndex << 7) & 0x80; if (samplingFrequencyIndex == 0x0f) { return srs_error_new(ERROR_AAC_DATA_INVALID, "invalid sampling frequency index"); } // 7bits left. // channelConfiguration; 4 bslbf - ch |= (channelConfiguration << 3) & 0x78; + chs[1] |= (channelConfiguration << 3) & 0x78; // 3bits left. // GASpecificConfig(), page 451 @@ -493,7 +486,7 @@ srs_error_t SrsRawAacStream::mux_sequence_header(SrsRawAacStreamCodec* codec, st // frameLengthFlag; 1 bslbf // dependsOnCoreCoder; 1 bslbf // extensionFlag; 1 bslbf - sh += ch; + sh = string((char*)chs, sizeof(chs)); return err; } diff --git a/trunk/src/utest/srs_utest.hpp b/trunk/src/utest/srs_utest.hpp index e128d350e..d054d71a6 100644 --- a/trunk/src/utest/srs_utest.hpp +++ b/trunk/src/utest/srs_utest.hpp @@ -67,6 +67,10 @@ extern srs_utime_t _srs_tmp_timeout; #define HELPER_BUFFER2STR(io) \ string((const char*)(io)->bytes(), (size_t)(io)->length()) +// Covert uint8_t array to string. +#define HELPER_ARR2STR(arr, size) \ + string((char*)(arr), (int)size) + // the asserts of gtest: // * {ASSERT|EXPECT}_EQ(expected, actual): Tests that expected == actual // * {ASSERT|EXPECT}_NE(v1, v2): Tests that v1 != v2 diff --git a/trunk/src/utest/srs_utest_avc.cpp b/trunk/src/utest/srs_utest_avc.cpp index b0ca629e9..503c2e4d3 100644 --- a/trunk/src/utest/srs_utest_avc.cpp +++ b/trunk/src/utest/srs_utest_avc.cpp @@ -27,7 +27,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #include #include -VOID TEST(SrsH264Test, ParseAnnexb) +VOID TEST(SrsAVCTest, H264ParseAnnexb) { srs_error_t err; @@ -123,11 +123,20 @@ VOID TEST(SrsH264Test, ParseAnnexb) } } -VOID TEST(SrsH264Test, SequenceHeader) +VOID TEST(SrsAVCTest, H264SequenceHeader) { srs_error_t err; - // For PPS demux. + // For muxing sequence header. + if (true) { + SrsRawH264Stream h; string sh; + HELPER_ASSERT_SUCCESS(h.mux_sequence_header("Hello", "world", 0, 0, sh)); + EXPECT_EQ(11+5+5, sh.length()); + EXPECT_STREQ("Hello", sh.substr(8, 5).c_str()); + EXPECT_STREQ("world", sh.substr(16).c_str()); + } + + // For PPS demuxing. if (true) { SrsRawH264Stream h; string pps; @@ -141,7 +150,7 @@ VOID TEST(SrsH264Test, SequenceHeader) EXPECT_STREQ("Hello, world!", pps.c_str()); } - // For SPS demux. + // For SPS demuxing. if (true) { SrsRawH264Stream h; string sps; @@ -216,3 +225,227 @@ VOID TEST(SrsH264Test, SequenceHeader) } } +VOID TEST(SrsAVCTest, H264IPBFrame) +{ + srs_error_t err; + + // For muxing avc to flv frame. + if (true) { + SrsRawH264Stream h; int nb_flv = 0; char* flv = NULL; + string video("Hello"); int8_t frame_type = SrsVideoAvcFrameTypeKeyFrame; int8_t avc_packet_type = SrsVideoAvcFrameTraitSequenceHeader; + HELPER_ASSERT_SUCCESS(h.mux_avc2flv(video, frame_type, avc_packet_type, 0, 0x010203, &flv, &nb_flv)); + EXPECT_EQ(10, nb_flv); + EXPECT_EQ(SrsVideoAvcFrameTypeKeyFrame, uint8_t((flv[0]>>4)&0x0f)); + EXPECT_EQ(SrsVideoAvcFrameTraitSequenceHeader, uint8_t(flv[1])); + EXPECT_EQ(01, flv[2]); EXPECT_EQ(02, flv[3]); EXPECT_EQ(03, flv[4]); + EXPECT_STREQ("Hello", HELPER_ARR2STR(flv+5, 5).c_str()); + srs_freep(flv); + } + + // For muxing I/P/B frame. + if (true) { + SrsRawH264Stream h; string frame; + HELPER_ASSERT_SUCCESS(h.mux_ipb_frame((char*)"Hello", 5, frame)); + EXPECT_EQ(4+5, frame.length()); + EXPECT_EQ(0, frame.at(0)); EXPECT_EQ(0, frame.at(1)); EXPECT_EQ(0, frame.at(2)); EXPECT_EQ(5, frame.at(3)); + EXPECT_STREQ("Hello", frame.substr(4).c_str()); + } +} + +VOID TEST(SrsAVCTest, AACDemuxADTS) +{ + srs_error_t err; + + // For lower sampling rate, such as 5512HZ. + if (true) { + SrsRawAacStream h; char* frame = NULL; int nb_frame = 0; SrsRawAacStreamCodec codec; + uint8_t b[] = {0xff, 0xf9, 0x2c,0x40, 0,0xe0,0}; SrsBuffer buf((char*)b, sizeof(b)); + HELPER_ASSERT_SUCCESS(h.adts_demux(&buf, &frame, &nb_frame, codec)); + EXPECT_EQ(1, codec.protection_absent); // b[1] + EXPECT_EQ(SrsAacObjectTypeAacMain, codec.aac_object); // b[2] + EXPECT_EQ(0xb, codec.sampling_frequency_index); // b[2] + EXPECT_EQ(1, codec.channel_configuration); // b[3] + EXPECT_EQ(7, codec.frame_length); // b[5] + EXPECT_EQ(0, nb_frame); + + EXPECT_EQ(SrsAudioSampleRate5512, codec.sound_rate); + EXPECT_EQ(0, codec.sound_type); + EXPECT_EQ(1, codec.sound_size); + } + + // For lower sampling rate, such as 22050HZ. + if (true) { + SrsRawAacStream h; char* frame = NULL; int nb_frame = 0; SrsRawAacStreamCodec codec; + uint8_t b[] = {0xff, 0xf9, 0x18,0x40, 0,0xe0,0}; SrsBuffer buf((char*)b, sizeof(b)); + HELPER_ASSERT_SUCCESS(h.adts_demux(&buf, &frame, &nb_frame, codec)); + EXPECT_EQ(1, codec.protection_absent); // b[1] + EXPECT_EQ(SrsAacObjectTypeAacMain, codec.aac_object); // b[2] + EXPECT_EQ(6, codec.sampling_frequency_index); // b[2] + EXPECT_EQ(1, codec.channel_configuration); // b[3] + EXPECT_EQ(7, codec.frame_length); // b[5] + EXPECT_EQ(0, nb_frame); + + EXPECT_EQ(SrsAudioSampleRate22050, codec.sound_rate); + EXPECT_EQ(0, codec.sound_type); + EXPECT_EQ(1, codec.sound_size); + } + + // For higher sampling rate, use 44100HZ. + if (true) { + SrsRawAacStream h; char* frame = NULL; int nb_frame = 0; SrsRawAacStreamCodec codec; + uint8_t b[] = {0xff, 0xf9, 0x04,0x40, 0,0xe0,0}; SrsBuffer buf((char*)b, sizeof(b)); + HELPER_ASSERT_SUCCESS(h.adts_demux(&buf, &frame, &nb_frame, codec)); + EXPECT_EQ(1, codec.protection_absent); // b[1] + EXPECT_EQ(SrsAacObjectTypeAacMain, codec.aac_object); // b[2] + EXPECT_EQ(1, codec.sampling_frequency_index); // b[2] + EXPECT_EQ(1, codec.channel_configuration); // b[3] + EXPECT_EQ(7, codec.frame_length); // b[5] + EXPECT_EQ(0, nb_frame); + + EXPECT_EQ(SrsAudioSampleRate44100, codec.sound_rate); + EXPECT_EQ(0, codec.sound_type); + EXPECT_EQ(1, codec.sound_size); + } + + // If protected, there are 2B signature. + if (true) { + SrsRawAacStream h; char* frame = NULL; int nb_frame = 0; SrsRawAacStreamCodec codec; + uint8_t b[] = {0xff, 0xf0, 0x10,0x40, 0x01,0x40,0, 0,0, 1}; SrsBuffer buf((char*)b, sizeof(b)); + HELPER_ASSERT_SUCCESS(h.adts_demux(&buf, &frame, &nb_frame, codec)); + EXPECT_EQ(0, codec.protection_absent); // b[1] + EXPECT_EQ(SrsAacObjectTypeAacMain, codec.aac_object); // b[2] + EXPECT_EQ(4, codec.sampling_frequency_index); // b[2] + EXPECT_EQ(1, codec.channel_configuration); // b[3] + EXPECT_EQ(10, codec.frame_length); // b[4,5] + ASSERT_EQ(1, nb_frame); EXPECT_EQ(1, (uint8_t)frame[0]); + + EXPECT_EQ(SrsAudioSampleRate44100, codec.sound_rate); + EXPECT_EQ(0, codec.sound_type); + EXPECT_EQ(1, codec.sound_size); + } + + // Fail if not enough data. + if (true) { + SrsRawAacStream h; char* frame = NULL; int nb_frame = 0; SrsRawAacStreamCodec codec; + uint8_t b[] = {0xff, 0xf0, 0x10,0x40, 0x04,0,0, 1}; SrsBuffer buf((char*)b, sizeof(b)); + HELPER_EXPECT_FAILED(h.adts_demux(&buf, &frame, &nb_frame, codec)); + } + + // If protected, there should be 2B signature. + if (true) { + SrsRawAacStream h; char* frame = NULL; int nb_frame = 0; SrsRawAacStreamCodec codec; + uint8_t b[] = {0xff, 0xf0, 0x10,0x40, 0x01,0,0, 1}; SrsBuffer buf((char*)b, sizeof(b)); + HELPER_EXPECT_FAILED(h.adts_demux(&buf, &frame, &nb_frame, codec)); + } + + // ID should be 1, but we ignored. + if (true) { + SrsRawAacStream h; char* frame = NULL; int nb_frame = 0; SrsRawAacStreamCodec codec; + uint8_t b[] = {0xff, 0xf1, 0x10,0x40, 0x01,0,0, 1}; SrsBuffer buf((char*)b, sizeof(b)); + HELPER_ASSERT_SUCCESS(h.adts_demux(&buf, &frame, &nb_frame, codec)); + } + + // Minimum AAC frame, with raw data. + if (true) { + SrsRawAacStream h; char* frame = NULL; int nb_frame = 0; SrsRawAacStreamCodec codec; + uint8_t b[] = {0xff, 0xf9, 0x10,0x40, 0x01,0,0, 1}; SrsBuffer buf((char*)b, sizeof(b)); + HELPER_ASSERT_SUCCESS(h.adts_demux(&buf, &frame, &nb_frame, codec)); + EXPECT_EQ(1, codec.protection_absent); // b[1] + EXPECT_EQ(SrsAacObjectTypeAacMain, codec.aac_object); // b[2] + EXPECT_EQ(4, codec.sampling_frequency_index); // b[2] + EXPECT_EQ(1, codec.channel_configuration); // b[3] + EXPECT_EQ(8, codec.frame_length); // b[4] + ASSERT_EQ(1, nb_frame); EXPECT_EQ(1, (uint8_t)frame[0]); + + EXPECT_EQ(SrsAudioSampleRate44100, codec.sound_rate); + EXPECT_EQ(0, codec.sound_type); + EXPECT_EQ(1, codec.sound_size); + } + + // Minimum AAC frame, no raw data. + if (true) { + SrsRawAacStream h; char* frame = NULL; int nb_frame = 0; SrsRawAacStreamCodec codec; + uint8_t b[] = {0xff, 0xf9, 0x10,0x40, 0,0xe0,0}; SrsBuffer buf((char*)b, sizeof(b)); + HELPER_ASSERT_SUCCESS(h.adts_demux(&buf, &frame, &nb_frame, codec)); + EXPECT_EQ(1, codec.protection_absent); // b[1] + EXPECT_EQ(SrsAacObjectTypeAacMain, codec.aac_object); // b[2] + EXPECT_EQ(4, codec.sampling_frequency_index); // b[2] + EXPECT_EQ(1, codec.channel_configuration); // b[3] + EXPECT_EQ(7, codec.frame_length); // b[5] + EXPECT_EQ(0, nb_frame); + + EXPECT_EQ(SrsAudioSampleRate44100, codec.sound_rate); + EXPECT_EQ(0, codec.sound_type); + EXPECT_EQ(1, codec.sound_size); + } +} + +VOID TEST(SrsAVCTest, AACMuxSequenceHeader) +{ + srs_error_t err; + + // For sampling rate 22050HZ. + if (true) { + SrsRawAacStream h; string sh; SrsRawAacStreamCodec codec; + codec.aac_object = SrsAacObjectTypeAacMain; + codec.channel_configuration = 1; + codec.sound_rate = SrsAudioSampleRate22050; + HELPER_ASSERT_SUCCESS(h.mux_sequence_header(&codec, sh)); + EXPECT_EQ(2, sh.length()); + EXPECT_EQ(0x0b, (uint8_t)sh.at(0)); + EXPECT_EQ(0x88, (uint8_t)sh.at(1)); + } + + // For sampling rate 11025HZ. + if (true) { + SrsRawAacStream h; string sh; SrsRawAacStreamCodec codec; + codec.aac_object = SrsAacObjectTypeAacMain; + codec.channel_configuration = 1; + codec.sound_rate = SrsAudioSampleRate11025; + HELPER_ASSERT_SUCCESS(h.mux_sequence_header(&codec, sh)); + EXPECT_EQ(2, sh.length()); + EXPECT_EQ(0x0d, (uint8_t)sh.at(0)); + EXPECT_EQ(0x08, (uint8_t)sh.at(1)); + } + + // Fail for invalid sampling rate. + if (true) { + SrsRawAacStream h; string sh; SrsRawAacStreamCodec codec; + codec.sampling_frequency_index = 0xf; + codec.sound_rate = SrsAudioSampleRateReserved; + HELPER_EXPECT_FAILED(h.mux_sequence_header(&codec, sh)); + } + + // Normal case. + if (true) { + SrsRawAacStream h; string sh; SrsRawAacStreamCodec codec; + codec.aac_object = SrsAacObjectTypeAacMain; + codec.channel_configuration = 1; + codec.sampling_frequency_index = 4; + codec.sound_rate = SrsAudioSampleRateReserved; + HELPER_ASSERT_SUCCESS(h.mux_sequence_header(&codec, sh)); + EXPECT_EQ(2, sh.length()); + EXPECT_EQ(0x0a, (uint8_t)sh.at(0)); + EXPECT_EQ(0x08, (uint8_t)sh.at(1)); + } + + // Fail for invalid aac object. + if (true) { + SrsRawAacStream h; string sh; SrsRawAacStreamCodec codec; + codec.aac_object = SrsAacObjectTypeReserved; + HELPER_EXPECT_FAILED(h.mux_sequence_header(&codec, sh)); + } + + // Normal case. + if (true) { + SrsRawAacStream h; string sh; SrsRawAacStreamCodec codec; + codec.aac_object = SrsAacObjectTypeAacMain; + codec.channel_configuration = 1; + codec.sound_rate = SrsAudioSampleRate44100; + HELPER_ASSERT_SUCCESS(h.mux_sequence_header(&codec, sh)); + EXPECT_EQ(2, sh.length()); + EXPECT_EQ(0x0a, (uint8_t)sh.at(0)); + EXPECT_EQ(0x08, (uint8_t)sh.at(1)); + } +} +