diff --git a/src/platform/common.h b/src/platform/common.h index 651e4d13..3301803a 100644 --- a/src/platform/common.h +++ b/src/platform/common.h @@ -187,6 +187,7 @@ namespace platf { vaapi, dxgi, cuda, + videotoolbox, unknown }; diff --git a/src/platform/macos/display.mm b/src/platform/macos/display.mm index 194848fc..f424cf4e 100644 --- a/src/platform/macos/display.mm +++ b/src/platform/macos/display.mm @@ -77,10 +77,10 @@ namespace platf { return std::make_unique(); } - else if (pix_fmt == pix_fmt_e::nv12) { + else if (pix_fmt == pix_fmt_e::nv12 || pix_fmt == pix_fmt_e::p010) { auto device = std::make_unique(); - device->init(static_cast(av_capture), setResolution, setPixelFormat); + device->init(static_cast(av_capture), pix_fmt, setResolution, setPixelFormat); return device; } @@ -135,7 +135,7 @@ namespace platf { std::shared_ptr display(platf::mem_type_e hwdevice_type, const std::string &display_name, const video::config_t &config) { - if (hwdevice_type != platf::mem_type_e::system) { + if (hwdevice_type != platf::mem_type_e::system && hwdevice_type != platf::mem_type_e::videotoolbox) { BOOST_LOG(error) << "Could not initialize display with the given hw device type."sv; return nullptr; } diff --git a/src/platform/macos/nv12_zero_device.cpp b/src/platform/macos/nv12_zero_device.cpp index a8b75202..881c86aa 100644 --- a/src/platform/macos/nv12_zero_device.cpp +++ b/src/platform/macos/nv12_zero_device.cpp @@ -17,23 +17,19 @@ namespace platf { av_frame_free(&frame); } + void + free_buffer(void *opaque, uint8_t *data) { + CVPixelBufferRelease((CVPixelBufferRef) data); + } + int nv12_zero_device::convert(platf::img_t &img) { - av_frame_make_writable(av_frame.get()); - av_img_t *av_img = (av_img_t *) &img; - // Set up the data fields in the AVFrame to point into the mapped CVPixelBuffer - int planes = CVPixelBufferGetPlaneCount(av_img->pixel_buffer->buf); - for (int i = 0; i < planes; i++) { - av_frame->linesize[i] = CVPixelBufferGetBytesPerRowOfPlane(av_img->pixel_buffer->buf, i); - av_frame->data[i] = (uint8_t *) CVPixelBufferGetBaseAddressOfPlane(av_img->pixel_buffer->buf, i); - } + av_buffer_unref(&av_frame->buf[0]); - // We just set data pointers to point into our CVPixelBuffer above, so we have to hold - // a reference to these buffers to keep them around until the AVFrame is done using them. - backing_img.sample_buffer = av_img->sample_buffer; - backing_img.pixel_buffer = av_img->pixel_buffer; + av_frame->buf[0] = av_buffer_create((uint8_t *) CFRetain(av_img->pixel_buffer->buf), 0, free_buffer, NULL, 0); + av_frame->data[3] = (uint8_t *) av_img->pixel_buffer->buf; return 0; } @@ -50,8 +46,10 @@ namespace platf { } int - nv12_zero_device::init(void *display, resolution_fn_t resolution_fn, pixel_format_fn_t pixel_format_fn) { - pixel_format_fn(display, '420v'); + nv12_zero_device::init(void *display, pix_fmt_e pix_fmt, resolution_fn_t resolution_fn, pixel_format_fn_t pixel_format_fn) { + pixel_format_fn(display, pix_fmt == pix_fmt_e::nv12 ? + kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange : + kCVPixelFormatType_420YpCbCr10BiPlanarVideoRange); this->display = display; this->resolution_fn = resolution_fn; diff --git a/src/platform/macos/nv12_zero_device.h b/src/platform/macos/nv12_zero_device.h index 574da984..f1ee2702 100644 --- a/src/platform/macos/nv12_zero_device.h +++ b/src/platform/macos/nv12_zero_device.h @@ -26,7 +26,7 @@ namespace platf { using pixel_format_fn_t = std::function; int - init(void *display, resolution_fn_t resolution_fn, pixel_format_fn_t pixel_format_fn); + init(void *display, pix_fmt_e pix_fmt, resolution_fn_t resolution_fn, pixel_format_fn_t pixel_format_fn); int convert(img_t &img); @@ -35,7 +35,6 @@ namespace platf { private: util::safe_ptr av_frame; - av_img_t backing_img; }; } // namespace platf diff --git a/src/video.cpp b/src/video.cpp index a6083f56..52d454f4 100644 --- a/src/video.cpp +++ b/src/video.cpp @@ -94,6 +94,8 @@ namespace video { vaapi_init_avcodec_hardware_input_buffer(platf::avcodec_encode_device_t *); util::Either cuda_init_avcodec_hardware_input_buffer(platf::avcodec_encode_device_t *); + util::Either + vt_init_avcodec_hardware_input_buffer(platf::avcodec_encode_device_t *); class avcodec_software_encode_device_t: public platf::avcodec_encode_device_t { public: @@ -930,10 +932,10 @@ namespace video { static encoder_t videotoolbox { "videotoolbox"sv, std::make_unique( - AV_HWDEVICE_TYPE_NONE, AV_HWDEVICE_TYPE_NONE, + AV_HWDEVICE_TYPE_VIDEOTOOLBOX, AV_HWDEVICE_TYPE_NONE, AV_PIX_FMT_VIDEOTOOLBOX, - AV_PIX_FMT_NV12, AV_PIX_FMT_NV12, - nullptr), + AV_PIX_FMT_NV12, AV_PIX_FMT_P010, + vt_init_avcodec_hardware_input_buffer), { // Common options { @@ -2634,6 +2636,20 @@ namespace video { return hw_device_buf; } + util::Either + vt_init_avcodec_hardware_input_buffer(platf::avcodec_encode_device_t *encode_device) { + avcodec_buffer_t hw_device_buf; + + auto status = av_hwdevice_ctx_create(&hw_device_buf, AV_HWDEVICE_TYPE_VIDEOTOOLBOX, nullptr, nullptr, 0); + if (status < 0) { + char string[AV_ERROR_MAX_STRING_SIZE]; + BOOST_LOG(error) << "Failed to create a VideoToolbox device: "sv << av_make_error_string(string, AV_ERROR_MAX_STRING_SIZE, status); + return -1; + } + + return hw_device_buf; + } + #ifdef _WIN32 } @@ -2712,6 +2728,8 @@ namespace video { return platf::mem_type_e::cuda; case AV_HWDEVICE_TYPE_NONE: return platf::mem_type_e::system; + case AV_HWDEVICE_TYPE_VIDEOTOOLBOX: + return platf::mem_type_e::videotoolbox; default: return platf::mem_type_e::unknown; }