Android使用Socket接收rtsp视频流的解码header问题

风中的的承诺 2014-12-30 04:58:44
应用里采用socket访问一个网络摄像机,该摄像机传递rtsp的码流数据,在做这个视频播放时,网络摄像机的设备制造商提供了一个该型号摄像机的音视频访问协议,大概内容如下:

通过网络摄像机提供的ip地址和端口来建立一个tcp连接,然后通过该socket来发送一个http的请求,然后根据发送的请求得到响应。响应的内容包括http包和媒体数据包,主要的问题在于媒体数据包里,根据协议,媒体数据包的包头大小为20个字节,包括
RTSP数据包头+RTP数据包头,包头结构通过代码表示为为:
/*
* rtsp数据包头(占8个字节)
*/
typedef struct sRTSP_ITLEAVED_HDR_S {
unsigned char daollar; /*8, $:dollar sign(24 decimal)*/
unsigned char channelid; /*8, channel id*/
unsigned short resv; /*16, reseved*/
unsigned int payloadLen; /*32, payload length*/
RTP_HDR_S rtpHead; /*rtp head*/
} RTSP_ITLEAVED_HDR_S;

下面的时标准的rtp头的结构
/*
* rtp数据包头(占12个字节)
*/
typedef struct sRTP_HDR_S {
/* byte 0 */
unsigned short cc :4; /* CSRC count */
unsigned short x :1; /* header extension flag */
unsigned short p :1; /* padding flag */
unsigned short version :2; /* protocol version */
/* byte 1 */
unsigned short pt :7; /* payload type */
unsigned short marker :1; /* marker bit */
/* bytes 2, 3 */
unsigned short seqno :16; /* sequence number */
/* bytes 4-7 */
unsigned int ts; /* timestamp in ms */
/* bytes 8-11 */
unsigned int ssrc; /* synchronization source */
} RTP_HDR_S;

我根据协议里面的描述,使用了下面的方法来接收数据,解包和解码:

while(!stop)
byte headerBuf[] = readSockData(20);
if (headerBuf == null) {
continue;
}
int pt = (byte) ((headerBuf[9] & 0xff) & 0x7f); //这里得到视频编码类型(H264)
int payloadLen = (((headerBuf[4] & 0xff) << 24) |
((headerBuf[5] & 0xff) << 16) |
((headerBuf[6] & 0xff) << 8) |
(headerBuf[7] & 0xff)); //这里得到H264数据的长度
int pack_len = payloadLen - 12; //减去rtp header的长度(12)
if (pt == RtspPacket.PT_H264) { //当编码类型为H264时
byte packBuf[] = null;
//h264码流
try {
packBuf = readSockData(pack_len); //通过解码得到的帧数据长度,通过
} catch (OutOfMemoryError e) {
Log.d(TAG, "out of memory");
continue;
}
}
}

private byte[] readSockData(int dataBufLen) {
try {
int len = 0;
byte dataBuf[] = new byte[dataBufLen];
if (in != null) {
while (dataBufLen - len > 0) {
int ret = in.read(dataBuf); //DataInputStream in = mSocket.getInputStream();
if (ret < 0) {
return null;
}
len = len + ret;
}
return dataBuf;
}
} catch (Exception e) {
return null;
}
return null;
}

然后通过以上的代码进行访问,得到的每一帧数据能够通过ffmpeg来解码并且在能在手机上播放。但是真正的问题来了,当手机网络不好时,视频就卡死在那不动了,我通过log发现原因是byte headerBuf[] = readSockData(20);接收到的rtsp头解析得到的payloadLen(也就是下面帧数据的长度)很大或者为负数,我看了下640*360分辨率码流正常大小是在2000~3000字节左右,而我在循环里面加了OutOfMemory异常处理,当payloadLen异常时,就continue,这显然不能解决问题。但是我想实现这样的效果:当某一个NALU包头接收异常时,就丢弃当前帧(如果有更好的办法来重新获取当前帧更好),然后接收下面的一个NALU包,从而不会因为一个媒体数据头接收解析数据长度错误而不能解码下面的数据。
我是刚刚入门视频播放这一块,碰到好多问题都感觉晦涩难懂,希望各位高手能够指点在下一二,可能问题写的很啰嗦,但是真心希望大家能够帮帮我。给的分不多,谢谢!
...全文
517 1 打赏 收藏 转发到动态 举报
写回复
用AI写文章
1 条回复
切换为时间正序
请发表友善的回复…
发表回复
baidu_37530477 2017-07-16
  • 打赏
  • 举报
回复
你好 请问有解决了没 望指点下

80,360

社区成员

发帖
与我相关
我的任务
社区描述
移动平台 Android
androidandroid-studioandroidx 技术论坛(原bbs)
社区管理员
  • Android
  • yechaoa
  • 失落夏天
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧