Document sequential presentation diagnostics and simplify GUI frame ownership
This commit is contained in:
1 parent
4ed2c4bbab
commit
a9b91145a6
3 files changed
+81
-92
No files matched your search
@@ -386,61 +386,61 @@ bool LiveVideoEncoder::encode(const QImage& image, uint64_t pts, bool key, QList
|
||||
const bool constrained = m->config.profile != LiveVideoProfile::Automatic;
|
||||
qint64 preparedUs = 0, submittedUs = 0;
|
||||
if (!image.isNull()) {
|
||||
QImage canvas(m->config.width, m->config.height, QImage::Format_RGB32); canvas.fill(Qt::black);
|
||||
QSize fitted = image.size().scaled(canvas.size(), Qt::KeepAspectRatio);
|
||||
{ QPainter painter(&canvas); painter.drawImage(QRect(QPoint((canvas.width() - fitted.width()) / 2,
|
||||
(canvas.height() - fitted.height()) / 2), fitted), image); }
|
||||
result = av_frame_make_writable(m->frame);
|
||||
m->scale = sws_getCachedContext(m->scale, canvas.width(), canvas.height(), AV_PIX_FMT_RGB32,
|
||||
m->frame->width, m->frame->height, static_cast<AVPixelFormat>(m->frame->format), SWS_FAST_BILINEAR, nullptr, nullptr, nullptr);
|
||||
if (!m->scale) result = AVERROR(ENOMEM);
|
||||
if (result >= 0) {
|
||||
const int* coefficients = sws_getCoefficients(SWS_CS_ITU709);
|
||||
sws_setColorspaceDetails(m->scale, coefficients, 1, coefficients, 0, 0, 1 << 16, 1 << 16);
|
||||
const uint8_t* input[4] = {canvas.constBits(), nullptr, nullptr, nullptr};
|
||||
int stride[4] = {static_cast<int>(canvas.bytesPerLine()), 0, 0, 0};
|
||||
result = sws_scale(m->scale, input, stride, 0, canvas.height(), m->frame->data, m->frame->linesize);
|
||||
}
|
||||
if (result >= 0 && m->reportTimer.elapsed() >= 1000 && debug_should_output(DEBUG_LEVEL_TRACE, DEBUG_CATEGORY_DEBUG)
|
||||
&& (m->frame->format == AV_PIX_FMT_NV12 || m->frame->format == AV_PIX_FMT_YUV420P)) {
|
||||
uint64_t edges = 0, samples = 0;
|
||||
int minimum = 255, maximum = 0;
|
||||
for (int y = 0; y + 1 < m->frame->height; y += 16) {
|
||||
const uint8_t* row = m->frame->data[0] + y * m->frame->linesize[0];
|
||||
for (int x = 0; x + 1 < m->frame->width; x += 16) {
|
||||
int value = row[x]; minimum = std::min(minimum, value); maximum = std::max(maximum, value);
|
||||
edges += std::abs(value - row[x + 1]) + std::abs(value - row[x + m->frame->linesize[0]]); samples += 2;
|
||||
}
|
||||
QImage canvas(m->config.width, m->config.height, QImage::Format_RGB32); canvas.fill(Qt::black);
|
||||
QSize fitted = image.size().scaled(canvas.size(), Qt::KeepAspectRatio);
|
||||
{ QPainter painter(&canvas); painter.drawImage(QRect(QPoint((canvas.width() - fitted.width()) / 2,
|
||||
(canvas.height() - fitted.height()) / 2), fitted), image); }
|
||||
result = av_frame_make_writable(m->frame);
|
||||
m->scale = sws_getCachedContext(m->scale, canvas.width(), canvas.height(), AV_PIX_FMT_RGB32,
|
||||
m->frame->width, m->frame->height, static_cast<AVPixelFormat>(m->frame->format), SWS_FAST_BILINEAR, nullptr, nullptr, nullptr);
|
||||
if (!m->scale) result = AVERROR(ENOMEM);
|
||||
if (result >= 0) {
|
||||
const int* coefficients = sws_getCoefficients(SWS_CS_ITU709);
|
||||
sws_setColorspaceDetails(m->scale, coefficients, 1, coefficients, 0, 0, 1 << 16, 1 << 16);
|
||||
const uint8_t* input[4] = {canvas.constBits(), nullptr, nullptr, nullptr};
|
||||
int stride[4] = {static_cast<int>(canvas.bytesPerLine()), 0, 0, 0};
|
||||
result = sws_scale(m->scale, input, stride, 0, canvas.height(), m->frame->data, m->frame->linesize);
|
||||
}
|
||||
DEBUG_TRACE(DEBUG_CATEGORY_DEBUG,
|
||||
"video encoder input name=%s pts=%llu source=%dx%d encoded=%dx%d pixel=%d luma_min=%d luma_max=%d edge_x1000=%llu",
|
||||
qPrintable(m->name), (unsigned long long)pts, image.width(), image.height(), m->frame->width, m->frame->height,
|
||||
m->frame->format, minimum, maximum, (unsigned long long)(samples ? edges * 1000 / samples : 0));
|
||||
}
|
||||
if (constrained && m->timestamps.size() >= 8) {
|
||||
m->error = "GPU encoder exceeded the bounded input pipeline";
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_VIDEO, "call encoder stalled name=%s pending=%zu pts=%llu",
|
||||
qPrintable(m->name), m->timestamps.size(), (unsigned long long)pts); return false;
|
||||
}
|
||||
bool forceKey = key && (m->forcedKeys || m->submittedFrames == 0);
|
||||
m->frame->pts = av_rescale_q(static_cast<int64_t>(pts), AVRational{1, 1000000}, m->codec->time_base);
|
||||
m->frame->pict_type = forceKey ? AV_PICTURE_TYPE_I : AV_PICTURE_TYPE_NONE;
|
||||
if (forceKey) m->frame->flags |= AV_FRAME_FLAG_KEY; else m->frame->flags &= ~AV_FRAME_FLAG_KEY;
|
||||
AVFrame* hardware = nullptr;
|
||||
if (result >= 0 && m->codec->hw_frames_ctx) {
|
||||
hardware = av_frame_alloc();
|
||||
result = hardware ? av_hwframe_get_buffer(m->codec->hw_frames_ctx, hardware, 0) : AVERROR(ENOMEM);
|
||||
if (result >= 0) result = av_hwframe_transfer_data(hardware, m->frame, 0);
|
||||
if (result >= 0) result = av_frame_copy_props(hardware, m->frame);
|
||||
}
|
||||
preparedUs = timer.nsecsElapsed() / 1000;
|
||||
if (result >= 0) result = avcodec_send_frame(m->codec, hardware ? hardware : m->frame);
|
||||
submittedUs = timer.nsecsElapsed() / 1000;
|
||||
if (result >= 0) {
|
||||
m->submittedFrames++;
|
||||
if (constrained) m->timestamps.emplace_back(m->frame->pts, pts);
|
||||
}
|
||||
av_frame_free(&hardware);
|
||||
if (result >= 0 && m->reportTimer.elapsed() >= 1000 && debug_should_output(DEBUG_LEVEL_TRACE, DEBUG_CATEGORY_DEBUG)
|
||||
&& (m->frame->format == AV_PIX_FMT_NV12 || m->frame->format == AV_PIX_FMT_YUV420P)) {
|
||||
uint64_t edges = 0, samples = 0;
|
||||
int minimum = 255, maximum = 0;
|
||||
for (int y = 0; y + 1 < m->frame->height; y += 16) {
|
||||
const uint8_t* row = m->frame->data[0] + y * m->frame->linesize[0];
|
||||
for (int x = 0; x + 1 < m->frame->width; x += 16) {
|
||||
int value = row[x]; minimum = std::min(minimum, value); maximum = std::max(maximum, value);
|
||||
edges += std::abs(value - row[x + 1]) + std::abs(value - row[x + m->frame->linesize[0]]); samples += 2;
|
||||
}
|
||||
}
|
||||
DEBUG_TRACE(DEBUG_CATEGORY_DEBUG,
|
||||
"video encoder input name=%s pts=%llu source=%dx%d encoded=%dx%d pixel=%d luma_min=%d luma_max=%d edge_x1000=%llu",
|
||||
qPrintable(m->name), (unsigned long long)pts, image.width(), image.height(), m->frame->width, m->frame->height,
|
||||
m->frame->format, minimum, maximum, (unsigned long long)(samples ? edges * 1000 / samples : 0));
|
||||
}
|
||||
if (constrained && m->timestamps.size() >= 8) {
|
||||
m->error = "GPU encoder exceeded the bounded input pipeline";
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_VIDEO, "call encoder stalled name=%s pending=%zu pts=%llu",
|
||||
qPrintable(m->name), m->timestamps.size(), (unsigned long long)pts); return false;
|
||||
}
|
||||
bool forceKey = key && (m->forcedKeys || m->submittedFrames == 0);
|
||||
m->frame->pts = av_rescale_q(static_cast<int64_t>(pts), AVRational{1, 1000000}, m->codec->time_base);
|
||||
m->frame->pict_type = forceKey ? AV_PICTURE_TYPE_I : AV_PICTURE_TYPE_NONE;
|
||||
if (forceKey) m->frame->flags |= AV_FRAME_FLAG_KEY; else m->frame->flags &= ~AV_FRAME_FLAG_KEY;
|
||||
AVFrame* hardware = nullptr;
|
||||
if (result >= 0 && m->codec->hw_frames_ctx) {
|
||||
hardware = av_frame_alloc();
|
||||
result = hardware ? av_hwframe_get_buffer(m->codec->hw_frames_ctx, hardware, 0) : AVERROR(ENOMEM);
|
||||
if (result >= 0) result = av_hwframe_transfer_data(hardware, m->frame, 0);
|
||||
if (result >= 0) result = av_frame_copy_props(hardware, m->frame);
|
||||
}
|
||||
preparedUs = timer.nsecsElapsed() / 1000;
|
||||
if (result >= 0) result = avcodec_send_frame(m->codec, hardware ? hardware : m->frame);
|
||||
submittedUs = timer.nsecsElapsed() / 1000;
|
||||
if (result >= 0) {
|
||||
m->submittedFrames++;
|
||||
if (constrained) m->timestamps.emplace_back(m->frame->pts, pts);
|
||||
}
|
||||
av_frame_free(&hardware);
|
||||
} else if (finish) result = avcodec_send_frame(m->codec, nullptr);
|
||||
AVPacket* packet = av_packet_alloc();
|
||||
if (!packet) result = AVERROR(ENOMEM);
|
||||
|
||||
Reference in new issue
Block a user