Skip to content

Commit abd6674

Browse files
committed
Add rgba64 to movit
1 parent 66d6a09 commit abd6674

3 files changed

Lines changed: 124 additions & 13 deletions

File tree

src/modules/movit/filter_glsl_manager.cpp

Lines changed: 73 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
/*
22
* filter_glsl_manager.cpp
33
* Copyright (C) 2011-2012 Christophe Thommeret <hftom@free.fr>
4-
* Copyright (C) 2013-2024 Dan Dennedy <dan@dennedy.org>
4+
* Copyright (C) 2013-2025 Dan Dennedy <dan@dennedy.org>
55
*
66
* This program is free software; you can redistribute it and/or modify
77
* it under the terms of the GNU General Public License as published by
@@ -605,6 +605,78 @@ int GlslManager::render_frame_rgba(
605605
return 0;
606606
}
607607

608+
int GlslManager::render_frame_rgba64(
609+
EffectChain *chain, mlt_frame frame, int width, int height, uint8_t **image)
610+
{
611+
if (width < 1 || height < 1) {
612+
return 1;
613+
}
614+
615+
glsl_texture texture = get_texture(width, height, GL_RGBA16);
616+
if (!texture) {
617+
return 1;
618+
}
619+
620+
// Use a PBO to hold the data we read back with glReadPixels().
621+
// (Intel/DRI goes into a slow path if we don't read to PBO.)
622+
int img_size = width * height * 8; // 8 bytes per pixel (4 channels * 2 bytes)
623+
glsl_pbo pbo = get_pbo(img_size);
624+
if (!pbo) {
625+
release_texture(texture);
626+
return 1;
627+
}
628+
629+
// Set the FBO
630+
GLuint fbo;
631+
glGenFramebuffers(1, &fbo);
632+
check_error();
633+
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
634+
check_error();
635+
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture->texture, 0);
636+
check_error();
637+
glBindFramebuffer(GL_FRAMEBUFFER, 0);
638+
check_error();
639+
640+
chain->render_to_fbo(fbo, width, height);
641+
642+
// Read FBO into PBO
643+
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
644+
check_error();
645+
glBindBuffer(GL_PIXEL_PACK_BUFFER_ARB, pbo->pbo);
646+
check_error();
647+
glBufferData(GL_PIXEL_PACK_BUFFER_ARB, img_size, NULL, GL_STREAM_READ);
648+
check_error();
649+
glReadPixels(0, 0, width, height, GL_RGBA, GL_UNSIGNED_SHORT, BUFFER_OFFSET(0));
650+
check_error();
651+
652+
// Copy from PBO
653+
uint8_t *buf = (uint8_t *) glMapBuffer(GL_PIXEL_PACK_BUFFER_ARB, GL_READ_ONLY);
654+
check_error();
655+
*image = (uint8_t *) mlt_pool_alloc(img_size);
656+
mlt_frame_set_image(frame, *image, img_size, mlt_pool_release);
657+
memcpy(*image, buf, img_size);
658+
659+
// Release PBO and FBO
660+
glUnmapBuffer(GL_PIXEL_PACK_BUFFER_ARB);
661+
check_error();
662+
glBindBuffer(GL_PIXEL_PACK_BUFFER_ARB, 0);
663+
check_error();
664+
glBindFramebuffer(GL_FRAMEBUFFER, 0);
665+
check_error();
666+
glBindTexture(GL_TEXTURE_2D, 0);
667+
check_error();
668+
mlt_properties_set_data(MLT_FRAME_PROPERTIES(frame),
669+
"movit.convert.texture",
670+
texture,
671+
0,
672+
(mlt_destructor) GlslManager::release_texture,
673+
NULL);
674+
glDeleteFramebuffers(1, &fbo);
675+
check_error();
676+
677+
return 0;
678+
}
679+
608680
int GlslManager::render_frame_ycbcr(
609681
EffectChain *chain, mlt_frame frame, int width, int height, uint8_t **image)
610682
{

src/modules/movit/filter_glsl_manager.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
/*
22
* filter_glsl_manager.h
3-
* Copyright (C) 2013-2024 Dan Dennedy <dan@dennedy.org>
3+
* Copyright (C) 2013-2025 Dan Dennedy <dan@dennedy.org>
44
*
55
* This program is free software; you can redistribute it and/or modify
66
* it under the terms of the GNU General Public License as published by
@@ -122,6 +122,7 @@ class GlslManager : public Mlt::Filter
122122

123123
int render_frame_texture(movit::EffectChain *, mlt_frame, int width, int height, uint8_t **image);
124124
int render_frame_rgba(movit::EffectChain *, mlt_frame, int width, int height, uint8_t **image);
125+
int render_frame_rgba64(movit::EffectChain *, mlt_frame, int width, int height, uint8_t **image);
125126
int render_frame_ycbcr(movit::EffectChain *, mlt_frame, int width, int height, uint8_t **image);
126127
static void lock_service(mlt_frame frame);
127128
static void unlock_service(mlt_frame frame);

src/modules/movit/filter_movit_convert.cpp

Lines changed: 49 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -344,6 +344,11 @@ static void finalize_movit_chain(mlt_service leaf_service, mlt_frame frame, mlt_
344344
YCBCR_OUTPUT_INTERLEAVED,
345345
GL_UNSIGNED_SHORT);
346346
chain->effect_chain->set_dither_bits(16);
347+
} else if (format == mlt_image_rgba64) {
348+
output_format.color_space = COLORSPACE_sRGB;
349+
output_format.gamma_curve = getOutputGamma(properties);
350+
chain->effect_chain->add_output(output_format, OUTPUT_ALPHA_FORMAT_POSTMULTIPLIED);
351+
chain->effect_chain->set_dither_bits(16);
347352
} else {
348353
output_format.color_space = COLORSPACE_sRGB;
349354
output_format.gamma_curve = getOutputGamma(properties);
@@ -480,22 +485,36 @@ static int movit_render(EffectChain *chain,
480485
}
481486

482487
GlslManager *glsl = GlslManager::get_instance();
483-
int error;
484-
if (output_format == mlt_image_opengl_texture) {
488+
int error = 0;
489+
490+
switch (output_format) {
491+
case mlt_image_opengl_texture:
485492
error = glsl->render_frame_texture(chain, frame, width, height, image);
486-
} else if (output_format == mlt_image_yuv444p10 || output_format == mlt_image_yuv420p10) {
493+
break;
494+
495+
case mlt_image_yuv444p10:
496+
case mlt_image_yuv420p10:
487497
error = glsl->render_frame_ycbcr(chain, frame, width, height, image);
488498
if (!error && output_format != mlt_image_yuv444p10) {
489499
*format = mlt_image_yuv444p10;
490500
error = convert_on_cpu(frame, image, format, output_format);
491501
}
492-
} else {
502+
break;
503+
504+
case mlt_image_rgba64:
505+
error = glsl->render_frame_rgba64(chain, frame, width, height, image);
506+
break;
507+
508+
default:
509+
// Covers mlt_image_rgba and all other fallbacks.
493510
error = glsl->render_frame_rgba(chain, frame, width, height, image);
494511
if (!error && output_format != mlt_image_rgba) {
495512
*format = mlt_image_rgba;
496513
error = convert_on_cpu(frame, image, format, output_format);
497514
}
515+
break;
498516
}
517+
499518
return error;
500519
}
501520

@@ -513,42 +532,61 @@ static MltInput *create_input(mlt_properties properties,
513532
}
514533

515534
MltInput *input = new MltInput(format);
516-
if (format == mlt_image_rgba) {
535+
536+
switch (format) {
537+
case mlt_image_rgba:
538+
case mlt_image_rgba64:
517539
// TODO: Get the color space if available.
518540
input->useFlatInput(FORMAT_RGBA_POSTMULTIPLIED_ALPHA, width, height);
519-
} else if (format == mlt_image_rgb) {
541+
break;
542+
543+
case mlt_image_rgb:
520544
// TODO: Get the color space if available.
521545
input->useFlatInput(FORMAT_RGB, width, height);
522-
} else if (format == mlt_image_yuv420p) {
546+
break;
547+
548+
case mlt_image_yuv420p: {
523549
ImageFormat image_format = {};
524550
YCbCrFormat ycbcr_format = {};
525551
get_format_from_properties(properties, &image_format, &ycbcr_format);
526552
ycbcr_format.chroma_subsampling_x = ycbcr_format.chroma_subsampling_y = 2;
527553
input->useYCbCrInput(image_format, ycbcr_format, width, height);
528-
} else if (format == mlt_image_yuv422) {
554+
} break;
555+
556+
case mlt_image_yuv422: {
529557
ImageFormat image_format = {};
530558
YCbCrFormat ycbcr_format = {};
531559
get_format_from_properties(properties, &image_format, &ycbcr_format);
532560
ycbcr_format.chroma_subsampling_x = 2;
533561
ycbcr_format.chroma_subsampling_y = 1;
534562
input->useYCbCrInput(image_format, ycbcr_format, width, height);
535-
} else if (format == mlt_image_yuv420p10) {
563+
} break;
564+
565+
case mlt_image_yuv420p10: {
536566
ImageFormat image_format = {};
537567
YCbCrFormat ycbcr_format = {};
538568
get_format_from_properties(properties, &image_format, &ycbcr_format);
539569
ycbcr_format.chroma_subsampling_x = 2;
540570
ycbcr_format.chroma_subsampling_y = 2;
541571
ycbcr_format.num_levels = 1024;
542572
input->useYCbCrInput(image_format, ycbcr_format, width, height);
543-
} else if (format == mlt_image_yuv444p10) {
573+
} break;
574+
575+
case mlt_image_yuv444p10: {
544576
ImageFormat image_format = {};
545577
YCbCrFormat ycbcr_format = {};
546578
get_format_from_properties(properties, &image_format, &ycbcr_format);
547579
ycbcr_format.chroma_subsampling_x = 1;
548580
ycbcr_format.chroma_subsampling_y = 1;
549581
ycbcr_format.num_levels = 1024;
550582
input->useYCbCrInput(image_format, ycbcr_format, width, height);
583+
} break;
584+
585+
default:
586+
// Leave input configured with its default for unsupported/other formats.
587+
break;
551588
}
589+
552590
return input;
553591
}
554592

@@ -613,7 +651,7 @@ static int convert_image(mlt_frame frame,
613651
// If we're at the beginning of a series of Movit effects, store the input
614652
// sent into the chain.
615653
if (output_format == mlt_image_movit) {
616-
if (*format != mlt_image_rgba && mlt_frame_get_alpha(frame)) {
654+
if (*format != mlt_image_rgba && *format != mlt_image_rgba64 && mlt_frame_get_alpha(frame)) {
617655
if (!convert_on_cpu(frame, image, format, mlt_image_rgba)) {
618656
*format = mlt_image_rgba;
619657
}

0 commit comments

Comments
 (0)