问题遇到的现象和发生背景
项目中读取Kinect TOF相机中RGBA与深度数据,需要将RGBA色彩数据推流到服务器上。我采用FFMPEG 编解RGBA数据,用H.264编码压缩,推流到ZLMediaKIT上,
1、采用ffplay拉流可以解码播放,但报错如下信息:
Input #0, flv, from 'rtmp://127.0.0.1:1936/live/livestream':f=0/0
Metadata:
encoder : Lavf57.83.100
server : ZLMediaKit(git hash:a0c1bc1,branch:master,build time:Apr 11 2022 09:38:46)
Duration: 00:00:00.00, start: 8.667000, bitrate: N/A
Stream #0:0: Video: h264 (Constrained Baseline), yuv420p(progressive), 1280x720, 20971 kb/s, 15.17 fps, 15 tbr, 1k tbn, 30 tbc
[h264 @ 0x7f48f40a5a40] non-existing PPS 0 referenced 0B f=0/0
[h264 @ 0x7f48f40a5a40] decode_slice_header error
[h264 @ 0x7f48f40a5a40] no frame!
[h264 @ 0x7f48f409ad80] non-existing PPS 0 referenced 0B f=0/0
[h264 @ 0x7f48f409ad80] decode_slice_header error
[h264 @ 0x7f48f409ad80] no frame!
[h264 @ 0x7f48f40a13a0] non-existing PPS 0 referenced 0B f=0/0
[h264 @ 0x7f48f40a13a0] decode_slice_header error
[h264 @ 0x7f48f40a13a0] no frame!
2、另外用我本地Android app 播放RTMP url 不成功。
3、如果直接采用“ffmpeg -f v4l2 -r 25 -i /dev/video0 -c:v libx264 -pix_fmt yuv420p -preset ultrafast -g 30 -b:v 500k -threads 0 -bufsize 512k -f flv rtmp://127.0.0.1:1935/live/livestream &”推流,可以本地Android app成功 播放RTMP url。
4 我推测FFMPEG 按照H.264直接编码RGBA数据推流时,没有把pps\sps等信息加进去,想请教一下各位该怎么处理呢?
其中推流代码如下:
for(;;) {
k4a_image_t color_image;
gettimeofday(&tv,NULL);
switch (k4a_device_get_capture(device,&capture,TIMEOUT_IN_MS)){
case K4A_WAIT_RESULT_SUCCEEDED:
break;
case K4A_WAIT_RESULT_TIMEOUT:
printf("Timed out waiting for a capture\n");
continue;
break;
case K4A_WAIT_RESULT_FAILED:
printf("Failed to read a capture\n");
return -1;
}
cout<<"完成取流后---->"<<tv.tv_sec*1000 + tv.tv_usec/1000<<endl;
// probe for a color image
color_image = k4a_capture_get_color_image(capture);
if(color_image) {
// printf(" | Color res:%4dx%4d stride:%5d ",
// k4a_image_get_height_pixels(color_image),
// k4a_image_get_width_pixels(color_image),
// k4a_image_get_stride_bytes(color_image));
}else{
printf("获取彩色帧数据失败");
}
// 得到YUV420数据地址
// 后续替换为队列保存数据
uint8_t * color_image_buffer = k4a_image_get_buffer(color_image);
AVFrame *yuv = convertRGBtoYUV(color_image_buffer);
yuv->pts = videoPts++;
int ret = avcodec_send_frame(avCodecContext, yuv);
if (ret != 0) {
break ;
}
ret = avcodec_receive_packet(avCodecContext, &outVideoPacket);
if (ret != 0 || outVideoPacket.size <= 0) {
break ;
}
AVPacket *pkt = &outVideoPacket;
if (pkt)
{
////推流
if (sendFrame(pkt,vindex))
{
cout << "@" << flush;
}
}
}
}
参照网上资料:
** 我在代码 ret = avcodec_receive_packet(avCodecContext, &outVideoPacket);后添加如下代码**也没有成功
斜体部分参考网上资料写的,但也没有成功,
```c++
if (pkt->flags &AV_PKT_FLAG_KEY)
{
cPacketData = (char*)pkt->data;
int n = 0;
while ((char*)pkt->data)
{
// 找到NAL中I帧位置
if (cPacketData[n] == 0 && cPacketData[n + 1] == 0 && cPacketData[n + 2] == 0 && cPacketData[n + 3] == 1 && cPacketData[n + 4] == 101)
{
//找到I帧,插入SPS和PPS
memcpy(cExtradata, avCodecContext->extradata, avCodecContext->extradata_size);
memcpy(cExtradata + avCodecContext->extradata_size, pkt->data, pkt->size);//&enc_packet.data[0]
pkt->size += avCodecContext->extradata_size;
pkt->data = cExtradata;
break;
}
if (n == pkt->size)
{
break;
}
cPacketData++;
n++;
}
}
另外我的编码器代码如下:
```c++
/**
* 初始化编码器
* @return
*/
bool initVideoCodec() {
int ret = 0;
// 创建编码器上下文
AVCodec* videoCodec = avcodec_find_encoder(AV_CODEC_ID_H264);
// AVCodec* videoCodec = avcodec_find_encoder(AV_CODEC_ID_HEVC);
if (!videoCodec) {
cout << "没有找到编码器" << endl;
return false;
}
// 编码器分配上下文
avCodecContext = avcodec_alloc_context3(videoCodec);
if (!avCodecContext) {
cout << "编码器上下文空间分配错误" << endl;
return false;
}
// 配置编码器参数
avCodecContext->codec_id = videoCodec->id;
avCodecContext->thread_count = 3; // 如果多个相机播放,这样没啥效果
cout << "initVideoCodec 获取CPU NUM: " << avCodecContext->thread_count << endl;
//压缩后每秒视频的bit位大小 20kB
avCodecContext->bit_rate = bitRate; // 码率
avCodecContext->width = outWidth;
avCodecContext->height = outHeight;
avCodecContext->time_base = {1, fps};
avCodecContext->framerate = {fps, 1};
// 画面组的大小,多少帧一个关键帧
avCodecContext->gop_size = 5;
avCodecContext->max_b_frames = 0; //编码器不使用B帧,提高直播解码效率
avCodecContext->pix_fmt = AV_PIX_FMT_NV12;
avCodecContext->codec_type = AVMEDIA_TYPE_VIDEO;
av_opt_set(avCodecContext->priv_data,"preset","ultrafast",0);
av_opt_set(avCodecContext->priv_data,"tune","zerolatency",0);
AVDictionary *opts = NULL;
av_dict_set(&opts, "profile", "baseline", 0);
// 打开编码器上下文
ret = avcodec_open2(avCodecContext, 0, &opts);
if (ret != 0) {
cout << "avcodec_open2出错" << endl;
return false;
}
cout << "视频编码器初始化 完成"<< endl;
return true;
}