#define CHECK_VASTATUS(va_status, func) \
if (va_status != VA_STATUS_SUCCESS) { \
fprintf(stderr, "%s:%d (%s) failed with %d\n", __func__, __LINE__, func, va_status); \
- exit(1); \
+ abort(); \
}
#undef BUFFER_OFFSET
} 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.v4l_output_device.empty()) {
+ fprintf(stderr, "Disabling zerocopy H.264 encoding due to --v4l-output.\n");
+ use_zerocopy = false;
} else {
use_zerocopy = true;
}
global_flags.use_zerocopy = use_zerocopy;
}
-VADisplayWithCleanup::~VADisplayWithCleanup()
+static unique_ptr<VADisplayWithCleanup> try_open_va_h264(const string &va_display, VAProfile *h264_profile, string *error)
{
- if (va_dpy != nullptr) {
- vaTerminate(va_dpy);
- }
- if (x11_display != nullptr) {
- XCloseDisplay(x11_display);
- }
- if (drm_fd != -1) {
- close(drm_fd);
- }
-}
-
-unique_ptr<VADisplayWithCleanup> va_open_display(const string &va_display)
-{
- 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());
- exit(1);
+ abort();
}
if (!va_dpy->can_use_zerocopy) {
use_zerocopy = false;
/* check the interested configattrib */
if ((attrib[VAConfigAttribRTFormat].value & VA_RT_FORMAT_YUV420) == 0) {
printf("Not find desired YUV420 RT format\n");
- exit(1);
+ abort();
} else {
config_attrib[config_attrib_num].type = VAConfigAttribRTFormat;
config_attrib[config_attrib_num].value = VA_RT_FORMAT_YUV420;
if (attrib[VAConfigAttribRateControl].value != VA_ATTRIB_NOT_SUPPORTED) {
if (!(attrib[VAConfigAttribRateControl].value & VA_RC_CQP)) {
fprintf(stderr, "ERROR: VA-API encoder does not support CQP mode.\n");
- exit(1);
+ abort();
}
config_attrib[config_attrib_num].type = VAConfigAttribRateControl;
memset(&slice_param, 0, sizeof(slice_param));
}
+ if (!global_flags.v4l_output_device.empty()) {
+ v4l_output.reset(new V4LOutput(global_flags.v4l_output_device.c_str(), width, height));
+ }
+
call_once(quick_sync_metrics_inited, [](){
mixer_latency_histogram.init("mixer");
qs_latency_histogram.init("quick_sync");
if (!make_current(context, this->surface)) {
printf("display=%p surface=%p context=%p curr=%p err=%d\n", eglGetCurrentDisplay(), this->surface, context, eglGetCurrentContext(),
eglGetError());
- exit(1);
+ abort();
}
encode_thread_func();
delete_context(context);
if (ret < 0) {
char tmp[AV_ERROR_MAX_STRING_SIZE];
fprintf(stderr, "%s: avio_open2() failed: %s\n", filename.c_str(), av_make_error_string(tmp, sizeof(tmp), ret));
- exit(1);
+ abort();
}
string video_extradata; // FIXME: See other comment about global headers.
} 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);
}
+
+ if (v4l_output != nullptr) {
+ v4l_output->send_frame(data);
+ }
}
void QuickSyncEncoderImpl::encode_frame(QuickSyncEncoderImpl::PendingFrame frame, int encoding_frame_num, int display_frame_num, int gop_start_display_frame_num,
}
// 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");
} 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());
fprintf(stderr, "to expose Quick Sync. Alternatively, you can use --record-x264-video\n");
fprintf(stderr, "to use software instead of hardware H.264 encoding, at the expense\n");
fprintf(stderr, "of increased CPU usage and possibly bit rate.\n");
- exit(1);
+ abort();
}