1.首先确保跑通了大疆官方的demo,demo功能是可以将本地h264的视频文件推到遥控器显示。
2.将264格式设置为普通264(默认为大疆264),更改demo里的代码如下
cpp
//returnCode = DjiPayloadCamera_SetVideoStreamType(DJI_CAMERA_VIDEO_STREAM_TYPE_H264_DJI_FORMAT);
returnCode = DjiPayloadCamera_SetVideoStreamType(DJI_CAMERA_VIDEO_STREAM_TYPE_H264_CUSTOM_FORMAT);
if (returnCode != DJI_ERROR_SYSTEM_MODULE_CODE_SUCCESS) {
USER_LOG_ERROR("DJI camera set video stream error.");
return DJI_ERROR_SYSTEM_MODULE_CODE_UNKNOWN;
}
//s_cameraVideoStreamType = DJI_CAMERA_VIDEO_STREAM_TYPE_H264_DJI_FORMAT;
s_cameraVideoStreamType = DJI_CAMERA_VIDEO_STREAM_TYPE_H264_CUSTOM_FORMAT;
3.通过ffmpeg将获取的摄像头数据进行264编码,然后通过DjiPayloadCamera_SendVideoStream函数将编码完的一帧数据发送出去,主要实现如下,以供参考。
cpp
void Ffmpeg_Encoder_Init()
{
av_register_all();
avcodec_register_all();
m_pRGBFrame = new AVFrame[1];//RGB帧数据赋值
m_pYUVFrame = new AVFrame[1];//YUV帧数据赋值
c = NULL;//解码器指针对象赋初值
}
void Ffmpeg_Encoder_Setpara(AVCodecID mycodeid, int vwidth, int vheight)
{
pCodecH264 = avcodec_find_encoder(mycodeid);//查找h264编码器
if (!pCodecH264)
{
fprintf(stderr, "h264 codec not found\n");
exit(1);
}
width = vwidth;
height = vheight;
c = avcodec_alloc_context3(pCodecH264);//函数用于分配一个AVCodecContext并设置默认值,如果失败返回NULL,并可用av_free()进行释放
c = avcodec_alloc_context3(pCodecH264);//函数用于分配一个AVCodecContext并设置默认值,如果失败返回NULL,并可用av_free()进行释放
c->bit_rate = 400000; //设置采样参数,即比特率
c->width = vwidth;//设置编码视频宽度
c->height = vheight; //设置编码视频高度
c->time_base.den = 25;//设置帧率,num为分子和den为分母,如果是1/25则表示25帧/s
c->time_base.num = 1;
c->gop_size = 25; //设置GOP大小,该值表示每25帧会插入一个I帧
c->pix_fmt = AV_PIX_FMT_YUV420P;//设置像素格式
c->profile = FF_PROFILE_H264_BASELINE;//仅支持I帧P帧
av_opt_set(c->priv_data, "tune", "zerolatency", 0);//设置编码器的延时,解决前面的几十帧不出数据的情况
if (avcodec_open2(c, pCodecH264, NULL) < 0)return;//打开编码器
nDataLen = vwidth*vheight * 3;//计算图像rgb数据区长度
yuv_buff = new uint8_t[nDataLen / 2];//初始化数据区,为yuv图像帧准备填充缓存
rgb_buff = new uint8_t[nDataLen];//初始化数据区,为rgb图像帧准备填充缓存
outbuf_size = 100000;//初始化编码输出数据区
outbuf = new uint8_t[outbuf_size];
scxt = sws_getContext(c->width, c->height, AV_PIX_FMT_BGR24, c->width, c->height, AV_PIX_FMT_YUV420P, SWS_POINT, NULL, NULL, NULL);//初始化格式转换函数
}
void Ffmpeg_Encoder_Encode(FILE *file, uint8_t *data)
{
av_init_packet(&pkt);
memcpy(rgb_buff, data, nDataLen);//拷贝图像数据到rgb图像帧缓存中准备处理
avpicture_fill((AVPicture*)m_pRGBFrame, (uint8_t*)rgb_buff, AV_PIX_FMT_RGB24, width, height);//将rgb_buff填充到m_pRGBFrame
//av_image_fill_arrays((AVPicture*)m_pRGBFrame, (uint8_t*)rgb_buff, AV_PIX_FMT_RGB24, width, height);
avpicture_fill((AVPicture*)m_pYUVFrame, (uint8_t*)yuv_buff, AV_PIX_FMT_YUV420P, width, height);//将yuv_buff填充到m_pYUVFrame
sws_scale(scxt, m_pRGBFrame->data, m_pRGBFrame->linesize, 0, c->height, m_pYUVFrame->data, m_pYUVFrame->linesize);// 将RGB转化为YUV
int myoutputlen = 0;
int returnvalue = avcodec_encode_video2(c, &pkt, m_pYUVFrame, &myoutputlen);
if (returnvalue == 0)
{
unsigned long dataLength = pkt.size;
int lengthOfDataHaveBeenSent = 0;
while (dataLength - lengthOfDataHaveBeenSent) { //如果发送完成一帧
uint16_t lengthOfDataToBeSent = USER_UTIL_MIN(60000,dataLength - lengthOfDataHaveBeenSent);
DjiPayloadCamera_SendVideoStream((const uint8_t *) pkt.data + lengthOfDataHaveBeenSent,lengthOfDataToBeSent); //发送一帧
lengthOfDataHaveBeenSent += lengthOfDataToBeSent; //发送的大小
}
}
av_free_packet(&pkt);
}
void Ffmpeg_Encoder_Close()
{
delete[]m_pRGBFrame;
delete[]m_pYUVFrame;
delete[]rgb_buff;
delete[]yuv_buff;
delete[]outbuf;
sws_freeContext(scxt);
avcodec_close(c);//关闭编码器
av_free(c);
}
int main()
{
//开启大疆服务
main1();
cv::VideoCapture capture(10);
if (!capture.isOpened()) {
printf("Failed to open camera");
}
cv::Mat imageTemp;
capture >> imageTemp;
Ffmpeg_Encoder_Init();//初始化编码器
Ffmpeg_Encoder_Setpara(AV_CODEC_ID_H264, imageTemp.cols, imageTemp.rows);//设置编码器参数
//图象编码
FILE *f = NULL;
char * filename = "myData.h264";
fopen_s(&f, filename, "wb");//打开文件存储编码完成数据
while(1)
{
capture >> imageTemp;
Ffmpeg_Encoder_Encode(f, (uchar*)imageTemp.data);//编码
//imshow("send", imageTemp);
cv::waitKey(30);
}
return 0;
}