Edit Windows Media Profile (.prx) file in code

0

I'm using a third party control for video capture that uses .prx files for certain output attributes, namely the output size. I'm trying to set the output height and width to be the largest possible while maintaining the ratio of the user's actual screen size.

I believe the .prx file is just an XML file, but when I open the it as an XMLDocument then save it, I get a message stating "The Profile is invalid. (0xC00D0BC6)" when trying to open with Windows Media Encoder. I was able to open the same file without issue before running the code.

Dim prx As New XmlDocument()
prx.Load(Globals.appPath + prxFileName)
Dim prxWidth As XmlAttribute = prx.SelectSingleNode("/profile/streamconfig/wmmediatype/videoinfoheader/bitmadinfoheader/@biwidth")
Dim prxHeight As XmlAttribute = prx.SelectSingleNode("/profile/streamconfig/wmmediatype/videoinfoheader/bitmadinfoheader/@biheight")
prx.Save(Globals.appPath + prxFileName)

So without doing any actual editing of the file but re-saving it as an XMLDocument, the profile becomes invalid. Is there a way to edit .prx files in code while maintaining the profile validity?.

For reference, a valid .prx file opened in a text editor is below.

<profile version="589824" 
         storageformat="1" 
         name="myProfile" 
         description=""> 
               <streamconfig majortype="{73647561-0000-0010-8000-00AA00389B71}" 
               streamnumber="1" 
               streamname="Audio Stream" 
               inputname="Audio409" 
               bitrate="48000" 
               bufferwindow="3000" 
               reliabletransport="0" 
               decodercomplexity="" 
               rfc1766langid="en-us" 
> 
         <wmmediatype subtype="{00000161-0000-0010-8000-00AA00389B71}"  
               bfixedsizesamples="1" 
               btemporalcompression="0" 
               lsamplesize="1152"> 
       <waveformatex wFormatTag="353" 
                     nChannels="2" 
                     nSamplesPerSec="32000" 
                     nAvgBytesPerSec="6000" 
                     nBlockAlign="1152" 
                     wBitsPerSample="16" 
                     codecdata="008800001F0000000000"/> 
        </wmmediatype>
        </streamconfig>
               <streamconfig majortype="{73646976-0000-0010-8000-00AA00389B71}" 
               streamnumber="2" 
               streamname="Video Stream" 
               inputname="Video409" 
               bitrate="400000" 
               bufferwindow="3000" 
               reliabletransport="0" 
               decodercomplexity="AU" 
               rfc1766langid="en-us" 
> 
                 <videomediaprops maxkeyframespacing="80000000" 
                                 quality="100"/> 
         <wmmediatype subtype="{33564D57-0000-0010-8000-00AA00389B71}"  
               bfixedsizesamples="0" 
               btemporalcompression="1" 
               lsamplesize="0"> 
   <videoinfoheader dwbitrate="400000" 
                    dwbiterrorrate="0" 
                    avgtimeperframe="333333"> 
    <rcsource left="0" 
              top="0" 
              right="2000" 
              bottom="562"/> 
    <rctarget left="0" 
              top="0" 
              right="2000" 
              bottom="562"/> 
        <bitmapinfoheader biwidth="2000" 
                          biheight="562" 
                          biplanes="1" 
                          bibitcount="24" 
                          bicompression="WMV3" 
                          bisizeimage="0" 
                          bixpelspermeter="0" 
                          biypelspermeter="0" 
                          biclrused="0" 
                          biclrimportant="0"/> 
   </videoinfoheader>
        </wmmediatype>
        </streamconfig>
</profile> 

With help from this question, Video Capture output always in 320x240 despite changing resolution, I changed my strategy a bit to use IWMStreamConfig.

    Dim profileData As String
    Using reader As New StreamReader(File.OpenRead(Globals.appPath + prxFileName))
        profileData = reader.ReadToEnd()
    End Using

    Dim profileManager As IWMProfileManager
    Dim wmProfile As IWMProfile = Nothing
    Dim hr As Integer = WMLib.WMCreateProfileManager(profileManager)
    If hr >= 0 Then
        hr = profileManager.LoadProfileByData(profileData, wmProfile)
    End If

    If profileManager IsNot Nothing Then
        System.Runtime.InteropServices.Marshal.ReleaseComObject(profileManager)
        profileManager = Nothing
    End If

    Dim pConfig As IWMStreamConfig
    wmProfile.GetStream("Video Stream", pConfig)

Now that I have at least the stream as an IWMStreamConfig object, I feel like I'm getting closer. But how do I edit the BITMAPINFOHEADER.biHeight and BITMAPINFOHEADER.biWidth as found in this MSDN article?

http://msdn.microsoft.com/en-us/library/windows/desktop/dd756998(v=vs.85).aspx

The SetBitRate and SetBufferWindow are showing up in InteliSense but I'm not sure how to get to these lower level properties.

.net
video-capture
asked on Stack Overflow Nov 27, 2012 by Alex • edited May 23, 2017 by Community

2 Answers

1

The file is Unicode. Specifically, little-endian UTF-16 based on the BOM code 0xFFFE.

Since it looks like you are using .NET, try wrapping your FileStream in a StreamWriter:

Dim FS As FileStream = New FileStream(prxFile, FileMode.CreateNew)
Dim SW As StreamWriter = New StreamWriter(FS, new UnicodeEncoding(false, true))

Then you can write whole strings to the file.

XmlDocument's Load/Save methods take a StreamWriter which extends TextWriter. Just create it the same way with the encoding specified.

answered on Stack Overflow Feb 27, 2013 by Jason S. Clary
0

After looking at the file in a Hex Editor, the valid profiles have 0x00 between each character and the file starts with 0xFFFE, I'm assuming for some encoding. Once that was determined, I just used a stream reader to read in the text to a string and made my changes with string manipulation.

The tricky part was writing everything back to the file. For some reason, any way I tried to write the first two Hex characters to the file, they would be translated to four different Hex characters. The solution was to write it byte by byte with a FileStream.

//Read in the initial profile
Dim profileData As String
Using reader As New StreamReader(File.OpenRead(prxFile))
    profileData = reader.ReadToEnd()
End Using

//Make changes to the profile with string manipulation

//Write the changed data back to the file including all the Hex characters
File.Delete(prxFile)
Dim FS As FileStream = New FileStream(prxFile, FileMode.CreateNew)
//Start by writing 0xFFFE
FS.WriteByte(&HFF)
FS.WriteByte(&HFE)
//Then write each character succeeded by 0x00
For Each Character As Char In profileData.ToCharArray
    FS.WriteByte(AscW(Character))
    FS.WriteByte(&H0)
Next
FS.Close()
answered on Stack Overflow Nov 28, 2012 by Alex

User contributions licensed under CC BY-SA 3.0