2

我用 C# 开发了一个小媒体播放器,现在我需要将它转换为 C++。我的老师希望我们比较这两种方法,看看哪种方法实际上更好/更快。

我有一个 C# WPF 项目,其中一些类在新的 C++ CLI 项目中使用时似乎无法正常运行。例如,我无法使用 MediaPlayer 类。Visual Studio 2008 找不到System.Windows.Media::MediaPlayer. 这是我从 MSDN 得到的:http: //msdn.microsoft.com/fr-fr/library/system.windows.media.mediaplayer.aspx#Y100

关于如何将 C# WPF 项目转换为 C++ CLI 项目的任何想法?我认为这实际上很容易,但由于某些原因,VS2008 找不到我需要的大部分类。

4

1 回答 1

1

以下应该很接近,但我可以保证它在速度方面不会有太大差异,因为它也是托管代码(我把它全部放在头文件中):

using namespace System;
using namespace System::Collections::Generic;
using namespace System::Linq;
using namespace System::Windows;
using namespace System::Windows::Controls;
using namespace System::Windows::Media;
using namespace System::Windows::Media::Imaging;
using namespace System::Windows::Threading;
using namespace Microsoft::Win32;

namespace VideoThumbnailer
{
    /*---------------------------------------------------------------------------------* 
     * CLASSE WINDOW1 
    /*---------------------------------------------------------------------------------*/ 
    public ref class Window1 : Window
    {
        // Inheritable attached dependency property indicates whether processing is going on 
    public:
        static bool GetProcessing(DependencyObject ^obj)
        {
            return safe_cast<bool>(obj->GetValue(ProcessingProperty));
        }
        static void SetProcessing(DependencyObject ^obj, bool value)
        {
            obj->SetValue(ProcessingProperty, value);
        }
        static initonly DependencyProperty ^ProcessingProperty = DependencyProperty::RegisterAttached("Processing", bool::typeid, Window1::typeid, gcnew FrameworkPropertyMetadata(false, FrameworkPropertyMetadataOptions::Inherits));

        // Dependency property indicates the file name of the current media 
        property String ^FileName
        {
            String ^get()
            {
                return safe_cast<String^>(GetValue(FileNameProperty));
            }
            void set(String ^value)
            {
                SetValue(FileNameProperty, value);
            }
        }
        static initonly DependencyProperty ^FileNameProperty = DependencyProperty::Register("FileName", String::typeid, Window1::typeid);

        // Member variables 
    private:
        MediaPlayer ^_mediaPlayer;
        Queue<TimeSpan> ^_positionsToThumbnail;
        //private TimeSpan _positionsToThumbnail = new TimeSpan(); 
        DispatcherTimer ^_watchdogTimer;
        array<Byte> ^framePixels;
        array<Byte> ^previousFramePixels;
        float m_iContrast;
        int m_iBrightness;

    public:
        Window1()
        {
            // Initialize window and hook up to events of interest 
            InitializeInstanceFields();
            InitializeComponent();
            _mediaPlayer->MediaOpened += gcnew EventHandler(this, &Window1::HandleMediaPlayerMediaOpened);
            _mediaPlayer->Changed += gcnew EventHandler(this, &Window1::HandleMediaPlayerChanged);
            _watchdogTimer->Interval = TimeSpan::FromSeconds(1);
            _watchdogTimer->Tick += gcnew EventHandler(this, &Window1::HandleWatchdogTimerTick);
        }


#pragma region Utils 
    private:
        void SeekToNextThumbnailPosition()
        {
            // If more frames remain to capture... 
            if (0 < _positionsToThumbnail->Count)
            {
                // Seek to next position and start watchdog timer 
                _mediaPlayer->Position = _positionsToThumbnail->Dequeue();
                _watchdogTimer->Start();
            }
            else
            {
                // Done; close media file and stop processing 
                _mediaPlayer->Close();
                framePixels = nullptr;
                previousFramePixels = nullptr;
                SetProcessing(this, false);
            }
        }

        void CaptureCurrentFrame(bool forceCapture)
        {
            // Capture the current frame as an ImageSource 
            WriteableBitmap ^imageSource = RenderBitmapAndCapturePixels(framePixels);

            // If captured pixels are different than the previous frame... 
            if (forceCapture || !framePixels->SequenceEqual(previousFramePixels))
            {
                // Stop the watchdog timer 
                _watchdogTimer->Stop();

                // Add an Image for the Thumbnail 
                ThumbnailPanel::Children->Clear(); // en effaçant a chaque fois, on réécrit au même endroit
                ThumbnailPanel::Children->Add(gcnew Image {Source = imageSource, ToolTip = _mediaPlayer->Position, MaxWidth = _mediaPlayer->NaturalVideoWidth, MaxHeight = _mediaPlayer->NaturalVideoHeight, Margin = Thickness(0)}); // distance entre chaque image

                // Swap the pixel buffers (moves current to previous and avoids allocating a new buffer for current) 
                array<Byte> ^tempPixels = framePixels;
                framePixels = previousFramePixels;
                previousFramePixels = tempPixels;

                // Seek to the next thumbnail position 
                SeekToNextThumbnailPosition();
            }
        }

        WriteableBitmap ^RenderBitmapAndCapturePixels(array<Byte> ^pixels)
        {
            // Render the current frame into a bitmap 
            DrawingVisual ^drawingVisual = gcnew DrawingVisual();
            RenderTargetBitmap ^renderTargetBitmap = gcnew RenderTargetBitmap(_mediaPlayer->NaturalVideoWidth, _mediaPlayer->NaturalVideoHeight, 96, 96, PixelFormats::Default);
            Rect videoRect = Rect(0, 0, _mediaPlayer->NaturalVideoWidth, _mediaPlayer->NaturalVideoHeight);

//C# TO C++ CONVERTER NOTE: The following 'using' block is replaced by its C++ equivalent:
//          using (var drawingContext = drawingVisual.RenderOpen())
            System::Windows::Media::DrawingContext ^drawingContext = drawingVisual->RenderOpen();
            try
            {
                drawingContext->DrawVideo(_mediaPlayer, videoRect);
            }
            finally
            {
                delete drawingContext;
            }
            renderTargetBitmap->Render(drawingVisual);

            // Copy the pixels to the specified location 
            renderTargetBitmap->CopyPixels(pixels, _mediaPlayer->NaturalVideoWidth * 4, 0);

            // Effectuer un traitement 
            TraiterImage(pixels);


            // Utiliser un "WritableBitMap" 
            WriteableBitmap ^wrBitMap = gcnew WriteableBitmap(renderTargetBitmap);
            Int32Rect wrRect = Int32Rect();
            wrRect.X = safe_cast<int>(videoRect.X);
            wrRect.Y = safe_cast<int>(videoRect.Y);
            wrRect.Width = safe_cast<int>(videoRect.Width);
            wrRect.Height = safe_cast<int>(videoRect.Height);

            wrBitMap->WritePixels(wrRect, pixels, _mediaPlayer->NaturalVideoWidth * 4, 0);

            // Return the bitmap 
            return wrBitMap;
        }

        void TraiterImage(array<Byte> ^pixels)
        {
            try
            {
                for (int i = 0; i < pixels->Length; i++)
                {
                    double tempPixel = pixels[i];

                    tempPixel = (pixels[i] + m_iBrightness) * m_iContrast;

                    if (tempPixel < 0)
                        tempPixel = 0;
                    else if (tempPixel > 255)
                        tempPixel = 255;

                    pixels[i] = Convert::ToByte(tempPixel);
                }
            }
            catch (Exception ^e)
            {
                Console::WriteLine("Une exception c'est produite : " + e->ToString());
            }
        }
#pragma endregion 
#pragma region Events 
        void but_brightnessDown_Click(Object ^sender, RoutedEventArgs ^e)
        {
            if (m_iBrightness > -255)
                m_iBrightness -= 5;

            lb_brightnessValue->Content = m_iBrightness;
        }

        void but_brightnessUp_Click(Object ^sender, RoutedEventArgs ^e)
        {
            if (m_iBrightness < 255)
                m_iBrightness += 5;

            lb_brightnessValue->Content = m_iBrightness;
        }

        void but_constrastDown_Click(Object ^sender, RoutedEventArgs ^e)
        {
            if (m_iContrast > 0.5)
                m_iContrast -= 0.5F;

            lb_contrastValue->Content = m_iContrast;
        }

        void but_contrastUp_Click(Object ^sender, RoutedEventArgs ^e)
        {
            if (m_iContrast < 2)
                m_iContrast += 0.5F;

            lb_contrastValue->Content = m_iContrast;
        }

#pragma endregion 
#pragma region handle 
        void HandleWatchdogTimerTick(Object ^sender, EventArgs ^e)
        {
            // Stop the watchdog timer 
            _watchdogTimer->Stop();

            // Capture the current frame (even if it's not different than the previous) 
            CaptureCurrentFrame(true);
        }

        void HandleOpenFileButtonClick(Object ^sender, RoutedEventArgs ^e)
        {
            // Display open file dialog 
            OpenFileDialog ^openFileDialog = gcnew OpenFileDialog {CheckFileExists = true, Filter = "Video Files (*.wmv;*.dvr-ms;*.mpeg;*.mpg;*.avi)|*.wmv;*.dvr-ms;*.mpeg;*.mpg;*.avi|All Files (*)|*"};

            // Show dialog 
            System::Nullable<System::Boolean> result = openFileDialog->ShowDialog();

            // If a file was chosen... 
            if (result.HasValue && result.Value)
            {
                // Reset state 
                System::String ^fileName = openFileDialog->FileName;
                SetProcessing(this, true);
                ThumbnailPanel::Children->Clear();
                FileName = fileName;

                // Open media file 
                _mediaPlayer->ScrubbingEnabled = true;
                _mediaPlayer->Open(gcnew Uri(fileName));
            }
        }

        void HandleMediaPlayerMediaOpened(Object ^sender, EventArgs ^e)
        {
            // Get details about opened file 
            //var numberFramesToThumbnail = (ThumbnailPanel.Columns * ThumbnailPanel.Rows); 
            System::Double totalMilliseconds = _mediaPlayer->NaturalDuration.TimeSpan::TotalMilliseconds;
//C# TO C++ CONVERTER TODO TASK: There is no equivalent to implicit typing in C++ unless the C++11 inferred typing option is selected:
            var numberFramesToThumbnail = 1 * totalMilliseconds / 67; // le vidéo sera joué à 8 frame par seconde
            framePixels = gcnew array<Byte>(_mediaPlayer->NaturalVideoWidth * _mediaPlayer->NaturalVideoHeight * 4);
            previousFramePixels = gcnew array<Byte>(framePixels->Length);

            // Enqueue a position for each frame (at the center of each of the N segments) 
            for (int i = 0; i < numberFramesToThumbnail; i++)
            {
                _positionsToThumbnail->Enqueue(TimeSpan::FromMilliseconds((((2 * i) + 1) * totalMilliseconds) / (2 * numberFramesToThumbnail)));
                //_positionsToThumbnail = (TimeSpan.FromMilliseconds((((2 * i) + 1) * totalMilliseconds) / (2 * numberFramesToThumbnail))); 
            }

            // Capture the first frame as a baseline 
            RenderBitmapAndCapturePixels(previousFramePixels);

            // Seek to the first thumbnail position 
            SeekToNextThumbnailPosition();
        }

        void HandleMediaPlayerChanged(Object ^sender, EventArgs ^e)
        {
            // If still processing the file (i.e., not done)... 
            if (GetProcessing(this))
            {
                // Capture the current frame 
                CaptureCurrentFrame(false);
            }
        }

    private:
        void InitializeInstanceFields()
        {
            _mediaPlayer = gcnew MediaPlayer();
            _positionsToThumbnail = gcnew Queue<TimeSpan>();
            _watchdogTimer = gcnew DispatcherTimer();
            m_iContrast = 1;
        }
    };
#pragma endregion 
}
于 2012-10-02T01:13:42.183 回答