ireader / media-server

RTSP/RTP/RTMP/FLV/HLS/MPEG-TS/MPEG-PS/MPEG-DASH/MP4/fMP4/MKV/WebM
MIT License
3.05k stars 1.07k forks source link

RTP转发VLC无法播放 #135

Closed AtomPod closed 3 years ago

AtomPod commented 3 years ago

@ireader 这几天使用librtp打包H265视频,用UDP转发给VLC后,但是显示不了,转发给使用gstreamer库的就可以解析播放。之前自己按照网上写的一个RTP打包H265转发给VLC是可以正常播放的。转发给VLC是否有什么特殊要求的格式?

ireader commented 3 years ago

描述下你的测试环境,如vlc启动参数,sdp之类的信息。

AtomPod commented 3 years ago

sdp的话,之前一直用的这个(没太多了解sdp,但是之前用这个sdp播放是可以显示的)

v=0 m=video 6200 RTP/AVP 96 a=rtpmap:96 H265/90000 c=IN IP4 127.0.0.1

VLC: 启动的话,一直是默认的,没加其他启动参数 debug日志中出现这个: live555 error: no data received in 10s, aborting main debug: EOF reached 同时开启另一个用gstreamer的播放是能接收到数据

ireader commented 3 years ago

你可以用librtsp/test/rtp-streaming-test.cpp测试程序验证下,输入是mp4文件。

将第18行的IP改成 127.0.0.1,新建一个sdp文件,内容如下:

m=video 8004 RTP/AVP 98
a=rtpmap:98 H265/90000
c=IN IP4 127.0.0.1
ireader commented 3 years ago

sdp的话,之前一直用的这个(没太多了解sdp,但是之前用这个sdp播放是可以显示的)

v=0 m=video 6200 RTP/AVP 96 a=rtpmap:96 H265/90000 c=IN IP4 127.0.0.1

VLC: 启动的话,一直是默认的,没加其他启动参数 debug日志中出现这个: live555 error: no data received in 10s, aborting main debug: EOF reached 同时开启另一个用gstreamer的播放是能接收到数据

确认下udp端口和rtp payload值。 librtp默认的265payload值是98

ireader commented 3 years ago

你可以用librtsp/test/rtp-streaming-test.cpp测试程序验证下,输入是mp4文件。

将第18行的IP改成 127.0.0.1,新建一个sdp文件,内容如下:

m=video 8004 RTP/AVP 98
a=rtpmap:98 H265/90000
c=IN IP4 127.0.0.1

可能会有编译错误,参照下面的图改一下 image

AtomPod commented 3 years ago

sdp的话,之前一直用的这个(没太多了解sdp,但是之前用这个sdp播放是可以显示的) v=0 m=video 6200 RTP/AVP 96 a=rtpmap:96 H265/90000 c=IN IP4 127.0.0.1 VLC: 启动的话,一直是默认的,没加其他启动参数 debug日志中出现这个: live555 error: no data received in 10s, aborting main debug: EOF reached 同时开启另一个用gstreamer的播放是能接收到数据

确认下udp端口和rtp payload值。 librtp默认的265payload值是98

udp端口发送端也是6200,payload改成98后,还是同样的问题,之前我在弄gb28181也出现过这个问题,发送RTP包给一些GB28181测试平台,视频同样放不了,但是有些就可以,很奇怪。

ireader commented 3 years ago

方便的话,贴下你的测试程序和265视频文件。

AtomPod commented 3 years ago

include

include

include

include

include

include

include

QByteArray nextVideoFrame(const QByteArray &rawData, int &offset) { int lastFrameHeader = rawData.size() - 3; if (rawData.size() <= offset) return nullptr;

int next = offset + 4; for (; next < lastFrameHeader; ++next) { if (rawData[next] == 0x00 && rawData[next + 1] == 0x00 && rawData[next + 2] == 0x00 && rawData[next + 3] == 0x01) { break; } }

QByteArray frameData(rawData.data() + offset, next - offset); offset = next;

return frameData; }

struct Params { QByteArray h265Data; int offset; QUdpSocket *socket; };

QByteArray readFileAll(const QString &filename) { QFile fp(filename); if (!fp.open(QIODevice::ReadOnly)) { qWarning() << "FileSource: cannot open file" << fp.fileName(); return nullptr; }

return fp.readAll(); }

int main(int argc, char *argv[]) { QCoreApplication a(argc, argv);

rtp_payload_t payload; payload.packet = [](void *params, const void packet, int size, unsigned int timestamp, int flags) { Params pparams = (Params)params; int result = pparams->socket->writeDatagram(static_cast(packet), size, QHostAddress("127.0.0.1"), 6200); };

payload.alloc = [](void *params, int size) { return malloc(size); };

payload.free = [](void params, void packet) { free(packet); };

Params *params = new Params(); params->h265Data = readFileAll("./stream_chn0.h265"); params->offset = 0; params->socket = new QUdpSocket(); params->socket->open(QUdpSocket::ReadWrite);

void *rtp = rtp_payload_encode_create(RTP_PAYLOAD_H265, "h265", 1, 1, &payload, params); assert(rtp != nullptr);

uint32_t timestamp = 0; while (params->offset < params->h265Data.size()) { QByteArray frameData = nextVideoFrame(params->h265Data, params->offset); if (frameData != nullptr) { rtp_payload_encode_input(rtp, frameData.data(), frameData.size(), timestamp); timestamp += 3000; QThread::msleep(1); } } return a.exec(); }

AtomPod commented 3 years ago

include

include

include

include

include

include

include

QByteArray nextVideoFrame(const QByteArray &rawData, int &offset) { int lastFrameHeader = rawData.size() - 3; if (rawData.size() <= offset) return nullptr;

int next = offset + 4; for (; next < lastFrameHeader; ++next) { if (rawData[next] == 0x00 && rawData[next + 1] == 0x00 && rawData[next + 2] == 0x00 && rawData[next + 3] == 0x01) { break; } }

QByteArray frameData(rawData.data() + offset, next - offset); offset = next;

return frameData; }

struct Params { QByteArray h265Data; int offset; QUdpSocket *socket; };

QByteArray readFileAll(const QString &filename) { QFile fp(filename); if (!fp.open(QIODevice::ReadOnly)) { qWarning() << "FileSource: cannot open file" << fp.fileName(); return nullptr; }

return fp.readAll(); }

int main(int argc, char *argv[]) { QCoreApplication a(argc, argv);

rtp_payload_t payload; payload.packet = [](void *params, const void packet, int size, unsigned int timestamp, int flags) { Params pparams = (Params)params; int result = pparams->socket->writeDatagram(static_cast(packet), size, QHostAddress("127.0.0.1"), 6200); };

payload.alloc = [](void *params, int size) { return malloc(size); };

payload.free = [](void params, void packet) { free(packet); };

Params *params = new Params(); params->h265Data = readFileAll("./stream_chn0.h265"); params->offset = 0; params->socket = new QUdpSocket(); params->socket->open(QUdpSocket::ReadWrite);

void *rtp = rtp_payload_encode_create(RTP_PAYLOAD_H265, "h265", 1, 1, &payload, params); assert(rtp != nullptr);

uint32_t timestamp = 0; while (params->offset < params->h265Data.size()) { QByteArray frameData = nextVideoFrame(params->h265Data, params->offset); if (frameData != nullptr) { rtp_payload_encode_input(rtp, frameData.data(), frameData.size(), timestamp); timestamp += 3000; QThread::msleep(1); } } return a.exec(); }

QT那几个怎么include发不出来,是QCoreApplication、QFile、QDebug、QUdpSocket、QThread

ireader commented 3 years ago

for (; next < lastFrameHeader; ++next) { if (rawData[next] == 0x00 && rawData[next + 1] == 0x00 && rawData[next + 2] == 0x00 && rawData[next + 3] == 0x01) { break; }

这段代码有问题,不要把vps、pps、sps作为独立视频帧。
可以参考libmov/test/mov-writer-h265.cpp里的分帧逻辑。重点是用h265_is_new_access_unit判断是否帧边界。

AtomPod commented 3 years ago

for (; next < lastFrameHeader; ++next) { if (rawData[next] == 0x00 && rawData[next + 1] == 0x00 && rawData[next + 2] == 0x00 && rawData[next + 3] == 0x01) { break; }

这段代码有问题,不要把vps、pps、sps作为独立视频帧。 可以参考libmov/test/mov-writer-h265.cpp里的分帧逻辑。重点是用h265_is_new_access_unit判断是否帧边界。

可以了