2637d609635f8f977935db83387c9e94a483be55
[rtmpclient.git] / app / src / main / java / ai / suanzi / rtmpclient / MyService.java
1 package ai.suanzi.rtmpclient;
2
3 import android.app.Service;
4 import android.content.Intent;
5 import android.graphics.SurfaceTexture;
6 import android.hardware.Camera;
7 import android.os.Handler;
8 import android.os.HandlerThread;
9 import android.os.IBinder;
10 import android.os.Looper;
11 import android.util.Log;
12 import android.view.SurfaceHolder;
13 import android.view.SurfaceView;
14 import android.view.WindowManager;
15 import android.widget.Toast;
16 import android.support.v4.app.NotificationCompat;
17 import android.graphics.BitmapFactory;
18 import android.app.Notification;
19 import android.os.Message;
20 import org.apache.log4j.Level;
21 import org.apache.log4j.Logger;
22 import android.hardware.Camera.PreviewCallback;
23 import android.os.IBinder;
24 import android.os.Binder;
25 import android.content.Context;
26 import android.graphics.PixelFormat;
27 import java.io.IOException;
28 import android.view.Gravity;
29
30 public class MyService extends Service  implements Camera.PreviewCallback {
31
32     private static Logger gLogger = Logger.getLogger("MyService");
33     private static String TAG = "MyService";
34
35     private Ffmpeg ffmpeg = Ffmpeg.getInstance();
36     private  Boolean isRunning = false;
37     //private FfmpegRunnable  runnable;
38     private Camera mCamera = null;
39     IBinder mBinder = new LocalBinder();
40     private String rtmpUrl;
41     //private WindowManager mWindowManager;
42     //private SurfaceView mOutComeVideoView;
43     private long frameCount = 0;
44
45
46     public class LocalBinder extends Binder {
47         public MyService getServiceInstance(){
48             return MyService.this;
49         }
50     }
51
52     public Camera getCameraInstance() {
53         if (mCamera == null) {
54             CameraHandlerThread mThread = new CameraHandlerThread("camera thread");
55             synchronized (mThread) {
56                 mThread.openCamera();
57             }
58         }
59         if (mCamera == null){
60             gLogger.error("getCameraInstance, camera is null");
61         }
62         return mCamera;
63     }
64
65     private void openCameraOriginal() {
66         try {
67             gLogger.error("openCameraOriginal");
68             mCamera = Camera.open(1);
69         } catch (Exception e) {
70             gLogger.error("camera is not available. error: " + e.getMessage());
71         }
72     }
73
74     private class CameraHandlerThread extends HandlerThread {
75         Handler mHandler;
76
77         public CameraHandlerThread(String name) {
78             super(name);
79             gLogger.error("CameraHandlerThread: " + name);
80             start();
81             mHandler = new Handler(getLooper());
82         }
83
84         synchronized void notifyCameraOpened() {
85             notify();
86         }
87
88         void openCamera() {
89             mHandler.post(new Runnable() {
90                 @Override
91                 public void run() {
92                     openCameraOriginal();
93                     notifyCameraOpened();
94                 }
95             });
96             try {
97                 wait();
98             } catch (InterruptedException e) {
99                 gLogger.error("wait was interrupted");
100             }
101         }
102     }
103
104     private static final int NOTIFICATION_DOWNLOAD_PROGRESS_ID = 0x0001;                                        //id不可设置为0,否则不能设置为前台service
105     private void createNotification(){
106         gLogger.debug("createNotification");
107         NotificationCompat.Builder builder=new NotificationCompat.Builder(this);                        //使用兼容版本
108         builder.setSmallIcon(R.mipmap.ic_launcher);                                                             //设置状态栏的通知图标
109         builder.setLargeIcon(BitmapFactory.decodeResource(getResources(),R.drawable.ic_launcher_background));   //设置通知栏横条的图标
110         builder.setAutoCancel(false);                                                                           //禁止用户点击删除按钮删除
111         builder.setOngoing(true);                                                                               //禁止滑动删除
112         builder.setShowWhen(true);                                                                              //右上角的时间显示
113         builder.setContentTitle("Rtmp Foreground Service!!!");                                                  //设置通知栏的标题内容
114         Notification notification = builder.build();                                                            //创建通知
115         startForeground(NOTIFICATION_DOWNLOAD_PROGRESS_ID,notification);                                        //设置为前台服务
116     }
117
118     @Override
119     public IBinder onBind(Intent intent) {
120         return mBinder;
121     }
122
123     @Override
124     public void onCreate() {
125         super.onCreate();
126         gLogger.error("onCreate ---> ");
127         createNotification();
128         Toast.makeText(this, "Video stream pushed to " + this.rtmpUrl, Toast.LENGTH_LONG).show();
129         mCamera = getCameraInstance();
130         configCamera(mCamera);
131     }
132
133     @Override
134     public void onDestroy() {
135         stopForeground(true);
136         super.onDestroy();
137         gLogger.error( "onDestroy --------->");
138         Toast.makeText(this, "MyService Stopped", Toast.LENGTH_LONG).show();
139         if(mCamera != null){
140             mCamera.stopPreview();
141             mCamera.release();
142         }
143     }
144
145
146     @Override
147     public int onStartCommand(Intent intent, int flags, int startId) {
148         gLogger.error("onStartCommand");
149         //nrunnable = new FfmpegRunnable("xxx", this);
150         //new Thread(runnable).start();
151         return START_STICKY;
152     }
153
154     @Override
155     public void onLowMemory(){
156         super.onLowMemory();
157         gLogger.error("onLowMemory");
158     }
159
160     // Camera.PreviewCallback
161     @Override
162     public void  onPreviewFrame(final byte[] data, Camera camera){
163         if(frameCount % (15 * 60) == 0) {
164             gLogger.error("onPreviewFrame");
165         }
166         frameCount++;
167         ffmpeg.process(data);
168     }
169
170     public void startPreview (SurfaceHolder holder){
171         gLogger.error("startPreview");
172         if (mCamera == null){
173             gLogger.error("startPreview - error: camera is null");
174             return;
175         }
176         try {
177             mCamera.setPreviewDisplay(holder);
178             mCamera.startPreview();
179         } catch (Exception e){
180             gLogger.error("startPreview - error: " + e.getMessage());
181             e.printStackTrace();
182         }
183     }
184
185     public boolean setRtmpUrl (String url){
186         this.rtmpUrl = url;
187         Camera.Parameters param = mCamera.getParameters();
188         int width = param.getPictureSize().width;
189         int height = param.getPictureSize().height;
190         gLogger.error("setRtmpUrl - size: " +  width + "x" + height + ". url: " + url);
191         int ret = ffmpeg.initnew(width, height, url);
192         return ret == 0 ? true : false;
193     }
194
195     private void configCamera(Camera camera){
196         if(mCamera == null){
197             gLogger.error("configCamera - camera is null");
198             return;
199         }
200         Camera.Parameters paras = camera.getParameters();
201         gLogger.error("Supported Picture Sizes:");
202         Camera.Size preferredSize = paras.getSupportedPictureSizes().get(0);
203         for (Camera.Size cc : paras.getSupportedPictureSizes()){
204             if (cc.width == 640)
205                 preferredSize = cc;
206             gLogger.error(cc.width + "x" + cc.height);
207         }
208         gLogger.error("Supported Preview fps range:");
209         for(int[] i : paras.getSupportedPreviewFpsRange()){
210             gLogger.error("[" + i[0] + "," + i[1] + "]");
211         }
212         paras.setPictureSize(preferredSize.width, preferredSize.height); // use 640x480 preferred
213         camera.setParameters(paras);
214         camera.setDisplayOrientation(0);
215         gLogger.error("Preview Format: " + paras.getPreviewFormat() + ". Size: " + paras.getPreviewSize().width + "x" + paras.getPreviewSize().height);
216         gLogger.error("Picture Format: " + paras.getPictureFormat() + ". Size: " + paras.getPictureSize().width + "x" + paras.getPictureSize().height);
217         camera.setPreviewCallback(this);
218         //camera.startPreview();
219     }
220 }
221
222 //    private class FfmpegRunnable implements Runnable {
223 //        private String url;
224 //        private Camera.PreviewCallback cb;
225 //        public FfmpegRunnable(String _url, Camera.PreviewCallback _cb){
226 //            this.url = _url;
227 //            this.cb = _cb;
228 //        }
229 //        @Override
230 //        public void run(){
231 //            gLogger.error("Run Ffmpeg url: " + url);
232 //            isRunning = true;
233 //            gLogger.error("Open camera");
234 //            mCamera = getCameraInstance();
235 //            if(mCamera == null) {
236 //                gLogger.error("Open camera, camera is null");
237 //            }
238 //            configCamera(mCamera);
239 //            mCamera.setPreviewCallback(this.cb);
240 //        }
241 //    }