修改数据库密码 进不了网站后台,界首市合肥网络推广外包,啥也不懂怎么建设网站,颜金华深圳广告公司背景
我们在做Android平台RTSP或者RTMP播放器开发的时候#xff0c;需要注意的点非常多#xff0c;以下#xff0c;以大牛直播SDK(官方)的接口为例#xff0c;大概介绍下相关接口设计#xff1a;
接口设计
1. Open() 接口
Open接口的目的#xff0c;主要是创建实例需要注意的点非常多以下以大牛直播SDK(官方)的接口为例大概介绍下相关接口设计
接口设计
1. Open() 接口
Open接口的目的主要是创建实例正常返回player实例句柄如有多路播放诉求创建多个实例即可。 /*** Initialize Player(启动播放实例)** param ctx: get by this.getApplicationContext()** preThis function must be called firstly./pre** return player handle if successful, if return 0, which means init failed. */public native long SmartPlayerOpen(Object ctx);
2. Close()接口
Close接口和Open()接口对应负责释放相应实例的资源调用Close()接口后记得实例句柄置0即可。
注意比如一个实例既可以实现播放又可同时录像亦或拉流转发这种情况下调Close()接口时需要确保录像、拉流都正常停止后再调用。
/*** 关闭播放实例结束时必须调用close接口释放资源** param handle: return value from SmartPlayerOpen()** pre NOTE: it could not use player handle after call this function. /pre ** return {0} if successful*/public native int SmartPlayerClose(long handle);
3. 网络状态回调
一个好的播放器好的状态回调必不可少比如网络连通状态、快照、录像状态、当前下载速度等实时反馈可以让上层开发者更好的掌控播放端状态给用户更好的播放体验。 /*** Set callback event(设置事件回调)** param handle: return value from SmartPlayerOpen()** param callbackv2: callback function** return {0} if successful*/public native int SetSmartPlayerEventCallbackV2(long handle, NTSmartEventCallbackV2 callbackv2);demo实现实例 class EventHandeV2 implements NTSmartEventCallbackV2 {Overridepublic void onNTSmartEventCallbackV2(long handle, int id, long param1,long param2, String param3, String param4, Object param5) {//Log.i(TAG, EventHandeV2: handle handle id: id);String player_event ;switch (id) {case NTSmartEventID.EVENT_DANIULIVE_ERC_PLAYER_STARTED:player_event 开始..;break;case NTSmartEventID.EVENT_DANIULIVE_ERC_PLAYER_CONNECTING:player_event 连接中..;break;case NTSmartEventID.EVENT_DANIULIVE_ERC_PLAYER_CONNECTION_FAILED:player_event 连接失败..;break;case NTSmartEventID.EVENT_DANIULIVE_ERC_PLAYER_CONNECTED:player_event 连接成功..;break;case NTSmartEventID.EVENT_DANIULIVE_ERC_PLAYER_DISCONNECTED:player_event 连接断开..;break;case NTSmartEventID.EVENT_DANIULIVE_ERC_PLAYER_STOP:player_event 停止播放..;break;case NTSmartEventID.EVENT_DANIULIVE_ERC_PLAYER_RESOLUTION_INFO:player_event 分辨率信息: width: param1 , height: param2;break;case NTSmartEventID.EVENT_DANIULIVE_ERC_PLAYER_NO_MEDIADATA_RECEIVED:player_event 收不到媒体数据可能是url错误..;break;case NTSmartEventID.EVENT_DANIULIVE_ERC_PLAYER_SWITCH_URL:player_event 切换播放URL..;break;case NTSmartEventID.EVENT_DANIULIVE_ERC_PLAYER_CAPTURE_IMAGE:player_event 快照: param1 路径 param3;if (param1 0) {player_event player_event , 截取快照成功;} else {player_event player_event , 截取快照失败;}break;case NTSmartEventID.EVENT_DANIULIVE_ERC_PLAYER_RECORDER_START_NEW_FILE:player_event [record]开始一个新的录像文件 : param3;break;case NTSmartEventID.EVENT_DANIULIVE_ERC_PLAYER_ONE_RECORDER_FILE_FINISHED:player_event [record]已生成一个录像文件 : param3;break;case NTSmartEventID.EVENT_DANIULIVE_ERC_PLAYER_START_BUFFERING:Log.i(TAG, Start Buffering);break;case NTSmartEventID.EVENT_DANIULIVE_ERC_PLAYER_BUFFERING:Log.i(TAG, Buffering: param1 %);break;case NTSmartEventID.EVENT_DANIULIVE_ERC_PLAYER_STOP_BUFFERING:Log.i(TAG, Stop Buffering);break;case NTSmartEventID.EVENT_DANIULIVE_ERC_PLAYER_DOWNLOAD_SPEED:player_event download_speed: param1 Byte/s , (param1 * 8 / 1000) kbps , (param1 / 1024) KB/s;break;case NTSmartEventID.EVENT_DANIULIVE_ERC_PLAYER_RTSP_STATUS_CODE:Log.e(TAG, RTSP error code received, please make sure username/password is correct, error code: param1);player_event RTSP error code: param1;break;case NTSmartEventID.EVENT_DANIULIVE_ERC_PLAYER_NEED_KEY:Log.e(TAG, RTMP加密流请设置播放需要的Key..);player_event RTMP加密流请设置播放需要的Key..;break;case NTSmartEventID.EVENT_DANIULIVE_ERC_PLAYER_KEY_ERROR:Log.e(TAG, RTMP加密流Key错误请重新设置..);player_event RTMP加密流Key错误请重新设置..;break;}if (player_event.length() 0) {Log.i(TAG, player_event);Message message new Message();message.what PLAYER_EVENT_MSG;message.obj player_event;handler.sendMessage(message);}}}
4. 软解码还是硬解码
随着Android发展越来越好各个厂商芯片对硬解码的支持也越来越友好一般情况下如果适合通用的产品在设备性能保障的情况下优先建议软解如果特定机型设备可酌情考虑硬解硬解码又分为264硬解、HEVC硬解直接设置surface模式的硬解接口如下 /*** Set Video H.264 HW decoder(设置H.264硬解码)** param handle: return value from SmartPlayerOpen()** param isHWDecoder: 0: software decoder; 1: hardware decoder.** return {0} if successful*/public native int SetSmartPlayerVideoHWDecoder(long handle, int isHWDecoder);/*** Set Video H.265(hevc) HW decoder(设置H.265硬解码)** param handle: return value from SmartPlayerOpen()** param isHevcHWDecoder: 0: software decoder; 1: hardware decoder.** return {0} if successful*/public native int SetSmartPlayerVideoHevcHWDecoder(long handle, int isHevcHWDecoder);设置surface模式的硬解 /*** 设置视频硬解码下Mediacodec自行绘制模式此种模式下硬解码兼容性和效率更好回调YUV/RGB和快照功能将不可用** param handle: return value from SmartPlayerOpen()** param isHWRenderMode: 0: not enable; 1: 用SmartPlayerSetSurface设置的surface自行绘制** return {0} if successful*/public native int SmartPlayerSetHWRenderMode(long handle, int isHWRenderMode);/*** 更新硬解码surface** param handle: return value from SmartPlayerOpen()** return {0} if successful*/public native int SmartPlayerUpdateHWRenderSurface(long handle);
5. 音频输出类型
音频输出android平台支持audiotrack模式和opensl es模式一般来说考虑到设备通用性建议采用audiotrack模式。 /*** Set AudioOutput Type(设置audio输出类型)** param handle: return value from SmartPlayerOpen()** param use_audiotrack:** pre NOTE: if use_audiotrack with 0: it will use auto-select output devices; if with 1: will use audio-track mode. /pre** return {0} if successful*/public native int SmartPlayerSetAudioOutputType(long handle, int use_audiotrack);6. 缓冲时间设置
缓冲时间顾名思义缓存多少数据才开始播放比如设置2000ms的buffer time直播模式下收到2秒数据后才正常播放。
加大buffer time会增大播放延迟好处是网络抖动的时候流畅性更好。 /*** Set buffer(设置缓冲时间单位:毫秒)** param handle: return value from SmartPlayerOpen()** param buffer:** pre NOTE: Unit is millisecond, range is 0-5000 ms /pre** return {0} if successful*/public native int SmartPlayerSetBuffer(long handle, int buffer);7. 实时静音、实时音量调节
实时静音、实时音量调节顾名思义播放端可以实时调整播放音量或者直接静音掉特别是多路播放场景下非常有必要。
此外我们还提供了音量放大的功能支持放大至原始音量的2倍。 /*** Set mute or not(设置实时静音)** param handle: return value from SmartPlayerOpen()** param is_mute: if with 1:mute, if with 0: does not mute** return {0} if successful*/public native int SmartPlayerSetMute(long handle, int is_mute);/*** 设置播放音量** param handle: return value from SmartPlayerOpen()** param volume: 范围是[0, 100], 0是静音100是最大音量, 默认是100** return {0} if successful*/public native int SmartPlayerSetAudioVolume(long handle, int volume);8. RTSP TCP-UDP模式设置、超时时间设置或模式切换
有的RTSP服务器或摄像机只支持RTSP TCP模式或者UDP模式这个时候默认设置TCP、UDP模式就至关重要此外我们还设计支持如TCP或UDP模式收不到数据在超时时间后可以自动切换到UDP或TCP。 /*** 设置RTSP TCP/UDP模式(默认UDP模式)** param handle: return value from SmartPlayerOpen()** param is_using_tcp: if with 1, it will via TCP mode, while 0 with UDP mode** return {0} if successful*/public native int SmartPlayerSetRTSPTcpMode(long handle, int is_using_tcp);/*** 设置RTSP超时时间, timeout单位为秒必须大于0** param handle: return value from SmartPlayerOpen()** param timeout: RTSP timeout setting** return {0} if successful*/public native int SmartPlayerSetRTSPTimeout(long handle, int timeout);/*** 设置RTSP TCP/UDP自动切换** param handle: return value from SmartPlayerOpen()** NOTE: 对于RTSP来说有些可能支持rtp over udp方式有些可能支持使用rtp over tcp方式.* 为了方便使用有些场景下可以开启自动尝试切换开关, 打开后如果udp无法播放sdk会自动尝试tcp, 如果tcp方式播放不了,sdk会自动尝试udp.** param is_auto_switch_tcp_udp 如果设置1的话, sdk将在tcp和udp之间尝试切换播放如果设置为0则不尝试切换.** return {0} if successful*/public native int SmartPlayerSetRTSPAutoSwitchTcpUdp(long handle, int is_auto_switch_tcp_udp);9. 快速启动
快速启动主要是针对服务器缓存GOP的场景下快速刷到最新的数据确保画面的持续性。 /*** Set fast startup(设置快速启动模式此模式针对服务器缓存GOP的场景有效)** param handle: return value from SmartPlayerOpen()** param is_fast_startup: if with 1, it will second play back, if with 0: does not it** return {0} if successful*/public native int SmartPlayerSetFastStartup(long handle, int is_fast_startup);
10. 低延迟模式
低延迟模式下设置buffer time为0延迟更低适用于比如需要操控控制的超低延迟场景下。 /*** Set low latency mode(设置低延迟模式)** param handle: return value from SmartPlayerOpen()** param mode: if with 1, low latency mode, if with 0: normal mode** return {0} if successful*/public native int SmartPlayerSetLowLatencyMode(long handle, int mode);
11. 视频view旋转、水平|垂直翻转
接口主要用于比如原始的视频倒置等场景下设备端无法调整时通过播放端完成图像的正常角度播放。 /*** 设置视频垂直反转** param handle: return value from SmartPlayerOpen()** param is_flip 0: 不反转, 1: 反转** return {0} if successful*/public native int SmartPlayerSetFlipVertical(long handle, int is_flip);/*** 设置视频水平反转** param handle: return value from SmartPlayerOpen()** param is_flip 0: 不反转, 1: 反转** return {0} if successful*/public native int SmartPlayerSetFlipHorizontal(long handle, int is_flip);/*** 设置顺时针旋转, 注意除了0度之外 其他角度都会额外消耗性能** param handle: return value from SmartPlayerOpen()** param degress 当前支持 0度90度, 180度, 270度 旋转** return {0} if successful*/public native int SmartPlayerSetRotation(long handle, int degress);
12. 设置实时回调下载速度
调用实时下载速度接口通过设置下载速度时间间隔和是否需要上报当前下载速度实现APP层和底层SDK更友好的交互。 /*** Set report download speed(设置实时回调下载速度)** param handle: return value from SmartPlayerOpen()** param is_report: if with 1, it will report download speed, it with 0: does not it.** param report_interval: report interval, unit is second, it must be greater than 0.** return {0} if successful*/public native int SmartPlayerSetReportDownloadSpeed(long handle, int is_report, int report_interval );13. 实时快照
简单来说播放过程中是不是要存取当前的播放画面。 /*** Set if needs to save image during playback stream(是否启动快照功能)** param handle: return value from SmartPlayerOpen()** param is_save_image: if with 1, it will save current image via the interface of SmartPlayerSaveCurImage(), if with 0: does not it** return {0} if successful*/public native int SmartPlayerSaveImageFlag(long handle, int is_save_image);/*** Save current image during playback stream(实时快照)** param handle: return value from SmartPlayerOpen()** param imageName: image name, which including fully path, /sdcard/daniuliveimage/daniu.png, etc.** return {0} if successful*/public native int SmartPlayerSaveCurImage(long handle, String imageName);14. 扩展录像操作
播放端录像我们做的非常细化比如可以只录制音频或者只录制视频设置录像存储路径设置单个文件size如果非AAC数据可以转AAC后再录像。 /*** Create file directory(创建录像目录)** param path, E.g: /sdcard/daniulive/rec** pre The interface is only used for recording the stream data to local side. /pre** return {0} if successful*/public native int SmartPlayerCreateFileDirectory(String path);/*** Set recorder directory(设置录像目录)** param handle: return value from SmartPlayerOpen()** param path: the directory of recorder file** pre NOTE: make sure the path should be existed, or else the setting failed. /pre** return {0} if successful*/public native int SmartPlayerSetRecorderDirectory(long handle, String path);/*** Set the size of every recorded file(设置单个录像文件大小如超过设定大小则自动切换到下个文件录制)** param handle: return value from SmartPlayerOpen()** param size: (MB), (5M~500M), if not in this range, set default size with 200MB.** return {0} if successful*/public native int SmartPlayerSetRecorderFileMaxSize(long handle, int size);/** 设置录像时音频转AAC编码的开关** param handle: return value from SmartPlayerOpen()** aac比较通用sdk增加其他音频编码(比如speex, pcmu, pcma等)转aac的功能.** param is_transcode: 设置为1的话如果音频编码不是aac则转成aac如果是aac则不做转换. 设置为0的话则不做任何转换. 默认是0.** 注意: 转码会增加性能消耗** return {0} if successful*/public native int SmartPlayerSetRecorderAudioTranscodeAAC(long handle, int is_transcode);/**设置是否录视频默认的话如果视频源有视频就录没有就没得录, 但有些场景下可能不想录制视频只想录音频所以增加个开关**param is_record_video: 1 表示录制视频, 0 表示不录制视频, 默认是1** return {0} if successful*/public native int SmartPlayerSetRecorderVideo(long handle, int is_record_video);/**设置是否录音频默认的话如果视频源有音频就录没有就没得录, 但有些场景下可能不想录制音频只想录视频所以增加个开关**param is_record_audio: 1 表示录制音频, 0 表示不录制音频, 默认是1** return {0} if successful*/public native int SmartPlayerSetRecorderAudio(long handle, int is_record_audio);/*** Start recorder stream(开始录像)** param handle: return value from SmartPlayerOpen()** return {0} if successful*/public native int SmartPlayerStartRecorder(long handle);/*** Stop recorder stream(停止录像)** param handle: return value from SmartPlayerOpen()** return {0} if successful*/public native int SmartPlayerStopRecorder(long handle);15. 拉流回调编码后的数据配合转发模块使用
拉流回调编码后的数据主要是为了配合转发模块使用比如拉取rtsp流数据直接转RTMP推送到RTMP服务。 /** 设置拉流时音频转AAC编码的开关** param handle: return value from SmartPlayerOpen()** aac比较通用sdk增加其他音频编码(比如speex, pcmu, pcma等)转aac的功能.** param is_transcode: 设置为1的话如果音频编码不是aac则转成aac, 如果是aac则不做转换. 设置为0的话则不做任何转换. 默认是0.* 注意: 转码会增加性能消耗** return {0} if successful*/public native int SmartPlayerSetPullStreamAudioTranscodeAAC(long handle, int is_transcode);/*** Start pull stream(开始拉流用于数据转发只拉流不播放)** param handle: return value from SmartPlayerOpen()** return {0} if successful*/public native int SmartPlayerStartPullStream(long handle);/*** Stop pull stream(停止拉流)** param handle: return value from SmartPlayerOpen()** return {0} if successful*/public native int SmartPlayerStopPullStream(long handle);/*** Set Audio Data Callback(设置回调编码后音频数据)** param handle: return value from SmartPlayerOpen()** param audio_data_callback: Audio Data Callback.** return {0} if successful*/public native int SmartPlayerSetAudioDataCallback(long handle, Object audio_data_callback);/*** Set Video Data Callback(设置回调编码后视频数据)** param handle: return value from SmartPlayerOpen()** param video_data_callback: Video Data Callback.** return {0} if successful*/public native int SmartPlayerSetVideoDataCallback(long handle, Object video_data_callback);16. H264用户数据回调或SEI数据回调
如发送端在264编码时加了自定义的user data数据可以通过以下接口实现数据回调如需直接回调SEI数据调下面SEI回调接口即可。 /*** Set user data Callback(设置回调SEI扩展用户数据)** param handle: return value from SmartPlayerOpen()** param user_data_callback: user data callback.** return {0} if successful*/public native int SmartPlayerSetUserDataCallback(long handle, Object user_data_callback);/*** Set SEI data Callback(设置回调SEI数据)** param handle: return value from SmartPlayerOpen()** param sei_data_callback: sei data callback.** return {0} if successful*/public native int SmartPlayerSetSEIDataCallback(long handle, Object sei_data_callback);17. 设置回调解码后YUV、RGB数据
如需对解码后的yuv或rgb数据进行二次处理如人脸识别等可以通回调yuv rgb接口实现数据二次处理。
以YUV为例 class I420ExternalRender implements NTExternalRender {// public static final int NT_FRAME_FORMAT_RGBA 1;// public static final int NT_FRAME_FORMAT_ABGR 2;// public static final int NT_FRAME_FORMAT_I420 3;private int width_ 0;private int height_ 0;private int y_row_bytes_ 0;private int u_row_bytes_ 0;private int v_row_bytes_ 0;private ByteBuffer y_buffer_ null;private ByteBuffer u_buffer_ null;private ByteBuffer v_buffer_ null;Overridepublic int getNTFrameFormat() {Log.i(TAG, I420ExternalRender::getNTFrameFormat return NT_FRAME_FORMAT_I420);return NT_FRAME_FORMAT_I420;}Overridepublic void onNTFrameSizeChanged(int width, int height) {width_ width;height_ height;y_row_bytes_ (width_ 15) (~15);u_row_bytes_ ((width_ 1) / 2 15) (~15);v_row_bytes_ ((width_ 1) / 2 15) (~15);y_buffer_ ByteBuffer.allocateDirect(y_row_bytes_ * height_);u_buffer_ ByteBuffer.allocateDirect(u_row_bytes_* ((height_ 1) / 2));v_buffer_ ByteBuffer.allocateDirect(v_row_bytes_* ((height_ 1) / 2));Log.i(TAG, I420ExternalRender::onNTFrameSizeChanged width_ width_ height_ height_ y_row_bytes_ y_row_bytes_ u_row_bytes_ u_row_bytes_ v_row_bytes_ v_row_bytes_);}Overridepublic ByteBuffer getNTPlaneByteBuffer(int index) {if (index 0) {return y_buffer_;} else if (index 1) {return u_buffer_;} else if (index 2) {return v_buffer_;} else {Log.e(TAG, I420ExternalRender::getNTPlaneByteBuffer index error: index);return null;}}Overridepublic int getNTPlanePerRowBytes(int index) {if (index 0) {return y_row_bytes_;} else if (index 1) {return u_row_bytes_;} else if (index 2) {return v_row_bytes_;} else {Log.e(TAG, I420ExternalRender::getNTPlanePerRowBytes index error: index);return 0;}}public void onNTRenderFrame(int width, int height, long timestamp) {if (y_buffer_ null)return;if (u_buffer_ null)return;if (v_buffer_ null)return;y_buffer_.rewind();u_buffer_.rewind();v_buffer_.rewind();/*if ( !is_saved_image ){is_saved_image true;int y_len y_row_bytes_*height_;int u_len u_row_bytes_*((height_1)/2);int v_len v_row_bytes_*((height_1)/2);int data_len y_len (y_row_bytes_*((height_1)/2));byte[] nv21_data new byte[data_len];byte[] u_data new byte[u_len];byte[] v_data new byte[v_len];y_buffer_.get(nv21_data, 0, y_len);u_buffer_.get(u_data, 0, u_len);v_buffer_.get(v_data, 0, v_len);int[] strides new int[2];strides[0] y_row_bytes_;strides[1] y_row_bytes_;int loop_row_c ((height_1)/2);int loop_c ((width_1)/2);int dst_row y_len;int src_v_row 0;int src_u_row 0;for ( int i 0; i loop_row_c; i){int dst_pos dst_row;for ( int j 0; j loop_c; j ){nv21_data[dst_pos] v_data[src_v_row j];nv21_data[dst_pos] u_data[src_u_row j];}dst_row y_row_bytes_;src_v_row v_row_bytes_;src_u_row u_row_bytes_;}String imagePath /sdcard / testonv21 .jpeg;Log.e(TAG, I420ExternalRender::begin test save iamge image_path: imagePath);try{File file new File(imagePath);FileOutputStream image_os new FileOutputStream(file);YuvImage image new YuvImage(nv21_data, ImageFormat.NV21, width_, height_, strides);image.compressToJpeg(new android.graphics.Rect(0, 0, width_, height_), 50, image_os);image_os.flush();image_os.close();}catch(IOException e){e.printStackTrace();}Log.e(TAG, I420ExternalRender::begin test save iamge--);}*/Log.i(TAG, I420ExternalRender::onNTRenderFrame w width h height timestamp timestamp);// copy buffer// test// byte[] test_buffer new byte[16];// y_buffer_.get(test_buffer);// Log.i(TAG, I420ExternalRender::onNTRenderFrame y data: bytesToHexString(test_buffer));// u_buffer_.get(test_buffer);// Log.i(TAG, I420ExternalRender::onNTRenderFrame u data: bytesToHexString(test_buffer));// v_buffer_.get(test_buffer);// Log.i(TAG, I420ExternalRender::onNTRenderFrame v data: bytesToHexString(test_buffer));}}18. 设置视频画面填充模式
设置视频画面的填充模式如填充整个view、等比例填充view如不设置默认填充整个view。
相关接口设计如下 /*** 设置视频画面的填充模式如填充整个view、等比例填充view如不设置默认填充整个view* param handle: return value from SmartPlayerOpen()* param render_scale_mode 0: 填充整个view; 1: 等比例填充view, 默认值是0* return {0} if successful*/public native int SmartPlayerSetRenderScaleMode(long handle, int render_scale_mode);
19. 设置SurfaceView模式下render类型
format: 0: RGB565格式如不设置默认此模式; 1: ARGB8888格式 /*** 设置SurfaceView模式下(NTRenderer.CreateRenderer第二个参数传false的情况)render类型** param handle: return value from SmartPlayerOpen()** param format: 0: RGB565格式如不设置默认此模式; 1: ARGB8888格式** return {0} if successful*/public native int SmartPlayerSetSurfaceRenderFormat(long handle, int format);20. 设置surfaceview模式下抗锯齿
需要注意的是抗锯齿模式开启后会增加性能消耗。 /*** 设置SurfaceView模式下(NTRenderer.CreateRenderer第二个参数传false的情况)抗锯齿效果注意抗锯齿模式开启后可能会影像性能请慎用** param handle: return value from SmartPlayerOpen()** param isEnableAntiAlias: 0: 如不设置默认不开启抗锯齿模式; 1: 开启抗锯齿模式** return {0} if successful*/public native int SmartPlayerSetSurfaceAntiAlias(long handle, int isEnableAntiAlias);
总结
以上就是Android平台RTSP、RTMP播放器接口设计需要参考的点对于大多数开发者来说不一定需要实现上述所有部分只要按照产品诉求实现其中的40%就足够满足特定场景使用了。
一个好的播放器特别是要满足低延迟稳定的播放毫秒级延迟需要注意的点远不止如此感兴趣的开发者可以参考blog其他文章。