]> git.sesse.net Git - ffmpeg/blobdiff - libavformat/matroskadec.c
matroskadec: don't merge packets which have no timestamp
[ffmpeg] / libavformat / matroskadec.c
index debf6a11acd38b7280ceeb077e98049d2a4ab1ad..442a5a013afacd13d22f523c201986ed4b372950 100644 (file)
@@ -205,6 +205,7 @@ typedef struct {
     /* the packet queue */
     AVPacket **packets;
     int num_packets;
+    AVPacket *prev_pkt;
 
     int done;
     int has_cluster_id;
@@ -934,7 +935,7 @@ static int matroska_decode_buffer(uint8_t** buf, int* buf_size,
 }
 
 static void matroska_fix_ass_packet(MatroskaDemuxContext *matroska,
-                                    AVPacket *pkt)
+                                    AVPacket *pkt, uint64_t display_duration)
 {
     char *line, *layer, *ptr = pkt->data, *end = ptr+pkt->size;
     for (; *ptr!=',' && ptr<end-1; ptr++);
@@ -942,7 +943,7 @@ static void matroska_fix_ass_packet(MatroskaDemuxContext *matroska,
         layer = ++ptr;
     for (; *ptr!=',' && ptr<end-1; ptr++);
     if (*ptr == ',') {
-        int64_t end_pts = pkt->pts + pkt->convergence_duration;
+        int64_t end_pts = pkt->pts + display_duration;
         int sc = matroska->time_scale * pkt->pts / 10000000;
         int ec = matroska->time_scale * end_pts  / 10000000;
         int sh, sm, ss, eh, em, es, len;
@@ -956,7 +957,7 @@ static void matroska_fix_ass_packet(MatroskaDemuxContext *matroska,
         len = 50 + end-ptr + FF_INPUT_BUFFER_PADDING_SIZE;
         if (!(line = av_malloc(len)))
             return;
-        snprintf(line,len,"Dialogue: %s,%d:%02d:%02d.%02d,%d:%02d:%02d.%02d,%s",
+        snprintf(line,len,"Dialogue: %s,%d:%02d:%02d.%02d,%d:%02d:%02d.%02d,%s\r\n",
                  layer, sh, sm, ss, sc, eh, em, es, ec, ptr);
         av_free(pkt->data);
         pkt->data = line;
@@ -964,6 +965,15 @@ static void matroska_fix_ass_packet(MatroskaDemuxContext *matroska,
     }
 }
 
+static void matroska_merge_packets(AVPacket *out, AVPacket *in)
+{
+    out->data = av_realloc(out->data, out->size+in->size);
+    memcpy(out->data+out->size, in->data, in->size);
+    out->size += in->size;
+    av_destruct_packet(in);
+    av_free(in);
+}
+
 static void matroska_convert_tags(AVFormatContext *s, EbmlList *list)
 {
     MatroskaTag *tags = list->elem;
@@ -1621,15 +1631,23 @@ static int matroska_parse_block(MatroskaDemuxContext *matroska, uint8_t *data,
 
                 pkt->pts = timecode;
                 pkt->pos = pos;
-                if (track->type == MATROSKA_TRACK_TYPE_SUBTITLE)
+                if (st->codec->codec_id == CODEC_ID_TEXT)
                     pkt->convergence_duration = duration;
-                else
+                else if (track->type != MATROSKA_TRACK_TYPE_SUBTITLE)
                     pkt->duration = duration;
 
                 if (st->codec->codec_id == CODEC_ID_SSA)
-                    matroska_fix_ass_packet(matroska, pkt);
-
+                    matroska_fix_ass_packet(matroska, pkt, duration);
+
+                if (matroska->prev_pkt &&
+                    timecode != AV_NOPTS_VALUE &&
+                    matroska->prev_pkt->pts == timecode &&
+                    matroska->prev_pkt->stream_index == st->index)
+                    matroska_merge_packets(matroska->prev_pkt, pkt);
+                else {
                 dynarray_add(&matroska->packets, &matroska->num_packets, pkt);
+                    matroska->prev_pkt = pkt;
+                }
             }
 
             if (timecode != AV_NOPTS_VALUE)
@@ -1649,6 +1667,7 @@ static int matroska_parse_cluster(MatroskaDemuxContext *matroska)
     MatroskaBlock *blocks;
     int i, res;
     offset_t pos = url_ftell(matroska->ctx->pb);
+    matroska->prev_pkt = NULL;
     if (matroska->has_cluster_id){
         /* For the first cluster we parse, its ID was already read as
            part of matroska_read_header(), so don't read it again */
@@ -1693,12 +1712,12 @@ static int matroska_read_seek(AVFormatContext *s, int stream_index,
     AVStream *st = s->streams[stream_index];
     int i, index, index_sub, index_min;
 
-    if (timestamp < 0)
-        timestamp = 0;
+    if (!st->nb_index_entries)
+        return 0;
+    timestamp = FFMAX(timestamp, st->index_entries[0].timestamp);
 
     if ((index = av_index_search_timestamp(st, timestamp, flags)) < 0) {
-        if (st->nb_index_entries)
-            url_fseek(s->pb, st->index_entries[st->nb_index_entries-1].pos, SEEK_SET);
+        url_fseek(s->pb, st->index_entries[st->nb_index_entries-1].pos, SEEK_SET);
         while ((index = av_index_search_timestamp(st, timestamp, flags)) < 0) {
             matroska_clear_queue(matroska);
             if (matroska_parse_cluster(matroska) < 0)