Log in

View Full Version : Subtitle PTS value


GZZ
17th January 2005, 12:58
I´m trying to create at sub/idx file, just like vobsub do. This is primary for me to learn a bit more, nothing less.

But I use the PTS code to get the timecode out, but in the middle of the stream, my PTS code reset to zero and start all over. I was thinking, that if I just append the new PTS code value to the old one, then I should be just fine. But I don't match with the value vobsub get, so I´m a bit confused and don't know what I shall do to get the proper timecode out...

Vobsub got this (taken from its IDX file)


timestamp: 01:02:06:320, filepos: 0024ba800
# Vob/Cell ID: 3, 1 (PTS: 3769000)
timestamp: 01:02:49:960, filepos: 0024c5800


what I got is:


01:02:06:320 - Filepos: 0024BA800
00:00:01:001 - Filepos: 0024C5800


as you can see my timestamp reset itself and putting the 2 timesteps together don't give proper result. Some help will be helpful on what to do?. Thanks

GZZ

jsoto
18th January 2005, 01:02
You have to add the elapsed time taken from the previous Cells in the PGC. This is what I'm doing in PgcDemux: (I've also checked the results with Vobsub)

//... reading sector by sector in m_buffer
if (IsNav(m_buffer))
{
// do nothing
m_nNavPacks++;
m_iNavPTS0= (int) GetNbytes(4,&m_buffer[0x39]);
m_iNavPTS1= (int) GetNbytes(4,&m_buffer[0x3d]);
if (m_iFirstNavPTS0==0) m_iFirstNavPTS0=m_iNavPTS0;
if (m_iNavPTS1_old> m_iNavPTS0)
{
// Discontinuity, so add the offset
m_iOffsetPTS+=(m_iNavPTS1_old-m_iNavPTS0);
}
m_iNavPTS0_old=m_iNavPTS0;
m_iNavPTS1_old=m_iNavPTS1;
}
else if (IsVideo(m_buffer))
{
m_nVidPacks++;
if (m_buffer[0x15] & 0x80)
{
m_iVidPTS= readpts(&m_buffer[0x17]);
if (m_iFirstVidPTS==0) m_iFirstVidPTS=m_iVidPTS;
}
if ( m_bcheckvid) demuxvideo(m_buffer);
}
else if (IsSubs(m_buffer))
{
m_nSubPacks++;
sID=m_buffer[0x17+m_buffer[0x16]] & 0x1F;

if (m_buffer[0x15] & 0x80)
{
m_iSubPTS= readpts(&m_buffer[0x17]);
if (m_iFirstSubPTS[sID]==0)
m_iFirstSubPTS[sID]=m_iSubPTS;
}
if ( m_bchecksub) demuxsubs(m_buffer);
}


And, finally the sub PTS is:

iPTS=m_iSubPTS-m_iFirstNavPTS0+m_iOffsetPTS;

jsoto

GZZ
18th January 2005, 10:10
I can see you read the PTS value from byte $39 in the nav pack, but compared to vobsub which read the SCR value. Because the PTS (presentation time) and the SCR value are not the same. So what is the correct value to read ?

Ex. from a nav pack with Vob/Cell ID: 1, 2.

Scr value = 51998400.000 div 90 = 577760 ms

PTS Value = 52023600 div 90 = 578040 ms

what vobsub report in its idx file are:

timestamp: 00:09:35:080, filepos: 000098000, PTS:03162300
# Vob/Cell ID: 1, 2 (PTS: 577760) <-- SCR value ?
timestamp: 00:09:39:440, filepos: 000099800, PTS:031c1fd0


so are vobsub wrong or is it your code which are wrong ?? hehe


GZZ

mpucoder
18th January 2005, 16:09
jsoto's code is correct. You should never use SCR to determine presentation time, its relationship to dts and pts is varied to accomodate the bitrate.
What jsoto's code does is two things
1) accumulates the discontinuity offsets
2) properly accounts for the pts delay (the delay from receiving data to presenting it, usually 25257 for Scenarist, Muxman, and mplex)

One thing, though - you can get the value m_iFirstNavPTS0 from any NAV pack at offset 0x433

Timestamps for NTSC are usually (as seen in cell elapsed time) non-drop. So for this you use:
frame_number = (pts - first_ptm)/duration
first_ptm is the same as m_iFirstNavPTS0
duration is 3003 for NTSC, 3600 for PAL

From that calculate time as:
frame = frame_number % frame_rate
seconds = frame_number/frame_rate
frame rate = 30 for NTSC (not 29.97) and 25 for PAL

mpucoder
18th January 2005, 16:46
Originally posted by mpucoder
you can get the value m_iFirstNavPTS0 from any NAV pack at offset 0x433

I just realized that is true only prior to the first discontinuity. The value at 0x433 (vob_v_s_ptm) is the first pts of the vob, which can change over a discontinuity (since SCR reset should happen only at the start of a new vob).

jsoto
18th January 2005, 18:13
so are vobsub wrong or is it your code which are wrong ?? hehe Mmm, I didn't notice what are you saying.... are you really sure VobSub is using SCR for subs timestamp calculations?. I did some binary comparations between the *.sup files produced by PgcDemux and Vobsub+SubToSup and they were identical.

jsoto

GZZ
18th January 2005, 21:15
Its not the *.sub file, it just all the sectors with subtitles ind one file. You can open it in vobedit and see all the subtitle sectors. But when its writing the idx file, I think it reads the scr value instead of pts value. It was the only I could get it to match with its own output...

GZZ

jsoto
18th January 2005, 23:22
Please check this (from an example I've done just now)

# Vob/Cell ID: 2, 2 (PTS: 255640)
timestamp: 00:04:17:560, filepos: 000018000

From those values, you can get:
255640*90=23007600, for the Cell
((4*60+17)*1000+560)*90=23180400, for the subpicture


Looking in the first Nav Pack of PGC (Cell 1,1)

[0039] Vobu Start Presentation Time (90KHz clk) 25854
[003d] Vobu End Presentation Time (PTM) 29054
[0041] End PTM of VOBU if Sequence_End_Code 0
[0045] Cell elapsed time (BCD) 64
00:00:00.00 / 25 fps

And, in the first Nav Pack of Cell 2,2 (No discontinuities between VIDs)

[0039] Vobu Start Presentation Time (90KHz clk) 23033454
[003d] Vobu End Presentation Time (PTM) 23080254
[0041] End PTM of VOBU if Sequence_End_Code 0
[0045] Cell elapsed time (BCD) 64
00:00:00.00 / 25 fps

Finally, the subpicture data:

[0017] PES HeaderData 33 5 137 50 22
header data details:
PTS 23206254
[001c] Stream ID 32 [20]


and this is what I get using pgcDemux algorithm:
23206254-25854=23180400

Which is exactly the same as Vobsub is giving as timestamp.

Also,
23033454-25854=23007600,

which, again, is the data given by VobSub.

jsoto

EDIT: I've done a binary comparation between *.sup files (pgcDemux and VobSub+SubToSup) and they are identical.
SubToSup takes the idx file (produced by VobSub) and generates the *.sup files, obviously using the timestamps from the idx file.

jsoto
18th January 2005, 23:28
I've to confess I found other DVD with a constant difference of 7200 tics of 90.000 KHz clock between pgcDemux and VobSub+SubToSup in each sub timestamp. It is not too much but I do not have an explanation for this...
Vobu start PTS in first Nav pack is in this case 25200, but I still need to find where is the difference of 7200 tics.

jsoto

GZZ
19th January 2005, 00:23
Thank Jsoto. I got it working thanks to your excelent explanation. Only got one problem left, it might be some roundings or some wierd shit. Because all my subtitles timestamps are 80 ms off vobsub

ex.

vobsubs

timestamp: 00:02:27:840, filepos: 000000000, PTS:00cb35fa
timestamp: 00:02:31:520, filepos: 000000800, PTS:00d043ba


those I got:

timestamp: 00:02:27:920, filepos: 000000000, PTS:00cb35fa
timestamp: 00:02:31:600, filepos: 000000800, PTS:00d043ba


and its ALWAYS 80ms, so I was thinking if I just need to pull 80ms off the timestamp or vobsub do some wierd rounding or my code still got some flaws left. HEHE


GZZ

jsoto
19th January 2005, 00:42
Did you notice 7200 tics = 80 msecs?

I found the reason..

In the DVD where there are no differences:
PTS of first video Pack is identical to PTS0 of Nav pack.
Both are 25854

But in the one where there are 7200 tics, the PTSs are:
Nav Pack PTS: 25200
First Video PTS: 32400

@GZZ
Did you see the 7200 tics (=80 msec)?. Is the same in your case?

Well, not sure what is the right choice, if use the offset given in the first Nav pack or the one in the first Video pack..

@mpucoder,
could you help here?

jsoto

mpucoder
19th January 2005, 01:54
Sure, the same problem that has plagued dvd2avi - closed GOP
If you look at the first frame you'll see it has a "temperal sequence number" (sic, should be temporal) of 2. PTS is for the first encoded frame, but you have to account for when it gets displayed. In NTSC you also have the rff flags on the B frames (which get displayed before the I frame) to account for as well.
Trust the vobu_s_ptm, or do a lot of work.

jsoto
19th January 2005, 08:58
@mpucoder
Thanks for the clarifications. I'll trust the vobu_s_ptm.

jsoto

GZZ
19th January 2005, 11:35
I think I will continue reading the vobu_s_ptm, did understand much of the mpucoder technical explanation, but its properly correct :D


So did I understand it right when my timestamps which are 80ms (7200 tics) off vobsubs are correct ? (simple yes or no question)


GZZ

GZZ
19th January 2005, 18:06
Btw Jsoto

what is your variable: m_iNavPTS0_old used for ?

I can't see it used anywere, except it set each time a nav pack is found.

GZZ

jsoto
19th January 2005, 20:39
Originally posted by GZZ
So did I understand it right when my timestamps which are 80ms (7200 tics) off vobsubs are correct ? (simple yes or no question)

Yes. (Assuming you have the same situation I've explained.)

Originally posted by GZZ
Btw Jsoto, what is your variable: m_iNavPTS0_old used for ?
Just for... nothing. But I like it. :) .
Seriously, it's not used, but it's there because I've been doing some tests.

jsoto

GZZ
20th January 2005, 17:22
I think I got it all working, just need to parse the subtitle color palette from the ifo file...But my test on my own system with reading and writing (*.sub). I can demux 20 subs subs from a 01:50:00 movie in just under 3 min.


Think its pretty good. HEHE

just need to make it a bit better. Can't come up with any 'easy' and faster solution for parsing the PTS value from the sub sektors. I use this code at the moment:


Function GetSubPTS(TempBuf: Array of byte): Integer;
var
Binary: String;
I: Integer;
Begin
Binary := '';
For I := 23 to 27 do (23 = $17)
Begin
Case I of
23: Binary := Binary + Copy(Int2Bin(TempBuf[I]), 5, 3);
24: Binary := Binary + Int2Bin(TempBuf[I]);
25: Binary := Binary + Copy(Int2Bin(TempBuf[I]), 0, 7);
26: Binary := Binary + Int2Bin(TempBuf[I]);
27: Binary := Binary + Copy(Int2Bin(TempBuf[I]), 0, 7);
end;
end;
Result := BinToInt(Binary);
end;


I got the info from: http://dvd.sourceforge.net/dvdinfo/pes-hdr.html

When parsing the PTS value from the NAV pack I use another metode because its located different...

Do you have any fast solution to read the SUB PTS in a faster and less hassle way, so I don't need int2bin and bin2int (because those are a bit slow).?????


GZZ

jsoto
21st January 2005, 00:12
This is the code I'm using, but it is C (It's not my code, I've taken it from dvdauthor/mplex)


int readpts(uchar *buf)
{
int a1,a2,a3;
int pts;

a1=(buf[0]&0xe)>>1;
a2=((buf[1]<<8)|buf[2])>>1;
a3=((buf[3]<<8)|buf[4])>>1;
pts= (int) ((( (__int64) a1)<<30) | (a2<<15) | a3);
return pts;
}
void writepts(uchar *buf,ulong pts)
{
buf[0]=((pts>>29)&0xe)|(buf[0]&0xf1); // this preserves the PTS / DTS / PTSwDTS top bits
write2(buf+1,(pts>>14)|1);
write2(buf+3,(pts<<1)|1);
}

GZZ
21st January 2005, 09:51
Thanks - I got it converted to Delphi, had to look up some C syntax. HEHE

But I got a delphi version of the same code, if anyone need it.


It takes a Sektor (2048 byte) input as a buffer..Like Buf: Array[0..2047] of byte.

So it looks like:


Function GetSubPTS(aBuf: Array of byte): Int64; //Return value are the PTS value. :)
var
a1, a2, a3: Integer;
Begin
a1 := (aBuf[$17] and $e) shr 1;
a2 := ((aBuf[$18] shl 8) or aBuf[$19]) shr 1;
a3 := ((aBuf[$1A] shl 8) or aBuf[$1B]) shr 1;
Result := (((a1) shl 30) or (a2 shl 15) or a3);
end;


It should hopefully be faster then my old code. Thanks alot.


GZZ

GZZ
21st January 2005, 09:56
Next Step should be to do a Vobsub2bmp files, so it can be used for scenarist. But thats properly a bit harder. hehe

GZZ