0

I've been working with DirectShow filters to convert and compress audio from one format to another. I use GraphStudio and GraphStudioNext to create a filter graph that I then translate to filters in VB.Net. They've always worked great until now. I'm attempting to convert a .wav file to .mp3. Using GraphStudio and the following filters chained together with the default connections I get the compressed files. FileSource-Async-->WaveParser-->MPEG Layer3--> WAV Dest --> Filewriter.

However, when I connect the same filters together in my VB.Net program I get no compression at all. I've even tried to set the compression using the IAMStreamConfig interface but the compression that shows in GraphStudio is not available when I enumerate the pins in my program. The Function (including some comments) is below. Any thoughts, suggestions much appreciated.

Private Function PlayInitMP3(ByVal path As String, ByVal dstPath As String) As Integer

    Dim asyncReader As DirectShowNET.IBaseFilter = Nothing
    Dim WaveParser As DirectShowNET.IBaseFilter = Nothing
    'Dim ACMWrapper As DirectShowNET.IBaseFilter = Nothing
    Dim MPEG3Wrapper As DirectShowNET.IBaseFilter = Nothing
    Dim WavDestWrapper As DirectShowNET.IBaseFilter = Nothing

    Dim fileSource As DirectShowNET.IFileSourceFilter = Nothing
    Dim fileDestination As DirectShowNET.IBaseFilter = Nothing




    Dim result As Integer = -1
    Dim srcFileInfo As System.IO.FileInfo = New FileInfo(path)

    Service1.nlog.LogError(0, "Starting Init", "", "")

    'Set to Null Renderer
    Try
        result = WaveParser.SetSyncSource(DBNull.Value)
        Marshal.ThrowExceptionForHR(result)
        Service1.nlog.LogError(0, "SetSyncSource-WaveParser", result.ToString, "")

        'result = ACMWrapper.SetSyncSource(DBNull.Value)
        'Marshal.ThrowExceptionForHR(result)
        'Service1.nlog.LogError(0, "SetSyncSource-ACMWrapper", result.ToString, "")

        result = MPEG3Wrapper.SetSyncSource(DBNull.Value)
        Marshal.ThrowExceptionForHR(result)
        Service1.nlog.LogError(0, "SetSyncSource-MPEG3Wrapper", result.ToString, "")

        result = WavDestWrapper.SetSyncSource(DBNull.Value)
        Marshal.ThrowExceptionForHR(result)
        Service1.nlog.LogError(0, "SetSyncSource-WavDestWrapper", result.ToString, "")

    Catch ex As Exception

    End Try


    Try

        If IsNothing(Me.graphBuilder) = False Then
            Marshal.ReleaseComObject(Me.mediaSeeking)
            Marshal.ReleaseComObject(Me.mediaControl)
            Marshal.ReleaseComObject(Me.graphBuilder)

            Me.mediaSeeking = Nothing
            Me.mediaControl = Nothing
            Me.graphBuilder = Nothing

        End If

        ' Create IGraphBuilder instance
        Me.graphBuilder = New DirectShowNET.FilterGraph()


        ' Create MediaControl

        ' File source filter addition
        asyncReader = New DirectShowNET.AsyncReader
        result = graphBuilder.AddFilter(asyncReader, System.IO.Path.GetFileName(path))
        Marshal.ThrowExceptionForHR(result)

        Service1.nlog.LogError(0, "SourceFilter", result.ToString, "")

        ' Add Wave Parser
        WaveParser = New DirectShowNET.WaveParser
        result = Me.graphBuilder.AddFilter(WaveParser, "Wave Parser")
        Marshal.ThrowExceptionForHR(result)

        Service1.nlog.LogError(0, "WaveParser", result.ToString, "")

        '' Add ACMWrapper
        'ACMWrapper = New DirectShowNET.ACMWrapper
        'result = Me.graphBuilder.AddFilter(ACMWrapper, "ACMWrapper Parser")
        'Marshal.ThrowExceptionForHR(result)

        'Service1.nlog.LogError(0, "ACMWrapper", result.ToString, "")

        ' Add MPEG3Wrapper
        MPEG3Wrapper = New DirectShowNET.MPEG3Layer
        result = Me.graphBuilder.AddFilter(MPEG3Wrapper, "MPEG3Layer Parser")
        Marshal.ThrowExceptionForHR(result)

        Service1.nlog.LogError(0, "MPEG3Wrapper", result.ToString, "")


        ' Add WAVDest
        WavDestWrapper = New DirectShowNET.WaveDestination
        result = Me.graphBuilder.AddFilter(WavDestWrapper, "WaveDestination")
        Marshal.ThrowExceptionForHR(result)

        Service1.nlog.LogError(0, "WaveDestination", result.ToString, "")


        ' FileWriter filter addition
        fileDestination = New DirectShowLib.FileWriter
        Dim fs As DirectShowLib.IFileSinkFilter = DirectCast(fileDestination, DirectShowLib.IFileSinkFilter)
        result = fs.SetFileName(dstPath, Nothing)
        Marshal.ThrowExceptionForHR(result)

        Service1.nlog.LogError(0, "FileWriter", result.ToString, "")

        result = Me.graphBuilder.AddFilter(DirectCast(fileDestination, DirectShowNET.IBaseFilter), "Filewriter")
        Marshal.ThrowExceptionForHR(result)



        ' Set the Filename using the IFileSinkFilter interface

        ' The file is loaded. 
        fileSource = asyncReader
        result = fileSource.Load(path, Nothing)
        Marshal.ThrowExceptionForHR(result)

        Service1.nlog.LogError(0, "SourceFileLoad", result.ToString, "")

        ' Wave Parser is connected with FileSourceFilter.
        Try
            result = ConnectFilters(Me.graphBuilder, asyncReader, WaveParser)
            Marshal.ThrowExceptionForHR(result)
        Catch ex As Exception
            Service1.nlog.LogError(0, "ConnectWaveParser", ex.Message, "")
        End Try

        Service1.nlog.LogError(0, "WaveParser Result", result.ToString, "")

        ' Wave Parser is connected with MPEG3.
        Try
            result = ConnectFilters(Me.graphBuilder, WaveParser, MPEG3Wrapper)
            Marshal.ThrowExceptionForHR(result)
        Catch ex As Exception
            Service1.nlog.LogError(0, "ConnectWaveParser", ex.Message, "")
        End Try

        Service1.nlog.LogError(0, "WaveParser Result", result.ToString, "")
        '' ACMParser is connected with WaveParser.
        'Try
        '    result = ConnectFilters(Me.graphBuilder, WaveParser, ACMWrapper)
        '    Marshal.ThrowExceptionForHR(result)
        'Catch ex As Exception
        '    Service1.nlog.LogError(0, "ConnectACMWrapper", ex.Message, "")
        'End Try

        'Service1.nlog.LogError(0, "ACMWrapper Result", result.ToString, "")

        ''COMPRESSION
        'Try
        '    'Configure the Compression Stream Variables
        '    Dim NewConfig As IAMStreamConfig
        '    Dim mp3Pin As IPin
        '    Dim ppEnum As IEnumPins
        '    Dim aPin(1) As IPin
        '    Dim dPin As PinDirection = PinDirection.Output
        '    Dim nPin As Integer


        '    Service1.nlog.LogError(0, "Beginning ACMWrapper Compression", "", "")
        '    ACMWrapper.EnumPins(ppEnum)
        '    While ppEnum.Next(1, aPin, nPin) = 0
        '        mp3Pin = aPin(0)
        '        mp3Pin.QueryDirection(dPin)
        '        If dPin = PinDirection.Output Then
        '            Exit While
        '        End If
        '    End While


        '    NewConfig = TryCast(mp3Pin, IAMStreamConfig)
        '    If NewConfig Is Nothing Then
        '        Service1.nlog.LogError(0, "NewConfig Is nothing", "", "")

        '    End If
        '    Service1.nlog.LogError(0, "After TryCast", "", "")

        '    Dim nCap As Integer
        '    Dim sCap As Integer
        '    Dim pmt As New DirectShowLib.AMMediaType
        '    Service1.nlog.LogError(0, "After pmt", "", "")

        '    NewConfig.GetNumberOfCapabilities(nCap, sCap)
        '    Dim i As Integer
        '    Dim sArray(sCap) As System.IntPtr
        '    Dim intPtr As IntPtr = Marshal.AllocCoTaskMem(sCap)

        '    Dim audioFormatACM As WaveFormatEx

        '    For i = 0 To nCap - 1
        '        NewConfig.GetStreamCaps(i, pmt, intPtr)

        '        audioFormatACM = New WaveFormatEx()

        '        Marshal.PtrToStructure(pmt.formatPtr, audioFormatACM)
        '        'Print Audio Format
        '        Service1.nlog.LogError(0, "Index:", i.ToString, "")
        '        Service1.nlog.LogError(0, "AudioFormat:BitsPerSample", audioFormatACM.wBitsPerSample.ToString, "")
        '        Service1.nlog.LogError(0, "AudioFormat:nSamplesPerSec", audioFormatACM.nSamplesPerSec.ToString, "")
        '        Service1.nlog.LogError(0, "AudioFormat:AvgBytesPerSec", audioFormatACM.nAvgBytesPerSec.ToString, "")

        '        ''Once find the proper format then save it and exit
        '        If audioFormatACM.nAvgBytesPerSec = 8000 AndAlso audioFormatACM.nSamplesPerSec = 8000 Then
        '            'audioFormatACM.nAvgBytesPerSec = 8000
        '            'audioFormatACM.wBitsPerSample = 8
        '            'audioFormatACM.nSamplesPerSec = 8000
        '            Marshal.StructureToPtr(audioFormatACM, pmt.formatPtr, True)
        '            Exit For
        '        End If
        '    Next

        '    'Use Selected format from enum to set

        '    If NewConfig.SetFormat(pmt) <> 0 Then
        '        Service1.nlog.LogError(0, "ACM Setformat Error", "", "")
        '    End If

        '    'See if Successfully Set

        '    audioFormatACM = New WaveFormatEx()

        '    Marshal.PtrToStructure(pmt.formatPtr, audioFormatACM)

        '    If NewConfig.GetFormat(pmt) <> 0 Then
        '        Service1.nlog.LogError(0, "ACM GetFormat Error", "", "")
        '    End If
        '    Service1.nlog.LogError(0, "ACM Updated AvgBytesPerSec", audioFormatACM.nAvgBytesPerSec.ToString, "")
        '    Service1.nlog.LogError(0, "ACM Updated SamplesPerSec", audioFormatACM.nSamplesPerSec.ToString, "")

        '    'Release Memory

        'Catch ex As Exception
        '    Service1.nlog.LogError(0, "Compression Error:", ex.Message, ex.Source)

        'End Try

        '' WaveParser is connected with MPEG3.
        'Try
        '    result = ConnectFilters(Me.graphBuilder, ACMWrapper, MPEG3Wrapper)
        '    Marshal.ThrowExceptionForHR(result)
        'Catch ex As Exception
        '    Service1.nlog.LogError(0, "Connect MPEG3Wrapper", ex.Message, "")
        'End Try

        'Service1.nlog.LogError(0, "MPEG3Wrapper Result", result.ToString, "")

        'COMPRESSION
        Try
            'Configure the Compression Stream Variables
            Dim NewConfig1 As IAMStreamConfig
            Dim mp3Pin1 As IPin
            Dim ppEnum1 As IEnumPins
            Dim aPin1(1) As IPin
            Dim dPin1 As PinDirection = PinDirection.Output
            Dim nPin1 As Integer

            MPEG3Wrapper.EnumPins(ppEnum1)
            While ppEnum1.Next(1, aPin1, nPin1) = 0
                mp3Pin1 = aPin1(0)
                mp3Pin1.QueryDirection(dPin1)
                If dPin1 = PinDirection.Output Then
                    Exit While
                End If
            End While


            NewConfig1 = TryCast(mp3Pin1, IAMStreamConfig)
            If NewConfig1 Is Nothing Then
                Service1.nlog.LogError(0, "NewConfig Is nothing", "", "")

            End If
            Service1.nlog.LogError(0, "After TryCast", "", "")

            Dim nCap1 As Integer
            Dim sCap1 As Integer
            Dim pmt1 As New DirectShowLib.AMMediaType
            Service1.nlog.LogError(0, "After pmt", "", "")

            NewConfig1.GetNumberOfCapabilities(nCap1, sCap1)
            Dim i As Integer
            Dim sArray1(sCap1) As System.IntPtr
            Dim intPtr1 As IntPtr = Marshal.AllocCoTaskMem(sCap1)

            Dim audioFormat As MPEGLAYER3WAVEFORMAT

            For i = 0 To nCap1 - 1
                NewConfig1.GetStreamCaps(i, pmt1, intPtr1)

                audioFormat = New MPEGLAYER3WAVEFORMAT()

                Marshal.PtrToStructure(pmt1.formatPtr, audioFormat)
                'Print Audio Format
                Service1.nlog.LogError(0, "Index:", i.ToString, "")
                Service1.nlog.LogError(0, "AudioFormat:BitsPerSample", audioFormat.wfx.wBitsPerSample.ToString, "")
                Service1.nlog.LogError(0, "AudioFormat:nSamplesPerSec", audioFormat.wfx.nSamplesPerSec.ToString, "")
                Service1.nlog.LogError(0, "AudioFormat:AvgBytesPerSec", audioFormat.wfx.nAvgBytesPerSec.ToString, "")

                'Once find the proper format then save it and exit
                'If audioFormat.wfx.nAvgBytesPerSec = 8000 AndAlso audioFormat.wfx.wBitsPerSample = 8 Then
                '    audioFormat.wfx.nAvgBytesPerSec = 8000
                '    'audioFormat.wfx.wBitsPerSample = 8
                '    'audioFormat.wfx.wFormatTag = 85
                '    'audioFormat.wfx.nSamplesPerSec = 1000
                '    Service1.nlog.LogError(0, "MP3 Selected Format AvgBytesPerSec", audioFormat.wfx.nSamplesPerSec.ToString, "")
                '    Marshal.StructureToPtr(audioFormat, pmt1.formatPtr, True)
                '    Exit For
                'End If
            Next

            'Use Selected format from enum to set

            'If NewConfig1.SetFormat(pmt1) <> 0 Then
            '    Service1.nlog.LogError(0, "Setformat Error:", NewConfig1.SetFormat(pmt1).ToString, "")
            'End If

            'See if Successfully Set

            audioFormat = New MPEGLAYER3WAVEFORMAT()
            pmt1 = New AMMediaType

            If NewConfig1.GetFormat(pmt1) <> 0 Then
                Service1.nlog.LogError(0, "GetFormat Error", "", "")
            End If

            Marshal.PtrToStructure(pmt1.formatPtr, audioFormat)
            Service1.nlog.LogError(0, "Updated AvgBytesPerSec", audioFormat.wfx.nAvgBytesPerSec.ToString, "")
            Service1.nlog.LogError(0, "Updated SamplesPerSec", audioFormat.wfx.nSamplesPerSec.ToString, "")
            Service1.nlog.LogError(0, "Updated FormatTag", audioFormat.wfx.wFormatTag.ToString, "")

        Catch ex As Exception
            Service1.nlog.LogError(0, "Compression Error:", ex.Message, ex.Source)

        End Try


        ' MPEG3 is connected with WavDest.
        Try
            result = ConnectFilters(Me.graphBuilder, MPEG3Wrapper, WavDestWrapper)
            Marshal.ThrowExceptionForHR(result)
        Catch ex As Exception
            Service1.nlog.LogError(0, "Connect WavDestWrapper", ex.Message, "")
        End Try

        Service1.nlog.LogError(0, "WaveDestWrapper Result", result.ToString, "")


        ' Connect to the File Writer 
        result = ConnectFilters(Me.graphBuilder, WavDestWrapper, fileDestination)
        Marshal.ThrowExceptionForHR(result)

        Service1.nlog.LogError(0, "ConnectFileWriter", result.ToString, "")



        'Actually Write The File

        ' The IMediaSeeking interface is acquired.
        Me.mediaSeeking = Me.graphBuilder
        Me.mediaSeeking.GetDuration(Me.duration)
        Me.duration /= DSS_MEDIA_TIME   ' MEDIA_TIME to Millisecond
        Service1.nlog.LogError(0, "Duration=", Me.duration.ToString, "")


    Catch ex As Exception

        Marshal.ReleaseComObject(Me.graphBuilder)
        Me.graphBuilder = Nothing
        Service1.nlog.LogError(0, "Exception MP3Convert", ex.Message, "")
    Finally

        asyncReader = Nothing
        WaveParser = Nothing
        'ACMWrapper = Nothing
        MPEG3Wrapper = Nothing
        WavDestWrapper = Nothing
        fileSource = Nothing
        fileDestination = Nothing

    End Try

        Service1.nlog.LogError(0, "Ending Init MP3", " Result:", result.ToString)

        Return result

End Function
Roman R.
  • 68,205
  • 6
  • 94
  • 158
user2176065
  • 43
  • 1
  • 3
  • why paste commented out code? how is that useful? – Mitch Wheat Mar 16 '13 at 02:53
  • It's there to show how I've attempted to set the compression parameters as I noted in my description so that if someone wanted to test it they could. Bottom line is that either attempting to set the IAMStreamConfig or not - I don't get the same result as in GraphStudio. – user2176065 Mar 16 '13 at 03:17
  • 1
    `1` What is DirectShowNET.MPEG3Layer? `2` You should not do SetSyncSource on individual filters, it's no good but it can be bad. – Roman R. Mar 16 '13 at 07:24
  • Did you try to set compression before connecting the output pin? – wimh Mar 16 '13 at 11:21
  • DirectShowNET.MPEG3Layer is a public interface. And not setting the syncsource on the filters unfortunately has no effect. _ Public Class MPEG3Layer End Class – user2176065 Mar 16 '13 at 20:55
  • Yes - that's what I attempt to do is set compression before the output pin is connected on the MPEG3Wrapper. In doing the enum of the IAMStreamConfig it doesn't match with the GraphEdit has has options. GraphEdit automatically selects 1000 as the nAvgBytesPerSec - which is what I want and which gives the expected compression. The ENUM of the PIN's minimum nAvgBytesPerSec is 8000 in the program. – user2176065 Mar 16 '13 at 21:00
  • It's not a public interface. You cannot instantiate an interface by the way (you can instantiate a class, which implements the interface - this is what your code does). More likely, it's a third party component that does not work the way you expect it to work. – Roman R. Mar 17 '13 at 14:23
  • Sorry - I misspoke that part about the interface. As to a third party component - GraphStudio calls the same 3rd party components and gets different results. That's what I'd like to figure out. – user2176065 Mar 17 '13 at 15:51
  • The thing is that `MPEG3Layer` is not even a part of DirectShow.NET, is it? So it's hard to tell what is going on in your code referencing an unknown thingy, even if it looks working well on GraphEdit. – Roman R. Mar 17 '13 at 20:15

1 Answers1

0

After much research I've not been able to make the compression work as it does with graphedit. So I've decided to change the project entirely and use the lame encoder to do the conversion. It works perfectly with very little code. Here's the new code:

Private Function PlayInitMP3(ByVal WaveFile As String, ByVal MP3File As String) As Integer
    Try
        'Convert WAV to MP3 using Lame
        Dim WaveFileInfo As New FileInfo(WaveFile)
        Dim MP3FileInfo As New FileInfo(MP3File)
        Dim strLameLine As String
        Dim LameExe As String = ConfigurationManager.AppSettings("LameExe") '"C:\scribe\lame\lame.exe -h"
        Dim sBlank As String = " "
        Dim waitTime As Integer = System.Convert.ToInt16(ConfigurationManager.AppSettings("LameWait")) '-1

        strLameLine = LameExe & sBlank & WaveFileInfo.FullName & sBlank & MP3FileInfo.FullName

        Shell(strLameLine, AppWinStyle.Hide, True, waitTime)

        'Debug
        Service1.nlog.LogError(0, WaveFileInfo.Name, strLameLine, "LAME MP3 Conversion Complete")

    Catch ex As Exception

    End Try

End Function
user2176065
  • 43
  • 1
  • 3