summaryrefslogtreecommitdiffstats
path: root/contrib/ffmpeg/A06-edit-list-offset.patch
blob: c6921622e6c85a41b60431158e202981c17297ff (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
From eeb38d760d0748b14c4faed1bfd04efad9ed0806 Mon Sep 17 00:00:00 2001
From: John Stebbins <stebbins@jetheaddev.com>
Date: Sun, 19 Feb 2017 14:45:44 -0700
Subject: [PATCH] mov: fix edit list issue that can cause A/V desync

Only the first entry in the edit list was factored into the time_offset
of the first sample in a track.  But when there is a delay (empty edit
entry) the mediatime from the second entry must also be factored into
the time_offset.
---
 libavformat/isom.h |  2 ++
 libavformat/mov.c  | 30 ++++++++++++++++++++++--------
 2 files changed, 24 insertions(+), 8 deletions(-)

diff --git a/libavformat/isom.h b/libavformat/isom.h
index 8cc5ab7..7c345e9 100644
--- a/libavformat/isom.h
+++ b/libavformat/isom.h
@@ -125,6 +125,8 @@ typedef struct MOVStreamContext {
     int *keyframes;
     int time_scale;
     int64_t time_offset;  ///< time offset of the first edit list entry
+    int64_t time_offset_delay;
+    int64_t time_offset_skip;
     int current_sample;
     unsigned int bytes_per_frame;
     unsigned int samples_per_frame;
diff --git a/libavformat/mov.c b/libavformat/mov.c
index 5c9f85c..1657647 100644
--- a/libavformat/mov.c
+++ b/libavformat/mov.c
@@ -2323,10 +2323,10 @@ static void mov_build_index(MOVContext *mov, AVStream *st)
     uint64_t stream_size = 0;
 
     /* adjust first dts according to edit list */
-    if (sc->time_offset && mov->time_scale > 0) {
-        if (sc->time_offset < 0)
-            sc->time_offset = av_rescale(sc->time_offset, sc->time_scale, mov->time_scale);
-        current_dts = -sc->time_offset;
+    if (mov->time_scale > 0) {
+        sc->time_offset = av_rescale(sc->time_offset_delay, sc->time_scale,
+                                     mov->time_scale) - sc->time_offset_skip;
+        current_dts = sc->time_offset;
     }
 
     /* only use old uncompressed audio chunk demuxing when stts specifies it */
@@ -2999,6 +2999,10 @@ static int mov_read_trun(MOVContext *c, AVIOContext *pb, MOVAtom atom)
     sc = st->priv_data;
     if (sc->pseudo_stream_id+1 != frag->stsd_id)
         return 0;
+    if (c->time_scale > 0) {
+        sc->time_offset = av_rescale(sc->time_offset_delay, sc->time_scale,
+                                     c->time_scale) - sc->time_offset_skip;
+    }
     avio_r8(pb); /* version */
     flags = avio_rb24(pb);
     entries = avio_rb32(pb);
@@ -3029,7 +3033,7 @@ static int mov_read_trun(MOVContext *c, AVIOContext *pb, MOVAtom atom)
     }
     if (flags & MOV_TRUN_DATA_OFFSET)        data_offset        = avio_rb32(pb);
     if (flags & MOV_TRUN_FIRST_SAMPLE_FLAGS) first_sample_flags = avio_rb32(pb);
-    dts    = sc->track_end - sc->time_offset;
+    dts    = sc->track_end + sc->time_offset;
     offset = frag->base_data_offset + data_offset;
     distance = 0;
     av_log(c->fc, AV_LOG_TRACE, "first sample flags 0x%x\n", first_sample_flags);
@@ -3069,7 +3073,7 @@ static int mov_read_trun(MOVContext *c, AVIOContext *pb, MOVAtom atom)
         return AVERROR_EOF;
 
     frag->implicit_offset = offset;
-    st->duration = sc->track_end = dts + sc->time_offset;
+    st->duration = sc->track_end = dts - sc->time_offset;
     return 0;
 }
 
@@ -3152,6 +3156,7 @@ static int mov_read_elst(MOVContext *c, AVIOContext *pb, MOVAtom atom)
 {
     MOVStreamContext *sc;
     int i, edit_count, version;
+    int time_offset_done = 0;
 
     if (c->fc->nb_streams < 1)
         return 0;
@@ -3175,8 +3180,17 @@ static int mov_read_elst(MOVContext *c, AVIOContext *pb, MOVAtom atom)
             time     = (int32_t)avio_rb32(pb); /* media time */
         }
         avio_rb32(pb); /* Media rate */
-        if (i == 0 && time >= -1) {
-            sc->time_offset = time != -1 ? time : -duration;
+        if (!time_offset_done) {
+            if (time == -1) {
+                /* delay is in movie timescale */
+                sc->time_offset_delay += duration;
+            } else if (time >= 0) {
+                /* samples to skip is in track timescale */
+                sc->time_offset_skip = time;
+                time_offset_done = 1;
+            }
+            /* timescales may not be known yet, so we can not compute
+             * a single combined time_offset yet */
         }
     }
 
-- 
2.9.3