H264封装为FLV

最近嘴的一个项目是VC++提供websocket推送flv服务  以供web端点播。该方案的优点是无需下载控件,也不用flash播放器。之前实现过rtmp协议,但是flash到2020年之后停止技术支持。websocket推送flv流,可以在html5上直播播放。在pc端和Android 和ios上都可播放。

获取到的流是H264需要转为flv格式。下面贴出主要代码后期会上传工程供大家参考

BOOL CFlvStream::InitFlvHead()
{
    FLV_FILE_HEAD flvHead;
    memset(&flvHead, 0, sizeof(flvHead));
    memcpy(flvHead.sign_flag, "FLV", 3);
    flvHead.version = 0x01;
    flvHead.flvflag = 0x01;
    flvHead.dataoff[3] = 0x09;
    memcpy(m_pFlvStream+m_dwStreamLen,&flvHead,sizeof(flvHead));
    m_dwStreamLen += sizeof(flvHead);
    m_dwStreamLen += 4;    //上一个tag长度,此处为0
    return TRUE;
}

BOOL CFlvStream::write_metadata(DWORD dwWith, DWORD dwHeight)
{    
    int SLen = 0;
    FLV_TAG_HEAD tagHead = { 0 };
    tagHead.tagtype = 0x12;        //脚本数据
    BYTE byData[1024] = { 0 };
    BYTE* pPos = byData;
    avio_w8(pPos, 0x02);
    put_amf_string(pPos, "onMetaData");
    avio_w8(pPos, 0x08);
    avio_wb32(pPos, 8);

    put_amf_string(pPos, "duration");
    put_amf_double(pPos, 0);

    put_amf_string(pPos, "width");
    put_amf_double(pPos, dwWith);

    put_amf_string(pPos, "height");
    put_amf_double(pPos, dwHeight);

    put_amf_string(pPos, "videodatarate"); 
    put_amf_double(pPos, 4096);

    put_amf_string(pPos, "framerate");
    put_amf_double(pPos, 25.00);

    put_amf_string(pPos, "videocodecid");
    put_amf_double(pPos, 7.0);

    put_amf_string(pPos, "encoder");
    put_amf_string(pPos, "Lavf55.49.100");

    put_amf_string(pPos, "filesize");
    put_amf_double(pPos, 0);

    put_amf_string(pPos, "");
    avio_w8(pPos, 0x09);
    int nLen = pPos - byData;
    tagHead.data_size[0] = (uint8_t)(nLen >> 16);
    tagHead.data_size[1] = (uint8_t)(nLen >> 8);
    tagHead.data_size[2] = (uint8_t)nLen;

    memcpy(m_pFlvStream + m_dwStreamLen, &tagHead, sizeof(tagHead));
    m_dwStreamLen += sizeof(tagHead);
    memcpy(m_pFlvStream + m_dwStreamLen, byData, pPos - byData);
    m_dwStreamLen += (pPos - byData);
    pPos = m_pFlvStream + m_dwStreamLen;
    avio_wb32(pPos, nLen + 11);
    m_dwStreamLen += 4;    
    return TRUE;
}

BOOL CFlvStream::write_avcconfig(BYTE* pData, DWORD dwSize)
{
    FLV_TAG_HEAD tagHead = { 0 };
    tagHead.tagtype = 0x09;        //脚本数据
    BYTE byData[1024] = { 0 };
    BYTE* pPos = byData;
    avio_w8(pPos, 0x17);
    avio_wb32(pPos, 0);
    avio_w8(pPos, 0x01);
    int nPos = GetFirstPosbyType(pData,dwSize,7);
    int nType = 0;
    if (nPos >= 0)
    {
        avio_write(pPos, (const char*)pData+nPos+5, 3);
        avio_w8(pPos, 0xFF);
        avio_w8(pPos, 0xE1);
        int nLen = GetFirstPos(pData + nPos + 4, dwSize - nPos - 4, nType);
        if (nLen == -1)
        {
            nLen = dwSize - nPos - 4;
        }
        avio_wb16(pPos, nLen);    //sps长度
        avio_write(pPos, (const char*)pData + nPos + 4, nLen);    //sps数据
        avio_w8(pPos, 0x01);    //pps个数
        nPos = GetFirstPosbyType(pData, dwSize, 8);
        nLen = GetFirstPos(pData + nPos + 4, dwSize - nPos - 4, nType);
        if (nLen == -1)
        {
            nLen = dwSize - nPos - 4;
        }
        avio_wb16(pPos, nLen);    //pps长度
        avio_write(pPos, (const char*)pData + nPos + 4, nLen);    //pps数据
        nLen = pPos - byData;
        tagHead.data_size[0] = (uint8_t)(nLen >> 16);
        tagHead.data_size[1] = (uint8_t)(nLen >> 8);
        tagHead.data_size[2] = (uint8_t)nLen;

        memcpy(m_pFlvStream + m_dwStreamLen, &tagHead, sizeof(tagHead));
        m_dwStreamLen += sizeof(tagHead);
        memcpy(m_pFlvStream + m_dwStreamLen, byData, pPos - byData);
        m_dwStreamLen += (pPos - byData);
        pPos = m_pFlvStream + m_dwStreamLen;
        avio_wb32(pPos, nLen + 11);
        m_dwStreamLen += 4;
    }
    else{
        return FALSE;
    }
}

BOOL CFlvStream::write_videodata(BYTE* pData, DWORD dwSize, DWORD dwTime, BOOL bKey)
{
    BYTE* pPos = m_pFlvStream + m_dwStreamLen;
    avio_w8(pPos, 0x09);
    avio_wb24(pPos, dwSize + 5);
    avio_wb24(pPos, dwTime & 0xFFFFFF);
    avio_w8(pPos, (dwTime >> 24) & 0x7F); // timestamps are 32 bits _signed_
    avio_wb24(pPos, 0);
    if (bKey)
    {
        avio_w8(pPos, 0x17);
    }
    else
    {
        avio_w8(pPos, 0x27);
    }

    avio_w8(pPos, 0x01);
    avio_wb24(pPos, 0);
    replaceStartCode(pData,dwSize);
    avio_write(pPos,(const char*)pData,dwSize);
    m_dwStreamLen += (pPos - m_pFlvStream);
    avio_wb32(pPos, pPos - m_pFlvStream);
    m_dwStreamLen += 4;
    return 0;
}

你可能感兴趣的:(H264封装为FLV)