Hi all.

First, some background about me. I am very new to open-source project
contribution. So, my apologies in advance for any inexperienced gaffes in my
tone or approach.
Also, I sent an earlier version, but apparently it was too large and needed
moderator approval. Please ignore if you get it again.

While working with VLC I noticed that libdvdnav does not accurately handle
setting position by time.
Specifically, there are two methods that seem to address this functionality,
but both have issues:
1. dvdnav_time_play in navigation.c
    This is not implemented, so it is not usable.
    printerr("Not implemented yet.");

2. dvdnav_time_search in searching.c:
    This function uses interpolation over a cell to get to a time, which is
inaccurate. The comment indicates as much
 /* FIXME: right now, this function does not use the time tables but
interpolates
   only the cell times */

With that in mind, I decided to try to implement an accurate method. As it
turns out, this is not a trivial issue.

I came up with an approach that does seem to work, but with a few
reservations:
- the approach is a bit complicated
  It uses VTS_TMAPTI and VTS_VOBU_ADMAP to get to time. I detail more below.
- the approach may fail on poorly-authored dvds
  If a DVD has a corrupt VTS_VOBU_ADMAP it will not work

I detail more in this thread:
http://forum.videolan.org/viewtopic.php?f=32&t=76308&start=15. I am
reposting my last post below. It is verbose, but hopefully it explains the
situation

Finally, I will send my version of searching.c in a follow-up email. It has
a new method: static int32_t dvdnav_jump_to_sector_by_time(dvdnav_t *this,
uint32_t time_in_pts_ticks);

I send it for curiosity/review purposes. If this new proc is acceptable, I
will convert to the preferred patching-method for libdvdnav. (I am honestly
ignorant of what is involved)

Also, please note I am also very new to C programming (I am a C# programmer
with some Java). My apologies in advance for the verbose
comments/printfs/lack of convention.

Let me know if there is anything else.
Thanks.

----EXCERPT FROM THREAD----
I used to use the MS DirectDvd library. I believe it's the same library that
Windows MediaPlayer uses (the behavior is exactly the same).
It does accurate seeking for most dvds, but there are some DVDs (< 5%) that
it will fail and give a Division by Zero error (it will freeze the app).
By my best analysis, I think DirectDVD uses the timestamps in the VOB PCI
pack (c_eltm?) http://dvd.sourceforge.net/dvdinfo/pci_pkt.html. It doesn't
seem to use the IFO at all.

>From what I've seen, I think this may be the best of all possible
approaches. The info in the IFO will be correct for most dvds, but there are
some dvds where the time map (VTS_TMAPTI) is corrupt or missing (5% of my
collection). I imagine there are some dvds that have similar issues with
VTS_VOBU_ADMAP (have not seen any yet).

That said, the div-by-zero errors shows that the VOB PCI pack is not always
correct (again, about 5% of my collection. some overlap with the prior 5%).
However, I think other info in the VOB PCI pack can be used to correct this
corruption (vobu_s_ptm; vobu_e_ptm; vobu_se_e_ptm). I'm assuming that
DirectDVD simply didn't bother enough to fix them (especially when
considering that div-by-zero freezes the app).

Unfortunately, scanning the VOB files for this data is a project beyond my
current ability/time.

So in its place, I devised an approach that uses the IFOs only. It's not
ideal, and will probably not work for poorly-authored DVDs. I'm hoping that
segment is small (< 1%). For those DVDs, I think there is no other recourse
other than to do VOB PCI pack analysis.

The IFO approach works as follows:
* Try the time_maps (should work for 95% of dvds)
  - for a given time, find the entry in the time_map table (VTS_TMAPTI)
    The time_map will break down a pgc into intervals of n seconds.
    Unfortunately n is generally 4 seconds, so...
  - lookup the corresponding sectors in the ad_map table (VTS_VOBU_ADMAP)
    The tmap sectors will produce a range in ad_map of 6 - 10 VOBUs.
  - do time interpolation over the 6 - 10 to get the time
    6 - 10 will be small enough that time interpolation will be accurate
* If there is no good time_map, try the ad_map (should work for the
remaining 5% of dvds)
  - for a given time, find the cell in the pgc
  - get the sector bounds of the cell
  - lookup the corresponding sectors from the ad_map table (VTS_VOBU_ADMAP)
    Unfortunately, the ad_map range will be much larger: a few hundred to a
few thousand VOBUs.
  - do time interpoloation over the range
    time interpolation is not ideal, as the range is very large
    however, VOBUs are sized between .4 and 1.5 seconds. Within a given
cell, they appear to be reasonably consistent (i.e.: VOBUs may hover around
15 frames)
* If there is no good ad_map, then just use the cell (same as
dvdnav_time_search)
  - for a given time, find the cell in the pgc
  - get the sector bounds of the cell
  - do time interpolation over the sector bounds
    this will rarely be accurate. It is there to handle the outlyer dvds (<
1%).

Here's a specific example for the time_map approach. It tries to find an
@sector for a @time of 5 seconds
1. look at VTS_TMAPTI
    @time_interval = 4
    Entries =  tmap_idx  sector   time
                                0     711      4
                                1    1776      8
                                2    2790     12

    since 5 seconds is between 4 and 8, @time is between tmap_idx 0 and 1
    @sector_bgn = 711
    @sector_end = 1776

2. look at VTS_VOBU_ADMAP
    Entries = vobu  sector
                       0          0
                       1        43
                        etc.
                       9       711
                      10      831
                      11      948
                      12    1080
                      13    1213
                      14    1349
                      15    1493
                      16    1642
                      17    1776
    @vobu_bgn = 9
    @vobu_end = 17

3. interpolate
    there are 8 vobus between 9 and 17
    5 is 1/4 of the way between 4 and 8
    1/4 of the way between 9 and 17 is 11
    so, @sector = 948
_______________________________________________
DVDnav-discuss mailing list
DVDnav-discuss@mplayerhq.hu
https://lists.mplayerhq.hu/mailman/listinfo/dvdnav-discuss

Reply via email to