最近,去了广东省电力设计院做实习生。外聘的那个项目经理让我一个实习生做流媒体这一块。。我也是醉。没办法,硬着头皮上呗。还好找到了一个开源的流媒体解决方案。改改他们的代码。就能用了。但是大疆回传的视频流还是很坑爹的。
首先。大疆的SDK使用要用USB连着他那个手柄。我了个大艹。连着这个手柄我就不能逐步调试了啊。简直设计脑残。嗯。吐槽完了。
1.现在大疆SDK经过更新。这个回传的videoBuffer的开头就有数据。数据不会再分隔在两个videoBuffer中了。
2.数据没有 0x00 0x00 0x00 0x01 0x09的开头了。一上来就是数据。
3.数据后边有大量冗余。全是0x00。只用读出他给的大小就好。就是那个Size参数
4.读出无冗余的数据后,把他官网说的I帧(raw文件夹下的),拼在这些数据前面,就完成了
5.之后你拿到这个数据,该推送到RTP就推送,该解码就解码。
6.不得不说大疆还是很坑爹的。你更新了数据格式也不说。又不能逐步调试。
嗯。时间过去了三年,DJI SDK也不知道更新了多少版。我也从一个Android实习改做后端,现在又改做架构。
刚刚查看了一下,现在获取I帧的方式与以前不同了,也许是DJI的机型增多,变焦的也出了,不能手动下载I帧文件了。
可以看他的Github
现在对于解码的描述在这个文件里:DJIVideoStreamDecoder.java
以下是对步骤说明的一些摘抄:
/**
* This class is a helper class for hardware decoding. Please follow the following steps to use it:
*
* 1. Initialize and set the instance as a listener of NativeDataListener to receive the frame data.
*
* 2. Send the raw data from camera to ffmpeg for frame parsing.
*
* 3. Get the parsed frame data from ffmpeg parsing frame callback and cache the parsed framed data into the frameQueue.
*
* 4. Initialize the MediaCodec as a decoder and then check whether there is any i-frame in the MediaCodec. If not, get
* the default i-frame from sdk resource and insert it at the head of frameQueue. Then dequeue the framed data from the
* frameQueue and feed it(which is Byte buffer) into the MediaCodec.
*
* 5. Get the output byte buffer from MediaCodec, if a surface(Video Previewing View) is configured in the MediaCodec,
* the output byte buffer is only need to be released. If not, the output yuv data should invoke the callback and pass
* it out to external listener, it should also be released too.
*
* 6. Release the ffmpeg and the MediaCodec, stop the decoding thread.
*/
现在的I帧被内置在了SDK的raw文件里,刚刚给出的类里现在有个getIframeRawId函数,是直接从SDK里获取I帧的,使用一个一个的Switch-Case和If判别R.raw的ID,得到资源ID。
/**
* Get the resource ID of the IDR frame.
* @param pModel Product model of connecting DJI product.
* @param width Width of current video stream.
* @return Resource ID of the IDR frame
*/
public int getIframeRawId(Model pModel, int width) {
int iframeId = R.raw.iframe_1280x720_ins;
switch(pModel) {
case PHANTOM_3_ADVANCED:
case PHANTOM_3_STANDARD:
if (width == 960) {
//for photo mode, 960x720, GDR
iframeId = R.raw.iframe_960x720_3s;
} else if (width == 640){
iframeId = R.raw.iframe_640x368_osmo_gop;
} else {
//for record mode, 1280x720, GDR
iframeId = R.raw.iframe_1280x720_3s;
}
break;
case INSPIRE_1: {
DataCameraGetPushStateInfo.CameraType cameraType = DataCameraGetPushStateInfo.getInstance().getCameraType();
if (cameraType == DataCameraGetPushStateInfo.CameraType.DJICameraTypeCV600) { //ZENMUSE_Z3
if (width == 960) {
//for photo mode, 960x720, GDR
iframeId = R.raw.iframe_960x720_3s;
} else if (width == 640){
iframeId = R.raw.iframe_640x368_osmo_gop;
} else {
//for record mode, 1280x720, GDR
iframeId = R.raw.iframe_1280x720_3s;
}
}
break;
}
case Phantom_3_4K:
switch(width) {
case 640:
//for P3-4K with resolution 640*480
iframeId = R.raw.iframe_640x480;
break;
case 848:
//for P3-4K with resolution 848*480
iframeId = R.raw.iframe_848x480;
break;
case 896:
iframeId = R.raw.iframe_896x480;
break;
case 960:
//DJILog.i(TAG, "Selected Iframe=iframe_960x720_3s");
//for photo mode, 960x720, GDR
iframeId = R.raw.iframe_960x720_3s;
break;
default:
iframeId = R.raw.iframe_1280x720_3s;
break;
}
break;
case OSMO:
if (DataCameraGetPushStateInfo.getInstance().getVerstion() >= 4) {
iframeId = -1;
} else {
iframeId = R.raw.iframe_1280x720_ins;
}
break;
case OSMO_PLUS:
if (width == 960) {
iframeId = R.raw.iframe_960x720_osmo_gop;
} else if (width==1280) {
//for record mode, 1280x720, GDR
//DJILog.i(TAG, "Selected Iframe=iframe_1280x720_3s");
// iframeId = R.raw.iframe_1280x720_3s;
iframeId = R.raw.iframe_1280x720_osmo_gop;
} else if (width == 640){
iframeId = R.raw.iframe_640x368_osmo_gop;
} else {
iframeId = R.raw.iframe_1280x720_3s;
}
break;
case OSMO_PRO:
case OSMO_RAW:
iframeId = R.raw.iframe_1280x720_ins;
break;
case MAVIC_PRO: //product small drone
case MAVIC_2:
if (((Aircraft) DJISDKManager.getInstance().getProduct()).getMobileRemoteController() != null) {
iframeId = R.raw.iframe_1280x720_wm220;
} else{
iframeId = -1;
}
break;
case Spark:
switch (width) {
case 1280: // 与P4相同
iframeId = R.raw.iframe_1280x720_p4;
break;
case 1024:
iframeId = R.raw.iframe_1024x768_wm100;
break;
default:
iframeId = R.raw.iframe_1280x720_p4;
break;
}
break;
case MAVIC_AIR:
switch (height) {
case 960:
iframeId = R.raw.iframe_1280x960_wm230;
break;
case 720:
iframeId = R.raw.iframe_1280x720_wm230;
break;
default:
iframeId = R.raw.iframe_1280x720_wm230;
break;
}
break;
case PHANTOM_4:
iframeId = R.raw.iframe_1280x720_p4;
break;
case PHANTOM_4_PRO: // p4p
case PHANTOM_4_ADVANCED: // p4p
switch (width) {
case 1280:
iframeId = R.raw.iframe_p4p_720_16x9;
break;
case 960:
iframeId = R.raw.iframe_p4p_720_4x3;
break;
case 1088:
iframeId = R.raw.iframe_p4p_720_3x2;
break;
case 1344:
iframeId = R.raw.iframe_p4p_1344x720;
break;
case 1440:
iframeId = R.raw.iframe_1440x1088_wm620;
break;
case 1920:
switch (height) {
case 1024:
iframeId = R.raw.iframe_1920x1024_wm620;
break;
case 800:
iframeId = R.raw.iframe_1920x800_wm620;
break;
default:
iframeId = R.raw.iframe_1920x1088_wm620;
break;
}
break;
default:
iframeId = R.raw.iframe_p4p_720_16x9;
break;
}
break;
case MATRICE_600:
case MATRICE_600_PRO: {
DataCameraGetPushStateInfo.CameraType cameraType = DataCameraGetPushStateInfo.getInstance().getCameraType();
if (width == 720 && height == 480) {
iframeId = R.raw.iframe_720x480_m600;
} else if (width == 720 && height == 576) {
iframeId = R.raw.iframe_720x576_m600;
} else {
if (width == 1280 && height == 720) {
if (cameraType == DataCameraGetPushStateInfo.CameraType.DJICameraTypeGD600) {
iframeId = R.raw.iframe_gd600_1280x720;
} else if (cameraType == DataCameraGetPushStateInfo.CameraType.DJICameraTypeCV600) {
iframeId = R.raw.iframe_1280x720_osmo_gop;
} else if (cameraType == DataCameraGetPushStateInfo.CameraType.DJICameraTypeFC350) {
iframeId = R.raw.iframe_1280x720_ins;
} else {
iframeId = R.raw.iframe_1280x720_m600;
}
} else if (width == 1920 && (height == 1080 || height == 1088)) {
iframeId = R.raw.iframe_1920x1080_m600;
} else if (width == 1080 && height == 720) {
iframeId = R.raw.iframe_1080x720_gd600;
} else if (width == 960 && height == 720) {
iframeId = R.raw.iframe_960x720_3s;
} else {
iframeId = -1;
}
}
break;
}
case MATRICE_100: {
DataCameraGetPushStateInfo.CameraType cameraType = DataCameraGetPushStateInfo.getInstance().getCameraType();
if (cameraType == DataCameraGetPushStateInfo.CameraType.DJICameraTypeGD600) {
if (width == 1280 && height == 720){
iframeId = R.raw.iframe_gd600_1280x720;
}else {
iframeId = R.raw.iframe_1080x720_gd600;
}
} else {
iframeId = R.raw.iframe_1280x720_ins;
}
break;
}
case MATRICE_200:
case MATRICE_210:
case MATRICE_210_RTK:
case INSPIRE_2: //inspire2
DataCameraGetPushStateInfo.CameraType cameraType = DataCameraGetPushStateInfo.getInstance().getCameraType(0);
if(cameraType == DataCameraGetPushStateInfo.CameraType.DJICameraTypeGD600) {
iframeId = R.raw.iframe_1080x720_gd600;
} else {
if (width == 640 && height == 368) {
DJILog.i(TAG, "Selected Iframe=iframe_640x368_wm620");
iframeId = R.raw.iframe_640x368_wm620;
}
if (width == 608 && height == 448) {
DJILog.i(TAG, "Selected Iframe=iframe_608x448_wm620");
iframeId = R.raw.iframe_608x448_wm620;
} else if (width == 720 && height == 480) {
DJILog.i(TAG, "Selected Iframe=iframe_720x480_wm620");
iframeId = R.raw.iframe_720x480_wm620;
} else if (width == 1280 && height == 720) {
DJILog.i(TAG, "Selected Iframe=iframe_1280x720_wm620");
iframeId = R.raw.iframe_1280x720_wm620;
} else if (width == 1080 && height == 720) {
DJILog.i(TAG, "Selected Iframe=iframe_1080x720_wm620");
iframeId = R.raw.iframe_1080x720_wm620;
} else if (width == 1088 && height == 720) {
DJILog.i(TAG, "Selected Iframe=iframe_1088x720_wm620");
iframeId = R.raw.iframe_1088x720_wm620;
} else if (width == 960 && height == 720) {
DJILog.i(TAG, "Selected Iframe=iframe_960x720_wm620");
iframeId = R.raw.iframe_960x720_wm620;
} else if (width == 1360 && height == 720) {
DJILog.i(TAG, "Selected Iframe=iframe_1360x720_wm620");
iframeId = R.raw.iframe_1360x720_wm620;
} else if (width == 1344 && height == 720) {
DJILog.i(TAG, "Selected Iframe=iframe_1344x720_wm620");
iframeId = R.raw.iframe_1344x720_wm620;
} else if (width == 1440 && height == 1088) {
DJILog.i(TAG, "Selected Iframe=iframe_1440x1088_wm620");
iframeId = R.raw.iframe_1440x1088_wm620;
} else if (width == 1632 && height == 1080){
DJILog.i(TAG, "Selected Iframe=iframe_1632x1080_wm620");
iframeId = R.raw.iframe_1632x1080_wm620;
} else if (width == 1760 && height == 720) {
DJILog.i(TAG, "Selected Iframe=iframe_1760x720_wm620");
iframeId = R.raw.iframe_1760x720_wm620;
} else if (width == 1920 && height == 800) {
DJILog.i(TAG, "Selected Iframe=iframe_1920x800_wm620");
iframeId = R.raw.iframe_1920x800_wm620;
} else if (width == 1920 && height == 1024) {
DJILog.i(TAG, "Selected Iframe=iframe_1920x1024_wm620");
iframeId = R.raw.iframe_1920x1024_wm620;
} else if (width == 1920 && height == 1088) {
DJILog.i(TAG, "Selected Iframe=iframe_1920x1080_wm620");
iframeId = R.raw.iframe_1920x1088_wm620;
} else if (width == 1920 && height == 1440) {
DJILog.i(TAG, "Selected Iframe=iframe_1920x1440_wm620");
iframeId = R.raw.iframe_1920x1440_wm620;
}
}
break;
case PHANTOM_4_PRO_V2:
case PHANTOM_4_RTK: {
iframeId = -1;
}
break;
default: //for P3P, Inspire1, etc/
iframeId = R.raw.iframe_1280x720_ins;
break;
}
return iframeId;
}
请自行查看。
更新于 2019-6-27