public void Parse_TestData_ReturnsValidFrame()
        {
            var testCodecInfo = new AACCodecInfo
            {
                ConfigBytes      = new byte[] { 20, 8 },
                IndexDeltaLength = 3,
                IndexLength      = 3,
                SizeLength       = 13
            };

            byte[] testBytes = Convert.FromBase64String(
                "ABAPyAE2Nay0eJ0OEMF4cOFyZeskqICVBWXLiAFDYHBG3GXFf0r/3nn+pRYcsdweO8Pzlxhjm0Q5QrEf7jx31b1PX8VuZOcZZ516jVY6sW/ISf8SQb6fONzpYJLiNRi7SO1o+" +
                "ByL8qHHiUeF9EoqyQ1VgamBApL8XaznlKoszkm9Td02961s0SznSmtSZcuhaEYCZaPe1k5qM+U3wHzs3CCnWMSNsK9UNCq1dzSm4YZWRkJPIY4oXJXsSCW67r8Xdb4slBDvxqu709z" +
                "ggyqrTuoOtkR3aHhFs6JHL8QwVgiusj39H8FrZ8Nu3Dt3qu0NQo5KpHN4R1jn2G71VHMfJwGEwZisU2e9Pz3h316dvpt97XbNcxLTgUCz9UpleUNXWAeygFCrPGTpWFv1Qn3JxS4W1xI" +
                "W5W/dHymYM5ElSMhtF+PFounb/IKbxKJThTUkxx3FWwYt00q7nMOilx2t6odQue/bTaENXKw304l1X5aiEl2S4+C0pIEzkHpbMp+5bmLw1+M8FNRkzlEngnPPATaJQSNOqTHTwVmK+" +
                "fAVSESminLM1TAOg0EZUw0pLTl3ka+scMp9kmxkFKLr3YRip0Uy0JMSnfefWxGezotf3sbV4afJZrnuVnKyanaK33korbN4LMIhvBgAAAAAAAAAAAAAAAAAAAAAAAAAA70=");

            byte[] frameBytes = Convert.FromBase64String(
                "ATY1rLR4nQ4QwXhw4XJl6ySogJUFZcuIAUNgcEbcZcV/Sv/eef6lFhyx3B47w/OXGGObRDlCsR/uPHfVvU9fxW5k5xlnnXqNVjqxb8hJ/xJBvp843OlgkuI1GLtI7Wj4HIvyoce" +
                "JR4X0SirJDVWBqYECkvxdrOeUqizOSb1N3Tb3rWzRLOdKa1Jly6FoRgJlo97WTmoz5TfAfOzcIKdYxI2wr1Q0KrV3NKbhhlZGQk8hjihclexIJbruvxd1viyUEO/Gq7vT3OCDKqtO6" +
                "g62RHdoeEWzokcvxDBWCK6yPf0fwWtnw27cO3eq7Q1Cjkqkc3hHWOfYbvVUcx8nAYTBmKxTZ70/PeHfXp2+m33tds1zEtOBQLP1SmV5Q1dYB7KAUKs8ZOlYW/VCfcnFLhbXEhblb90f" +
                "KZgzkSVIyG0X48Wi6dv8gpvEolOFNSTHHcVbBi3TSrucw6KXHa3qh1C579tNoQ1crDfTiXVflqISXZLj4LSkgTOQelsyn7luYvDX4zwU1GTOUSeCc88BNolBI06pMdPBWYr58BVIRKaK" +
                "cszVMA6DQRlTDSktOXeRr6xwyn2SbGQUouvdhGKnRTLQkxKd959bEZ7Oi1/extXhp8lmue5WcrJqdorfeSits3gswiG8GAAAAAAAAAAAAAAAAAAAAAAAAAADvQ==");

            RawAACFrame frame  = null;
            var         parser = new AACAudioPayloadParser(testCodecInfo);

            parser.FrameGenerated = rawFrame => frame = (RawAACFrame)rawFrame;
            parser.Parse(TimeSpan.Zero, new ArraySegment <byte>(testBytes), true);

            Assert.IsNotNull(frame);
            Assert.AreEqual(FrameType.Audio, frame.Type);
            Assert.IsTrue(frame.ConfigSegment.SequenceEqual(testCodecInfo.ConfigBytes));
            Assert.IsTrue(frame.FrameSegment.SequenceEqual(frameBytes));
        }
Exemplo n.º 2
0
        /// <summary>
        /// Creates media frame data segments.
        /// </summary>
        /// <param name="mediaFrame">Media frame.</param>
        /// <param name="metadataRequired">Indicates whether to include metadata.</param>
        /// <returns>An array of data segments.</returns>
        private static ArraySegment <byte>[] CreateDataSegments(RawFrame mediaFrame, bool metadataRequired)
        {
            if (!metadataRequired)
            {
                return new[] { new byte[] { 0 }, mediaFrame.FrameSegment }
            }
            ;

            var codecName = mediaFrame switch
            {
                RawAACFrame _ => "AAC",
                RawG711AFrame _ => "G711A",
                RawG711UFrame _ => "G711U",
                RawG726Frame _ => "G726",
                RawPCMFrame _ => "PCM",
                RawH264IFrame _ => "H264",
                RawH264PFrame _ => "H264",
                RawJpegFrame _ => "MJPEG",
                _ => string.Empty
            };

            var bitsPerCodedUnit = mediaFrame switch
            {
                RawG726Frame rawG726Frame => rawG726Frame.BitsPerCodedSample,
                _ => 0
            };

            var configSegment = mediaFrame switch
            {
                RawAACFrame rawAacFrame => rawAacFrame.ConfigSegment,
                RawH264IFrame rawH264IFrame => rawH264IFrame.SpsPpsSegment,
                _ => default
            };

            var codecBytes = Encoding.UTF8.GetBytes(codecName);

            Array.Resize(ref codecBytes, 10);

            var metaSegment = new byte[19];

            using var stream = new MemoryStream(metaSegment);
            using var writer = new EndianBinaryWriter(stream);

            writer.Write((byte)1);
            writer.Write(codecBytes);
            writer.Write(bitsPerCodedUnit);
            writer.Write(configSegment.Count);

            return(configSegment.Count > 0
                ? new[] { metaSegment, configSegment, mediaFrame.FrameSegment }
                : new[] { metaSegment, mediaFrame.FrameSegment });
        }
        public override void Parse(TimeSpan timeOffset, ArraySegment <byte> byteSegment, bool markerBit)
        {
            int auHeadersBitLength   = BigEndianConverter.ReadUInt16(byteSegment.Array, byteSegment.Offset);
            int auHeadersLengthBytes = (auHeadersBitLength + 7) / 8;

            int headerBitSize  = _codecInfo.SizeLength + _codecInfo.IndexLength;
            int audioBitsAvail = auHeadersBitLength - headerBitSize;

            if (audioBitsAvail < 0 || headerBitSize <= 0)
            {
                return;
            }

            int framesCount = 1 + audioBitsAvail / (_codecInfo.SizeLength + _codecInfo.IndexDeltaLength);

            _bitStreamReader.ReInitialize(byteSegment.SubSegment(2));

            int offset = byteSegment.Offset + auHeadersLengthBytes;

            for (int i = 0; i < framesCount; ++i)
            {
                int frameSize = _bitStreamReader.ReadBits(_codecInfo.SizeLength);

                if (i == 0)
                {
                    _bitStreamReader.ReadBits(_codecInfo.IndexLength);
                }
                else if (_codecInfo.IndexDeltaLength != 0)
                {
                    _bitStreamReader.ReadBits(_codecInfo.IndexDeltaLength);
                }

                Debug.Assert(byteSegment.Array != null, "byteSegment.Array != null");
                var frameBytes = new ArraySegment <byte>(byteSegment.Array, offset, frameSize);

                DateTime timestamp = GetFrameTimestamp(timeOffset);

                var aacFrame = new RawAACFrame(timestamp, frameBytes,
                                               new ArraySegment <byte>(_codecInfo.ConfigBytes));

                OnFrameGenerated(aacFrame);
                offset += frameSize;
            }
        }
        public void Parse_TestData_ReturnsValidFrame()
        {
            var testCodecInfo = new AACCodecInfo
            {
                ConfigBytes      = new byte[] { 20, 8 },
                IndexDeltaLength = 3,
                IndexLength      = 3,
                SizeLength       = 13
            };

            byte[] testBytes = Convert.FromBase64String(
                "ABAPyAE2Nay0eJ0OEMF4cOFyZeskqICVBWXLiAFDYHBG3GXFf0r/3nn+pRYcsdweO8Pzlxhjm0Q5QrEf7jx31b1PX8VuZOcZZ516jVY6sW/ISf8SQb6fONzpYJLiNRi7SO1o+" +
                "ByL8qHHiUeF9EoqyQ1VgamBApL8XaznlKoszkm9Td02961s0SznSmtSZcuhaEYCZaPe1k5qM+U3wHzs3CCnWMSNsK9UNCq1dzSm4YZWRkJPIY4oXJXsSCW67r8Xdb4slBDvxqu709z" +
                "ggyqrTuoOtkR3aHhFs6JHL8QwVgiusj39H8FrZ8Nu3Dt3qu0NQo5KpHN4R1jn2G71VHMfJwGEwZisU2e9Pz3h316dvpt97XbNcxLTgUCz9UpleUNXWAeygFCrPGTpWFv1Qn3JxS4W1xI" +
                "W5W/dHymYM5ElSMhtF+PFounb/IKbxKJThTUkxx3FWwYt00q7nMOilx2t6odQue/bTaENXKw304l1X5aiEl2S4+C0pIEzkHpbMp+5bmLw1+M8FNRkzlEngnPPATaJQSNOqTHTwVmK+" +
                "fAVSESminLM1TAOg0EZUw0pLTl3ka+scMp9kmxkFKLr3YRip0Uy0JMSnfefWxGezotf3sbV4afJZrnuVnKyanaK33korbN4LMIhvBgAAAAAAAAAAAAAAAAAAAAAAAAAA70=");

            byte[] frameBytes = Convert.FromBase64String(
                "D8gBNjWstHidDhDBeHDhcmXrJKiAlQVly4gBQ2BwRtxlxX9K/955/qUWHLHcHjvD85cYY5tEOUKxH+48d9W9T1/FbmTnGWedeo1" +
                "WOrFvyEn/EkG+nzjc6WCS4jUYu0jtaPgci/Khx4lHhfRKKskNVYGpgQKS/F2s55SqLM5JvU3dNvetbNEs50prUmXLoWhGAmWj3tZO" +
                "ajPlN8B87Nwgp1jEjbCvVDQqtXc0puGGVkZCTyGOKFyV7Egluu6/F3W+LJQQ78aru9Pc4IMqq07qDrZEd2h4RbOiRy/EMFYIrrI9/R/" +
                "Ba2fDbtw7d6rtDUKOSqRzeEdY59hu9VRzHycBhMGYrFNnvT894d9enb6bfe12zXMS04FAs/VKZXlDV1gHsoBQqzxk6Vhb9UJ9ycUuFt" +
                "cSFuVv3R8pmDORJUjIbRfjxaLp2/yCm8SiU4U1JMcdxVsGLdNKu5zDopcdreqHULnv202hDVysN9OJdV+WohJdkuPgtKSBM5B6WzKfuW" +
                "5i8NfjPBTUZM5RJ4JzzwE2iUEjTqkx08FZivnwFUhEpopyzNUwDoNBGVMNKS05d5GvrHDKfZJsZBSi692EYqdFMtCTEp33n1sRns6LX97" +
                "G1eGnyWa57lZysmp2it95KK2zeCzCIbwYAAAAAAAAAAAAAAAAAAAAAAAAAA==");

            RawAACFrame frame  = null;
            var         parser = new AACAudioPayloadParser(testCodecInfo);

            parser.FrameGenerated = rawFrame => frame = (RawAACFrame)rawFrame;
            parser.Parse(TimeSpan.Zero, new ArraySegment <byte>(testBytes), true);

            Assert.IsNotNull(frame);
            Assert.AreEqual(FrameType.Audio, frame.Type);
            Assert.IsTrue(frame.ConfigSegment.SequenceEqual(testCodecInfo.ConfigBytes));
            Assert.IsTrue(frame.FrameSegment.SequenceEqual(frameBytes));
        }