|
Imports System.Collections.Generic
Imports System.Threading
Imports System.IO
Imports System.Runtime.InteropServices
Imports System.ComponentModel
Imports Silverlight5_SampleVB1.cAVIDefs
Public Class MyDerivedMediaStreamSource : Inherits MediaStreamSource
' <summary>
' Describes the Media Stream
' </summary>
Private _videoDesc As MediaStreamDescription
' <summary>
' Width of the Video Frame (set as constant)
' </summary>
Private _frameWidth As Integer = 320 ' *** best to set this when you have acquired actual video width using obj.videoWidth()
' <summary>
' Height of the Video frame (set as constant)
' </summary>
Private _frameHeight As Integer = 240 ' *** best to set this when you have acquired actual video height using obj.videoHeight()
' <summary>
' Rendering time in the media
' </summary>
Private _timeStamp As Long = 0
' <summary>
' Number of bytes of each pixel (4 bytes - RGBA)
' </summary>
Private Const _framePixelSize As Integer = 4
' <summary>
' Size in bytes for each Sample of type RGBA (4 bytes per pixel)
' </summary>
Private _count As Integer '= _frameHeight * _frameWidth * _framePixelSize
' <summary>
' Size in bytes of the stream (same as the frame size in bytes)
' </summary>
Private _frameStreamSize As Integer '= _count
' <summary>
' Stream to contain a Sample
' </summary>
Private _stream As MemoryStream = New MemoryStream(_frameStreamSize)
' <summary>
' The Offset into the stream where the actual sample data begins
' </summary>
Private _offset As Integer = 0
' <summary>
' Buffer to hold a collection of type Sample.
' </summary>
Private sampleBufferList As Queue(Of Sample) = New Queue(Of Sample)
' <summary>
' variable holds the FPS of the video played
' </summary>
Public _speed As Long = 30
' <summary>
' Timeout period (fps from video is used).
' </summary>
Private timeout As TimeSpan = TimeSpan.FromSeconds(_speed)
' <summary>
' Empty Dictionary used in the returned empty sample.
' </summary>
Private emptyDictionary As Dictionary(Of MediaSampleAttributeKeys, String) = New Dictionary(Of MediaSampleAttributeKeys, String)
' <summary>
' Total number of Samples to buffer.
' </summary>
Private Const numberOfSamplesBuffer As Integer = 15 ' I set to 15 as an example, but you can increase or decrease
Protected Overrides Sub OpenMediaAsync()
Dim availableStreams As List(Of MediaStreamDescription) = New List(Of MediaStreamDescription)
Dim streamAttributes As Dictionary(Of MediaStreamAttributeKeys, String) = New Dictionary(Of MediaStreamAttributeKeys, String)
Dim sourceAttributes As Dictionary(Of MediaSourceAttributesKeys, String) = New Dictionary(Of MediaSourceAttributesKeys, String)
' We are going to convert our video frame/sample from RGB to RGBA
streamAttributes(MediaStreamAttributeKeys.VideoFourCC) = "RGBA"
streamAttributes(MediaStreamAttributeKeys.Height) = _frameHeight.ToString()
streamAttributes(MediaStreamAttributeKeys.Width) = _frameWidth.ToString()
_videoDesc = New MediaStreamDescription(MediaStreamType.Video, streamAttributes)
availableStreams.Add(_videoDesc)
sourceAttributes(MediaSourceAttributesKeys.Duration) = TimeSpan.FromSeconds(0).Ticks.ToString()
sourceAttributes(MediaSourceAttributesKeys.CanSeek) = False.ToString()
ReportOpenMediaCompleted(sourceAttributes, availableStreams)
Return
End Sub
Protected Overrides Sub GetSampleAsync(mediaStreamType As System.Windows.Media.MediaStreamType)
If mediaStreamType = mediaStreamType.Video Then
' start a thread to get the sample
'Dim thread As Thread = New Thread(New ThreadStart(AddressOf retrieveSampleThread))
'thread.Start()
retrieveSample()
Return
End If
End Sub
Protected Overrides Sub SeekAsync(seekToTime As Long)
_timeStamp = seekToTime
ReportSeekCompleted(seekToTime)
End Sub
Protected Overrides Sub GetDiagnosticAsync(diagnosticKind As System.Windows.Media.MediaStreamSourceDiagnosticKind)
End Sub
Protected Overrides Sub SwitchMediaStreamAsync(mediaStreamDescription As System.Windows.Media.MediaStreamDescription)
End Sub
Protected Overrides Sub CloseMedia()
' Do your cleanup here
_stream.Close()
_stream = Nothing
End Sub
' <summary>
' flag to kill a Sample processing thread
' </summary>
Private _done As Boolean = True
' <summary>
' Background Worker Thread to process Samples
' </summary>
Private _worker As BackgroundWorker = New BackgroundWorker()
' <summary>
' Represents the total number of frames in the video
' </summary>
Dim numFrames As Integer = 0
' <summary>
' Byte Array for a single Sample (RGB format, hence * 3 bytes for each pixel)
' </summary>
Private RGB_Sample As Byte() '= New Byte(_frameHeight * _frameWidth * 3)
' <summary>
' Byte Array for a single frame (RGBA format)
' </summary>
Private RGBA_Sample() As Byte '= New Byte(_count)
' <summary>
' Set to true to rotate Sample to normal view
' </summary>
Private _flipped As Boolean = True
Public Sub closeStream()
' set to true to stop the processing thread
'_done = True
CloseMedia()
If pGetFrameObj <> 0 Then
Call AVIStreamGetFrameClose(pGetFrameObj) '
End If
If pAVIStream <> 0 Then
Call AVIStreamRelease(pAVIStream) ' Close video stream
End If
If pAVIFile <> 0 Then
Call AVIFileRelease(pAVIFile) ' Close the AVI file
End If
AVIFileExit()
End Sub
Public Sub flipped(val As Boolean)
_flipped = val
'sampleBufferList.Clear()
End Sub
Private j As Int32 = 0
Private Const RGBByteCount As Int16 = 3 ' represents RGB total bytes per pixel
Private Const RGBAByteCount As Int16 = 4 ' represents RGBA total bytes per pixel
Private pixelPos As Int32
Private timeexpended As Int32, frametime As Int32, initialtime As Int32
Private timelapse As Integer, initcapture As Integer
Private m_memBits() As Byte
Private m_bih As New BITMAPINFO
Private Sub initializeFrametime()
frametime = 0
timelapse = 30
initcapture = 1
End Sub
' <summary>
' Method that checks availability of a Sample
' </summary>
Private Sub retrieveSample()
'---------------------------------------------------------------
' I CANNOT REMEMBER WHERE I GOT THIS CALCULATION FROM ONLINE
' it basically calculates the frame number based on time passed
' since start of play
'-------------------------**********----------------------------
'If Not videoPaused Then
If initcapture = 0 Then
timeexpended = timeGetTime() - initialtime
Else
frametime = 0
timeexpended = 0
initialtime = timeGetTime()
End If
If initcapture = 0 Then
If timelapse > 1000 Then
frametime = frametime + 1
Else
frametime = (timeexpended / 1000) * (1000 / _speed) 'timelapse)
If frametime >= numFrames Then
initializeFrametime()
End If
End If
Else
initcapture = 0
End If
'End If
'-------------------------**********----------------------------
'
'---------------------------------------------------------------
Try
' Get the requested Frame from the Stream - frame number "frametime" provided.
' Return a Pointer to the DIB
pDIB = AVIStreamGetFrame(pGetFrameObj, frametime)
Catch ex As Exception
End Try
If pDIB <> 0 Then
'Copy the Frame bits into RGB_Sample
'Call CopyMemory(RGB_Sample(0), pDIB + Marshal.SizeOf(bih), bih.biSizeImage)
Marshal.Copy(pDIB + Marshal.SizeOf(bih), RGB_Sample, 0, bih.biSizeImage)
If Not RGB_Sample Is Nothing Then
For verticalCount As Integer = RGB_Sample.Length - 1 To 0 Step _frameWidth * RGBByteCount * -1
For horizontalCount As Integer = 0 To _frameWidth - 1
' Calculate the next pixel position from the original Sample
' based on the outer loop, it is calculated from bottom-right
pixelPos = verticalCount - (_frameWidth * RGBByteCount) + (horizontalCount * RGBByteCount) + 1
RGBA_Sample(j) = RGB_Sample(pixelPos)
RGBA_Sample(j + 1) = RGB_Sample(pixelPos + 1)
RGBA_Sample(j + 2) = RGB_Sample(pixelPos + 2)
' Assign 1 byte for the Alpha Channel
RGBA_Sample(j + 3) = 255 '&FF
'jump 4 bytes for the RGBA byte counter
j += RGBAByteCount
Next
Next
End If
j = 0
End If
' Instantiate a Sample
' The Sample has two members (Time & Buffer)
Dim _sample As Sample = New Sample()
_sample.sampleBuffer = RGBA_Sample
_sample.sampleTime = DateTime.Now
' We always start at the beginning of the stream
' this is because we always reset the stream with one sample at a time
' if you decide to add more than one sample into the stream then you
' can modify the logic to increment this offset by the size of the sample
' everytime there is a call to return a sample
_offset = 0
_stream.Seek(0, SeekOrigin.Begin)
' write the retrieved Sample into the stream
' remember our stream is just one Sample
_stream.Write(_sample.sampleBuffer, 0, _count)
Dim mediaSample As MediaStreamSample = New MediaStreamSample(
Me._videoDesc,
_stream,
_offset,
_count,
_timeStamp,
Me.emptyDictionary)
_timeStamp += TimeSpan.FromSeconds(1 / _speed).Ticks
' report back a successful Sample
Me.ReportGetSampleCompleted(mediaSample)
Return
End Sub
' <summary>
' Pointer to the AVI File in memory
' </summary>
Private pAVIFile As Int32
' <summary>
' Pointer to the AVI Stream in memory
' </summary>
Private pAVIStream As Int32
' <summary>
' Structure representing the Bitmap Information
' </summary>
Private bih As BITMAPINFOHEADER
' <summary>
' Pointer to Video Frames Object in Memory
' </summary>
Private pGetFrameObj As Int32
' <summary>
' Pointer to a DIB
' </summary>
Private pDIB As Int32
' <summary>
' Number of Scanlines in a Video Frame
' </summary>
Private numScans As Int16
Private Const streamtypeVIDEO As Int32 = 1935960438
Private Const BI_RGB As Int32 = 0
Private firstFrame As Int32
Private streamInfo As AVISTREAM_INFO = New AVISTREAM_INFO()
' <summary>
' Opens an AVI File and extract the Video Stream
' IN: fname, video file name
' </summary>
Public Function startVideo(fname As String) As Boolean
' Return a Pointer of the File in Memory assigned to pAVIFile
Dim res As Int32 = AVIFileOpen(pAVIFile, fname, 32, 0)
' Return a Pointer of the Video Stream in Memory assigned to pAVIStream
res = AVIFileGetStream(pAVIFile, pAVIStream, streamtypeVIDEO, 0)
' Return the First Video Frame Number
firstFrame = AVIStreamStart(pAVIStream)
' Return the Total Number of Frames in the Stream
numFrames = AVIStreamLength(pAVIStream)
' Return the Video Stream Information
res = AVIStreamInfo(pAVIStream, streamInfo, Marshal.SizeOf(streamInfo))
_speed = streamInfo.dwRate 'fps
With bih
.biBitCount = 24
.biClrImportant = 0
.biClrUsed = 0
.biCompression = BI_RGB
.biHeight = streamInfo.rcFrame.bottom - streamInfo.rcFrame.top
.biPlanes = 1
.biSize = 40
.biWidth = streamInfo.rcFrame.right - streamInfo.rcFrame.left
.biXPelsPerMeter = 0
.biYPelsPerMeter = 0
.biSizeImage = (((.biWidth * 3) + 3) And &HFFFC) * .biHeight
End With
_frameWidth = bih.biWidth
_frameHeight = bih.biHeight
_count = _frameHeight * _frameWidth * _framePixelSize
_frameStreamSize = _count
numScans = IIf(_frameHeight > _frameWidth, _frameHeight, _frameWidth)
' Retrieve the Frames Object from the stream byte by supplying the Stream and the format we expect
pGetFrameObj = AVIStreamGetFrameOpen(pAVIStream, bih)
If pGetFrameObj = 0 Then Return False 'ERROR
' Resize our actual Samples in Bytes
ReDim RGB_Sample(bih.biSizeImage - 1)
' Resize our final modified sample in Bytes
ReDim RGBA_Sample(_count - 1)
initializeFrametime()
Return True
End Function
End Class
|
By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.
If a file you wish to view isn't highlighted, and is a text file (not binary), please
let us know and we'll add colourisation support for it.
I have been a Developer for many years. I have worked as Senior Developer in Kenya, Canada and Saudi Arabia. I enjoy coding and I am looking forward to more challenges with new Technologies
I am currently IT Manager at Norconsult Telematics, Saudi Arabia.