diff --git a/libavcodec/dvbsubdec.c b/libavcodec/dvbsubdec.c index e6e746dba6..7fb887ebb0 100644 --- a/libavcodec/dvbsubdec.c +++ b/libavcodec/dvbsubdec.c @@ -234,6 +234,9 @@ typedef struct DVBSubContext { int version; int time_out; + int compute_edt; /**< if 1 end display time calculated using pts + if 0 (Default) calculated using time out */ + int64_t prev_start; DVBSubRegion *region_list; DVBSubCLUT *clut_list; DVBSubObject *object_list; @@ -383,6 +386,7 @@ static av_cold int dvbsub_init_decoder(AVCodecContext *avctx) } ctx->version = -1; + ctx->prev_start = AV_NOPTS_VALUE; default_clut.id = -1; default_clut.next = NULL; @@ -759,7 +763,7 @@ static int dvbsub_read_8bit_string(uint8_t *destbuf, int dbuf_len, return pixels_read; } -static void save_subtitle_set(AVCodecContext *avctx, AVSubtitle *sub) +static void save_subtitle_set(AVCodecContext *avctx, AVSubtitle *sub, int *got_output) { DVBSubContext *ctx = avctx->priv_data; DVBSubRegionDisplay *display; @@ -771,14 +775,19 @@ static void save_subtitle_set(AVCodecContext *avctx, AVSubtitle *sub) int i; int offset_x=0, offset_y=0; - sub->end_display_time = ctx->time_out * 1000; + if(ctx->compute_edt == 0) + sub->end_display_time = ctx->time_out * 1000; if (display_def) { offset_x = display_def->x; offset_y = display_def->y; } - sub->num_rects = 0; + /* Not touching AVSubtitles again*/ + if(sub->num_rects) { + avpriv_request_sample(ctx, "Different Version of Segment asked Twice\n"); + return; + } for (display = ctx->display_list; display; display = display->next) { region = get_region(ctx, display->region_id); if (region && region->dirty) @@ -786,6 +795,13 @@ static void save_subtitle_set(AVCodecContext *avctx, AVSubtitle *sub) } if (sub->num_rects > 0) { + if(ctx->compute_edt == 1 && ctx->prev_start != AV_NOPTS_VALUE) { + sub->end_display_time = av_rescale_q((sub->pts - ctx->prev_start ), AV_TIME_BASE_Q, (AVRational){ 1, 1000 }) - 1; + *got_output = 1; + } else if (ctx->compute_edt == 0) { + *got_output = 1; + } + sub->rects = av_mallocz_array(sizeof(*sub->rects), sub->num_rects); for(i=0; inum_rects; i++) sub->rects[i] = av_mallocz(sizeof(*sub->rects[i])); @@ -1228,7 +1244,7 @@ static void dvbsub_parse_region_segment(AVCodecContext *avctx, } static void dvbsub_parse_page_segment(AVCodecContext *avctx, - const uint8_t *buf, int buf_size, AVSubtitle *sub) + const uint8_t *buf, int buf_size, AVSubtitle *sub, int *got_output) { DVBSubContext *ctx = avctx->priv_data; DVBSubRegionDisplay *display; @@ -1256,6 +1272,9 @@ static void dvbsub_parse_page_segment(AVCodecContext *avctx, av_dlog(avctx, "Page time out %ds, state %d\n", ctx->time_out, page_state); + if(ctx->compute_edt == 1) + save_subtitle_set(avctx, sub, got_output); + if (page_state == 1 || page_state == 2) { delete_regions(ctx); delete_objects(ctx); @@ -1445,17 +1464,17 @@ static void dvbsub_parse_display_definition_segment(AVCodecContext *avctx, } } -static int dvbsub_display_end_segment(AVCodecContext *avctx, const uint8_t *buf, - int buf_size, AVSubtitle *sub) +static void dvbsub_display_end_segment(AVCodecContext *avctx, const uint8_t *buf, + int buf_size, AVSubtitle *sub,int *got_output) { DVBSubContext *ctx = avctx->priv_data; - save_subtitle_set(avctx,sub); + if(ctx->compute_edt == 0) + save_subtitle_set(avctx, sub, got_output); #ifdef DEBUG save_display_set(ctx); #endif - return 1; } static int dvbsub_decode(AVCodecContext *avctx, @@ -1471,7 +1490,7 @@ static int dvbsub_decode(AVCodecContext *avctx, int page_id; int segment_length; int i; - int ret; + int ret = 0; int got_segment = 0; av_dlog(avctx, "DVB sub packet:\n"); @@ -1507,14 +1526,15 @@ static int dvbsub_decode(AVCodecContext *avctx, if (p_end - p < segment_length) { av_dlog(avctx, "incomplete or broken packet"); - return -1; + ret = -1; + goto end; } if (page_id == ctx->composition_id || page_id == ctx->ancillary_id || ctx->composition_id == -1 || ctx->ancillary_id == -1) { switch (segment_type) { case DVBSUB_PAGE_SEGMENT: - dvbsub_parse_page_segment(avctx, p, segment_length, sub); + dvbsub_parse_page_segment(avctx, p, segment_length, sub, data_size); got_segment |= 1; break; case DVBSUB_REGION_SEGMENT: @@ -1523,7 +1543,7 @@ static int dvbsub_decode(AVCodecContext *avctx, break; case DVBSUB_CLUT_SEGMENT: ret = dvbsub_parse_clut_segment(avctx, p, segment_length); - if (ret < 0) return ret; + if (ret < 0) goto end; got_segment |= 4; break; case DVBSUB_OBJECT_SEGMENT: @@ -1534,7 +1554,7 @@ static int dvbsub_decode(AVCodecContext *avctx, dvbsub_parse_display_definition_segment(avctx, p, segment_length); break; case DVBSUB_DISPLAY_SEGMENT: - *data_size = dvbsub_display_end_segment(avctx, p, segment_length, sub); + dvbsub_display_end_segment(avctx, p, segment_length, sub, data_size); got_segment |= 16; break; default: @@ -1550,13 +1570,24 @@ static int dvbsub_decode(AVCodecContext *avctx, // segments then we need no further data. if (got_segment == 15 && sub) { av_log(avctx, AV_LOG_DEBUG, "Missing display_end_segment, emulating\n"); - *data_size = dvbsub_display_end_segment(avctx, p, 0, sub); + dvbsub_display_end_segment(avctx, p, 0, sub, data_size); + } + +end: + if(ret < 0) { + *data_size = 0; + avsubtitle_free(sub); + return ret; + } else { + if(ctx->compute_edt == 1 ) + FFSWAP(int64_t, ctx->prev_start, sub->pts); } return p - buf; } static const AVOption options[] = { + {"compute_edt", "compute end of time using pts or timeout", offsetof(DVBSubContext, compute_edt), FF_OPT_TYPE_INT, {.i64 = 0}, 0, 1, 0}, {NULL} }; static const AVClass dvbsubdec_class = {