]> granicus.if.org Git - handbrake/commitdiff
libhb: repair split packets in reader
authorJohn Stebbins <jstebbins.hb@gmail.com>
Tue, 10 Nov 2015 20:40:54 +0000 (12:40 -0800)
committerJohn Stebbins <jstebbins.hb@gmail.com>
Tue, 10 Nov 2015 20:40:54 +0000 (12:40 -0800)
We split PES packets when there is a PCR change in the middle of the
packet.  This works fine for audio and video where the decoder parses
the ES to find frame boundaries.  But it does not work for some decoders
such as PGS subtitles.  So mark split buffers and reassemble them in
reader after processing the PCR change.

libhb/common.c
libhb/common.h
libhb/internal.h
libhb/reader.c
libhb/stream.c

index 3e91635be49f60eebe2ba8253d9c5f75f7155005..5f40b217d3313f3323bc918b6b01385dd844f890 100644 (file)
@@ -2592,6 +2592,7 @@ void hb_limit_rational64( int64_t *x, int64_t *y, int64_t num, int64_t den, int6
 void hb_buffer_list_append(hb_buffer_list_t *list, hb_buffer_t *buf)
 {
     int count = 1;
+    int size = 0;
     hb_buffer_t *end = buf;
 
     if (buf == NULL)
@@ -2600,8 +2601,10 @@ void hb_buffer_list_append(hb_buffer_list_t *list, hb_buffer_t *buf)
     }
 
     // Input buffer may be a list of buffers, find the end.
+    size += buf->size;
     while (end != NULL && end->next != NULL)
     {
+        size += end->size;
         end = end->next;
         count++;
     }
@@ -2616,11 +2619,13 @@ void hb_buffer_list_append(hb_buffer_list_t *list, hb_buffer_t *buf)
         list->tail = end;
     }
     list->count += count;
+    list->size += size;
 }
 
 void hb_buffer_list_prepend(hb_buffer_list_t *list, hb_buffer_t *buf)
 {
     int count = 1;
+    int size = 0;
     hb_buffer_t *end = buf;
 
     if (buf == NULL)
@@ -2629,8 +2634,10 @@ void hb_buffer_list_prepend(hb_buffer_list_t *list, hb_buffer_t *buf)
     }
 
     // Input buffer may be a list of buffers, find the end.
+    size += buf->size;
     while (end != NULL && end->next != NULL)
     {
+        size += end->size;
         end = end->next;
         count++;
     }
@@ -2645,6 +2652,7 @@ void hb_buffer_list_prepend(hb_buffer_list_t *list, hb_buffer_t *buf)
         list->head = buf;
     }
     list->count += count;
+    list->size += size;
 }
 
 hb_buffer_t* hb_buffer_list_rem_head(hb_buffer_list_t *list)
@@ -2662,6 +2670,7 @@ hb_buffer_t* hb_buffer_list_rem_head(hb_buffer_list_t *list)
         }
         list->head = list->head->next;
         list->count--;
+        list->size -= head->size;
     }
     if (head != NULL)
     {
@@ -2682,6 +2691,7 @@ hb_buffer_t* hb_buffer_list_rem_tail(hb_buffer_list_t *list)
     {
         list->head = list->tail = NULL;
         list->count = 0;
+        list->size = 0;
     }
     else if (list->tail != NULL)
     {
@@ -2693,6 +2703,7 @@ hb_buffer_t* hb_buffer_list_rem_tail(hb_buffer_list_t *list)
         end->next = NULL;
         list->tail = end;
         list->count--;
+        list->size -= tail->size;
     }
     if (tail != NULL)
     {
@@ -2722,6 +2733,7 @@ hb_buffer_t* hb_buffer_list_tail(hb_buffer_list_t *list)
 hb_buffer_t* hb_buffer_list_set(hb_buffer_list_t *list, hb_buffer_t *buf)
 {
     int count = 0;
+    int size = 0;
 
     if (list == NULL)
     {
@@ -2733,15 +2745,18 @@ hb_buffer_t* hb_buffer_list_set(hb_buffer_list_t *list, hb_buffer_t *buf)
     if (end != NULL)
     {
         count++;
+        size += end->size;
         while (end->next != NULL)
         {
             end = end->next;
             count++;
+            size += end->size;
         }
     }
     list->head = buf;
     list->tail = end;
     list->count = count;
+    list->size = size;
     return head;
 }
 
@@ -2754,6 +2769,7 @@ hb_buffer_t* hb_buffer_list_clear(hb_buffer_list_t *list)
     hb_buffer_t *head = list->head;
     list->head = list->tail = NULL;
     list->count = 0;
+    list->size = 0;
     return head;
 }
 
@@ -2768,6 +2784,11 @@ int hb_buffer_list_count(hb_buffer_list_t *list)
     return list->count;
 }
 
+int hb_buffer_list_size(hb_buffer_list_t *list)
+{
+    return list->size;
+}
+
 /**********************************************************************
  * hb_list implementation
  **********************************************************************
index 92d911320b25b17c753eba28308b1c33f2107252..d38e4fce556c55c585d6fe6a729fd5e4554c3432 100644 (file)
@@ -144,6 +144,7 @@ struct hb_buffer_list_s
     hb_buffer_t *head;
     hb_buffer_t *tail;
     int count;
+    int size;
 };
 
 void hb_buffer_list_append(hb_buffer_list_t *list, hb_buffer_t *buf);
@@ -156,6 +157,7 @@ hb_buffer_t* hb_buffer_list_clear(hb_buffer_list_t *list);
 hb_buffer_t* hb_buffer_list_set(hb_buffer_list_t *list, hb_buffer_t *buf);
 void hb_buffer_list_close(hb_buffer_list_t *list);
 int hb_buffer_list_count(hb_buffer_list_t *list);
+int hb_buffer_list_size(hb_buffer_list_t *list);
 
 hb_list_t * hb_list_init();
 int         hb_list_count( const hb_list_t * );
index 79a01dd9b90bb6c2912df4469a0da1c87bab3eec..d4014dca06dd4aa9f3da630d0705417099b468c5 100644 (file)
@@ -71,6 +71,7 @@ struct hb_buffer_settings_s
     int64_t       stop;         // stop time of frame
     int64_t       renderOffset; // DTS used by b-frame offsets in muxmp4
     int64_t       pcr;
+    int           split;
     uint8_t       discontinuity;
     int           new_chap;     // Video packets: if non-zero, is the index of the chapter whose boundary was crossed
 
index 0c6f6d85384361de3b67be9d39cb082af57e0a83..d58271b56464766a36d670fc50577ebc753f224d 100644 (file)
@@ -36,6 +36,12 @@ typedef struct
     int valid;      // Stream timing is not valid until next scr.
 } stream_timing_t;
 
+typedef struct
+{
+    int              id;
+    hb_buffer_list_t list;
+} buffer_splice_list_t;
+
 struct hb_work_private_s
 {
     hb_handle_t  * h;
@@ -63,6 +69,9 @@ struct hb_work_private_s
     uint64_t       st_first;
     uint64_t       duration;
     hb_fifo_t    * fifos[100];
+
+    buffer_splice_list_t * splice_list;
+    int                    splice_list_size;
 };
 
 /***********************************************************************
@@ -70,6 +79,7 @@ struct hb_work_private_s
  **********************************************************************/
 static hb_fifo_t ** GetFifoForId( hb_work_private_t * r, int id );
 static void UpdateState( hb_work_private_t  * r, int64_t start);
+static hb_buffer_list_t * get_splice_list(hb_work_private_t * r, int id);
 
 /***********************************************************************
  * reader_init
@@ -250,6 +260,28 @@ static int reader_init( hb_work_object_t * w, hb_job_t * job )
         }
     }
 
+    // Count number of splice lists needed for merging buffers
+    // that have been split
+    int count = 1; // 1 for video
+    count += hb_list_count( job->list_subtitle );
+    count += hb_list_count( job->list_audio );
+    r->splice_list_size = count;
+    r->splice_list = calloc(count, sizeof(buffer_splice_list_t));
+
+    // Initialize stream id's of splice lists
+    int ii, jj = 0;
+    r->splice_list[jj++].id = r->title->video_id;
+    for (ii = 0; ii < hb_list_count(job->list_subtitle); ii++)
+    {
+        hb_subtitle_t * subtitle = hb_list_item(job->list_subtitle, ii);
+        r->splice_list[jj++].id = subtitle->id;
+    }
+    for (ii = 0; ii < hb_list_count(job->list_audio); ii++)
+    {
+        hb_audio_t * audio = hb_list_item(job->list_audio, ii);
+        r->splice_list[jj++].id = audio->id;
+    }
+
     // The stream needs to be open before starting the reader thead
     // to prevent a race with decoders that may share information
     // with the reader. Specifically avcodec needs this.
@@ -290,8 +322,41 @@ static void reader_close( hb_work_object_t * w )
     free( r );
 }
 
-static void push_buf( const hb_work_private_t *r, hb_fifo_t *fifo, hb_buffer_t *buf )
+static void push_buf( hb_work_private_t *r, hb_fifo_t *fifo, hb_buffer_t *buf )
 {
+    // Handle buffers that were split across a PCR discontinuity.
+    // Rejoin them into a single buffer.
+    hb_buffer_list_t * list = get_splice_list(r, buf->s.id);
+    if (list != NULL)
+    {
+        hb_buffer_list_append(list, buf);
+        if (buf->s.split)
+        {
+            return;
+        }
+
+        int count = hb_buffer_list_count(list);
+        if (count > 1)
+        {
+            int size = hb_buffer_list_size(list);
+            hb_buffer_t * b = hb_buffer_init(size);
+            buf = hb_buffer_list_head(list);
+            b->s = buf->s;
+
+            int pos = 0;
+            while ((buf = hb_buffer_list_rem_head(list)) != NULL)
+            {
+                memcpy(b->data + pos, buf->data, buf->size);
+                pos += buf->size;
+                hb_buffer_close(&buf);
+            }
+            buf = b;
+        }
+        else
+        {
+            buf = hb_buffer_list_clear(list);
+        }
+    }
     while ( !*r->die && !r->job->done )
     {
         if ( hb_fifo_full_wait( fifo ) )
@@ -853,3 +918,16 @@ static hb_fifo_t ** GetFifoForId( hb_work_private_t * r, int id )
     return NULL;
 }
 
+static hb_buffer_list_t * get_splice_list(hb_work_private_t * r, int id)
+{
+    int ii;
+
+    for (ii = 0; ii < r->splice_list_size; ii++)
+    {
+        if (r->splice_list[ii].id == id)
+        {
+            return &r->splice_list[ii].list;
+        }
+    }
+    return NULL;
+}
index 3ddba0256520a0e7be04e718d9fd793be6b325c1..caa998a0752dc88319eb5dcb64af7b286bd454d7 100644 (file)
@@ -4537,6 +4537,10 @@ static hb_buffer_t * generate_output_data(hb_stream_t *stream, int curstream)
         // DTS-HD is an example of this.
 
         buf = hb_buffer_init(es_size);
+        if (ts_stream->packet_len < ts_stream->pes_info.packet_len + 6)
+        {
+            buf->s.split = 1;
+        }
         hb_buffer_list_append(&list, buf);
 
         buf->s.id = get_id(pes_stream);