@@ -26,8 +26,23 @@ extern "C" {
2626#include < sys/wait.h>
2727#include < unistd.h>
2828
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+
2944struct Decoder {
30- int pipe ;
45+ int input_fd ;
3146 std::future<std::optional<std::string>> encoding_thread;
3247 std::atomic<bool > should_cancel;
3348};
@@ -65,7 +80,7 @@ namespace {
6580 u32 fps,
6681 shapes::UPoint size,
6782 const std::filesystem::path& destination_path,
68- int input_fd ,
83+ const std::string& input_url ,
6984 const std::unique_ptr<Decoder>& decoder
7085 ) {
7186
@@ -104,10 +119,8 @@ namespace {
104119 // "-r {framerate}"
105120 av_dict_set (&input_options, " framerate" , framerate.c_str (), 0 );
106121
107- // see: https://ffmpeg.org/ffmpeg-protocols.html
108- std::string input_url = fmt::format (" pipe:{}" , input_fd);
109122
110- // "-i pipe:{fd }"
123+ // "-i {input_url }"
111124 auto av_input_ret = avformat_open_input (&input_format_ctx, input_url.c_str (), input_fmt, &input_options);
112125 if (av_input_ret != 0 ) {
113126 return fmt::format (" Could not open input file stdin: {}" , av_error_to_string (av_input_ret));
@@ -333,7 +346,7 @@ namespace {
333346 while (true ) {
334347 // check atomic bool, if we are cancelled
335348 // 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 ) {
337350 return std::nullopt ;
338351 }
339352
@@ -443,19 +456,38 @@ void VideoRendererBackend::is_supported_async(const std::function<void(bool)>& c
443456
444457
445458std::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
446472 std::array<int , 2 > pipefd = { 0 , 0 };
447473
448474 if (pipe (pipefd.data ()) < 0 ) {
449475 return fmt::format (" Could not create a pipe: {}" , strerror (errno));
450476 }
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
451481
452482 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> {
454484 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 );
456486
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+ }
459491 }
460492
461493 if (result.has_value ()) {
@@ -465,16 +497,34 @@ std::optional<std::string> VideoRendererBackend::setup(u32 fps, shapes::UPoint s
465497 return std::nullopt ;
466498 });
467499
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 );
468517
469- m_decoder = std::make_unique<Decoder>(pipefd[WRITE_END], std::move (encoding_thread), false );
470518 return std::nullopt ;
471519}
472520
473521bool 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 ) {
475524 spdlog::error (" failed to write into ffmpeg pipe: {}" , strerror (errno));
476525 return false ;
477526 }
527+
478528 return true ;
479529}
480530
@@ -484,7 +534,7 @@ bool VideoRendererBackend::finish(bool cancel) {
484534 m_decoder->should_cancel = true ;
485535 }
486536
487- if (close (m_decoder->pipe ) < 0 ) {
537+ if (close (m_decoder->input_fd ) < 0 ) {
488538 spdlog::warn (" could not close write end of the pipe: {}" , strerror (errno));
489539 }
490540
0 commit comments