X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=nageru%2Fmjpeg_encoder.cpp;h=71af1693778aa51684c8c98ba65c99582f779cde;hb=f81ae3be1aae619fe4ad022f55d95a4a83ace076;hp=03afac9e1df27fb10bd12bc8bc8d7a1a8183279c;hpb=4d97399a1b67631f1844d807d95cb9da48f20477;p=nageru diff --git a/nageru/mjpeg_encoder.cpp b/nageru/mjpeg_encoder.cpp index 03afac9..71af169 100644 --- a/nageru/mjpeg_encoder.cpp +++ b/nageru/mjpeg_encoder.cpp @@ -1,32 +1,59 @@ #include "mjpeg_encoder.h" +#include +#include #include +#include #include -#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #if __SSE2__ #include #endif -#include extern "C" { +#include +#include +#include #include +#include +#include +#include +#include +#include +#include +#include +#include } -#include "defs.h" -#include "shared/ffmpeg_raii.h" #include "flags.h" +#include "pbo_frame_allocator.h" +#include "ref_counted_frame.h" +#include "shared/ffmpeg_raii.h" #include "shared/httpd.h" #include "shared/memcpy_interleaved.h" #include "shared/metrics.h" -#include "pbo_frame_allocator.h" +#include "shared/shared_defs.h" #include "shared/timebase.h" -#include "va_display_with_cleanup.h" - -#include - -#include -#include -#include +#include "shared/va_display.h" +#include "shared/va_resource_pool.h" using namespace Eigen; using namespace bmusb; @@ -190,8 +217,9 @@ void add_audio_stream(AVFormatContext *avctx) stream->time_base = AVRational{ 1, OUTPUT_FREQUENCY }; stream->codecpar->codec_type = AVMEDIA_TYPE_AUDIO; stream->codecpar->codec_id = AV_CODEC_ID_PCM_S32LE; - stream->codecpar->channel_layout = AV_CH_LAYOUT_STEREO; - stream->codecpar->channels = 2; + stream->codecpar->ch_layout.order = AV_CHANNEL_ORDER_NATIVE; + stream->codecpar->ch_layout.nb_channels = 2; + stream->codecpar->ch_layout.u.mask = AV_CH_LAYOUT_STEREO; stream->codecpar->sample_rate = OUTPUT_FREQUENCY; } @@ -221,14 +249,22 @@ MJPEGEncoder::MJPEGEncoder(HTTPD *httpd, const string &va_display) add_stream(HTTPD::StreamID{ HTTPD::MULTICAM_STREAM, 0 }); // Initialize VA-API. + VAConfigID config_id_422, config_id_420; string error; - va_dpy = try_open_va(va_display, &error, &config_id_422, &config_id_420); + va_dpy = try_open_va(va_display, { VAProfileJPEGBaseline }, VAEntrypointEncPicture, + { + { "4:2:2", VA_RT_FORMAT_YUV422, VA_FOURCC_UYVY, &config_id_422, &uyvy_format }, + // We'd prefer VA_FOURCC_I420, but it's not supported by Intel's driver. + { "4:2:0", VA_RT_FORMAT_YUV420, VA_FOURCC_NV12, &config_id_420, &nv12_format } + }, + /*chosen_profile=*/nullptr, &error); if (va_dpy == nullptr) { fprintf(stderr, "Could not initialize VA-API for MJPEG encoding: %s. JPEGs will be encoded in software if needed.\n", error.c_str()); } encoder_thread = thread(&MJPEGEncoder::encoder_thread_func, this); if (va_dpy != nullptr) { + va_pool.reset(new VAResourcePool(va_dpy->va_dpy, uyvy_format, nv12_format, config_id_422, config_id_420, /*with_data_buffer=*/true)); va_receiver_thread = thread(&MJPEGEncoder::va_receiver_thread_func, this); } @@ -271,87 +307,6 @@ void MJPEGEncoder::stop() } } -unique_ptr MJPEGEncoder::try_open_va(const string &va_display, string *error, VAConfigID *config_id_422, VAConfigID *config_id_420) -{ - unique_ptr 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; - } - - { - VAConfigAttrib attr = { VAConfigAttribRTFormat, VA_RT_FORMAT_YUV422 }; - va_status = vaCreateConfig(va_dpy->va_dpy, VAProfileJPEGBaseline, VAEntrypointEncPicture, - &attr, 1, config_id_422); - if (va_status == VA_STATUS_ERROR_UNSUPPORTED_ENTRYPOINT) { - if (error != nullptr) *error = "No 4:2:2 hardware support"; - return nullptr; - } else if (va_status != VA_STATUS_SUCCESS) { - char buf[256]; - snprintf(buf, sizeof(buf), "vaCreateConfig() for 4:2:2 failed with status %d\n", va_status); - if (error != nullptr) *error = buf; - return nullptr; - } - } - { - VAConfigAttrib attr = { VAConfigAttribRTFormat, VA_RT_FORMAT_YUV420 }; - va_status = vaCreateConfig(va_dpy->va_dpy, VAProfileJPEGBaseline, VAEntrypointEncPicture, - &attr, 1, config_id_420); - if (va_status == VA_STATUS_ERROR_UNSUPPORTED_ENTRYPOINT) { - if (error != nullptr) *error = "No 4:2:0 hardware support"; - return nullptr; - } else if (va_status != VA_STATUS_SUCCESS) { - char buf[256]; - snprintf(buf, sizeof(buf), "vaCreateConfig() for 4:2:0 failed with status %d\n", va_status); - if (error != nullptr) *error = buf; - return nullptr; - } - } - - // TODO: Unify with the code in Futatabi. - int num_formats = vaMaxNumImageFormats(va_dpy->va_dpy); - assert(num_formats > 0); - - unique_ptr formats(new VAImageFormat[num_formats]); - va_status = vaQueryImageFormats(va_dpy->va_dpy, formats.get(), &num_formats); - if (va_status != VA_STATUS_SUCCESS) { - char buf[256]; - snprintf(buf, sizeof(buf), "vaQueryImageFormats() failed with status %d\n", va_status); - if (error != nullptr) *error = buf; - return nullptr; - } - - bool uyvy_found = false, nv12_found = false; - for (int i = 0; i < num_formats; ++i) { - if (formats[i].fourcc == VA_FOURCC_UYVY) { - memcpy(&uyvy_format, &formats[i], sizeof(VAImageFormat)); - uyvy_found = true; - } - if (formats[i].fourcc == VA_FOURCC_NV12) { - memcpy(&nv12_format, &formats[i], sizeof(VAImageFormat)); - nv12_found = true; - } - } - if (!uyvy_found) { - if (error != nullptr) *error = "UYVY format not found"; - return nullptr; - } - if (!nv12_found) { - if (error != nullptr) *error = "NV12 format not found"; - return nullptr; - } - - return va_dpy; -} - namespace { bool is_uyvy(RefCountedFrame frame) @@ -524,85 +479,6 @@ private: VABufferID buf; }; -MJPEGEncoder::VAResources MJPEGEncoder::get_va_resources(unsigned width, unsigned height, uint32_t fourcc) -{ - { - lock_guard lock(va_resources_mutex); - for (auto it = va_resources_freelist.begin(); it != va_resources_freelist.end(); ++it) { - if (it->width == width && it->height == height && it->fourcc == fourcc) { - VAResources ret = *it; - va_resources_freelist.erase(it); - return ret; - } - } - } - - VAResources ret; - - ret.width = width; - ret.height = height; - ret.fourcc = fourcc; - - VASurfaceAttrib attrib; - attrib.flags = VA_SURFACE_ATTRIB_SETTABLE; - attrib.type = VASurfaceAttribPixelFormat; - attrib.value.type = VAGenericValueTypeInteger; - attrib.value.value.i = fourcc; - - VAStatus va_status; - VAConfigID config_id; - if (fourcc == VA_FOURCC_UYVY) { - va_status = vaCreateSurfaces(va_dpy->va_dpy, VA_RT_FORMAT_YUV422, width, height, &ret.surface, 1, &attrib, 1); - config_id = config_id_422; - } else { - assert(fourcc == VA_FOURCC_NV12); - va_status = vaCreateSurfaces(va_dpy->va_dpy, VA_RT_FORMAT_YUV420, width, height, &ret.surface, 1, &attrib, 1); - config_id = config_id_420; - } - - va_status = vaCreateContext(va_dpy->va_dpy, config_id, width, height, 0, &ret.surface, 1, &ret.context); - CHECK_VASTATUS(va_status, "vaCreateContext"); - - va_status = vaCreateBuffer(va_dpy->va_dpy, ret.context, VAEncCodedBufferType, width * height * 3 + 8192, 1, nullptr, &ret.data_buffer); - CHECK_VASTATUS(va_status, "vaCreateBuffer"); - - if (fourcc == VA_FOURCC_UYVY) { - va_status = vaCreateImage(va_dpy->va_dpy, &uyvy_format, width, height, &ret.image); - CHECK_VASTATUS(va_status, "vaCreateImage"); - } else { - assert(fourcc == VA_FOURCC_NV12); - va_status = vaCreateImage(va_dpy->va_dpy, &nv12_format, width, height, &ret.image); - CHECK_VASTATUS(va_status, "vaCreateImage"); - } - - return ret; -} - -void MJPEGEncoder::release_va_resources(MJPEGEncoder::VAResources resources) -{ - lock_guard lock(va_resources_mutex); - if (va_resources_freelist.size() > 50) { - auto it = va_resources_freelist.end(); - --it; - - VAStatus va_status = vaDestroyBuffer(va_dpy->va_dpy, it->data_buffer); - CHECK_VASTATUS(va_status, "vaDestroyBuffer"); - - va_status = vaDestroyContext(va_dpy->va_dpy, it->context); - CHECK_VASTATUS(va_status, "vaDestroyContext"); - - va_status = vaDestroySurfaces(va_dpy->va_dpy, &it->surface, 1); - CHECK_VASTATUS(va_status, "vaDestroySurfaces"); - - va_status = vaDestroyImage(va_dpy->va_dpy, it->image.image_id); - CHECK_VASTATUS(va_status, "vaDestroyImage"); - - va_resources_freelist.erase(it); - } - - va_resources_freelist.push_front(resources); -} - namespace { void push16(uint16_t val, string *str) @@ -862,7 +738,7 @@ void MJPEGEncoder::encode_jpeg_va(QueuedFrame &&qf) unsigned width = qf.video_format.width; unsigned height = qf.video_format.height; - VAResources resources; + VAResourcePool::VAResources resources; ReleaseVAResources release; if (userdata->data_copy_current_src == PBOFrameAllocator::Userdata::FROM_VA_API) { assert(is_uyvy(qf.frame)); @@ -871,13 +747,12 @@ void MJPEGEncoder::encode_jpeg_va(QueuedFrame &&qf) } else { assert(userdata->data_copy_current_src == PBOFrameAllocator::Userdata::FROM_MALLOC); if (is_uyvy(qf.frame)) { - resources = get_va_resources(width, height, VA_FOURCC_UYVY); + resources = va_pool->get_va_resources(width, height, VA_FOURCC_UYVY); } else { assert(is_i420(qf.frame)); - // We'd prefer VA_FOURCC_I420, but it's not supported by Intel's driver. - resources = get_va_resources(width, height, VA_FOURCC_NV12); + resources = va_pool->get_va_resources(width, height, VA_FOURCC_NV12); } - release = ReleaseVAResources(this, resources); + release = ReleaseVAResources(va_pool.get(), resources); } int y_h_samp_factor, y_v_samp_factor;