■ FFMpeg을 사용해 RTP/RTSP 영상 재생하기

------------------------------------------------------------------------------------------------------------------------


TestProject.z01 TestProject.z02 TestProject.zip


FFMpegHelper.cs

 

 

using System;

using System.IO;

using System.Runtime.InteropServices;

 

using FFmpeg.AutoGen;

 

namespace TestProject

{

    /// <summary>

    /// FFMPEG 헬퍼

    /// </summary>

    public static class FFMpegHelper

    {

        //////////////////////////////////////////////////////////////////////////////////////////////////// Import

        ////////////////////////////////////////////////////////////////////////////////////////// Static

        //////////////////////////////////////////////////////////////////////////////// Private

 

        #region DLL 디렉토리 설정하기 - SetDllDirectory(directoryPath)

 

        /// <summary>

        /// DLL 디렉토리 설정하기

        /// </summary>

        /// <param name="directoryPath">디렉토리 경로</param>

        /// <returns>처리 결과</returns>

        [DllImport("kernel32", SetLastError = true)]

        private static extern bool SetDllDirectory(string directoryPath);

 

        #endregion

 

        //////////////////////////////////////////////////////////////////////////////////////////////////// Field

        ////////////////////////////////////////////////////////////////////////////////////////// Private

 

        #region Field

 

        /// <summary>

        /// LD_LIBRARY_PATH

        /// </summary>

        private const string LD_LIBRARY_PATH = "LD_LIBRARY_PATH";

 

        #endregion

 

        //////////////////////////////////////////////////////////////////////////////////////////////////// Method

        ////////////////////////////////////////////////////////////////////////////////////////// Static

        //////////////////////////////////////////////////////////////////////////////// Public

 

        #region 등록하기 - Register()

 

        /// <summary>

        /// 등록하기

        /// </summary>

        public static void Register()

        {

            switch(Environment.OSVersion.Platform)

            {

                case PlatformID.Win32NT      :

                case PlatformID.Win32S       :

                case PlatformID.Win32Windows :

                {

                    string currentDirectoryPath = Environment.CurrentDirectory;

 

                    while(currentDirectoryPath != null)

                    {

                        string dllDirectoryPath = Path.Combine(currentDirectoryPath, "FFMpegDLL");

 

                        if(Directory.Exists(dllDirectoryPath))

                        {

                            Register(dllDirectoryPath);

 

                            return;

                        }

 

                        currentDirectoryPath = Directory.GetParent(currentDirectoryPath)?.FullName;

                    }

 

                    break;

                }

                case PlatformID.Unix   :

                case PlatformID.MacOSX :

                {

                    string dllDirectoryPath = Environment.GetEnvironmentVariable(LD_LIBRARY_PATH);

 

                    Register(dllDirectoryPath);

 

                    break;

                }

            }

        }

 

        #endregion

 

        #region 에러 메시지 구하기 - GetErrorMessage(errorCode)

 

        /// <summary>

        /// 에러 메시지 구하기

        /// </summary>

        /// <param name="errorCode">에러 코드</param>

        /// <returns>에러 메시지</returns>

        public static unsafe string GetErrorMessage(int errorCode)

        {

            int bufferSize = 1024;

 

            byte* buffer = stackalloc byte[bufferSize];

 

            ffmpeg.av_strerror(errorCode, buffer, (ulong)bufferSize);

 

            string message = Marshal.PtrToStringAnsi((IntPtr)buffer);

 

            return message;

        }

 

        #endregion

        #region 에러시 예외 던지기 - ThrowExceptionIfError(error)

 

        /// <summary>

        /// 에러시 예외 던지기

        /// </summary>

        /// <param name="errorCode">에러 코드</param>

        /// <returns>에러 코드</returns>

        public static int ThrowExceptionIfError(this int errorCode)

        {

            if(errorCode < 0)

            {

                throw new ApplicationException(GetErrorMessage(errorCode));

            }

 

            return errorCode;

        }

 

        #endregion

 

        //////////////////////////////////////////////////////////////////////////////// Private

 

        #region 등록하기 - Register(dllDirectoryPath)

 

        /// <summary>

        /// 등록하기

        /// </summary>

        /// <param name="dllDirectoryPath">DLL 디렉토리 경로</param>

        private static void Register(string dllDirectoryPath)

        {

            switch(Environment.OSVersion.Platform)

            {

                case PlatformID.Win32NT      :

                case PlatformID.Win32S       :

                case PlatformID.Win32Windows :

 

                    SetDllDirectory(dllDirectoryPath);

 

                    break;

 

                case PlatformID.Unix   :

                case PlatformID.MacOSX :

 

                    string currentValue = Environment.GetEnvironmentVariable(LD_LIBRARY_PATH);

 

                    if(string.IsNullOrWhiteSpace(currentValue) == false && currentValue.Contains(dllDirectoryPath) == false)

                    {

                        string newValue = currentValue + Path.PathSeparator + dllDirectoryPath;

 

                        Environment.SetEnvironmentVariable(LD_LIBRARY_PATH, newValue);

                    }

 

                    break;

            }

        }

 

        #endregion

    }

}

 

 

VideoFrameConverter.cs

 

 

using System;

using System.Runtime.InteropServices;

using System.Windows;

 

using FFmpeg.AutoGen;

 

namespace TestProject

{

    /// <summary>

    /// 비디오 프레임 컨버터

    /// </summary>

    public sealed unsafe class VideoFrameConverter : IDisposable

    {

        //////////////////////////////////////////////////////////////////////////////////////////////////// Field

        ////////////////////////////////////////////////////////////////////////////////////////// Private

 

        #region Field

 

        /// <summary>

        /// 타겟 크기

        /// </summary>

        private readonly Size targetSize;

 

        /// <summary>

        /// 컨텍스트

        /// </summary>

        private readonly SwsContext* context;

 

        /// <summary>

        /// 버퍼 핸들

        /// </summary>

        private readonly IntPtr buferHandle;

 

        /// <summary>

        /// 임시 프레임 데이터

        /// </summary>

        private readonly byte_ptrArray4 temporaryFrameData;

 

        /// <summary>

        /// 임시 프레임 라인 크기

        /// </summary>

        private readonly int_array4 temporaryFrameLineSize;

 

        #endregion

 

        //////////////////////////////////////////////////////////////////////////////////////////////////// Constructor

        ////////////////////////////////////////////////////////////////////////////////////////// Public

 

        #region 생성자 - VideoFrameConverter(sourceSize, sourcePixelFormat, targetSize, targetPixelFormat)

 

        /// <summary>

        /// 생성자

        /// </summary>

        /// <param name="sourceSize">소스 크기</param>

        /// <param name="sourcePixelFormat">소스 픽셀 포맷</param>

        /// <param name="targetSize">타겟 크기</param>

        /// <param name="targetPixelFormat">타겟 픽셀 포맷</param>

        public VideoFrameConverter(Size sourceSize, AVPixelFormat sourcePixelFormat, Size targetSize, AVPixelFormat targetPixelFormat)

        {

            this.targetSize = targetSize;

 

            this.context = ffmpeg.sws_getContext

            (

                (int)sourceSize.Width,

                (int)sourceSize.Height,

                sourcePixelFormat,

                (int)targetSize.Width,

                (int)targetSize.Height,

                targetPixelFormat,

                ffmpeg.SWS_FAST_BILINEAR,

                null,

                null,

                null

            );

 

            if(this.context == null)

            {

                throw new ApplicationException("Could not initialize the conversion context.");

            }

 

            int bufferSize = ffmpeg.av_image_get_buffer_size(targetPixelFormat, (int)targetSize.Width, (