Requried to remux mkv to m2ts --- libavcodec/Makefile | 1 + libavcodec/bitstream_filters.c | 1 + libavcodec/pgs_frame_split_bsf.c | 176 +++++++++++++++++++++++++++++++ 3 files changed, 178 insertions(+) create mode 100644 libavcodec/pgs_frame_split_bsf.c
diff --git a/libavcodec/Makefile b/libavcodec/Makefile index 13909faabf..948aee0252 100644 --- a/libavcodec/Makefile +++ b/libavcodec/Makefile @@ -1120,6 +1120,7 @@ OBJS-$(CONFIG_VP9_RAW_REORDER_BSF) += vp9_raw_reorder_bsf.o OBJS-$(CONFIG_VP9_SUPERFRAME_BSF) += vp9_superframe_bsf.o OBJS-$(CONFIG_VP9_SUPERFRAME_SPLIT_BSF) += vp9_superframe_split_bsf.o OBJS-$(CONFIG_PGS_FRAME_MERGE_BSF) += pgs_frame_merge_bsf.o +OBJS-$(CONFIG_PGS_FRAME_SPLIT_BSF) += pgs_frame_split_bsf.o # thread libraries OBJS-$(HAVE_LIBC_MSVCRT) += file_open.o diff --git a/libavcodec/bitstream_filters.c b/libavcodec/bitstream_filters.c index 138f6dd7ad..5422392e11 100644 --- a/libavcodec/bitstream_filters.c +++ b/libavcodec/bitstream_filters.c @@ -59,6 +59,7 @@ extern const AVBitStreamFilter ff_vp9_raw_reorder_bsf; extern const AVBitStreamFilter ff_vp9_superframe_bsf; extern const AVBitStreamFilter ff_vp9_superframe_split_bsf; extern const AVBitStreamFilter ff_pgs_frame_merge_bsf; +extern const AVBitStreamFilter ff_pgs_frame_split_bsf; #include "libavcodec/bsf_list.c" diff --git a/libavcodec/pgs_frame_split_bsf.c b/libavcodec/pgs_frame_split_bsf.c new file mode 100644 index 0000000000..c983f6acf5 --- /dev/null +++ b/libavcodec/pgs_frame_split_bsf.c @@ -0,0 +1,176 @@ +/* + * Copyright (c) 2020 John Stebbins <jstebbins...@gmail.com> + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * This bitstream filter splits PGS subtitle packets into packets containing + * just one segment. + * + * Packets already containing only one segment will be passed through + * unchanged. + */ + +#include "avcodec.h" +#include "bsf.h" +#include "libavutil/intreadwrite.h" + +enum PGSSegmentType { + PALETTE_SEGMENT = 0x14, + OBJECT_SEGMENT = 0x15, + PRESENTATION_SEGMENT = 0x16, + WINDOW_SEGMENT = 0x17, + DISPLAY_SEGMENT = 0x80, +}; + +typedef struct PGSSplitContext { + AVPacket *in; +} PGSSplitContext; + +static int frame_split_filter(AVBSFContext *bsf, AVPacket *out) +{ + PGSSplitContext *ctx = bsf->priv_data; + AVPacket *in = ctx->in; + int i, ret; + uint8_t segment_type; + uint16_t segment_len; + int split = !!in->data; + + if (!in->data) { + ret = ff_bsf_get_packet_ref(bsf, in); + if (ret < 0) + return ret; + } + if (!in->size) { + av_packet_unref(in); + return AVERROR(EAGAIN); + } + + // Validate packet data + i = 0; + while (i < in->size) { + segment_type = in->data[i]; + segment_len = AV_RB16(in->data + i + 1) + 3; + i += segment_len; + } + if (i != in->size) { + av_log(bsf, AV_LOG_WARNING, "Failed to parse PGS segments.\n"); + av_packet_move_ref(out, in); + return 0; + } + + segment_type = in->data[0]; + segment_len = AV_RB16(in->data + 1) + 3; + if (split || segment_len < in->size) { // Split + int64_t ts_delta, dts; + + ret = av_packet_ref(out, in); + if (ret < 0) + goto fail; + out->size = segment_len; + in->data += segment_len; + in->size -= segment_len; + + // Update PTS/DTS, Stagger timestamps by 3ms + ts_delta = 270; // Assume 90khz tick if no time_base_in + if (bsf->time_base_in.num && bsf->time_base_in.den) + ts_delta = bsf->time_base_in.den / bsf->time_base_in.num / 333; + if (ts_delta == 0) + ts_delta = 1; + + // Compute DTS, it's the same for all packets that carry it + // Assuming input PTS/DTS come from original presentation_segment + if (in->dts <= in->pts - 2 * ts_delta && + in->dts != AV_NOPTS_VALUE) + dts = in->dts; + else if (in->pts != AV_NOPTS_VALUE) + dts = in->pts - 2 * ts_delta; + + switch (segment_type) { + case DISPLAY_SEGMENT: + if (in->pts != AV_NOPTS_VALUE) + out->pts = in->pts - ts_delta; + out->dts = AV_NOPTS_VALUE; + break; + case PALETTE_SEGMENT: + if (in->pts != AV_NOPTS_VALUE) + out->pts = in->pts - 2 * ts_delta; + out->dts = AV_NOPTS_VALUE; + break; + case PRESENTATION_SEGMENT: + out->pts = in->pts; + out->dts = dts; + break; + case WINDOW_SEGMENT: + case OBJECT_SEGMENT: + default: + if (in->pts != AV_NOPTS_VALUE) + out->pts = in->pts - ts_delta; + out->dts = dts; + break; + } + } else + av_packet_move_ref(out, in); + + return 0; + +fail: + av_packet_unref(in); + + return ret; +} + +static int frame_split_init(AVBSFContext *bsf) +{ + PGSSplitContext *ctx = bsf->priv_data; + + ctx->in = av_packet_alloc(); + if (!ctx->in) + return AVERROR(ENOMEM); + + return 0; +} + +static void frame_split_flush(AVBSFContext *bsf) +{ + PGSSplitContext *ctx = bsf->priv_data; + + av_packet_unref(ctx->in); +} + +static void frame_split_close(AVBSFContext *bsf) +{ + PGSSplitContext *ctx = bsf->priv_data; + + av_packet_free(&ctx->in); +} + +static const enum AVCodecID frame_split_codec_ids[] = { + AV_CODEC_ID_HDMV_PGS_SUBTITLE, AV_CODEC_ID_NONE, +}; + +const AVBitStreamFilter ff_pgs_frame_split_bsf = { + .name = "pgs_frame_split", + .priv_data_size = sizeof(PGSSplitContext), + .init = frame_split_init, + .flush = frame_split_flush, + .close = frame_split_close, + .filter = frame_split_filter, + .codec_ids = frame_split_codec_ids, +}; -- 2.25.2 _______________________________________________ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org https://ffmpeg.org/mailman/listinfo/ffmpeg-devel To unsubscribe, visit link above, or email ffmpeg-devel-requ...@ffmpeg.org with subject "unsubscribe".