diff --git a/lib/upipe-framers/upipe_h264_framer.c b/lib/upipe-framers/upipe_h264_framer.c index 5ef4cac69..246cc3a9b 100644 --- a/lib/upipe-framers/upipe_h264_framer.c +++ b/lib/upipe-framers/upipe_h264_framer.c @@ -2402,6 +2402,16 @@ static void upipe_h264f_work_annexb(struct upipe *upipe, struct upump **upump_p) break; size_t start_size = !prev ? 5 : 4; + if (unlikely(upipe_h264f->au_size < start_size)) { + /* The start code overlaps a previously flushed boundary (stale + * scan context): discard it and rescan from a clean state. */ + upipe_warn(upipe, "discarding start code spanning a flush"); + upipe_h264f->au_size = 0; + upipe_h264f->au_last_nal_offset = -1; + upipe_h264f->scan_context = UINT32_MAX; + continue; + } + upipe_h264f->au_size -= start_size; upipe_h264f_end_annexb(upipe, upump_p); @@ -2421,12 +2431,16 @@ static void upipe_h264f_work_annexb(struct upipe *upipe, struct upump **upump_p) upipe_h264f_begin_annexb(upipe, upump_p); } - if (!upipe_h264f->complete_input || !upipe_h264f->au_size) + if (!upipe_h264f->complete_input || !upipe_h264f->au_size || + upipe_h264f->next_uref == NULL) return; upipe_h264f_end_annexb(upipe, upump_p); upipe_h264f_output_annexb(upipe, upump_p); upipe_h264f->au_last_nal_offset = -1; + /* The flush consumes up to the end of the stream, so the scan context + * must not be carried over to the next input uref. */ + upipe_h264f->scan_context = UINT32_MAX; } /** @internal @This prepares a raw access unit. @@ -2868,7 +2882,8 @@ static void upipe_h264f_free(struct upipe *upipe) /* Output any buffered frame. */ if (upipe_h264f->encaps_input == UREF_H26X_ENCAPS_ANNEXB && - !upipe_h264f->complete_input && upipe_h264f->au_size) { + !upipe_h264f->complete_input && upipe_h264f->au_size && + upipe_h264f->next_uref != NULL) { upipe_h264f_end_annexb(upipe, NULL); upipe_h264f_output_annexb(upipe, NULL); } diff --git a/lib/upipe-framers/upipe_h265_framer.c b/lib/upipe-framers/upipe_h265_framer.c index 5603662c5..ee47d75ec 100644 --- a/lib/upipe-framers/upipe_h265_framer.c +++ b/lib/upipe-framers/upipe_h265_framer.c @@ -2602,6 +2602,16 @@ static void upipe_h265f_work_annexb(struct upipe *upipe, struct upump **upump_p) break; size_t start_size = !prev ? 6 : 5; + if (unlikely(upipe_h265f->au_size < start_size)) { + /* The start code overlaps a previously flushed boundary (stale + * scan context): discard it and rescan from a clean state. */ + upipe_warn(upipe, "discarding start code spanning a flush"); + upipe_h265f->au_size = 0; + upipe_h265f->au_last_nal_offset = -1; + upipe_h265f->scan_context = UINT32_MAX; + continue; + } + upipe_h265f->au_size -= start_size; upipe_h265f_end_annexb(upipe, upump_p); @@ -2621,12 +2631,16 @@ static void upipe_h265f_work_annexb(struct upipe *upipe, struct upump **upump_p) upipe_h265f_begin_annexb(upipe, upump_p); } - if (!upipe_h265f->complete_input || !upipe_h265f->au_size) + if (!upipe_h265f->complete_input || !upipe_h265f->au_size || + upipe_h265f->next_uref == NULL) return; upipe_h265f_end_annexb(upipe, upump_p); upipe_h265f_output_annexb(upipe, upump_p); upipe_h265f->au_last_nal_offset = -1; + /* The flush consumes up to the end of the stream, so the scan context + * must not be carried over to the next input uref. */ + upipe_h265f->scan_context = UINT32_MAX; } /** @internal @This works on incoming frames in NALU format (supposedly @@ -2990,7 +3004,8 @@ static void upipe_h265f_free(struct upipe *upipe) /* Output any buffered frame. */ if (upipe_h265f->encaps_input == UREF_H26X_ENCAPS_ANNEXB && - !upipe_h265f->complete_input && upipe_h265f->au_size) { + !upipe_h265f->complete_input && upipe_h265f->au_size && + upipe_h265f->next_uref != NULL) { upipe_h265f_end_annexb(upipe, NULL); upipe_h265f_output_annexb(upipe, NULL); } diff --git a/lib/upipe-framers/upipe_mpgv_framer.c b/lib/upipe-framers/upipe_mpgv_framer.c index 0ab5806ec..936279579 100644 --- a/lib/upipe-framers/upipe_mpgv_framer.c +++ b/lib/upipe-framers/upipe_mpgv_framer.c @@ -1082,10 +1082,17 @@ static struct uref *upipe_mpgvf_handle_frame(struct upipe *upipe) return NULL; } + if (unlikely(upipe_mpgvf->next_frame_offset == -1)) { + /* No picture start code was found (e.g. a trailing sequence or GOP + * header flushed at end of stream): this is not a decodable frame. */ + upipe_mpgvf_consume_uref_stream(upipe, upipe_mpgvf->next_frame_size); + return NULL; + } + /* The PTS can be updated up to the first octet of the picture start code, * so any preceding structure must be extracted before, so that the PTS * can be properly promoted and taken into account. */ - if (upipe_mpgvf->next_frame_offset) { + if (upipe_mpgvf->next_frame_offset > 0) { uref = upipe_mpgvf_extract_uref_stream(upipe, upipe_mpgvf->next_frame_offset); if (unlikely(uref == NULL)) { @@ -1270,6 +1277,16 @@ static void upipe_mpgvf_work(struct upipe *upipe, struct upump **upump_p) if (!upipe_mpgvf_find(upipe, &start, &next)) break; + if (unlikely(upipe_mpgvf->next_frame_size < 4)) { + /* The start code overlaps a previously flushed boundary (stale + * scan context): discard it and rescan from a clean state. */ + upipe_warn(upipe, "discarding start code spanning a flush"); + upipe_mpgvf->next_frame_size = 0; + upipe_mpgvf->scan_context = UINT32_MAX; + upipe_mpgvf_reset(upipe); + continue; + } + if (unlikely(!upipe_mpgvf->acquired)) { bool discard = upipe_mpgvf->next_frame_size > 4; if (discard) { @@ -1386,12 +1403,15 @@ static void upipe_mpgvf_work(struct upipe *upipe, struct upump **upump_p) upipe_mpgvf_output_frame(upipe, uref, upump_p); } - if (!upipe_mpgvf->complete_input || !upipe_mpgvf->next_frame_size) + if (!upipe_mpgvf->complete_input || !upipe_mpgvf->next_frame_size || upipe_mpgvf->next_uref == NULL) return; struct uref *uref = upipe_mpgvf_handle_frame(upipe); upipe_mpgvf_reset(upipe); upipe_mpgvf->next_frame_size = 0; + /* The flush consumes up to the end of the stream, so the scan context + * must not be carried over to the next input uref. */ + upipe_mpgvf->scan_context = UINT32_MAX; if (uref == NULL) return; @@ -1606,7 +1626,7 @@ static void upipe_mpgvf_free(struct upipe *upipe) struct upipe_mpgvf *upipe_mpgvf = upipe_mpgvf_from_upipe(upipe); /* Output any buffered frame. */ - if (upipe_mpgvf->next_frame_size) { + if (upipe_mpgvf->next_frame_size && upipe_mpgvf->next_uref != NULL) { struct uref *uref = upipe_mpgvf_handle_frame(upipe); if (uref != NULL) upipe_mpgvf_output_frame(upipe, uref, NULL);