Skip to content
Snippets Groups Projects
Commit 6c445147 authored by Leo Ma's avatar Leo Ma
Browse files

Substitute message handler for exception


Reduce try-catch blocks for the whole project.

Signed-off-by: default avatarLeo Ma <begeekmyfriend@gmail.com>
parent d15f1930
No related branches found
No related tags found
No related merge requests found
Showing
with 465 additions and 295 deletions
Loading
Loading
@@ -20,14 +20,16 @@ import com.github.faucamp.simplertmp.RtmpHandler;
import com.seu.magicfilter.utils.MagicFilterType;
 
import net.ossrs.yasea.SrsCameraView;
import net.ossrs.yasea.SrsNetworkHandler;
import net.ossrs.yasea.SrsEncodeHandler;
import net.ossrs.yasea.SrsPublisher;
import net.ossrs.yasea.SrsRecordHandler;
 
import java.io.IOException;
import java.net.SocketException;
import java.util.Random;
 
public class MainActivity extends AppCompatActivity implements RtmpHandler.RtmpListener,
SrsRecordHandler.SrsRecordListener, SrsNetworkHandler.SrsNetworkListener {
SrsRecordHandler.SrsRecordListener, SrsEncodeHandler.SrsEncodeListener {
 
private static final String TAG = "Yasea";
 
Loading
Loading
@@ -66,9 +68,9 @@ public class MainActivity extends AppCompatActivity implements RtmpHandler.RtmpL
btnSwitchEncoder = (Button) findViewById(R.id.swEnc);
 
mPublisher = new SrsPublisher((SrsCameraView) findViewById(R.id.glsurfaceview_camera));
mPublisher.setEncodeHandler(new SrsEncodeHandler(this));
mPublisher.setRtmpHandler(new RtmpHandler(this));
mPublisher.setRecordHandler(new SrsRecordHandler(this));
mPublisher.setNetworkHandler(new SrsNetworkHandler(this));
mPublisher.setPreviewResolution(640, 480);
 
btnPublish.setOnClickListener(new View.OnClickListener() {
Loading
Loading
@@ -138,24 +140,6 @@ public class MainActivity extends AppCompatActivity implements RtmpHandler.RtmpL
}
}
});
Thread.setDefaultUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
@Override
public void uncaughtException(Thread thread, Throwable ex) {
final String msg = ex.getMessage();
runOnUiThread(new Runnable() {
@Override
public void run() {
Toast.makeText(getApplicationContext(), msg, Toast.LENGTH_LONG).show();
mPublisher.stopPublish();
mPublisher.stopRecord();
btnPublish.setText("publish");
btnRecord.setText("record");
btnSwitchEncoder.setEnabled(true);
}
});
}
});
}
 
@Override
Loading
Loading
@@ -271,7 +255,7 @@ public class MainActivity extends AppCompatActivity implements RtmpHandler.RtmpL
private static String getRandomAlphaString(int length) {
String base = "abcdefghijklmnopqrstuvwxyz";
Random random = new Random();
StringBuffer sb = new StringBuffer();
StringBuilder sb = new StringBuilder();
for (int i = 0; i < length; i++) {
int number = random.nextInt(base.length());
sb.append(base.charAt(number));
Loading
Loading
@@ -282,7 +266,7 @@ public class MainActivity extends AppCompatActivity implements RtmpHandler.RtmpL
private static String getRandomAlphaDigitString(int length) {
String base = "abcdefghijklmnopqrstuvwxyz0123456789";
Random random = new Random();
StringBuffer sb = new StringBuffer();
StringBuilder sb = new StringBuilder();
for (int i = 0; i < length; i++) {
int number = random.nextInt(base.length());
sb.append(base.charAt(number));
Loading
Loading
@@ -290,6 +274,19 @@ public class MainActivity extends AppCompatActivity implements RtmpHandler.RtmpL
return sb.toString();
}
 
private void handleException(Exception e) {
try {
Toast.makeText(getApplicationContext(), e.getMessage(), Toast.LENGTH_SHORT).show();
mPublisher.stopPublish();
mPublisher.stopRecord();
btnPublish.setText("publish");
btnRecord.setText("record");
btnSwitchEncoder.setEnabled(true);
} catch (Exception e1) {
//
}
}
// Implementation of SrsRtmpListener.
 
@Override
Loading
Loading
@@ -345,6 +342,26 @@ public class MainActivity extends AppCompatActivity implements RtmpHandler.RtmpL
}
}
 
@Override
public void onRtmpSocketException(SocketException e) {
handleException(e);
}
@Override
public void onRtmpIOException(IOException e) {
handleException(e);
}
@Override
public void onRtmpIllegalArgumentException(IllegalArgumentException e) {
handleException(e);
}
@Override
public void onRtmpIllegalStateException(IllegalStateException e) {
handleException(e);
}
// Implementation of SrsRecordHandler.
 
@Override
Loading
Loading
@@ -367,7 +384,17 @@ public class MainActivity extends AppCompatActivity implements RtmpHandler.RtmpL
Toast.makeText(getApplicationContext(), "MP4 file saved: " + msg, Toast.LENGTH_SHORT).show();
}
 
// Implementation of SrsNetworkHandler.
@Override
public void onRecordIOException(IOException e) {
handleException(e);
}
@Override
public void onRecordIllegalArgumentException(IllegalArgumentException e) {
handleException(e);
}
// Implementation of SrsEncodeHandler.
 
@Override
public void onNetworkWeak() {
Loading
Loading
@@ -378,4 +405,9 @@ public class MainActivity extends AppCompatActivity implements RtmpHandler.RtmpL
public void onNetworkResume() {
Toast.makeText(getApplicationContext(), "Network resume", Toast.LENGTH_SHORT).show();
}
@Override
public void onEncodeIllegalArgumentException(IllegalArgumentException e) {
handleException(e);
}
}
Loading
Loading
@@ -19,41 +19,27 @@ public class DefaultRtmpPublisher implements RtmpPublisher {
}
 
@Override
public boolean connect(String url) throws IOException {
public boolean connect(String url) {
return rtmpConnection.connect(url);
}
 
@Override
public void shutdown() {
rtmpConnection.shutdown();
}
@Override
public boolean publish(String publishType) throws IllegalStateException, IOException {
if (publishType == null) {
throw new IllegalStateException("No publish type specified");
}
public boolean publish(String publishType) {
return rtmpConnection.publish(publishType);
}
 
@Override
public void closeStream() throws IllegalStateException {
rtmpConnection.closeStream();
public void close() {
rtmpConnection.close();
}
 
@Override
public void publishVideoData(byte[] data, int dts) throws IllegalStateException {
if (data == null || data.length == 0 || dts < 0) {
throw new IllegalStateException("Invalid Video Data");
}
public void publishVideoData(byte[] data, int dts) {
rtmpConnection.publishVideoData(data, dts);
}
 
@Override
public void publishAudioData(byte[] data, int dts) throws IllegalStateException {
if (data == null || data.length == 0 || dts < 0) {
throw new IllegalStateException("Invalid Audio Data");
}
public void publishAudioData(byte[] data, int dts) {
rtmpConnection.publishAudioData(data, dts);
}
 
Loading
Loading
Loading
Loading
@@ -3,7 +3,9 @@ package com.github.faucamp.simplertmp;
import android.os.Handler;
import android.os.Message;
import java.io.IOException;
import java.lang.ref.WeakReference;
import java.net.SocketException;
/**
* Created by leo.ma on 2016/11/3.
Loading
Loading
@@ -21,6 +23,11 @@ public class RtmpHandler extends Handler {
private static final int MSG_RTMP_VIDEO_BITRATE_CHANGED = 7;
private static final int MSG_RTMP_AUDIO_BITRATE_CHANGED = 8;
private static final int MSG_RTMP_SOCKET_EXCEPTION = 9;
private static final int MSG_RTMP_IO_EXCEPTION = 10;
private static final int MSG_RTMP_ILLEGAL_ARGUMENT_EXCEPTION = 11;
private static final int MSG_RTMP_ILLEGAL_STATE_EXCEPTION = 12;
private WeakReference<RtmpListener> mWeakListener;
public RtmpHandler(RtmpListener listener) {
Loading
Loading
@@ -63,6 +70,22 @@ public class RtmpHandler extends Handler {
obtainMessage(MSG_RTMP_AUDIO_BITRATE_CHANGED, bitrate).sendToTarget();
}
public void notifyRtmpSocketException(SocketException e) {
obtainMessage(MSG_RTMP_SOCKET_EXCEPTION, e).sendToTarget();
}
public void notifyRtmpIOException(IOException e) {
obtainMessage(MSG_RTMP_IO_EXCEPTION, e).sendToTarget();
}
public void notifyRtmpIllegalArgumentException(IllegalArgumentException e) {
obtainMessage(MSG_RTMP_ILLEGAL_ARGUMENT_EXCEPTION, e).sendToTarget();
}
public void notifyRtmpIllegalStateException(IllegalStateException e) {
obtainMessage(MSG_RTMP_ILLEGAL_STATE_EXCEPTION, e).sendToTarget();
}
@Override // runs on UI thread
public void handleMessage(Message msg) {
RtmpListener listener = mWeakListener.get();
Loading
Loading
@@ -98,6 +121,18 @@ public class RtmpHandler extends Handler {
case MSG_RTMP_AUDIO_BITRATE_CHANGED:
listener.onRtmpAudioBitrateChanged((double) msg.obj);
break;
case MSG_RTMP_SOCKET_EXCEPTION:
listener.onRtmpSocketException((SocketException) msg.obj);
break;
case MSG_RTMP_IO_EXCEPTION:
listener.onRtmpIOException((IOException) msg.obj);
break;
case MSG_RTMP_ILLEGAL_ARGUMENT_EXCEPTION:
listener.onRtmpIllegalArgumentException((IllegalArgumentException) msg.obj);
break;
case MSG_RTMP_ILLEGAL_STATE_EXCEPTION:
listener.onRtmpIllegalStateException((IllegalStateException) msg.obj);
break;
default:
throw new RuntimeException("unknown msg " + msg.what);
}
Loading
Loading
@@ -122,5 +157,13 @@ public class RtmpHandler extends Handler {
void onRtmpVideoBitrateChanged(double bitrate);
void onRtmpAudioBitrateChanged(double bitrate);
void onRtmpSocketException(SocketException e);
void onRtmpIOException(IOException e);
void onRtmpIllegalArgumentException(IllegalArgumentException e);
void onRtmpIllegalStateException(IllegalStateException e);
}
}
Loading
Loading
@@ -17,9 +17,8 @@ public interface RtmpPublisher {
*
* @param url specify the RTMP url
* @return If succeeded return true else return false
* @throws IOException if a network/IO error occurs
*/
boolean connect(String url) throws IOException;
boolean connect(String url);
/**
* Issues an RTMP "publish" command and write the media content stream packets (audio and video).
Loading
Loading
@@ -27,19 +26,13 @@ public interface RtmpPublisher {
* @param publishType specify the way to publish raw RTMP packets among "live", "record" and "append"
* @return If succeeded return true else return false
* @throws IllegalStateException if the client is not connected to a RTMP server
* @throws IOException if a network/IO error occurs
*/
boolean publish(String publishType) throws IllegalStateException, IOException;
boolean publish(String publishType);
/**
* Stops and closes the current RTMP stream
* Stop and close the current RTMP streaming client.
*/
void closeStream() throws IllegalStateException;
/**
* Shuts down the RTMP client and stops all threads associated with it
*/
void shutdown();
void close();
 
/**
* publish a video content packet to server
Loading
Loading
@@ -47,7 +40,7 @@ public interface RtmpPublisher {
* @param data video stream byte array
* @param dts video stream decoding timestamp
*/
void publishVideoData(byte[] data, int dts) throws IllegalStateException;
void publishVideoData(byte[] data, int dts);
 
/**
* publish an audio content packet to server
Loading
Loading
@@ -55,7 +48,7 @@ public interface RtmpPublisher {
* @param data audio stream byte array
* @param dts audio stream decoding timestamp
*/
void publishAudioData(byte[] data, int dts) throws IllegalStateException;
void publishAudioData(byte[] data, int dts);
 
/**
* obtain video frame number cached in publisher
Loading
Loading
@@ -80,8 +73,8 @@ public interface RtmpPublisher {
/**
* set video resolution
*
* @param width
* @param height
* @param width video width
* @param height video height
*/
void setVideoResolution(int width, int height);
 
Loading
Loading
Loading
Loading
@@ -98,7 +98,7 @@ public class RtmpConnection implements RtmpPublisher {
}
 
@Override
public boolean connect(String url) throws IOException {
public boolean connect(String url) {
Matcher matcher = rtmpUrlPattern.matcher(url);
if (matcher.matches()) {
tcUrl = url.substring(0, url.lastIndexOf('/'));
Loading
Loading
@@ -110,7 +110,9 @@ public class RtmpConnection implements RtmpPublisher {
appName = matcher.group(4);
streamName = matcher.group(6);
} else {
throw new IllegalArgumentException("Invalid RTMP URL. Must be in format: rtmp://host[:port]/application[/streamName]");
mHandler.notifyRtmpIllegalArgumentException(new IllegalArgumentException(
"Invalid RTMP URL. Must be in format: rtmp://host[:port]/application[/streamName]"));
return false;
}
 
// socket connection
Loading
Loading
@@ -119,12 +121,18 @@ public class RtmpConnection implements RtmpPublisher {
rtmpDecoder = new RtmpDecoder(rtmpSessionInfo);
socket = new Socket();
SocketAddress socketAddress = new InetSocketAddress(host, port);
socket.connect(socketAddress, 3000);
inputStream = new BufferedInputStream(socket.getInputStream());
outputStream = new BufferedOutputStream(socket.getOutputStream());
Log.d(TAG, "connect(): socket connection established, doing handhake...");
handshake(inputStream, outputStream);
Log.d(TAG, "connect(): handshake done");
try {
socket.connect(socketAddress, 3000);
inputStream = new BufferedInputStream(socket.getInputStream());
outputStream = new BufferedOutputStream(socket.getOutputStream());
Log.d(TAG, "connect(): socket connection established, doing handhake...");
handshake(inputStream, outputStream);
Log.d(TAG, "connect(): handshake done");
} catch (IOException e) {
e.printStackTrace();
mHandler.notifyRtmpIOException(e);
return false;
}
 
// Start the "main" handling thread
rxPacketHandler = new Thread(new Runnable() {
Loading
Loading
@@ -144,9 +152,10 @@ public class RtmpConnection implements RtmpPublisher {
return rtmpConnect();
}
 
private boolean rtmpConnect() throws IllegalStateException {
private boolean rtmpConnect() {
if (connected) {
throw new IllegalStateException("Already connected to RTMP server");
mHandler.notifyRtmpIllegalStateException(new IllegalStateException("Already connected to RTMP server"));
return false;
}
 
// Mark session timestamp of all chunk stream information on connection.
Loading
Loading
@@ -186,17 +195,23 @@ public class RtmpConnection implements RtmpPublisher {
}
 
@Override
public boolean publish(String type) throws IllegalStateException, IOException {
public boolean publish(String type) {
if (type == null) {
mHandler.notifyRtmpIllegalArgumentException(new IllegalArgumentException("No publish type specified"));
return false;
}
publishType = type;
return createStream();
}
 
private boolean createStream() {
if (!connected) {
throw new IllegalStateException("Not connected to RTMP server");
mHandler.notifyRtmpIllegalStateException(new IllegalStateException("Not connected to RTMP server"));
return false;
}
if (currentStreamId != 0) {
throw new IllegalStateException("Current stream object has existed");
mHandler.notifyRtmpIllegalStateException(new IllegalStateException("Current stream object has existed"));
return false;
}
 
Log.d(TAG, "createStream(): Sending releaseStream command...");
Loading
Loading
@@ -238,12 +253,14 @@ public class RtmpConnection implements RtmpPublisher {
return publishPermitted;
}
 
private void fmlePublish() throws IllegalStateException {
private void fmlePublish() {
if (!connected) {
throw new IllegalStateException("Not connected to RTMP server");
mHandler.notifyRtmpIllegalStateException(new IllegalStateException("Not connected to RTMP server"));
return;
}
if (currentStreamId == 0) {
throw new IllegalStateException("No current stream object exists");
mHandler.notifyRtmpIllegalStateException(new IllegalStateException("No current stream object exists"));
return;
}
 
Log.d(TAG, "fmlePublish(): Sending publish command...");
Loading
Loading
@@ -257,12 +274,14 @@ public class RtmpConnection implements RtmpPublisher {
sendRtmpPacket(publish);
}
 
private void onMetaData() throws IllegalStateException {
private void onMetaData() {
if (!connected) {
throw new IllegalStateException("Not connected to RTMP server");
mHandler.notifyRtmpIllegalStateException(new IllegalStateException("Not connected to RTMP server"));
return;
}
if (currentStreamId == 0) {
throw new IllegalStateException("No current stream object exists");
mHandler.notifyRtmpIllegalStateException(new IllegalStateException("No current stream object exists"));
return;
}
 
Log.d(TAG, "onMetaData(): Sending empty onMetaData...");
Loading
Loading
@@ -285,15 +304,25 @@ public class RtmpConnection implements RtmpPublisher {
}
 
@Override
public void closeStream() throws IllegalStateException {
public void close() {
if (socket != null) {
closeStream();
}
shutdown();
}
private void closeStream() {
if (!connected) {
throw new IllegalStateException("Not connected to RTMP server");
mHandler.notifyRtmpIllegalStateException(new IllegalStateException("Not connected to RTMP server"));
return;
}
if (currentStreamId == 0) {
throw new IllegalStateException("No current stream object exists");
mHandler.notifyRtmpIllegalStateException(new IllegalStateException("No current stream object exists"));
return;
}
if (!publishPermitted) {
throw new IllegalStateException("Not get _result(Netstream.Publish.Start)");
mHandler.notifyRtmpIllegalStateException(new IllegalStateException("Not get _result(Netstream.Publish.Start)"));
return;
}
Log.d(TAG, "closeStream(): setting current stream ID to 0");
Command closeStream = new Command("closeStream", 0);
Loading
Loading
@@ -304,8 +333,7 @@ public class RtmpConnection implements RtmpPublisher {
mHandler.notifyRtmpStopped();
}
 
@Override
public void shutdown() {
private void shutdown() {
if (socket != null) {
try {
// It will raise EOFException in handleRxPacketThread
Loading
Loading
@@ -357,20 +385,28 @@ public class RtmpConnection implements RtmpPublisher {
serverIpAddr = null;
serverPid = null;
serverId = null;
socket = null;
rtmpSessionInfo = null;
rtmpDecoder = null;
}
 
@Override
public void publishAudioData(byte[] data, int dts) throws IllegalStateException {
public void publishAudioData(byte[] data, int dts) {
if (data == null || data.length == 0 || dts < 0) {
mHandler.notifyRtmpIllegalArgumentException(new IllegalArgumentException("Invalid Audio Data"));
return;
}
if (!connected) {
throw new IllegalStateException("Not connected to RTMP server");
mHandler.notifyRtmpIllegalStateException(new IllegalStateException("Not connected to RTMP server"));
return;
}
if (currentStreamId == 0) {
throw new IllegalStateException("No current stream object exists");
mHandler.notifyRtmpIllegalStateException(new IllegalStateException("No current stream object exists"));
return;
}
if (!publishPermitted) {
throw new IllegalStateException("Not get _result(Netstream.Publish.Start)");
mHandler.notifyRtmpIllegalStateException(new IllegalStateException("Not get _result(Netstream.Publish.Start)"));
return;
}
Audio audio = new Audio();
audio.setData(data);
Loading
Loading
@@ -382,15 +418,22 @@ public class RtmpConnection implements RtmpPublisher {
}
 
@Override
public void publishVideoData(byte[] data, int dts) throws IllegalStateException {
public void publishVideoData(byte[] data, int dts) {
if (data == null || data.length == 0 || dts < 0) {
mHandler.notifyRtmpIllegalArgumentException(new IllegalArgumentException("Invalid Video Data"));
return;
}
if (!connected) {
throw new IllegalStateException("Not connected to RTMP server");
mHandler.notifyRtmpIllegalStateException(new IllegalStateException("Not connected to RTMP server"));
return;
}
if (currentStreamId == 0) {
throw new IllegalStateException("No current stream object exists");
mHandler.notifyRtmpIllegalStateException(new IllegalStateException("No current stream object exists"));
return;
}
if (!publishPermitted) {
throw new IllegalStateException("Not get _result(Netstream.Publish.Start)");
mHandler.notifyRtmpIllegalStateException(new IllegalStateException("Not get _result(Netstream.Publish.Start)"));
return;
}
Video video = new Video();
video.setData(data);
Loading
Loading
@@ -447,14 +490,16 @@ public class RtmpConnection implements RtmpPublisher {
}
outputStream.flush();
} catch (SocketException se) {
// Since there are still remaining AV frame in the cache, we set a flag to guarantee the
// socket exception only issue one time.
if (!socketExceptionCause.contentEquals(se.getMessage())) {
socketExceptionCause = se.getMessage();
Log.e(TAG, "Caught SocketException during write loop, shutting down: " + se.getMessage());
Thread.getDefaultUncaughtExceptionHandler().uncaughtException(Thread.currentThread(), se);
mHandler.notifyRtmpSocketException(se);
}
} catch (IOException ioe) {
Log.e(TAG, "Caught IOException during write loop, shutting down: " + ioe.getMessage());
Thread.getDefaultUncaughtExceptionHandler().uncaughtException(Thread.currentThread(), ioe);
mHandler.notifyRtmpIOException(ioe);
}
}
 
Loading
Loading
@@ -475,7 +520,7 @@ public class RtmpConnection implements RtmpPublisher {
switch (user.getType()) {
case STREAM_BEGIN:
if (currentStreamId != user.getFirstEventData()) {
throw new IllegalStateException("Current stream ID error!");
mHandler.notifyRtmpIllegalStateException(new IllegalStateException("Current stream ID error!"));
}
break;
case PING_REQUEST:
Loading
Loading
@@ -520,10 +565,10 @@ public class RtmpConnection implements RtmpPublisher {
Thread.currentThread().interrupt();
} catch (SocketException se) {
Log.e(TAG, "Caught SocketException while reading/decoding packet, shutting down: " + se.getMessage());
Thread.getDefaultUncaughtExceptionHandler().uncaughtException(Thread.currentThread(), se);
mHandler.notifyRtmpSocketException(se);
} catch (IOException ioe) {
Log.e(TAG, "Caught exception while reading/decoding packet, shutting down: " + ioe.getMessage());
Thread.getDefaultUncaughtExceptionHandler().uncaughtException(Thread.currentThread(), ioe);
mHandler.notifyRtmpIOException(ioe);
}
}
}
Loading
Loading
Loading
Loading
@@ -9,48 +9,57 @@ import java.lang.ref.WeakReference;
* Created by leo.ma on 2016/11/4.
*/
public class SrsNetworkHandler extends Handler {
public class SrsEncodeHandler extends Handler {
private static final int MSG_NETWORK_WEAK = 0;
private static final int MSG_NETWORK_RESUME = 1;
private static final int MSG_ENCODE_NETWORK_WEAK = 0;
private static final int MSG_ENCODE_NETWORK_RESUME = 1;
private static final int MSG_ENCODE_ILLEGAL_ARGUMENT_EXCEPTION = 2;
private WeakReference<SrsNetworkListener> mWeakListener;
private WeakReference<SrsEncodeListener> mWeakListener;
public SrsNetworkHandler(SrsNetworkListener listener) {
public SrsEncodeHandler(SrsEncodeListener listener) {
mWeakListener = new WeakReference<>(listener);
}
public void notifyNetworkWeak() {
sendEmptyMessage(MSG_NETWORK_WEAK);
sendEmptyMessage(MSG_ENCODE_NETWORK_WEAK);
}
public void notifyNetworkResume() {
sendEmptyMessage(MSG_NETWORK_RESUME);
sendEmptyMessage(MSG_ENCODE_NETWORK_RESUME);
}
public void notifyEncodeIllegalArgumentException(IllegalArgumentException e) {
obtainMessage(MSG_ENCODE_ILLEGAL_ARGUMENT_EXCEPTION, e).sendToTarget();
}
@Override // runs on UI thread
public void handleMessage(Message msg) {
SrsNetworkListener listener = mWeakListener.get();
SrsEncodeListener listener = mWeakListener.get();
if (listener == null) {
return;
}
switch (msg.what) {
case MSG_NETWORK_WEAK:
case MSG_ENCODE_NETWORK_WEAK:
listener.onNetworkWeak();
break;
case MSG_NETWORK_RESUME:
case MSG_ENCODE_NETWORK_RESUME:
listener.onNetworkResume();
break;
case MSG_ENCODE_ILLEGAL_ARGUMENT_EXCEPTION:
listener.onEncodeIllegalArgumentException((IllegalArgumentException) msg.obj);
default:
throw new RuntimeException("unknown msg " + msg.what);
}
}
public interface SrsNetworkListener {
public interface SrsEncodeListener {
void onNetworkWeak();
void onNetworkResume();
}
void onEncodeIllegalArgumentException(IllegalArgumentException e);
}
}
Loading
Loading
@@ -38,7 +38,7 @@ public class SrsEncoder {
public static int aChannelConfig = AudioFormat.CHANNEL_IN_STEREO;
public static final int ABITRATE = 32 * 1000; // 32kbps
private int mOrientation = Configuration.ORIENTATION_PORTRAIT;
private SrsEncodeHandler mHandler;
private SrsFlvMuxer flvMuxer;
private SrsMp4Muxer mp4Muxer;
Loading
Loading
@@ -49,7 +49,6 @@ public class SrsEncoder {
private MediaCodec.BufferInfo vebi = new MediaCodec.BufferInfo();
private MediaCodec.BufferInfo aebi = new MediaCodec.BufferInfo();
private SrsNetworkHandler mHandler;
private boolean networkWeakTriggered = false;
private boolean mCameraFaceFront = true;
private boolean useSoftEncoder = false;
Loading
Loading
@@ -74,7 +73,8 @@ public class SrsEncoder {
// NV16 -> YUV422SP yyyy uv uv
// YUY2 -> YUV422SP yuyv yuyv
public SrsEncoder() {
public SrsEncoder(SrsEncodeHandler handler) {
mHandler = handler;
mVideoColorFormat = chooseVideoEncoder();
}
Loading
Loading
@@ -86,10 +86,6 @@ public class SrsEncoder {
this.mp4Muxer = mp4Muxer;
}
public void setNetworkEventHandler(SrsNetworkHandler handler) {
mHandler = handler;
}
public boolean start() {
if (flvMuxer == null || mp4Muxer == null) {
return false;
Loading
Loading
@@ -261,11 +257,10 @@ public class SrsEncoder {
}
public void setScreenOrientation(int orientation) {
mOrientation = orientation;
if (mOrientation == Configuration.ORIENTATION_PORTRAIT) {
if (orientation == Configuration.ORIENTATION_PORTRAIT) {
vOutWidth = vPortraitWidth;
vOutHeight = vPortraitHeight;
} else if (mOrientation == Configuration.ORIENTATION_LANDSCAPE) {
} else if (orientation == Configuration.ORIENTATION_LANDSCAPE) {
vOutWidth = vLandscapeWidth;
vOutHeight = vLandscapeHeight;
}
Loading
Loading
@@ -316,26 +311,16 @@ public class SrsEncoder {
// when got encoded h264 es stream.
private void onEncodedAnnexbFrame(ByteBuffer es, MediaCodec.BufferInfo bi) {
try {
ByteBuffer record = es.duplicate();
mp4Muxer.writeSampleData(videoMp4Track, record, bi);
flvMuxer.writeSampleData(videoFlvTrack, es, bi);
} catch (Exception e) {
Log.e(TAG, "muxer write video sample failed.");
e.printStackTrace();
}
ByteBuffer record = es.duplicate();
mp4Muxer.writeSampleData(videoMp4Track, record, bi);
flvMuxer.writeSampleData(videoFlvTrack, es, bi);
}
// when got encoded aac raw stream.
private void onEncodedAacFrame(ByteBuffer es, MediaCodec.BufferInfo bi) {
try {
ByteBuffer record = es.duplicate();
mp4Muxer.writeSampleData(audioMp4Track, record, bi);
flvMuxer.writeSampleData(audioFlvTrack, es, bi);
} catch (Exception e) {
Log.e(TAG, "muxer write audio sample failed.");
e.printStackTrace();
}
ByteBuffer record = es.duplicate();
mp4Muxer.writeSampleData(audioMp4Track, record, bi);
flvMuxer.writeSampleData(audioFlvTrack, es, bi);
}
public void onGetPcmFrame(byte[] data, int size) {
Loading
Loading
@@ -376,8 +361,7 @@ public class SrsEncoder {
if (processedData != null) {
onProcessedYuvFrame(processedData, pts);
} else {
Thread.getDefaultUncaughtExceptionHandler().uncaughtException(Thread.currentThread(),
new IllegalArgumentException("libyuv failure"));
mHandler.notifyEncodeIllegalArgumentException(new IllegalArgumentException("libyuv failure"));
}
}
Loading
Loading
Loading
Loading
@@ -17,7 +17,6 @@ import java.util.concurrent.atomic.AtomicInteger;
* Created by winlin on 5/2/15.
* Updated by leoma on 4/1/16.
* to POST the h.264/avc annexb frame to SRS over RTMP.
* @remark we must start a worker thread to send data to server.
* @see android.media.MediaMuxer https://developer.android.com/reference/android/media/MediaMuxer.html
*
* Usage:
Loading
Loading
@@ -48,6 +47,7 @@ import java.util.concurrent.atomic.AtomicInteger;
public class SrsFlvMuxer {
private volatile boolean connected = false;
private DefaultRtmpPublisher publisher;
private RtmpHandler mHandler;
 
private Thread worker;
private final Object txFrameLock = new Object();
Loading
Loading
@@ -67,6 +67,7 @@ public class SrsFlvMuxer {
* @param handler the rtmp event handler.
*/
public SrsFlvMuxer(RtmpHandler handler) {
mHandler = handler;
publisher = new DefaultRtmpPublisher(handler);
}
 
Loading
Loading
@@ -105,11 +106,10 @@ public class SrsFlvMuxer {
 
private void disconnect() {
try {
publisher.closeStream();
publisher.close();
} catch (IllegalStateException e) {
// Ignore illegal state.
}
publisher.shutdown();
connected = false;
videoSequenceHeader = null;
audioSequenceHeader = null;
Loading
Loading
@@ -117,23 +117,18 @@ public class SrsFlvMuxer {
}
 
private boolean connect(String url) {
try {
if (!connected) {
Log.i(TAG, String.format("worker: connecting to RTMP server by url=%s\n", url));
if (publisher.connect(url)) {
connected = publisher.publish("live");
}
videoSequenceHeader = null;
audioSequenceHeader = null;
if (!connected) {
Log.i(TAG, String.format("worker: connecting to RTMP server by url=%s\n", url));
if (publisher.connect(url)) {
connected = publisher.publish("live");
}
} catch (IOException ioe) {
ioe.printStackTrace();
Thread.getDefaultUncaughtExceptionHandler().uncaughtException(Thread.currentThread(), ioe);
videoSequenceHeader = null;
audioSequenceHeader = null;
}
return connected;
}
 
private void sendFlvTag(SrsFlvFrame frame) throws IllegalStateException, IOException {
private void sendFlvTag(SrsFlvFrame frame) {
if (!connected || frame == null) {
return;
}
Loading
Loading
@@ -153,8 +148,7 @@ public class SrsFlvMuxer {
/**
* start to the remote SRS for remux.
*/
public void start(final String rtmpUrl) throws IOException {
public void start(final String rtmpUrl) {
worker = new Thread(new Runnable() {
@Override
public void run() {
Loading
Loading
@@ -165,25 +159,20 @@ public class SrsFlvMuxer {
while (!Thread.interrupted()) {
while (!frameCache.isEmpty()) {
SrsFlvFrame frame = frameCache.poll();
try {
if (frame.is_sequenceHeader()) {
if (frame.is_video()) {
videoSequenceHeader = frame;
sendFlvTag(videoSequenceHeader);
} else if (frame.is_audio()) {
audioSequenceHeader = frame;
sendFlvTag(audioSequenceHeader);
}
} else {
if (frame.is_video() && videoSequenceHeader != null) {
sendFlvTag(frame);
} else if (frame.is_audio() && audioSequenceHeader != null) {
sendFlvTag(frame);
}
if (frame.is_sequenceHeader()) {
if (frame.is_video()) {
videoSequenceHeader = frame;
sendFlvTag(videoSequenceHeader);
} else if (frame.is_audio()) {
audioSequenceHeader = frame;
sendFlvTag(audioSequenceHeader);
}
} else {
if (frame.is_video() && videoSequenceHeader != null) {
sendFlvTag(frame);
} else if (frame.is_audio() && audioSequenceHeader != null) {
sendFlvTag(frame);
}
} catch (IOException ioe) {
ioe.printStackTrace();
Thread.getDefaultUncaughtExceptionHandler().uncaughtException(worker, ioe);
}
}
// Waiting for next frame
Loading
Loading
@@ -205,13 +194,6 @@ public class SrsFlvMuxer {
* stop the muxer, disconnect RTMP connection from SRS.
*/
public void stop() {
new Thread(new Runnable() {
@Override
public void run() {
disconnect();
}
}).start();
if (worker != null) {
worker.interrupt();
try {
Loading
Loading
@@ -223,10 +205,16 @@ public class SrsFlvMuxer {
frameCache.clear();
worker = null;
}
flv.reset();
needToFindKeyFrame = true;
Log.i(TAG, "SrsFlvMuxer closed");
new Thread(new Runnable() {
@Override
public void run() {
disconnect();
}
}).start();
}
 
/**
Loading
Loading
@@ -235,7 +223,7 @@ public class SrsFlvMuxer {
* @param byteBuf The encoded sample.
* @param bufferInfo The buffer information related to this sample.
*/
public void writeSampleData(int trackIndex, ByteBuffer byteBuf, MediaCodec.BufferInfo bufferInfo) throws IllegalArgumentException {
public void writeSampleData(int trackIndex, ByteBuffer byteBuf, MediaCodec.BufferInfo bufferInfo) {
if (bufferInfo.offset > 0) {
Log.w(TAG, String.format("encoded frame %dB, offset=%d pts=%dms",
bufferInfo.size, bufferInfo.offset, bufferInfo.presentationTimeUs / 1000
Loading
Loading
@@ -279,7 +267,7 @@ public class SrsFlvMuxer {
// 3 = disposable inter frame (H.263 only)
// 4 = generated key frame (reserved for server use only)
// 5 = video info/command frame
class SrsCodecVideoAVCFrame
private class SrsCodecVideoAVCFrame
{
// set to the zero to reserved, for array map.
public final static int Reserved = 0;
Loading
Loading
@@ -298,7 +286,7 @@ public class SrsFlvMuxer {
// 1 = AVC NALU
// 2 = AVC end of sequence (lower level NALU sequence ender is
// not required or supported)
class SrsCodecVideoAVCType
private class SrsCodecVideoAVCType
{
// set to the max value to reserved, for array map.
public final static int Reserved = 3;
Loading
Loading
@@ -311,7 +299,7 @@ public class SrsFlvMuxer {
/**
* E.4.1 FLV Tag, page 75
*/
class SrsCodecFlvTag
private class SrsCodecFlvTag
{
// set to the zero to reserved, for array map.
public final static int Reserved = 0;
Loading
Loading
@@ -333,7 +321,7 @@ public class SrsFlvMuxer {
// 5 = On2 VP6 with alpha channel
// 6 = Screen video version 2
// 7 = AVC
class SrsCodecVideo
private class SrsCodecVideo
{
// set to the zero to reserved, for array map.
public final static int Reserved = 0;
Loading
Loading
@@ -356,7 +344,7 @@ public class SrsFlvMuxer {
* for AudioSpecificConfig, @see aac-mp4a-format-ISO_IEC_14496-3+2001.pdf, page 33
* for audioObjectType, @see aac-mp4a-format-ISO_IEC_14496-3+2001.pdf, page 23
*/
class SrsAacObjectType
private class SrsAacObjectType
{
public final static int Reserved = 0;
 
Loading
Loading
@@ -376,7 +364,7 @@ public class SrsFlvMuxer {
* the aac profile, for ADTS(HLS/TS)
* @see https://github.com/simple-rtmp-server/srs/issues/310
*/
class SrsAacProfile
private class SrsAacProfile
{
public final static int Reserved = 3;
 
Loading
Loading
@@ -394,7 +382,7 @@ public class SrsFlvMuxer {
* 2 = 22 kHz = 22050 Hz
* 3 = 44 kHz = 44100 Hz
*/
class SrsCodecAudioSampleRate
private class SrsCodecAudioSampleRate
{
// set to the max value to reserved, for array map.
public final static int Reserved = 4;
Loading
Loading
@@ -409,7 +397,7 @@ public class SrsFlvMuxer {
* Table 7-1 NAL unit type codes, syntax element categories, and NAL unit type classes
* H.264-AVC-ISO_IEC_14496-10-2012.pdf, page 83.
*/
class SrsAvcNaluType
private class SrsAvcNaluType
{
// Unspecified
public final static int Reserved = 0;
Loading
Loading
@@ -499,7 +487,7 @@ public class SrsFlvMuxer {
/**
* the search result for annexb.
*/
class SrsAnnexbSearch {
private class SrsAnnexbSearch {
public int nb_start_code = 0;
public boolean match = false;
}
Loading
Loading
@@ -507,7 +495,7 @@ public class SrsFlvMuxer {
/**
* the demuxed tag frame.
*/
class SrsFlvFrameBytes {
private class SrsFlvFrameBytes {
public ByteBuffer data;
public int size;
}
Loading
Loading
@@ -515,7 +503,7 @@ public class SrsFlvMuxer {
/**
* the muxed flv frame.
*/
class SrsFlvFrame {
private class SrsFlvFrame {
// the tag bytes.
public ByteBuffer flvTag;
// the codec type for audio/aac and video/avc for instance.
Loading
Loading
@@ -547,7 +535,7 @@ public class SrsFlvMuxer {
/**
* the raw h.264 stream, in annexb.
*/
class SrsRawH264Stream {
private class SrsRawH264Stream {
private SrsUtils utils;
private final static String TAG = "SrsFlvMuxer";
 
Loading
Loading
@@ -727,7 +715,7 @@ public class SrsFlvMuxer {
return flv_tag;
}
 
public SrsFlvFrameBytes annexb_demux(ByteBuffer bb, MediaCodec.BufferInfo bi) throws IllegalArgumentException {
public SrsFlvFrameBytes annexb_demux(ByteBuffer bb, MediaCodec.BufferInfo bi) {
SrsFlvFrameBytes tbb = new SrsFlvFrameBytes();
 
while (bb.position() < bi.size) {
Loading
Loading
@@ -737,7 +725,8 @@ public class SrsFlvMuxer {
if (!tbbsc.match || tbbsc.nb_start_code < 3) {
Log.e(TAG, "annexb not match.");
SrsFlvMuxer.srs_print_bytes(TAG, bb, 16);
throw new IllegalArgumentException(String.format("annexb not match for %dB, pos=%d", bi.size, bb.position()));
mHandler.notifyRtmpIllegalArgumentException(new IllegalArgumentException(
String.format("annexb not match for %dB, pos=%d", bi.size, bb.position())));
}
 
// the start codes.
Loading
Loading
@@ -765,7 +754,7 @@ public class SrsFlvMuxer {
}
}
 
class SrsRawAacStreamCodec {
private class SrsRawAacStreamCodec {
public byte protection_absent;
// SrsAacObjectType
public int aac_object;
Loading
Loading
@@ -786,7 +775,7 @@ public class SrsFlvMuxer {
/**
* remux the annexb to flv tags.
*/
class SrsFlv {
private class SrsFlv {
private MediaFormat videoTrack;
private MediaFormat audioTrack;
private int achannel;
Loading
Loading
@@ -941,7 +930,7 @@ public class SrsFlvMuxer {
frame[offset + 6] |= 0x0;
}
 
public void writeVideoSample(final ByteBuffer bb, MediaCodec.BufferInfo bi) throws IllegalArgumentException {
public void writeVideoSample(final ByteBuffer bb, MediaCodec.BufferInfo bi) {
int pts = (int)(bi.presentationTimeUs / 1000);
int dts = (int)pts;
 
Loading
Loading
Loading
Loading
@@ -112,7 +112,7 @@ public class SrsMp4Muxer {
/**
* start recording.
*/
public void record(File outputFile) throws IOException {
public void record(File outputFile) {
mRecFile = outputFile;
createMovie(mRecFile);
mHandler.notifyRecordStarted(mRecFile.getPath());
Loading
Loading
@@ -130,11 +130,7 @@ public class SrsMp4Muxer {
// Keep at least one audio and video frame in cache to ensure monotonically increasing.
while (!frameCache.isEmpty()) {
SrsEsFrame frame = frameCache.poll();
try {
writeSampleData(frame.bb, frame.bi, frame.is_audio());
} catch (IOException e) {
e.printStackTrace();
}
writeSampleData(frame.bb, frame.bi, frame.is_audio());
}
// Waiting for next frame
synchronized (writeLock) {
Loading
Loading
@@ -191,14 +187,10 @@ public class SrsMp4Muxer {
}
worker = null;
try {
finishMovie();
} catch (IOException e) {
e.printStackTrace();
}
finishMovie();
mHandler.notifyRecordFinished(mRecFile.getPath());
}
Log.i(TAG, String.format("SrsMp4Muxer closed"));
Log.i(TAG, "SrsMp4Muxer closed");
}
/**
Loading
Loading
@@ -224,7 +216,7 @@ public class SrsMp4Muxer {
* @param byteBuf The encoded sample.
* @param bufferInfo The buffer information related to this sample.
*/
public void writeSampleData(int trackIndex, ByteBuffer byteBuf, MediaCodec.BufferInfo bufferInfo) throws IllegalArgumentException {
public void writeSampleData(int trackIndex, ByteBuffer byteBuf, MediaCodec.BufferInfo bufferInfo) {
if (VIDEO_TRACK == trackIndex) {
writeVideoSample(byteBuf, bufferInfo);
} else {
Loading
Loading
@@ -236,7 +228,7 @@ public class SrsMp4Muxer {
* Table 7-1 NAL unit type codes, syntax element categories, and NAL unit type classes
* H.264-AVC-ISO_IEC_14496-10-2012.pdf, page 83.
*/
class SrsAvcNaluType
private class SrsAvcNaluType
{
// Unspecified
public final static int Reserved = 0;
Loading
Loading
@@ -277,7 +269,7 @@ public class SrsMp4Muxer {
public final static int CodedSliceExt = 20;
}
private void writeVideoSample(final ByteBuffer bb, MediaCodec.BufferInfo bi) throws IllegalArgumentException {
private void writeVideoSample(final ByteBuffer bb, MediaCodec.BufferInfo bi) {
int nal_unit_type = bb.get(4) & 0x1f;
if (nal_unit_type == SrsAvcNaluType.IDR || nal_unit_type == SrsAvcNaluType.NonIDR) {
writeFrameByte(VIDEO_TRACK, bb, bi, nal_unit_type == SrsAvcNaluType.IDR);
Loading
Loading
@@ -346,7 +338,7 @@ public class SrsMp4Muxer {
/**
* the search result for annexb.
*/
class SrsAnnexbSearch {
private class SrsAnnexbSearch {
public int nb_start_code = 0;
public boolean match = false;
}
Loading
Loading
@@ -354,7 +346,7 @@ public class SrsMp4Muxer {
/**
* the demuxed tag frame.
*/
class SrsEsFrameBytes {
private class SrsEsFrameBytes {
public ByteBuffer data;
public int size;
}
Loading
Loading
@@ -362,7 +354,7 @@ public class SrsMp4Muxer {
/**
* the AV frame.
*/
class SrsEsFrame {
private class SrsEsFrame {
public ByteBuffer bb;
public MediaCodec.BufferInfo bi;
public int track;
Loading
Loading
@@ -380,7 +372,7 @@ public class SrsMp4Muxer {
/**
* the raw h.264 stream, in annexb.
*/
class SrsRawH264Stream {
private class SrsRawH264Stream {
public boolean is_sps(SrsEsFrameBytes frame) {
if (frame.size < 1) {
return false;
Loading
Loading
@@ -420,7 +412,7 @@ public class SrsMp4Muxer {
return as;
}
public SrsEsFrameBytes annexb_demux(ByteBuffer bb, MediaCodec.BufferInfo bi) throws IllegalArgumentException {
public SrsEsFrameBytes annexb_demux(ByteBuffer bb, MediaCodec.BufferInfo bi) {
SrsEsFrameBytes tbb = new SrsEsFrameBytes();
while (bb.position() < bi.size) {
Loading
Loading
@@ -429,7 +421,8 @@ public class SrsMp4Muxer {
SrsAnnexbSearch tbbsc = srs_avc_startswith_annexb(bb, bi);
if (!tbbsc.match || tbbsc.nb_start_code < 3) {
Log.e(TAG, "annexb not match.");
throw new IllegalArgumentException(String.format("annexb not match for %dB, pos=%d", bi.size, bb.position()));
mHandler.notifyRecordIllegalArgumentException(new IllegalArgumentException(
String.format("annexb not match for %dB, pos=%d", bi.size, bb.position())));
}
// the start codes.
Loading
Loading
@@ -457,7 +450,7 @@ public class SrsMp4Muxer {
}
}
class Sample {
private class Sample {
private long offset = 0;
private long size = 0;
Loading
Loading
@@ -475,7 +468,7 @@ public class SrsMp4Muxer {
}
}
class Track {
private class Track {
private int trackId = 0;
private ArrayList<Sample> samples = new ArrayList<>();
private long duration = 0;
Loading
Loading
@@ -669,7 +662,7 @@ public class SrsMp4Muxer {
}
}
class Mp4Movie {
private class Mp4Movie {
private Matrix matrix = Matrix.ROTATE_0;
private HashMap<Integer, Track> tracks = new HashMap<>();
Loading
Loading
@@ -699,7 +692,7 @@ public class SrsMp4Muxer {
}
}
class InterleaveChunkMdat implements Box {
private class InterleaveChunkMdat implements Box {
private boolean first = true;
private ContainerBox parent;
private ByteBuffer header = ByteBuffer.allocateDirect(16);
Loading
Loading
@@ -737,7 +730,7 @@ public class SrsMp4Muxer {
return (contentSize + header.limit()) < 4294967296L;
}
public void getBox(WritableByteChannel writableByteChannel) throws IOException {
public void getBox(WritableByteChannel writableByteChannel) {
header.rewind();
long size = getSize();
if (isSmallBox(size)) {
Loading
Loading
@@ -752,7 +745,12 @@ public class SrsMp4Muxer {
IsoTypeWriter.writeUInt64(header, size);
}
header.rewind();
writableByteChannel.write(header);
try {
writableByteChannel.write(header);
} catch (IOException e) {
mHandler.notifyRecordIOException(e);
}
}
@Override
Loading
Loading
@@ -768,86 +766,100 @@ public class SrsMp4Muxer {
private volatile long flushBytes = 0;
private HashMap<Track, long[]> track2SampleSizes = new HashMap<>();
private void createMovie(File outputFile) throws IOException {
fos = new FileOutputStream(outputFile);
fc = fos.getChannel();
mdat = new InterleaveChunkMdat();
mdatOffset = 0;
private void createMovie(File outputFile) {
try {
fos = new FileOutputStream(outputFile);
fc = fos.getChannel();
mdat = new InterleaveChunkMdat();
mdatOffset = 0;
FileTypeBox fileTypeBox = createFileTypeBox();
fileTypeBox.getBox(fc);
recFileSize += fileTypeBox.getSize();
FileTypeBox fileTypeBox = createFileTypeBox();
fileTypeBox.getBox(fc);
recFileSize += fileTypeBox.getSize();
} catch (IOException e) {
e.printStackTrace();
mHandler.notifyRecordIOException(e);
}
}
private void writeSampleData(ByteBuffer byteBuf, MediaCodec.BufferInfo bi, boolean isAudio) throws IOException {
private void writeSampleData(ByteBuffer byteBuf, MediaCodec.BufferInfo bi, boolean isAudio) {
int trackIndex = isAudio ? AUDIO_TRACK : VIDEO_TRACK;
if (!mp4Movie.getTracks().containsKey(trackIndex)) {
return;
}
if (mdat.first) {
mdat.setContentSize(0);
mdat.getBox(fc);
mdatOffset = recFileSize;
recFileSize += mdat.getHeaderSize();
mdat.first = false;
}
try {
if (mdat.first) {
mdat.setContentSize(0);
mdat.getBox(fc);
mdatOffset = recFileSize;
recFileSize += mdat.getHeaderSize();
mdat.first = false;
}
mp4Movie.addSample(trackIndex, recFileSize, bi);
byteBuf.position(bi.offset + (isAudio ? 0 : 4));
byteBuf.limit(bi.offset + bi.size);
if (!isAudio) {
ByteBuffer size = ByteBuffer.allocateDirect(4);
size.position(0);
size.putInt(bi.size - 4);
size.position(0);
recFileSize += fc.write(size);
}
int writeBytes = fc.write(byteBuf);
mp4Movie.addSample(trackIndex, recFileSize, bi);
byteBuf.position(bi.offset + (isAudio ? 0 : 4));
byteBuf.limit(bi.offset + bi.size);
if (!isAudio) {
ByteBuffer size = ByteBuffer.allocateDirect(4);
size.position(0);
size.putInt(bi.size - 4);
size.position(0);
recFileSize += fc.write(size);
}
int writeBytes = fc.write(byteBuf);
recFileSize += writeBytes;
flushBytes += writeBytes;
if (flushBytes > 64 * 1024) {
fos.flush();
flushBytes = 0;
recFileSize += writeBytes;
flushBytes += writeBytes;
if (flushBytes > 64 * 1024) {
fos.flush();
flushBytes = 0;
}
} catch (IOException e) {
e.printStackTrace();
mHandler.notifyRecordIOException(e);
}
}
private void finishMovie() throws IOException {
if (flushBytes > 0) {
fos.flush();
flushBytes = 0;
}
if (mdat.getSize() != 0) {
// flush cached mdat box
long oldPosition = fc.position();
fc.position(mdatOffset);
mdat.setContentSize(recFileSize - mdat.getHeaderSize() - mdatOffset);
mdat.getBox(fc);
fc.position(oldPosition);
mdat.setContentSize(0);
fos.flush();
}
private void finishMovie() {
try {
if (flushBytes > 0) {
fos.flush();
flushBytes = 0;
}
if (mdat.getSize() != 0) {
// flush cached mdat box
long oldPosition = fc.position();
fc.position(mdatOffset);
mdat.setContentSize(recFileSize - mdat.getHeaderSize() - mdatOffset);
mdat.getBox(fc);
fc.position(oldPosition);
mdat.setContentSize(0);
fos.flush();
}
for (Track track : mp4Movie.getTracks().values()) {
List<Sample> samples = track.getSamples();
long[] sizes = new long[samples.size()];
for (int i = 0; i < sizes.length; i++) {
sizes[i] = samples.get(i).getSize();
for (Track track : mp4Movie.getTracks().values()) {
List<Sample> samples = track.getSamples();
long[] sizes = new long[samples.size()];
for (int i = 0; i < sizes.length; i++) {
sizes[i] = samples.get(i).getSize();
}
track2SampleSizes.put(track, sizes);
}
track2SampleSizes.put(track, sizes);
}
Box moov = createMovieBox(mp4Movie);
moov.getBox(fc);
fos.flush();
Box moov = createMovieBox(mp4Movie);
moov.getBox(fc);
fos.flush();
fc.close();
fos.close();
mp4Movie.getTracks().clear();
track2SampleSizes.clear();
recFileSize = 0;
flushBytes = 0;
fc.close();
fos.close();
mp4Movie.getTracks().clear();
track2SampleSizes.clear();
recFileSize = 0;
flushBytes = 0;
} catch (IOException e) {
mHandler.notifyRecordIOException(e);
}
}
private FileTypeBox createFileTypeBox() {
Loading
Loading
Loading
Loading
@@ -28,7 +28,7 @@ public class SrsPublisher {
private SrsFlvMuxer mFlvMuxer;
private SrsMp4Muxer mMp4Muxer;
private SrsEncoder mEncoder = new SrsEncoder();
private SrsEncoder mEncoder;
public SrsPublisher(SrsCameraView view) {
mCameraView = view;
Loading
Loading
@@ -91,14 +91,8 @@ public class SrsPublisher {
public void startPublish(String rtmpUrl) {
if (mFlvMuxer != null) {
try {
mFlvMuxer.start(rtmpUrl);
} catch (IOException e) {
e.printStackTrace();
return;
}
mFlvMuxer.start(rtmpUrl);
mFlvMuxer.setVideoResolution(mEncoder.getOutputWidth(), mEncoder.getOutputHeight());
startEncode();
}
}
Loading
Loading
@@ -112,11 +106,7 @@ public class SrsPublisher {
public void startRecord(String recPath) {
if (mMp4Muxer != null) {
try {
mMp4Muxer.record(new File(recPath));
} catch (IOException e) {
e.printStackTrace();
}
mMp4Muxer.record(new File(recPath));
}
}
Loading
Loading
@@ -198,7 +188,7 @@ public class SrsPublisher {
public void setSendAudioOnly(boolean flag) {
sendAudioOnly = flag;
}
public boolean switchCameraFilter(MagicFilterType type) {
return mCameraView.setFilter(type);
}
Loading
Loading
@@ -236,7 +226,6 @@ public class SrsPublisher {
try {
aworker.join();
} catch (InterruptedException e) {
e.printStackTrace();
aworker.interrupt();
}
aworker = null;
Loading
Loading
@@ -261,15 +250,25 @@ public class SrsPublisher {
public void setRtmpHandler(RtmpHandler handler) {
mFlvMuxer = new SrsFlvMuxer(handler);
mEncoder.setFlvMuxer(mFlvMuxer);
if (mEncoder != null) {
mEncoder.setFlvMuxer(mFlvMuxer);
}
}
public void setRecordHandler(SrsRecordHandler handler) {
mMp4Muxer = new SrsMp4Muxer(handler);
mEncoder.setMp4Muxer(mMp4Muxer);
if (mEncoder != null) {
mEncoder.setMp4Muxer(mMp4Muxer);
}
}
public void setNetworkHandler(SrsNetworkHandler handler) {
mEncoder.setNetworkEventHandler(handler);
public void setEncodeHandler(SrsEncodeHandler handler) {
mEncoder = new SrsEncoder(handler);
if (mFlvMuxer != null) {
mEncoder.setFlvMuxer(mFlvMuxer);
}
if (mMp4Muxer != null) {
mEncoder.setMp4Muxer(mMp4Muxer);
}
}
}
Loading
Loading
@@ -3,6 +3,7 @@ package net.ossrs.yasea;
import android.os.Handler;
import android.os.Message;
import java.io.IOException;
import java.lang.ref.WeakReference;
/**
Loading
Loading
@@ -16,6 +17,9 @@ public class SrsRecordHandler extends Handler {
private static final int MSG_RECORD_STARTED = 2;
private static final int MSG_RECORD_FINISHED = 3;
private static final int MSG_RECORD_ILLEGEL_ARGUMENT_EXCEPTION = 4;
private static final int MSG_RECORD_IO_EXCEPTION = 5;
private WeakReference<SrsRecordListener> mWeakListener;
public SrsRecordHandler(SrsRecordListener listener) {
Loading
Loading
@@ -38,6 +42,14 @@ public class SrsRecordHandler extends Handler {
obtainMessage(MSG_RECORD_FINISHED, msg).sendToTarget();
}
public void notifyRecordIllegalArgumentException(IllegalArgumentException e) {
obtainMessage(MSG_RECORD_ILLEGEL_ARGUMENT_EXCEPTION, e).sendToTarget();
}
public void notifyRecordIOException(IOException e) {
obtainMessage(MSG_RECORD_IO_EXCEPTION, e).sendToTarget();
}
@Override // runs on UI thread
public void handleMessage(Message msg) {
SrsRecordListener listener = mWeakListener.get();
Loading
Loading
@@ -58,6 +70,12 @@ public class SrsRecordHandler extends Handler {
case MSG_RECORD_FINISHED:
listener.onRecordFinished((String) msg.obj);
break;
case MSG_RECORD_ILLEGEL_ARGUMENT_EXCEPTION:
listener.onRecordIllegalArgumentException((IllegalArgumentException) msg.obj);
break;
case MSG_RECORD_IO_EXCEPTION:
listener.onRecordIOException((IOException) msg.obj);
break;
default:
throw new RuntimeException("unknown msg " + msg.what);
}
Loading
Loading
@@ -72,5 +90,9 @@ public class SrsRecordHandler extends Handler {
void onRecordStarted(String msg);
void onRecordFinished(String msg);
void onRecordIllegalArgumentException(IllegalArgumentException e);
void onRecordIOException(IOException e);
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment