Skip to content

Commit 7da6a32

Browse files
committed
fix(VideoStreamNDI): Use Texture2DRD to support BGRA
1 parent 842ce1b commit 7da6a32

File tree

3 files changed

+74
-33
lines changed

3 files changed

+74
-33
lines changed

build_profile.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@
4444
"OS",
4545
"ProjectSettings",
4646
"RDTextureFormat",
47+
"RDTextureView",
4748
"RenderingDevice",
4849
"RenderingServer",
4950
"Resource",
@@ -54,6 +55,7 @@
5455
"Time",
5556
"Timer",
5657
"Texture",
58+
"Texture2DRD",
5759
"Viewport",
5860
"ViewportTexture",
5961
"VideoStream",

src/video_stream_playback_ndi.cpp

Lines changed: 64 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,14 @@ file, You can obtain one at https://mozilla.org/MPL/2.0/.
1212
#include <godot_cpp/classes/engine.hpp>
1313
#include <godot_cpp/classes/os.hpp>
1414
#include <godot_cpp/classes/project_settings.hpp>
15+
#include <godot_cpp/classes/rd_texture_format.hpp>
16+
#include <godot_cpp/classes/rd_texture_view.hpp>
17+
#include <godot_cpp/classes/rendering_server.hpp>
1518

1619
using namespace godot;
1720

1821
VideoStreamPlaybackNDI::VideoStreamPlaybackNDI() {
22+
rd = RenderingServer::get_singleton()->get_rendering_device();
1923
texture.instantiate();
2024
}
2125

@@ -26,6 +30,12 @@ VideoStreamPlaybackNDI::VideoStreamPlaybackNDI(NDIlib_recv_create_v3_t p_recv_de
2630

2731
VideoStreamPlaybackNDI::~VideoStreamPlaybackNDI() {
2832
_stop();
33+
34+
RID texture_rd_rid = texture->get_texture_rd_rid();
35+
if (texture_rd_rid.is_valid()) {
36+
rd->free_rid(texture_rd_rid);
37+
}
38+
2939
texture.unref();
3040
}
3141

@@ -114,50 +124,77 @@ void VideoStreamPlaybackNDI::_update(double p_delta) {
114124

115125
void VideoStreamPlaybackNDI::_bind_methods() {}
116126

127+
void VideoStreamPlaybackNDI::update_texture(NDIlib_video_frame_v2_t p_video_frame) {
128+
Vector2i new_texture_size = Vector2i(p_video_frame.xres, p_video_frame.yres);
129+
130+
PackedByteArray data;
131+
data.resize(p_video_frame.line_stride_in_bytes * p_video_frame.yres);
132+
memcpy(data.ptrw(), p_video_frame.p_data, data.size());
133+
134+
RID texture_rd_rid = texture->get_texture_rd_rid();
135+
136+
if (new_texture_size == texture_size && texture_rd_rid.is_valid()) {
137+
rd->texture_update(texture_rd_rid, 0, data);
138+
} else {
139+
if (texture_rd_rid.is_valid()) {
140+
rd->free_rid(texture_rd_rid);
141+
}
142+
143+
Ref<RDTextureFormat> tf;
144+
tf.instantiate();
145+
tf->set_format(RenderingDevice::DATA_FORMAT_B8G8R8A8_UNORM);
146+
tf->set_width(new_texture_size.x);
147+
tf->set_height(new_texture_size.y);
148+
tf->set_usage_bits(RenderingDevice::TEXTURE_USAGE_SAMPLING_BIT | RenderingDevice::TEXTURE_USAGE_CAN_UPDATE_BIT);
149+
150+
// tf->set_depth(1);
151+
// tf->set_array_layers(1);
152+
// tf->set_mipmaps(1);
153+
// tf->set_samples(RenderingDevice::TEXTURE_SAMPLES_1);
154+
// tf->set_texture_type(RenderingDevice::TEXTURE_TYPE_2D);
155+
156+
Ref<RDTextureView> tv;
157+
tv.instantiate();
158+
159+
Array texture_data = Array();
160+
texture_data.append(data);
161+
162+
texture_rd_rid = rd->texture_create(tf, tv, texture_data);
163+
tf.unref();
164+
tv.unref();
165+
166+
texture->set_texture_rd_rid(texture_rd_rid);
167+
168+
texture_size = new_texture_size;
169+
}
170+
}
171+
117172
void VideoStreamPlaybackNDI::wait_for_non_empty_frame() {
118173
for (size_t i = 0; i < 1000; i++) {
119-
ndi->framesync_capture_video(sync, &video_frame, NDIlib_frame_format_type_progressive);
120-
if (video_frame.xres != 0 && video_frame.yres != 0) {
121-
texture->set_image(Image::create_empty(video_frame.xres, video_frame.yres, false, Image::FORMAT_RGBA8));
122-
ndi->framesync_free_video(sync, &video_frame);
174+
if (render_video()) {
123175
return;
124176
}
125-
ndi->framesync_free_video(sync, &video_frame);
126177
OS::get_singleton()->delay_msec(10);
127178
}
128179

129180
// Fallback resolution
130-
texture->set_image(Image::create_empty(1920, 1080, false, Image::FORMAT_RGBA8));
131181
ERR_FAIL_MSG("NDI: Source not found at playback start. It will play at fallback resolution of 1920x1080 once discovered. See docs for NDIOutput.");
132182
}
133183

134-
void VideoStreamPlaybackNDI::render_video() {
135-
if (img.is_valid()) {
136-
if (texture->get_width() == img->get_width() && texture->get_height() == img->get_height()) {
137-
texture->update(img);
138-
} else {
139-
texture->set_image(img);
140-
}
141-
}
184+
bool VideoStreamPlaybackNDI::render_video() {
185+
bool updated = false;
142186

187+
NDIlib_video_frame_v2_t video_frame;
143188
ndi->framesync_capture_video(sync, &video_frame, NDIlib_frame_format_type_progressive);
144189

145-
if (video_frame.p_data != nullptr && (video_frame.FourCC == NDIlib_FourCC_type_RGBA || video_frame.FourCC == NDIlib_FourCC_type_RGBX)) {
146-
video_buffer.resize(video_frame.xres * video_frame.yres * 4);
147-
148-
// memcpy(video_buffer.ptrw(), video_frame.p_data, video_buffer.size());
149-
150-
for (size_t i = 0; i < video_frame.xres * video_frame.yres; i++) {
151-
video_buffer.set(i * 4 + 0, video_frame.p_data[i * 4 + 2]);
152-
video_buffer.set(i * 4 + 1, video_frame.p_data[i * 4 + 1]);
153-
video_buffer.set(i * 4 + 2, video_frame.p_data[i * 4 + 0]);
154-
video_buffer.set(i * 4 + 3, video_frame.p_data[i * 4 + 3]);
155-
}
156-
157-
img = Image::create_from_data(video_frame.xres, video_frame.yres, false, Image::Format::FORMAT_RGBA8, video_buffer);
190+
if (video_frame.p_data != nullptr && video_frame.xres != 0 && video_frame.yres != 0 && (video_frame.FourCC == NDIlib_FourCC_type_BGRA || video_frame.FourCC == NDIlib_FourCC_type_BGRX)) {
191+
update_texture(video_frame);
192+
updated = true;
158193
}
159194

160195
ndi->framesync_free_video(sync, &video_frame);
196+
197+
return updated;
161198
}
162199

163200
void VideoStreamPlaybackNDI::render_audio(double p_delta) {

src/video_stream_playback_ndi.hpp

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,8 @@ file, You can obtain one at https://mozilla.org/MPL/2.0/.
1111

1212
#include "ndi.hpp"
1313

14-
#include <godot_cpp/classes/image_texture.hpp>
14+
#include <godot_cpp/classes/rendering_device.hpp>
15+
#include <godot_cpp/classes/texture2drd.hpp>
1516
#include <godot_cpp/classes/video_stream_playback.hpp>
1617

1718
using namespace godot;
@@ -48,12 +49,13 @@ class VideoStreamPlaybackNDI : public VideoStreamPlayback {
4849
NDIlib_recv_instance_t recv = nullptr;
4950
NDIlib_framesync_instance_t sync = nullptr;
5051

51-
Ref<ImageTexture> texture;
52-
Ref<Image> img;
53-
NDIlib_video_frame_v2_t video_frame;
54-
PackedByteArray video_buffer;
52+
RenderingDevice *rd;
53+
Ref<Texture2DRD> texture;
54+
Vector2i texture_size = Vector2i(0, 0);
55+
void update_texture(NDIlib_video_frame_v2_t p_video_frame);
56+
5557
void wait_for_non_empty_frame();
56-
void render_video();
58+
bool render_video();
5759

5860
NDIlib_audio_frame_v3_t audio_frame;
5961
PackedFloat32Array audio_buffer_planar;

0 commit comments

Comments
 (0)