diff options
-rw-r--r-- | capture.c | 90 | ||||
-rw-r--r-- | capture.h | 2 | ||||
-rw-r--r-- | encode.c | 153 | ||||
-rw-r--r-- | encode.h | 2 | ||||
-rw-r--r-- | gpu.c | 163 | ||||
-rw-r--r-- | gpu.h | 4 | ||||
-rw-r--r-- | main.c | 29 | ||||
-rw-r--r-- | util.h | 8 |
8 files changed, 256 insertions, 195 deletions
@@ -53,45 +53,38 @@ static int OpenAnyModule(void) { return -1; } -static void drmModeResPtrDestroy(drmModeResPtr* res) { - if (res && *res) drmModeFreeResources(*res); -} - -static void drmModeCrtcPtrDestroy(drmModeCrtcPtr* crtc) { - if (crtc && *crtc) drmModeFreeCrtc(*crtc); -} - -static void drmModeFB2PtrDestroy(drmModeFB2Ptr* fb2) { - if (fb2 && *fb2) drmModeFreeFB2(*fb2); -} - static bool IsCrtcComplete(int drm_fd, uint32_t crtc_id) { - AUTO(drmModeCrtcPtr) - crtc = drmModeGetCrtc(drm_fd, crtc_id); + drmModeCrtcPtr crtc = drmModeGetCrtc(drm_fd, crtc_id); if (!crtc) { - LOG("Failed to get crtc %u", crtc_id); + LOG("Failed to get crtc %u (%s)", crtc_id, strerror(errno)); return false; } + bool result = false; if (!crtc->buffer_id) { LOG("Crtc %u has no framebuffer", crtc_id); - return false; + goto rollback_crtc; } - AUTO(drmModeFB2Ptr) - fb2 = drmModeGetFB2(drm_fd, crtc->buffer_id); + drmModeFB2Ptr fb2 = drmModeGetFB2(drm_fd, crtc->buffer_id); if (!fb2) { - LOG("Failed to get framebuffer %u", crtc->buffer_id); - return false; + LOG("Failed to get framebuffer %u (%s)", crtc->buffer_id, strerror(errno)); + goto rollback_crtc; } if (!fb2->handles[0]) { LOG("Framebuffer %u has no handles", crtc->buffer_id); - return false; + goto rollback_fb2; } - return true; + result = true; + +rollback_fb2: + drmModeFreeFB2(fb2); +rollback_crtc: + drmModeFreeCrtc(crtc); + return result; } struct CaptureContext* CaptureContextCreate(struct GpuContext* gpu_context) { - struct AUTO(CaptureContext)* capture_context = + struct CaptureContext* capture_context = malloc(sizeof(struct CaptureContext)); if (!capture_context) { LOG("Failed to allocate capture context (%s)", strerror(errno)); @@ -103,23 +96,33 @@ struct CaptureContext* CaptureContextCreate(struct GpuContext* gpu_context) { }; capture_context->drm_fd = OpenAnyModule(); - if (capture_context->drm_fd == -1) return NULL; + if (capture_context->drm_fd == -1) { + LOG("Failed to open any module"); + goto rollback_capture_context; + } - AUTO(drmModeResPtr) res = drmModeGetResources(capture_context->drm_fd); + drmModeResPtr res = drmModeGetResources(capture_context->drm_fd); if (!res) { LOG("Failed to get drm mode resources (%s)", strerror(errno)); - return NULL; + goto rollback_drm_fd; } for (int i = 0; i < res->count_crtcs; i++) { if (IsCrtcComplete(capture_context->drm_fd, res->crtcs[i])) { LOG("Capturing crtc %u", res->crtcs[i]); capture_context->crtc_id = res->crtcs[i]; - return RELEASE(capture_context); + drmModeFreeResources(res); + return capture_context; } } LOG("Nothing to capture"); + drmModeFreeResources(res); + +rollback_drm_fd: + drmClose(capture_context->drm_fd); +rollback_capture_context: + free(capture_context); return NULL; } @@ -155,35 +158,38 @@ release_planes: const struct GpuFrame* CaptureContextGetFrame( struct CaptureContext* capture_context) { - AUTO(drmModeCrtcPtr) - crtc = drmModeGetCrtc(capture_context->drm_fd, capture_context->crtc_id); + drmModeCrtcPtr crtc = + drmModeGetCrtc(capture_context->drm_fd, capture_context->crtc_id); if (!crtc) { LOG("Failed to get crtc %u", capture_context->crtc_id); return NULL; } - AUTO(drmModeFB2Ptr) - fb2 = drmModeGetFB2(capture_context->drm_fd, crtc->buffer_id); + struct GpuFrame* gpu_frame = NULL; + drmModeFB2Ptr fb2 = drmModeGetFB2(capture_context->drm_fd, crtc->buffer_id); if (!fb2) { LOG("Failed to get framebuffer %u", crtc->buffer_id); - return NULL; + goto rollback_crtc; } if (!fb2->handles[0]) { LOG("Framebuffer %u has no handles", crtc->buffer_id); - return NULL; + goto rollback_fb2; } - GpuFrameDestroy(&capture_context->gpu_frame); + if (capture_context->gpu_frame) GpuFrameDestroy(capture_context->gpu_frame); capture_context->gpu_frame = WrapFramebuffer(capture_context->drm_fd, fb2, capture_context->gpu_context); - return capture_context->gpu_frame; + gpu_frame = capture_context->gpu_frame; + +rollback_fb2: + drmModeFreeFB2(fb2); +rollback_crtc: + drmModeFreeCrtc(crtc); + return gpu_frame; } -void CaptureContextDestroy(struct CaptureContext** capture_context) { - if (!capture_context || !*capture_context) return; - if ((*capture_context)->gpu_frame) - GpuFrameDestroy(&(*capture_context)->gpu_frame); - if ((*capture_context)->drm_fd != -1) drmClose((*capture_context)->drm_fd); - free(*capture_context); - capture_context = NULL; +void CaptureContextDestroy(struct CaptureContext* capture_context) { + GpuFrameDestroy(capture_context->gpu_frame); + drmClose(capture_context->drm_fd); + free(capture_context); } @@ -25,6 +25,6 @@ struct GpuFrame; struct CaptureContext* CaptureContextCreate(struct GpuContext* gpu_context); const struct GpuFrame* CaptureContextGetFrame( struct CaptureContext* capture_context); -void CaptureContextDestroy(struct CaptureContext** capture_context); +void CaptureContextDestroy(struct CaptureContext* capture_context); #endif // STREAMER_CAPTURE_H_ @@ -34,10 +34,6 @@ #include "perf.h" #include "util.h" -#define AVBufferRefDestroy av_buffer_unref -#define AVFrameDestroy av_frame_free -#define AVPacketDestroy av_packet_free - struct EncodeContext { struct GpuContext* gpu_context; AVBufferRef* hwdevice_context; @@ -49,32 +45,26 @@ struct EncodeContext { static bool SetHwFramesContext(struct EncodeContext* encode_context, int width, int height) { - AUTO(AVBufferRef)* hwframes_context = + encode_context->codec_context->hw_frames_ctx = av_hwframe_ctx_alloc(encode_context->hwdevice_context); - if (!hwframes_context) { + if (!encode_context->codec_context->hw_frames_ctx) { LOG("Failed to allocate hwframes context"); return false; } - AVHWFramesContext* hwframes_context_data = (void*)(hwframes_context->data); + AVHWFramesContext* hwframes_context_data = + (void*)(encode_context->codec_context->hw_frames_ctx->data); hwframes_context_data->initial_pool_size = 8; hwframes_context_data->format = AV_PIX_FMT_VAAPI; hwframes_context_data->sw_format = AV_PIX_FMT_NV12; hwframes_context_data->width = width; hwframes_context_data->height = height; - int err = av_hwframe_ctx_init(hwframes_context); + int err = av_hwframe_ctx_init(encode_context->codec_context->hw_frames_ctx); if (err < 0) { LOG("Failed to init hwframes context (%s)", av_err2str(err)); + av_buffer_unref(&encode_context->codec_context->hw_frames_ctx); return false; } - - encode_context->codec_context->hw_frames_ctx = - av_buffer_ref(hwframes_context); - if (!encode_context->codec_context->hw_frames_ctx) { - LOG("Failed to ref hwframes context"); - return false; - } - return true; } @@ -105,38 +95,32 @@ struct EncodeContext* EncodeContextCreate(struct GpuContext* gpu_context, uint32_t width, uint32_t height, enum YuvColorspace colrospace, enum YuvRange range) { - struct AUTO(EncodeContext)* encode_context = - malloc(sizeof(struct EncodeContext)); + struct EncodeContext* encode_context = malloc(sizeof(struct EncodeContext)); if (!encode_context) { LOG("Failed to allocate encode context (%s)", strerror(errno)); return NULL; } *encode_context = (struct EncodeContext){ .gpu_context = gpu_context, - .hwdevice_context = NULL, - .codec_context = NULL, - .hw_frame = NULL, - .gpu_frame = NULL, }; int err = av_hwdevice_ctx_create(&encode_context->hwdevice_context, AV_HWDEVICE_TYPE_VAAPI, NULL, NULL, 0); if (err < 0) { LOG("Failed to create hwdevice context (%s)", av_err2str(err)); - return NULL; + goto rollback_encode_context; } static const char codec_name[] = "hevc_vaapi"; const AVCodec* codec = avcodec_find_encoder_by_name(codec_name); if (!codec) { LOG("Failed to find %s encoder", codec_name); - return NULL; + goto rollback_hwdevice_context; } - encode_context->codec_context = avcodec_alloc_context3(codec); if (!encode_context->codec_context) { LOG("Failed to allocate codec context"); - return NULL; + goto rollback_hwdevice_context; } encode_context->codec_context->time_base = (AVRational){1, 60}; @@ -145,26 +129,53 @@ struct EncodeContext* EncodeContextCreate(struct GpuContext* gpu_context, encode_context->codec_context->pix_fmt = AV_PIX_FMT_VAAPI; encode_context->codec_context->max_b_frames = 0; encode_context->codec_context->refs = 1; - encode_context->codec_context->global_quality = 32; + encode_context->codec_context->global_quality = 28; encode_context->codec_context->colorspace = ConvertColorspace(colrospace); encode_context->codec_context->color_range = ConvertRange(range); if (!SetHwFramesContext(encode_context, (int)width, (int)height)) { LOG("Failed to set hwframes context"); - return NULL; + goto rollback_codec_context; } - err = avcodec_open2(encode_context->codec_context, codec, NULL); if (err < 0) { LOG("Failed to open codec (%s)", av_err2str(err)); - return NULL; + goto rollback_codec_context; } - return RELEASE(encode_context); + return encode_context; + +rollback_codec_context: + avcodec_free_context(&encode_context->codec_context); +rollback_hwdevice_context: + av_buffer_unref(&encode_context->hwdevice_context); +rollback_encode_context: + free(encode_context); + return NULL; +} + +static struct GpuFrame* PrimeToGpuFrame( + struct GpuContext* gpu_context, const VADRMPRIMESurfaceDescriptor* prime) { + struct GpuFramePlane planes[4]; + for (size_t i = 0; i < prime->layers[0].num_planes; i++) { + uint32_t object_index = prime->layers[0].object_index[i]; + if (prime->objects[object_index].fd == -1) break; + planes[i] = (struct GpuFramePlane){ + .dmabuf_fd = prime->objects[object_index].fd, + .pitch = prime->layers[0].pitch[i], + .offset = prime->layers[0].offset[i], + .modifier = prime->objects[object_index].drm_format_modifier, + }; + } + struct GpuFrame* gpu_frame = + GpuFrameCreate(gpu_context, prime->width, prime->height, prime->fourcc, + prime->layers[0].num_planes, planes); + for (size_t i = prime->num_objects; i; i--) close(prime->objects[i - 1].fd); + return gpu_frame; } const struct GpuFrame* EncodeContextGetFrame( struct EncodeContext* encode_context) { - AUTO(AVFrame)* hw_frame = av_frame_alloc(); + AVFrame* hw_frame = av_frame_alloc(); if (!hw_frame) { LOG("Failed to allocate hwframe"); return NULL; @@ -174,11 +185,11 @@ const struct GpuFrame* EncodeContextGetFrame( hw_frame, 0); if (err < 0) { LOG("Failed to get hwframe buffer (%s)", av_err2str(err)); - return NULL; + goto rollback_hw_frame; } if (!hw_frame->hw_frames_ctx) { LOG("Failed to ref hwframe context"); - return NULL; + goto rollback_hw_frame; } // mburakov: Roughly based on Sunshine code... @@ -193,33 +204,23 @@ const struct GpuFrame* EncodeContextGetFrame( VA_EXPORT_SURFACE_WRITE_ONLY | VA_EXPORT_SURFACE_COMPOSED_LAYERS, &prime); if (status != VA_STATUS_SUCCESS) { LOG("Failed to export vaapi surface (%d)", status); - return NULL; + goto rollback_hw_frame; } - struct GpuFramePlane planes[prime.layers[0].num_planes]; - for (size_t i = 0; i < LENGTH(planes); i++) { - planes[i] = (struct GpuFramePlane){ - .dmabuf_fd = prime.objects[prime.layers[0].object_index[i]].fd, - .pitch = prime.layers[0].pitch[i], - .offset = prime.layers[0].offset[i], - .modifier = - prime.objects[prime.layers[0].object_index[i]].drm_format_modifier, - }; - } - struct AUTO(GpuFrame)* gpu_frame = - GpuFrameCreate(encode_context->gpu_context, prime.width, prime.height, - prime.fourcc, LENGTH(planes), planes); + struct GpuFrame* gpu_frame = + PrimeToGpuFrame(encode_context->gpu_context, &prime); if (!gpu_frame) { LOG("Failed to create gpu frame"); - goto release_planes; + goto rollback_hw_frame; } - encode_context->hw_frame = RELEASE(hw_frame); - encode_context->gpu_frame = RELEASE(gpu_frame); + encode_context->hw_frame = hw_frame; + encode_context->gpu_frame = gpu_frame; + return gpu_frame; -release_planes: - for (size_t i = prime.num_objects; i; i--) close(prime.objects[i - 1].fd); - return encode_context->gpu_frame; +rollback_hw_frame: + av_frame_free(&hw_frame); + return NULL; } static bool DrainPacket(const struct AVPacket* packet, int fd) { @@ -255,19 +256,23 @@ static bool DrainPacket(const struct AVPacket* packet, int fd) { bool EncodeContextEncodeFrame(struct EncodeContext* encode_context, int fd, struct TimingStats* encode, struct TimingStats* drain) { + bool result = false; unsigned long long before_send = MicrosNow(); - GpuFrameDestroy(&encode_context->gpu_frame); - AUTO(AVFrame)* hw_frame = RELEASE(encode_context->hw_frame); - AUTO(AVPacket)* packet = av_packet_alloc(); + if (encode_context->gpu_frame) { + GpuFrameDestroy(encode_context->gpu_frame); + encode_context->gpu_frame = NULL; + } + AVPacket* packet = av_packet_alloc(); if (!packet) { LOG("Failed to allocate packet (%s)", strerror(errno)); - return false; + goto rollback_hw_frame; } - int err = avcodec_send_frame(encode_context->codec_context, hw_frame); + int err = avcodec_send_frame(encode_context->codec_context, + encode_context->hw_frame); if (err < 0) { LOG("Failed to send frame (%s)", av_err2str(err)); - return false; + goto rollback_packet; } unsigned long long total_send = MicrosNow() - before_send; @@ -284,10 +289,11 @@ bool EncodeContextEncodeFrame(struct EncodeContext* encode_context, int fd, total_receive += MicrosNow() - before_receive; if (encode) TimingStatsRecord(encode, total_send + total_receive); if (drain) TimingStatsRecord(drain, total_drain); - return true; + result = true; + goto rollback_packet; default: LOG("Failed to receive packet (%s)", av_err2str(err)); - return false; + goto rollback_packet; } packet->stream_index = 0; @@ -296,21 +302,24 @@ bool EncodeContextEncodeFrame(struct EncodeContext* encode_context, int fd, av_packet_unref(packet); if (!result) { LOG("Failed to write full packet (%s)", strerror(errno)); - return false; + goto rollback_packet; } total_receive += before_drain - before_receive; total_drain += MicrosNow() - before_drain; } + +rollback_packet: + av_packet_free(&packet); +rollback_hw_frame: + av_frame_free(&encode_context->hw_frame); + return result; } -void EncodeContextDestroy(struct EncodeContext** encode_context) { - if (!encode_context || !*encode_context) return; - if ((*encode_context)->gpu_frame) - GpuFrameDestroy(&(*encode_context)->gpu_frame); - if ((*encode_context)->hw_frame) av_frame_free(&(*encode_context)->hw_frame); - if ((*encode_context)->codec_context) - avcodec_free_context(&(*encode_context)->codec_context); - if ((*encode_context)->hwdevice_context) - av_buffer_unref(&(*encode_context)->hwdevice_context); +void EncodeContextDestroy(struct EncodeContext* encode_context) { + if (encode_context->gpu_frame) GpuFrameDestroy(encode_context->gpu_frame); + if (encode_context->hw_frame) av_frame_free(&encode_context->hw_frame); + avcodec_free_context(&encode_context->codec_context); + av_buffer_unref(&encode_context->hwdevice_context); + free(encode_context); } @@ -37,6 +37,6 @@ const struct GpuFrame* EncodeContextGetFrame( bool EncodeContextEncodeFrame(struct EncodeContext* encode_context, int fd, struct TimingStats* encode, struct TimingStats* drain); -void EncodeContextDestroy(struct EncodeContext** encode_context); +void EncodeContextDestroy(struct EncodeContext* encode_context); #endif // STREAMER_ENCODE_H_ @@ -42,7 +42,7 @@ gpu_context->b = (a)eglGetProcAddress(#b); \ if (!gpu_context->b) { \ LOG("Failed to look up " #b " function"); \ - return NULL; \ + goto rollback_display; \ } // TODO(mburakov): It should be theoretically possible to do everything in a @@ -269,7 +269,7 @@ static bool SetupCommonUniforms(GLuint program, enum YuvColorspace colorspace, struct GpuContext* GpuContextCreate(enum YuvColorspace colorspace, enum YuvRange range) { - struct AUTO(GpuContext)* gpu_context = malloc(sizeof(struct GpuContext)); + struct GpuContext* gpu_context = malloc(sizeof(struct GpuContext)); if (!gpu_context) { LOG("Failed to allocate gpu context (%s)", strerror(errno)); return NULL; @@ -287,7 +287,7 @@ struct GpuContext* GpuContextCreate(enum YuvColorspace colorspace, if (!egl_ext) { LOG("Failed to query platformless egl extensions (%s)", EglErrorString(eglGetError())); - return NULL; + goto rollback_gpu_context; } LOG("EGL_EXTENSIONS: %s", egl_ext); @@ -297,40 +297,46 @@ struct GpuContext* GpuContextCreate(enum YuvColorspace colorspace, // framebuffers are reported as supported by EGL. Maybe that's because the // support for RDNA3 is still quite young in MESA. #ifndef USE_EGL_MESA_PLATFORM_SURFACELESS - if (!HasExtension(egl_ext, "EGL_MESA_platform_gbm")) return NULL; + if (!HasExtension(egl_ext, "EGL_MESA_platform_gbm")) + goto rollback_gpu_context; gpu_context->render_node = open("/dev/dri/renderD128", O_RDWR); if (gpu_context->render_node == -1) { LOG("Failed to open render node (%s)", strerror(errno)); - return NULL; + goto rollback_gpu_context; } gpu_context->device = gbm_create_device(gpu_context->render_node); if (!gpu_context->device) { LOG("Failed to create gbm device (%s)", strerror(errno)); - return NULL; + goto rollback_render_node; } gpu_context->display = eglGetPlatformDisplay(EGL_PLATFORM_GBM_MESA, gpu_context->device, NULL); #else // USE_EGL_MESA_PLATFORM_SURFACELESS - if (!HasExtension(egl_ext, "EGL_MESA_platform_surfaceless")) return NULL; + if (!HasExtension(egl_ext, "EGL_MESA_platform_surfaceless")) + goto rollback_gpu_context; gpu_context->display = eglGetPlatformDisplay(EGL_PLATFORM_SURFACELESS_MESA, NULL, NULL); #endif // USE_EGL_MESA_PLATFORM_SURFACELESS if (gpu_context->display == EGL_NO_DISPLAY) { LOG("Failed to get egl display (%s)", EglErrorString(eglGetError())); - return NULL; +#ifndef USE_EGL_MESA_PLATFORM_SURFACELESS + goto rollback_device; +#else // USE_EGL_MESA_PLATFORM_SURFACELESS + goto rollback_gpu_context; +#endif // USE_EGL_MESA_PLATFORM_SURFACELESS } EGLint major, minor; if (!eglInitialize(gpu_context->display, &major, &minor)) { LOG("Failed to initialize egl display (%s)", EglErrorString(eglGetError())); - return NULL; + goto rollback_display; } LOG("Initialized EGL %d.%d", major, minor); egl_ext = eglQueryString(gpu_context->display, EGL_EXTENSIONS); if (!egl_ext) { LOG("Failed to query egl extensions (%s)", EglErrorString(eglGetError())); - return NULL; + goto rollback_display; } LOG("EGL_EXTENSIONS: %s", egl_ext); @@ -338,13 +344,13 @@ struct GpuContext* GpuContextCreate(enum YuvColorspace colorspace, !HasExtension(egl_ext, "EGL_KHR_no_config_context") || !HasExtension(egl_ext, "EGL_EXT_image_dma_buf_import") || !HasExtension(egl_ext, "EGL_EXT_image_dma_buf_import_modifiers")) - return NULL; + goto rollback_display; LOOKUP_FUNCTION(PFNEGLQUERYDMABUFFORMATSEXTPROC, eglQueryDmaBufFormatsEXT) LOOKUP_FUNCTION(PFNEGLQUERYDMABUFMODIFIERSEXTPROC, eglQueryDmaBufModifiersEXT) if (!eglBindAPI(EGL_OPENGL_ES_API)) { LOG("Failed to bind egl api (%s)", EglErrorString(eglGetError())); - return NULL; + goto rollback_display; } static const EGLint context_attribs[] = { @@ -356,24 +362,24 @@ struct GpuContext* GpuContextCreate(enum YuvColorspace colorspace, gpu_context->display, EGL_NO_CONFIG_KHR, EGL_NO_CONTEXT, context_attribs); if (gpu_context->context == EGL_NO_CONTEXT) { LOG("Failed to create egl context (%s)", EglErrorString(eglGetError())); - return NULL; + goto rollback_display; } if (!eglMakeCurrent(gpu_context->display, EGL_NO_SURFACE, EGL_NO_SURFACE, gpu_context->context)) { LOG("Failed to make egl context current (%s)", EglErrorString(eglGetError())); - return NULL; + goto rollback_context; } const char* gl_ext = (const char*)glGetString(GL_EXTENSIONS); if (!gl_ext) { LOG("Failed to get gl extensions (%s)", GlErrorString(glGetError())); - return NULL; + goto rollback_context; } LOG("GL_EXTENSIONS: %s", gl_ext); - if (!HasExtension(gl_ext, "GL_OES_EGL_image")) return NULL; + if (!HasExtension(gl_ext, "GL_OES_EGL_image")) goto rollback_context; LOOKUP_FUNCTION(PFNGLEGLIMAGETARGETTEXTURE2DOESPROC, glEGLImageTargetTexture2DOES) @@ -383,7 +389,7 @@ struct GpuContext* GpuContextCreate(enum YuvColorspace colorspace, if (!gpu_context->program_luma || !SetupCommonUniforms(gpu_context->program_luma, colorspace, range)) { LOG("Failed to create luma program"); - return NULL; + goto rollback_context; } gpu_context->program_chroma = @@ -392,14 +398,14 @@ struct GpuContext* GpuContextCreate(enum YuvColorspace colorspace, if (!gpu_context->program_chroma || !SetupCommonUniforms(gpu_context->program_chroma, colorspace, range)) { LOG("Failed to create chroma program"); - return NULL; + goto rollback_program_luma; } gpu_context->sample_offsets = glGetUniformLocation(gpu_context->program_chroma, "sample_offsets"); if (gpu_context->sample_offsets == -1) { LOG("Failed to find sample_offsets uniform (%s)", GlErrorString(glGetError())); - return NULL; + goto rollback_program_chroma; } glGenFramebuffers(1, &gpu_context->framebuffer); @@ -413,9 +419,33 @@ struct GpuContext* GpuContextCreate(enum YuvColorspace colorspace, GLenum error = glGetError(); if (error != GL_NO_ERROR) { LOG("Failed to create gl objects (%s)", GlErrorString(glGetError())); - return NULL; - } - return RELEASE(gpu_context); + goto rollback_buffers; + } + return gpu_context; + +rollback_buffers: + if (gpu_context->vertices) glDeleteBuffers(1, &gpu_context->vertices); + if (gpu_context->framebuffer) + glDeleteFramebuffers(1, &gpu_context->framebuffer); +rollback_program_chroma: + glDeleteProgram(gpu_context->program_chroma); +rollback_program_luma: + glDeleteProgram(gpu_context->program_luma); +rollback_context: + eglMakeCurrent(gpu_context->display, EGL_NO_SURFACE, EGL_NO_SURFACE, + EGL_NO_CONTEXT); + eglDestroyContext(gpu_context->display, gpu_context->context); +rollback_display: + eglTerminate(gpu_context->display); +#ifndef USE_EGL_MESA_PLATFORM_SURFACELESS +rollback_device: + gbm_device_destroy(gpu_context->device); +rollback_render_node: + close(gpu_context->render_node); +#endif // USE_EGL_MESA_PLATFORM_SURFACELESS +rollback_gpu_context: + free(gpu_context); + return NULL; } bool GpuContextSync(struct GpuContext* gpu_context) { @@ -429,28 +459,20 @@ bool GpuContextSync(struct GpuContext* gpu_context) { return true; } -void GpuContextDestroy(struct GpuContext** gpu_context) { - if (!gpu_context || !*gpu_context) return; - if ((*gpu_context)->vertices) glDeleteBuffers(1, &(*gpu_context)->vertices); - if ((*gpu_context)->framebuffer) - glDeleteFramebuffers(1, &(*gpu_context)->framebuffer); - if ((*gpu_context)->program_chroma) - glDeleteProgram((*gpu_context)->program_chroma); - if ((*gpu_context)->program_luma) - glDeleteProgram((*gpu_context)->program_luma); - if ((*gpu_context)->context != EGL_NO_CONTEXT) { - eglMakeCurrent((*gpu_context)->display, EGL_NO_SURFACE, EGL_NO_SURFACE, - EGL_NO_CONTEXT); - eglDestroyContext((*gpu_context)->display, (*gpu_context)->context); - } - if ((*gpu_context)->display != EGL_NO_DISPLAY) - eglTerminate((*gpu_context)->display); +void GpuContextDestroy(struct GpuContext* gpu_context) { + glDeleteBuffers(1, &gpu_context->vertices); + glDeleteFramebuffers(1, &gpu_context->framebuffer); + glDeleteProgram(gpu_context->program_chroma); + glDeleteProgram(gpu_context->program_luma); + eglMakeCurrent(gpu_context->display, EGL_NO_SURFACE, EGL_NO_SURFACE, + EGL_NO_CONTEXT); + eglDestroyContext(gpu_context->display, gpu_context->context); + eglTerminate(gpu_context->display); #ifndef USE_EGL_MESA_PLATFORM_SURFACELESS - if ((*gpu_context)->device) gbm_device_destroy((*gpu_context)->device); - if ((*gpu_context)->render_node != -1) close((*gpu_context)->render_node); + gbm_device_destroy(gpu_context->device); + close(gpu_context->render_node); #endif // USE_EGL_MESA_PLATFORM_SURFACELESS - free(*gpu_context); - *gpu_context = NULL; + free(gpu_context); } static void DumpEglImageParams(const EGLAttrib* attribs) { @@ -646,7 +668,7 @@ struct GpuFrame* GpuFrameCreate(struct GpuContext* gpu_context, uint32_t width, uint32_t height, uint32_t fourcc, size_t nplanes, const struct GpuFramePlane* planes) { - struct AUTO(GpuFrame)* gpu_frame = malloc(sizeof(struct GpuFrame)); + struct GpuFrame* gpu_frame = malloc(sizeof(struct GpuFrame)); if (!gpu_frame) { LOG("Failed to allocate gpu frame (%s)", strerror(errno)); return NULL; @@ -657,18 +679,17 @@ struct GpuFrame* GpuFrameCreate(struct GpuContext* gpu_context, uint32_t width, .height = height, .dmabuf_fds = {-1, -1, -1, -1}, .images = {EGL_NO_IMAGE, EGL_NO_IMAGE}, - .textures = {0, 0}, }; for (size_t i = 0; i < nplanes; i++) { gpu_frame->dmabuf_fds[i] = dup(planes[i].dmabuf_fd); if (gpu_frame->dmabuf_fds[i] == -1) { LOG("Failed to dup dmabuf fd (%s)", strerror(errno)); - return NULL; + goto rollback_dmabuf_fds; } } - struct GpuFramePlane dummy_planes[nplanes]; + struct GpuFramePlane dummy_planes[4]; for (size_t i = 0; i < nplanes; i++) { dummy_planes[i] = (struct GpuFramePlane){ .dmabuf_fd = gpu_frame->dmabuf_fds[i], @@ -683,20 +704,20 @@ struct GpuFrame* GpuFrameCreate(struct GpuContext* gpu_context, uint32_t width, DRM_FORMAT_R8, 1, &dummy_planes[0]); if (gpu_frame->images[0] == EGL_NO_IMAGE) { LOG("Failed to create luma plane image"); - return NULL; + goto rollback_dmabuf_fds; } gpu_frame->images[1] = CreateEglImage(gpu_context, width / 2, height / 2, DRM_FORMAT_GR88, 1, &dummy_planes[1]); if (gpu_frame->images[1] == EGL_NO_IMAGE) { LOG("Failed to create chroma plane image"); - return NULL; + goto rollback_images; } } else { gpu_frame->images[0] = CreateEglImage(gpu_context, width, height, fourcc, nplanes, dummy_planes); if (gpu_frame->images[0] == EGL_NO_IMAGE) { LOG("Failed to create multiplanar image"); - return NULL; + goto rollback_dmabuf_fds; } } @@ -705,11 +726,27 @@ struct GpuFrame* GpuFrameCreate(struct GpuContext* gpu_context, uint32_t width, gpu_frame->textures[i] = CreateTexture(gpu_context, gpu_frame->images[i]); if (!gpu_frame->textures[i]) { LOG("Failed to create texture"); - return NULL; + goto rollback_textures; } } + return gpu_frame; - return RELEASE(gpu_frame); +rollback_textures: + for (size_t i = LENGTH(gpu_frame->textures); i; i--) { + if (gpu_frame->textures[i - 1]) + glDeleteTextures(1, &gpu_frame->textures[i - 1]); + } +rollback_images: + for (size_t i = LENGTH(gpu_frame->images); i; i--) { + if (gpu_frame->images[i - 1] != EGL_NO_IMAGE) + eglDestroyImage(gpu_frame->gpu_context->device, gpu_frame->images[i - 1]); + } +rollback_dmabuf_fds: + for (size_t i = LENGTH(gpu_frame->dmabuf_fds); i; i--) { + if (gpu_frame->dmabuf_fds[i - 1] != -1) close(gpu_frame->dmabuf_fds[i - 1]); + } + free(gpu_frame); + return NULL; } void GpuFrameGetSize(const struct GpuFrame* gpu_frame, uint32_t* width, @@ -762,21 +799,17 @@ bool GpuFrameConvert(const struct GpuFrame* from, const struct GpuFrame* to) { return true; } -void GpuFrameDestroy(struct GpuFrame** gpu_frame) { - if (!gpu_frame || !*gpu_frame) return; - for (size_t i = LENGTH((*gpu_frame)->textures); i; i--) { - if ((*gpu_frame)->textures[i - 1]) - glDeleteTextures(1, &(*gpu_frame)->textures[i - 1]); +void GpuFrameDestroy(struct GpuFrame* gpu_frame) { + for (size_t i = LENGTH(gpu_frame->textures); i; i--) { + if (gpu_frame->textures[i - 1]) + glDeleteTextures(1, &gpu_frame->textures[i - 1]); } - for (size_t i = LENGTH((*gpu_frame)->images); i; i--) { - if ((*gpu_frame)->images[i - 1] != EGL_NO_IMAGE) - eglDestroyImage((*gpu_frame)->gpu_context->display, - (*gpu_frame)->images[i - 1]); + for (size_t i = LENGTH(gpu_frame->images); i; i--) { + if (gpu_frame->images[i - 1] != EGL_NO_IMAGE) + eglDestroyImage(gpu_frame->gpu_context->device, gpu_frame->images[i - 1]); } - for (size_t i = LENGTH((*gpu_frame)->dmabuf_fds); i; i--) { - if ((*gpu_frame)->dmabuf_fds[i - 1] != -1) - close((*gpu_frame)->dmabuf_fds[i - 1]); + for (size_t i = LENGTH(gpu_frame->dmabuf_fds); i; i--) { + if (gpu_frame->dmabuf_fds[i - 1] != -1) close(gpu_frame->dmabuf_fds[i - 1]); } - free(*gpu_frame); - *gpu_frame = NULL; + free(gpu_frame); } @@ -34,7 +34,7 @@ struct GpuFramePlane { struct GpuContext* GpuContextCreate(enum YuvColorspace colorspace, enum YuvRange range); bool GpuContextSync(struct GpuContext* gpu_context); -void GpuContextDestroy(struct GpuContext** gpu_context); +void GpuContextDestroy(struct GpuContext* gpu_context); struct GpuFrame* GpuFrameCreate(struct GpuContext* gpu_context, uint32_t width, uint32_t height, uint32_t fourcc, @@ -43,6 +43,6 @@ struct GpuFrame* GpuFrameCreate(struct GpuContext* gpu_context, uint32_t width, void GpuFrameGetSize(const struct GpuFrame* gpu_frame, uint32_t* width, uint32_t* height); bool GpuFrameConvert(const struct GpuFrame* from, const struct GpuFrame* to); -void GpuFrameDestroy(struct GpuFrame** gpu_frame); +void GpuFrameDestroy(struct GpuFrame* gpu_frame); #endif // STREAMER_GPU_H_ @@ -39,6 +39,24 @@ static const enum YuvRange range = kNarrowRange; static volatile sig_atomic_t g_signal; static void OnSignal(int status) { g_signal = status; } +static void GpuContextDtor(struct GpuContext** gpu_context) { + if (!*gpu_context) return; + GpuContextDestroy(*gpu_context); + *gpu_context = NULL; +} + +static void CaptureContextDtor(struct CaptureContext** capture_context) { + if (!*capture_context) return; + CaptureContextDestroy(*capture_context); + *capture_context = NULL; +} + +static void EncodeContextDtor(struct EncodeContext** encode_context) { + if (!*encode_context) return; + EncodeContextDestroy(*encode_context); + *encode_context = NULL; +} + int main(int argc, char* argv[]) { (void)argc; (void)argv; @@ -50,20 +68,23 @@ int main(int argc, char* argv[]) { return EXIT_FAILURE; } - struct AUTO(GpuContext)* gpu_context = GpuContextCreate(colorspace, range); + struct GpuContext __attribute__((cleanup(GpuContextDtor)))* gpu_context = + GpuContextCreate(colorspace, range); if (!gpu_context) { LOG("Failed to create gpu context"); return EXIT_FAILURE; } - struct AUTO(CaptureContext)* capture_context = - CaptureContextCreate(gpu_context); + struct CaptureContext + __attribute__((cleanup(CaptureContextDtor)))* capture_context = + CaptureContextCreate(gpu_context); if (!capture_context) { LOG("Failed to create capture context"); return EXIT_FAILURE; } - struct AUTO(EncodeContext)* encode_context = NULL; + struct EncodeContext + __attribute__((cleanup(EncodeContextDtor)))* encode_context = NULL; struct TimingStats capture; struct TimingStats convert; @@ -22,17 +22,9 @@ #define STR(x) STR_IMPL(x) #define LOG(fmt, ...) \ fprintf(stderr, __FILE__ ":" STR(__LINE__) " " fmt "\n", ##__VA_ARGS__) -#define AUTO(x) x __attribute__((__cleanup__(x##Destroy))) -#define RELEASE(x) Release((void**)&x) #define LENGTH(x) (sizeof(x) / sizeof *(x)) #define MAX(a, b) ((a) > (b) ? (a) : (b)) #define MIN(a, b) ((a) < (b) ? (a) : (b)) #define _(...) __VA_ARGS__ -static inline void* Release(void** x) { - void* result = *x; - *x = 0; - return result; -} - #endif // STREAMER_UTIL_H_ |