About Me
Michael Zucchi
B.E. (Comp. Sys. Eng.)
also known as Zed
to his mates & enemies!
< notzed at gmail >
< fosstodon.org/@notzed >
Frame Accurate Seeking in H.264 streams with libavformat, FFmpeg
I had the need for accurate seeking in H.264 streams using jjmpeg
(FFmpeg/libavformat) and spent some time over the last few days
trying to work it out. JJMediaReader has a seek that works quite
well but I knew it wasn't correct as it was offsetting the read
timestamp by the stream start - I can't exactly remember why I did
this but I think its because it didn't work very well otherwise.
Anyway ... I finally found out why. Depending on the container,
when seeking it will go to the next or equal keyframe
rather than the previous or equal. Sigh. So that offset I was
using just happened to be enough to work most of the time and as
it reported the same start-relative time it appeared to work
properly.
So I changed the seek code to use a reverse offset for the seek
point, and then it will run forward to get to the correct frame.
This is based on the framerate rather than a fixed time offset
because some of the video I have uses low framerates. This works
but can be a bit slow as it might seek back too far.
To reduce some of the redundant work I thought of using the packet
byte position to read the exact packet of the closest previous
keyframe. Unfortunately it seems the container formats i'm using
don't support AVSEEK_FLAG_BYTE
so that idea went
nowhere. Fuck.
The best solution so far has been to implement a two-value seek
function. The first argument is the keyframe timestamp and the
second argument is the desired frame timestamp. Thus it seeks to
the keyframe first and then advances by single frames until the
desired frame is decoded. Short forward seeks bypass the seek
step This requires an external index but the application in
question needed it anyway as it requires a wall-clock-time to
frame-time mapping as well.
Summary
- If you know the timestamp is a keyframe,
use
av_seek_file()
.
- Otherwise, seek to a timestamp which is at least a few
frames before the desired timestamp and then step forwards.
Spring
I went to Thailand for a couple of weeks in September with a mate
from the pub. We ate too much good food and drank too much warm
beer. The food was fantastic and the place was interesting
although after a couple of weeks I needed a break. I've got a ton
of photos and if i ever sort them out i'll put up a post. We were
up north and only spent a night in Bangkok on the way home, and
avoided the seedy strips. He grew up in Thailand so did all the
talking and we visited some relatives so it was a nice mix of
touristy and local action.
I haven't travelled anywhere for nearly 15 years and while it was
fun it hasn't sparked any desire to travel again anytime soon.
The flying is to physically tortuous and the constant action is
pretty exhausting.
It's also made me hate Adelaide even more! This town is starting
to suck a lot. Thr urban development is turning it into a shitty
overdeveloped town but without any of the benefits of becoming a
real city - it's not dense enough and the road design is from the
50s where cars are absolute king. Makes it pretty
human-unfriendly. And the people can suck. Somehow i've seemed
to basically run out of friends. I just don't fit in with anyone
and when I reach out and try I just get spat in the face in one
way or another. I guess I must just suck or something. I don't
really feel like i have anything to do with my copious spare time
apart from go to the pub and i'm pretty sick of that. Lately i've
only been going to try to get out of the house but it's just made
things worse and I think i'll stay in for a while.
Work is pretty dull too. I'm doing some machine learning stuff so
that's a lot of data preparation and then waiting for shit to run.
It's not very interesting and it's not fun at all, and the
application itself eats away at my soul. I sometimes think of
getting another job but I don't want to have to apply for one and
I don't have enough money to retire yet (depending on how long I
might live).
Apart from all that I've not been doing a lot apart from wasting
my life away reading reddit. As i've been using it for work there
are some small changes to jjmpeg that i've committed but not
released but otherwise I haven't been doing any coding. I've
downloaded java and javafx 13 and will migrate to that soon, it
should be a simple transition from java 11.
I've spent a good amount of time lately in the yard, from
cleaning up weeds to finishing long-outstanding projects like
installing the set of steps above. The two big things left are
what to do under the verndah and some sort of shed floor.
Either paving under the verandah and cement shed floor or
decking under the verndah and paving in the shed. Might be a
while yet on those.
It's a nice warm day today and I haven't decided what to do.
Probably not the pub, or at least only one or two if i do. I
should probably go for a ride but I don't really feel like it, i
haven't had a decent ride in a long time. I'm taking a half break
off work because I'm ahead of where I need to be and I don't feel
like working. Next week the weather is turning to shit so I'll
get back to it then.
Not quite a new computer!
Well I decided I'm sick of piss farting about thinking about a new
computer so I would just go and buy the bits to build one. And I
was looking forward to having something to do on the weekend.
But for various reasons I wanted to pay cash and of course an
online shop-front doesn't have that option, so I email the
retailer regarding the list of items i'd arrived at. Do they have
them on hand, are they compatible, that sort of thing.
But alas, still no reply two days later.
So that bummed me out.
Then I looked at another retailer in another state, but they don't
sell a single 32GB memory kit that's present in tested memory list
for the only suitable motherboard they have. I'm after an itx
board so that severely limits the options.
So that bummed me out further and I decided I'd just walk in to
the first shop I tried and just go buy it in person.
Unfortunately I ran into a mate who I haven't seen in yonks so I
just ended up catching up with him all afternoon and never made
it.
And now i've got a hangover and what was really just an impulse
buy has turned into a hassle and so I guess it's off the table for
this weekend at least. Maybe next week.
I'll probably still just end up going to them if i've still got a
pocket full of cash because the retailer options are so limited in
this tiny city. If they're still in business anyway, they don't
seem to be too keen on making money. The chips will only get
better althgough RAM is volatile so who knows there.
For what it's worth this is what I came up with:
- AMD Ryzen 3700X
- 32GB 3200C16 RAM 2x16GB
- 1TB Samsung 970 EVO NVMe SSD
- MSI B450I Gaming Plus AC.
The motherboard is the only ITX available that I can find here (or
really, anywhere in the whole country in ready supply), but at
least this shop says the BIOS is already upgraded. I've already
got a power supply. The aim would be to build a case ... but it's
a bit involved so I may never get around to it and i've got some
old shit lying around I can use in the mean time. GPU is a bit of
a pain, really I just want a short 1 or 2 slot AMD card (for the
proper free software linux drivers). Rare as fucking hens teeth
here though, the shop I was going to has had no AMD graphics cards
at all for months until the 5700 came out and now that's all they
have. No one else local has anything below RX 580 nor any of the
workstation line which would do, if a little pricey. I have an
old HD 5770 that i'll use to start with. It's a double pain if i
build my own case as I need to make sure whatever i end up with
will fit. And if i get a new one it may as well be the latest
design. I'll probably have to order online, whatever I decide.
Primary Tool Upgrades
I've been looking for a new keyboard for a while. My venerable
old (old!) litetouch honeywell keyboard has finally worn itself
out. I tried cleaning it but that probably just damaged the
contacts further. It's a really amazing design, no screws in the
whole thing, the contacts are just printed on a thin plastic sheet
that folds over itself, and the springs are just a single silicone
overlay which sits over it. Virtually silent and yet the keys
have a very positive bump action. Each row of keys is a single
injection moulded piece - almost like the way a plastic aeroplane
model comes - that clips off the base. You can just unclip them
all and chuck them in the dishwasher!
It still works but the left quarter is a bit finicky if you don't
press hard enough. Many of the clips which are part of the
injection moulded parts have snapped off. Some for example held
down the contact between the keyboard sheet and PCB which houses
the MCU and LEDs so the contact isn't as solid as it used to be.
I actually semi-retired it some years ago, i've just been using it
on a secondary machine here.
Real pity, just comparing the key feel now it's still amazing for
the keys that still work, but C and A mis-firing often enough to
become obnoxious and it just can't be repaired. I can't even
remember how I ended up with it or even when, I certainly didn't
buy it. I think I got it through a mate (Jamie) who collected
piles of computer shit. It seems to have been made in 1991! I
was still using a C64 in 1991, my first year at uni.
Anyway i looked around a bit and didn't bother doing anything
about it for months until last Friday when I ordered a couple of
"ducky one" keyboards online. Only one shop in Australia seems to
sell them, albiet in 600km away (i.e. the nearest next
town). Locally you can only get microsoft keyboards or some RGB
"gamer" monstrosities at exhorbitant prices.
I don't really know anything about them, or what appears to be a
whole computer sub-culture regarding 'mechanical' keyboards.
But I liked the idea of a keyboard with no markings, i've worn a
few off over the years so this should be immune to that at least!
Actually from a sitting position you can read the front face of
the keys not covered by your hands anyway. It was also a bit
cheaper. I also really liked the idea of the `ten-key-less' design -
I've always found the numpad a fucking pointless desk-waster.
The description of the `brown' switches are soft but with a bump -
but they're not quite as positive as the litetouch was though, and
definitely much louder particularly when they bottom out. If my
sister ever types on it she'll make a racket as she really thumps
the keys and types like she's on a mechanical typewriter (on which
she learnt).
And this one really just because I liked the colours. It's quite
pretty! This is a newer design and feels a little softer and
quieter but i haven't used it much yet.
They both come with a couple of extra key caps in contrasting
colours (pink for the black one), although a few of the keys are
for the non-existent numpad. They're both fairly heavy and very
solid, basically no flex in the body.
I'm still getting used to the tiny differences even though the
layout and dimensions are identical to the keyboards I was using.
Probably the main difference is that the very top of the key is
slightly smaller so they have larger gaps in between, it just
throws out my touch enough but it wont take long to get used to
them. Oddly I end up not making typos so much as typing a
completely different word? I mostly type on my work laptop
anyway, whose keyboard isn't fantastic but it's adequate.
My desks are always full of shit so the smaller size is handy as
well.
I wouldn't have minded a bit more of a positve feedback on the key
presses, but I guess I will get used to it and they aren't squashy
at least. I suppose i'd better, the pair of them cost $250, but
given the amount of time I spent on the damn machines it's
justifiable. I only really needed one but this saves more desk
space, and maybe i'll take one to work if i ever spend enough time
there.
Another tool looking to be upgraded is my home machine. I'm
thinking of getting a ryzen 3K system at some point, but i'll
probably umm and ahh over that for months more yet - or just spend
on a whim. The X570 boards are just too overpriced and there's
basically no ITX boards to be had either.
Update 21/7/19: Short mini-review. I've been using the
D1-2 (the blue one) on my home machine enough to get used to it.
In a word: very good. I was at work using a keyboard that I
thought was ok before (a HP workstation keyboard, one of the flat
square-keyed ones) but it felt like typing on soggy bread -
although this was the project managers keyboard and not my pc of
the same, and well, he eats at his desk.
Improved post navigation links
I've made a minor improvement
to blogz so that when viewing a
single post the navigation links at the bottom of the post show
the title of the next/previous post rather than just saying 'Older'
or 'Newer'. This was something I had intended to add when I got
the database backend working but that is still in limbo. Actually
most of the code for the blog output is done, I just can't decide
on relatively unimportant details like the serialisation format
for the metadata records. The other issue is adds a whole mass of
potential complexity to creating posts rather than just editing a
file on a shell login. Like an order of magnitue of complexity.
It doesn't require this complexity but it enables it.
I made some other minor changes to the stylesheet mostly to do
with inline figures (photos and captions), justified the text of
posts, and messed about with the About box.
Reading multi-stream high-depth videos in octave (and matlab)
So I discovered recently that octave and matlab support direct
calling out to Java. We had a need to read both multi-stream and
high bit-depth videos from them, and using jjmpeg seemed a lot
easier than writing some mex shit. The native video format
support in matlab is abysmal and it simply has no capability for
reading multi-stream videos either.
Anyway, i've just commited some stuff to jjmpeg
in contrib/octave.
It consists of a simplified multi-stream VideoReader and a small
set of octave.m files which ease it's use and make it portable.
And a Makefile to compile this using a Java 8 JDK because those
tools are so wildly out of date.
The .jar file and octave scripts are portable to matlab.
Althhough the license means they cannot be distributed, I think.
Since the freenect2 indev patches were not accepted into ffmpeg I
will add them and probably the kinect2 indev patches to
jjmpeg/contrib as well. At some future point in time.
ZedZone sitemap.xml
I've added a sitemap.xml to the site.
Maybe that'll make google consider adding it to it's index as it's
only indexing 130 odd pages out of 1K+. bing is probably a lost
cause, it's only indexed 10 pages.
It's a
patch to blogz which
generates both the short (id only) and long (date-title) urls as
well as a sitemap for the few plain html articles which mostly
cover the project home pages.
I also noticed some very old url's were being accessed so I added
a redirect from /blog?post=xx to /post/xx. Huh now i think of it
/blog?post=xx was blog by date, but no matter, it's good enough.
Been a bit sick and not really on top of it the last few days.
incremental javac, make
I've been looking into incremental javac compilation again. I had
most of the code for one approach done weeks ago but it never
really got to the point of doing anything useful.
The goal is to simplify a GNU make based Java build system while
ensuring consitent and complete builds.
javac -m <module>
comes very close to what I
want but the main problem is that it doesn't remove stale files.
These come about for the same reasons that might occur with C
development, for example the .java file is renamed or deleted.
But there are many more cases that occur regularly in Java, for
example an inner class or anonymous inner class is removed or
renamed. And in C these aren't such an issue since a link line or
whatever is just going to ignore any stale files anyway but with
Java you can't easily calculate all the possible .class files
(without recompiling the source) so you just grab all the files in
the directory when creating a jar or module, so you don't want
stale ones lying about.
So far i've created a tool called ijavac
that uses
the --module-source-path
only to automatically find
all source files that need recompiling. It optionally supports
per-module mode where it restricts processing to in-module
classes. It also automatically removes all stale files before
they are recompiled. It works by parsing all the existing .class
files, matching them up with their source based
on --module-source-path
and checking timestamps. The
parsed .class files are used to create the full set of down-stream
dependent classes, then match them to the corresponding set of
.java files, and then invoke javac with this set.
In per-module mode it isn't quite as fast as using javac -m, but
it's close and it ensures stale files are removed. Because it's
only performing file-level dependencies it can recompile more than
is necessary. In whole-project mode it depends on what was
changed and how many files could need recompiling. However i'm
not sure I can fit this in with my build system as I want to
support generated files which may require a per-module build
order.
There are also cases where module mode fails, regardless of
whether the stale files are removed or not. For example:
// module a
public class Bob {
int x;
}
// module b
public class Foo {
Bob bob;
int baz() {
return bob.x;
}
}
If x is renamed in class Bob then a per-module rebuild will only
rebuild Bob.class. Subsequently running a dependency-aware module
build on module b will not recompile Foo.
The whole-project mode will catch this case succesfully assuming a
per-module build hasn't already updated Bob.class independently.
Although if you have a deeply dependent object (that is used
widely in a project) it's about the same speed just to delete all
the classes and rebuild them all together.
The main reason is that the per-module mode restricts it's view to
only in-module classes and sources. I guess it should be able to
handle cross-module checks with some additional work.
Another idea i'm toying with is creating a cleanup routine that is
run as a post-process after javac -m
. Becasue this
only needs to match each .class with a .java it doesn't have to
worry about building the whole dependency graph and can get away
with only parsing the Source attribute. I'm not sure why javac -m
doesn't expunge stale files but alas it does not.
I also have the code to generate the module-level dependency lists
which is what would go into a makefile. The makefile wouldn't
track .class files as one would with C.
But for now i'm not sure I really got anywhere so I guess it'll
just go on the backburner again.
Apparently 'best practice' using maven is just to delete and
rebuild every time which is nonsense.
Copyright (C) 2019 Michael Zucchi, All Rights Reserved.
Powered by gcc & me!