OpenCVのは、検出結果を描きます

OpenCVのは、検出結果を描きます

I.はじめに

私たちのアルゴリズムは非常に遅い検出検証段階、FPGAを使用するので、それ以外の場合は、我々は主流の描画アルゴリズムを待つには長い時間をすべきで、主流に直接描画することはできません。だから、私たちのソリューションは、クライアントにボックスをプッシュすることです、我々はクライアント上にプロットしました。

この場合、クライアントは、画像フレームを受信音声フレーム、また、メッセージボックスが表示されます、すべての3つの表示ではなく、画像を同期させる必要がある、オーディオ、フレームが一致していないだけではなく。画像、音声がffmpegのによって書かれて、問題がないが、検出アルゴリズムはないffmpegのパッケージを介して、描画処理の表側から独立しているので、NTP時刻同期を使用する必要があります。

問題:

  1. あなたが同期を行うと、いくつかの時間またはわずかに異なる2となります準同期するように、rtcp_ntp_timestamp av_bufferタイムスタンプを設定するのが最適であることが可能。
  2. 、ffmpegのntp_timeから取得してAVPacketにffmpegの増加first_rtcp_ntp_timeフィールドを変更(AVFormatContextで実際にstart_real_timeフィールドが、一部は注目されるべきである)する方法
  3. 20FPSは、場合AVPackate->pts以上223usである50223us、2つの間の差です。

二、FFMPEG

ffmpegのタイムスタンプの説明:
https://www.cnblogs.com/gr-nick/p/10993363.html

すべては、PTSのみを得ることができ、発見のほんの始まりを封じPTSと結果が計算によって得られたffmpegのため、最初のフレームに比較的時間の相対的であり、フレームは、両方のことができない絶対的な時間であり、試合。

私たちはするつもりAVPacket1を追加しfirst_rtcp_ntp_time、我々が合格とすることができるように、AVPacketリアルタイムのNTP PTSの統合計算を取得します。

コードの分析、でPTSを見つけるlibavofrmat/rtpdec.c finalize_packet同じトークンを割り当てられた機能・コンピューティング、我々はまた、機能を算出しましたfirst_rtcp_ntp_time

    pkt->first_rtcp_ntp_time = av_rescale(s->first_rtcp_ntp_time,
            s->st->time_base.den,
            (uint64_t) s->st->time_base.num << 32);

写个程序测试,打印该值,并没有写入到AVPacket中,发现,实际上ffmpeg中内部处理时会新建临时packet对象,而在赋值的时候,之前的代码并没有进行这个字段的拷贝,所以导致值没有传出来,需要修改libavformat/utils.cparse_packet函数:

        out_pkt.stream_index = st->index;
        out_pkt.pts          = st->parser->pts;
        out_pkt.dts          = st->parser->dts;
        out_pkt.pos          = st->parser->pos;
        /* 新增如下行 */
        out_pkt.first_rtcp_ntp_time = pkt->first_rtcp_ntp_time; 

实际上,后来突然发现在AVFormatContext中存在一个start_time_realtime字段,里面存储了ntp时间,所以可以直接利用这个值,不需要修改AVPacket。但存在一个问题,这边在计算时,对这个时间减去了一个NTP_OFFSET(1900~1970的时间差),而我们在编码时并没有加上该偏移,这边相当于多减了NTP_OFFSET,所以使用的时候需要把这个值再加回来。

s->start_time_realtime = av_rescale (rtpctx->first_rtcp_ntp_time - (NTP_OFFSET << 32), 1000000, 1LL << 32);

三、OpenCV

OpenCV中包含了一个cap.get(CV_CAP_PROP_POS_MSEC)函数用于获取当前帧时间,其实现方式如下,主要是通过内部维护的frame_number与fps进行计算,但好像对我们没什么用:

case CV_FFMPEG_CAP_PROP_POS_MSEC:
    return 1000.0*(double)frame_number/get_fps();

OpenCV调用ffmpeg进行rtsp解析的主要流程,最终还是调用av_read_frame()函数:

OpenCV
OpenCV

在VideoCapture中提供一个成员函数cap.getRealTimestamp()用于返回时间戳,
CvCapture_FFMPEG中提供一个timestamp成员用来保存时间戳,提供一个接口函数,如下:

@@ -423,6 +423,7 @@ struct CvCapture_FFMPEG
     double  get_duration_sec() const;
     double  get_fps() const;
     int     get_bitrate() const;
+    int64_t getRealTimestamp() const { return timestamp; }
     AVRational get_sample_aspect_ratio(AVStream *stream) const;
     
@@ -436,6 +437,7 @@ struct CvCapture_FFMPEG
     AVFrame         * picture;
     AVFrame           rgb_picture;
     int64_t           picture_pts;
+    int64_t           timestamp;

最后在CvCapture_FFMPEG grabFrame函数中计算时间戳:

int64_t time = packet.first_rtcp_ntp_time + packet.pts;
AVRational in_base = {1, 90000};
AVRational out_base = {1, 1000000};
timestamp = av_rescale_q(time, in_base, out_base);

如果是使用start_time_realtime则有:

#define NTP_OFFSET 2208988800ULL            
int64_t time = av_rescale (ic->start_time_realtime, 1LL << 32, 1000000) + (NTP_OFFSET << 32);
timestamp = av_rescale (time, 1000000, 1LL << 32) + av_rescale (packet.pts, 1000000, 90000);

四、绘制

新建一个线程使用libcurl获取websocket传过来的框信息,放入到一个std::list容器中进行管理。

分别获取帧时间与框时间进行比较,满足条件则绘图:

list<struct box_result>::iterator it;

/* frame time */
int64_t frame_time = cap.getRealTimestamp();

/* compare and draw */
pthread_mutex_lock(&mutex);
for (it = l.begin(); it != l.end();) {
    int64_t diff = it->timestamp - frame_time;
    if (diff < DROP_TIME * 1.3) {
        it = l.erase(it);
    } else if (diff < -WAIT_TIME*0.1) {
        for (int i = 0; i < it->box_num; ++i)
            rectangle(frame, it->box[i].start, it->box[i].end, it->box[i].color, 2);
        it++;
    } else
        break;

}
pthread_mutex_unlock(&mutex);

おすすめ

転載: www.cnblogs.com/gr-nick/p/10993823.html