下應接近,但我可以保證,它不會太大的差別在速度方面,因爲它也託管代碼(我把它全部在頭文件):
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
}
於C++。 NET或純粹的Win32 C++? – zerkms
C++ .NET,VS2008,CLI。 – dnLL
「看看實際上更好/更快。」 ---那麼代碼將99%相同,以及結果二進制。 PS:用於媒體播放器的「CLI」? – zerkms