Browse code

Fix PTS for OGM codecs. Fixes issue251

Originally committed as revision 20815 to svn://svn.ffmpeg.org/ffmpeg/trunk

David Conrad authored on 2009/12/13 05:18:43
Showing 4 changed files
... ...
@@ -116,7 +116,7 @@ ogg_reset (struct ogg * ogg)
116 116
         os->pstart = 0;
117 117
         os->psize = 0;
118 118
         os->granule = -1;
119
-        os->lastgp = -1;
119
+        os->lastpts = AV_NOPTS_VALUE;
120 120
         os->nsegs = 0;
121 121
         os->segp = 0;
122 122
     }
... ...
@@ -288,7 +288,6 @@ ogg_read_page (AVFormatContext * s, int *str)
288 288
     if (get_buffer (bc, os->buf + os->bufpos, size) < size)
289 289
         return -1;
290 290
 
291
-    os->lastgp = os->granule;
292 291
     os->bufpos += size;
293 292
     os->granule = gp;
294 293
     os->flags = flags;
... ...
@@ -303,7 +302,7 @@ static int
303 303
 ogg_packet (AVFormatContext * s, int *str, int *dstart, int *dsize)
304 304
 {
305 305
     struct ogg *ogg = s->priv_data;
306
-    int idx;
306
+    int idx, i;
307 307
     struct ogg_stream *os;
308 308
     int complete = 0;
309 309
     int segp = 0, psize = 0;
... ...
@@ -393,6 +392,15 @@ ogg_packet (AVFormatContext * s, int *str, int *dstart, int *dsize)
393 393
         os->psize = 0;
394 394
     }
395 395
 
396
+    // determine whether there are more complete packets in this page
397
+    // if not, the page's granule will apply to this packet
398
+    os->page_end = 1;
399
+    for (i = os->segp; i < os->nsegs; i++)
400
+        if (os->segments[i] < 255) {
401
+            os->page_end = 0;
402
+            break;
403
+        }
404
+
396 405
     os->seq++;
397 406
     if (os->segp == os->nsegs)
398 407
         ogg->curidx = -1;
... ...
@@ -519,9 +527,20 @@ ogg_read_packet (AVFormatContext * s, AVPacket * pkt)
519 519
         return AVERROR(EIO);
520 520
     pkt->stream_index = idx;
521 521
     memcpy (pkt->data, os->buf + pstart, psize);
522
-    if (os->lastgp != -1LL){
523
-        pkt->pts = ogg_gptopts (s, idx, os->lastgp);
524
-        os->lastgp = -1;
522
+
523
+    if (os->lastpts != AV_NOPTS_VALUE) {
524
+        pkt->pts = os->lastpts;
525
+        os->lastpts = AV_NOPTS_VALUE;
526
+    }
527
+    if (os->page_end) {
528
+        if (os->granule != -1LL) {
529
+            if (os->codec && os->codec->granule_is_start)
530
+                pkt->pts    = ogg_gptopts(s, idx, os->granule);
531
+            else
532
+                os->lastpts = ogg_gptopts(s, idx, os->granule);
533
+            os->granule = -1LL;
534
+        } else
535
+            av_log(s, AV_LOG_WARNING, "Packet is missing granule\n");
525 536
     }
526 537
 
527 538
     pkt->flags = os->pflags;
... ...
@@ -41,6 +41,11 @@ struct ogg_codec {
41 41
     int (*header)(AVFormatContext *, int);
42 42
     int (*packet)(AVFormatContext *, int);
43 43
     uint64_t (*gptopts)(AVFormatContext *, int, uint64_t);
44
+    /**
45
+     * 1 if granule is the start time of the associated packet.
46
+     * 0 if granule is the end time of the associated packet.
47
+     */
48
+    int granule_is_start;
44 49
 };
45 50
 
46 51
 struct ogg_stream {
... ...
@@ -53,12 +58,14 @@ struct ogg_stream {
53 53
     unsigned int pduration;
54 54
     uint32_t serial;
55 55
     uint32_t seq;
56
-    uint64_t granule, lastgp;
56
+    uint64_t granule;
57
+    int64_t lastpts;
57 58
     int flags;
58 59
     const struct ogg_codec *codec;
59 60
     int header;
60 61
     int nsegs, segp;
61 62
     uint8_t segments[255];
63
+    int page_end;   ///< current packet is the last one completed in the page
62 64
     void *private;
63 65
 };
64 66
 
... ...
@@ -153,26 +153,30 @@ const struct ogg_codec ff_ogm_video_codec = {
153 153
     .magic = "\001video",
154 154
     .magicsize = 6,
155 155
     .header = ogm_header,
156
-    .packet = ogm_packet
156
+    .packet = ogm_packet,
157
+    .granule_is_start = 1,
157 158
 };
158 159
 
159 160
 const struct ogg_codec ff_ogm_audio_codec = {
160 161
     .magic = "\001audio",
161 162
     .magicsize = 6,
162 163
     .header = ogm_header,
163
-    .packet = ogm_packet
164
+    .packet = ogm_packet,
165
+    .granule_is_start = 1,
164 166
 };
165 167
 
166 168
 const struct ogg_codec ff_ogm_text_codec = {
167 169
     .magic = "\001text",
168 170
     .magicsize = 5,
169 171
     .header = ogm_header,
170
-    .packet = ogm_packet
172
+    .packet = ogm_packet,
173
+    .granule_is_start = 1,
171 174
 };
172 175
 
173 176
 const struct ogg_codec ff_ogm_old_codec = {
174 177
     .magic = "\001Direct Show Samples embedded in Ogg",
175 178
     .magicsize = 35,
176 179
     .header = ogm_dshow_header,
177
-    .packet = ogm_packet
180
+    .packet = ogm_packet,
181
+    .granule_is_start = 1,
178 182
 };
... ...
@@ -95,15 +95,16 @@ static int speex_packet(AVFormatContext *s, int idx)
95 95
         os->private = spxp;
96 96
     }
97 97
 
98
-    if (os->flags & OGG_FLAG_EOS && os->lastgp != -1 && os->granule > 0) {
98
+    if (os->flags & OGG_FLAG_EOS && os->lastpts != AV_NOPTS_VALUE &&
99
+        os->granule > 0) {
99 100
         /* first packet of final page. we have to calculate the final packet
100 101
            duration here because it is the only place we know the next-to-last
101 102
            granule position. */
102
-        spxp->final_packet_duration = os->granule - os->lastgp -
103
+        spxp->final_packet_duration = os->granule - os->lastpts -
103 104
                                       packet_size * (ogg_page_packets(os) - 1);
104 105
     }
105 106
 
106
-    if (!os->lastgp && os->granule > 0)
107
+    if (!os->lastpts && os->granule > 0)
107 108
         /* first packet */
108 109
         os->pduration = os->granule - packet_size * (ogg_page_packets(os) - 1);
109 110
     else if (os->flags & OGG_FLAG_EOS && os->segp == os->nsegs &&