Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

About obscurity of some extended attributes structures descriptions given in WMFSDK

138 views
Skip to first unread message

Vincas Stepankevicius

unread,
Oct 4, 2004, 6:52:03 AM10/4/04
to
Hi all,
I wonder if anybody have tried to read/write WM file (wma,mp3) extended
attributes, such as WM/Lyrics_Synchronised or WM/Picture.
I tried to do this in VB.NET (many thanks to Robert Smith for help), using
WMFSDKWrapper.dll from WMFSDK, and had no problems, reading/writing simple
WM attributes of type
WMT_ATTR_DATATYPE.WMT_TYPE_STRING, .WMT_TYPE_DWORD, .WMT_TYPE_QWORD or
.WMT_TYPE_BOOL.
I'm even able to read all extended attributes, and show their values
(embeded pictures, lyrics and synchronised lyrics).
But here I'm running into problems, raised by some mismatch between
structures described in WMFSDK and those returned by
IWMHeaderInfo3.GetAttributeByIndexEx
Let's take attribute "WM/Lyrics_Synchronised".
WMFSDK states that it's data array must contain such structure:

typedef struct _WMSynchronisedLyrics{
BYTE bTimeStampFormat; '(1 or 2 - depending on TimeStamp
format used)
BYTE bContentType; '(0-8 - ContentType dependant)
LPWSTR pwszContentDescriptor; '(Pointer to a wide-character
null-terminated string containing data from the encoding application;
app-dependant(?))
DWORD dwLyricsLen; '(length of the lyrics data in bytes)
BYTE* pbLyrics; '(Pointer to a BYTE array
containing the lyrics)
} WM_SYNCHRONISED_LYRICS;

, while dataArray, returned by GetAttributeByIndexEx, contains this (by zero
based position in array):

0(1-st byte) - bTimeStampFormat (2 in my case, meaning absolute time of the
lyric in milliseconds)
1(2-nd byte) - bContentType (1 in my case, meaning song lyrics)
2(3-6 bytes) - dword, with unknown meaning, let's name it dwA
6(7-10 bytes) - dword, corresponding to dwLyricsLen
10(11-14 bytes) - dword, with unknown meaning, let's name it dwB
14 - wide-character null-terminated string, containing description of
Synched lyrics attribute,
and after it goes pbLyrics-BYTE array containing the lyrics data (timestamps
& their strings) itself.

The most interesting thing is that dwords dwA and dwB are getting new,
absolutely random at first sight values on every GetAttributeByIndexEx call
on the same mp3 file!
I say 'at first sight' because it's not absolutely true: difference dwB-dwA
always remains the same for a file (but may differ for various files)!
It would be only interesting, if I only wanted to read synched lyrics - I
can simply ignore those dwA & dwB; and I do so, reading
WM/Lyrics_Synchronised.
But when you decide to update this attribute, you'll see, that you can't
ignore them, leaving zeroed or even filling with some values according this
strange 'constant difference' rule!
That's why I ask for your help. Of course, it would be ideal to see some VB
code sample for updating (IWMHeaderInfo3.ModifyAttribute), but I thank in
advance for any ideas in vb.net or c#:)

Here is the same mismatch for WM/Picture for example:
description in WMFSDK:

typedef struct _WMPicture{
LPWSTR pwszMIMEType;
BYTE bPictureType;
LPWSTR pwszDescription;
DWORD dwDataLen;
BYTE* pbData;
} WM_PICTURE;

structure, returned by GetAttributeByIndexEx:
0: - dword with unknown meaning
4: - bPictureType (Picture type (author, album cover, group etc.) )
5: - dword with unknown meaning
9: - dwDataLen 'Picture size
13: -dword with unknown meaning
17: -pwszMIMEType (wide-character null-terminated string, usualy
"image/jpeg" in my case)
then goes pwszDescription,
then goes pbData

So, please, all guru, - help me to find a vb.net solution for WM attributes
update!

tia,
Vincas Stepankevicius

P.S.
One idea came into my head while writing these notes - most likely those
'mystic' dwords means nothing else but addresses of pointers to data?
Nonetheless I don't know what can I do with such 'knowledge', - so you
remain my last hope :)


smith

unread,
Oct 4, 2004, 6:29:54 PM10/4/04
to
I'll give a $10 prize (ten dollars US) via Paypal to anyone who can answer
this adequately using VB.Net or C# (without using UnSafe).

Code to this group please, Vincas being the judge of the result.

Robert Smith
Kirkland, WA
http://www.smithvoice.com

"Vincas Stepankevicius" <vstepan...@vilnius.vmi.lt> wrote in message
news:e6pTwAgq...@TK2MSFTNGP11.phx.gbl...


smith

unread,
Oct 4, 2004, 6:33:46 PM10/4/04
to
Make that "The First Person" with the adequate answer, judged by Vincas :)

-smith

"smith" <rcsTA...@smithvoiceTAKEOUT.com> wrote in message
news:C9k8d.2693$UP1....@newsread1.news.pas.earthlink.net...

Neil Smith [MVP Digital Media]

unread,
Oct 5, 2004, 4:18:31 AM10/5/04
to
I'll consider giving $10 to anybody who understands and can explain to
me a word he's on about Hehe. ;-)))

Cheers - Neil

Vincas Stepankevicius

unread,
Oct 5, 2004, 6:03:44 AM10/5/04
to
Hi, Neil,

Of cource, you may be not so savy as I expected, but please be at least more
well-meant :)
If my terrible English (I'm Lithanian) is the only reason you can't answer
this question - it's not so bad ;)

In the simplest terms I just asked for a sample of VB.NET code for updating
extended binary attributes of media files...
If you are still hazy about purport of my request - please, be so kind -
don't waste your time :)

thanks,
Vincas


"Neil Smith [MVP Digital Media]" <ne...@nospam.com> wrote in message
news:o2n4m056oedn8v3bs...@4ax.com...

Alessandro Angeli [MVP::DigitalMedia]

unread,
Oct 5, 2004, 6:09:20 AM10/5/04
to
"Vincas Stepankevicius" <vstepan...@vilnius.vmi.lt> wrote:

> One idea came into my head while writing these notes - most likely
> those 'mystic' dwords means nothing else but addresses of pointers to
> data? Nonetheless I don't know what can I do with such 'knowledge', -
> so you remain my last hope :)

They are pointers and the difference is a constant because the data is
always laid out in th same way. You can access the data they point to using
methods in System.Runtime.InteropServices.Marshal like PtrToStringUni(),
PtrToStructure(), ReadByte(), ReadInt16()... I think there may be a more
elegant solution, but this should do.


--

Alessandro Angeli

MVP::DigitalMedia

a dot angeli at biosys dot net

Alessandro Angeli [MVP::DigitalMedia]

unread,
Oct 5, 2004, 6:11:46 AM10/5/04
to
"Alessandro Angeli [MVP::DigitalMedia]" <nob...@nowhere.in.the.net> wrote:

> They are pointers and the difference is a constant because the data is
> always laid out in th same way. You can access the data they point to
> using methods in System.Runtime.InteropServices.Marshal like
> PtrToStringUni(), PtrToStructure(), ReadByte(), ReadInt16()... I
> think there may be a more elegant solution, but this should do.

Of course, you can use the inverse methods to write new data and get
pointers to your own structs and strings.

Iain

unread,
Oct 5, 2004, 6:55:17 AM10/5/04
to
Allesandro's comments are pertinent here.

It is also useful to know that the Lyrics fields are derived from the MP3
definitions for such things which are documented in in various places.

I haven't looked at them in detail so the following may be wrong.

It *may* be that in practive the pointers are effectively offsets into the
datablock so if you tread them as longs and see what is at point it may be
pertinent.

Iain

Vincas Stepankevicius

unread,
Oct 5, 2004, 6:58:06 AM10/5/04
to
Thanx, Alessandro,
I'll try it, while one question still remains: which structure must be used
in IWMHeaderInfo3.ModifyAttribute - structure described in SDK or one
returned by GetAttributeByIndexEx? They are different even considering your
explanation.

I'm glad to see that my English is not such bad as to be absolutely unclear
:)

thanks,
Vincas

Alessandro Angeli [MVP::DigitalMedia]" <nob...@nowhere.in.the.net> wrote in
message news:O%23pfpNsq...@tk2msftngp13.phx.gbl...

Alessandro Angeli [MVP::DigitalMedia]

unread,
Oct 5, 2004, 7:23:17 AM10/5/04
to
"Iain" <Iai...@idcl.co.uk> wrote:

> It *may* be that in practive the pointers are effectively offsets
> into the datablock so if you tread them as longs and see what is at
> point it may be pertinent.

I don't think so. The data block where the pointers are embedded is
marshalled as an unstructured byte array so they are not interpreted and
hence must retain their valued in unmanaged code, where they are actual
pointers and not offsets.

Alessandro Angeli [MVP::DigitalMedia]

unread,
Oct 5, 2004, 7:45:14 AM10/5/04
to
"Vincas Stepankevicius" <vstepan...@vilnius.vmi.lt> wrote:

> I'll try it, while one question still remains: which structure must
> be used in IWMHeaderInfo3.ModifyAttribute - structure described in
> SDK or one returned by GetAttributeByIndexEx? They are different even
> considering your explanation.

Both methods do not use any specific structure so I'll assume you mean the
structure relative to a specific attribute type, for example
WM_SYNCHRONISED_LYRICS, in which case the structure is exactly the same for
both methods, no difference. Or maybe you meant that the buffer you get
filled by GetAttributeByIndexEx() doesn't look like a WM_SYNCHRONISED_LYRICS
structure? Since I do not have any file that contains such an attribute, I
can not investigate it (do you have a sample you can share?).

Iain

unread,
Oct 5, 2004, 9:05:46 AM10/5/04
to
On Tue, 5 Oct 2004 13:23:17 +0200, Alessandro Angeli [MVP::DigitalMedia]
wrote:

> "Iain" <Iai...@idcl.co.uk> wrote:
>
>> It *may* be that in practive the pointers are effectively offsets
>> into the datablock so if you tread them as longs and see what is at
>> point it may be pertinent.
>
> I don't think so. The data block where the pointers are embedded is
> marshalled as an unstructured byte array so they are not interpreted and
> hence must retain their valued in unmanaged code, where they are actual
> pointers and not offsets.

Yeah, but are you saying that the the WMFSDK knows enough to fix up these
pointers as it loads the header metadata block into memory?

It would seem a remarkably clever thing to get it to do.

Mind you if you actually have tried this then I'll shut up, since I have
not. I found out just enough to reckon it wasn't worth my while! A little
knowledge and all that!

Iain

Vincas Stepankevicius

unread,
Oct 5, 2004, 10:39:31 AM10/5/04
to
"Alessandro Angeli [MVP::DigitalMedia]" <nob...@nowhere.in.the.net> wrote in
message news:e9wRWDtq...@TK2MSFTNGP12.phx.gbl...
......

> Both methods do not use any specific structure so I'll assume you mean the
> structure relative to a specific attribute type, for example
> WM_SYNCHRONISED_LYRICS, in which case the structure is exactly the same
for
> both methods, no difference. Or maybe you meant that the buffer you get
> filled by GetAttributeByIndexEx() doesn't look like a
WM_SYNCHRONISED_LYRICS
> structure?

I agree, that *internal* structure is the same for both methods, but as you
can see from declaration of WMFSDKWrapper.dll method GetAttributeByIndexEx
inVB:
--
Public Overridable Function GetAttributeByIndexEx(ByVal wStreamNum As
System.UInt16,
ByVal wIndex As System.UInt16, ByVal pwszName As String, ByRef pwNameLen
As System.UInt16,
ByRef pType As WMFSDKWrapper.WMT_ATTR_DATATYPE, ByRef pwLangIndex As
System.UInt16, ByVal pValue() As Byte,
ByRef pdwDataLength As System.UInt32) As System.UInt32
--
, this method returns attribute data as as byte array pValue, and I must
decide myself what structure has data in it, depending on attr name &
type...

>Since I do not have any file that contains such an attribute, I
> can not investigate it (do you have a sample you can share?).

Of cource I have, but I don't know if this group is a proper place for
messages with audio files attached :)
If You have Windows Media player (ver 9 or 10), you can simply create such
attributes on any mp3 or wma file you have.
If not - let me know, and I'll try to make a mp3 or wma file as little as
possible, with required attributes set.
If I got it right, I can use your spelled e-mail for sending such file.
Correct me if I'm wrong.

Vincas


Neil Smith [MVP Digital Media]

unread,
Oct 5, 2004, 10:45:42 AM10/5/04
to
Not at all - I wasn't being nasty ! I'm a web developer so I'm more or
less clueless about what you were asking ;-)

The English was fine, it was the technical content that baffled me.
It's probably a very interesting question, I just have no idea what
the answer will be !

Hopefully, Alessandro has a few clues he can offer.

Kind regards - Neil

Vincas Stepankevicius

unread,
Oct 5, 2004, 10:45:35 AM10/5/04
to
"Iain" <Iai...@idcl.co.uk> wrote in message
news:1mtsmts0y3d6g.3...@40tude.net...

Alessandro is positively right: they are *not* offsets in datablock for one
simple reason: their values are just too big for that :)

Vincas


smith

unread,
Oct 5, 2004, 12:05:55 PM10/5/04
to
Would it be any eaiser for folks to get rolling if instead of
Lyrics_Synchronised we tried the struct for the image first?

As to the conversion of the sdk C# sample structures to VB.net a starter can
be had from http://www.smithvoice.com/downs/svmedia.zip

For a quick look at what that does without a download, just click on
http://www.smithvoice.com/wmediaattrib.htm

This does the simple types (Strings, Bools, Ints) and the question, as I
understand it, is how to use Set or Add/Modify on the binary types.

-smith


Vincas Stepankevicius

unread,
Oct 5, 2004, 1:24:51 PM10/5/04
to
Nice to see you here again, Robert :)

There is absolutely no difference, which attr you'll examine. Having
clearness with pic, you'll be done with slyr too and vice versa.

After visiting your site site thought that it would be nice to show you a
screenshot of my app I've told you about.
Unfortunately, I haven't any public website to publish it for you, so if you
agree, I'll send it by e-mail.
What app's doing:
Attribute view/update (view - all attrs/update- all but those we are
talking about);
displays all embeded pics, lyrics, synched lyrics;
scrolls synched lyrics in a karaoke-style while playing;
plus has a very simple & handy lyrics synchronising interface (in
contrast to awkward WMP10 one)
So, the only thing I'm missing - binary attrs update (with simple ones, as
I've told, I had no problems).
That's why I'm here :)

Vincas


"smith" <rcsTA...@smithvoiceTAKEOUT.com> wrote in message

news:DDz8d.3343$UP1...@newsread1.news.pas.earthlink.net...

Alessandro Angeli [MVP::DigitalMedia]

unread,
Oct 5, 2004, 3:19:42 PM10/5/04
to
Vincas Stepankevicius wrote:

> If I got it right, I can use your spelled e-mail for
> sending such file. Correct me if I'm wrong.

Here is the sample code that dumps the synchronized lyrics:

---------------------------------------------
using System;
using System.IO;
using System.Runtime.InteropServices;
using WMFSDKWrapper;

public class slyr
{
public static void Main(string[] args)
{
try {
IWMMetadataEditor pEditor = null;

WMFSDKFunctions.WMCreateEditor(out pEditor);
pEditor.Open("x.wma");

IWMHeaderInfo3 pHeader = (IWMHeaderInfo3)pEditor;

ushort wStream = 0;
ushort wCount = 0;

pHeader.GetAttributeCountEx(wStream,out wCount);

for(ushort i = 0; i < wCount; i++) {
WMT_ATTR_DATATYPE dtType = 0;
ushort wLang = 0;
string szName = null;
byte[] pbData = null;
ushort wName = 0;
uint dwData = 0;

pHeader.GetAttributeByIndexEx(wStream,i,szName,ref
wName,out dtType,out wLang,pbData,ref dwData);
szName = new string('\0',wName-1);
pbData = new byte[dwData];
pHeader.GetAttributeByIndexEx(wStream,i,szName,ref
wName,out dtType,out wLang,pbData,ref dwData);

if(szName != "WM/Lyrics_Synchronised") continue;

MemoryStream pStream = new MemoryStream(pbData);
BinaryReader pReader = new BinaryReader(pStream);

uint ptr, end; string line; uint time;
Console.WriteLine(">>> bTimeStampFormat .... =
{0}",pReader.ReadByte());
Console.WriteLine(">>> bContentType ........ =
{0}",pReader.ReadByte());
Console.WriteLine(">>> pwszContentDescriptor =
L\"{0}\"",Marshal.PtrToStringUni(new
IntPtr(pReader.ReadUInt32())));
Console.WriteLine(">>> dwLyricsLen ......... = {0}",end
= pReader.ReadUInt32());
Console.WriteLine(">>> pbLyrics ............ =
${0:X8}",ptr = pReader.ReadUInt32());
for(end += ptr; ptr < end; ) {
line = Marshal.PtrToStringUni(new IntPtr(ptr)); ptr +=
(uint)(2*(1+line.Length));
time = (uint)Marshal.ReadInt32(new IntPtr(ptr)); ptr +=
4;
Console.WriteLine(">>>\t [{0:d}:{1:d2}:{2:d2}.{3:d3}]
L\"{4}\"",time/1000/60/60,(time/1000/60)%60,(time/1000)%60,t
ime%1000,line);
}
}
} catch(COMException ex) {
Console.WriteLine(ex.ToString());
}
}
}
---------------------------------------------

--

// Alessandro Angeli
// MVP :: Digital Media
// a dot angeli at psynet dot net


Vincas Stepankevicius

unread,
Oct 5, 2004, 3:30:50 PM10/5/04
to
I'm glad about my English and Alessandro - I consider you being indebted him
$10 ;-)

Vincas
"Neil Smith [MVP Digital Media]" <ne...@nospam.com> wrote in message
news:cmd5m0hm53phv4m35...@4ax.com...

Vincas Stepankevicius

unread,
Oct 5, 2004, 3:50:23 PM10/5/04
to
Thanx, Alessandro, I must rush now to study & test your sample (regrettably,
I need some time to convert it Into VB)
But now I see some "light in the end of tunnel" :)
I'll be back tomorow,

regards,
Vincas

"Alessandro Angeli [MVP::DigitalMedia]" <nob...@nowhere.in.the.net> wrote in

message news:u$$JOBxqE...@TK2MSFTNGP14.phx.gbl...

smith

unread,
Oct 5, 2004, 3:54:53 PM10/5/04
to
That's a nice looking app, Vincas.

I threw together a fast page so others can see what you're up to and maybe
get more help on this.

Here's your page:

http://www.smithvoice.com/vincas.htm

You'll have to let me know when you get a winner here, I don't have the
resources to make a redundant thread on my sitelett and keeping it to this
group will help far more people.


-robert smith
kirkland, wa


Alessandro Angeli [MVP::DigitalMedia]

unread,
Oct 5, 2004, 4:27:26 PM10/5/04
to
Vincas Stepankevicius wrote:

> Thanx, Alessandro, I must rush now to study & test your
> sample (regrettably, I need some time to convert it Into
> VB)
> But now I see some "light in the end of tunnel" :)
> I'll be back tomorow,

Unfortunately, I don't enough VB.NET to provide samples in
that language in a short time. Here you are a better sample
which also supports WM/Picture:

IWMHeaderInfo3 pHeader = (IWMHeaderInfo3)pEditor;

pHeader.GetAttributeCountEx(wStream,out wCount);

Console.WriteLine(">>> \"{0}\"",szName);

MemoryStream pStream = new MemoryStream(pbData);
BinaryReader pReader = new BinaryReader(pStream);
uint ptr, end;

if(szName == "WM/Lyrics_Synchronised") {
Console.WriteLine(">>>\t bTimeStampFormat .... =
{0}",pReader.ReadByte());
Console.WriteLine(">>>\t bContentType ........ =
{0}",pReader.ReadByte());
Console.WriteLine(">>>\t pwszContentDescriptor =
L\"{0}\"",Marshal.PtrToStringUni(new
IntPtr(pReader.ReadUInt32())));
Console.WriteLine(">>>\t dwLyricsLen ......... =
{0}",end = pReader.ReadUInt32());
Console.WriteLine(">>>\t pbLyrics ............ =


${0:X8}",ptr = pReader.ReadUInt32());

for(end += ptr; ptr < end; ) {

string line; uint time;


line = Marshal.PtrToStringUni(new IntPtr(ptr)); ptr +=
(uint)(2*(1+line.Length));
time = (uint)Marshal.ReadInt32(new IntPtr(ptr)); ptr
+= 4;

Console.WriteLine(">>>\t\t


[{0:d}:{1:d2}:{2:d2}.{3:d3}]
L\"{4}\"",time/1000/60/60,(time/1000/60)%60,(time/1000)%60,t
ime%1000,line);
}

} else if(szName == "WM/Picture") {
Console.WriteLine(">>>\t pwszMIMEType .. =
{0}",Marshal.PtrToStringUni(new
IntPtr(pReader.ReadUInt32())));
Console.WriteLine(">>>\t bPictureType .. =
{0}",pReader.ReadByte());
Console.WriteLine(">>>\t pwszDescription =
L\"{0}\"",Marshal.PtrToStringUni(new
IntPtr(pReader.ReadUInt32())));
Console.WriteLine(">>>\t dwDataLen ..... = {0}",end =
pReader.ReadUInt32());
Console.WriteLine(">>>\t pbData ........ = ${0:X8}",ptr
= pReader.ReadUInt32());

FileStream pFile = new
FileStream("picture"+i+".img",FileMode.OpenOrCreate,FileAcce
ss.Write);
IntPtr bas = new IntPtr(ptr);
for(int off = 0; off < end; off++)
pFile.WriteByte(Marshal.ReadByte(bas,off));
}
}
} catch(COMException ex) {
Console.WriteLine(ex.ToString());

Neil Smith [MVP Digital Media]

unread,
Oct 5, 2004, 4:50:44 PM10/5/04
to
On Tue, 5 Oct 2004 22:30:50 +0300, "Vincas Stepankevicius"
<vstepan...@vilnius.vmi.lt> wrote:

>I'm glad about my English and Alessandro - I consider you being indebted him
>$10 ;-)

Damn !

>Vincas

Oh, yeah I see what you;re doing from the screenshots now. I had some
similar problems to do an 'Export to Excel' (which was only partly
tested) but I did it in javascript. It mostly falls down on the XML
processing, and really needs to go client side :

http://www.windowsmediatv.com/wmprocessor/medialibrarytoexcel.html

The problem is, AFAIK the Excel ("Office Web Components") you can put
into a web page, don't read *native* OfficeXML format files :-P

Anyway - cheers & good luck with this.

========================================================
CaptionKit http://www.captionkit.com : Produce subtitled
internet media, transcripts and searchable video. Supports
Real Player, Quicktime and Windows Media Player.

VideoChat with friends online, get Freshly Toasted every
day at http://www.fresh-toast.net : NetMeeting solutions
for a connected world.

Alessandro Angeli [MVP::DigitalMedia]

unread,
Oct 5, 2004, 5:32:26 PM10/5/04
to
Vincas Stepankevicius wrote:

> (regrettably, I need some time to convert it Into VB)

Well, I couldn't sleep, so here you are the VB.NET version:


----------vb.bat------------
csc /debug+ /target:module WMFSDKFunctions.cs
vbc /debug+ /addmodule:WMFSDKFunctions.netmodule *.vb
----------------------------
----------slyr.vb-----------
IMPORTS System
IMPORTS System.IO
IMPORTS System.Runtime.InteropServices
IMPORTS WMFSDKWrapper

PUBLIC MODULE slyr
SUB Main()
TRY
DIM pEditor AS IWMMetadataEditor

WMFSDKFunctions.WMCreateEditor(pEditor)
pEditor.Open("x.wma")

DIM pHeader AS IWMHeaderInfo3 = pEditor

DIM wStream AS UInt16
DIM wCount AS UInt16

pHeader.GetAttributeCountEx(wStream,wCount)

FOR i AS Integer = 0 TO Convert.ToInt32(wCount)-1
DIM dtType AS WMT_ATTR_DATATYPE
DIM wLang AS UInt16
DIM szName AS String = Nothing
DIM pbData() AS Byte = Nothing
DIM wName AS UInt16
DIM dwData AS UInt32


pHeader.GetAttributeByIndexEx(wStream,Convert.ToUInt16(i),sz
Name,wName,dtType,wLang,pbData,dwData)
szName = NEW String("0",Convert.ToInt32(wName)-1)
REDIM pbData(Convert.ToInt32(dwData))

pHeader.GetAttributeByIndexEx(wStream,Convert.ToUInt16(i),sz
Name,wName,dtType,wLang,pbData,dwData)

Console.WriteLine(">>> ""{0}""",szName)

DIM pStream AS MemoryStream = NEW MemoryStream(pbData)
DIM pReader AS BinaryReader = NEW BinaryReader(pStream)
DIM _ptr, _end AS Integer

IF szName = "WM/Lyrics_Synchronised" THEN


Console.WriteLine(">>> bTimeStampFormat .... =
{0}",pReader.ReadByte())
Console.WriteLine(">>> bContentType ........ =
{0}",pReader.ReadByte())
Console.WriteLine(">>> pwszContentDescriptor =

L""{0}""",Marshal.PtrToStringUni(NEW
IntPtr(pReader.ReadInt32())))
_end = pReader.ReadInt32()
Console.WriteLine(">>> dwLyricsLen ......... =
{0}",_end)
_ptr = pReader.ReadInt32()
Console.WriteLine(">>> pbLyrics ............ =
${0:X8}",_ptr)

_end = _end + _ptr
WHILE _ptr < _end
DIM line AS String
DIM time As Integer

line = Marshal.PtrToStringUni(NEW IntPtr(_ptr))
_ptr = _ptr + 2 * (1 + line.Length)
time = Marshal.ReadInt32(NEW IntPtr(_ptr))
_ptr = _ptr + 4
Console.WriteLine(">>>


[{0:d}:{1:d2}:{2:d2}.{3:d3}]

L""{4}""",time\1000\60\60,(time\1000\60) mod 60,(time\1000)
mod 60,time mod 1000,line)
END WHILE
ELSE IF szName = "WM/Picture" THEN
Console.WriteLine(">>> pwszMIMEType .. =
{0}",Marshal.PtrToStringUni(NEW
IntPtr(pReader.ReadInt32())))
Console.WriteLine(">>> bPictureType .. =
{0}",pReader.ReadByte())
Console.WriteLine(">>> pwszDescription =
L""{0}""",Marshal.PtrToStringUni(NEW
IntPtr(pReader.ReadInt32())))
_end = pReader.ReadInt32()
Console.WriteLine(">>> dwDataLen ..... = {0}",_end)
_ptr = pReader.ReadInt32()
Console.WriteLine(">>> pbData ........ =
${0:X8}",_ptr)

DIM pFile AS FileStream = NEW FileStream("picture" & i
& ".jpg",FileMode.OpenOrCreate,FileAccess.Write)
DIM bas AS IntPtr = NEW IntPtr(_ptr)
FOR off AS Integer = 0 TO _end-1
pFile.WriteByte(Marshal.ReadByte(bas,off))
NEXT off
END IF
NEXT i
CATCH ex AS COMException
Console.WriteLine(ex.ToString())
END TRY
END SUB
END MODULE

Vincas Stepankevicius

unread,
Oct 5, 2004, 6:27:59 PM10/5/04
to
Yep!
Great job, Alessandro!
Now it's too late(1:30) to check your code but it seems for me that you
have allredy $20 from two Smith's - 10 from Robert + 10 from Neil ;)
Forgive me, that I cant propose you nothing else but my respect and
gratitude :)
I see now how my problems can be solved but I'd appreciate if you find time
to make an experiment with updating attrs ;)

My best regards,
Vincas


"Alessandro Angeli [MVP::DigitalMedia]" <nob...@nowhere.in.the.net> wrote in

message news:OSqWTLyq...@TK2MSFTNGP11.phx.gbl...

smith

unread,
Oct 5, 2004, 6:43:55 PM10/5/04
to
So that's the winner? You sure? You positive that's what you want? That
VB.Net code works? :)

I'll need to be emailed by Alessandro, then.

*Great* job everyone!. And a bit of fun, too.

Robert Smith
Kirkland, WA
http://www.smithvoice.com

"Vincas Stepankevicius" <vstepan...@vilnius.vmi.lt> wrote in message

news:%238U9Uqy...@TK2MSFTNGP15.phx.gbl...

Vincas Stepankevicius

unread,
Oct 5, 2004, 7:00:55 PM10/5/04
to
Yes, R, code is working, I tested it - and Alessandro is *shoo-in*!
Updating I hope should not be a big problem after that...

Thank all you ever so much for help & fun, and good night (oh my God -
2:00!)
Vincas

"smith" <rcsTA...@smithvoiceTAKEOUT.com> wrote in message

news:LsF8d.3738$M05....@newsread3.news.pas.earthlink.net...

Alessandro Angeli [MVP::DigitalMedia]

unread,
Oct 6, 2004, 5:24:24 AM10/6/04
to
"Vincas Stepankevicius" <vstepan...@vilnius.vmi.lt> wrote:

> Updating I hope should not be a big problem after that...

A sample about updating will have to wait until this evening, since I'm
quite busy at work today.

Vincas Stepankevicius

unread,
Oct 6, 2004, 6:15:10 AM10/6/04
to
Thanks in advance, Alessandro, I'll be eager waiting for evening :)
Meanwhile I'm remastering my app applying new knowledge I've bought from you
for Robert's money ;)

Vincas


smith

unread,
Oct 6, 2004, 12:18:14 PM10/6/04
to
I'm sure he did it just to be helpful, but when he contacts me he'll get the
token ;)

I'll be waiting, but back to work today.

-s


"Vincas Stepankevicius" <vstepan...@vilnius.vmi.lt> wrote in message

news:%23yYhh14...@TK2MSFTNGP09.phx.gbl...

Alessandro Angeli [MVP::DigitalMedia]

unread,
Oct 6, 2004, 2:20:11 PM10/6/04
to
Vincas Stepankevicius wrote:

Added the code to add a new WM/Lyrics_Synchronised
attribute. There are more effient ways to do this: remember
you can copy whole array back and forth from managed arrays
and unmanaged memory buffers using the Marshal.Copy() family
of methods.

------------------------------------------

WMFSDKFunctions.WMCreateEditor(pEditor)
pEditor.Open("x.wma")

pHeader.GetAttributeCountEx(wStream,wCount)

pHeader.GetAttributeByIndexEx(wStream,Convert.ToUInt16(i),sz
Name,wName,dtType,wLang,pbData,dwData)

Console.WriteLine(">>> ""{0}""",szName)

DIM pLines() AS String = { "First Line", "Second Line" }
DIM pTimes() AS Integer = { 1500, 5230 }

DIM sz AS IntPtr = Marshal.StringToCoTaskMemUni("Some
string without meaning")

DIM cb AS Integer = 0
FOR i AS Integer = 0 TO pLines.Length-1
cb = cb + 4 + 2 * (1 + pLines(i).Length)
NEXT i
DIM pb AS IntPtr = Marshal.AllocCoTaskMem(cb)
DIM p AS Integer = 0
FOR i AS Integer = 0 TO pLines.Length-1
FOR k AS Integer = 0 TO pLines(i).Length-1

Marshal.WriteInt16(pb,p,Convert.ToInt16(pLines(i).Chars(k)))
p = p + 2
NEXT k
Marshal.WriteInt16(pb,p,Convert.ToInt16(0))
p = p + 2
Marshal.WriteInt32(pb,p,pTimes(i))
p = p + 4
NEXT i

DIM wIndex AS UInt16
DIM pData(14) AS Byte

DIM pBuffer AS MemoryStream = NEW MemoryStream(pData)
DIM pWriter AS BinaryWriter = NEW BinaryWriter(pBuffer)

pWriter.Write(Convert.ToByte(2))
pWriter.Write(Convert.ToByte(1))
pWriter.Write(sz.ToInt32())
pWriter.Write(Convert.ToUInt32(cb))
pWriter.Write(pb.ToInt32())


pHeader.AddAttribute(wStream,"WM/Lyrics_Synchronised",wIndex
,WMT_ATTR_DATATYPE.WMT_TYPE_BINARY,Convert.ToUInt16(0),pData
,Convert.ToUInt32(pData.Length))

pEditor.Flush()

Marshal.FreeCoTaskMem(pb)
Marshal.FreeCoTaskMem(sz)


CATCH ex AS COMException
Console.WriteLine(ex.ToString())
END TRY
END SUB
END MODULE

------------------------------------------

Alessandro Angeli [MVP::DigitalMedia]

unread,
Oct 6, 2004, 2:21:08 PM10/6/04
to
smith wrote:

> I'm sure he did it just to be helpful, but when he
> contacts me he'll get the token ;)

Why don't you donate the $10 to support UNICEF?

http://www.unicef.org/support/

Neil will buy me a beer next time I'm in Bristol instead :-)

Vincas Stepankevicius

unread,
Oct 6, 2004, 3:30:13 PM10/6/04
to

"Alessandro Angeli [MVP::DigitalMedia]" <nob...@nowhere.in.the.net> wrote in
message news:%23eEQDF9...@tk2msftngp13.phx.gbl...
> smith wrote:
...

> Neil will buy me a beer next time I'm in Bristol instead :-)
>
Good Lithuanian beer is waiting for you in Vilnius too :)
-Vincas

Vincas Stepankevicius

unread,
Oct 6, 2004, 5:47:43 PM10/6/04
to

"Alessandro Angeli [MVP::DigitalMedia]" <nob...@nowhere.in.the.net> wrote in
message news:%233QvCF9...@tk2msftngp13.phx.gbl...
...

> Added the code to add a new WM/Lyrics_Synchronised
> attribute. There are more effient ways to do this: remember
> you can copy whole array back and forth from managed arrays
> and unmanaged memory buffers using the Marshal.Copy() family
> of methods.

Great! I tested your sample - it works like a sharm (despite some minor, mp3
tagging rules related details wich are out of scope of our discussion).
The main thing is that thanks to your help WM attr updating is no longer any
problem for me (and I hope- not only for me).

Once more many thanks for your attitude, knowledge and wasted time,
-your debtor - Vincas


Alessandro Angeli [MVP::DigitalMedia]

unread,
Oct 6, 2004, 6:18:24 PM10/6/04
to
Vincas Stepankevicius wrote:

> Once more many thanks for your attitude, knowledge and
> wasted time, -your debtor - Vincas

You're welcome. I learned a few things myself in the
meantime (how to code using VB.NET for example, which I
never used before and I hope to never use again :-)).

smith

unread,
Oct 6, 2004, 6:40:52 PM10/6/04
to
You're a saint, but let's just wrap this by the friendly rules, OK?. You
can donate it to whatever you want but don't make me feel bad, Alessandro,
send me an email :)

-smith


"Alessandro Angeli [MVP::DigitalMedia]" <nob...@nowhere.in.the.net> wrote in

message news:%23eEQDF9...@tk2msftngp13.phx.gbl...

Neil Smith [MVP Digital Media]

unread,
Oct 7, 2004, 7:26:35 PM10/7/04
to
On Wed, 6 Oct 2004 20:21:08 +0200, "Alessandro Angeli
[MVP::DigitalMedia]" <nob...@nowhere.in.the.net> wrote:

>smith wrote:
>
>> I'm sure he did it just to be helpful, but when he
>> contacts me he'll get the token ;)
>
>Why don't you donate the $10 to support UNICEF?
>
>http://www.unicef.org/support/
>
>Neil will buy me a beer next time I'm in Bristol instead :-)

** He has a point - either there or at the next MVP summit hehe

smith

unread,
Oct 8, 2004, 12:56:25 PM10/8/04
to
to bed the contest: Alessandro has accepted the token prize so he can
afford your second round ... if it's Old Milwaukee, that is :)

"Neil Smith [MVP Digital Media]" <ne...@nospam.com> wrote in message

news:72lbm0pv9utsjp9k0...@4ax.com...


> On Wed, 6 Oct 2004 20:21:08 +0200, "Alessandro Angeli
> [MVP::DigitalMedia]" <nob...@nowhere.in.the.net> wrote:

>snipp<

0 new messages