2626
2727import net .butterflytv .rtmp_client .RTMPMuxer ;
2828
29+ import java .util .Collections ;
30+ import java .util .Comparator ;
31+ import java .util .LinkedList ;
32+ import java .util .List ;
33+ import java .util .Locale ;
34+
2935/**
3036 * Created by Chilling on 2017/5/29.
3137 */
3238
3339public class RTMPStreamMuxer implements IMuxer {
3440
3541
42+ public static final int KEEP_COUNT = 30 ;
3643 private String filename = "" ;
3744 private RTMPMuxer rtmpMuxer ;
3845
39- private long lastVideoTime = -1 ;
40- private long lastAudioTime = -1 ;
46+ private long lastVideoTime ;
47+ private long lastAudioTime ;
48+ private int totalVideoTime ;
49+ private int totalAudioTime ;
50+
51+
52+ private List <Frame > frameQueue = new LinkedList <>();
4153
4254 public RTMPStreamMuxer () {
4355 this ("" );
@@ -49,51 +61,109 @@ public RTMPStreamMuxer(String filename) {
4961 }
5062
5163 @ Override
52- public int open (String url , int videoWidth , int videoHeight ) {
64+ public synchronized int open (String url , int videoWidth , int videoHeight ) {
65+ lastVideoTime = -1 ;
66+ lastAudioTime = -1 ;
67+ totalVideoTime = 0 ;
68+ totalAudioTime = 0 ;
69+
70+ int open = rtmpMuxer .open (url , videoWidth , videoHeight );
71+ Loggers .d ("RTMPStreamMuxer" , String .format (Locale .CHINA , "open: open: %d" , open ));
72+ int connected = rtmpMuxer .isConnected ();
73+ Loggers .d ("RTMPStreamMuxer" , String .format (Locale .CHINA , "open: isConnected: %d" , connected ));
74+
5375 Loggers .d ("RTMPStreamMuxer" , String .format ("open: %s" , url ));
5476 if (!"" .equals (filename )) {
5577 rtmpMuxer .file_open (filename );
5678 rtmpMuxer .write_flv_header (true , true );
5779 }
58-
59- int open = rtmpMuxer .open (url , videoWidth , videoHeight );
60- Loggers .d ("RTMPStreamMuxer" , String .format ("open: open: %d" , open ));
61- int connected = rtmpMuxer .isConnected ();
62- Loggers .d ("RTMPStreamMuxer" , String .format ("open: isConnected: %d" , connected ));
6380 return connected ;
6481 }
6582
6683 @ Override
67- public void writeVideo (byte [] buffer , int offset , int length , MediaCodec .BufferInfo bufferInfo ) {
68- Loggers .d ("RTMPStreamMuxer" , String . format ( "writeVideo: " ) );
84+ public synchronized void writeVideo (byte [] buffer , int offset , int length , MediaCodec .BufferInfo bufferInfo ) {
85+ Loggers .d ("RTMPStreamMuxer" , "writeVideo: " );
6986 if (lastVideoTime <= 0 ) {
7087 lastVideoTime = bufferInfo .presentationTimeUs ;
7188 }
7289
7390 int delta = (int ) (bufferInfo .presentationTimeUs - lastVideoTime );
7491 lastVideoTime = bufferInfo .presentationTimeUs ;
7592
76- rtmpMuxer .writeVideo (buffer , offset , length , Math .abs (delta /1000 ));
93+ totalVideoTime += Math .abs (delta /1000 );
94+ addFrame (buffer , offset , length , totalVideoTime , Frame .TYPE_VIDEO );
95+ sendFrame (KEEP_COUNT );
96+ }
97+
98+ private void addFrame (byte [] buffer , int offset , int length , int time , int type ) {
99+ byte [] frameData = new byte [length ];
100+ System .arraycopy (buffer , offset , frameData , 0 , length );
101+ frameQueue .add (new Frame (frameData , time , type ));
102+ Frame .sortFrame (frameQueue );
103+ }
104+
105+ private void sendFrame (int keepCount ) {
106+ while (frameQueue .size () >= keepCount ) {
107+ Frame sendFrame = frameQueue .remove (0 );
108+ Loggers .i ("RTMPStreamMuxer" , String .format (Locale .CHINA , "sendFrame: size:%d time:%d, type:%d" , sendFrame .data .length , sendFrame .timeStampMs , sendFrame .type ));
109+ byte [] array = sendFrame .data ;
110+ if (sendFrame .type == Frame .TYPE_VIDEO ) {
111+ rtmpMuxer .writeVideo (array , 0 , array .length , sendFrame .timeStampMs );
112+ } else {
113+ rtmpMuxer .writeAudio (array , 0 , array .length , sendFrame .timeStampMs );
114+ }
115+ }
77116 }
78117
79118 @ Override
80- public void writeAudio (byte [] buffer , int offset , int length , MediaCodec .BufferInfo bufferInfo ) {
81- Loggers .d ("RTMPStreamMuxer" , String . format ( "writeAudio: " ) );
119+ public synchronized void writeAudio (byte [] buffer , int offset , int length , MediaCodec .BufferInfo bufferInfo ) {
120+ Loggers .d ("RTMPStreamMuxer" , "writeAudio: " );
82121 if (lastAudioTime <= 0 ) {
83122 lastAudioTime = bufferInfo .presentationTimeUs ;
84123 }
85124
86125 int delta = (int ) (bufferInfo .presentationTimeUs - lastAudioTime );
87126 lastAudioTime = bufferInfo .presentationTimeUs ;
88- rtmpMuxer .writeAudio (buffer , offset , length , Math .abs (delta /1000 ));
127+ totalAudioTime += Math .abs (delta /1000 );
128+ addFrame (buffer , offset , length , totalAudioTime , Frame .TYPE_AUDIO );
129+ sendFrame (KEEP_COUNT );
89130 }
90131
91132 @ Override
92- public int close () {
133+ public synchronized int close () {
134+ sendFrame (0 );
93135 if (!"" .equals (filename )) {
94136 rtmpMuxer .file_close ();
95137 }
96138 return rtmpMuxer .close ();
97- // return 0;
139+ }
140+
141+ private static class Frame {
142+ public byte [] data ;
143+ public int timeStampMs ;
144+ public int type ;
145+ public static final int TYPE_VIDEO = 1 ;
146+ public static final int TYPE_AUDIO = 2 ;
147+
148+ public Frame (byte [] data , int timeStampMs , int type ) {
149+ this .data = data ;
150+ this .timeStampMs = timeStampMs ;
151+ this .type = type ;
152+ }
153+
154+ static void sortFrame (List <Frame > frameQueue ) {
155+ Collections .sort (frameQueue , new Comparator <Frame >() {
156+ @ Override
157+ public int compare (Frame left , Frame right ) {
158+ if (left .timeStampMs < right .timeStampMs ) {
159+ return -1 ;
160+ } else if (left .timeStampMs == right .timeStampMs ) {
161+ return 0 ;
162+ } else {
163+ return 1 ;
164+ }
165+ }
166+ });
167+ }
98168 }
99169}
0 commit comments