diff options
Diffstat (limited to 'modules/vidloop/vidloop.c')
-rw-r--r-- | modules/vidloop/vidloop.c | 229 |
1 files changed, 209 insertions, 20 deletions
diff --git a/modules/vidloop/vidloop.c b/modules/vidloop/vidloop.c index d99fa49..ca7979b 100644 --- a/modules/vidloop/vidloop.c +++ b/modules/vidloop/vidloop.c @@ -32,12 +32,6 @@ */ -/** Internal pixel-format */ -#ifndef VIDLOOP_INTERNAL_FMT -#define VIDLOOP_INTERNAL_FMT (VID_FMT_YUV420P) -#endif - - /** Video Statistics */ struct vstat { uint64_t tsamp; @@ -58,13 +52,31 @@ struct video_loop { struct viddec_state *dec; struct vidisp_st *vidisp; struct vidsrc_st *vsrc; + struct vidsrc_prm srcprm; struct list filtencl; struct list filtdecl; struct vstat stat; struct tmr tmr_bw; + struct vidsz src_size; + struct vidsz disp_size; + enum vidfmt src_fmt; + uint64_t ts_start; /* usec */ + uint64_t ts_last; /* usec */ uint16_t seq; bool need_conv; + bool started; int err; + + struct { + uint64_t src_frames; + uint64_t enc_bytes; + uint64_t enc_packets; + uint64_t disp_frames; + } stats; + + bool timestamp_set; + uint64_t timestamp_base; /* lowest timestamp */ + uint64_t timestamp_last; /* most recent timestamp */ }; @@ -108,21 +120,27 @@ static int display(struct video_loop *vl, struct vidframe *frame) warning("vidloop: error in video-filters (%m)\n", err); } + /* save the displayed frame info */ + vl->disp_size = frame->size; + ++vl->stats.disp_frames; + /* display frame */ err = vidisp_display(vl->vidisp, "Video Loop", frame); if (err == ENODEV) { info("vidloop: video-display was closed\n"); vl->vidisp = mem_deref(vl->vidisp); vl->err = err; + goto out; } + out: mem_deref(frame_filt); return err; } -static int packet_handler(bool marker, uint32_t rtp_ts, +static int packet_handler(bool marker, uint64_t rtp_ts, const uint8_t *hdr, size_t hdr_len, const uint8_t *pld, size_t pld_len, void *arg) @@ -134,6 +152,9 @@ static int packet_handler(bool marker, uint32_t rtp_ts, int err = 0; (void)rtp_ts; + ++vl->stats.enc_packets; + vl->stats.enc_bytes += (hdr_len + pld_len); + mb = mbuf_alloc(hdr_len + pld_len); if (!mb) return ENOMEM; @@ -172,26 +193,65 @@ static int packet_handler(bool marker, uint32_t rtp_ts, } -static void vidsrc_frame_handler(struct vidframe *frame, void *arg) +static double stream_duration(const struct video_loop *vl) +{ + uint64_t dur; + + if (vl->timestamp_set) + dur = vl->timestamp_last - vl->timestamp_base; + else + dur = 0; + + return video_timestamp_to_seconds(dur); +} + + +static void vidsrc_frame_handler(struct vidframe *frame, uint64_t timestamp, + void *arg) { struct video_loop *vl = arg; struct vidframe *f2 = NULL; struct le *le; + const uint64_t now = tmr_jiffies_usec(); int err = 0; + /* save the timing info */ + if (!gvl->ts_start) + gvl->ts_start = now; + gvl->ts_last = now; + + /* save the video frame info */ + vl->src_size = frame->size; + vl->src_fmt = frame->fmt; + ++vl->stats.src_frames; + + /* Timestamp logic */ + if (vl->timestamp_set) { + if (timestamp <= vl->timestamp_base) { + info("vidloop: timestamp wrapped -- reset base\n"); + vl->timestamp_base = timestamp; + } + vl->timestamp_last = timestamp; + } + else { + vl->timestamp_base = timestamp; + vl->timestamp_last = timestamp; + vl->timestamp_set = true; + } + ++vl->stat.frames; - if (frame->fmt != VIDLOOP_INTERNAL_FMT) { + if (frame->fmt != (enum vidfmt)vl->cfg.enc_fmt) { if (!vl->need_conv) { info("vidloop: NOTE: pixel-format conversion" " needed: %s --> %s\n", vidfmt_name(frame->fmt), - vidfmt_name(VIDLOOP_INTERNAL_FMT)); + vidfmt_name(vl->cfg.enc_fmt)); vl->need_conv = true; } - if (vidframe_alloc(&f2, VIDLOOP_INTERNAL_FMT, &frame->size)) + if (vidframe_alloc(&f2, vl->cfg.enc_fmt, &frame->size)) return; vidconv(f2, frame, 0); @@ -209,21 +269,147 @@ static void vidsrc_frame_handler(struct vidframe *frame, void *arg) } if (vl->vc_enc && vl->enc) { - (void)vl->vc_enc->ench(vl->enc, false, frame); + err = vl->vc_enc->ench(vl->enc, false, frame); + if (err) { + warning("vidloop: encoder error (%m)\n", err); + goto out; + } } else { vl->stat.bytes += vidframe_size(frame->fmt, &frame->size); (void)display(vl, frame); } + out: mem_deref(f2); } +static int print_stats(struct re_printf *pf, const struct video_loop *vl) +{ + const struct config_video *cfg = &vl->cfg; + double real_dur = .0; + int err = 0; + + if (vl->ts_start) { + real_dur = stream_duration(vl); + } + + err |= re_hprintf(pf, "~~~~~ Videoloop summary: ~~~~~\n"); + + /* Source */ + if (vl->vsrc) { + struct vidsrc *vs = vidsrc_get(vl->vsrc); + double avg_fps = .0; + + if (vl->stats.src_frames >= 2) + avg_fps = (vl->stats.src_frames-1) / real_dur; + + err |= re_hprintf(pf, + "* Source\n" + " module %s\n" + " resolution %u x %u (actual %u x %u)\n" + " pixformat %s\n" + " frames %llu\n" + " framerate %.2f fps (avg %.2f fps)\n" + " duration %.3f sec\n" + "\n" + , + vs->name, + cfg->width, cfg->height, + vl->src_size.w, vl->src_size.h, + vidfmt_name(vl->src_fmt), + vl->stats.src_frames, + vl->srcprm.fps, avg_fps, + real_dur); + } + + /* Video conversion */ + if (vl->need_conv) { + err |= re_hprintf(pf, + "* Vidconv\n" + " pixformat %s\n" + "\n" + , + vidfmt_name(cfg->enc_fmt)); + } + + /* Filters */ + if (!list_isempty(baresip_vidfiltl())) { + struct le *le; + + err |= re_hprintf(pf, + "* Filters (%u):", + list_count(baresip_vidfiltl())); + + for (le = list_head(baresip_vidfiltl()); le; le = le->next) { + struct vidfilt *vf = le->data; + err |= re_hprintf(pf, " %s", vf->name); + } + err |= re_hprintf(pf, "\n\n"); + } + + /* Encoder */ + if (vl->vc_enc) { + double avg_bitrate; + double avg_pktrate; + + avg_bitrate = 8.0 * (double)vl->stats.enc_bytes / real_dur; + avg_pktrate = (double)vl->stats.enc_packets / real_dur; + + err |= re_hprintf(pf, + "* Encoder\n" + " module %s\n" + " bitrate %u bit/s (avg %.1f bit/s)\n" + " packets %llu (avg %.1f pkt/s)\n" + "\n" + , + vl->vc_enc->name, + cfg->bitrate, avg_bitrate, + vl->stats.enc_packets, avg_pktrate); + } + + /* Decoder */ + if (vl->vc_dec) { + err |= re_hprintf(pf, + "* Decoder\n" + " module %s\n" + " key-frames %zu\n" + "\n" + , + vl->vc_dec->name, + vl->stat.n_intra); + } + + /* Display */ + if (vl->vidisp) { + struct vidisp *vd = vidisp_get(vl->vidisp); + + err |= re_hprintf(pf, + "* Display\n" + " module %s\n" + " resolution %u x %u\n" + " fullscreen %s\n" + " frames %llu\n" + "\n" + , + vd->name, + vl->disp_size.w, vl->disp_size.h, + cfg->fullscreen ? "Yes" : "No", + vl->stats.disp_frames); + } + + return err; +} + + static void vidloop_destructor(void *arg) { struct video_loop *vl = arg; + if (vl->started) + re_printf("%H\n", print_stats, vl); + tmr_cancel(&vl->tmr_bw); mem_deref(vl->vsrc); mem_deref(vl->enc); @@ -253,7 +439,7 @@ static int enable_codec(struct video_loop *vl, const char *name) return ENOENT; } - info("vidloop: enabled encoder %s (%u fps, %u bit/s)\n", + info("vidloop: enabled encoder %s (%.2f fps, %u bit/s)\n", vl->vc_enc->name, prm.fps, prm.bitrate); vl->vc_dec = vidcodec_find_decoder(vidcodecl, name); @@ -287,10 +473,12 @@ static void print_status(struct video_loop *vl) { (void)re_fprintf(stdout, "\rstatus:" - " [%s] [%s] intra=%zu " + " %.3f sec [%s] [%s] fmt=%s intra=%zu " " EFPS=%.1f %u kbit/s \r", + stream_duration(vl), vl->vc_enc ? vl->vc_enc->name : "", vl->vc_dec ? vl->vc_dec->name : "", + vidfmt_name(vl->cfg.enc_fmt), vl->stat.n_intra, vl->stat.efps, vl->stat.bitrate); fflush(stdout); @@ -326,7 +514,7 @@ static void timeout_bw(void *arg) return; } - tmr_start(&vl->tmr_bw, 2000, timeout_bw, vl); + tmr_start(&vl->tmr_bw, 500, timeout_bw, vl); calc_bitrate(vl); print_status(vl); @@ -335,19 +523,18 @@ static void timeout_bw(void *arg) static int vsrc_reopen(struct video_loop *vl, const struct vidsz *sz) { - struct vidsrc_prm prm; int err; - info("vidloop: %s,%s: open video source: %u x %u at %u fps\n", + info("vidloop: %s,%s: open video source: %u x %u at %.2f fps\n", vl->cfg.src_mod, vl->cfg.src_dev, sz->w, sz->h, vl->cfg.fps); - prm.orient = VIDORIENT_PORTRAIT; - prm.fps = vl->cfg.fps; + vl->srcprm.orient = VIDORIENT_PORTRAIT; + vl->srcprm.fps = vl->cfg.fps; vl->vsrc = mem_deref(vl->vsrc); err = vidsrc_alloc(&vl->vsrc, baresip_vidsrcl(), - vl->cfg.src_mod, NULL, &prm, sz, + vl->cfg.src_mod, NULL, &vl->srcprm, sz, NULL, vl->cfg.src_dev, vidsrc_frame_handler, NULL, vl); if (err) { @@ -462,6 +649,8 @@ static int vidloop_start(struct re_printf *pf, void *arg) return err; } + gvl->started = true; + return err; } |