From e5f6abab65aff8eed80e9cec249e4e562e482a51 Mon Sep 17 00:00:00 2001 From: lastpeony Date: Tue, 6 Aug 2024 15:46:48 +0300 Subject: [PATCH 1/3] fix rtmp dts overflow after approximately 24 days --- .../java/io/antmedia/muxer/MuxAdaptor.java | 44 ++++- .../java/io/antmedia/test/MuxerUnitTest.java | 183 +++++++++++++++++- 2 files changed, 217 insertions(+), 10 deletions(-) diff --git a/src/main/java/io/antmedia/muxer/MuxAdaptor.java b/src/main/java/io/antmedia/muxer/MuxAdaptor.java index 8758d151a..bdaa04405 100644 --- a/src/main/java/io/antmedia/muxer/MuxAdaptor.java +++ b/src/main/java/io/antmedia/muxer/MuxAdaptor.java @@ -199,6 +199,9 @@ public class MuxAdaptor implements IRecordingListener, IEndpointStatusListener { */ private Deque packetTimeList = new ConcurrentLinkedDeque<>(); + private long[] lastDTS = new long[2]; + private int[] overflowCount = {0, 0}; + public boolean addID3Data(String data) { for (Muxer muxer : muxerList) { if(muxer instanceof HLSMuxer) { @@ -278,7 +281,7 @@ public PacketTime(long packetTimeMs, long systemTimeMs) { private BytePointer audioExtraDataPointer; private BytePointer videoExtraDataPointer; private AtomicLong endpointStatusUpdaterTimer = new AtomicLong(-1l); - private ConcurrentHashMap endpointStatusUpdateMap = new ConcurrentHashMap<>(); + private ConcurrentHashMap endpointStatusUpdateMap = new ConcurrentHashMap<>(); protected PacketFeeder packetFeeder; @@ -971,9 +974,32 @@ public DataStore getDataStore() { return dataStore; } + public long correctPacketDtsOverflow(long packetDts, byte streamType) { + int index = 0; + + if(streamType == Constants.TYPE_AUDIO_DATA) { + index = 1; + } + + if (lastDTS[index] > packetDts) { + + if (lastDTS[index] > packetDts + overflowCount[index] * Integer.MAX_VALUE) { + overflowCount[index]++; + } + + packetDts = packetDts + overflowCount[index] * Integer.MAX_VALUE; + } + + lastDTS[index] = packetDts; + + return packetDts; + + } + public void writeStreamPacket(IStreamPacket packet) { long dts = packet.getTimestamp() & 0xffffffffL; + dts = correctPacketDtsOverflow(dts, packet.getDataType()); if (packet.getDataType() == Constants.TYPE_VIDEO_DATA) { @@ -2430,6 +2456,22 @@ public void setWidth(int width) { this.width = width; } + public long[] getLastDTS() { + return lastDTS; + } + + public int[] getOverflowCount() { + return overflowCount; + } + + public PacketFeeder getPacketFeeder() { + return packetFeeder; + } + + public void setPacketFeeder(PacketFeeder packetFeeder) { + this.packetFeeder = packetFeeder; + } + } diff --git a/src/test/java/io/antmedia/test/MuxerUnitTest.java b/src/test/java/io/antmedia/test/MuxerUnitTest.java index e090bd597..f1a6ab19e 100644 --- a/src/test/java/io/antmedia/test/MuxerUnitTest.java +++ b/src/test/java/io/antmedia/test/MuxerUnitTest.java @@ -9,7 +9,6 @@ import static org.bytedeco.ffmpeg.global.avformat.avformat_close_input; import static org.bytedeco.ffmpeg.global.avformat.avformat_find_stream_info; import static org.bytedeco.ffmpeg.global.avformat.avformat_free_context; -import static org.bytedeco.ffmpeg.global.avformat.*; import static org.bytedeco.ffmpeg.global.avutil.AVMEDIA_TYPE_ATTACHMENT; import static org.bytedeco.ffmpeg.global.avutil.AVMEDIA_TYPE_AUDIO; import static org.bytedeco.ffmpeg.global.avutil.AVMEDIA_TYPE_DATA; @@ -47,12 +46,7 @@ import java.io.IOException; import java.lang.ref.WeakReference; import java.nio.ByteBuffer; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.HashMap; -import java.util.Iterator; -import java.util.List; -import java.util.Map; +import java.util.*; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentSkipListSet; import java.util.concurrent.TimeUnit; @@ -97,7 +91,6 @@ import org.red5.io.ITag; import org.red5.io.flv.impl.FLVReader; import org.red5.io.flv.impl.Tag; -import org.red5.server.api.IContext; import org.red5.server.api.scope.IScope; import org.red5.server.api.stream.IStreamCapableConnection; import org.red5.server.api.stream.IStreamPacket; @@ -114,7 +107,6 @@ import org.red5.server.stream.VideoCodecFactory; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.springframework.context.ApplicationContext; import org.springframework.test.annotation.DirtiesContext; import org.springframework.test.annotation.DirtiesContext.ClassMode; import org.springframework.test.context.ContextConfiguration; @@ -4963,4 +4955,177 @@ public void testRecordingWithRecordingSubfolder() { testMp4Muxing("record" + RandomUtils.nextInt(0, 10000)); } + @Test + public void testRtmpDtsOverflow() { + + if (appScope == null) { + appScope = (WebScope) applicationContext.getBean("web.scope"); + logger.debug("Application / web scope: {}", appScope); + assertTrue(appScope.getDepth() == 1); + } + + ClientBroadcastStream clientBroadcastStream = mock(ClientBroadcastStream.class); + MuxAdaptor muxAdaptor = Mockito.spy(MuxAdaptor.initializeMuxAdaptor(clientBroadcastStream, null, false, appScope)); + PacketFeeder packetFeeder = new PacketFeeder("test"); + muxAdaptor.setPacketFeeder(packetFeeder); + + muxAdaptor.setVideoStreamIndex(0); + muxAdaptor.setAudioStreamIndex(1); + + HLSMuxer hlsMuxer = mock(HLSMuxer.class); + muxAdaptor.addMuxer(hlsMuxer); + + muxAdaptor.setEnableAudio(true); + muxAdaptor.setEnableVideo(true); + + ByteBuffer byteBuffer = mock(ByteBuffer.class); + IoBuffer ioBuffer = mock(IoBuffer.class); + when(ioBuffer.limit()).thenReturn(1024); + when(ioBuffer.buf()).thenReturn(byteBuffer); + when(byteBuffer.position(2)).thenReturn(ByteBuffer.allocateDirect(3)); + when(byteBuffer.position(5)).thenReturn(ByteBuffer.allocateDirect(3)); + + + when(ioBuffer.position(0)).thenReturn(ioBuffer); + when(ioBuffer.position(2)).thenReturn(ioBuffer); + when(ioBuffer.position(3)).thenReturn(ioBuffer); + + ByteBuffer directByteBuffer = ByteBuffer.allocateDirect(1024-2); + directByteBuffer.put(ioBuffer.buf().position(2)); + directByteBuffer.position(0); + + ByteBuffer directByteBufferVideo = ByteBuffer.allocateDirect(1024-5); + directByteBufferVideo.put(ioBuffer.buf().position(2)); + directByteBufferVideo.position(3); + + //audio packets + IStreamPacket audioPacket1 = mock(IStreamPacket.class); + when(audioPacket1.getDataType()).thenReturn(Constants.TYPE_AUDIO_DATA); + when(audioPacket1.getTimestamp()).thenReturn(2147483584); + when(audioPacket1.getData()).thenReturn(ioBuffer); + + IStreamPacket audioPacket2 = mock(IStreamPacket.class); + when(audioPacket2.getDataType()).thenReturn(Constants.TYPE_AUDIO_DATA); + when(audioPacket2.getTimestamp()).thenReturn(2147483604); + when(audioPacket2.getData()).thenReturn(ioBuffer); + + IStreamPacket audioPacket3 = mock(IStreamPacket.class); + when(audioPacket3.getDataType()).thenReturn(Constants.TYPE_AUDIO_DATA); + when(audioPacket3.getTimestamp()).thenReturn(2147483627); + when(audioPacket3.getData()).thenReturn(ioBuffer); + + IStreamPacket audioPacket4 = mock(IStreamPacket.class); + when(audioPacket4.getDataType()).thenReturn(Constants.TYPE_AUDIO_DATA); + when(audioPacket4.getTimestamp()).thenReturn(2147483628); + when(audioPacket4.getData()).thenReturn(ioBuffer); + + IStreamPacket audioPacketOverflowed = mock(IStreamPacket.class); + when(audioPacketOverflowed.getDataType()).thenReturn(Constants.TYPE_AUDIO_DATA); + when(audioPacketOverflowed.getTimestamp()).thenReturn(24); + when(audioPacketOverflowed.getData()).thenReturn(ioBuffer); + + //video packets + IStreamPacket videoPacket1 = mock(CachedEvent.class); + when(videoPacket1.getDataType()).thenReturn(Constants.TYPE_VIDEO_DATA); + when(videoPacket1.getTimestamp()).thenReturn(2147483579); + when(videoPacket1.getData()).thenReturn(ioBuffer); + + IStreamPacket videoPacket2 = mock(CachedEvent.class); + when(videoPacket2.getDataType()).thenReturn(Constants.TYPE_VIDEO_DATA); + when(videoPacket2.getTimestamp()).thenReturn(2147483613); + when(videoPacket2.getData()).thenReturn(ioBuffer); + + IStreamPacket videoPacket3 = mock(CachedEvent.class); + when(videoPacket3.getDataType()).thenReturn(Constants.TYPE_VIDEO_DATA); + when(videoPacket3.getTimestamp()).thenReturn(2147483646); + when(videoPacket3.getData()).thenReturn(ioBuffer); + + IStreamPacket videoPacket4 = mock(CachedEvent.class); + when(videoPacket4.getDataType()).thenReturn(Constants.TYPE_VIDEO_DATA); + when(videoPacket4.getTimestamp()).thenReturn(2147483647); + when(videoPacket4.getData()).thenReturn(ioBuffer); + + IStreamPacket videoPacketOverflowed = mock(CachedEvent.class); + + when(videoPacketOverflowed.getDataType()).thenReturn(Constants.TYPE_VIDEO_DATA); + when(videoPacketOverflowed.getTimestamp()).thenReturn(65); + when(videoPacketOverflowed.getData()).thenReturn(ioBuffer); + + + muxAdaptor.writeStreamPacket(audioPacket1); + int audioOverFlowCount = muxAdaptor.getOverflowCount()[1]; + assertEquals(0, audioOverFlowCount); + long lastAudioDts = muxAdaptor.getLastDTS()[1]; + assertEquals(lastAudioDts, audioPacket1.getTimestamp()); + + muxAdaptor.writeStreamPacket(videoPacket1); + int videoOverFlowCount = muxAdaptor.getOverflowCount()[0]; + assertEquals(0, audioOverFlowCount); + long lastVideoDts = muxAdaptor.getLastDTS()[0]; + assertEquals(lastVideoDts, videoPacket1.getTimestamp()); + + muxAdaptor.writeStreamPacket(audioPacket2); + audioOverFlowCount = muxAdaptor.getOverflowCount()[1]; + assertEquals(0, audioOverFlowCount); + lastAudioDts = muxAdaptor.getLastDTS()[1]; + assertEquals(lastAudioDts, audioPacket2.getTimestamp()); + + muxAdaptor.writeStreamPacket(videoPacket2); + videoOverFlowCount = muxAdaptor.getOverflowCount()[0]; + assertEquals(0, videoOverFlowCount); + lastVideoDts = muxAdaptor.getLastDTS()[0]; + assertEquals(lastVideoDts, videoPacket2.getTimestamp()); + + + verify(hlsMuxer,times(1)).writeAudioBuffer(directByteBuffer,1, audioPacket2.getTimestamp()); + verify(hlsMuxer,times(1)).writeVideoBuffer(directByteBufferVideo, videoPacket2.getTimestamp(), 0, 0, false, 0, videoPacket2.getTimestamp()); + + muxAdaptor.writeStreamPacket(audioPacket3); + audioOverFlowCount = muxAdaptor.getOverflowCount()[1]; + assertEquals(0, audioOverFlowCount); + lastAudioDts = muxAdaptor.getLastDTS()[1]; + assertEquals(lastAudioDts, audioPacket3.getTimestamp()); + + muxAdaptor.writeStreamPacket(videoPacket3); + videoOverFlowCount = muxAdaptor.getOverflowCount()[0]; + assertEquals(0, videoOverFlowCount); + lastVideoDts = muxAdaptor.getLastDTS()[0]; + assertEquals(lastVideoDts, videoPacket3.getTimestamp()); + + verify(hlsMuxer,times(1)).writeAudioBuffer(directByteBuffer,1, audioPacket3.getTimestamp()); + + directByteBufferVideo.position(0); + verify(hlsMuxer,times(1)).writeVideoBuffer(directByteBufferVideo, videoPacket3.getTimestamp(), 0, 0, false, 0, videoPacket3.getTimestamp()); + + muxAdaptor.writeStreamPacket(audioPacket4); + audioOverFlowCount = muxAdaptor.getOverflowCount()[1]; + assertEquals(0, audioOverFlowCount); + lastAudioDts = muxAdaptor.getLastDTS()[1]; + assertEquals(lastAudioDts, audioPacket4.getTimestamp()); + + muxAdaptor.writeStreamPacket(videoPacket4); + videoOverFlowCount = muxAdaptor.getOverflowCount()[0]; + assertEquals(0, videoOverFlowCount); + lastVideoDts = muxAdaptor.getLastDTS()[0]; + assertEquals(lastVideoDts, videoPacket4.getTimestamp()); + + verify(hlsMuxer,times(1)).writeAudioBuffer(directByteBuffer,1, audioPacket4.getTimestamp()); + verify(hlsMuxer,times(1)).writeVideoBuffer(directByteBufferVideo, videoPacket4.getTimestamp(), 0, 0, false, 0, videoPacket4.getTimestamp()); + + muxAdaptor.writeStreamPacket(audioPacketOverflowed); + audioOverFlowCount = muxAdaptor.getOverflowCount()[1]; + assertEquals(1, audioOverFlowCount); + lastAudioDts = muxAdaptor.getLastDTS()[1]; + assertEquals(lastAudioDts, audioPacketOverflowed.getTimestamp() + (long) audioOverFlowCount * Integer.MAX_VALUE); + + muxAdaptor.writeStreamPacket(videoPacketOverflowed); + videoOverFlowCount = muxAdaptor.getOverflowCount()[0]; + assertEquals(1, videoOverFlowCount); + lastVideoDts = muxAdaptor.getLastDTS()[0]; + assertEquals(lastVideoDts, videoPacketOverflowed.getTimestamp() + (long) videoOverFlowCount * Integer.MAX_VALUE); + + verify(hlsMuxer,times(1)).writeAudioBuffer(directByteBuffer,1, lastAudioDts); + verify(hlsMuxer,times(1)).writeVideoBuffer(directByteBufferVideo, lastVideoDts, 0, 0, false, 0, lastVideoDts); + } + } From 7fe431cc5169883f5d1dfe7cdf0d5ddfff499cac Mon Sep 17 00:00:00 2001 From: lastpeony Date: Tue, 6 Aug 2024 15:52:39 +0300 Subject: [PATCH 2/3] comment --- src/main/java/io/antmedia/muxer/MuxAdaptor.java | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/src/main/java/io/antmedia/muxer/MuxAdaptor.java b/src/main/java/io/antmedia/muxer/MuxAdaptor.java index bdaa04405..8f0f93e2a 100644 --- a/src/main/java/io/antmedia/muxer/MuxAdaptor.java +++ b/src/main/java/io/antmedia/muxer/MuxAdaptor.java @@ -974,7 +974,16 @@ public DataStore getDataStore() { return dataStore; } + public long correctPacketDtsOverflow(long packetDts, byte streamType) { + /* + * Continuous RTMP streaming for approximately 24 days can cause the DTS values to overflow + * and reset to 0 once they reach the maximum value for a signed integer. + * This method handles the overflow by continuing to increment the DTS values as if they hadn't reset, + * ensuring that the timestamps remain consistent and do not start over from 0. + * If this correction is not applied, errors occur when writing to the HLS muxer, leading to a halt in .ts generation. + */ + int index = 0; if(streamType == Constants.TYPE_AUDIO_DATA) { @@ -983,11 +992,11 @@ public long correctPacketDtsOverflow(long packetDts, byte streamType) { if (lastDTS[index] > packetDts) { - if (lastDTS[index] > packetDts + overflowCount[index] * Integer.MAX_VALUE) { + if (lastDTS[index] > packetDts + (long) overflowCount[index] * Integer.MAX_VALUE) { overflowCount[index]++; } - packetDts = packetDts + overflowCount[index] * Integer.MAX_VALUE; + packetDts = packetDts + (long) overflowCount[index] * Integer.MAX_VALUE; } lastDTS[index] = packetDts; From 7c24c9d7fa36eeadb5920132597e10585e17561c Mon Sep 17 00:00:00 2001 From: mekya Date: Tue, 27 Aug 2024 22:31:05 +0300 Subject: [PATCH 3/3] Refactor RTMP overflow and update test code --- .../java/io/antmedia/muxer/MuxAdaptor.java | 5 +- .../java/io/antmedia/test/MuxerUnitTest.java | 94 +++++++++---------- 2 files changed, 49 insertions(+), 50 deletions(-) diff --git a/src/main/java/io/antmedia/muxer/MuxAdaptor.java b/src/main/java/io/antmedia/muxer/MuxAdaptor.java index e938a0698..e33aeecd4 100644 --- a/src/main/java/io/antmedia/muxer/MuxAdaptor.java +++ b/src/main/java/io/antmedia/muxer/MuxAdaptor.java @@ -1064,7 +1064,7 @@ public DataStore getDataStore() { } - public long correctPacketDtsOverflow(long packetDts, byte streamType) { + public long correctPacketDtsOverflow(long packetDts) { /* * Continuous RTMP streaming for approximately 24 days can cause the DTS values to overflow * and reset to 0 once they reach the maximum value for a signed integer. @@ -1101,8 +1101,7 @@ public void writeStreamPacket(IStreamPacket packet) { //RTMPProtocolDecoder overflows after 24 days(Integer.MAX_Value) of continuous streaming and it starts from zero again. //According to the protocol it should overflow after 49 days. Anyway, we fix the overflow here - long dts = packet.getTimestamp() & 0xffffffffL; - dts = correctPacketDtsOverflow(dts, packet.getDataType()); + long dts = correctPacketDtsOverflow(packet.getTimestamp()); if (packet.getDataType() == Constants.TYPE_VIDEO_DATA) { diff --git a/src/test/java/io/antmedia/test/MuxerUnitTest.java b/src/test/java/io/antmedia/test/MuxerUnitTest.java index 6a2aad9aa..4134ca093 100644 --- a/src/test/java/io/antmedia/test/MuxerUnitTest.java +++ b/src/test/java/io/antmedia/test/MuxerUnitTest.java @@ -5497,8 +5497,6 @@ public void testSetSEIData() { } - - } @Test @@ -5605,76 +5603,78 @@ public void testRtmpDtsOverflow() { muxAdaptor.writeStreamPacket(audioPacket1); - int audioOverFlowCount = muxAdaptor.getOverflowCount()[1]; - assertEquals(0, audioOverFlowCount); - long lastAudioDts = muxAdaptor.getLastDTS()[1]; + int overFlowCount = muxAdaptor.getOverflowCount(); + assertEquals(0, overFlowCount); + long lastAudioDts = muxAdaptor.getLastDTS(); assertEquals(lastAudioDts, audioPacket1.getTimestamp()); muxAdaptor.writeStreamPacket(videoPacket1); - int videoOverFlowCount = muxAdaptor.getOverflowCount()[0]; - assertEquals(0, audioOverFlowCount); - long lastVideoDts = muxAdaptor.getLastDTS()[0]; - assertEquals(lastVideoDts, videoPacket1.getTimestamp()); + overFlowCount = muxAdaptor.getOverflowCount(); + assertEquals(1, overFlowCount); + long lastVideoDts = muxAdaptor.getLastDTS(); + assertEquals(lastVideoDts, videoPacket1.getTimestamp() + (long) overFlowCount * Integer.MAX_VALUE); muxAdaptor.writeStreamPacket(audioPacket2); - audioOverFlowCount = muxAdaptor.getOverflowCount()[1]; - assertEquals(0, audioOverFlowCount); - lastAudioDts = muxAdaptor.getLastDTS()[1]; - assertEquals(lastAudioDts, audioPacket2.getTimestamp()); + overFlowCount = muxAdaptor.getOverflowCount(); + assertEquals(1, overFlowCount); + lastAudioDts = muxAdaptor.getLastDTS(); + assertEquals(lastAudioDts, audioPacket2.getTimestamp() + (long) overFlowCount * Integer.MAX_VALUE); muxAdaptor.writeStreamPacket(videoPacket2); - videoOverFlowCount = muxAdaptor.getOverflowCount()[0]; - assertEquals(0, videoOverFlowCount); - lastVideoDts = muxAdaptor.getLastDTS()[0]; - assertEquals(lastVideoDts, videoPacket2.getTimestamp()); + overFlowCount = muxAdaptor.getOverflowCount(); + assertEquals(1, overFlowCount); + lastVideoDts = muxAdaptor.getLastDTS(); + assertEquals(lastVideoDts, videoPacket2.getTimestamp() + (long) overFlowCount * Integer.MAX_VALUE); - verify(hlsMuxer,times(1)).writeAudioBuffer(directByteBuffer,1, audioPacket2.getTimestamp()); - verify(hlsMuxer,times(1)).writeVideoBuffer(directByteBufferVideo, videoPacket2.getTimestamp(), 0, 0, false, 0, videoPacket2.getTimestamp()); + verify(hlsMuxer,times(1)).writeAudioBuffer(directByteBuffer,1, audioPacket2.getTimestamp() + (long) overFlowCount * Integer.MAX_VALUE ); + verify(hlsMuxer,times(1)).writeVideoBuffer(directByteBufferVideo, videoPacket2.getTimestamp() + (long) overFlowCount * Integer.MAX_VALUE, 0, 0, false, 0, videoPacket2.getTimestamp() + (long) overFlowCount * Integer.MAX_VALUE); muxAdaptor.writeStreamPacket(audioPacket3); - audioOverFlowCount = muxAdaptor.getOverflowCount()[1]; - assertEquals(0, audioOverFlowCount); - lastAudioDts = muxAdaptor.getLastDTS()[1]; - assertEquals(lastAudioDts, audioPacket3.getTimestamp()); + overFlowCount = muxAdaptor.getOverflowCount(); + assertEquals(1, overFlowCount); + lastAudioDts = muxAdaptor.getLastDTS(); + assertEquals(lastAudioDts, audioPacket3.getTimestamp() + (long) overFlowCount * Integer.MAX_VALUE); muxAdaptor.writeStreamPacket(videoPacket3); - videoOverFlowCount = muxAdaptor.getOverflowCount()[0]; - assertEquals(0, videoOverFlowCount); - lastVideoDts = muxAdaptor.getLastDTS()[0]; - assertEquals(lastVideoDts, videoPacket3.getTimestamp()); + overFlowCount = muxAdaptor.getOverflowCount(); + assertEquals(1, overFlowCount); + lastVideoDts = muxAdaptor.getLastDTS(); + assertEquals(lastVideoDts, videoPacket3.getTimestamp() + (long) overFlowCount * Integer.MAX_VALUE); - verify(hlsMuxer,times(1)).writeAudioBuffer(directByteBuffer,1, audioPacket3.getTimestamp()); + verify(hlsMuxer,times(1)).writeAudioBuffer(directByteBuffer,1, audioPacket3.getTimestamp() + (long) overFlowCount * Integer.MAX_VALUE); directByteBufferVideo.position(0); - verify(hlsMuxer,times(1)).writeVideoBuffer(directByteBufferVideo, videoPacket3.getTimestamp(), 0, 0, false, 0, videoPacket3.getTimestamp()); + verify(hlsMuxer,times(1)).writeVideoBuffer(directByteBufferVideo, videoPacket3.getTimestamp() + (long) overFlowCount * Integer.MAX_VALUE, 0, 0, false, 0, + videoPacket3.getTimestamp() + (long) overFlowCount * Integer.MAX_VALUE); muxAdaptor.writeStreamPacket(audioPacket4); - audioOverFlowCount = muxAdaptor.getOverflowCount()[1]; - assertEquals(0, audioOverFlowCount); - lastAudioDts = muxAdaptor.getLastDTS()[1]; - assertEquals(lastAudioDts, audioPacket4.getTimestamp()); + overFlowCount = muxAdaptor.getOverflowCount(); + assertEquals(2, overFlowCount); + lastAudioDts = muxAdaptor.getLastDTS(); + assertEquals(lastAudioDts, audioPacket4.getTimestamp()+(long) overFlowCount * Integer.MAX_VALUE); muxAdaptor.writeStreamPacket(videoPacket4); - videoOverFlowCount = muxAdaptor.getOverflowCount()[0]; - assertEquals(0, videoOverFlowCount); - lastVideoDts = muxAdaptor.getLastDTS()[0]; - assertEquals(lastVideoDts, videoPacket4.getTimestamp()); + overFlowCount = muxAdaptor.getOverflowCount(); + assertEquals(2, overFlowCount); + lastVideoDts = muxAdaptor.getLastDTS(); + assertEquals(lastVideoDts, videoPacket4.getTimestamp() + (long) overFlowCount * Integer.MAX_VALUE); - verify(hlsMuxer,times(1)).writeAudioBuffer(directByteBuffer,1, audioPacket4.getTimestamp()); - verify(hlsMuxer,times(1)).writeVideoBuffer(directByteBufferVideo, videoPacket4.getTimestamp(), 0, 0, false, 0, videoPacket4.getTimestamp()); + verify(hlsMuxer,times(1)).writeAudioBuffer(directByteBuffer,1, audioPacket4.getTimestamp() + (long) overFlowCount * Integer.MAX_VALUE); + verify(hlsMuxer,times(1)).writeVideoBuffer(directByteBufferVideo, videoPacket4.getTimestamp() + (long) overFlowCount * Integer.MAX_VALUE, 0, 0, false, 0, + videoPacket4.getTimestamp() + (long) overFlowCount * Integer.MAX_VALUE); muxAdaptor.writeStreamPacket(audioPacketOverflowed); - audioOverFlowCount = muxAdaptor.getOverflowCount()[1]; - assertEquals(1, audioOverFlowCount); - lastAudioDts = muxAdaptor.getLastDTS()[1]; - assertEquals(lastAudioDts, audioPacketOverflowed.getTimestamp() + (long) audioOverFlowCount * Integer.MAX_VALUE); + overFlowCount = muxAdaptor.getOverflowCount(); + assertEquals(3, overFlowCount); + lastAudioDts = muxAdaptor.getLastDTS(); + assertEquals(lastAudioDts, audioPacketOverflowed.getTimestamp() + (long) overFlowCount * Integer.MAX_VALUE); muxAdaptor.writeStreamPacket(videoPacketOverflowed); - videoOverFlowCount = muxAdaptor.getOverflowCount()[0]; - assertEquals(1, videoOverFlowCount); - lastVideoDts = muxAdaptor.getLastDTS()[0]; - assertEquals(lastVideoDts, videoPacketOverflowed.getTimestamp() + (long) videoOverFlowCount * Integer.MAX_VALUE); + overFlowCount = muxAdaptor.getOverflowCount(); + assertEquals(3, overFlowCount); + lastVideoDts = muxAdaptor.getLastDTS(); + assertEquals(lastVideoDts, videoPacketOverflowed.getTimestamp() + (long) overFlowCount * Integer.MAX_VALUE); verify(hlsMuxer,times(1)).writeAudioBuffer(directByteBuffer,1, lastAudioDts); verify(hlsMuxer,times(1)).writeVideoBuffer(directByteBufferVideo, lastVideoDts, 0, 0, false, 0, lastVideoDts);