Package: lsdvd
Version: 0.16-3+b1
Severity: normal
Tags: upstream patch

To convert timestamps from libdvdread, lsdvd uses the following code, from
function dvdtime2msec():

double fps = frames_per_s[(dt->frame_u & 0xc0) >> 6];
ms  = (((dt->hour &   0xf0) >> 3) * 5 + (dt->hour   & 0x0f)) * 3600000;
ms += (((dt->minute & 0xf0) >> 3) * 5 + (dt->minute & 0x0f)) * 60000;
ms += (((dt->second & 0xf0) >> 3) * 5 + (dt->second & 0x0f)) * 1000;
if(fps > 0)
ms += ((dt->frame_u & 0x30) >> 3) * 5 + (dt->frame_u & 0x0f) * 1000.0 / fps;

Obviously, the hour, minute and second field are in BCD, and the frame_u
field is too, except for the two most significant bits that code the frame
rate.

Except... the parentheses are missing in the last formula, and therefore the
*1000/fps is only applied to the low nibble, not the high one.

The attached patch fixes the problem.

I can observe it is the right behaviour using a DVD I have on my disk.
Extracting a cell from the VOB streams, I get with ffprobe:

frame|pkt_pts_time=0.168178|pkt_duration_time=0.040000
...
frame|pkt_pts_time=20.008178|pkt_duration_time=0.040000
frame|pkt_pts_time=N/A|pkt_duration_time=0.040000
frame|pkt_pts_time=N/A|pkt_duration_time=0.040000

As you can see, the correct duration would be:
20.008178 + 3*0.040000 - 0.168178 = 19.960.

Unpatched lsdvd prints 19.180. With the attached patch, 19.960.

-- System Information:
Debian Release: jessie/sid
  APT prefers testing
  APT policy: (500, 'testing'), (500, 'stable'), (50, 'unstable')
Architecture: amd64 (x86_64)
Foreign Architectures: i386

Kernel: Linux 3.11-2-amd64 (SMP w/8 CPU cores)
Locale: LANG=C, LC_CTYPE=fr_FR.UTF-8 (charmap=UTF-8)
Shell: /bin/sh linked to /bin/dash

Versions of packages lsdvd depends on:
ii  libc6        2.17-97
ii  libdvdread4  4.2.1-2

lsdvd recommends no packages.

lsdvd suggests no packages.

-- no debconf information
--- lsdvd.c.orig	2014-03-01 19:41:51.102966573 +0100
+++ lsdvd.c	2014-03-01 19:41:54.095011681 +0100
@@ -92,7 +92,7 @@
 	ms += (((dt->second & 0xf0) >> 3) * 5 + (dt->second & 0x0f)) * 1000;
 
 	if(fps > 0)
-	ms += ((dt->frame_u & 0x30) >> 3) * 5 + (dt->frame_u & 0x0f) * 1000.0 / fps;
+	ms += (((dt->frame_u & 0x30) >> 3) * 5 + (dt->frame_u & 0x0f)) * 1000.0 / fps;
 
 	return ms;
 }

Reply via email to