Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

More PGS improvements

Add patch to fix timestamp handling in libav pgs decoder and add
"forced" subtitle flag support.

Add support for foreign audio search and forced subtitles to decpgs.c

Move processing of interjob foreign audio search to before
initialization of filters.  The subtitle found needs to exist in
list_subtitle in order for the rendersub filter to initialize properly.

Add capability to initialize filters in a different order than they are
executed in the pipeline.  rendersub needs to be initialized after we
know cropping (cropscale), but must be executed before cropping.

Fix a problem in rendersub.c blend function that caused subtitles that
have the same resolution as the video frame to be dropped.
  • Loading branch information...
commit 3fdd1eb8ffd5c6a4a02a665ea2e045ef97228528 1 parent 0f29d8b
@jstebbins authored
View
82 contrib/ffmpeg/A09-pgs-pts.patch
@@ -0,0 +1,82 @@
+diff -Naur ffmpeg-v0.7-1696-gcae4f4b.orig/libavcodec/avcodec.h ffmpeg-v0.7-1696-gcae4f4b/libavcodec/avcodec.h
+--- ffmpeg-v0.7-1696-gcae4f4b.orig/libavcodec/avcodec.h 2011-11-03 12:29:48.000000000 +0100
++++ ffmpeg-v0.7-1696-gcae4f4b/libavcodec/avcodec.h 2012-04-22 10:59:41.122351884 +0200
+@@ -3193,6 +3193,7 @@
+ unsigned num_rects;
+ AVSubtitleRect **rects;
+ int64_t pts; ///< Same as packet pts, in AV_TIME_BASE
++ uint8_t forced;
+ } AVSubtitle;
+
+ /* packet functions */
+diff -Naur ffmpeg-v0.7-1696-gcae4f4b.orig/libavcodec/pgssubdec.c ffmpeg-v0.7-1696-gcae4f4b/libavcodec/pgssubdec.c
+--- ffmpeg-v0.7-1696-gcae4f4b.orig/libavcodec/pgssubdec.c 2011-11-03 12:29:48.000000000 +0100
++++ ffmpeg-v0.7-1696-gcae4f4b/libavcodec/pgssubdec.c 2012-04-22 13:09:29.499671541 +0200
+@@ -45,6 +45,8 @@
+ int y;
+ int id_number;
+ int object_number;
++ uint8_t composition_flag;
++ int64_t pts;
+ } PGSSubPresentation;
+
+ typedef struct PGSSubPicture {
+@@ -271,7 +273,8 @@
+ * @todo TODO: Implement forcing of subtitles
+ */
+ static void parse_presentation_segment(AVCodecContext *avctx,
+- const uint8_t *buf, int buf_size)
++ const uint8_t *buf, int buf_size,
++ int64_t pts)
+ {
+ PGSSubContext *ctx = avctx->priv_data;
+
+@@ -280,6 +283,8 @@
+ int w = bytestream_get_be16(&buf);
+ int h = bytestream_get_be16(&buf);
+
++ ctx->presentation.pts = pts;
++
+ av_dlog(avctx, "Video Dimensions %dx%d\n",
+ w, h);
+ if (av_image_check_size(w, h, 0, avctx) >= 0)
+@@ -299,16 +304,17 @@
+ buf += 3;
+
+ ctx->presentation.object_number = bytestream_get_byte(&buf);
++ ctx->presentation.composition_flag = 0;
+ if (!ctx->presentation.object_number)
+ return;
+
+ /*
+- * Skip 4 bytes of unknown:
++ * Skip 3 bytes of unknown:
+ * object_id_ref (2 bytes),
+ * window_id_ref,
+- * composition_flag (0x80 - object cropped, 0x40 - object forced)
+ */
+- buf += 4;
++ buf += 3;
++ ctx->presentation.composition_flag = bytestream_get_byte(&buf);
+
+ x = bytestream_get_be16(&buf);
+ y = bytestream_get_be16(&buf);
+@@ -356,6 +362,9 @@
+ */
+
+ memset(sub, 0, sizeof(*sub));
++ sub->pts = ctx->presentation.pts;
++ sub->forced = (ctx->presentation.composition_flag & 0x40) != 0;
++
+ // Blank if last object_number was 0.
+ // Note that this may be wrong for more complex subtitles.
+ if (!ctx->presentation.object_number)
+@@ -441,7 +450,7 @@
+ parse_picture_segment(avctx, buf, segment_length);
+ break;
+ case PRESENTATION_SEGMENT:
+- parse_presentation_segment(avctx, buf, segment_length);
++ parse_presentation_segment(avctx, buf, segment_length, avpkt->pts);
+ break;
+ case WINDOW_SEGMENT:
+ /*
View
1  libhb/common.h
@@ -928,6 +928,7 @@ struct hb_filter_object_s
{
int id;
int enforce_order;
+ int init_index;
char * name;
char * settings;
View
1  libhb/cropscale.c
@@ -30,6 +30,7 @@ hb_filter_object_t hb_filter_crop_scale =
{
.id = HB_FILTER_CROP_SCALE,
.enforce_order = 1,
+ .init_index = 0,
.name = "Crop and Scale",
.settings = NULL,
.init = hb_crop_scale_init,
View
1  libhb/deblock.c
@@ -63,6 +63,7 @@ hb_filter_object_t hb_filter_deblock =
{
.id = HB_FILTER_DEBLOCK,
.enforce_order = 1,
+ .init_index = 0,
.name = "Deblock (pp7)",
.settings = NULL,
.init = hb_deblock_init,
View
1  libhb/decomb.c
@@ -233,6 +233,7 @@ hb_filter_object_t hb_filter_decomb =
{
.id = HB_FILTER_DECOMB,
.enforce_order = 1,
+ .init_index = 0,
.name = "Decomb",
.settings = NULL,
.init = hb_decomb_init,
View
192 libhb/decpgssub.c
@@ -4,8 +4,7 @@
struct hb_work_private_s
{
AVCodecContext * context;
- hb_buffer_t * subtitle;
- uint32_t frame;
+ hb_job_t * job;
};
static int decsubInit( hb_work_object_t * w, hb_job_t * job )
@@ -14,13 +13,12 @@ static int decsubInit( hb_work_object_t * w, hb_job_t * job )
AVCodecContext *context = avcodec_alloc_context3( codec );
context->codec = codec;
- hb_work_private_t * private_data;
- private_data = calloc( 1, sizeof( hb_work_private_t ) );
- w->private_data = private_data;
+ hb_work_private_t * pv;
+ pv = calloc( 1, sizeof( hb_work_private_t ) );
+ w->private_data = pv;
- private_data->context = context;
- private_data->subtitle = NULL;
- private_data->frame = 0;
+ pv->context = context;
+ pv->job = job;
return 0;
}
@@ -28,15 +26,14 @@ static int decsubInit( hb_work_object_t * w, hb_job_t * job )
static int decsubWork( hb_work_object_t * w, hb_buffer_t ** buf_in,
hb_buffer_t ** buf_out )
{
- hb_work_private_t * private_data = w->private_data;
+ hb_work_private_t * pv = w->private_data;
hb_buffer_t * in = *buf_in;
if ( in->size <= 0 )
{
/* EOF on input stream - send it downstream & say that we're done */
*buf_out = in;
- *buf_in = private_data->subtitle;
- private_data->subtitle = NULL;
+ *buf_in = NULL;
return HB_WORK_DONE;
}
@@ -44,122 +41,145 @@ static int decsubWork( hb_work_object_t * w, hb_buffer_t ** buf_in,
AVSubtitle subtitle;
memset( &subtitle, 0, sizeof(subtitle) );
- AVPacket packet;
- av_init_packet( &packet );
- packet.data = in->data;
- packet.size = in->size;
+ AVPacket avp;
+ av_init_packet( &avp );
+ avp.data = in->data;
+ avp.size = in->size;
+ // libav wants pkt pts in AV_TIME_BASE units
+ avp.pts = av_rescale(in->s.start, AV_TIME_BASE, 90000);
int has_subtitle = 0;
do
{
- int usedBytes = avcodec_decode_subtitle2( private_data->context, &subtitle, &has_subtitle, &packet );
+ int usedBytes = avcodec_decode_subtitle2( pv->context, &subtitle, &has_subtitle, &avp );
if (usedBytes < 0)
{
- hb_log("unable to decode subtitle with %d bytes.", packet.size);
+ hb_log("unable to decode subtitle with %d bytes.", avp.size);
return HB_WORK_OK;
}
- if (usedBytes <= packet.size)
+ if (usedBytes <= avp.size)
{
- packet.data += usedBytes;
- packet.size -= usedBytes;
+ avp.data += usedBytes;
+ avp.size -= usedBytes;
}
else
{
- packet.size = 0;
+ avp.size = 0;
}
- if (has_subtitle)
+ // The sub is "usable" if:
+ // 1. libav returned a sub AND
+ // 2. we are scanning for foreign audio subs OR
+ // 3. we want all subs (e.g. not forced) OR
+ // 4. the sub is forced and we only want forced OR
+ // 5. subtitle clears the previous sub (these are never forced)
+ // subtitle.num_rects == 0
+ uint8_t useable_sub = (has_subtitle &&
+ ( pv->job->indepth_scan ||
+ subtitle.num_rects == 0 ||
+ !w->subtitle->config.force ||
+ ( w->subtitle->config.force && subtitle.forced ) ) );
+
+ if (useable_sub)
{
+ int64_t pts = av_rescale(subtitle.pts, 90000, AV_TIME_BASE);
hb_buffer_t * out = NULL;
- if (subtitle.num_rects != 0)
+
+ if( pv->job->indepth_scan )
+ {
+ if (subtitle.forced)
+ {
+ w->subtitle->forced_hits++;
+ }
+ }
+ else
{
- unsigned rectIndex;
- for (rectIndex = 0; rectIndex < subtitle.num_rects; rectIndex++)
+ if (subtitle.num_rects != 0)
{
- AVSubtitleRect *rect = subtitle.rects[rectIndex];
+ unsigned ii;
+ for (ii = 0; ii < subtitle.num_rects; ii++)
+ {
+ AVSubtitleRect *rect = subtitle.rects[ii];
- hb_buffer_t * image = hb_frame_buffer_init(
- PIX_FMT_YUVA420P, rect->w, rect->h );
+ hb_buffer_t * image = hb_frame_buffer_init(
+ PIX_FMT_YUVA420P, rect->w, rect->h );
- image->s.id = in->s.id;
- image->sequence = in->sequence;
- image->s.start = in->s.start;
- image->s.stop = 0;
- image->f.x = rect->x;
- image->f.y = rect->y;
+ image->s.id = in->s.id;
+ image->sequence = in->sequence;
+ image->s.start = pts;
+ image->s.stop = 0;
+ image->f.x = rect->x;
+ image->f.y = rect->y;
- uint8_t *lum = image->plane[0].data;
- uint8_t *chromaU = image->plane[1].data;
- uint8_t *chromaV = image->plane[2].data;
- uint8_t *alpha = image->plane[3].data;
+ uint8_t *lum = image->plane[0].data;
+ uint8_t *chromaU = image->plane[1].data;
+ uint8_t *chromaV = image->plane[2].data;
+ uint8_t *alpha = image->plane[3].data;
- int xx, yy;
- for (yy = 0; yy < rect->h; yy++)
- {
- for (xx = 0; xx < rect->w; xx++)
+ int xx, yy;
+ for (yy = 0; yy < rect->h; yy++)
{
- unsigned pixel = yy * rect->w + xx;
- uint8_t color = rect->pict.data[0][pixel];
- uint32_t argb;
- memcpy( &argb, &rect->pict.data[1][4 * color], 4);
- uint32_t yuv = hb_rgb2yuv(argb);
-
- lum[xx] = (yuv >> 16) & 0xff;
- alpha[xx] = (argb >> 24) & 0xff;
- if ((xx & 1) == 0 && (yy & 1) == 0)
+ for (xx = 0; xx < rect->w; xx++)
{
- chromaU[xx>>1] = (yuv >> 8) & 0xff;
- chromaV[xx>>1] = yuv & 0xff;
+ uint32_t argb, yuv;
+ int pixel;
+ uint8_t color;
+
+ pixel = yy * rect->w + xx;
+ color = rect->pict.data[0][pixel];
+ argb = ((uint32_t*)rect->pict.data[1])[color];
+ yuv = hb_rgb2yuv(argb);
+
+ lum[xx] = (yuv >> 16) & 0xff;
+ alpha[xx] = (argb >> 24) & 0xff;
+ if ((xx & 1) == 0 && (yy & 1) == 0)
+ {
+ chromaU[xx>>1] = (yuv >> 8) & 0xff;
+ chromaV[xx>>1] = yuv & 0xff;
+ }
}
+ lum += image->plane[0].stride;
+ if ((yy & 1) == 0)
+ {
+ chromaU += image->plane[1].stride;
+ chromaV += image->plane[2].stride;
+ }
+ alpha += image->plane[3].stride;
}
- lum += image->plane[0].stride;
- if ((yy & 1) == 0)
- {
- chromaU += image->plane[1].stride;
- chromaV += image->plane[2].stride;
- }
- alpha += image->plane[3].stride;
- }
- image->sub = NULL;
- out = image;
+ image->sub = NULL;
+ out = image;
+ }
+ }
+ else
+ {
+ out = hb_buffer_init( 1 );
+
+ out->s.id = in->s.id;
+ out->s.start = pts;
+ out->s.stop = 0;
+ out->f.x = 0;
+ out->f.y = 0;
+ out->f.width = 0;
+ out->f.height = 0;
}
- }
- else
- {
- out = hb_buffer_init( 0 );
-
- out->s.id = in->s.id;
- out->s.start = in->s.start;
- out->s.stop = in->s.start;
- out->f.x = 0;
- out->f.y = 0;
- out->f.width = 0;
- out->f.height = 0;
}
*buf_out = out;
}
- else
- {
- hb_log("no subtitle.");
- }
- } while (packet.size > 0);
+ } while (avp.size > 0);
return HB_WORK_OK;
}
static void decsubClose( hb_work_object_t * w )
{
- hb_work_private_t * private_data = w->private_data;
- avcodec_flush_buffers( private_data->context );
- avcodec_close( private_data->context );
-
- if (private_data->subtitle != NULL)
- hb_buffer_close( &private_data->subtitle );
+ hb_work_private_t * pv = w->private_data;
+ avcodec_flush_buffers( pv->context );
+ avcodec_close( pv->context );
}
hb_work_object_t hb_decpgssub =
View
1  libhb/deinterlace.c
@@ -77,6 +77,7 @@ hb_filter_object_t hb_filter_deinterlace =
{
.id = HB_FILTER_DEINTERLACE,
.enforce_order = 1,
+ .init_index = 0,
.name = "Deinterlace (ffmpeg or yadif/mcdeint)",
.settings = NULL,
.init = hb_deinterlace_init,
View
1  libhb/denoise.c
@@ -46,6 +46,7 @@ hb_filter_object_t hb_filter_denoise =
{
.id = HB_FILTER_DENOISE,
.enforce_order = 1,
+ .init_index = 0,
.name = "Denoise (hqdn3d)",
.settings = NULL,
.init = hb_denoise_init,
View
1  libhb/detelecine.c
@@ -98,6 +98,7 @@ hb_filter_object_t hb_filter_detelecine =
{
.id = HB_FILTER_DETELECINE,
.enforce_order = 1,
+ .init_index = 0,
.name = "Detelecine (pullup)",
.settings = NULL,
.init = hb_detelecine_init,
View
2  libhb/hb.c
@@ -1570,7 +1570,7 @@ void hb_add( hb_handle_t * h, hb_job_t * job )
{
subtitle = hb_list_item( title->list_subtitle, i );
if( strcmp( subtitle->iso639_2, audio_lang ) == 0 &&
- subtitle->source == VOBSUB )
+ hb_subtitle_can_force( subtitle->source ) )
{
/*
* Matched subtitle language with audio language, so
View
10 libhb/rendersub.c
@@ -62,6 +62,7 @@ hb_filter_object_t hb_filter_render_sub =
{
.id = HB_FILTER_RENDER_SUB,
.enforce_order = 1,
+ .init_index = 1,
.name = "Subtitle renderer",
.settings = NULL,
.init = hb_rendersub_init,
@@ -90,16 +91,15 @@ static void blend( hb_buffer_t *dst, hb_buffer_t *src, int left, int top )
}
ww = src->f.width;
- if( left + src->f.width > dst->f.width )
+ if( src->f.width - x0 > dst->f.width - left )
{
- ww = dst->f.width - ( left + src->f.width );
+ ww = dst->f.width - left + x0;
}
hh = src->f.height;
- if( top + src->f.height > dst->f.height )
+ if( src->f.height - y0 > dst->f.height - top )
{
- hh = dst->f.height - ( top + src->f.height );
+ hh = dst->f.height - top + y0;
}
-
// Blend luma
for( yy = y0; yy < hh; yy++ )
{
View
1  libhb/rotate.c
@@ -46,6 +46,7 @@ hb_filter_object_t hb_filter_rotate =
{
.id = HB_FILTER_ROTATE,
.enforce_order = 0,
+ .init_index = 2,
.name = "Rotate (rotate & flip image axes)",
.settings = NULL,
.init = hb_rotate_init,
View
1  libhb/vfr.c
@@ -46,6 +46,7 @@ hb_filter_object_t hb_filter_vfr =
{
.id = HB_FILTER_VFR,
.enforce_order = 1,
+ .init_index = 0,
.name = "Framerate Shaper",
.settings = NULL,
.init = hb_vfr_init,
View
164 libhb/work.c
@@ -489,6 +489,46 @@ void correct_framerate( hb_job_t * job )
interjob->vrate_base = job->vrate_base;
}
+void hb_filter_init_next( hb_list_t * list, int *score, int *ret_pos )
+{
+ int count = hb_list_count( list );
+ int pos = *ret_pos + 1;
+ int ii = 0;
+ if ( pos == 0 )
+ {
+ hb_filter_object_t * filter = hb_list_item( list, pos );
+ if ( filter->init_index == *score )
+ {
+ *ret_pos = pos;
+ return;
+ }
+ pos++;
+ }
+ while (1)
+ {
+ if ( pos == count )
+ {
+ pos = 0;
+ (*score)++;
+ }
+ hb_filter_object_t * filter = hb_list_item( list, pos );
+ if ( filter->init_index == *score )
+ {
+ *ret_pos = pos;
+ return;
+ }
+ pos++;
+ ii++;
+ if (ii > count)
+ {
+ // This is an error that should never happen
+ hb_error("internal error during filter initialization");
+ *ret_pos = -1;
+ return;
+ }
+ }
+}
+
/**
* Job initialization rountine.
* Initializes fifos.
@@ -529,11 +569,67 @@ static void do_job( hb_job_t * job )
hb_log( "starting job" );
+ /*
+ * Look for the scanned subtitle in the existing subtitle list
+ * select_subtitle implies that we did a scan.
+ */
+ if ( !job->indepth_scan && interjob->select_subtitle &&
+ ( job->pass == 0 || job->pass == 2 ) )
+ {
+ /*
+ * Disable forced subtitles if we didn't find any in the scan
+ * so that we display normal subtitles instead.
+ */
+ if( interjob->select_subtitle->config.force &&
+ interjob->select_subtitle->forced_hits == 0 )
+ {
+ interjob->select_subtitle->config.force = 0;
+ }
+ for( i=0; i < hb_list_count(title->list_subtitle); i++ )
+ {
+ subtitle = hb_list_item( title->list_subtitle, i );
+
+ if( subtitle )
+ {
+ /*
+ * Remove the scanned subtitle from the subtitle list if
+ * it would result in an identical duplicate subtitle track
+ * or an emty track (forced and no forced hits).
+ */
+ if( ( interjob->select_subtitle->id == subtitle->id ) &&
+ ( ( interjob->select_subtitle->forced_hits == 0 &&
+ subtitle->config.force ) ||
+ ( subtitle->config.force == interjob->select_subtitle->config.force ) ) )
+ {
+ *subtitle = *(interjob->select_subtitle);
+ free( interjob->select_subtitle );
+ interjob->select_subtitle = NULL;
+ break;
+ }
+ }
+ }
+
+ if( interjob->select_subtitle )
+ {
+ /*
+ * Its not in the existing list
+ *
+ * Must be second pass of a two pass with subtitle scan enabled, so
+ * add the subtitle that we found on the first pass for use in this
+ * pass.
+ */
+ hb_list_add( title->list_subtitle, interjob->select_subtitle );
+ interjob->select_subtitle = NULL;
+ }
+ }
+
+
// Filters have an effect on settings.
// So initialize the filters and update the job.
if( job->list_filter && hb_list_count( job->list_filter ) )
{
hb_filter_init_t init;
+ int pos = -1, score = 0;
init.job = job;
init.pix_fmt = PIX_FMT_YUV420P;
@@ -547,7 +643,19 @@ static void do_job( hb_job_t * job )
init.cfr = 0;
for( i = 0; i < hb_list_count( job->list_filter ); i++ )
{
- hb_filter_object_t * filter = hb_list_item( job->list_filter, i );
+ // Some filters need to be initialized in a different order
+ // than they are executed in the pipeline. e.g. rendersub
+ // needs to be initialized after cropscale so that it knows
+ // the crop settings, but it needs to be executed before
+ // cropscale. so hb_filter_init_next() finds returns the
+ // position of filters in initialization order.
+ hb_filter_init_next( job->list_filter, &score, &pos );
+ if( pos == -1)
+ {
+ // This is an error that should never happen!
+ break;
+ }
+ hb_filter_object_t * filter = hb_list_item( job->list_filter, pos );
if( filter->init( filter, &init ) )
{
hb_log( "Failure to initialise filter '%s', disabling",
@@ -847,60 +955,6 @@ static void do_job( hb_job_t * job )
w->fifo_in = job->fifo_mpeg2;
w->fifo_out = job->fifo_raw;
- /*
- * Look for the scanned subtitle in the existing subtitle list
- * select_subtitle implies that we did a scan.
- */
- if ( !job->indepth_scan && interjob->select_subtitle &&
- ( job->pass == 0 || job->pass == 2 ) )
- {
- /*
- * Disable forced subtitles if we didn't find any in the scan
- * so that we display normal subtitles instead.
- */
- if( interjob->select_subtitle->config.force &&
- interjob->select_subtitle->forced_hits == 0 )
- {
- interjob->select_subtitle->config.force = 0;
- }
- for( i=0; i < hb_list_count(title->list_subtitle); i++ )
- {
- subtitle = hb_list_item( title->list_subtitle, i );
-
- if( subtitle )
- {
- /*
- * Remove the scanned subtitle from the subtitle list if
- * it would result in an identical duplicate subtitle track
- * or an emty track (forced and no forced hits).
- */
- if( ( interjob->select_subtitle->id == subtitle->id ) &&
- ( ( interjob->select_subtitle->forced_hits == 0 &&
- subtitle->config.force ) ||
- ( subtitle->config.force == interjob->select_subtitle->config.force ) ) )
- {
- *subtitle = *(interjob->select_subtitle);
- free( interjob->select_subtitle );
- interjob->select_subtitle = NULL;
- break;
- }
- }
- }
-
- if( interjob->select_subtitle )
- {
- /*
- * Its not in the existing list
- *
- * Must be second pass of a two pass with subtitle scan enabled, so
- * add the subtitle that we found on the first pass for use in this
- * pass.
- */
- hb_list_add( title->list_subtitle, interjob->select_subtitle );
- interjob->select_subtitle = NULL;
- }
- }
-
for( i=0; i < hb_list_count(title->list_subtitle); i++ )
{
subtitle = hb_list_item( title->list_subtitle, i );

0 comments on commit 3fdd1eb

Please sign in to comment.
Something went wrong with that request. Please try again.