summaryrefslogtreecommitdiffstats
path: root/libhb
diff options
context:
space:
mode:
authorJohn Stebbins <[email protected]>2016-05-17 11:51:25 -0600
committerJohn Stebbins <[email protected]>2016-05-17 11:51:25 -0600
commitde858d1600ac61258dc895b2fc8756b7c5d1d3a8 (patch)
treecdbd82e3d9ee83cfb9a31ebbb034852aa36fb2cb /libhb
parent9dcce9df07f4db1fa61f25ffeb106aa00bd64190 (diff)
libhb: send initial chapter through pipeline
Eliminate the need for everyone to assume that the first chapter starts at the first frame.
Diffstat (limited to 'libhb')
-rw-r--r--libhb/bd.c28
-rw-r--r--libhb/common.c73
-rw-r--r--libhb/decavcodec.c8
-rw-r--r--libhb/dvd.c18
-rw-r--r--libhb/dvd.h1
-rw-r--r--libhb/dvdnav.c13
-rw-r--r--libhb/enc_qsv.c138
-rw-r--r--libhb/encavcodec.c45
-rw-r--r--libhb/encx264.c179
-rw-r--r--libhb/internal.h19
-rw-r--r--libhb/muxavformat.c54
-rw-r--r--libhb/stream.c59
12 files changed, 316 insertions, 319 deletions
diff --git a/libhb/bd.c b/libhb/bd.c
index c153f5ab6..16f79dc4c 100644
--- a/libhb/bd.c
+++ b/libhb/bd.c
@@ -636,7 +636,8 @@ int hb_bd_start( hb_bd_t * d, hb_title_t *title )
// Calling bd_get_event initializes libbluray event queue.
bd_select_title( d->bd, d->title_info[title->index - 1]->idx );
bd_get_event( d->bd, &event );
- d->chapter = 1;
+ d->chapter = 0;
+ d->next_chap = 1;
d->stream = hb_bd_stream_open( d->h, title );
if ( d->stream == NULL )
{
@@ -700,15 +701,10 @@ hb_buffer_t * hb_bd_read( hb_bd_t * d )
uint64_t pos;
hb_buffer_t * out = NULL;
uint8_t discontinuity;
- int new_chap = 0;
while ( 1 )
{
discontinuity = 0;
- if ( d->next_chap != d->chapter )
- {
- new_chap = d->chapter = d->next_chap;
- }
result = next_packet( d->bd, buf );
if ( result < 0 )
{
@@ -737,7 +733,10 @@ hb_buffer_t * hb_bd_read( hb_bd_t * d )
case BD_EVENT_CHAPTER:
// The muxers expect to only get chapter 2 and above
// They write chapter 1 when chapter 2 is detected.
- d->next_chap = event.param;
+ if (event.param > d->chapter)
+ {
+ d->next_chap = event.param;
+ }
break;
case BD_EVENT_PLAYITEM:
@@ -754,10 +753,19 @@ hb_buffer_t * hb_bd_read( hb_bd_t * d )
}
}
// buf+4 to skip the BD timestamp at start of packet
- out = hb_ts_decode_pkt( d->stream, buf+4, new_chap, discontinuity );
+ if (d->chapter != d->next_chap)
+ {
+ d->chapter = d->next_chap;
+ out = hb_ts_decode_pkt(d->stream, buf+4, d->chapter, discontinuity);
+ }
+ else
+ {
+ out = hb_ts_decode_pkt(d->stream, buf+4, 0, discontinuity);
+ }
if (out != NULL)
+ {
return out;
- new_chap = 0;
+ }
}
return NULL;
}
@@ -770,7 +778,7 @@ hb_buffer_t * hb_bd_read( hb_bd_t * d )
**********************************************************************/
int hb_bd_chapter( hb_bd_t * d )
{
- return d->next_chap;
+ return d->chapter;
}
/***********************************************************************
diff --git a/libhb/common.c b/libhb/common.c
index f282bbbcf..0310eeeac 100644
--- a/libhb/common.c
+++ b/libhb/common.c
@@ -5361,3 +5361,76 @@ void hb_str_vfree( char **strv )
free( strv );
}
+hb_chapter_queue_t * hb_chapter_queue_init(void)
+{
+ hb_chapter_queue_t * q;
+
+ q = calloc(1, sizeof(*q));
+ if (q != NULL)
+ {
+ q->list_chapter = hb_list_init();
+ if (q->list_chapter == NULL)
+ {
+ free(q);
+ q = NULL;
+ }
+ }
+ return q;
+}
+
+void hb_chapter_queue_close(hb_chapter_queue_t **_q)
+{
+ hb_chapter_queue_t * q = *_q;
+ hb_chapter_queue_item_t * item;
+
+ if (q == NULL)
+ {
+ return;
+ }
+ while ((item = hb_list_item(q->list_chapter, 0)) != NULL)
+ {
+ hb_list_rem(q->list_chapter, item);
+ free(item);
+ }
+ hb_list_close(&q->list_chapter);
+ free(q);
+ *_q = NULL;
+}
+
+void hb_chapter_enqueue(hb_chapter_queue_t *q, hb_buffer_t *buf)
+{
+ /*
+ * Chapter markers are sometimes so close we can get a new
+ * one before the previous goes through the encoding queue.
+ *
+ * Dropping markers can cause weird side-effects downstream,
+ * including but not limited to missing chapters in the
+ * output, so we need to save it somehow.
+ */
+ hb_chapter_queue_item_t *item = malloc(sizeof(hb_chapter_queue_item_t));
+ if (item != NULL)
+ {
+ item->start = buf->s.start;
+ item->new_chap = buf->s.new_chap;
+ hb_list_add(q->list_chapter, item);
+ }
+}
+
+void hb_chapter_dequeue(hb_chapter_queue_t *q, hb_buffer_t *buf)
+{
+ hb_chapter_queue_item_t *item = hb_list_item(q->list_chapter, 0);
+ if (item != NULL)
+ {
+ if (buf->s.start < item->start)
+ {
+ // Have not reached the next chapter yet.
+ return;
+ }
+
+ // we're done with this chapter
+ hb_list_rem(q->list_chapter, item);
+ buf->s.new_chap = item->new_chap;
+ free(item);
+ }
+}
+
diff --git a/libhb/decavcodec.c b/libhb/decavcodec.c
index bc6637143..f20afb2e9 100644
--- a/libhb/decavcodec.c
+++ b/libhb/decavcodec.c
@@ -1345,10 +1345,6 @@ static int decodeFrame( hb_work_object_t *w, uint8_t *data, int size, int sequen
pv->new_chap = 0;
pv->chap_time = 0;
}
- else if ( pv->nframes == 0 && pv->job )
- {
- log_chapter( pv, pv->job->chapter_start, buf->s.start );
- }
checkCadence( pv->cadence, flags, buf->s.start );
hb_buffer_list_append(&pv->list, buf);
++pv->nframes;
@@ -1389,10 +1385,6 @@ static int decodeFrame( hb_work_object_t *w, uint8_t *data, int size, int sequen
pv->new_chap = 0;
pv->chap_time = 0;
}
- else if ( pv->nframes == 0 && pv->job )
- {
- log_chapter( pv, pv->job->chapter_start, buf->s.start );
- }
checkCadence( pv->cadence, buf->s.flags, buf->s.start );
hb_buffer_list_append(&pv->list, buf);
}
diff --git a/libhb/dvd.c b/libhb/dvd.c
index 7255aec74..ab06efd3a 100644
--- a/libhb/dvd.c
+++ b/libhb/dvd.c
@@ -1056,11 +1056,7 @@ static hb_buffer_t * hb_dvdread_read( hb_dvd_t * e )
d->cur_vob_id = dsi_pack.dsi_gi.vobu_vob_idn;
d->cur_cell_id = dsi_pack.dsi_gi.vobu_c_idn;
- if( d->cell_overlap )
- {
- b->s.new_chap = hb_dvdread_is_break( d );
- d->cell_overlap = 0;
- }
+ d->cell_overlap = 0;
}
}
@@ -1095,6 +1091,10 @@ static hb_buffer_t * hb_dvdread_read( hb_dvd_t * e )
}
d->pack_len--;
}
+ if (b != NULL)
+ {
+ b->s.new_chap = hb_dvdread_is_break( d );
+ }
d->block++;
@@ -1149,9 +1149,7 @@ static int hb_dvdread_is_break( hb_dvdread_t * d )
pgc_t * pgc;
int cell;
- for( i = nr_of_ptts - 1;
- i > 0;
- i-- )
+ for (i = nr_of_ptts - 1; i >= 0; i--)
{
/* Get pgc for chapter (i+1) */
pgc_id = d->ifo->vts_ptt_srpt->title[d->ttn-1].ptt[i].pgcn;
@@ -1159,11 +1157,11 @@ static int hb_dvdread_is_break( hb_dvdread_t * d )
pgc = d->ifo->vts_pgcit->pgci_srp[pgc_id-1].pgc;
cell = pgc->program_map[pgn-1] - 1;
- if( cell <= d->cell_start )
+ if( cell < d->cell_start )
break;
// This must not match against the start cell.
- if( pgc->cell_playback[cell].first_sector == d->block && cell != d->cell_start )
+ if (pgc->cell_playback[cell].first_sector == d->block)
{
return i + 1;
}
diff --git a/libhb/dvd.h b/libhb/dvd.h
index 55ddb66b9..f5e904433 100644
--- a/libhb/dvd.h
+++ b/libhb/dvd.h
@@ -43,6 +43,7 @@ struct hb_dvdread_s
uint16_t cur_vob_id;
uint8_t cur_cell_id;
hb_handle_t * h;
+ int chapter;
};
struct hb_dvdnav_s
diff --git a/libhb/dvdnav.c b/libhb/dvdnav.c
index e2a472cb5..6075a8ee6 100644
--- a/libhb/dvdnav.c
+++ b/libhb/dvdnav.c
@@ -1646,11 +1646,7 @@ static hb_buffer_t * hb_dvdnav_read( hb_dvd_t * e )
case DVDNAV_BLOCK_OK:
// We have received a regular block of the currently playing
// MPEG stream.
-
- // The muxers expect to only get chapter 2 and above
- // They write chapter 1 when chapter 2 is detected.
- if (chapter > 1)
- b->s.new_chap = chapter;
+ b->s.new_chap = chapter;
chapter = 0;
error_count = 0;
return b;
@@ -1791,12 +1787,7 @@ static hb_buffer_t * hb_dvdnav_read( hb_dvd_t * e )
// mpegdemux expects to get these. I don't think it does
// anything useful with them however.
-
- // The muxers expect to only get chapter 2 and above
- // They write chapter 1 when chapter 2 is detected.
- if (chapter > 1)
- b->s.new_chap = chapter;
- chapter = 0;
+ b->s.new_chap = chapter;
return b;
break;
diff --git a/libhb/enc_qsv.c b/libhb/enc_qsv.c
index 5e1a77824..4030cd30c 100644
--- a/libhb/enc_qsv.c
+++ b/libhb/enc_qsv.c
@@ -67,51 +67,43 @@ hb_work_object_t hb_encqsv =
struct hb_work_private_s
{
- hb_job_t * job;
- uint32_t frames_in;
- uint32_t frames_out;
- int64_t last_start;
+ hb_job_t * job;
+ uint32_t frames_in;
+ uint32_t frames_out;
+ int64_t last_start;
- hb_qsv_param_t param;
- av_qsv_space enc_space;
- hb_qsv_info_t * qsv_info;
+ hb_qsv_param_t param;
+ av_qsv_space enc_space;
+ hb_qsv_info_t * qsv_info;
- hb_list_t * delayed_chapters;
- int64_t next_chapter_pts;
+ hb_chapter_queue_t * chapter_queue;
#define BFRM_DELAY_MAX 16
- int * init_delay;
- int bfrm_delay;
- int64_t init_pts[BFRM_DELAY_MAX + 1];
- hb_list_t * list_dts;
+ int * init_delay;
+ int bfrm_delay;
+ int64_t init_pts[BFRM_DELAY_MAX + 1];
+ hb_list_t * list_dts;
- int64_t frame_duration[FRAME_INFO_SIZE];
+ int64_t frame_duration[FRAME_INFO_SIZE];
- int async_depth;
- int max_async_depth;
+ int async_depth;
+ int max_async_depth;
// if encode-only, system memory used
- int is_sys_mem;
- mfxSession mfx_session;
- struct SwsContext * sws_context_to_nv12;
+ int is_sys_mem;
+ mfxSession mfx_session;
+ struct SwsContext * sws_context_to_nv12;
// whether to expect input from VPP or from QSV decode
- int is_vpp_present;
+ int is_vpp_present;
// whether the encoder is initialized
- int init_done;
+ int init_done;
- hb_list_t * delayed_processing;
- hb_buffer_list_t encoded_frames;
+ hb_list_t * delayed_processing;
+ hb_buffer_list_t encoded_frames;
- hb_list_t * loaded_plugins;
-};
-
-// used in delayed_chapters list
-struct chapter_s
-{
- int index;
- int64_t start;
+ hb_list_t * loaded_plugins;
};
static void hb_qsv_add_new_dts(hb_list_t *list, int64_t new_dts)
@@ -683,8 +675,7 @@ int encqsvInit(hb_work_object_t *w, hb_job_t *job)
pv->last_start = INT64_MIN;
hb_buffer_list_clear(&pv->encoded_frames);
- pv->next_chapter_pts = AV_NOPTS_VALUE;
- pv->delayed_chapters = hb_list_init();
+ pv->chapter_queue = hb_chapter_queue_init();
// default encoding parameters
if (hb_qsv_param_default_preset(&pv->param, &pv->enc_space.m_mfxVideoParam,
@@ -1486,6 +1477,7 @@ void encqsvClose(hb_work_object_t *w)
if (pv != NULL)
{
+ hb_chapter_queue_close(&pv->chapter_queue);
if (pv->delayed_processing != NULL)
{
/* the list is already empty */
@@ -1505,16 +1497,6 @@ void encqsvClose(hb_work_object_t *w)
}
hb_list_close(&pv->list_dts);
}
- if (pv->delayed_chapters != NULL)
- {
- struct chapter_s *item;
- while ((item = hb_list_item(pv->delayed_chapters, 0)) != NULL)
- {
- hb_list_rem(pv->delayed_chapters, item);
- free(item);
- }
- hb_list_close(&pv->delayed_chapters);
- }
hb_buffer_list_close(&pv->encoded_frames);
}
@@ -1522,68 +1504,6 @@ void encqsvClose(hb_work_object_t *w)
w->private_data = NULL;
}
-static void save_chapter(hb_work_private_t *pv, hb_buffer_t *buf)
-{
- /*
- * Since there may be several frames buffered in the encoder, remember the
- * timestamp so when this frame finally pops out of the encoder we'll mark
- * its buffer as the start of a chapter.
- */
- if (pv->next_chapter_pts == AV_NOPTS_VALUE)
- {
- pv->next_chapter_pts = buf->s.start;
- }
-
- /*
- * Chapter markers are sometimes so close we can get a new
- * one before the previous goes through the encoding queue.
- *
- * Dropping markers can cause weird side-effects downstream,
- * including but not limited to missing chapters in the
- * output, so we need to save it somehow.
- */
- struct chapter_s *item = malloc(sizeof(struct chapter_s));
-
- if (item != NULL)
- {
- item->start = buf->s.start;
- item->index = buf->s.new_chap;
- hb_list_add(pv->delayed_chapters, item);
- }
-
- /* don't let 'work_loop' put a chapter mark on the wrong buffer */
- buf->s.new_chap = 0;
-}
-
-static void restore_chapter(hb_work_private_t *pv, hb_buffer_t *buf)
-{
- /* we're no longer looking for this chapter */
- pv->next_chapter_pts = AV_NOPTS_VALUE;
-
- /* get the chapter index from the list */
- struct chapter_s *item = hb_list_item(pv->delayed_chapters, 0);
-
- if (item != NULL)
- {
- /* we're done with this chapter */
- hb_list_rem(pv->delayed_chapters, item);
- buf->s.new_chap = item->index;
- free(item);
-
- /* we may still have another pending chapter */
- item = hb_list_item(pv->delayed_chapters, 0);
-
- if (item != NULL)
- {
- /*
- * we're looking for this chapter now
- * we still need it, don't remove it
- */
- pv->next_chapter_pts = item->start;
- }
- }
-}
-
static void compute_init_delay(hb_work_private_t *pv, mfxBitstream *bs)
{
if (pv->init_delay == NULL)
@@ -1766,11 +1686,9 @@ static void qsv_bitstream_slurp(hb_work_private_t *pv, mfxBitstream *bs)
* If we have a chapter marker pending and this frame's PTS
* is at or after the marker's PTS, use it as the chapter start.
*/
- if (pv->next_chapter_pts != AV_NOPTS_VALUE &&
- pv->next_chapter_pts <= buf->s.start &&
- qsv_frame_is_key(bs->FrameType))
+ if (qsv_frame_is_key(bs->FrameType))
{
- restore_chapter(pv, buf);
+ hb_chapter_dequeue(pv->chapter_queue, buf);
}
hb_buffer_list_append(&pv->encoded_frames, buf);
@@ -2040,7 +1958,7 @@ int encqsvWork(hb_work_object_t *w, hb_buffer_t **buf_in, hb_buffer_t **buf_out)
goto fail;
}
- save_chapter(pv, in);
+ hb_chapter_enqueue(pv->chapter_queue, in);
}
/*
diff --git a/libhb/encavcodec.c b/libhb/encavcodec.c
index 129921d0b..59c787326 100644
--- a/libhb/encavcodec.c
+++ b/libhb/encavcodec.c
@@ -26,20 +26,22 @@
struct hb_work_private_s
{
- hb_job_t * job;
- AVCodecContext * context;
- FILE * file;
+ hb_job_t * job;
+ AVCodecContext * context;
+ FILE * file;
- int frameno_in;
- int frameno_out;
- hb_buffer_list_t delay_list;
+ int frameno_in;
+ int frameno_out;
+ hb_buffer_list_t delay_list;
- int64_t dts_delay;
+ int64_t dts_delay;
struct {
- int64_t start;
- int64_t duration;
+ int64_t start;
+ int64_t duration;
} frame_info[FRAME_INFO_SIZE];
+
+ hb_chapter_queue_t * chapter_queue;
};
int encavcodecInit( hb_work_object_t *, hb_job_t * );
@@ -62,8 +64,9 @@ int encavcodecInit( hb_work_object_t * w, hb_job_t * job )
AVRational fps;
hb_work_private_t * pv = calloc( 1, sizeof( hb_work_private_t ) );
- w->private_data = pv;
- pv->job = job;
+ w->private_data = pv;
+ pv->job = job;
+ pv->chapter_queue = hb_chapter_queue_init();
hb_buffer_list_clear(&pv->delay_list);
@@ -319,6 +322,11 @@ void encavcodecClose( hb_work_object_t * w )
{
hb_work_private_t * pv = w->private_data;
+ if (pv == NULL)
+ {
+ return;
+ }
+ hb_chapter_queue_close(&pv->chapter_queue);
if( pv->context && pv->context->codec )
{
hb_deep_log( 2, "encavcodec: closing libavcodec" );
@@ -513,6 +521,17 @@ int encavcodecWork( hb_work_object_t * w, hb_buffer_t ** buf_in,
frame->linesize[1] = in->plane[1].stride;
frame->linesize[2] = in->plane[2].stride;
+ if (in->s.new_chap > 0 && job->chapter_markers)
+ {
+ /* chapters have to start with an IDR frame so request that this
+ frame be coded as IDR. Since there may be multiple frames
+ currently buffered in the encoder remember the timestamp so
+ when this frame finally pops out of the encoder we'll mark
+ its buffer as the start of a chapter. */
+ frame->pict_type = AV_PICTURE_TYPE_I;
+ hb_chapter_enqueue(pv->chapter_queue, in);
+ }
+
// For constant quality, setting the quality in AVCodecContext
// doesn't do the trick. It must be set in the AVFrame.
frame->quality = pv->context->global_quality;
@@ -558,6 +577,10 @@ int encavcodecWork( hb_work_object_t * w, hb_buffer_t ** buf_in,
buf->s.stop = buf->s.stop + buf->s.duration;
buf->s.flags &= ~HB_FRAME_REF;
buf->s.frametype = convert_pict_type( pv->context->coded_frame->pict_type, pkt.flags & AV_PKT_FLAG_KEY, &buf->s.flags );
+ if (buf->s.frametype & HB_FRAME_KEY)
+ {
+ hb_chapter_dequeue(pv->chapter_queue, buf);
+ }
buf = process_delay_list( pv, buf );
hb_buffer_list_append(&list, buf);
diff --git a/libhb/encx264.c b/libhb/encx264.c
index 30cee1096..50f7fe197 100644
--- a/libhb/encx264.c
+++ b/libhb/encx264.c
@@ -48,34 +48,27 @@ hb_work_object_t hb_encx264 =
struct hb_work_private_s
{
- hb_job_t * job;
- x264_t * x264;
- x264_picture_t pic_in;
+ hb_job_t * job;
+ x264_t * x264;
+ x264_picture_t pic_in;
- int64_t last_stop; // Debugging - stop time of previous input frame
+ int64_t last_stop; // Debugging - stop time of previous input frame
+
+ hb_chapter_queue_t * chapter_queue;
- hb_list_t * delayed_chapters;
- int64_t next_chapter_pts;
struct {
- int64_t duration;
+ int64_t duration;
} frame_info[FRAME_INFO_SIZE];
- char filename[1024];
+ char filename[1024];
// Multiple bit-depth
- const x264_api_t * api;
+ const x264_api_t * api;
};
#define HB_X264_API_COUNT 2
static x264_api_t x264_apis[HB_X264_API_COUNT];
-// used in delayed_chapters list
-struct chapter_s
-{
- int index;
- int64_t start;
-};
-
const char *libx264_10bit_names[] = {
"libx26410b", "libx264_main10", NULL
};
@@ -313,12 +306,12 @@ int encx264Init( hb_work_object_t * w, hb_job_t * job )
if (pv->api == NULL)
{
hb_error("encx264: hb_x264_api_get failed, bit-depth %d", bit_depth);
+ return 1;
}
pv->job = job;
- pv->next_chapter_pts = AV_NOPTS_VALUE;
pv->last_stop = AV_NOPTS_VALUE;
- pv->delayed_chapters = hb_list_init();
+ pv->chapter_queue = hb_chapter_queue_init();
if (pv->api->param_default_preset(&param,
job->encoder_preset, job->encoder_tune) < 0)
@@ -613,22 +606,12 @@ void encx264Close( hb_work_object_t * w )
// Not initialized
return;
}
- if (pv->delayed_chapters != NULL)
- {
- struct chapter_s *item;
- while ((item = hb_list_item(pv->delayed_chapters, 0)) != NULL)
- {
- hb_list_rem(pv->delayed_chapters, item);
- free(item);
- }
- hb_list_close(&pv->delayed_chapters);
- }
+
+ hb_chapter_queue_close(&pv->chapter_queue);
pv->api->encoder_close( pv->x264 );
free( pv );
w->private_data = NULL;
-
- /* TODO */
}
/*
@@ -669,6 +652,50 @@ static hb_buffer_t *nal_encode( hb_work_object_t *w, x264_picture_t *pic_out,
w->config->h264.init_delay = -pic_out->i_dts;
}
+ /* Decide what type of frame we have. */
+ switch( pic_out->i_type )
+ {
+ case X264_TYPE_IDR:
+ // Handled in b_keyframe check below.
+ break;
+
+ case X264_TYPE_I:
+ buf->s.frametype = HB_FRAME_I;
+ break;
+
+ case X264_TYPE_P:
+ buf->s.frametype = HB_FRAME_P;
+ break;
+
+ case X264_TYPE_B:
+ buf->s.frametype = HB_FRAME_B;
+ break;
+
+ /* This is for b-pyramid, which has reference b-frames
+ However, it doesn't seem to ever be used... */
+ case X264_TYPE_BREF:
+ buf->s.frametype = HB_FRAME_BREF;
+ break;
+
+ // If it isn't the above, what type of frame is it??
+ default:
+ buf->s.frametype = 0;
+ break;
+ }
+
+ // PIR has no IDR frames, but x264 marks recovery points
+ // as keyframes. So fake an IDR at these points. This flag
+ // is also set for real IDR frames.
+ if (pic_out->b_keyframe)
+ {
+ buf->s.frametype = HB_FRAME_IDR;
+ /* if we have a chapter marker pending and this
+ frame's presentation time stamp is at or after
+ the marker's time stamp, use this as the
+ chapter start. */
+ hb_chapter_dequeue(pv->chapter_queue, buf);
+ }
+
/* Encode all the NALs we were given into buf.
NOTE: This code assumes one video frame per NAL (but there can
be other stuff like SPS and/or PPS). If there are multiple
@@ -701,37 +728,6 @@ static hb_buffer_t *nal_encode( hb_work_object_t *w, x264_picture_t *pic_out,
break;
}
- /* Decide what type of frame we have. */
- switch( pic_out->i_type )
- {
- case X264_TYPE_IDR:
- // Handled in b_keyframe check below.
- break;
-
- case X264_TYPE_I:
- buf->s.frametype = HB_FRAME_I;
- break;
-
- case X264_TYPE_P:
- buf->s.frametype = HB_FRAME_P;
- break;
-
- case X264_TYPE_B:
- buf->s.frametype = HB_FRAME_B;
- break;
-
- /* This is for b-pyramid, which has reference b-frames
- However, it doesn't seem to ever be used... */
- case X264_TYPE_BREF:
- buf->s.frametype = HB_FRAME_BREF;
- break;
-
- // If it isn't the above, what type of frame is it??
- default:
- buf->s.frametype = 0;
- break;
- }
-
/* Since libx264 doesn't tell us when b-frames are
themselves reference frames, figure it out on our own. */
if( (buf->s.frametype == HB_FRAME_B) &&
@@ -744,43 +740,6 @@ static hb_buffer_t *nal_encode( hb_work_object_t *w, x264_picture_t *pic_out,
else
buf->s.flags |= HB_FRAME_REF;
- // PIR has no IDR frames, but x264 marks recovery points
- // as keyframes. So fake an IDR at these points. This flag
- // is also set for real IDR frames.
- if( pic_out->b_keyframe )
- {
- buf->s.frametype = HB_FRAME_IDR;
- /* if we have a chapter marker pending and this
- frame's presentation time stamp is at or after
- the marker's time stamp, use this as the
- chapter start. */
- if (pv->next_chapter_pts != AV_NOPTS_VALUE &&
- pv->next_chapter_pts <= pic_out->i_pts)
- {
- // we're no longer looking for this chapter
- pv->next_chapter_pts = AV_NOPTS_VALUE;
-
- // get the chapter index from the list
- struct chapter_s *item = hb_list_item(pv->delayed_chapters, 0);
- if (item != NULL)
- {
- // we're done with this chapter
- buf->s.new_chap = item->index;
- hb_list_rem(pv->delayed_chapters, item);
- free(item);
-
- // we may still have another pending chapter
- item = hb_list_item(pv->delayed_chapters, 0);
- if (item != NULL)
- {
- // we're looking for this one now
- // we still need it, don't remove it
- pv->next_chapter_pts = item->start;
- }
- }
- }
- }
-
buf->size += size;
}
// make sure we found at least one video frame
@@ -845,7 +804,7 @@ static hb_buffer_t *x264_encode( hb_work_object_t *w, hb_buffer_t *in )
pv->pic_in.img.plane[2] = in->plane[2].data;
}
- if( in->s.new_chap && job->chapter_markers )
+ if( in->s.new_chap > 0 && job->chapter_markers )
{
/* chapters have to start with an IDR frame so request that this
frame be coded as IDR. Since there may be up to 16 frames
@@ -853,27 +812,7 @@ static hb_buffer_t *x264_encode( hb_work_object_t *w, hb_buffer_t *in )
when this frame finally pops out of the encoder we'll mark
its buffer as the start of a chapter. */
pv->pic_in.i_type = X264_TYPE_IDR;
- if (pv->next_chapter_pts == AV_NOPTS_VALUE)
- {
- pv->next_chapter_pts = in->s.start;
- }
- /*
- * Chapter markers are sometimes so close we can get a new one before the
- * previous marker has been through the encoding queue.
- *
- * Dropping markers can cause weird side-effects downstream, including but
- * not limited to missing chapters in the output, so we need to save it
- * somehow.
- */
- struct chapter_s *item = malloc(sizeof(struct chapter_s));
- if (item != NULL)
- {
- item->start = in->s.start;
- item->index = in->s.new_chap;
- hb_list_add(pv->delayed_chapters, item);
- }
- /* don't let 'work_loop' put a chapter mark on the wrong buffer */
- in->s.new_chap = 0;
+ hb_chapter_enqueue(pv->chapter_queue, in);
}
else
{
diff --git a/libhb/internal.h b/libhb/internal.h
index 4e477eba6..82012a7d7 100644
--- a/libhb/internal.h
+++ b/libhb/internal.h
@@ -509,3 +509,22 @@ void hb_muxmp4_process_subtitle_style( uint8_t *input,
void hb_deinterlace(hb_buffer_t *dst, hb_buffer_t *src);
void hb_avfilter_combine( hb_list_t * list );
+struct hb_chapter_queue_item_s
+{
+ int64_t start;
+ int new_chap;
+};
+
+struct hb_chapter_queue_s
+{
+ hb_list_t * list_chapter;
+};
+
+typedef struct hb_chapter_queue_item_s hb_chapter_queue_item_t;
+typedef struct hb_chapter_queue_s hb_chapter_queue_t;
+
+hb_chapter_queue_t * hb_chapter_queue_init(void);
+void hb_chapter_queue_close(hb_chapter_queue_t **_q);
+void hb_chapter_enqueue(hb_chapter_queue_t *q, hb_buffer_t *b);
+void hb_chapter_dequeue(hb_chapter_queue_t *q, hb_buffer_t *b);
+
diff --git a/libhb/muxavformat.c b/libhb/muxavformat.c
index ef72130b6..0a69d83f8 100644
--- a/libhb/muxavformat.c
+++ b/libhb/muxavformat.c
@@ -197,7 +197,7 @@ static int avformatInit( hb_mux_object_t * m )
job->mux_data = track;
track->type = MUX_TYPE_VIDEO;
- track->prev_chapter_tc = 0;
+ track->prev_chapter_tc = AV_NOPTS_VALUE;
track->st = avformat_new_stream(m->oc, NULL);
if (track->st == NULL)
{
@@ -1156,33 +1156,37 @@ static int avformatMux(hb_mux_object_t *m, hb_mux_data_t *track, hb_buffer_t *bu
{
if (job->chapter_markers && buf->s.new_chap)
{
- hb_chapter_t *chapter;
-
- // reached chapter N, write marker for chapter N-1
- // we don't know the end time of chapter N-1 till we receive
- // chapter N. So we are always writing the previous chapter
- // mark.
- track->current_chapter = buf->s.new_chap - 1;
-
- // chapter numbers start at 1, but the list starts at 0
- chapter = hb_list_item(job->list_chapter,
- track->current_chapter - 1);
-
- // make sure we're not writing a chapter that has 0 length
- if (chapter != NULL && track->prev_chapter_tc < pkt.pts)
+ if (track->current_chapter > 0)
{
- char title[1024];
- if (chapter->title != NULL)
- {
- snprintf(title, 1023, "%s", chapter->title);
- }
- else
+ hb_chapter_t *chapter;
+
+ // reached chapter N, write marker for chapter N-1
+ // we don't know the end time of chapter N-1 till we receive
+ // chapter N. So we are always writing the previous chapter
+ // mark.
+ // chapter numbers start at 1, but the list starts at 0
+ chapter = hb_list_item(job->list_chapter,
+ track->current_chapter - 1);
+
+ // make sure we're not writing a chapter that has 0 length
+ if (chapter != NULL &&
+ track->prev_chapter_tc != AV_NOPTS_VALUE &&
+ track->prev_chapter_tc < pkt.pts)
{
- snprintf(title, 1023, "Chapter %d",
- track->current_chapter);
+ char title[1024];
+ if (chapter->title != NULL)
+ {
+ snprintf(title, 1023, "%s", chapter->title);
+ }
+ else
+ {
+ snprintf(title, 1023, "Chapter %d",
+ track->current_chapter);
+ }
+ add_chapter(m, track->prev_chapter_tc, pkt.pts, title);
}
- add_chapter(m, track->prev_chapter_tc, pkt.pts, title);
}
+ track->current_chapter = buf->s.new_chap;
track->prev_chapter_tc = pkt.pts;
}
} break;
@@ -1362,7 +1366,7 @@ static int avformatEnd(hb_mux_object_t *m)
hb_chapter_t *chapter;
// get the last chapter
- chapter = hb_list_item(job->list_chapter, track->current_chapter++);
+ chapter = hb_list_item(job->list_chapter, track->current_chapter - 1);
// only write the last chapter marker if it lasts at least 1.5 second
if (chapter != NULL && chapter->duration > 135000LL)
diff --git a/libhb/stream.c b/libhb/stream.c
index 65db14396..3fb7ca5a2 100644
--- a/libhb/stream.c
+++ b/libhb/stream.c
@@ -1749,20 +1749,22 @@ int hb_stream_seek_chapter( hb_stream_t * stream, int chapter_num )
return 0;
}
- int64_t sum_dur = 0;
- hb_chapter_t *chapter = NULL;
- int i;
- for ( i = 0; i < chapter_num; ++i)
- {
- chapter = hb_list_item( stream->title->list_chapter, i );
+ // TODO: add chapter start time to hb_chapter_t
+ // The first chapter does not necessarily start at time 0.
+ int64_t sum_dur = 0;
+ hb_chapter_t * chapter = NULL;
+ int ii;
+ for (ii = 0; ii < chapter_num - 1; ii++)
+ {
+ chapter = hb_list_item(stream->title->list_chapter, ii);
sum_dur += chapter->duration;
}
- stream->chapter = chapter_num - 1;
+ stream->chapter = chapter_num - 1;
stream->chapter_end = sum_dur;
if (chapter != NULL && chapter_num > 1)
{
- int64_t pos = (((sum_dur - chapter->duration) * AV_TIME_BASE) / 90000) +
+ int64_t pos = ((sum_dur * AV_TIME_BASE) / 90000) +
ffmpeg_initial_timestamp(stream);
if (pos > 0)
@@ -1770,7 +1772,7 @@ int hb_stream_seek_chapter( hb_stream_t * stream, int chapter_num )
hb_deep_log(2,
"Seeking to chapter %d: starts %"PRId64", ends %"PRId64
", AV pos %"PRId64,
- chapter_num, sum_dur - chapter->duration, sum_dur, pos);
+ chapter_num, sum_dur, sum_dur + chapter->duration, pos);
AVStream *st = stream->ffmpeg_ic->streams[stream->ffmpeg_video_id];
// timebase must be adjusted to match timebase of stream we are
@@ -1792,7 +1794,7 @@ int hb_stream_seek_chapter( hb_stream_t * stream, int chapter_num )
**********************************************************************/
int hb_stream_chapter( hb_stream_t * src_stream )
{
- return( src_stream->chapter + 1 );
+ return( src_stream->chapter );
}
/***********************************************************************
@@ -5829,16 +5831,20 @@ hb_buffer_t * hb_ffmpeg_read( hb_stream_t *stream )
buf->s.start >= stream->chapter_end )
{
hb_chapter_t *chapter = hb_list_item( stream->title->list_chapter,
- stream->chapter+1 );
- if( chapter )
+ stream->chapter);
+ if (chapter != NULL)
{
stream->chapter++;
stream->chapter_end += chapter->duration;
- buf->s.new_chap = stream->chapter + 1;
+ buf->s.new_chap = stream->chapter;
hb_deep_log( 2, "ffmpeg_read starting chapter %i at %"PRId64,
- stream->chapter + 1, buf->s.start);
+ stream->chapter, buf->s.start);
} else {
+ // Some titles run longer than the sum of their chapters
+ // Don't increment to a nonexistent chapter number
// Must have run out of chapters, stop looking.
+ hb_deep_log( 2, "ffmpeg_read end of chapter %i at %"PRId64,
+ stream->chapter, buf->s.start);
stream->chapter_end = INT64_MAX;
buf->s.new_chap = 0;
}
@@ -5883,6 +5889,31 @@ static int ffmpeg_seek_ts( hb_stream_t *stream, int64_t ts )
int64_t pos;
int ret;
+ // Find the initial chapter we have seeked into
+ int count = hb_list_count(stream->title->list_chapter);
+ if (count > 0)
+ {
+ int64_t sum_dur = 0;
+ hb_chapter_t * chapter;
+ int ii;
+ for (ii = 0; ii < count; ii++)
+ {
+ chapter = hb_list_item( stream->title->list_chapter, ii );
+ if (sum_dur + chapter->duration > ts)
+ {
+ break;
+ }
+ sum_dur += chapter->duration;
+ }
+ stream->chapter = ii;
+ stream->chapter_end = sum_dur;
+ }
+ else
+ {
+ stream->chapter = 0;
+ stream->chapter_end = INT64_MAX;
+ }
+
pos = ts * AV_TIME_BASE / 90000 + ffmpeg_initial_timestamp( stream );
AVStream *st = stream->ffmpeg_ic->streams[stream->ffmpeg_video_id];
// timebase must be adjusted to match timebase of stream we are