<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
+ <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_SUPERUSER" />
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
private static Logger gLogger = Logger.getLogger("FfmpegHelper");
// callback from native
- public static void javaPrint(String string){
- gLogger.error(string);
+ public static void javaPrint(String string, int level){
+ if(level == 1)
+ gLogger.error(string);
+ else
+ gLogger.info(string);
}
// native methods
- public static native int initialEncoder(int width, int height, String url);
+ public static native int initEncoder(int width, int height, String url);
public static native int processFrame(byte[] frame);
public static native int close();
}
import ai.suanzi.rtmpclient.MyService.LocalBinder;
import android.os.IBinder;
+import android.net.ConnectivityManager;
//"rtmp://gpussh.suanzi.ai:1935/myapp/suanzi_ac83f34ead90_cameraid";
private String mMacAddr = "";
//private CameraView mCameraView;
private String mRtmpUrl;
+ private NetworkMonitor networkMonitor;
boolean mBounded;
MyService mServer;
mSufaceView = findViewById(R.id.surfaceView);
mHolder = mSufaceView.getHolder();
mHolder.addCallback(this);
-
-
//intent.setPackage(this.getPackageName()); // init service
//intent.setAction("ai.suanzi.rtmpclient.service");
}
if(mServer.setRtmpUrl(UserInfo.getConfig().toUrl())){
mServer.startPreview(mHolder);
}
-
}
};
+ private void doBindService(){
+ if(!mBounded) {
+ gLogger.debug("doBindService");
+ bindService(mIntent, mConnection, BIND_AUTO_CREATE);
+ }
+ }
+
+ private void doUnbindService() {
+ if(mBounded){
+ gLogger.debug("doUnbindService");
+ unbindService(mConnection);
+ mBounded = false;
+ }
+ }
+
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//startService(intent);
mIntent = new Intent(this, MyService.class);
- bindService(mIntent, mConnection, BIND_AUTO_CREATE);
-
+ if(NetworkMonitor.isNetworkAvailable(this)){
+ gLogger.error("Current network is available");
+ doBindService();
+ } else {
+ gLogger.error("Current network is NOT available");
+ }
mBtnStart.setText("start");
mBtnStart.setOnClickListener(new View.OnClickListener(){
public void onClick(View view){
gLogger.error("----------> onClick");
saveConfig();
- unbindService(mConnection);
- bindService(mIntent, mConnection, BIND_AUTO_CREATE);
+ doUnbindService();
+
}
});
+
+ if ( networkMonitor == null) {
+ networkMonitor = new NetworkMonitor(new NetworkMonitor.NetworkListener() {
+ @Override
+ public void onWifiConnected() {
+ gLogger.error("onWifiConnected");
+ doBindService();
+ }
+
+ @Override
+ public void onWifiDisconnected() {
+ gLogger.error("onWifiDisconnected");
+ doUnbindService();
+ }
+
+ @Override
+ public void onWifiEnabled() {
+ gLogger.error("onWifiEnabled");
+ }
+
+ @Override
+ public void onWifiDisabled() {
+ gLogger.error("onWifiDisabled");
+ }
+ });
+ }
+ IntentFilter filter = new IntentFilter();
+ filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
+ registerReceiver(networkMonitor, filter);
}
@Override
@Override
protected void onDestroy(){
super.onDestroy();
+ unregisterReceiver(networkMonitor);
gLogger.debug("onDestroy --------->");
}
gLogger.debug("onRestart ---------->");
}
-
-
-
// SurfaceHolder.Callback implementation
@Override
public void surfaceCreated(final SurfaceHolder holder){
i.addCategory(Intent.CATEGORY_HOME);
this.startActivity(i);
}
-
-//
-// // class StreamTask AsyncTask
-// private class StreamTask extends AsyncTask<Void, Void, Void>{
-// private byte[] data;
-//
-// StreamTask(byte[] data){
-// this.data = data;
-// }
-//
-// @Override
-// protected Void doInBackground(Void... params) {
-//
-// if (this.data != null){
-// Log.e(TAG, "fps: " + mCamera.getParameters().getPreviewFrameRate());
-// ffmpeg.process(this.data);
-// }
-// return null;
-// }
-// }
-
- /*if (null != mStreamTask){
- switch (mStreamTask.getStatus()){
- case RUNNING:
- Log.e(TAG, "onPreviewFrame Running");
- return;
- case PENDING:
- Log.e(TAG,"OnPreviewFrame Pending");
- mStreamTask.cancel(false);
- break;
- }
- }
- mStreamTask = new StreamTask(data);
- mStreamTask.execute((Void)null);
-*/
-
-// ong endTime = System.currentTimeMillis();
-// mExecutor.execute(new Runnable() {
-// @Override
-// public void run() {
-// //long encodeTime = System.currentTimeMillis();
-// ffmpeg.process(data);
- //Log.e(TAG, "编码第:" + (encodeCount++) + "帧,耗时:" + (System.currentTimeMillis() - encodeTime));
-// }
-// });
- //Log.e(TAG, "采集第:" + (++count) + "帧,距上一帧间隔时间:"
-// + (endTime - previewTime) + " " + Thread.currentThread().getName());
-// previewTime = endTime;*/
-
-
-
}
private static String TAG = "MyService";
//private Ffmpeg ffmpeg = Ffmpeg.getInstance();
- private FfmpegHelper helper;
private Boolean isRunning = false;
private Camera mCamera = null;
IBinder mBinder = new LocalBinder();
mCamera.stopPreview();
mCamera.release();
}
+ FfmpegHelper.close();
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
gLogger.error("onStartCommand");
- //nrunnable = new FfmpegRunnable("xxx", this);
- //new Thread(runnable).start();
return START_STICKY;
}
gLogger.error("onPreviewFrame");
}
frameCount++;
- //ffmpeg.process(data);
+ if(FfmpegHelper.processFrame(data) != 0){
+ gLogger.error("FfmpegHelper.processFrame error. close");
+ FfmpegHelper.close();
+ }
}
public void startPreview (SurfaceHolder holder){
int width = param.getPictureSize().width;
int height = param.getPictureSize().height;
gLogger.error("setRtmpUrl - size: " + width + "x" + height + ". url: " + url);
- //int ret = ffmpeg.initnew(width, height, url);
- int ret = FfmpegHelper.initialEncoder(width, height, url);
+ int ret = FfmpegHelper.initEncoder(width, height, url);
return ret == 0 ? true : false;
}
--- /dev/null
+package ai.suanzi.rtmpclient;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.net.NetworkInfo;
+import android.net.wifi.WifiInfo;
+import android.net.wifi.WifiManager;
+import android.util.Log;
+import org.apache.log4j.Logger;
+import android.net.ConnectivityManager;
+import android.widget.Toast;
+
+import java.lang.ref.WeakReference;
+
+public class NetworkMonitor extends BroadcastReceiver {
+
+ private Logger gLogger = Logger.getLogger("NetworkMonitor");
+ private NetworkListener mListener;
+
+ public NetworkMonitor(NetworkListener listener) {
+ mListener = listener;
+ }
+
+ @Override
+ public void onReceive (Context context, Intent intent) {
+
+ //获得ConnectivityManager对象
+ ConnectivityManager connMgr = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
+
+ NetworkInfo wifiNetworkInfo = connMgr.getNetworkInfo(ConnectivityManager.TYPE_WIFI);
+
+ //NetworkInfo dataNetworkInfo = connMgr.getNetworkInfo(ConnectivityManager.TYPE_MOBILE);
+ if(wifiNetworkInfo.isConnected()){
+ Toast.makeText(context, "Wifi Connected", Toast.LENGTH_SHORT).show();
+ gLogger.error("Wifi Connected");
+ mListener.onWifiConnected();
+ } else {
+ Toast.makeText(context, "Wifi Disconnected", Toast.LENGTH_SHORT).show();
+ gLogger.error("Wifi Disconnected");
+ mListener.onWifiDisconnected();
+ }
+ }
+
+ public static boolean isNetworkAvailable(Context context){
+ ConnectivityManager connectivity = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
+ if (connectivity != null) {
+ NetworkInfo info = connectivity.getActiveNetworkInfo();
+ if (info != null && info.isConnected()) {
+ if (info.getState() == NetworkInfo.State.CONNECTED) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ public interface NetworkListener {
+ void onWifiConnected();
+ void onWifiDisconnected();
+ void onWifiEnabled();
+ void onWifiDisabled();
+ }
+}
--- /dev/null
+package ai.suanzi.rtmpclient;
+
+public class UsbMonitor {
+}
--- /dev/null
+package ai.suanzi.rtmpclient;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.net.NetworkInfo;
+import android.net.wifi.WifiManager;
+
+import org.apache.log4j.Logger;
+import android.net.wifi.WifiInfo;
+import android.util.Log;
+
+public class WifiReceiver extends BroadcastReceiver {
+
+ private Logger gLogger = Logger.getLogger("WifiReceiver");
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ if(intent.getAction().equals(WifiManager.RSSI_CHANGED_ACTION)) {
+ gLogger.error("Wifi rssi changed");
+ }
+
+ if(intent.getAction().equals(WifiManager.NETWORK_STATE_CHANGED_ACTION)){
+ NetworkInfo info = intent.getParcelableExtra(WifiManager.EXTRA_NETWORK_INFO);
+ if(info.getState().equals(NetworkInfo.State.DISCONNECTED)){
+ Log.e("WIFI", "wowowo");
+ gLogger.error("Wifi Disconnected");
+ } else if (info.getState().equals(NetworkInfo.State.CONNECTED)){
+ gLogger.error("Wifi Connected");
+ WifiManager wifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
+ WifiInfo wifiInfo = wifiManager.getConnectionInfo();
+ //获取当前wifi名称
+ gLogger.error("连接到网络 " + wifiInfo.getSSID());
+ //TtsManager ttsManager = new TtsManager();
+ //ttsManager.checkTtsJet(context.getApplicationContext());
+
+ }
+ }
+ if(intent.getAction().equals(WifiManager.WIFI_STATE_CHANGED_ACTION)) {
+ int wifiState = intent.getIntExtra(WifiManager.EXTRA_WIFI_STATE, WifiManager.WIFI_STATE_DISABLED);
+ if(wifiState == WifiManager.WIFI_STATE_DISABLED){
+ gLogger.error("Wifi Disabled");
+ } else if (wifiState == WifiManager.WIFI_STATE_ENABLED) {
+ gLogger.error("Wifi Enabled");
+ }
+ }
+ }
+}
+++ /dev/null
-let l:bm_file_version = 1
-let l:bm_sessions = {'default': {'/Users/peng/project/yunzhi/RtmpClient/app/src/main/jni/FfmpegHelper.cpp': [{'sign_idx': 9500, 'line_nr': 109, 'content': ' //pCodecCtx->me_range = 16;'},],}}
-let l:bm_current_session = 'default'
-APP_ABI := armeabi-v7a x86
+APP_ABI := armeabi-v7a
APP_STL := c++_shared
\ No newline at end of file
#include <string>
#define FLOGE(...) av_log(NULL, AV_LOG_ERROR, __VA_ARGS__)
-#define FLOGD(...) av_log(NULL, AV_LOG_DEBUG, __VA_ARGS__)
+#define FLOGD(...) av_log(NULL, AV_LOG_INFO, __VA_ARGS__)
FfmpegHelper* FfmpegHelper::singleton = NULL;
bool FfmpegHelper::isInit = false;
av_log_format_line(ptr, level, fmt, vl, line, sizeof(line), &print_prefix);
if (level <= AV_LOG_WARNING){
- if (singleton) singleton->javaPrint(line);
+ if (singleton) singleton->javaPrint(line, 1);
+ } else if(level <= AV_LOG_INFO){
+ if (singleton) singleton->javaPrint(line, 0);
+ // LOGE("%s", line);
} else {
- if (singleton) singleton->javaPrint(line);
- //LOGE("%s", line);
+
}
}
-void FfmpegHelper::javaPrint(const char* str)
+void FfmpegHelper::javaPrint(const char* str, int level)
{
JNIEnv* env = 0;
if(this->jvm->GetEnv(reinterpret_cast<void **>(&env), JNI_VERSION_1_6) != JNI_OK){
return;
}
- jmethodID mid = env->GetStaticMethodID(ai_suanzi_rtmpclient_FfmpegHelper, "javaPrint", "(Ljava/lang/String;)V");
+ jmethodID mid = env->GetStaticMethodID(ai_suanzi_rtmpclient_FfmpegHelper, "javaPrint", "(Ljava/lang/String;I)V");
jstring jstr = env->NewStringUTF(str);
- env->CallStaticVoidMethod(ai_suanzi_rtmpclient_FfmpegHelper, mid, jstr);
+ env->CallStaticVoidMethod(ai_suanzi_rtmpclient_FfmpegHelper, mid, jstr, level);
env->DeleteLocalRef(jstr);
}
{
av_log_set_callback(av_log_cb);
av_log_set_level(AV_LOG_DEBUG);
- FLOGE("########## Ffmpeg Init ##########");
+ FLOGD("########## Ffmpeg Init ##########");
unsigned int v = avutil_version();
- FLOGE("libavutil - %d.%d.%d", AV_VERSION_MAJOR(v), AV_VERSION_MINOR(v), AV_VERSION_MICRO(v));
+ FLOGD("libavutil - %d.%d.%d", AV_VERSION_MAJOR(v), AV_VERSION_MINOR(v), AV_VERSION_MICRO(v));
v = avcodec_version();
- FLOGE("libavcodec - %d.%d.%d", AV_VERSION_MAJOR(v), AV_VERSION_MINOR(v), AV_VERSION_MICRO(v));
+ FLOGD("libavcodec - %d.%d.%d", AV_VERSION_MAJOR(v), AV_VERSION_MINOR(v), AV_VERSION_MICRO(v));
v = avformat_version();
- FLOGE("libavformat - %d.%d.%d", AV_VERSION_MAJOR(v), AV_VERSION_MINOR(v), AV_VERSION_MICRO(v));
+ FLOGD("libavformat - %d.%d.%d", AV_VERSION_MAJOR(v), AV_VERSION_MINOR(v), AV_VERSION_MICRO(v));
v = avdevice_version();
- FLOGE("libavdevice - %d.%d.%d", AV_VERSION_MAJOR(v), AV_VERSION_MINOR(v), AV_VERSION_MICRO(v));
+ FLOGD("libavdevice - %d.%d.%d", AV_VERSION_MAJOR(v), AV_VERSION_MINOR(v), AV_VERSION_MICRO(v));
av_register_all();
//avdevice_register_all();
int FfmpegHelper::initEncoder(int width, int height, const char* outpath)
{
if(!isInit) init();
- FLOGE("initEncoder - width=%d, height=%d, url=%s", width, height, outpath);
+ FLOGE("-----------> FfmpegHelper::initEncoder");
+ FLOGD("initEncoder - width=%d, height=%d, url=%s", width, height, outpath);
pWidth = width;
pHeight = height;
}
//Add a new stream to output,should be called by the user before avformat_write_header() for muxing
- AVStream* vStream;
if ((vStream = avformat_new_stream(formatCtx, codec)) == NULL){
FLOGE("avformat_new_stream - error");
return -1;
return -1;
}
startTime = av_gettime();
+ frameCnt = 0;
return 0;
}
+
int FfmpegHelper::processFrame(uint8_t* data)
{
int ret = 0;
- AVFrame *pFrame, *pFrameYUV;
- pFrameYUV = av_frame_alloc();
int y_length = pWidth * pHeight;
+ pFrameYUV = av_frame_alloc();
uint8_t *outBuf = (uint8_t *)av_malloc(av_image_get_buffer_size(AV_PIX_FMT_YUV420P, codecCtx->width, codecCtx->height, 1));
- av_image_fill_arrays(pFrameYUV->data, pFrameYUV->linesize, outBuf, AV_PIX_FMT_YUV420P, codecCtx->width, codecCtx->height, 1);
+ if(outBuf == NULL) {
+ FLOGE("av_malloc, error");
+ av_frame_free(&pFrameYUV);
+ return -1;
+ }
+ if((ret = av_image_fill_arrays(pFrameYUV->data, pFrameYUV->linesize, outBuf, AV_PIX_FMT_YUV420P, codecCtx->width, codecCtx->height, 1)) < 0){
+ FLOGE("av_image_fill_arrays - error: %s(%d).", av_err2str(ret), ret);
+ av_frame_free(&pFrameYUV);
+ return -1;
+ }
+ // NV21 to YUV420P
memcpy(pFrameYUV->data[0], data, y_length);
for (int i = 0; i < y_length / 4; i++){
- *(pFrameYUV->data[2] + i) = *(data + y_length * 2);
- *(pFrameYUV->data[1] + i) = *(data + y_length * 2 + 1);
+ *(pFrameYUV->data[2] + i) = *(data + y_length + i * 2);
+ *(pFrameYUV->data[1] + i) = *(data + y_length + i * 2 + 1);
}
pFrameYUV->format = AV_PIX_FMT_YUV420P;
pFrameYUV->height = pHeight;
- AVPacket encPkt;
encPkt.data = NULL;
encPkt.size = 0;
av_init_packet(&encPkt);
int got_frame = 0;
- avcodec_encode_video2(codecCtx, &encPkt, pFrameYUV, &got_frame);
+ if((ret = avcodec_encode_video2(codecCtx, &encPkt, pFrameYUV, &got_frame)) < 0){
+ FLOGE("avcodec_encode_video2 - error: %s(%d).", av_err2str(ret), ret);
+ av_frame_free(&pFrameYUV);
+ return -1;
+ }
av_frame_free(&pFrameYUV);
if(got_frame == 1){
if (frameCnt % (15 * 60) == 0){
- FLOGE("Succeed to encode frame: %5d\tsize:%5d\n", frameCnt, encPkt.size);
+ FLOGD("Succeed to encode frame: %5d\tsize:%5d\n", frameCnt, encPkt.size);
}
frameCnt++;
encPkt.stream_index = vStream->index;
if (pts_time > now_time)
av_usleep(pts_time - now_time);
- ret = av_interleaved_write_frame(formatCtx, &encPkt);
+ if((ret = av_interleaved_write_frame(formatCtx, &encPkt)) < 0){
+ FLOGE("av_interleaved_write_frame - error: %s(%d)", av_err2str(ret), ret);
+ return -1;
+ }
av_packet_unref(&encPkt);
}
av_free(outBuf);
{
if(vStream)
avcodec_close(vStream->codec);
- avio_close(formatCtx->pb);
- avformat_free_context(formatCtx);
+ if (formatCtx){
+ avio_close(formatCtx->pb);
+ avformat_free_context(formatCtx);
+ }
+ FLOGE("<----------- FfmpegHelper::close ");
return 0;
}
-jint FfmpegHelper::nativeInitialEncoder(JNIEnv *env, jclass cls, jint width, jint height, jstring url)
+jint FfmpegHelper::nativeInitEncoder(JNIEnv *env, jclass cls, jint width, jint height, jstring url)
{
const char* output = env->GetStringUTFChars(url, 0);
int ret = 0;
class FfmpegHelper {
public:
static jint nativeOnLoad(JavaVM * jvm, void* reserved);
- static jint nativeInitialEncoder(JNIEnv *env, jclass cls, jint width, jint height, jstring url);
+ static jint nativeInitEncoder(JNIEnv *env, jclass cls, jint width, jint height, jstring url);
static jint nativeProcessFrame(JNIEnv *env, jclass cls, jbyteArray data);
static jint nativeClose();
private:
static void av_log_cb (void *ptr, int level, const char* fmt, va_list vl);
- void javaPrint(const char* str);
+ void javaPrint(const char* str, int level);
static void init();
int processFrame(uint8_t *data);
int initEncoder(int width, int height, const char* url);
AVCodecContext* codecCtx;
AVCodec* codec;
AVStream* vStream;
+ AVPacket encPkt;
+ AVFrame *pFrameYUV;
int pWidth;
int pHeight;
unsigned int frameCnt;
* Method: initialDecoder
* Signature: ()I
*/
-JNIEXPORT jint JNICALL Java_ai_suanzi_rtmpclient_FfmpegHelper_initialEncoder (JNIEnv *env, jclass cls, jint width, jint height, jstring url)
+JNIEXPORT jint JNICALL Java_ai_suanzi_rtmpclient_FfmpegHelper_initEncoder (JNIEnv *env, jclass cls, jint width, jint height, jstring url)
{
- return FfmpegHelper::nativeInitialEncoder(env, cls, width, height, url);
+ return FfmpegHelper::nativeInitEncoder(env, cls, width, height, url);
}
/*
#endif
/*
* Class: ai_suanzi_rtmpclient_FfmpegHelper
- * Method: initialEncoder
+ * Method: initEncoder
* Signature: (IILjava/lang/String;)I
*/
-JNIEXPORT jint JNICALL Java_ai_suanzi_rtmpclient_FfmpegHelper_initialEncoder
+JNIEXPORT jint JNICALL Java_ai_suanzi_rtmpclient_FfmpegHelper_initEncoder
(JNIEnv *, jclass, jint, jint, jstring);
/*