@@ -26,8 +26,23 @@ extern "C" {
26
26
#include < sys/wait.h>
27
27
#include < unistd.h>
28
28
29
+ #if defined(__NINTENDO_CONSOLE__) && defined(__SWITCH__)
30
+ #include < arpa/inet.h>
31
+ #include < netinet/in.h>
32
+ #include < netinet/tcp.h>
33
+ #include < sys/socket.h>
34
+ #include < sys/types.h>
35
+ #include < unistd.h>
36
+
37
+ #ifndef INADDR_LOOPBACK
38
+ // 127.0.0.1
39
+ #define INADDR_LOOPBACK (static_cast <in_addr_t >(0x7f000001 ))
40
+ #endif
41
+
42
+ #endif
43
+
29
44
struct Decoder {
30
- int pipe ;
45
+ int input_fd ;
31
46
std::future<std::optional<std::string>> encoding_thread;
32
47
std::atomic<bool > should_cancel;
33
48
};
@@ -65,7 +80,7 @@ namespace {
65
80
u32 fps,
66
81
shapes::UPoint size,
67
82
const std::filesystem::path& destination_path,
68
- int input_fd ,
83
+ const std::string& input_url ,
69
84
const std::unique_ptr<Decoder>& decoder
70
85
) {
71
86
@@ -104,10 +119,8 @@ namespace {
104
119
// "-r {framerate}"
105
120
av_dict_set (&input_options, " framerate" , framerate.c_str (), 0 );
106
121
107
- // see: https://ffmpeg.org/ffmpeg-protocols.html
108
- std::string input_url = fmt::format (" pipe:{}" , input_fd);
109
122
110
- // "-i pipe:{fd }"
123
+ // "-i {input_url }"
111
124
auto av_input_ret = avformat_open_input (&input_format_ctx, input_url.c_str (), input_fmt, &input_options);
112
125
if (av_input_ret != 0 ) {
113
126
return fmt::format (" Could not open input file stdin: {}" , av_error_to_string (av_input_ret));
@@ -333,7 +346,7 @@ namespace {
333
346
while (true ) {
334
347
// check atomic bool, if we are cancelled
335
348
// NOTE: the video is garbage after this, since we don't close it correctly (which isn't the intention of this)
336
- if (decoder->should_cancel ) {
349
+ if (decoder && decoder ->should_cancel ) {
337
350
return std::nullopt;
338
351
}
339
352
@@ -443,19 +456,38 @@ void VideoRendererBackend::is_supported_async(const std::function<void(bool)>& c
443
456
444
457
445
458
std::optional<std::string> VideoRendererBackend::setup (u32 fps, shapes::UPoint size) {
459
+
460
+ // see: https://ffmpeg.org/ffmpeg-protocols.html
461
+ #if defined(__NINTENDO_CONSOLE__) && defined(__SWITCH__)
462
+ int socket_fd = socket (AF_INET, SOCK_STREAM, 0 );
463
+ if (socket_fd < 0 ) {
464
+ return fmt::format (" Could not create a UNIX socket: {}" , strerror (errno));
465
+ }
466
+
467
+ u16 port = 1045 ;
468
+ std::string input_url = fmt::format (" tcp://localhost:{}?listen=1" , port);
469
+ int close_fd = -1 ;
470
+
471
+ #else
446
472
std::array<int , 2 > pipefd = { 0 , 0 };
447
473
448
474
if (pipe (pipefd.data ()) < 0 ) {
449
475
return fmt::format (" Could not create a pipe: {}" , strerror (errno));
450
476
}
477
+ int close_fd = pipefd[READ_END];
478
+ int input_fd = pipefd[WRITE_END];
479
+ std::string input_url = fmt::format (" pipe:{}" , close_fd);
480
+ #endif
451
481
452
482
std::future<std::optional<std::string>> encoding_thread =
453
- std::async (std::launch::async, [pipefd , fps, size, this ] -> std::optional<std::string> {
483
+ std::async (std::launch::async, [close_fd, input_url , fps, size, this ] -> std::optional<std::string> {
454
484
utils::set_thread_name (" ffmpeg encoder" );
455
- auto result = start_encoding (fps, size, this ->m_destination_path , pipefd[READ_END] , this ->m_decoder );
485
+ auto result = start_encoding (fps, size, this ->m_destination_path , input_url , this ->m_decoder );
456
486
457
- if (close (pipefd[READ_END]) < 0 ) {
458
- spdlog::warn (" could not close read end of the pipe: {}" , strerror (errno));
487
+ if (close_fd >= 0 ) {
488
+ if (close (close_fd) < 0 ) {
489
+ spdlog::warn (" could not close read end of the pipe: {}" , strerror (errno));
490
+ }
459
491
}
460
492
461
493
if (result.has_value ()) {
@@ -465,16 +497,34 @@ std::optional<std::string> VideoRendererBackend::setup(u32 fps, shapes::UPoint s
465
497
return std::nullopt;
466
498
});
467
499
500
+ #if defined(__NINTENDO_CONSOLE__) && defined(__SWITCH__)
501
+ struct sockaddr_in addr;
502
+ memset (&addr, 0 , sizeof (addr));
503
+
504
+ addr.sin_family = AF_INET;
505
+ addr.sin_port = htons (port);
506
+
507
+ // localhost
508
+ addr.sin_addr .s_addr = INADDR_LOOPBACK;
509
+
510
+ int input_fd = connect (socket_fd, reinterpret_cast <const struct sockaddr *>(&addr), sizeof (addr));
511
+ if (input_fd < 0 ) {
512
+ return fmt::format (" Could not connect to a TCP socket: {}" , strerror (errno));
513
+ }
514
+ #endif
515
+
516
+ m_decoder = std::make_unique<Decoder>(input_fd, std::move (encoding_thread), false );
468
517
469
- m_decoder = std::make_unique<Decoder>(pipefd[WRITE_END], std::move (encoding_thread), false );
470
518
return std::nullopt;
471
519
}
472
520
473
521
bool VideoRendererBackend::add_frame (SDL_Surface* surface) {
474
- if (write (m_decoder->pipe , surface->pixels , static_cast <size_t >(surface->h ) * surface->pitch ) < 0 ) {
522
+
523
+ if (write (m_decoder->input_fd , surface->pixels , static_cast <size_t >(surface->h ) * surface->pitch ) < 0 ) {
475
524
spdlog::error (" failed to write into ffmpeg pipe: {}" , strerror (errno));
476
525
return false ;
477
526
}
527
+
478
528
return true ;
479
529
}
480
530
@@ -484,7 +534,7 @@ bool VideoRendererBackend::finish(bool cancel) {
484
534
m_decoder->should_cancel = true ;
485
535
}
486
536
487
- if (close (m_decoder->pipe ) < 0 ) {
537
+ if (close (m_decoder->input_fd ) < 0 ) {
488
538
spdlog::warn (" could not close write end of the pipe: {}" , strerror (errno));
489
539
}
490
540
0 commit comments