Microsoft MVP성태의 닷넷 이야기
글쓴 사람
정성태 (techsharer at outlook.com)
홈페이지
첨부 파일
 

(시리즈 글이 24개 있습니다.)
.NET Framework: 1129. C# - ffmpeg(FFmpeg.AutoGen)를 이용한 비디오 인코딩 예제(encode_video.c)
; https://www.sysnet.pe.kr/2/0/12898

.NET Framework: 1134. C# - ffmpeg(FFmpeg.AutoGen)를 이용한 비디오 디코딩 예제(decode_video.c)
; https://www.sysnet.pe.kr/2/0/12924

.NET Framework: 1135. C# - ffmpeg(FFmpeg.AutoGen)로 하드웨어 가속기를 이용한 비디오 디코딩 예제(hw_decode.c)
; https://www.sysnet.pe.kr/2/0/12932

.NET Framework: 1136. C# - ffmpeg(FFmpeg.AutoGen)를 이용해 MP2 오디오 파일 디코딩 예제(decode_audio.c)
; https://www.sysnet.pe.kr/2/0/12933

.NET Framework: 1137. ffmpeg의 파일 해시 예제(ffhash.c)를 C#으로 포팅
; https://www.sysnet.pe.kr/2/0/12935

.NET Framework: 1138. C# - ffmpeg(FFmpeg.AutoGen)를 이용해 멀티미디어 파일의 메타데이터를 보여주는 예제(metadata.c)
; https://www.sysnet.pe.kr/2/0/12936

.NET Framework: 1139. C# - ffmpeg(FFmpeg.AutoGen)를 이용해 오디오(mp2) 인코딩하는 예제(encode_audio.c)
; https://www.sysnet.pe.kr/2/0/12937

.NET Framework: 1147. C# - ffmpeg(FFmpeg.AutoGen)를 이용한 오디오 필터링 예제(filtering_audio.c)
; https://www.sysnet.pe.kr/2/0/12951

.NET Framework: 1148. C# - ffmpeg(FFmpeg.AutoGen)를 이용한 오디오 필터 예제(filter_audio.c)
; https://www.sysnet.pe.kr/2/0/12952

.NET Framework: 1150. C# - ffmpeg(FFmpeg.AutoGen)를 이용한 비디오 디코딩 예제(decode_video.c) - 두 번째 이야기
; https://www.sysnet.pe.kr/2/0/12959

개발 환경 구성: 637. ffmpeg(FFmpeg.AutoGen)를 이용한 비디오 디코딩 예제(decode_video.c) - 세 번째 이야기
; https://www.sysnet.pe.kr/2/0/12960

.NET Framework: 1151. C# - ffmpeg(FFmpeg.AutoGen)를 이용한 비디오 프레임의 크기 및 포맷 변경 예제(scaling_video.c)
; https://www.sysnet.pe.kr/2/0/12961

.NET Framework: 1153. C# - ffmpeg(FFmpeg.AutoGen)를 이용한 avio_reading.c 예제 포팅
; https://www.sysnet.pe.kr/2/0/12964

.NET Framework: 1157. C# - ffmpeg(FFmpeg.AutoGen)를 이용한 muxing.c 예제 포팅
; https://www.sysnet.pe.kr/2/0/12971

.NET Framework: 1159. C# - ffmpeg(FFmpeg.AutoGen)를 이용한 qsvdec.c 예제 포팅
; https://www.sysnet.pe.kr/2/0/12975

.NET Framework: 1161. C# - ffmpeg(FFmpeg.AutoGen)를 이용한 resampling_audio.c 예제 포팅
; https://www.sysnet.pe.kr/2/0/12978

.NET Framework: 1166. C# - ffmpeg(FFmpeg.AutoGen)를 이용한 filtering_video.c 예제 포팅
; https://www.sysnet.pe.kr/2/0/12984

.NET Framework: 1169. C# - ffmpeg(FFmpeg.AutoGen)를 이용한 demuxing_decoding.c 예제 포팅
; https://www.sysnet.pe.kr/2/0/12987

.NET Framework: 1170. C# - ffmpeg(FFmpeg.AutoGen)를 이용한 transcode_aac.c 예제 포팅
; https://www.sysnet.pe.kr/2/0/12991

.NET Framework: 1178. C# - ffmpeg(FFmpeg.AutoGen)를 이용한 http_multiclient.c 예제 포팅
; https://www.sysnet.pe.kr/2/0/13002

.NET Framework: 1180. C# - ffmpeg(FFmpeg.AutoGen)를 이용한 remuxing.c 예제 포팅
; https://www.sysnet.pe.kr/2/0/13006

.NET Framework: 1188. C# - ffmpeg(FFmpeg.AutoGen)를 이용한 transcoding.c 예제 포팅
; https://www.sysnet.pe.kr/2/0/13023

.NET Framework: 1190. C# - ffmpeg(FFmpeg.AutoGen)를 이용한 vaapi_encode.c, vaapi_transcode.c 예제 포팅
; https://www.sysnet.pe.kr/2/0/13025

.NET Framework: 1191. C 언어로 작성된 FFmpeg Examples의 C# 포팅 전체 소스 코드
; https://www.sysnet.pe.kr/2/0/13026




C# - ffmpeg(FFmpeg.AutoGen)를 이용한 demuxing_decoding.c 예제 포팅

지난 예제에 이어,

C# - ffmpeg(FFmpeg.AutoGen)를 이용한 filtering_video.c 예제 포팅
; https://www.sysnet.pe.kr/2/0/12984

이번에는 ffmpeg 예제 중 "demuxing_decoding.c" 파일을 FFmpeg.AutoGen으로 포팅하겠습니다.

using FFmpeg.AutoGen;
using FFmpeg.AutoGen.Example;
using System;
using System.IO;

namespace encode_video
{
    internal unsafe class Program
    {
        static AVFormatContext* fmt_ctx = null;
        static AVCodecContext* video_dec_ctx = null;
        static AVCodecContext* audio_dec_ctx = null;
        static int width, height;
        static AVPixelFormat pix_fmt;
        static AVStream* video_stream;
        static AVStream* audio_stream;
        static string src_filename = "";
        static string video_dst_filename = "";
        static string audio_dst_filename = "";
        static FileStream? video_dst_file;
        static FileStream? audio_dst_file;

        static byte_ptrArray4 video_dst_data;
        static int_array4 video_dst_linesize;
        static int video_dst_bufsize;

        static int video_stream_idx = -1;
        static int audio_stream_idx = -1;
        static AVFrame* frame = null;
        static AVPacket* pkt = null;
        static int video_Frame_count = 0;
        static int audio_frame_count = 0;

        static unsafe int output_video_frame(AVFrame* frame)
        {
            if (frame->width != width || frame->height != height || frame->format != (int)pix_fmt)
            {
                Console.WriteLine("Error: Width, height and pixel format have to be constant in an rawvideo file, but the width, height or pixel format of the input video changed:\n" +
                    $"old: width = {width}, height = {height}, format = {ffmpeg.av_get_pix_fmt_name(pix_fmt)}\n" +
                    $"new: width = {frame->width}, height = {frame->height}, format = {ffmpeg.av_get_pix_fmt_name((AVPixelFormat)frame->format)}");
                return -1;
            }

            Console.WriteLine($"video_frame n: {video_Frame_count++} coded: {frame->coded_picture_number}\n");

            byte_ptrArray4 tempData = new byte_ptrArray4();
            tempData.UpdateFrom(frame->data);

            int_array4 tempLinesize = new int_array4();
            tempLinesize.UpdateFrom(frame->linesize);
            ffmpeg.av_image_copy(ref video_dst_data, ref video_dst_linesize, ref tempData, tempLinesize, pix_fmt, width, height);

            video_dst_file?.Write(new ReadOnlySpan<byte>(video_dst_data[0], video_dst_bufsize));
            return 0;
        }

        static int output_audio_frame(AVFrame* frame)
        {
            int unpadded_linesize = frame->nb_samples * ffmpeg.av_get_bytes_per_sample((AVSampleFormat)frame->format);
            Console.WriteLine($"audio_frame n: {audio_frame_count++} nb_samples: {frame->nb_samples} pts: {FFmpegHelper.av_ts2timestr(frame->pts, in audio_dec_ctx->time_base)}");

            audio_dst_file?.Write(new ReadOnlySpan<byte>(frame->extended_data[0], unpadded_linesize));

            return 0;
        }

        static unsafe int decode_packet(AVCodecContext* dec, AVPacket* pkt)
        {
            int ret = ffmpeg.avcodec_send_packet(dec, pkt);
            if (ret < 0)
            {
                Console.WriteLine($"Error submitting a packet for decoding {ret}");
                return ret;
            }

            while (ret >= 0)
            {
                ret = ffmpeg.avcodec_receive_frame(dec, frame);
                if (ret < 0)
                {
                    if (ret == ffmpeg.AVERROR(ffmpeg.AVERROR_EOF) || ret == ffmpeg.AVERROR(ffmpeg.EAGAIN))
                    {
                        return 0;
                    }

                    Console.WriteLine($"Error during decoding ({FFmpegHelper.av_err2str(ret)})");
                    return ret;
                }

                if (dec->codec->type == AVMediaType.AVMEDIA_TYPE_VIDEO)
                {
                    ret = output_video_frame(frame);
                }
                else
                {
                    ret = output_audio_frame(frame);
                }

                ffmpeg.av_frame_unref(frame);

                if (ret < 0)
                {
                    return ret;
                }
            }

            return 0;
        }

        static unsafe int open_codec_context(int* stream_idx, AVCodecContext** dec_ctx, AVFormatContext* fmt_ctx, AVMediaType type)
        {
            int ret, stream_index;
            AVStream* st;
            AVCodec* dec = null;

            ret = ffmpeg.av_find_best_stream(fmt_ctx, type, -1, -1, null, 0);
            if (ret < 0)
            {
                Console.WriteLine($"Could not find {ffmpeg.av_get_media_type_string(type)} stream in input file '{src_filename}'");
                return ret;
            }
            else
            {
                stream_index = ret;
                st = fmt_ctx->streams[stream_index];

                dec = ffmpeg.avcodec_find_decoder(st->codecpar->codec_id);
                if (dec == null)
                {
                    Console.WriteLine($"Failed to find {ffmpeg.av_get_media_type_string(type)} codec");
                    return ffmpeg.AVERROR(ffmpeg.EINVAL);
                }

                *dec_ctx = ffmpeg.avcodec_alloc_context3(dec);
                if (*dec_ctx == null)
                {
                    Console.WriteLine($"Failed to allocate the {ffmpeg.av_get_media_type_string(type)} codec context");
                    return ffmpeg.AVERROR(ffmpeg.ENOMEM);
                }

                if ((ret = ffmpeg.avcodec_parameters_to_context(*dec_ctx, st->codecpar)) < 0)
                {
                    Console.WriteLine($"Failed to copy {ffmpeg.av_get_media_type_string(type)} codec parameters to decoder context");
                    return ret;
                }

                if ((ret = ffmpeg.avcodec_open2(*dec_ctx, dec, null)) < 0)
                {
                    Console.WriteLine($"Failed to open {ffmpeg.av_get_media_type_string(type)} codec");
                    return ret;
                }

                *stream_idx = stream_index;
            }

            return 0;
        }

        static unsafe int Main(string[] args)
        {
            FFmpegBinariesHelper.RegisterFFmpegBinaries();

            int ret = 0;

            // https://samplelib.com/sample-mp4.html
            string dirPath = Path.GetDirectoryName(typeof(Program).Assembly.Location) ?? "";
            src_filename = Path.Combine(dirPath, "..", "..", "..", "Samples", "sample-10s.mp4");

            video_dst_filename = Path.Combine(dirPath, "video.out");
            audio_dst_filename = Path.Combine(dirPath, "audio.out");

            fixed (AVFormatContext** pfmt_ctx = &fmt_ctx)
            fixed (AVCodecContext** pvideo_dec_ctx = &video_dec_ctx)
            fixed (AVCodecContext** paudio_dec_ctx = &audio_dec_ctx)
            fixed (int* pvideo_stream_index = &video_stream_idx)
            fixed (int* paudio_stream_index = &audio_stream_idx)
            fixed (AVPacket** ppkt = &pkt)
            fixed (AVFrame** pframe = &frame)
            {
                if (ffmpeg.avformat_open_input(pfmt_ctx, src_filename, null, null) < 0)
                {
                    Console.WriteLine($"Could not open source file {src_filename}");
                    return 1;
                }

                if (ffmpeg.avformat_find_stream_info(fmt_ctx, null) < 0)
                {
                    Console.WriteLine($"Could not find stream information");
                    return 1;
                }

                if (open_codec_context(pvideo_stream_index, pvideo_dec_ctx, fmt_ctx, AVMediaType.AVMEDIA_TYPE_VIDEO) >= 0)
                {
                    video_stream = fmt_ctx->streams[video_stream_idx];

                    video_dst_file = File.OpenWrite(video_dst_filename);
                    if (video_dst_file == null)
                    {
                        Console.WriteLine($"Could not open destination file {video_dst_filename}");
                        ret = 1;
                        goto end;
                    }

                    width = video_dec_ctx->width;
                    height = video_dec_ctx->height;
                    pix_fmt = video_dec_ctx->pix_fmt;
                    ret = ffmpeg.av_image_alloc(ref video_dst_data, ref video_dst_linesize, width, height, pix_fmt, 1);
                    if (ret < 0)
                    {
                        Console.WriteLine("Could not allocate raw video buffer");
                        goto end;
                    }

                    video_dst_bufsize = ret;
                }

                if (open_codec_context(paudio_stream_index, paudio_dec_ctx, fmt_ctx, AVMediaType.AVMEDIA_TYPE_AUDIO) >= 0)
                {
                    audio_stream = fmt_ctx->streams[audio_stream_idx];
                    audio_dst_file = File.OpenWrite(audio_dst_filename);
                    if (audio_dst_file == null)
                    {
                        Console.WriteLine($"Could not open destination file {audio_dst_filename}");
                        ret = 1;
                        goto end;
                    }
                }

                ffmpeg.av_dump_format(fmt_ctx, 0, src_filename, 0);

                if (audio_stream == null && video_stream == null)
                {
                    Console.WriteLine("Could not find audio or video stream in the input, aborting");
                    ret = 1;
                    goto end;
                }

                frame = ffmpeg.av_frame_alloc();
                if (frame == null)
                {
                    Console.WriteLine("Could not allocate frame");
                    ret = ffmpeg.AVERROR(ffmpeg.ENOMEM);
                    goto end;
                }

                pkt = ffmpeg.av_packet_alloc();
                if (pkt == null)
                {
                    Console.WriteLine("Could not allocate packet");
                    ret = ffmpeg.AVERROR(ffmpeg.ENOMEM);
                    goto end;
                }

                if (video_stream != null)
                {
                    Console.WriteLine($"Demuxing video from file '{src_filename}' into '{video_dst_filename}'");
                }

                if (audio_stream != null)
                {
                    Console.WriteLine($"Demuxing audio from file '{src_filename}' into '{audio_dst_filename}'");
                }

                while (ffmpeg.av_read_frame(fmt_ctx, pkt) >= 0)
                {
                    if (pkt->stream_index == video_stream_idx)
                    {
                        ret = decode_packet(video_dec_ctx, pkt);
                    }
                    else if (pkt->stream_index == audio_stream_idx)
                    {
                        ret = decode_packet(audio_dec_ctx, pkt);
                    }

                    ffmpeg.av_packet_unref(pkt);
                    if (ret < 0)
                    {
                        break;
                    }
                }

                if (video_dec_ctx != null)
                {
                    decode_packet(video_dec_ctx, null);
                }

                if (audio_dec_ctx != null)
                {
                    decode_packet(audio_dec_ctx, null);
                }

                Console.WriteLine("Demuxing succeeded.");

                if (video_stream != null)
                {
                    Console.WriteLine("Play the output video file with the command: \n" +
                        $"ffplay -autoexit -f rawvideo -pix_fmt {ffmpeg.av_get_pix_fmt_name(pix_fmt)} -video_size {width}x{height} {video_dst_filename}");
                }

                if (audio_stream != null)
                {
                    AVSampleFormat sfmt = audio_dec_ctx->sample_fmt;
                    int n_channels = audio_dec_ctx->channels;
                    string fmt;

                    if (ffmpeg.av_sample_fmt_is_planar(sfmt) == 1)
                    {
                        string packed = ffmpeg.av_get_sample_fmt_name(sfmt);
                        Console.WriteLine("Warning: the sample format the decoder produced is planar " +
                            $"({(packed != null ? packed : "?")}). This example will output the first channel only.");
                        sfmt = ffmpeg.av_get_packed_sample_fmt(sfmt);
                        n_channels = 1;
                    }

                    if ((ret = FFmpegHelper.get_format_from_sample_fmt(out fmt, sfmt)) < 0)
                    {
                        goto end;
                    }

                    Console.WriteLine("Play the output audio file with the command:\n" +
                        $"ffplay -autoexit -f {fmt} -ac {n_channels} -ar {audio_dec_ctx->sample_rate} {audio_dst_filename}");
                }

            end:

                ffmpeg.avcodec_free_context(pvideo_dec_ctx);
                ffmpeg.avcodec_free_context(paudio_dec_ctx);
                ffmpeg.avformat_close_input(pfmt_ctx);

                if (video_dst_file != null)
                {
                    video_dst_file.Close();
                }

                if (audio_dst_file != null)
                {
                    audio_dst_file.Close();
                }

                ffmpeg.av_packet_free(ppkt);
                ffmpeg.av_frame_free(pframe);
                ffmpeg.av_free(video_dst_data[0]);

            }

            return 0;
        }
    }
}

실행하면,

Input #0, mov,mp4,m4a,3gp,3g2,mj2, from '...[생략]...\demuxing_decoding\bin\Debug\..\..\..\Samples\sample-10s.mp4':
  Metadata:
    major_brand     : isom
    minor_version   : 512
    compatible_brands: isomiso2avc1mp41
    encoder         : Lavf58.44.100
  Duration: 00:00:10.24, start: 0.000000, bitrate: 4285 kb/s
  Stream #0:0[0x1](und): Video: h264 (High) (avc1 / 0x31637661), yuv420p(progressive), 1920x1080 [SAR 1:1 DAR 16:9], 4207 kb/s, 29.97 fps, 29.97 tbr, 30k tbn (default)
    Metadata:
      handler_name    : VideoHandler
      vendor_id       : [0][0][0][0]
  Stream #0:1[0x2](eng): Audio: aac (LC) (mp4a / 0x6134706D), 44100 Hz, stereo, fltp, 121 kb/s (default)
    Metadata:
      handler_name    : SoundHandler
      vendor_id       : [0][0][0][0]
Demuxing video from file 'E:\git_clone\ffmpeg_autogen_cs\ffmpeg_autogen_cs\demuxing_decoding\bin\Debug\..\..\..\Samples\sample-10s.mp4' into '...[생략]...\demuxing_decoding\bin\Debug\video.out'
Demuxing audio from file 'E:\git_clone\ffmpeg_autogen_cs\ffmpeg_autogen_cs\demuxing_decoding\bin\Debug\..\..\..\Samples\sample-10s.mp4' into '...[생략]...\demuxing_decoding\bin\Debug\audio.out'
video_frame n: 0 coded: 0

audio_frame n: 0 nb_samples: 1024 pts: 0
audio_frame n: 1 nb_samples: 1024 pts: 0.023219954648526078
video_frame n: 1 coded: 3

audio_frame n: 2 nb_samples: 1024 pts: 0.046439909297052155
video_frame n: 2 coded: 2

...[생략]...
audio_frame n: 437 nb_samples: 1024 pts: 10.147120181405896
audio_frame n: 438 nb_samples: 1024 pts: 10.170340136054422
audio_frame n: 439 nb_samples: 1024 pts: 10.193560090702949
video_frame n: 301 coded: 302

video_frame n: 302 coded: 299

Error during decoding (End of file)
Error during decoding (End of file)
Demuxing succeeded.
Play the output video file with the command:
ffplay -autoexit -f rawvideo -pix_fmt yuv420p -video_size 1920x1080 ...[생략]...\demuxing_decoding\bin\Debug\video.out
Warning: the sample format the decoder produced is planar (fltp). This example will output the first channel only.
Play the output audio file with the command:
ffplay -autoexit -f f32le -ac 1 -ar 44100 ...[생략]...\demuxing_decoding\bin\Debug\audio.out

입력 파일의 동영상 파일을 각각 영상과 음성 파일로 분리해 별도의 파일로 저장합니다. 그리고 마지막 콘솔 출력 부분을 보면, 해당 파일들을 ffplay로 어떻게 재생할 수 있는지 명령행 옵션과 함께 보여줍니다.

(이 글의 소스 코드는 github에 올려져 있습니다.)




[이 글에 대해서 여러분들과 의견을 공유하고 싶습니다. 틀리거나 미흡한 부분 또는 의문 사항이 있으시면 언제든 댓글 남겨주십시오.]







[최초 등록일: ]
[최종 수정일: 3/1/2022]

Creative Commons License
이 저작물은 크리에이티브 커먼즈 코리아 저작자표시-비영리-변경금지 2.0 대한민국 라이센스에 따라 이용하실 수 있습니다.
by SeongTae Jeong, mailto:techsharer at outlook.com

비밀번호

댓글 작성자
 




1  2  3  4  5  6  7  8  9  10  11  12  13  14  [15]  ...
NoWriterDateCnt.TitleFile(s)
13248정성태2/7/20234052오류 유형: 841. 리눅스 - [사용자 계정] is not in the sudoers file. This incident will be reported.
13247정성태2/7/20234963VS.NET IDE: 180. Visual Studio - 닷넷 소스 코드 디버깅 중 "Decompile source code"가 동작하는 않는 문제
13246정성태2/6/20234089개발 환경 구성: 664. Hyper-V에 설치한 리눅스 VM의 VHD 크기 늘리는 방법 - 두 번째 이야기
13245정성태2/6/20234637.NET Framework: 2093. C# - PEM 파일을 이용한 RSA 개인키/공개키 설정 방법파일 다운로드1
13244정성태2/5/20233989VS.NET IDE: 179. Visual Studio - External Tools에 Shell 내장 명령어 등록
13243정성태2/5/20234856디버깅 기술: 190. windbg - Win32 API 호출 시점에 BP 거는 방법 [1]
13242정성태2/4/20234303디버깅 기술: 189. ASP.NET Web Application (.NET Framework) 프로젝트의 숨겨진 예외 - System.UnauthorizedAccessException
13241정성태2/3/20233827디버깅 기술: 188. ASP.NET Web Application (.NET Framework) 프로젝트의 숨겨진 예외 - System.IO.FileNotFoundException
13240정성태2/1/20233987디버깅 기술: 187. ASP.NET Web Application (.NET Framework) 프로젝트의 숨겨진 예외 - System.Web.HttpException
13239정성태2/1/20233629디버깅 기술: 186. C# - CacheDependency의 숨겨진 예외 - System.Web.HttpException
13238정성태1/31/20235640.NET Framework: 2092. IIS 웹 사이트를 TLS 1.2 또는 TLS 1.3 프로토콜로만 운영하는 방법
13237정성태1/30/20235328.NET Framework: 2091. C# - 웹 사이트가 어떤 버전의 TLS/SSL을 지원하는지 확인하는 방법
13236정성태1/29/20234972개발 환경 구성: 663. openssl을 이용해 인트라넷 IIS 사이트의 SSL 인증서 생성
13235정성태1/29/20234515개발 환경 구성: 662. openssl - 윈도우 환경의 명령행에서 SAN 적용하는 방법
13234정성태1/28/20235561개발 환경 구성: 661. dnSpy를 이용해 소스 코드가 없는 .NET 어셈블리의 코드를 변경하는 방법 [1]
13233정성태1/28/20236903오류 유형: 840. C# - WebClient로 https 호출 시 "The request was aborted: Could not create SSL/TLS secure channel" 예외 발생
13232정성태1/27/20234703스크립트: 43. uwsgi의 --processes와 --threads 옵션
13231정성태1/27/20233618오류 유형: 839. python - TypeError: '...' object is not callable
13230정성태1/26/20234031개발 환경 구성: 660. WSL 2 내부로부터 호스트 측의 네트워크로 UDP 데이터가 1개의 패킷으로만 제한되는 문제
13229정성태1/25/20234972.NET Framework: 2090. C# - UDP Datagram의 최대 크기
13228정성태1/24/20235119.NET Framework: 2089. C# - WMI 논리 디스크가 속한 물리 디스크의 정보를 얻는 방법 [2]파일 다운로드1
13227정성태1/23/20234823개발 환경 구성: 659. Windows - IP MTU 값을 바꿀 수 있을까요? [1]
13226정성태1/23/20234497.NET Framework: 2088. .NET 5부터 지원하는 GetRawSocketOption 사용 시 주의할 점
13225정성태1/21/20233749개발 환경 구성: 658. Windows에서 실행 중인 소켓 서버를 다른 PC 또는 WSL에서 접속할 수 없는 경우
13224정성태1/21/20234095Windows: 221. Windows - Private/Public/Domain이 아닌 네트워크 어댑터 단위로 방화벽을 on/off하는 방법
13223정성태1/20/20234288오류 유형: 838. RDP 연결 오류 - The two computers couldn't connect in the amount of time allotted
1  2  3  4  5  6  7  8  9  10  11  12  13  14  [15]  ...