X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=nageru%2Fmjpeg_encoder.cpp;h=07e302c4e93148c2b9a83edfc1034e5465f1e8bc;hb=0b776ba19a0b0703f87e5529b2e4f82af6b50435;hp=9ddb9ff15af20598ead26b5b9a6c282f16861e6c;hpb=c913b0254382c2a1bd7410d720e45dfc63223c9c;p=nageru diff --git a/nageru/mjpeg_encoder.cpp b/nageru/mjpeg_encoder.cpp index 9ddb9ff..07e302c 100644 --- a/nageru/mjpeg_encoder.cpp +++ b/nageru/mjpeg_encoder.cpp @@ -16,6 +16,7 @@ extern "C" { #include "flags.h" #include "shared/httpd.h" #include "shared/memcpy_interleaved.h" +#include "shared/metrics.h" #include "pbo_frame_allocator.h" #include "shared/timebase.h" #include "va_display_with_cleanup.h" @@ -177,12 +178,26 @@ MJPEGEncoder::MJPEGEncoder(HTTPD *httpd, const string &va_display) va_receiver_thread = thread(&MJPEGEncoder::va_receiver_thread_func, this); } + global_metrics.add("mjpeg_frames", {{ "status", "dropped" }, { "reason", "zero_size" }}, &metric_mjpeg_frames_zero_size_dropped); + global_metrics.add("mjpeg_frames", {{ "status", "dropped" }, { "reason", "interlaced" }}, &metric_mjpeg_frames_interlaced_dropped); + global_metrics.add("mjpeg_frames", {{ "status", "dropped" }, { "reason", "unsupported_pixel_format" }}, &metric_mjpeg_frames_unsupported_pixel_format_dropped); + global_metrics.add("mjpeg_frames", {{ "status", "dropped" }, { "reason", "oversized" }}, &metric_mjpeg_frames_oversized_dropped); + global_metrics.add("mjpeg_frames", {{ "status", "dropped" }, { "reason", "overrun" }}, &metric_mjpeg_overrun_dropped); + global_metrics.add("mjpeg_frames", {{ "status", "submitted" }}, &metric_mjpeg_overrun_submitted); + running = true; } MJPEGEncoder::~MJPEGEncoder() { av_free(avctx->pb->buffer); + + global_metrics.remove("mjpeg_frames", {{ "status", "dropped" }, { "reason", "zero_size" }}); + global_metrics.remove("mjpeg_frames", {{ "status", "dropped" }, { "reason", "interlaced" }}); + global_metrics.remove("mjpeg_frames", {{ "status", "dropped" }, { "reason", "unsupported_pixel_format" }}); + global_metrics.remove("mjpeg_frames", {{ "status", "dropped" }, { "reason", "oversized" }}); + global_metrics.remove("mjpeg_frames", {{ "status", "dropped" }, { "reason", "overrun" }}); + global_metrics.remove("mjpeg_frames", {{ "status", "submitted" }}); } void MJPEGEncoder::stop() @@ -193,6 +208,7 @@ void MJPEGEncoder::stop() running = false; should_quit = true; any_frames_to_be_encoded.notify_all(); + any_frames_encoding.notify_all(); encoder_thread.join(); if (va_dpy != nullptr) { va_receiver_thread.join(); @@ -247,27 +263,33 @@ void MJPEGEncoder::upload_frame(int64_t pts, unsigned card_index, RefCountedFram { PBOFrameAllocator::Userdata *userdata = (PBOFrameAllocator::Userdata *)frame->userdata; if (video_format.width == 0 || video_format.height == 0) { + ++metric_mjpeg_frames_zero_size_dropped; return; } if (video_format.interlaced) { fprintf(stderr, "Card %u: Ignoring JPEG encoding for interlaced frame\n", card_index); + ++metric_mjpeg_frames_interlaced_dropped; return; } if (userdata->pixel_format != PixelFormat_8BitYCbCr || !frame->interleaved) { fprintf(stderr, "Card %u: Ignoring JPEG encoding for unsupported pixel format\n", card_index); + ++metric_mjpeg_frames_unsupported_pixel_format_dropped; return; } if (video_format.width > 4096 || video_format.height > 4096) { fprintf(stderr, "Card %u: Ignoring JPEG encoding for oversized frame\n", card_index); + ++metric_mjpeg_frames_oversized_dropped; return; } lock_guard lock(mu); - if (frames_to_be_encoded.size() + frames_encoding.size() > 10) { + if (frames_to_be_encoded.size() + frames_encoding.size() > 50) { fprintf(stderr, "WARNING: MJPEG encoding doesn't keep up, discarding frame.\n"); + ++metric_mjpeg_overrun_dropped; return; } + ++metric_mjpeg_overrun_submitted; frames_to_be_encoded.push(QueuedFrame{ pts, card_index, frame, video_format, y_offset, cbcr_offset }); any_frames_to_be_encoded.notify_all(); } @@ -296,7 +318,7 @@ void MJPEGEncoder::encoder_thread_func() } else { // Encode synchronously, in the same thread. vector jpeg = encode_jpeg_libjpeg(qf); - write_mjpeg_packet(qf.pts, qf.card_index, jpeg); + write_mjpeg_packet(qf.pts, qf.card_index, jpeg.data(), jpeg.size()); } } @@ -306,16 +328,17 @@ void MJPEGEncoder::encoder_thread_func() free(tmp_cr); } -void MJPEGEncoder::write_mjpeg_packet(int64_t pts, unsigned card_index, const vector &jpeg) +void MJPEGEncoder::write_mjpeg_packet(int64_t pts, unsigned card_index, const uint8_t *jpeg, size_t jpeg_size) { AVPacket pkt; memset(&pkt, 0, sizeof(pkt)); pkt.buf = nullptr; - pkt.data = const_cast(&jpeg[0]); - pkt.size = jpeg.size(); + pkt.data = const_cast(jpeg); + pkt.size = jpeg_size; pkt.stream_index = card_index; pkt.flags = AV_PKT_FLAG_KEY; - pkt.pts = pkt.dts = pts; + AVRational time_base = avctx->streams[pkt.stream_index]->time_base; + pkt.pts = pkt.dts = av_rescale_q(pts, AVRational{ 1, TIMEBASE }, time_base); if (av_write_frame(avctx.get(), &pkt) < 0) { fprintf(stderr, "av_write_frame() failed\n"); @@ -685,13 +708,11 @@ void MJPEGEncoder::va_receiver_thread_func() va_status = vaMapBuffer(va_dpy->va_dpy, qf.resources.data_buffer, (void **)&segment); CHECK_VASTATUS(va_status, "vaMapBuffer"); - const char *coded_buf = reinterpret_cast(segment->buf); - vector jpeg(coded_buf, coded_buf + segment->size); + const uint8_t *coded_buf = reinterpret_cast(segment->buf); + write_mjpeg_packet(qf.pts, qf.card_index, coded_buf, segment->size); va_status = vaUnmapBuffer(va_dpy->va_dpy, qf.resources.data_buffer); CHECK_VASTATUS(va_status, "vaUnmapBuffer"); - - write_mjpeg_packet(qf.pts, qf.card_index, jpeg); } }