Improve Ffmpeg layer
[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 FfmpegHelper helper;
37     private  Boolean isRunning = false;
38     private Camera mCamera = null;
39     IBinder mBinder = new LocalBinder();
40     private String rtmpUrl;
41     private long frameCount = 0;
42
43
44     public class LocalBinder extends Binder {
45         public MyService getServiceInstance(){
46             return MyService.this;
47         }
48     }
49
50     public Camera getCameraInstance() {
51         if (mCamera == null) {
52             CameraHandlerThread mThread = new CameraHandlerThread("camera thread");
53             synchronized (mThread) {
54                 mThread.openCamera();
55             }
56         }
57         if (mCamera == null){
58             gLogger.error("getCameraInstance, camera is null");
59         }
60         return mCamera;
61     }
62
63     private void openCameraOriginal() {
64         try {
65             gLogger.error("openCameraOriginal");
66             mCamera = Camera.open(1);
67         } catch (Exception e) {
68             gLogger.error("camera is not available. error: " + e.getMessage());
69         }
70     }
71
72     private class CameraHandlerThread extends HandlerThread {
73         Handler mHandler;
74
75         public CameraHandlerThread(String name) {
76             super(name);
77             gLogger.error("CameraHandlerThread: " + name);
78             start();
79             mHandler = new Handler(getLooper());
80         }
81
82         synchronized void notifyCameraOpened() {
83             notify();
84         }
85
86         void openCamera() {
87             mHandler.post(new Runnable() {
88                 @Override
89                 public void run() {
90                     openCameraOriginal();
91                     notifyCameraOpened();
92                 }
93             });
94             try {
95                 wait();
96             } catch (InterruptedException e) {
97                 gLogger.error("wait was interrupted");
98             }
99         }
100     }
101
102     private static final int NOTIFICATION_DOWNLOAD_PROGRESS_ID = 0x0001;                                        //id不可设置为0,否则不能设置为前台service
103     private void createNotification(){
104         gLogger.debug("createNotification");
105         NotificationCompat.Builder builder=new NotificationCompat.Builder(this);                        //使用兼容版本
106         builder.setSmallIcon(R.mipmap.ic_launcher);                                                             //设置状态栏的通知图标
107         builder.setLargeIcon(BitmapFactory.decodeResource(getResources(),R.drawable.ic_launcher_background));   //设置通知栏横条的图标
108         builder.setAutoCancel(false);                                                                           //禁止用户点击删除按钮删除
109         builder.setOngoing(true);                                                                               //禁止滑动删除
110         builder.setShowWhen(true);                                                                              //右上角的时间显示
111         builder.setContentTitle("Rtmp Foreground Service!!!");                                                  //设置通知栏的标题内容
112         Notification notification = builder.build();                                                            //创建通知
113         startForeground(NOTIFICATION_DOWNLOAD_PROGRESS_ID,notification);                                        //设置为前台服务
114     }
115
116     @Override
117     public IBinder onBind(Intent intent) {
118         return mBinder;
119     }
120
121     @Override
122     public void onCreate() {
123         super.onCreate();
124         gLogger.error("onCreate ---> ");
125         createNotification();
126         Toast.makeText(this, "Video stream pushed to " + this.rtmpUrl, Toast.LENGTH_LONG).show();
127         mCamera = getCameraInstance();
128         configCamera(mCamera);
129     }
130
131     @Override
132     public void onDestroy() {
133         stopForeground(true);
134         super.onDestroy();
135         gLogger.error( "onDestroy --------->");
136         Toast.makeText(this, "MyService Stopped", Toast.LENGTH_LONG).show();
137         if(mCamera != null){
138             mCamera.stopPreview();
139             mCamera.release();
140         }
141     }
142
143
144     @Override
145     public int onStartCommand(Intent intent, int flags, int startId) {
146         gLogger.error("onStartCommand");
147         //nrunnable = new FfmpegRunnable("xxx", this);
148         //new Thread(runnable).start();
149         return START_STICKY;
150     }
151
152     @Override
153     public void onLowMemory(){
154         super.onLowMemory();
155         gLogger.error("onLowMemory");
156     }
157
158     // Camera.PreviewCallback
159     @Override
160     public void  onPreviewFrame(final byte[] data, Camera camera){
161         if(frameCount % (15 * 60) == 0) {
162             gLogger.error("onPreviewFrame");
163         }
164         frameCount++;
165         //ffmpeg.process(data);
166     }
167
168     public void startPreview (SurfaceHolder holder){
169         gLogger.error("startPreview");
170         if (mCamera == null){
171             gLogger.error("startPreview - error: camera is null");
172             return;
173         }
174         try {
175             mCamera.setPreviewDisplay(holder);
176             mCamera.startPreview();
177         } catch (Exception e){
178             gLogger.error("startPreview - error: " + e.getMessage());
179             e.printStackTrace();
180         }
181     }
182
183     public boolean setRtmpUrl (String url){
184         this.rtmpUrl = url;
185         Camera.Parameters param = mCamera.getParameters();
186         int width = param.getPictureSize().width;
187         int height = param.getPictureSize().height;
188         gLogger.error("setRtmpUrl - size: " +  width + "x" + height + ". url: " + url);
189         //int ret = ffmpeg.initnew(width, height, url);
190         int ret = FfmpegHelper.initialEncoder(width, height, url);
191         return ret == 0 ? true : false;
192     }
193
194     private void configCamera(Camera camera){
195         if(mCamera == null){
196             gLogger.error("configCamera - camera is null");
197             return;
198         }
199         Camera.Parameters paras = camera.getParameters();
200         gLogger.error("Supported Picture Sizes:");
201         Camera.Size preferredSize = paras.getSupportedPictureSizes().get(0);
202         for (Camera.Size cc : paras.getSupportedPictureSizes()){
203             if (cc.width == 640)
204                 preferredSize = cc;
205             gLogger.error(cc.width + "x" + cc.height);
206         }
207         gLogger.error("Supported Preview fps range:");
208         for(int[] i : paras.getSupportedPreviewFpsRange()){
209             gLogger.error("[" + i[0] + "," + i[1] + "]");
210         }
211         paras.setPictureSize(preferredSize.width, preferredSize.height); // use 640x480 preferred
212         camera.setParameters(paras);
213         camera.setDisplayOrientation(0);
214         gLogger.error("Preview Format: " + paras.getPreviewFormat() + ". Size: " + paras.getPreviewSize().width + "x" + paras.getPreviewSize().height);
215         gLogger.error("Picture Format: " + paras.getPictureFormat() + ". Size: " + paras.getPictureSize().width + "x" + paras.getPictureSize().height);
216         camera.setPreviewCallback(this);
217     }
218 }