perf: prefer VideoToolbox decoding with software fallback

This commit is contained in:
2026-10-17 01:11:58 +02:00
parent 599c1492ee
commit fcad96de62
8 changed files with 513 additions and 36 deletions
+14 -4
View File
@@ -2,6 +2,7 @@
#include "player_macos.h"
#include "output.hpp"
#include "progress_reporter.hpp"
#include "video_decoder.hpp"
extern "C" {
#include <libavcodec/avcodec.h>
@@ -64,6 +65,7 @@ struct Track {
AVPacket *packet = nullptr;
bool packetPending = false;
bool receiving = false;
bool firstPacket = true;
double packetBufferedEnd = 0;
double decoderBufferedEnd = 0;
bool sourceEnded = false;
@@ -456,6 +458,7 @@ struct Player {
track.codec->pkt_timebase = source->streams[index]->time_base;
// A bounded software decoder pool; FFmpeg owns its internal frame reorder buffer.
track.codec->thread_count = 2;
if (type == AVMEDIA_TYPE_VIDEO) playback::preferVideoToolbox(track.codec);
check(avcodec_open2(track.codec, decoder, nullptr), "Opening decoder");
}
@@ -466,6 +469,7 @@ struct Player {
if (!track.codec) continue;
avcodec_flush_buffers(track.codec);
track.drainSent = track.drained = false;
track.firstPacket = true;
av_packet_unref(track.packet);
track.packetPending = track.receiving = track.sourceEnded = false;
track.packetBufferedEnd = track.decoderBufferedEnd = 0;
@@ -1086,8 +1090,11 @@ struct Player {
return;
skipPresentedTimestamp = AV_NOPTS_VALUE;
}
const int size = av_image_get_buffer_size(static_cast<AVPixelFormat>(decoded->format),
decoded->width, decoded->height, 1);
Frame frame(av_frame_alloc());
if (!frame) throw std::bad_alloc();
check(playback::refVideoFrame(frame.get(), decoded), "Mapping decoded video");
const int size = av_image_get_buffer_size(static_cast<AVPixelFormat>(frame->format),
frame->width, frame->height, 1);
check(size, "Sizing decoded video");
const auto bytes = static_cast<std::size_t>(size);
if (bytes > videoByteLimit)
@@ -1100,8 +1107,6 @@ struct Player {
videoBytes -= video.back().bytes;
video.pop_back();
}
Frame frame(av_frame_clone(decoded));
if (!frame) throw std::bad_alloc();
VideoFrame item{std::move(frame), pts, pts + frameDuration, bytes, track.timestampOccurrence};
auto insertion = std::upper_bound(video.begin(), video.end(), pts,
[](double value, const VideoFrame &entry) { return value < entry.pts; });
@@ -1137,6 +1142,11 @@ struct Player {
return true;
}
if (track.packetPending) {
if (slot == 1 && track.firstPacket) {
check(playback::prepareVideoPacket(track.codec, *track.stream()->codecpar, *track.packet),
"Preparing video decoder preroll");
track.firstPacket = false;
}
const int result = avcodec_send_packet(track.codec, track.packet);
if (result != AVERROR(EAGAIN)) {
check(result, "Sending media packet to decoder");