《音视频:从h264裸流数据中提取各NALU单元》

一、前言

本文旨在将h264裸流数据分解成一个个NALU单元,以便后续对每一个NALU单元进行RTP封包将其发送出去。

二、实现-解析H264裸流数据

h264裸流数据中一般以“00 00 00 01”或者“00 00 01”来分隔NALU单元,所有要做的就是识别到这两种头,将两个头之间的所需要的NALU数据提取出来。直接上代码。

typedef struct  
{
    
      
    unsigned len;
    char *buf; 
} MY_NALU_t;

/*
	从h264裸流数据中提取出NALU单元数据
	srcStr:裸流数据
	srcStrLen: 裸流数据长度
	nalu:存放所有的nalu单元
*/
int getAllNalu(char* srcStr, int srcStrLen,MY_NALU_t nalu[])
{
    
    
    int srcIndex = 0;
    int lastNaluPos = -1;
    int naluLen = 0;
    int naluCount = 0;
    int maxLen = 0;
    int lastNaluStartType = 0;

    static BYTE byHeadLong[] = {
    
     0x00, 0x00, 0x00, 0x01 };
    static BYTE byHeadShort[] = {
    
     0x00, 0x00, 0x01 };

    if (!srcStr || !srcStrLen) return -1;

    qDebug("srcLen: %d", srcStrLen);

    while (srcStrLen)
    {
    
    
        if (memcmp(srcStr + srcIndex, byHeadShort, sizeof(byHeadShort)) == 0)
        {
    
           
            if (lastNaluPos != -1)
            {
    
    
                // 之前找到过一个开头,那么这一次再次找到,则上一个完整nalu长度为 srcIndex-lastNaluPos
                naluLen = srcIndex - lastNaluPos;
                if (naluLen > maxLen)
                {
    
    
                    maxLen = naluLen;
                }
                
                if (lastNaluStartType == 1)
                {
    
    
                    // qDebug("find %d nalu type: %d,len: %d", naluCount, srcStr[lastNaluPos + sizeof(byHeadShort)] & 0x1f, naluLen);
                    nalu[naluCount].buf = &srcStr[lastNaluPos + sizeof(byHeadShort)];
                    nalu[naluCount].len = naluLen - sizeof(byHeadShort);  // 不要起始头
                    qDebug("find %d nalu type: %d,len: %d", naluCount, nalu[naluCount].buf[0] & 0x1f, nalu[naluCount].len);
                    naluCount++;
                }
                else if (lastNaluStartType == 2)
                {
    
    
                    // qDebug("find %d nalu type: %d,len: %d", naluCount, srcStr[lastNaluPos + sizeof(byHeadLong)] & 0x1f, naluLen);
                    nalu[naluCount].buf = &srcStr[lastNaluPos + sizeof(byHeadLong)];
                    nalu[naluCount].len = naluLen - sizeof(byHeadLong);  // 不要起始头
                    qDebug("find %d nalu type: %d,len: %d", naluCount, nalu[naluCount].buf[0] & 0x1f, nalu[naluCount].len);
                    naluCount++;
                }
            }

            lastNaluPos = srcIndex;
            lastNaluStartType = 1;

            srcStrLen -= sizeof(byHeadShort);
            srcIndex += sizeof(byHeadShort);
        }
        else if (memcmp(srcStr + srcIndex, byHeadLong, sizeof(byHeadLong)) == 0)
        {
    
           
            if (lastNaluPos != -1)
            {
    
    
                // 之前找到过一个开头,那么这一次再次找到,则上一个完整nalu长度为 srcIndex-lastNaluPos
                naluLen = srcIndex - lastNaluPos;
                if (naluLen > maxLen)
                {
    
    
                    maxLen = naluLen;
                }
                
                if (lastNaluStartType == 1)
                {
    
    
                    // qDebug("find %d nalu type: %d,len: %d", naluCount, srcStr[lastNaluPos + sizeof(byHeadShort)] & 0x1f, naluLen);
                    nalu[naluCount].buf = &srcStr[lastNaluPos + sizeof(byHeadShort)];
                    nalu[naluCount].len = naluLen - sizeof(byHeadShort);  // 不要起始头
                    qDebug("find %d nalu type: %d,len: %d", naluCount, nalu[naluCount].buf[0] & 0x1f, nalu[naluCount].len);
                    naluCount++;
                }
                else if (lastNaluStartType == 2)
                {
    
    
                    // qDebug("find %d nalu type: %d,len: %d", naluCount, srcStr[lastNaluPos + sizeof(byHeadLong)] & 0x1f, naluLen);
                    nalu[naluCount].buf = &srcStr[lastNaluPos + sizeof(byHeadLong)];
                    nalu[naluCount].len = naluLen - sizeof(byHeadLong);  // 不要起始头
                    qDebug("find %d nalu type: %d,len: %d", naluCount, nalu[naluCount].buf[0] & 0x1f, nalu[naluCount].len);
                    naluCount++;
                }      
            }

            lastNaluPos = srcIndex;
            lastNaluStartType = 2;

            srcStrLen -= sizeof(byHeadLong);
            srcIndex  += sizeof(byHeadLong);
        }
        else 
        {
    
    
            srcStrLen--;
            srcIndex++;
        }

        if (!srcStrLen)
        {
    
    
            if (lastNaluPos != -1)
            {
    
    
                // 之前找到过一个开头,那么这一次再次找到,则上一个完整nalu长度为 srcIndex-lastNaluPos
                naluLen = srcIndex - lastNaluPos;
                if (naluLen > maxLen)
                {
    
    
                    maxLen = naluLen;
                }
                
                if (lastNaluStartType == 1)
                {
    
    
                    // qDebug("find %d nalu type: %d,len: %d", naluCount, srcStr[lastNaluPos + sizeof(byHeadShort)] & 0x1f, naluLen);
                    nalu[naluCount].buf = &srcStr[lastNaluPos + sizeof(byHeadShort)];
                    nalu[naluCount].len = naluLen - sizeof(byHeadShort);  // 不要起始头
                    qDebug("find %d nalu type: %d,len: %d", naluCount, nalu[naluCount].buf[0] & 0x1f, nalu[naluCount].len);
                    naluCount++;
                }
                else if (lastNaluStartType == 2)
                {
    
    
                    // qDebug("find %d nalu type: %d,len: %d", naluCount, srcStr[lastNaluPos + sizeof(byHeadLong)] & 0x1f, naluLen);
                    nalu[naluCount].buf = &srcStr[lastNaluPos + sizeof(byHeadLong)];
                    nalu[naluCount].len = naluLen - sizeof(byHeadLong);  // 不要起始头
                    qDebug("find %d nalu type: %d,len: %d", naluCount, nalu[naluCount].buf[0] & 0x1f, nalu[naluCount].len);
                    naluCount++;
                }
            }
        }
    }

    qDebug("max nalu len: %d", maxLen);

    return naluCount;
}

三、测试-使用getAllNalu接口

int naluNum = 0;
MY_NALU_t nalu[10];  // 一帧数据里面包含的nalu数量应该不会太多,最多不会超过10个。
   
// 一帧数据中可能有多个nalu单元,需要将其识别出来一个一个封包处理,根据00 00 00 01或者00 00 01起始码识别
naluNum = getAllNalu(databuff, len,nalu);

for(int i=0;i<naluNum;i++)
{
    
    
    // 对每一个nalu单元处理
    qDebug(" %d nalu type: %d,len: %d nalu head: 0x%x", i, nalu[i].buf[0] & 0x1f, nalu[i].len,nalu[i].buf[0]);
    // 对每个nalu单元进行rtp封包处理。
    // package_rtp(nalu[i].buf,nalu[i].len,transport);
}

猜你喜欢

转载自blog.csdn.net/qq_40709487/article/details/128166396