Log in

View Full Version : HTPC "smooth" playback ideas/solutions


hagayg
4th March 2008, 09:19
Anyone who ever built a htpc setup and hooked it trough D-SUB or DVI/HDMI knows of jerky playback issues.
I have been researching that area for about 3 months, found many scattered pieces of the puzzle till lately i fully understood the problem and kinda "solved" it from my point of view (i finally got the smooth playback i wanted).

I would like to share my finding and get comments since i didnt really find my solution just written on a single page.

For start i'll explain the problem as i understand it.

Human eyes needs a certain frame rate to translate a moving pictures as "smooth" , each one has its own limits , my eyes for example are very sensitive to frame rate varation, i can easily notice the difference between 50 fps to 60 fps (frame rate per second).
Now , our old television broadcast system (PAL/NTSC) indeed uses only 25/30 fps , but they are interlaced, so the effective unique picture per second is doubled (50/60 fps), the TV blends the picture by seperated them to fields.
This subject is well coverd so we can move on.
When we use progressive scan (not interlaced one) which means each frame is shown fully and get replaced fully with following frame, we get only effective fps of the original video, which means normally between 23.976-25 on DVD matirial.
Of course this frame rate is much lower than the TV one, this is mainly what causes the difference between our HTPC expierince to a TV one.
It is really noticed on non slow Pan shot , when whole scene is sliding, there are not enough FPS to smoothly describe the enviorment changes , so we notice jerky/jumpy movments.
Sensitive eyes (like mine) can see the diffenece even in slow pace scenes when only himan mouth and body parts are moving without background change.

Now for my findings.
Searching around the web for ideas to solve this was not simple.
There are even some pepole which claims the behaivor is normal and gives the video matirial cinema look (I for one, strongly disagree with this notion).
There are some places with example how to set you monitor refresh rate to the fps, which is basicly a correct step towards the goal, but even setting refresh rate to 47.952hz and still having 23.976 fps wont give you smooth playback, it will be smoother than with 60hz and same fps, but not smooth.
There are tools such as reclock which helps change the fps of the original video and match the refresh rate, but this tool is bit heavy for novice users and for me at least , didnt achieve nothing (except higher pitcher audio playback :) ).
Now , the two only tools that you gonna need are ffdshow & avisynth.

ffdshow was a big supprise for me,till about 6 month ago i tought its a simpe codec pack for "newbies" which cant install codecs like "pro" ones.
I was amazed how wrong i was, this tool is really great for pc playback nor htpc usage.
ffdshow tutorials are available, so this short description will suffice for now.
after installing avisynth and ffdshow, we need to make sure ffdshow is the active decoder of our avi/mkv files.
in ffdshow settings, we got avisynth tab/settings.
now , ffdshow allows you to set different profiles by certain resolution/fps/etc.
i made one for SD and one for HD.
for SD i wrote this script in avisynth window :
ConvertToRGB()
ConvertToFps(60)

for HD i did :
ConvertToYUY2()
ConvertToFps(60)

what this script does , it inceases the fps of the matirial without really speeding up the movies, you actually get new frames!!!

The 60 parameter is the refreshrate your monitor is working on.
if you got 72 for example write ConvertToFps(72).
this plugin/action is kinda cpu intesive, espcially for the HD matirial.
for SD you can get around with old pentium D or prescott.
for HD you prolly gona need core 2 duo.

I suggest enable & using the shortcut keys of ffdshow to enable/disable the avisynth on live playback (ctrl+alt+a by default).

I am sure you'll see the differance.

P.S : I use the ConverToRGB() command mainly because i noticed it improves the colors on Xvid/divx matirial , not sure about the reason , its some how relate to 16-235 colos, i dont fully understand it at the moment.

Hope this helps, any comments question are welcome.

later additions :

Bit more research and i found its better to do :

ColorYUV(levels="TV->PC")

than

ConvertToRGB()

much less cpu usage (espcially on HD content)

dimzon
4th March 2008, 15:29
Actually some Samsung LCD TV has feature "Film+" wich do same transformations BUT using motion vectors.
Philips has "Digital Natural Motion (DNM)"
WinDVD has "Trimension DNM"

Read this (http://compression.ru/video/frame_rate_conversion/index_en_msu.html) first

This is some thread in russian (http://forum.ixbt.com/print/0062/012524.html) BUT anyway You can look @ some Avisynth scripts in it...

Fragment of the "matrix" sequence (2 frames):
http://compression.ru/video/frame_rate_conversion/images/msu_matrix_src.gif


After processing by the FRC filter the frame rate increased 4 times
http://compression.ru/video/frame_rate_conversion/images/msu_matrix_frc.gif

hagayg
4th March 2008, 16:25
I think its really bad to ask Television to do this fix up, no matter what they say, in the future the playback device will do the work and you will end finding yourself turning off those feature in the TV.

I tried those mvtools scripts, it gave me very poor frame rate + 100% cpu load, maybe i used it wrong.
The ConvertFps gives quite good results for much less cpu work...

dimzon
4th March 2008, 19:37
I tried those mvtools scripts, it gave me very poor frame rate + 100% cpu load, maybe i used it wrong.
The ConvertFps gives quite good results for much less cpu work...
No, motion based math is too expensive for CPU.
But, just for fun, you can reduce source resolution and compare it against ConvertFps (at same reduced resolution). Try it!

hagayg
5th March 2008, 08:55
Thats why i posted this info,that motion verctor fps conversion is not relevant for realtime application, which means you cant use it for getting smooth playback in htpc.

and btw , if you just want to double the frame rate, ffdshow got under deinterlacing -> frame rate doubler some motion estimation features.

dimzon
5th March 2008, 11:26
motion verctor fps conversion is not relevant for realtime application
this is not true
As I said before some modern HD TV do this conversion at realtime themself.
WinDVD decoder utilize motion verctors from MPEG2 stream and do such convertion themself too.
If you have modern dual core CPU you can do such conversion for SD content using AviSynth script in realtime.

fusion_400
6th March 2008, 23:58
Hello i have tried this ConvertFPS function and it does work wonders for both 23.976 and 25 fps material but for some strange reason there are some frames that are jerky and they come very randomly and no my CPU is not the problem i have c2d clocked at 2.6Ghz and i have checked taskmanager and there are no cpu usage spikes at the places where the jerkyness occurs.

Am i missing something i have tried buffering frames but it does not make a difference.

Also when seeking there are some old frames displayed randomly.

If this would work perfectly it would be a godsend because i am limited to only 60hz on my Eizo 24" monitor.

hagayg
7th March 2008, 01:35
> Also when seeking there are some old frames displayed randomly.

Also happens here , seems a side effect of using avisynth, if ffdshow was smart enough to disable it whileing seeking it wouldnt happen i think.

About the other problem, doesnt really happen here , note that avisynth requires quite a lot of ram, check that as a problem.

fusion_400
7th March 2008, 01:46
> Also when seeking there are some old frames displayed randomly.

Also happens here , seems a side effect of using avisynth, if ffdshow was smart enough to disable it whileing seeking it wouldnt happen i think.

About the other problem, doesnt really happen here , note that avisynth requires quite a lot of ram, check that as a problem.

I have solved the issue by using these command

AssumeFPS(24,true)

This works strangely with both 23.976 and 25 fps sources.

25fps sources i never had troubles when seeking but i think just because 23.976 is uneven and changing to 24fps instead using assumeFPS makes the convertfps function better and my seeking problems are now gone thanks to assumefps.

i use these settings now
AssumeFPS(24,true)
ConvertFps(90)

hagayg
7th March 2008, 13:01
I'll check it out, altough i dont like the idea of messing with the audio.

Another tip you could check, put avisynth as the last "processing" filter on ffdshow, like if you use sharpen and or postprocessing, make sure they apply before avisynth, i noticed the movie is much more smooth when setting this.

btw , why you do ConvertFps(90)? dont you have 60hz monitor ?

fusion_400
7th March 2008, 15:30
I'll check it out, altough i dont like the idea of messing with the audio.

Another tip you could check, put avisynth as the last "processing" filter on ffdshow, like if you use sharpen and or postprocessing, make sure they apply before avisynth, i noticed the movie is much more smooth when setting this.

btw , why you do ConvertFps(90)? dont you have 60hz monitor ?

It seemed to get smoother. Anyway i have since thought even more about this problem.

And i want to write a script that chooses AssumeFPS(24,true) if the framerate is 23.976fps and if the framerate is 25fps i want AssumeFPS(25,true) i wonder how this is done i am not good at programming.

This seems to give the smoothest results when i change it manually but i want an automatic solution.

dimzon
7th March 2008, 16:02
And i want to write a script that chooses AssumeFPS(24,true) if the framerate is 23.976fps and if the framerate is 25fps i want AssumeFPS(25,true) i wonder how this is done i am not good at programming.
Try this:
assumeFPS(Round(Framerate),true)

dimzon
7th March 2008, 16:12
Anyway I think this feature must me ffdShow build-in feature
In this key ffdshow can automatically select the best frame interpolation math according current CPU load (just like PP do)
http://img176.imageshack.us/img176/8773/fpstj4.png

In this case ffdshow can perform additional motion interpolation if CPU is free, use blending (like ConvertFPS do) if CPU is at middle and (if CPU is very low) just show nearest frame.

I think we can ask ffdshow developers for such features

fusion_400
7th March 2008, 16:23
Try this:
assumeFPS(Round(Framerate),true)

Thanks do you know how i can show what the value of the Framerate variable is directly on the overlay?

dimzon
7th March 2008, 16:35
Thanks do you know how i can show what the value of the Framerate variable is directly on the overlay?
I think You must read Avisynth manual (http://avisynth.org/oldwiki/index.php?page=Subtitle) furst.

fusion_400
7th March 2008, 17:02
I think You must read Avisynth manual (http://avisynth.org/oldwiki/index.php?page=Subtitle) furst.

Ok i have looked but cant find a function that shows a variable contents on screen.

dimzon
7th March 2008, 18:11
Ok i have looked but cant find a function that shows a variable contents on screen.

Subtitle(string(Framerate))
assumeFPS(Round(Framerate),true)
Subtitle(string(Framerate), x=100)
ConvertFPS(60)
Subtitle(string(Framerate), x=200)

dimzon
7th March 2008, 18:24
Seems like this code cause ConvertFPS to run into separate thread
c=last.assumeFPS(Round(Framerate),true)
eval("c.ConvertFPS(60)")

dimzon
7th March 2008, 18:45
Such script performs 60fps for SD and 30fps for HD content
c=last.assumeFPS(Round(Framerate),true)
eval("c.ConvertFPS((c.Width>1000)?30:60)")

dimzon
7th March 2008, 20:02
this version produce less blending for 24/25 fps source when converting to 30/60 fps
c=last
c=c.assumeFPS(Round(c.Framerate),true)
c=c.Framerate==25? c.SelectEvery(5,0,1,2,3,4,4).assumeFPS(30):c
c=c.Framerate==24? c.SelectEvery(4,0,1,1,2,3).assumeFPS(30):c
eval("c.ConvertFPS((c.Width>1000)?30:60)")

fusion_400
7th March 2008, 23:45
this version produce less blending for 24/25 fps source when converting to 30/60 fps
c=last
c=c.assumeFPS(Round(c.Framerate),true)
c=c.Framerate==25? c.SelectEvery(5,0,1,2,3,4,4).assumeFPS(30):c
c=c.Framerate==24? c.SelectEvery(4,0,1,1,2,3).assumeFPS(30):c
eval("c.ConvertFPS((c.Width>1000)?30:60)")

I tried this script but it got very choppy and not as smooth as before. Maybe something is wrong with the code because it does not take alot of CPU time.

Thanks for the help with the subtitle command.

This still gives the smoothest playback for all 23.976 and 25 fps sources although with some blending ofcourse maybe
your results are different i can only use 60hz framerate on my 24" Eizo screen.

c=last.assumeFPS(Round(Framerate),true)
eval("c.ConvertFPS(60)")

If the blending issue also could be dealt with and still provide smooth playback it would be amazing truly a revolution especially for people who are stuck with 60hz only mode on their monitors like i am.

Is it possible to write a script that does nothing at all when the framerate is 29.97 or 30fps and only does ConvertFPS when framerate is 23.976 and 25fps. Together with solving the blending issue this would be a miracle come true.

hagayg
8th March 2008, 14:24
> c=c.assumeFPS(Round(c.Framerate),true)

this line indeed prdouce much nicer playback + seems the seek problems gone :)

dizmon, your code produce somewhat skippy playback here.

can you explain what those lines meant to do ? :

c=c.Framerate==25? c.SelectEvery(5,0,1,2,3,4,4).assumeFPS(30):c
c=c.Framerate==24? c.SelectEvery(4,0,1,1,2,3).assumeFPS(30):c

hagayg
8th March 2008, 14:28
also , the command eval("c.ConvertFPS(60)") , doesnt seem to run here on different thread , i got dual core cpu and on task manager i see the job is mainly done on one core ....
is it normal ? or i need to define something ?

fusion_400
8th March 2008, 17:12
also , the command eval("c.ConvertFPS(60)") , doesnt seem to run here on different thread , i got dual core cpu and on task manager i see the job is mainly done on one core ....
is it normal ? or i need to define something ?

Yes i also have dual core and it only runs on one of the cores.

I hope that the blending issues can be solved though without makeing it look jerky.

hagayg
8th March 2008, 18:09
Make sure ConvertToYUY2() is written at the start of your script.
here it gives more smooth video... (not sure why , but it definitly noticeable)

sheppaul
12th March 2008, 06:55
Actually some Samsung LCD TV has feature "Film+" wich do same transformations BUT using motion vectors.

This is interesting. I googled for "Film+" but no result. Would you let me know some details?

dimzon
12th March 2008, 14:21
This is interesting. I googled for "Film+" but no result. Would you let me know some details?
Sorry, not Film+ but Movie+
Seem's like Samsung license this (http://compression.ru/video/frame_rate_conversion/index_en_frcn.html) filter from MSU.
It's same like Philips Digital Natural Motion (DNM)
Unfortunally this feature doesn't work for FullHD or 1360*768 (i think it's too expensive to build-in TV signal processor)

hagayg
19th March 2008, 07:35
Made some more testing to "fight" the bluriness.

I set my refreshrate to 48hz and ran a 23.976fps file, as we know there is no "Hiccup" or "skippy" pan movments, but there are not enough frames.

I normally tried to use the ffdshow detinterlace frame rate doubler, the result were better (i tried all the options , 3x3 square, current location etc) but still not something.

Now i tried to use convertfps again , but not to 60 but to 48 like this :

c=c.assumeFPS(Round(c.Framerate),true)
c.ConvertFps(Framerate*2)

The result seems much less blended if at all...
you just need a way to match your monitor refresh rate to the video , i use media portal with refreshrate plugin.
but of course it doesnt help to guys who stuck with 60hz...

hagayg
21st August 2008, 07:06
ConvertToYUY2()
c=c.assumeFPS(Round(c.Framerate),true)
c.ConvertFps(Framerate*2,zone=Height/2)
c.ConvertFps(60) # // or what ever is your refresh rate

lych_necross
28th August 2008, 07:21
ConvertToYUY2()
c=c.assumeFPS(Round(c.Framerate),true)
c.ConvertFps(Framerate*2,zone=Height/2)
c.ConvertFps(60) # // or what ever is your refresh rate

I think you forgot to put c=last below the converttvyuy2(). Anyways, the above code works wonderfully! :thanks:

P.S. I don't think converttoyuy2() is needed if you set the input colorspace in ffdshow to yuv2 only.

hagayg
22nd July 2009, 10:09
Better script for kinda same results :

c.assumeFPS(Round(c.Framerate),true)
Framerate <= 30 ? ChangeFps(Framerate*2) : last
c.ConvertFps(60) # // or what ever is your refresh rate

daWsOn_s
2nd October 2009, 21:11
is this still for avisynth? "c=" is not recognized.

Anyway I'm trying to use these useful tools for smooth playback on monitors stuck at 60hz but i have two major problems

1) it adds very noticeable compression artifacts in scenes! like the bitrate was half it actually is! is this normal?

2) in mkv container with ac3 sound the audio is out of sync, it starts ok but the lag gets bigger as you go further in the playback, at 1h it's 2 seconds of difference

any solution?

lych_necross
3rd October 2009, 04:06
is this still for avisynth? "c=" is not recognized.

Anyway I'm trying to use these useful tools for smooth playback on monitors stuck at 60hz but i have two major problems

1) it adds very noticeable compression artifacts in scenes! like the bitrate was half it actually is! is this normal?

2) in mkv container with ac3 sound the audio is out of sync, it starts ok but the lag gets bigger as you go further in the playback, at 1h it's 2 seconds of difference

any solution?
1.) All of these smooth playback solutions convert the framerate. To accomplish this one of two methods are commonly used. First, new frames are created by blending two frames to create a new intermediate frame (like convertfps). The other way is to use motion compensation to interpolate the missing frames (like mvtools). Both methods will introduce artifacts and cannot be eliminated, only minimized. Here's what I recommend. Instead of converting the framerate to the monitor's refreshrate, try changing the framerate to a multiple of the monitor's refreshrate. I use this for ntsc film movies on a 60hz monitor/projector

# requires mvtools 2.4.x+
super = MSuper(pel=1,hpad=16,vpad=16)
backward_vec = MAnalyse(super, blksize=16, isb = true, chroma=false, searchparam=1)
forward_vec = MAnalyse(super, blksize=16, isb = false, chroma=false, searchparam=1)
MFlowFps(super, backward_vec, forward_vec, num=30000, den=1001, mask=0)

2.) I have used reclock (http://forum.slysoft.com/showthread.php?t=19931) to fix these kinds of problems. An alternative could be to remux the files in question or re-rip from the original source and reencode.

daWsOn_s
3rd October 2009, 12:23
I'm sorry but where do I have to use that code?

lych_necross
4th October 2009, 01:35
I'm sorry but where do I have to use that code?
That code can be used in the avisynth tab of ffdshow. Install the latest ffdshow tryout, set Raw Video to All Supported under the codec's section of the video configuration screen, and paste the code in the avisynth section and enable it.

daWsOn_s
4th October 2009, 13:59
OK i did but the playback takes 100% of CPU, and everything blocks! why?

daWsOn_s
4th October 2009, 14:24
sorry it was a temp problem, anyway the process still remains really heavy and it just makes an unreal video movement and it shutters, so I think for me the best way is the simple convertfps, anyway is this like a pulldown?

which plugin do I need for

c.assumeFPS(Round(c.Framerate),true)
Framerate <= 30 ? ChangeFps(Framerate*2) : last
c.ConvertFps(60) # // or what ever is your refresh rate


It says "c" is unknown

lych_necross
5th October 2009, 07:18
sorry it was a temp problem, anyway the process still remains really heavy and it just makes an unreal video movement and it shutters, so I think for me the best way is the simple convertfps, anyway is this like a pulldown?

which plugin do I need for

c.assumeFPS(Round(c.Framerate),true)
Framerate <= 30 ? ChangeFps(Framerate*2) : last
c.ConvertFps(60) # // or what ever is your refresh rate


It says "c" is unknown
This is not like a pulldown. You can read more about it here (http://avisynth.org/mediawiki/FPS). To make that code work, you need to add c=last before everything else. It should look like:

c=last
c.assumeFPS(Round(c.Framerate),true)
Framerate <= 30 ? ChangeFps(Framerate*2) : last
c.ConvertFps(60) # // or what ever is your refresh rate


You could just try ConvertFPS(60) # or whatever the desired refreshrate is.