]> git.sesse.net Git - nageru/blobdiff - nageru/quicksync_encoder.cpp
Collapse all the 10-bit flags.
[nageru] / nageru / quicksync_encoder.cpp
index 7ec9f71c5eced50096af99bd4baed2a433cd8a2b..d0ca914e2901b031cc8f56899a4ed81eb1a78bd1 100644 (file)
@@ -40,7 +40,7 @@ extern "C" {
 #include <libavcodec/avcodec.h>
 #include <libavformat/avio.h>
 #include <libavutil/error.h>
-#include <libdrm/drm_fourcc.h>
+#include <drm_fourcc.h>
 
 }  // namespace
 
@@ -719,6 +719,9 @@ void QuickSyncEncoderImpl::enable_zerocopy_if_possible()
        } else if (global_flags.x264_video_to_http) {
                fprintf(stderr, "Disabling zerocopy H.264 encoding due to --http-x264-video.\n");
                use_zerocopy = false;
+       } else if (global_flags.av1_video_to_http) {
+               fprintf(stderr, "Disabling zerocopy H.264 encoding due to --http-av1-video.\n");
+               use_zerocopy = false;
        } else if (!global_flags.v4l_output_device.empty()) {
                fprintf(stderr, "Disabling zerocopy H.264 encoding due to --v4l-output.\n");
                use_zerocopy = false;
@@ -728,88 +731,16 @@ void QuickSyncEncoderImpl::enable_zerocopy_if_possible()
        global_flags.use_zerocopy = use_zerocopy;
 }
 
-unique_ptr<VADisplayWithCleanup> va_open_display(const string &va_display)
+static unique_ptr<VADisplayWithCleanup> try_open_va_h264(const string &va_display, VAProfile *h264_profile, string *error)
 {
-       if (va_display.empty() || va_display[0] != '/') {  // An X display.
-               Display *x11_display = XOpenDisplay(va_display.empty() ? nullptr : va_display.c_str());
-               if (x11_display == nullptr) {
-                       fprintf(stderr, "error: can't connect to X server!\n");
-                       return nullptr;
-               }
-
-               unique_ptr<VADisplayWithCleanup> ret(new VADisplayWithCleanup);
-               ret->x11_display = x11_display;
-               ret->can_use_zerocopy = true;
-               ret->va_dpy = vaGetDisplay(x11_display);
-               if (ret->va_dpy == nullptr) {
-                       return nullptr;
-               }
-               return ret;
-       } else {  // A DRM node on the filesystem (e.g. /dev/dri/renderD128).
-               int drm_fd = open(va_display.c_str(), O_RDWR);
-               if (drm_fd == -1) {
-                       perror(va_display.c_str());
-                       return NULL;
-               }
-               unique_ptr<VADisplayWithCleanup> ret(new VADisplayWithCleanup);
-               ret->drm_fd = drm_fd;
-               ret->can_use_zerocopy = false;
-               ret->va_dpy = vaGetDisplayDRM(drm_fd);
-               if (ret->va_dpy == nullptr) {
-                       return nullptr;
-               }
-               return ret;
-       }
-}
-
-unique_ptr<VADisplayWithCleanup> try_open_va(const string &va_display, VAProfile *h264_profile, string *error)
-{
-       unique_ptr<VADisplayWithCleanup> va_dpy = va_open_display(va_display);
-       if (va_dpy == nullptr) {
-               if (error) *error = "Opening VA display failed";
-               return nullptr;
-       }
-       int major_ver, minor_ver;
-       VAStatus va_status = vaInitialize(va_dpy->va_dpy, &major_ver, &minor_ver);
-       if (va_status != VA_STATUS_SUCCESS) {
-               char buf[256];
-               snprintf(buf, sizeof(buf), "vaInitialize() failed with status %d\n", va_status);
-               if (error != nullptr) *error = buf;
-               return nullptr;
-       }
-
-       int num_entrypoints = vaMaxNumEntrypoints(va_dpy->va_dpy);
-       unique_ptr<VAEntrypoint[]> entrypoints(new VAEntrypoint[num_entrypoints]);
-       if (entrypoints == nullptr) {
-               if (error != nullptr) *error = "Failed to allocate memory for VA entry points";
-               return nullptr;
-       }
-
-       // Try the profiles from highest to lowest until we find one that can be encoded.
-       constexpr VAProfile profile_list[] = { VAProfileH264High, VAProfileH264Main, VAProfileH264ConstrainedBaseline };
-       for (unsigned i = 0; i < sizeof(profile_list) / sizeof(profile_list[0]); ++i) {
-               vaQueryConfigEntrypoints(va_dpy->va_dpy, profile_list[i], entrypoints.get(), &num_entrypoints);
-               for (int slice_entrypoint = 0; slice_entrypoint < num_entrypoints; slice_entrypoint++) {
-                       if (entrypoints[slice_entrypoint] != VAEntrypointEncSlice) {
-                               continue;
-                       }
-
-                       // We found a usable encoder, so return it.
-                       if (h264_profile != nullptr) {
-                               *h264_profile = profile_list[i];
-                       }
-                       return va_dpy;
-               }
-       }
-
-       if (error != nullptr) *error = "Can't find VAEntrypointEncSlice for H264 profiles";
-       return nullptr;
+       return try_open_va(va_display, { VAProfileH264High, VAProfileH264Main, VAProfileH264ConstrainedBaseline },
+               VAEntrypointEncSlice, /*desired_configs=*/{}, h264_profile, error);
 }
 
 int QuickSyncEncoderImpl::init_va(const string &va_display)
 {
     string error;
-    va_dpy = try_open_va(va_display, &h264_profile, &error);
+    va_dpy = try_open_va_h264(va_display, &h264_profile, &error);
     if (va_dpy == nullptr) {
        fprintf(stderr, "error: %s\n", error.c_str());
         abort();
@@ -975,7 +906,7 @@ int QuickSyncEncoderImpl::setup_encode()
                        gl_surfaces[i].y_tex = resource_pool->create_2d_texture(GL_R8, 1, 1);
                        gl_surfaces[i].cbcr_tex = resource_pool->create_2d_texture(GL_RG8, 1, 1);
                } else {
-                       size_t bytes_per_pixel = (global_flags.x264_bit_depth > 8) ? 2 : 1;
+                       size_t bytes_per_pixel = (global_flags.bit_depth > 8) ? 2 : 1;
 
                        // Generate a PBO to read into. It doesn't necessarily fit 1:1 with the VA-API
                        // buffers, due to potentially differing pitch.
@@ -1414,7 +1345,8 @@ void QuickSyncEncoderImpl::save_codeddata(GLSurface *surf, storage_task task)
                        file_mux->add_packet(pkt, task.pts + global_delay(), task.dts + global_delay());
                }
                if (!global_flags.uncompressed_video_to_http &&
-                   !global_flags.x264_video_to_http) {
+                   !global_flags.x264_video_to_http &&
+                   !global_flags.av1_video_to_http) {
                        stream_mux->add_packet(pkt, task.pts + global_delay(), task.dts + global_delay());
                }
        }
@@ -1507,8 +1439,8 @@ void QuickSyncEncoderImpl::release_gl_resources()
        has_released_gl_resources = true;
 }
 
-QuickSyncEncoderImpl::QuickSyncEncoderImpl(const std::string &filename, ResourcePool *resource_pool, QSurface *surface, const string &va_display, int width, int height, AVOutputFormat *oformat, X264Encoder *x264_encoder, DiskSpaceEstimator *disk_space_estimator)
-       : current_storage_frame(0), resource_pool(resource_pool), surface(surface), x264_encoder(x264_encoder), frame_width(width), frame_height(height), disk_space_estimator(disk_space_estimator)
+QuickSyncEncoderImpl::QuickSyncEncoderImpl(const std::string &filename, ResourcePool *resource_pool, QSurface *surface, const string &va_display, int width, int height, const AVOutputFormat *oformat, VideoCodecInterface *http_encoder, VideoCodecInterface *disk_encoder, DiskSpaceEstimator *disk_space_estimator)
+       : current_storage_frame(0), resource_pool(resource_pool), surface(surface), http_encoder(http_encoder), disk_encoder(disk_encoder), frame_width(width), frame_height(height), disk_space_estimator(disk_space_estimator)
 {
        file_audio_encoder.reset(new AudioEncoder(AUDIO_OUTPUT_CODEC_NAME, DEFAULT_AUDIO_OUTPUT_BIT_RATE, oformat));
        open_output_file(filename);
@@ -1520,9 +1452,13 @@ QuickSyncEncoderImpl::QuickSyncEncoderImpl(const std::string &filename, Resource
        //print_input();
 
        if (global_flags.x264_video_to_http || global_flags.x264_video_to_disk) {
-               assert(x264_encoder != nullptr);
+               assert(http_encoder != nullptr);
+               assert(disk_encoder != nullptr);
+       } else if (global_flags.av1_video_to_http) {
+               assert(http_encoder != nullptr);
        } else {
-               assert(x264_encoder == nullptr);
+               assert(http_encoder == nullptr);
+               assert(disk_encoder == nullptr);
        }
 
        enable_zerocopy_if_possible();
@@ -1697,7 +1633,7 @@ RefCountedGLsync QuickSyncEncoderImpl::end_frame()
        assert(!is_shutdown);
 
        if (!use_zerocopy) {
-               GLenum type = global_flags.x264_bit_depth > 8 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_BYTE;
+               GLenum type = global_flags.bit_depth > 8 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_BYTE;
                GLSurface *surf;
                {
                        lock_guard<mutex> lock(storage_task_queue_mutex);
@@ -1803,7 +1739,7 @@ void QuickSyncEncoderImpl::open_output_file(const std::string &filename)
 
        string video_extradata;  // FIXME: See other comment about global headers.
        if (global_flags.x264_video_to_disk) {
-               video_extradata = x264_encoder->get_global_headers();
+               video_extradata = disk_encoder->get_global_headers();
        }
 
        current_file_mux_metrics.reset();
@@ -1819,7 +1755,7 @@ void QuickSyncEncoderImpl::open_output_file(const std::string &filename)
        metric_current_file_start_time_seconds = get_timestamp_for_metrics();
 
        if (global_flags.x264_video_to_disk) {
-               x264_encoder->add_mux(file_mux.get());
+               disk_encoder->add_mux(file_mux.get());
        }
 }
 
@@ -1981,8 +1917,10 @@ void QuickSyncEncoderImpl::pass_frame(QuickSyncEncoderImpl::PendingFrame frame,
        uint8_t *data = reinterpret_cast<uint8_t *>(surf->y_ptr);
        if (global_flags.uncompressed_video_to_http) {
                add_packet_for_uncompressed_frame(pts, duration, data);
-       } else if (global_flags.x264_video_to_http || global_flags.x264_video_to_disk) {
-               x264_encoder->add_frame(pts, duration, frame.ycbcr_coefficients, data, received_ts);
+       } else if (http_encoder != nullptr) {
+               http_encoder->add_frame(pts, duration, frame.ycbcr_coefficients, data, received_ts);
+       } if (disk_encoder != nullptr && disk_encoder != http_encoder) {
+               disk_encoder->add_frame(pts, duration, frame.ycbcr_coefficients, data, received_ts);
        }
 
        if (v4l_output != nullptr) {
@@ -2084,8 +2022,8 @@ void QuickSyncEncoderImpl::encode_frame(QuickSyncEncoderImpl::PendingFrame frame
 }
 
 // Proxy object.
-QuickSyncEncoder::QuickSyncEncoder(const std::string &filename, ResourcePool *resource_pool, QSurface *surface, const string &va_display, int width, int height, AVOutputFormat *oformat, X264Encoder *x264_encoder, DiskSpaceEstimator *disk_space_estimator)
-       : impl(new QuickSyncEncoderImpl(filename, resource_pool, surface, va_display, width, height, oformat, x264_encoder, disk_space_estimator)) {}
+QuickSyncEncoder::QuickSyncEncoder(const std::string &filename, ResourcePool *resource_pool, QSurface *surface, const string &va_display, int width, int height, const AVOutputFormat *oformat, VideoCodecInterface *http_encoder, VideoCodecInterface *disk_encoder, DiskSpaceEstimator *disk_space_estimator)
+       : impl(new QuickSyncEncoderImpl(filename, resource_pool, surface, va_display, width, height, oformat, http_encoder, disk_encoder, disk_space_estimator)) {}
 
 // Must be defined here because unique_ptr<> destructor needs to know the impl.
 QuickSyncEncoder::~QuickSyncEncoder() {}
@@ -2140,7 +2078,7 @@ string QuickSyncEncoder::get_usable_va_display()
        }
 
        // First try the default (ie., whatever $DISPLAY is set to).
-       unique_ptr<VADisplayWithCleanup> va_dpy = try_open_va("", nullptr, nullptr);
+       unique_ptr<VADisplayWithCleanup> va_dpy = try_open_va_h264("", nullptr, nullptr);
        if (va_dpy != nullptr) {
                if (need_env_reset) {
                        unsetenv("LIBVA_MESSAGING_LEVEL");
@@ -2158,7 +2096,7 @@ string QuickSyncEncoder::get_usable_va_display()
        } else {
                for (size_t i = 0; i < g.gl_pathc; ++i) {
                        string path = g.gl_pathv[i];
-                       va_dpy = try_open_va(path, nullptr, nullptr);
+                       va_dpy = try_open_va_h264(path, nullptr, nullptr);
                        if (va_dpy != nullptr) {
                                fprintf(stderr, "Autodetected %s as a suitable replacement; using it.\n",
                                        path.c_str());