summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJohn Stebbins <[email protected]>2015-11-10 12:40:54 -0800
committerJohn Stebbins <[email protected]>2015-11-10 12:40:54 -0800
commit6fd35381a879def5e76f99cded43a2a3c265c333 (patch)
tree55c62a71ff3bdf65ed5e3ff95af2be9995a3627a
parent598a40fc53002a9f5adeba8fc45e4f7a42df2e25 (diff)
libhb: repair split packets in reader
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.
-rw-r--r--libhb/common.c21
-rw-r--r--libhb/common.h2
-rw-r--r--libhb/internal.h1
-rw-r--r--libhb/reader.c80
-rw-r--r--libhb/stream.c4
5 files changed, 107 insertions, 1 deletions
diff --git a/libhb/common.c b/libhb/common.c
index 3e91635be..5f40b217d 100644
--- a/libhb/common.c
+++ b/libhb/common.c
@@ -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
**********************************************************************
diff --git a/libhb/common.h b/libhb/common.h
index 92d911320..d38e4fce5 100644
--- a/libhb/common.h
+++ b/libhb/common.h
@@ -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 * );
diff --git a/libhb/internal.h b/libhb/internal.h
index 79a01dd9b..d4014dca0 100644
--- a/libhb/internal.h
+++ b/libhb/internal.h
@@ -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
diff --git a/libhb/reader.c b/libhb/reader.c
index 0c6f6d853..d58271b56 100644
--- a/libhb/reader.c
+++ b/libhb/reader.c
@@ -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;
+}
diff --git a/libhb/stream.c b/libhb/stream.c
index 3ddba0256..caa998a07 100644
--- a/libhb/stream.c
+++ b/libhb/stream.c
@@ -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);