Include file for native Directshow support in PB4

Developed or developing a new product in PureBasic? Tell the world about it.
Jan Vooijs
Enthusiast
Enthusiast
Posts: 196
Joined: Tue Sep 30, 2003 4:32 pm
Location: The Netherlands

Post by Jan Vooijs »

Inc,

Again, Traumatics routine is not at risk sofar unless you count in that it is declarering 4 times the size of the memory needed!

A normal string is 1 byte per character. And Unicode is 2 bytes per char. So converting from string to unicode is TWICE the length of string PLUS the zero byte(s) at the end of the UNICODE string.

Code: Select all

Procedure.l L(string.s)
  *out = AllocateMemory(Len(string)*2 * #SIZEOF_WORD)
  MultiByteToWideChar_(#CP_ACP, 0, string, -1, *out, Len(string)) 
  ProcedureReturn *out 
EndProcedure 
See ? "Len(string)*2 * #SIZEOF_WORD" so length of string TIMES 2 and then times size of a word but since WORD is 2 bytes there is a 4 times longer than needed string. This was all that is needed "Len(string) * #SIZEOF_WORD + 2" and the 2 bytes are for the zero to denotes the end of the UNICODE string.

Oke sofar things are clear. But in your latest version you make *out protected (local) which is fine, than allocate memory ON the heap (fine). But at the end of the proc L() the return is the adress of the memory area ON the heap. By using that it is distroyed leaving that region of memory still on the HEAP! But nobody (i think even PB itself) is NOT nowing where it is it leaves unused memory. Do this more than once and you have a problem, you run out of memory and your program grows and grows in memory size. Unless you end your program than PB (as I understand) frees the memory!! Not before. In desiging a program that is 'always' on (like a media center) you get a memory problem in the long run.

So your code is valid as Traumatics and my code is (more) valid. Both are right, but the usage is the difference. Yours (in the example) is short run, only 1 film and exit. Mine is for 24h on (and longer) and noumerous films tv programs DVD perhaps. See it will build up.

Hope this is clear. And thanks for looking in the IEnumfilter issue.

Jan V.
Life goes to Fast, Enjoy!!

PB 4 is to good to be true, wake up man it is NOT a dream THIS is a reality!!!

AMD Athlon on 1.75G, 1Gb ram, 160Gb HD, NVidia FX5200, NEC ND-3500AG DVD+RW and CD+RW, in a Qbic EO3702A and Win XP Pro SP2 (registered)
inc.
Enthusiast
Enthusiast
Posts: 406
Joined: Thu May 06, 2004 4:28 pm
Location: Cologne/GER

Post by inc. »

You're right that if playing 20 Files where each file will have a lenght of its name of about 64 chars this would end up in senseless memory on the heap of about 19files*(64ytes*2UnicodeCharLenght) = 2432bytes = 2,432Kb (approx.!)

So I did catch your point that it's the way to avoid such senseless Heap occupation of 2,432Kb in case of 19 used files. of Ok so far. Right?
Do this more than once and you have a problem, you run out of memory and your program grows and grows in memory size. Unless you end your program than PB (as I understand) frees the memory!!
Please clearify: Do you mean a bug in PB according the heap? Cause if not ... I cant reproduce (according to your statement "Do this more than once") that an application could run out of memory if for instance 2,432Kb are unused stored on the heap? Or did I miss something?

I do assume that Traumatic maybe also did not bother about such a small amount of unused but allocated Kb's (just imho).

So how many files including very big filename string lenghts are you about to load? Cause if beeing exact my HTPC for example will be switched off after watching/listening Media for several hours or if a timer based recording has been finished.

Dont get me wrong I see your "declare as global" way as 100% correct but with the little risk that maybe these defined globals could be also used by the user using the same name without beeing aware of it in his further code where the include has been loaded into. Thats why I tried to avoid any globals in an include file I do provide official. ;)

So the quintessence was/is that someone has to choose between the compromise of some KBs unused on the heap ... and the risk of declaring pointers as globals where you dont know what pointer names the user will use in his later code.
In C/C++ where codeparts can be compiled & linked as .obj's to libs/dlls/exes where such Global pointers wont mix up things by using auto or static in the obj's ... there this wont be such an issue unless you force to access the value in the other obj. by using "extern".
AFAIK PB generates "one" asm file out of the whole user code where this resulting single obj. containing everything of the user code will be linked with the needed libraries.
.... just imho based on my actual programming knowlege


PS: All this could be avoided by including the WideChar data into the Directshow_Media Structure below, where the L() function comes with an added argument of a pointer to the Structure where that unicode string will be stored and finally also be deleted when freeing the memory within the FreeMedia() Command.

Code: Select all

#MaxWcFilenameLenght = 512 ; 512 chars should be enough for a wc filename?

Structure Dshow_Interfaces
  pGraphBuilder.IGraphBuilder
  pControl.IMediaControl
  pEvent.IMediaEventEx
  pWindow.IVideoWindow
  pAudio.IBasicAudio
  pVideo.IBasicVideo2
  pSeeking.IMediaSeeking
  WideCharFileName.w[#MaxWcFilenameLenght] 
EndStructure

..
..
..

Procedure InitMedia()
  Protected a, b, c, d, e, f
  *p.Dshow_Interfaces = AllocateMemory(SizeOf(Dshow_Interfaces))
  ...
  ... 
  ...
  ProcedureReturn *p
  ...
  ...
  ...
EndProcedure

...
...
...

Procedure.l L(*p.Dshow_Interfaces, string.s) ; Ansi->Unicode
  If string and p
    PokeS(@*p\WideCharFileName[0], string, Len(string), #PB_Unicode)
  Endif 
EndProcedure 

...
..
...

Procedure FreeMedia(*p.Dshow_Interfaces)
  Protected pfs.l
  If *p
    *p\pControl\GetState(10,@pfs)
    If Not pfs = #State_Stopped
      *p\pControl\stop()
    EndIf
    *p\pSeeking\Release()
    *p\pVideo\Release()
    *p\pAudio\Release()
    *p\pWindow\Release()
    *p\pEvent\Release()
    *p\pControl\Release()
    *p\pGraphBuilder\Release()
    FreeMemory(*p)
    CoUninitialize_()
    ProcedureReturn = #True
  Else
    ProcedureReturn = #False
  EndIf 
EndProcedure
Like this? (just written straight out of head far away from my Windows pc as Im at work using a MAC ;) )
Check out OOP support for PB here!
Jan Vooijs
Enthusiast
Enthusiast
Posts: 196
Joined: Tue Sep 30, 2003 4:32 pm
Location: The Netherlands

Post by Jan Vooijs »

Inc,

Programming is always a way of doing more. Like i said on a topic before you can program at N ways. Meaning that you can do it on version A till ZZplus and arrive at the same end result.

Like i said BOTH ways are fine. If you have an application which runs a fixed time than keeping *out INSIDE a proc no problem, even better. You wrote that your htpc would be on for (only) a few hours. Mine is on 24/7 i use a DVB-s with decoder (movie channel) a need the activation puls which arives once in 24h but one never knows when in that period. So not on, no picture (in 24h the most).

I have to write for robust code, there for use EnableExplicit (i'am forced to). I write the program so I have control of the code.
So the quintessence was/is that someone has to choose between the compromise of some KBs unused on the heap ... and the risk of declaring pointers as globals where you dont know what pointer names the user will use in his later code.
Exactly true for both our views!! But you can minimize by declaring your variables with a prefix like in this case DS_ (in lowercase) so *out becomes *ds_out, and every variable alike. Advertise that and every user is happy. And since the code is open everybody can look at it, and see how it is done.

Oh one thing I made a bummer with "IEnumFilters" they are there i did not read the message from the compiler in all (oops) it was just complaining that pEnum was not global or not on a protected, so SORRY for that on. You code is running fine now!! (with my mods).
And yes I have put *p global and modified the code for it (just a few "SHARED" here and there.

I would like to help expanding your include file, as i discover more and more.

I need to put TV in at first, after some experimenting on playback. Have to find a way to know how to modify the output for 16:9 viewing since it is now displaying 16:9 as 4:3 (with black bars on top and bottom).

Showing a 16:9 recording in 12% proccessor time NOT bad since PowerDvd is doing it in 20% on the same computer and the same file. Wink wink, PowerDvd is 30+Gb and yours is about what!! 27K yes K not Gb ouch how about bloatware!! :) ;)


Thanks anyway.

Jan V.

(edit a few typos)
Life goes to Fast, Enjoy!!

PB 4 is to good to be true, wake up man it is NOT a dream THIS is a reality!!!

AMD Athlon on 1.75G, 1Gb ram, 160Gb HD, NVidia FX5200, NEC ND-3500AG DVD+RW and CD+RW, in a Qbic EO3702A and Win XP Pro SP2 (registered)
inc.
Enthusiast
Enthusiast
Posts: 406
Joined: Thu May 06, 2004 4:28 pm
Location: Cologne/GER

Post by inc. »

I just updatet the pbi and the example pb files. Now its v1.1

See changes & link in the first post.

So Jan, no more little growing memory when re-loading files by still not needing Global pointers. ;)
Last edited by inc. on Wed Jul 26, 2006 12:11 am, edited 1 time in total.
Check out OOP support for PB here!
inc.
Enthusiast
Enthusiast
Posts: 406
Joined: Thu May 06, 2004 4:28 pm
Location: Cologne/GER

Post by inc. »

I need to put TV in at first, after some experimenting on playback. Have to find a way to know how to modify the output for 16:9 viewing since it is now displaying 16:9 as 4:3 (with black bars on top and bottom).
Yup, thats what I meant when mentioning "proper aspect ratio".
On 2.35:1 Widescreen movies the (small) black borders are still there, but the decoder forces the output to be de-anamorphed by using a width stretching factor of 1/0.75 (means 1.333p) PLUS a stretching of the width using the ITU norm factor from square to quadra pixels. In PAL this is 128/117 (768/702). Almost all Software MediaPlayers do scale DVD and mpeg2 mostly wrong if the source is 720px wide. Why? Because they do simply parse the mpeg2 header on the AspectRatio value which is 4:3 or 16:9. So a 16:9 movie generally is shown at 1024x576 and a 4:3 one generally at 768x576 (both PAL examples).

But ITU says 128/117 at 720x576 (or 704x576) at PAL! As the full active square pixels area which keeps the actual 768px quadra content IS 702px.

So a 16:9 720x576 DVD has to be played back at 720*((128/117)/0.75) = approx. 1050px x 576px instead of 1024px x 576px. See the error? ;)
Showing a 16:9 recording in 12% proccessor time NOT bad since PowerDvd is doing it in 20% on the same computer and the same file. Wink wink, PowerDvd is 30+Gb and yours is about what!! 27K yes K not Gb ouch how about bloatware!!
Well it depends on the PowerDVDs internal routines or if it even uses own individual DS-filters. WinDVD for example is capable to enhance audio+video while playback, I dunno what PowerDVD is able to do or even forcing when doing the playback.

If running DVB etc. you should have a look at DVBviewer as its very nice and handy.
For simple Mediaplayback you should checkout MediaPlayerClassic as its an opensource all-in-one player incl. integrated splitters/decoders etc.
Also VideoLan is the favorite Player if you dont want to bother the user by focing them to install codec(pack)s for playing back a wide range of audio/video formats. And that one contains the ffmpeg library libavcodec.
Im looking in the PB forums for members with deeper C skills than me for helping me making libavcodec supported directly by PB. With that all codec/format dependencies or system dependencies are gone (can be used on Win/Linux/OSx platforms)
Check out OOP support for PB here!
Jan Vooijs
Enthusiast
Enthusiast
Posts: 196
Joined: Tue Sep 30, 2003 4:32 pm
Location: The Netherlands

Post by Jan Vooijs »

Inc,

I found (one of) the aspect ratios's as it is called:

Code: Select all


Procedure.s MediaAspect(*p.Dshow_Interfaces)
Protected aspX.l, aspY, Answ.s

	If *p
		*p\pVideo\GetPreferredAspectRatio( @aspX, @aspY)
		Answ.s = Str( aspX) + ":" + Str( aspY)
	EndIf 

	ProcedureReturn Answ.s	
EndProcedure

One other thing would it not be more logical to keepthe naming of your proc more consistent? Like you have:

Procedure PlayMedia(*p.Dshow_Interfaces)
Procedure PauseMedia(*p.Dshow_Interfaces)
Procedure MediaSeek(*p.Dshow_Interfaces, pos.q)
Procedure MediaStop(*p.Dshow_Interfaces)

Why not:
Procedure PlayMedia(*p.Dshow_Interfaces)
Procedure PauseMedia(*p.Dshow_Interfaces)
Procedure SeekMedia(*p.Dshow_Interfaces, pos.q)
Procedure StopMedia(*p.Dshow_Interfaces)

more consistent (i have don't in my copy already) and the commando playing are 'command name'Media() and the function where we get information are called Media'function name'()

like: MediaHeight() ; gives info
like: StopMedia() ; playing command

Jan V.
Life goes to Fast, Enjoy!!

PB 4 is to good to be true, wake up man it is NOT a dream THIS is a reality!!!

AMD Athlon on 1.75G, 1Gb ram, 160Gb HD, NVidia FX5200, NEC ND-3500AG DVD+RW and CD+RW, in a Qbic EO3702A and Win XP Pro SP2 (registered)
Fred
Administrator
Administrator
Posts: 18153
Joined: Fri May 17, 2002 4:39 pm
Location: France
Contact:

Post by Fred »

Why not use the p-unicode pseudotype ?
inc.
Enthusiast
Enthusiast
Posts: 406
Joined: Thu May 06, 2004 4:28 pm
Location: Cologne/GER

Post by inc. »

Jan Vooijs wrote:*p\pVideo\GetPreferredAspectRatio( @aspX, @aspY)
Yep, I already tried that one but it gives everytime just the aspect of the native video size. Like in case of a 720x576 source just 720, 576.
Maybe its the combination between that command and some renderer properties ...

EDIT: I figued out when using FFshow as Decoder in the system, the AR wont be served properly unless you are using VMR9. I did tests using ffdshow decoding mpeg2 and XVID/mpeg4 media video contents.

I switched FFdshow for mpeg2 and XVID FourCCs dcoding off, so in case of mpeg2 the "DVDExpress Videodecoder" did the mpeg2 decoding job. Here the providing of the proper AR worked well BUT the fps isnt provided at all .. hmmm. Same in case of mpeg4 when XVID decoder then does the decoding. ....... Trrrrricky
One other thing would it not be more logical to keepthe naming of your proc more consistent?
Ill think about it. Aren't PBs Movie commands also mixed in thier naming logics?
But when thinking about it a clearer logic makes sense, yes.
Im even thinking about including an object based approach also:

*Movie =MediaLoad("X:/MyMediaFile.xyz", a, b, c)
*Movie\play()
*Movie\Stop()
..
..


Fred wrote:Why not use the p-unicode pseudotype ?
I tried that, but I get the error mess "Structure p-unicode not" found or so similiar.

Could you give me an example? As Im still not that in PBs unicode stuff :)
Check out OOP support for PB here!
T-Light
User
User
Posts: 45
Joined: Sat Aug 05, 2006 5:42 pm
Location: UK

Post by T-Light »

Anyone tried playing back DV AVI files with this include?, I'm currently getting 360x288 rather than 720x576.

Seem to remember Windows Media Player used to do this some time ago. Essentially, I'd like to create an DV video enhancement routine, but with the current system not passing the full DV resolution through to the program I'll have to revert to using still image sequences input from another package (DFX etc).

Is there a way around this?

ps Nice one inc, great bit of coding 8)
T-Light
User
User
Posts: 45
Joined: Sat Aug 05, 2006 5:42 pm
Location: UK

Post by T-Light »

Found a quick workaround to the DV AVI problem.

Just re-encoded the DV AVI footage using the (FREE) Matrox DVCPRO codec. No quality loss from the original file and can be played perfectly well with inc's include :)
inc.
Enthusiast
Enthusiast
Posts: 406
Joined: Thu May 06, 2004 4:28 pm
Location: Cologne/GER

Post by inc. »

Those problems mostly do depend on the installed specific directshow decoder for decoding the format xyz.

As also reported above. I did implement a routine (I can post if needed) to properly show the video including the correct aspect ratio. This is useful when decoding mpeg2s or mpeg4s where the videos aren't encoded using quadra pixels.
But also here, some dshow decoders do correctly provide the AR flag and others not, so its a thing of luck.
Check out OOP support for PB here!
T-Light
User
User
Posts: 45
Joined: Sat Aug 05, 2006 5:42 pm
Location: UK

Post by T-Light »

Inc-
As also reported above. I did implement a routine (I can post if needed) to properly show the video including the correct aspect ratio.
Oh yes :D
Not sure how usefull this would be with my current routine (It requires 1 to 1 pixels in the image data or I'll loose quality, but I've plans for writing a number of utilities where this would be exceptional.

Thanks again for some genuinely usefull routines.
User avatar
netmaestro
PureBasic Bullfrog
PureBasic Bullfrog
Posts: 8451
Joined: Wed Jul 06, 2005 5:42 am
Location: Fort Nelson, BC, Canada

Post by netmaestro »

I've made a small modification to the version of this .pbi I'm using, it's quite simple but it allows resizing of the video:

Code: Select all

Procedure ResizeVideo(*p.Dshow_Interfaces, new_w, new_h)
  If *p
    *p\pWindow\put_Width(new_w)
    *p\pWindow\put_Height(new_h)
  EndIf
EndProcedure
And a resizable version of the test program: (SmartWindowRefresh really helps!)

Code: Select all

IncludeFile "directshowmedia.pbi"
; Mini example v1.1 for DshowMedia.pbi for Purebasic v4, 2006 by Inc.

CompilerIf #PB_Compiler_Debugger = #False
  MessageRequester("Info","Please run this example using the debugger and see its output while choosing a media file")
  End
CompilerEndIf

hwnd = OpenWindow(0,20,20,352,288,"PB native Dshow example", $CF0001)   
SmartWindowRefresh(0, 1)  ; <---- This line added for Resizing
hMedia = InitMedia()

If hMedia
  File.s = OpenFileRequester("Choose media file","","All Files (*.*)|*.*",0)
  If File
    If LoadMedia(hMedia, File, hwnd, #VMR7_Windowed, #WaveOutRenderer)
      mWidth = MediaWidth(hMedia) : mHeight = MediaHeight(hMedia)
      If mWidth = 0 : mWidth = #PB_Ignore :EndIf
      If mHeight = 0 : mHeight = #PB_Ignore :EndIf
      ResizeWindow(0, #PB_Ignore, #PB_Ignore, mWidth, mHeight)
      PlayMedia(hMedia)
      Debug "lenght = "+MediaTime2String(MediaLenght(hMedia))+" (hh:mm:ss:ms)"
      fps.f = MediaFPS(hMedia)
      If fps ; Does media contain Videodata?
        Debug "FPS    = "+StrF(fps,3)
        Debug "Width  = "+Str(MediaWidth(hMedia))
        Debug "Height = "+Str(MediaHeight(hMedia))
      EndIf 
      Debug "playing ..."
      Debug " "
      Debug "esc = exit"
      Debug "c = capture current image to C:/"
      Debug "left/right keys = step forward/backward in 5% steps"
      Debug "up/down keys = alter volume in 2db steps"
      Debug " "
      
      Repeat
        Delay(5)
        ;Debug MediaTime2String(MediaPosition(hMedia)) ;- #### Uncomment this for watching continous counter ###
        ev = WindowEvent()
        If ev = #WM_KEYDOWN
          wParam = EventwParam()
          If wParam = #VK_ESCAPE
            MediaPutVolume(hMedia,0)
            FreeMedia(hMedia)
            End
          ElseIf wParam = #VK_C
            If CaptureCurrMediaImage(hMedia, 99)
              SaveImage(99, "G:/MyImage"+Str(im)+".bmp",#PB_ImagePlugin_BMP)
              FreeImage(99)
              im+1
              Debug "Image "+Str(im)+" safed to C:/"
            EndIf 
          ElseIf wParam = #VK_LEFT
            MediaSeek(hMedia, MediaPosition(hMedia)-Int(MediaLenght(hMedia)/20)) ; 5% steps
          ElseIf wParam = #VK_RIGHT
            MediaSeek(hMedia, MediaPosition(hMedia)+Int(MediaLenght(hMedia)/20)) ; 5% steps 
          ElseIf wParam =#VK_UP
            MediaPutVolume(hMedia, MediaGetVolume(hMedia)+2)
          ElseIf wParam = #VK_DOWN
            MediaPutVolume(hMedia ,MediaGetVolume(hMedia)-2)
          EndIf
        ElseIf ev = #WM_GRAPHEVENT 
          OnMediaEvent(EventlParam())
        ElseIf ev = #WM_SIZE                                    ; <---- This line added for Resizing
          ResizeVideo(hMedia, WindowWidth(0), WindowHeight(0))  ; <---- This line added for Resizing
        EndIf
      Until ev = #PB_Event_CloseWindow  

      MediaPutVolume(hMedia,0) ; '0' means 0db = maxVolume --> this is necessary! Otherwise the system sound device will keep the vol state even when appl. has been closed.
      FreeMedia(hMedia)
      End
      
    EndIf
  Else
    FreeMedia(hMedia)
    End
  EndIf
EndIf
BERESHEIT
ricardo
Addict
Addict
Posts: 2438
Joined: Fri Apr 25, 2003 7:06 pm
Location: Argentina

Post by ricardo »

Any way to point to a buffer instead of a file using this method? or to access the buffer?
Niffo
Enthusiast
Enthusiast
Posts: 504
Joined: Tue Jan 31, 2006 9:43 am
Location: France

Post by Niffo »

Sadly, "FreeMedia" does not liberate the codecs ;( I am trying to make a multi video file player and - for example - the audio codec opens a new instance of itself each time (ffdshow in the systray)
Niffo
Post Reply