七牛推流SDK demo 中 关键类的注释
2016-10-18 15:42
204 查看
SWCodecCameraStreamingActivity
StreamingBaseActivity
package com.pili.pldroid.streaming.camera.demo; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.os.Bundle; import android.util.Log; import com.pili.pldroid.streaming.CameraStreamingManager; import com.pili.pldroid.streaming.CameraStreamingManager.EncodingType; import com.pili.pldroid.streaming.WatermarkSetting; import com.pili.pldroid.streaming.widget.AspectFrameLayout; /** * Created by jerikc on 15/10/29. */ public class SWCodecCameraStreamingActivity extends StreamingBaseActivity { private static final String TAG = "SWCodecCameraStreaming"; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); //用户使用我们的demon apk进入推流摄像界面,屏幕尺寸大小的控制: AspectFrameLayout afl = (AspectFrameLayout) findViewById(R.id.cameraPreview_afl); //SHOW_MODE.FULL,可以全屏显示(没有黑边),但是预览的图像和播放的效果有出入,即之前的黑边部分其实没有推流 //SHOW_MODE.REAL,所见即所得 afl.setShowMode(AspectFrameLayout.SHOW_MODE.FULL); // FULL,REAL; CameraPreviewFrameView cameraPreviewFrameView = (CameraPreviewFrameView) findViewById(R.id.cameraPreview_surfaceView); cameraPreviewFrameView.setListener(this); //------------------------水印参数设置------------------------------- //第二个参数设置水印图片,可以传入本地drawable中的图片,也可以传入图片的绝对路径作为水印资源 //第三个参数设置水印的位置 //第四个参数设置水印显示的大小 //public WatermarkSetting(Context ctx, String absoluteResPath, WATERMARK_LOCATION location, WATERMARK_SIZE size, int alpha) WatermarkSetting watermarksetting = new WatermarkSetting(this, R.drawable.qiniu_logo, WatermarkSetting.WATERMARK_LOCATION.NORTH_EAST, WatermarkSetting.WATERMARK_SIZE.MEDIUM, 100); //构造带有视频 CameraStremaingManager,需要传入AspectFrameLayout,第四个参数设置编码的方式,硬编or软编 mCameraStreamingManager = new CameraStreamingManager(this, afl, cameraPreviewFrameView, EncodingType.SW_VIDEO_WITH_SW_AUDIO_CODEC); // sw codec mCameraStreamingManager.prepare(mCameraStreamingSetting, mMicrophoneStreamingSetting, watermarksetting, mProfile); //-----------注册各种Listener---------------------------------------- //流状态改变回调监听: //推流状态回调监听,比如流断开,重连回调 mCameraStreamingManager.setStreamingStateListener(this); //实现StreamStatusCallback 接口的 mCameraStreamingManager.setSurfaceTextureCallback(this); //可以在 StreamingSessionListener 处理一些重连、音频读取失败、preview size 的自定义操作。 mCameraStreamingManager.setStreamingSessionListener(this); // mCameraStreamingManager.setNativeLoggingEnabled(false); mCameraStreamingManager.setStreamStatusCallback(this); // update the StreamingProfile // mProfile.setStream(new Stream(mJSONObject1)); // mCameraStreamingManager.setStreamingProfile(mProfile); setFocusAreaIndicator(); } }
StreamingBaseActivity
package com.pili.pldroid.streaming.camera.demo; import android.app.Activity; import android.content.Context; import android.content.Intent; import android.content.pm.ActivityInfo; import android.graphics.Bitmap; import android.hardware.Camera; import android.os.Build; import android.os.Bundle; import android.os.Environment; import android.os.Handler; import android.os.Looper; import android.os.Message; import android.util.Log; import android.view.MotionEvent; import android.view.View; import android.view.Window; import android.view.WindowManager; import android.widget.Button; import android.widget.SeekBar; import android.widget.TextView; import android.widget.Toast; import com.pili.pldroid.streaming.CameraStreamingManager; import com.pili.pldroid.streaming.CameraStreamingSetting; import com.pili.pldroid.streaming.FrameCapturedCallback; import com.pili.pldroid.streaming.MicrophoneStreamingSetting; import com.pili.pldroid.streaming.SharedLibraryNameHelper; import com.pili.pldroid.streaming.StreamStatusCallback; import com.pili.pldroid.streaming.StreamingPreviewCallback; import com.pili.pldroid.streaming.StreamingProfile; import com.pili.pldroid.streaming.SurfaceTextureCallback; import com.pili.pldroid.streaming.camera.demo.gles.FBO; import com.pili.pldroid.streaming.camera.demo.ui.RotateLayout; import com.qiniu.android.dns.DnsManager; import com.qiniu.android.dns.IResolver; import com.qiniu.android.dns.NetworkInfo; import com.qiniu.android.dns.http.DnspodFree; import com.qiniu.android.dns.local.AndroidDnsServer; import com.qiniu.android.dns.local.Resolver; import org.json.JSONException; import org.json.JSONObject; import java.io.BufferedOutputStream; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.net.InetAddress; import java.util.List; /** * Created by jerikc on 15/7/6. */ public class StreamingBaseActivity extends Activity implements View.OnLayoutChangeListener, StreamStatusCallback, StreamingPreviewCallback, SurfaceTextureCallback, CameraPreviewFrameView.Listener, CameraStreamingManager.StreamingSessionListener, CameraStreamingManager.StreamingStateListener { private static final String TAG = "StreamingBaseActivity"; private static final int ZOOM_MINIMUM_WAIT_MILLIS = 33; //ms private Context mContext; protected Button mShutterButton; private Button mMuteButton; private Button mTorchBtn; private Button mCameraSwitchBtn; private Button mCaptureFrameBtn; private Button mEncodingOrientationSwitcherBtn; private Button mFaceBeautyBtn; //Filter private Button mFilterBtn; private RotateLayout mRotateLayout; protected TextView mSatusTextView; private TextView mLogTextView; private TextView mStreamStatus; protected boolean mShutterButtonPressed = false; private boolean mIsTorchOn = false; private boolean mIsNeedMute = false; private boolean mIsNeedFB = false; private boolean mIsNeedFL = false; private boolean isEncOrientationPort = true; protected static final int MSG_START_STREAMING = 0; protected static final int MSG_STOP_STREAMING = 1; private static final int MSG_SET_ZOOM = 2; private static final int MSG_MUTE = 3; private static final int MSG_FB = 4; private static final int MSG_FL = 5; protected String mStatusMsgContent; protected String mLogContent = "\n"; private View mRootView; protected CameraStreamingManager mCameraStreamingManager; protected CameraStreamingSetting mCameraStreamingSetting; protected MicrophoneStreamingSetting mMicrophoneStreamingSetting; protected StreamingProfile mProfile; protected JSONObject mJSONObject; private boolean mIsNeedSpeedCheck = true; private boolean mOrientationChanged = false; protected boolean mIsReady = false; private int mCurrentZoom = 0; private int mMaxZoom = 0; private FBO mFBO = new FBO(); private Screenshooter mScreenshooter = new Screenshooter(); private EncodingOrientationSwitcher mEncodingOrientationSwitcher = new EncodingOrientationSwitcher(); protected Handler mHandler = new Handler(Looper.getMainLooper()) { @Override public void handleMessage(Message msg) { switch (msg.what) { case MSG_START_STREAMING: new Thread(new Runnable() { @Override public void run() { // disable the shutter button before startStreaming setShutterButtonEnabled(false); boolean res = mCameraStreamingManager.startStreaming(); mShutterButtonPressed = true; Log.i(TAG, "res:" + res); if (!res) { mShutterButtonPressed = false; setShutterButtonEnabled(true); } setShutterButtonPressed(mShutterButtonPressed); } }).start(); break; case MSG_STOP_STREAMING: // disable the shutter button before stopStreaming setShutterButtonEnabled(false); boolean res = mCameraStreamingManager.stopStreaming(); if (!res) { mShutterButtonPressed = true; setShutterButtonEnabled(true); } setShutterButtonPressed(mShutterButtonPressed); break; case MSG_SET_ZOOM: mCameraStreamingManager.setZoomValue(mCurrentZoom); break; case MSG_MUTE: mIsNeedMute = !mIsNeedMute; //-----------------禁音推流-------------------------------------- //设置为true为禁止声音推流,默认为falase mCameraStreamingManager.mute(mIsNeedMute); updateMuteButtonText(); break; case MSG_FB: mIsNeedFB = !mIsNeedFB; mCameraStreamingManager.setVideoFilterType(mIsNeedFB ? CameraStreamingSetting.VIDEO_FILTER_TYPE.VIDEO_FILTER_BEAUTY : CameraStreamingSetting.VIDEO_FILTER_TYPE.VIDEO_FILTER_NONE); updateFBButtonText(); break; case MSG_FL: mIsNeedFL = !mIsNeedFL; onSurfaceCreated(); /*mCameraStreamingManager.setVideoFilterType(mIsNeedFL ? CameraStreamingSetting.VIDEO_FILTER_TYPE.VIDEO_FILTER_BEAUTY : CameraStreamingSetting.VIDEO_FILTER_TYPE.VIDEO_FILTER_NONE);*/ updateFLButtonText(); break; default: Log.e(TAG, "Invalid message"); break; } } }; @Override protected void onCreate(Bundle savedInstanceState) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) { requestWindowFeature(Window.FEATURE_ACTION_BAR_OVERLAY); } else { requestWindowFeature(Window.FEATURE_NO_TITLE); } super.onCreate(savedInstanceState); getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); if (Config.SCREEN_ORIENTATION == ActivityInfo.SCREEN_ORIENTATION_PORTRAIT) { isEncOrientationPort = true; } else if (Config.SCREEN_ORIENTATION == ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE) { isEncOrientationPort = false; } setRequestedOrientation(Config.SCREEN_ORIENTATION); setContentView(R.layout.activity_camera_streaming); //从MainActivity获取传入的推流的JSON数据 String streamJsonStrFromServer = getIntent().getStringExtra(Config.EXTRA_KEY_STREAM_JSON); Log.i(TAG, "streamJsonStrFromServer:" + streamJsonStrFromServer); try { mJSONObject = new JSONObject(streamJsonStrFromServer); } catch (Exception e) { e.printStackTrace(); } mContext = this; StreamingProfile.AudioProfile aProfile = new StreamingProfile.AudioProfile(44100, 96 * 1024); StreamingProfile.VideoProfile vProfile = new StreamingProfile.VideoProfile(30, 1000 * 1024, 48); StreamingProfile.AVProfile avProfile = new StreamingProfile.AVProfile(vProfile, aProfile); //------------------------推流参数设置------------------------------- mProfile = new StreamingProfile(); StreamingProfile.Stream stream = new StreamingProfile.Stream(mJSONObject); //------------------通过setStream设置推流地址---------------- mProfile.setStream(stream); //-----------------通过setVideoQuality设置推流视频部分质量参数------------ /* Level Fps Video Bitrate(Kbps) VIDEO_QUALITY_LOW1 12 150 VIDEO_QUALITY_LOW2 15 264 VIDEO_QUALITY_LOW3 15 350 VIDEO_QUALITY_MEDIUM1 30 512 VIDEO_QUALITY_MEDIUM2 30 800 VIDEO_QUALITY_MEDIUM3 30 1000 VIDEO_QUALITY_HIGH1 30 1200 VIDEO_QUALITY_HIGH2 30 1500 VIDEO_QUALITY_HIGH3 30 2000 */ mProfile.setVideoQuality(StreamingProfile.VIDEO_QUALITY_HIGH3) //-----------------通过setAudioQuality设置推流音频部分质量参数------------ /* Level Audio Bitrate(Kbps) Audio Sample Rate(Hz) AUDIO_QUALITY_LOW1 18 44100 AUDIO_QUALITY_LOW2 24 44100 AUDIO_QUALITY_MEDIUM1 32 44100 AUDIO_QUALITY_MEDIUM2 48 44100 AUDIO_QUALITY_HIGH1 96 44100 AUDIO_QUALITY_HIGH2 128 44100 */ .setAudioQuality(StreamingProfile.AUDIO_QUALITY_MEDIUM2) //setPreferredVideoEncodingSize 自定义设置推流分辨率,此优先级高于setEncodingSizeLevel // .setPreferredVideoEncodingSize(960, 544) .setEncodingSizeLevel(Config.ENCODING_LEVEL) //--------------通过setEncoderRCMode设置质量优先还是码率优先---------------- //EncoderRCModes.QUALITY_PRIORITY: 质量优先,实际的码率可能高于设置的码率 //EncoderRCModes.BITRATE_PRIORITY: 码率优先,更精确地码率控制 //默认值为 EncoderRCModes.QUALITY_PRIORITY .setEncoderRCMode(StreamingProfile.EncoderRCModes.QUALITY_PRIORITY) //--------------通过AVProfile参数自定义推流音视频码率帧率-------------------- // 自定义设置音频采样率为44100Hz, 码率为96 * 1024 bps // 自定义设置视频帧率为30, 码率为1000 * 1024 bps,最大帧率为48 //setAVProfile 的优先级高于 Quality,也就是说,当同时调用了 Quality 和 AVProfile 的设置,AVProfile 会覆盖 Quality 的设置值 .setAVProfile(avProfile) .setDnsManager(getMyDnsManager()) .setStreamStatusConfig(new StreamingProfile.StreamStatusConfig(3)) // .setEncodingOrientation(StreamingProfile.ENCODING_ORIENTATION.PORT) // (lowThreshold,highThreshold,durationLimit,timeout) .setSendingBufferProfile(new StreamingProfile.SendingBufferProfile(0.2f, 0.8f, 3.0f, 20 * 1000)); //----------------------------摄像头设置---------------------------- mCameraStreamingSetting = new CameraStreamingSetting(); //------------前后置镜头相关-------- //通过setCameraId可以指定使用前置摄像头或者是后置摄像头, CAMERA_FACING_FONT为前置, CAMERA_FACING_BACK为后置 mCameraStreamingSetting.setCameraId(Camera.CameraInfo.CAMERA_FACING_FRONT) //-------------对焦相关---------- //通过setContinuousFocusModeEnabled设置自动对焦 .setContinuousFocusModeEnabled(true) //---------------RecordingHint提升数据源的帧率-------- //在部分机型开启 Recording Hint 之后,会出现画面卡帧等风险,所以请慎用该API。如果需要实现高 fps 推流,可以考虑开启并加入白名单机制 .setRecordingHint(false) .setBuiltInFaceBeautyEnabled(true) .setResetTouchFocusDelayInMs(3000) //通过setFocusMode设置对焦模式 /* FOCUS_MODE_CONTINUOUS_PICTURE 自动对焦(Picture); FOCUS_MODE_CONTINUOUS_VIDEO 自动对焦(Video); FOCUS_MODE_AUTO 手动对焦*/ // .setFocusMode(CameraStreamingSetting.FOCUS_MODE_CONTINUOUS_PICTURE) //--------------摄像头预览相关--------- // 使用 PREVIEW_SIZE_LEVEL 和 PREVIEW_SIZE_RATIO 共同确定一个预览Size //PREVIEW_SIZE_LEVEL和相机预览的清晰度有关系, 设置为SMALL预览的画面会很不清晰 //PREVIEW_SIZE_RATIO 我们的SDK是提供的两种规格16_9 和 4_3 .setCameraPrvSizeLevel(CameraStreamingSetting.PREVIEW_SIZE_LEVEL.MEDIUM) .setCameraPrvSizeRatio(CameraStreamingSetting.PREVIEW_SIZE_RATIO.RATIO_16_9) //--------------美颜相关设置--------- //参数说明:1,beautyLevel;2,whiten ;3,redden. .setFaceBeautySetting(new CameraStreamingSetting.FaceBeautySetting(1.0f, 1.0f, 0.8f)) .setVideoFilter(CameraStreamingSetting.VIDEO_FILTER_TYPE.VIDEO_FILTER_BEAUTY); mIsNeedFB = true; mIsNeedFL = true; //Filter //------------------------麦克风参数配置----------------------------- mMicrophoneStreamingSetting = new MicrophoneStreamingSetting(); //希望增加蓝牙麦克风的支持,可以设置:true mMicrophoneStreamingSetting.setBluetoothSCOEnabled(false); initUIs(); } @Override protected void onResume() { super.onResume(); Log.i(TAG, "tid:" + Thread.currentThread().getId()); try { //CameraStreamingManager#resume 会进行 Camera 的打开操作,当成功打开后, //会返回 STATE.READY 消息,用户可以在接受到 STATE.READY 之后,安全地进行推流操作。 mCameraStreamingManager.resume(); } catch (Exception e) { Toast.makeText(StreamingBaseActivity.this, "Device open error!", Toast.LENGTH_SHORT).show(); } } @Override protected void onPause() { super.onPause(); mIsReady = false; mShutterButtonPressed = false; //退出 CameraStreamingManager,该操作会主动断开当前的流链接,并关闭 Camera 和释放相应的资源。 mCameraStreamingManager.pause(); mHandler.removeCallbacksAndMessages(null); } @Override protected void onDestroy() { super.onDestroy(); mCameraStreamingManager.destroy(); } protected void setShutterButtonPressed(final boolean pressed) { runOnUiThread(new Runnable() { @Override public void run() { mShutterButtonPressed = pressed; mShutterButton.setPressed(pressed); } }); } protected void setShutterButtonEnabled(final boolean enable) { runOnUiThread(new Runnable() { @Override public void run() { mShutterButton.setFocusable(enable); mShutterButton.setClickable(enable); mShutterButton.setEnabled(enable); } }); } protected void startStreaming() { mHandler.removeCallbacksAndMessages(null); mHandler.sendMessageDelayed(mHandler.obtainMessage(MSG_START_STREAMING), 50); } protected void stopStreaming() { mHandler.removeCallbacksAndMessages(null); mHandler.sendMessageDelayed(mHandler.obtainMessage(MSG_STOP_STREAMING), 50); } @Override public boolean onRecordAudioFailedHandled(int err) { mCameraStreamingManager.updateEncodingType(CameraStreamingManager.EncodingType.SW_VIDEO_CODEC); mCameraStreamingManager.startStreaming(); return true; } @Override public boolean onRestartStreamingHandled(int err) { Log.i(TAG, "onRestartStreamingHandled"); return mCameraStreamingManager.startStreaming(); } @Override public Camera.Size onPreviewSizeSelected(List<Camera.Size> list) { Camera.Size size = null; // if (list != null) { // for (Camera.Size s : list) { // size = s; // Log.i(TAG, "w:" + s.width + ", h:" + s.height); // break; // if (s.height < 480) { // continue; // } else { // size = s; // break; // } // } // } // Log.e(TAG, "selected size :" + size.width + "x" + size.height); return size; } @Override public boolean onSingleTapUp(MotionEvent e) { Log.i(TAG, "onSingleTapUp X:" + e.getX() + ",Y:" + e.getY()); if (mIsReady) { setFocusAreaIndicator(); mCameraStreamingManager.doSingleTapUp((int) e.getX(), (int) e.getY()); return true; } return false; } @Override public boolean onZoomValueChanged(float factor) { if (mIsReady && mCameraStreamingManager.isZoomSupported()) { mCurrentZoom = (int) (mMaxZoom * factor); mCurrentZoom = Math.min(mCurrentZoom, mMaxZoom); mCurrentZoom = Math.max(0, mCurrentZoom); Log.d(TAG, "zoom ongoing, scale: " + mCurrentZoom + ",factor:" + factor + ",maxZoom:" + mMaxZoom); if (!mHandler.hasMessages(MSG_SET_ZOOM)) { mHandler.sendMessageDelayed(mHandler.obtainMessage(MSG_SET_ZOOM), ZOOM_MINIMUM_WAIT_MILLIS); return true; } } return false; } private Switcher mSwitcher = new Switcher(); @Override public void onLayoutChange(View v, int left, int top, int right, int bottom, int oldLeft, int oldTop, int oldRight, int oldBottom) { Log.i(TAG, "view!!!!:" + v); } @Override public void onPreviewFrame(byte[] bytes, Camera camera) { } @Override public boolean onPreviewFrame(byte[] bytes, int width, int height) { // deal with the yuv data. // long start = System.currentTimeMillis(); // for (int i = 0; i < bytes.length; i++) { // bytes[i] = 0x00; // } // Log.i(TAG, "old onPreviewFrame cost :" + (System.currentTimeMillis() - start)); return true; } @Override public void onSurfaceCreated() { Log.i(TAG, "onSurfaceCreated"); mFBO.initialize(this); } @Override public void onSurfaceChanged(int width, int height) { Log.i(TAG, "onSurfaceChanged width:" + width + ",height:" + height); mFBO.updateSurfaceSize(width, height); } @Override public void onSurfaceDestroyed() { Log.i(TAG, "onSurfaceDestroyed"); mFBO.release(); } @Override public int onDrawFrame(int texId, int texWidth, int texHeight, float[] transformMatrix) { // newTexId should not equal with texId. texId is from the SurfaceTexture. // Otherwise, there is no filter effect. int newTexId = mFBO.drawFrame(texId, texWidth, texHeight); // Log.i(TAG, "onDrawFrame texId:" + texId + ",newTexId:" + newTexId + ",texWidth:" + texWidth + ",texHeight:" + texHeight); return newTexId; } //推流状态信息 @Override public void notifyStreamStatusChanged(final StreamingProfile.StreamStatus streamStatus) { runOnUiThread(new Runnable() { @Override public void run() { mStreamStatus.setText("bitrate:" + streamStatus.totalAVBitrate / 1024 + " kbps" + "\naudio:" + streamStatus.audioFps + " fps" + "\nvideo:" + streamStatus.videoFps + " fps"); } }); } private class Switcher implements Runnable { @Override public void run() { mCameraStreamingManager.switchCamera(); } } private class EncodingOrientationSwitcher implements Runnable { @Override public void run() { Log.i(TAG, "isEncOrientationPort:" + isEncOrientationPort); stopStreaming(); mOrientationChanged = !mOrientationChanged; isEncOrientationPort = !isEncOrientationPort; //-------------------设置推流播放端方向------------------------------- //设置ENCODING_ORIENTATION.LAND推流播放端会横屏播放 //设置ENCODING_ORIENTATION.PORT推流播放端会竖屏播放 mProfile.setEncodingOrientation(isEncOrientationPort ? StreamingProfile.ENCODING_ORIENTATION.PORT : StreamingProfile.ENCODING_ORIENTATION.LAND); mCameraStreamingManager.setStreamingProfile(mProfile); setRequestedOrientation(isEncOrientationPort ? ActivityInfo.SCREEN_ORIENTATION_PORTRAIT : ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE); mCameraStreamingManager.notifyActivityOrientationChanged(); updateOrientationBtnText(); Toast.makeText(StreamingBaseActivity.this, Config.HINT_ENCODING_ORIENTATION_CHANGED, Toast.LENGTH_SHORT).show(); Log.i(TAG, "EncodingOrientationSwitcher -"); } } private class Screenshooter implements Runnable { @Override public void run() { final String fileName = "PLStreaming_" + System.currentTimeMillis() + ".jpg"; //SDK 完成截帧之后,会回调 onFrameCaptured,并将结果以参数的形式返回给调用者。 mCameraStreamingManager.captureFrame(100, 100, new FrameCapturedCallback() { private Bitmap bitmap; @Override public void onFrameCaptured(Bitmap bmp) { if (bmp == null) { return; } bitmap = bmp; new Thread(new Runnable() { @Override public void run() { try { saveToSDCard(fileName, bitmap); } catch (IOException e) { e.printStackTrace(); } finally { if (bitmap != null) { bitmap.recycle(); bitmap = null; } } } }).start(); } }); } } private void setTorchEnabled(final boolean enabled) { runOnUiThread(new Runnable() { @Override public void run() { String flashlight = enabled ? getString(R.string.flash_light_off) : getString(R.string.flash_light_on); mTorchBtn.setText(flashlight); } }); } //推流过程中流状态信息的一些回调 @Override public void onStateChanged(final int state, Object extra) { switch (state) { case CameraStreamingManager.STATE.PREPARING: mStatusMsgContent = getString(R.string.string_state_preparing); break; case CameraStreamingManager.STATE.READY: // 当流的状态是READY的时候开始推流 mIsReady = true; mMaxZoom = mCameraStreamingManager.getMaxZoom(); mStatusMsgContent = getString(R.string.string_state_ready); // start streaming when READY startStreaming(); break; case CameraStreamingManager.STATE.CONNECTING: mStatusMsgContent = getString(R.string.string_state_connecting); break; case CameraStreamingManager.STATE.STREAMING: mStatusMsgContent = getString(R.string.string_state_streaming); setShutterButtonEnabled(true); setShutterButtonPressed(true); break; case CameraStreamingManager.STATE.SHUTDOWN: mStatusMsgContent = getString(R.string.string_state_ready); setShutterButtonEnabled(true); setShutterButtonPressed(false); if (mOrientationChanged) { mOrientationChanged = false; startStreaming(); } break; //若网络不可达(网络断开等情况),尝试重连之后,会返回 STATE.IOERROR,可以不用担心循环重连的问题。 //在网络层会有三次重连的机会,即没有必要在收到 STATE.IOERROR 之后继续进行重连,一般接收到 STATE.IOERROR 代表无法通过网络和服务端建立链接。 case CameraStreamingManager.STATE.IOERROR: mLogContent += "IOERROR\n"; mStatusMsgContent = getString(R.string.string_state_ready); setShutterButtonEnabled(true); break; case CameraStreamingManager.STATE.UNKNOWN: mStatusMsgContent = getString(R.string.string_state_ready); break; case CameraStreamingManager.STATE.SENDING_BUFFER_EMPTY: break; case CameraStreamingManager.STATE.SENDING_BUFFER_FULL: break; case CameraStreamingManager.STATE.AUDIO_RECORDING_FAIL: break; case CameraStreamingManager.STATE.OPEN_CAMERA_FAIL: Log.e(TAG, "Open Camera Fail. id:" + extra); break; //在网络断开、sendTimeOut 后没有发出数据、网络链接被服务端断开等网络异常后,STATE.DISCONNECTED 消息会被回调 case CameraStreamingManager.STATE.DISCONNECTED: mLogContent += "DISCONNECTED\n"; break; case CameraStreamingManager.STATE.INVALID_STREAMING_URL: Log.e(TAG, "Invalid streaming url:" + extra); break; case CameraStreamingManager.STATE.CAMERA_SWITCHED: // mShutterButtonPressed = false; if (extra != null) { Log.i(TAG, "current camera id:" + (Integer)extra); } Log.i(TAG, "camera switched"); final int currentCamId = (Integer)extra; this.runOnUiThread(new Runnable() { @Override public void run() { updateCameraSwitcherButtonText(currentCamId); } }); break; case CameraStreamingManager.STATE.TORCH_INFO: if (extra != null) { final boolean isSupportedTorch = (Boolean) extra; Log.i(TAG, "isSupportedTorch=" + isSupportedTorch); this.runOnUiThread(new Runnable() { @Override public void run() { if (isSupportedTorch) { mTorchBtn.setVisibility(View.VISIBLE); } else { mTorchBtn.setVisibility(View.GONE); } } }); } break; } runOnUiThread(new Runnable() { @Override public void run() { if (mLogTextView != null) { mLogTextView.setText(mLogContent); } mSatusTextView.setText(mStatusMsgContent); } }); } @Override public boolean onStateHandled(final int state, Object extra) { switch (state) { case CameraStreamingManager.STATE.SENDING_BUFFER_HAS_FEW_ITEMS: return false; case CameraStreamingManager.STATE.SENDING_BUFFER_HAS_MANY_ITEMS: return false; } return false; } private void initUIs() { mRootView = findViewById(R.id.content); mRootView.addOnLayoutChangeListener(this); mMuteButton = (Button) findViewById(R.id.mute_btn); mShutterButton = (Button) findViewById(R.id.toggleRecording_button); mTorchBtn = (Button) findViewById(R.id.torch_btn); mCameraSwitchBtn = (Button) findViewById(R.id.camera_switch_btn); mCaptureFrameBtn = (Button) findViewById(R.id.capture_btn); mFaceBeautyBtn = (Button) findViewById(R.id.fb_btn); //Filter mFilterBtn = (Button) findViewById(R.id.fl_btn); mSatusTextView = (TextView) findViewById(R.id.streamingStatus); mLogTextView = (TextView) findViewById(R.id.log_info); //推流状态信息回调mStreamStatus初始化 mStreamStatus = (TextView) findViewById(R.id.stream_status); mFaceBeautyBtn.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { if (!mHandler.hasMessages(MSG_FB)) { mHandler.sendEmptyMessage(MSG_FB); } } }); //Filter mFilterBtn.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Toast.makeText(StreamingBaseActivity.this, "Sorry,this fuction will up by the next version", Toast.LENGTH_SHORT).show(); /*if (!mHandler.hasMessages(MSG_FL)) { mHandler.sendEmptyMessage(MSG_FL); }*/ } }); mMuteButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { if (!mHandler.hasMessages(MSG_MUTE)) { mHandler.sendEmptyMessage(MSG_MUTE); } /*客户的操作,在按钮中添加跳转activity的操作,出现黑屏现象???*/ /*Intent intent = new Intent(StreamingBaseActivity.this,MainActivity.class); startActivity(intent);*/ } }); mShutterButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { if (mShutterButtonPressed) { stopStreaming(); } else { startStreaming(); } } }); mTorchBtn.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { new Thread(new Runnable() { @Override public void run() { if (!mIsTorchOn) { mIsTorchOn = true; mCameraStreamingManager.turnLightOn(); } else { mIsTorchOn = false; mCameraStreamingManager.turnLightOff(); } setTorchEnabled(mIsTorchOn); } }).start(); } }); //postDelayed的作用是延迟多少毫秒后开始运行 //removeCallbacks方法是删除指定的Runnable对象,使线程对象停止运行。 mCameraSwitchBtn.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { mHandler.removeCallbacks(mSwitcher); mHandler.postDelayed(mSwitcher, 100); } }); mCaptureFrameBtn.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { mHandler.removeCallbacks(mScreenshooter); mHandler.postDelayed(mScreenshooter, 100); } }); mEncodingOrientationSwitcherBtn = (Button) findViewById(R.id.orientation_btn); mEncodingOrientationSwitcherBtn.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { mHandler.removeCallbacks(mEncodingOrientationSwitcher); mHandler.post(mEncodingOrientationSwitcher); } }); //进度条-调节美颜效果程度 SeekBar seekBarBeauty = (SeekBar) findViewById(R.id.beautyLevel_seekBar); seekBarBeauty.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() { @Override public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) { CameraStreamingSetting.FaceBeautySetting fbSetting = mCameraStreamingSetting.getFaceBeautySetting(); fbSetting.beautyLevel = progress / 100.0f; fbSetting.whiten = progress / 100.0f; fbSetting.redden = progress / 100.0f; mCameraStreamingManager.updateFaceBeautySetting(fbSetting); } @Override public void onStartTrackingTouch(SeekBar seekBar) { } @Override public void onStopTrackingTouch(SeekBar seekBar) { } }); initButtonText(); } private void initButtonText() { updateFLButtonText(); // updateCameraSwitcherButtonText(mCameraStreamingSetting.getReqCameraId()); mCaptureFrameBtn.setText("截帧"); //截屏 Capture updateFBButtonText(); updateMuteButtonText(); updateOrientationBtnText(); } private void updateOrientationBtnText() { //横屏和竖屏 if (isEncOrientationPort) { mEncodingOrientationSwitcherBtn.setText("切横屏");//横屏 Land } else { mEncodingOrientationSwitcherBtn.setText("切竖屏");//竖屏 Port } } protected void setFocusAreaIndicator() { if (mRotateLayout == null) { mRotateLayout = (RotateLayout)findViewById(R.id.focus_indicator_rotate_layout); mCameraStreamingManager.setFocusAreaIndicator(mRotateLayout, mRotateLayout.findViewById(R.id.focus_indicator)); } } private void updateFBButtonText() { if (mFaceBeautyBtn != null) { mFaceBeautyBtn.setText(mIsNeedFB ? "关闭美颜" : "开启美颜"); //美颜开关 FB Off FB On } } //Filter private void updateFLButtonText() { if (mFilterBtn != null) { mFilterBtn.setText(mIsNeedFL ? "关闭滤镜" : "开启滤镜"); //滤镜开关 FB Off FB On } } private void updateMuteButtonText() { if (mMuteButton != null) { mMuteButton.setText(mIsNeedMute ? "恢复声音" : "静音"); //有声 Unmute or 无声 Mute } } private void updateCameraSwitcherButtonText(int camId) { if (mCameraSwitchBtn == null) { return; } if (camId == Camera.CameraInfo.CAMERA_FACING_FRONT) { mCameraSwitchBtn.setText("后摄"); //后摄 Back } else { mCameraSwitchBtn.setText("前摄"); //前摄 Front } } private void saveToSDCard(String filename, Bitmap bmp) throws IOException { if(Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) { File file = new File(Environment.getExternalStorageDirectory(), filename); BufferedOutputStream bos = null; try { bos = new BufferedOutputStream(new FileOutputStream(file)); bmp.compress(Bitmap.CompressFormat.PNG, 90, bos); bmp.recycle(); bmp = null; } finally { if (bos != null) bos.close(); } final String info = "Save frame to:" + Environment.getExternalStorageDirectory().getAbsolutePath() + "/" + filename; runOnUiThread(new Runnable() { @Override public void run() { Toast.makeText(mContext, info, Toast.LENGTH_LONG).show(); } }); } } private static DnsManager getMyDnsManager() { IResolver r0 = new DnspodFree(); IResolver r1 = AndroidDnsServer.defaultResolver(); IResolver r2 = null; try { r2 = new Resolver(InetAddress.getByName("119.29.29.29")); } catch (IOException ex) { ex.printStackTrace(); } return new DnsManager(NetworkInfo.normal, new IResolver[]{r0, r1, r2}); } }
相关文章推荐
- 七牛---关于Ruby SDK的各种Demo
- 七牛---关于Node.js SDK的各种Demo
- 七牛---Pili直播推流SDK问题总结
- 【转自戴Sir】七牛关于Python SDK的各种Demo
- 七牛---关于PHP SDK的各种Demo
- 七牛---关于JAVA SDK的各种Demo
- 七牛---关于GO SDK的各种Demo
- 七牛---关于C# SDK的各种Demo
- 七牛---各种SDK Demo汇总
- 七牛---关于PHP SDK的各种Demo
- 七牛---关于Python SDK的各种Demo
- 实时显示倒计时状态demo(附详细的注释)
- 转:iOS app支付宝接口调用的一点总结(补充支付宝SDK&Demo下载地址)
- 七牛android-7.0demo工程
- 微信JS SDK PHP Demo
- 微信JS-SDK应用DEMO
- Eclipse下如何运行微信SDK_Demo
- Android Manifest之<uses-sdk>元素中文注释
- IOS调试下载的demo出现说项目不能在什么的SDK调试