firefly-rk3399 開發記錄3-編碼與RTSP實現

1.幀捕獲

在前面的實現過程當中,採用了QVideoProbe捕獲攝像頭數據,在信號綁定以後,傳輸到QSmartVenc,編碼模塊是額外放在另一個線程處理的app

QVencParm param;
    param.width  = 1280;
    param.height = 720;
    param.code   = MPP_VIDEO_CodingAVC;
    param.fmt    = MPP_FMT_YUV420P;
    m_venc.reset(new QSmartVenc(param));
    QThread *vencThread = new QThread(this);
    m_venc->moveToThread(vencThread);
    vencThread->start();

將probe數據綁定到編碼模塊tcp

connect(m_probe.data(),&QVideoProbe::videoFrameProbed,m_venc.data(),&QSmartVenc::needHandleImage);

2.編碼

編碼是使用的瑞芯微MPP,參考歷程mpi_enc_test,總體接口略顯麻煩,基本能夠跟着流程不動進行修改。其中須要注意一點的是stride在MPP中須要是16字節對齊,這裏最好將輸入分辨率也作16字節對齊,這樣寬和高就恰好和stride匹配,避免後面填充的時候還有手動計算YUV份量位置.ide

MppFrame frame = NULL;
    MppPacket packet = NULL;
    void *buf = mpp_buffer_get_ptr(frm_buf);
    
    f.map(QAbstractVideoBuffer::ReadOnly);
    memcpy(buf,f.bits(),frame_size);
    f.unmap();

    int ret = mpp_frame_init(&frame);
    if(ret)
    {
        qWarning("Init frame failed");
        return;
    }
   
    mpp_frame_set_width(frame, par.width);
    mpp_frame_set_height(frame, par.height);
    mpp_frame_set_hor_stride(frame, hor_stride);
    mpp_frame_set_ver_stride(frame, ver_stride);
    mpp_frame_set_fmt(frame, par.fmt);
    mpp_frame_set_eos(frame, 0);

    mpp_frame_set_buffer(frame, frm_buf);
    ret = mpi->encode_put_frame(ctx, frame);
    if(ret)
    {
        qWarning( "encode_put_frame failed");
        return;
    }

    ret = mpi->encode_get_packet(ctx, &packet);
    if (ret) {
      qWarning("mpp encode get packet failed\n");
    }
    if(!packet)
        return;

    // write packet to file here
    void *ptr   = mpp_packet_get_pos(packet);
    size_t len  = mpp_packet_get_length(packet);
    encFile.write((char *)ptr,len);
    //p->pkt_eos = mpp_packet_get_eos(packet);
    {
        QMutexLocker locker(&encDataLock);
        if((encDataLen + len) > MAX_STREAM_BUFFER)
        {
            auto ba = encDataList.takeFirst(); //右值
            encDataLen -= ba.length();
        }
        qDebug() << "encode len " << len;
        encDataList.append(rtcpInfo + QByteArray((char *)ptr,len)); //右值,這裏必定要加上sps,pps
        encDataLen += (len + rtcpInfo.size());;
    }
   
    mpp_packet_deinit(&packet);

    //qDebug("encoded frame %u size %lu\n", frame_count, len);
    frame_count++;

在memcpy的位置,若是寬高和stride不匹配的,就不能直接拷貝了,手動計算,麻煩得一逼。。函數

這裏在編碼完成以後,經過 QList<QByteArray>存儲起來,須要作緩衝大小限制,這個大小限制和具體業務相關了。this

3.RTSP

RTSP的實現採用的是live555,根據livemedia進行的修改,目前跑多路視頻流,1080P,沒有問題,live555這裏是通過修改過的和原生略有不一樣。
首先提供碼流信息和讀取回調函數,live555是單獨一個線程運行的,在合適的時候會調用到提供的函數讀取視頻流。
編碼

int rtsp_sever_callback(void *data,unsigned int max,const char * des,int *fps);
VIDEO_RTSP_INFO rtspServerInfo[] = {
    {PT_H264,"smartcam","smartcam",rtsp_sever_callback}
};

經過此接口將信息註冊到RTSP服務上,video_init_rtsp是本身實現的和live555交互的處理邏輯。spa

void QSmartVenc::init_rtsp_server(void)
{
    MESSAGE msg;
    msg.pstInfo = rtspServerInfo;
    msg.size    = sizeof(rtspServerInfo)/sizeof(rtspServerInfo[0]);
    video_init_rtsp(&msg);
}

rtsp_sever_callback實現以下,這裏須要注意的就是生產和消費關係了,若是每次取多了,可能會致使下次來取無數據,從而斷流,若是取少了,會致使數據丟失,從而花屏。.net

int rtsp_sever_callback(void *data,unsigned int max,const char * des,int *fps)
{
    //可經過des判斷是哪一條流信息
    QMutexLocker locker(&encDataLock);
    if(!encDataList.size()) //無數據
        return -1;
    unsigned int  remain = max;
    int num = 0;
    //while(!encDataList.isEmpty() && num++ < 2) //最多取兩針,這裏根據實際狀況來作處理吧,協調好生產消費的關係,否則很容易掉幀,花屏
    {
        auto ba = encDataList.takeFirst();
        int readLen = ba.size() < remain ? ba.size()  : remain;
        memcpy(data,ba.data(),readLen);
        if(readLen < ba.size()) //此幀沒有讀取完畢
        {
            encDataList.insert(0,ba.remove(0,readLen));
        }
        encDataLen -= readLen;
        remain -= readLen;

        // if(remain < 512)
        //     break;
    }
    qDebug() << "left data "<< encDataLen;
    *fps = encDataLen < 2 * 1024 ? 10 : 30;
    return (max - remain);
}

這裏的實現也有個問題,沒有處理I幀,會出現剛開始獲取視頻流時,有點花屏,過一會就行了,初步分析是由於第一次獲取到的可能不是I幀,後面讀到I幀以後,就恢復正常線程

 

執行文件和相關庫文件在連接上code

https://download.csdn.net/download/huahuang1508/12694057

相關文章
相關標籤/搜索