1cabdff1aSopenharmony_ci/* 2cabdff1aSopenharmony_ci * Copyright (c) 2020 John Stebbins <jstebbins.hb@gmail.com> 3cabdff1aSopenharmony_ci * 4cabdff1aSopenharmony_ci * This file is part of FFmpeg. 5cabdff1aSopenharmony_ci * 6cabdff1aSopenharmony_ci * FFmpeg is free software; you can redistribute it and/or 7cabdff1aSopenharmony_ci * modify it under the terms of the GNU Lesser General Public 8cabdff1aSopenharmony_ci * License as published by the Free Software Foundation; either 9cabdff1aSopenharmony_ci * version 2.1 of the License, or (at your option) any later version. 10cabdff1aSopenharmony_ci * 11cabdff1aSopenharmony_ci * FFmpeg is distributed in the hope that it will be useful, 12cabdff1aSopenharmony_ci * but WITHOUT ANY WARRANTY; without even the implied warranty of 13cabdff1aSopenharmony_ci * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14cabdff1aSopenharmony_ci * Lesser General Public License for more details. 15cabdff1aSopenharmony_ci * 16cabdff1aSopenharmony_ci * You should have received a copy of the GNU Lesser General Public 17cabdff1aSopenharmony_ci * License along with FFmpeg; if not, write to the Free Software 18cabdff1aSopenharmony_ci * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 19cabdff1aSopenharmony_ci */ 20cabdff1aSopenharmony_ci 21cabdff1aSopenharmony_ci/** 22cabdff1aSopenharmony_ci * @file 23cabdff1aSopenharmony_ci * This bitstream filter merges PGS subtitle packets containing incomplete 24cabdff1aSopenharmony_ci * set of segments into a single packet 25cabdff1aSopenharmony_ci * 26cabdff1aSopenharmony_ci * Packets already containing a complete set of segments will be passed through 27cabdff1aSopenharmony_ci * unchanged. 28cabdff1aSopenharmony_ci */ 29cabdff1aSopenharmony_ci 30cabdff1aSopenharmony_ci#include "libavutil/attributes.h" 31cabdff1aSopenharmony_ci#include "libavutil/intreadwrite.h" 32cabdff1aSopenharmony_ci#include "libavutil/log.h" 33cabdff1aSopenharmony_ci#include "bsf.h" 34cabdff1aSopenharmony_ci#include "bsf_internal.h" 35cabdff1aSopenharmony_ci 36cabdff1aSopenharmony_cienum PGSSegmentType { 37cabdff1aSopenharmony_ci PALETTE_SEGMENT = 0x14, 38cabdff1aSopenharmony_ci OBJECT_SEGMENT = 0x15, 39cabdff1aSopenharmony_ci PRESENTATION_SEGMENT = 0x16, 40cabdff1aSopenharmony_ci WINDOW_SEGMENT = 0x17, 41cabdff1aSopenharmony_ci END_DISPLAY_SET_SEGMENT = 0x80, 42cabdff1aSopenharmony_ci}; 43cabdff1aSopenharmony_ci 44cabdff1aSopenharmony_citypedef struct PGSMergeContext { 45cabdff1aSopenharmony_ci AVPacket *buffer_pkt, *in; 46cabdff1aSopenharmony_ci int presentation_found; 47cabdff1aSopenharmony_ci int pkt_flags; 48cabdff1aSopenharmony_ci} PGSMergeContext; 49cabdff1aSopenharmony_ci 50cabdff1aSopenharmony_cistatic av_cold void frame_merge_flush(AVBSFContext *bsf) 51cabdff1aSopenharmony_ci{ 52cabdff1aSopenharmony_ci PGSMergeContext *ctx = bsf->priv_data; 53cabdff1aSopenharmony_ci 54cabdff1aSopenharmony_ci ctx->presentation_found = ctx->pkt_flags = 0; 55cabdff1aSopenharmony_ci av_packet_unref(ctx->in); 56cabdff1aSopenharmony_ci av_packet_unref(ctx->buffer_pkt); 57cabdff1aSopenharmony_ci} 58cabdff1aSopenharmony_ci 59cabdff1aSopenharmony_cistatic int frame_merge_output(PGSMergeContext *ctx, AVPacket *dst, AVPacket *src) 60cabdff1aSopenharmony_ci{ 61cabdff1aSopenharmony_ci if (!ctx->presentation_found) 62cabdff1aSopenharmony_ci ctx->pkt_flags |= AV_PKT_FLAG_CORRUPT; 63cabdff1aSopenharmony_ci ctx->presentation_found = 0; 64cabdff1aSopenharmony_ci src->flags |= ctx->pkt_flags; 65cabdff1aSopenharmony_ci ctx->pkt_flags = 0; 66cabdff1aSopenharmony_ci av_packet_move_ref(dst, src); 67cabdff1aSopenharmony_ci return 0; 68cabdff1aSopenharmony_ci} 69cabdff1aSopenharmony_ci 70cabdff1aSopenharmony_cistatic int frame_merge_filter(AVBSFContext *bsf, AVPacket *out) 71cabdff1aSopenharmony_ci{ 72cabdff1aSopenharmony_ci PGSMergeContext *ctx = bsf->priv_data; 73cabdff1aSopenharmony_ci AVPacket *in = ctx->in, *pkt = ctx->buffer_pkt; 74cabdff1aSopenharmony_ci int ret, size, pos, display = 0, presentation = 0; 75cabdff1aSopenharmony_ci unsigned int i; 76cabdff1aSopenharmony_ci 77cabdff1aSopenharmony_ci if (!in->data) { 78cabdff1aSopenharmony_ci ret = ff_bsf_get_packet_ref(bsf, in); 79cabdff1aSopenharmony_ci if (ret == AVERROR_EOF && pkt->data) { 80cabdff1aSopenharmony_ci // Output remaining data 81cabdff1aSopenharmony_ci ctx->pkt_flags |= AV_PKT_FLAG_CORRUPT; 82cabdff1aSopenharmony_ci return frame_merge_output(ctx, out, pkt); 83cabdff1aSopenharmony_ci } 84cabdff1aSopenharmony_ci if (ret < 0) 85cabdff1aSopenharmony_ci return ret; 86cabdff1aSopenharmony_ci } 87cabdff1aSopenharmony_ci if (!in->size) { 88cabdff1aSopenharmony_ci av_packet_unref(in); 89cabdff1aSopenharmony_ci return AVERROR(EAGAIN); 90cabdff1aSopenharmony_ci } 91cabdff1aSopenharmony_ci in->flags &= ~AV_PKT_FLAG_KEY; // Will be detected in the stream 92cabdff1aSopenharmony_ci 93cabdff1aSopenharmony_ci // Validate packet data and find display_end segment 94cabdff1aSopenharmony_ci size = in->size; 95cabdff1aSopenharmony_ci i = 0; 96cabdff1aSopenharmony_ci while (i + 3 <= in->size) { 97cabdff1aSopenharmony_ci uint8_t segment_type = in->data[i]; 98cabdff1aSopenharmony_ci int segment_len = AV_RB16(in->data + i + 1) + 3; 99cabdff1aSopenharmony_ci 100cabdff1aSopenharmony_ci if (i + segment_len > in->size) 101cabdff1aSopenharmony_ci break; // Invalid, segments can't span packets 102cabdff1aSopenharmony_ci if (segment_type == PRESENTATION_SEGMENT && ctx->presentation_found) 103cabdff1aSopenharmony_ci break; // Invalid, there can be only one 104cabdff1aSopenharmony_ci if (segment_type == PRESENTATION_SEGMENT) { 105cabdff1aSopenharmony_ci uint8_t state; 106cabdff1aSopenharmony_ci if (segment_len < 11) 107cabdff1aSopenharmony_ci break; // Invalid presentation segment length 108cabdff1aSopenharmony_ci ctx->presentation_found = presentation = 1; 109cabdff1aSopenharmony_ci state = in->data[i + 10] & 0xc0; 110cabdff1aSopenharmony_ci if (state) 111cabdff1aSopenharmony_ci ctx->pkt_flags |= AV_PKT_FLAG_KEY; 112cabdff1aSopenharmony_ci else 113cabdff1aSopenharmony_ci ctx->pkt_flags &= ~AV_PKT_FLAG_KEY; 114cabdff1aSopenharmony_ci } 115cabdff1aSopenharmony_ci i += segment_len; 116cabdff1aSopenharmony_ci if (segment_type == END_DISPLAY_SET_SEGMENT) { 117cabdff1aSopenharmony_ci size = i; 118cabdff1aSopenharmony_ci display = 1; 119cabdff1aSopenharmony_ci break; 120cabdff1aSopenharmony_ci } 121cabdff1aSopenharmony_ci } 122cabdff1aSopenharmony_ci if (display && pkt->size == 0 && size == in->size) // passthrough 123cabdff1aSopenharmony_ci return frame_merge_output(ctx, out, in); 124cabdff1aSopenharmony_ci if (!display && i != in->size) { 125cabdff1aSopenharmony_ci av_log(bsf, AV_LOG_WARNING, "Failed to parse PGS segments.\n"); 126cabdff1aSopenharmony_ci // force output what we have 127cabdff1aSopenharmony_ci size = in->size; 128cabdff1aSopenharmony_ci display = 1; 129cabdff1aSopenharmony_ci ctx->pkt_flags |= AV_PKT_FLAG_CORRUPT; 130cabdff1aSopenharmony_ci } 131cabdff1aSopenharmony_ci 132cabdff1aSopenharmony_ci if (presentation) { 133cabdff1aSopenharmony_ci ret = av_packet_copy_props(pkt, in); 134cabdff1aSopenharmony_ci if (ret < 0) 135cabdff1aSopenharmony_ci goto fail; 136cabdff1aSopenharmony_ci } 137cabdff1aSopenharmony_ci pos = pkt->size; 138cabdff1aSopenharmony_ci ret = av_grow_packet(pkt, size); 139cabdff1aSopenharmony_ci if (ret < 0) 140cabdff1aSopenharmony_ci goto fail; 141cabdff1aSopenharmony_ci memcpy(pkt->data + pos, in->data, size); 142cabdff1aSopenharmony_ci 143cabdff1aSopenharmony_ci if (size == in->size) 144cabdff1aSopenharmony_ci av_packet_unref(in); 145cabdff1aSopenharmony_ci else { 146cabdff1aSopenharmony_ci in->data += size; 147cabdff1aSopenharmony_ci in->size -= size; 148cabdff1aSopenharmony_ci } 149cabdff1aSopenharmony_ci 150cabdff1aSopenharmony_ci if (display) 151cabdff1aSopenharmony_ci return frame_merge_output(ctx, out, pkt); 152cabdff1aSopenharmony_ci return AVERROR(EAGAIN); 153cabdff1aSopenharmony_ci 154cabdff1aSopenharmony_cifail: 155cabdff1aSopenharmony_ci frame_merge_flush(bsf); 156cabdff1aSopenharmony_ci return ret; 157cabdff1aSopenharmony_ci} 158cabdff1aSopenharmony_ci 159cabdff1aSopenharmony_cistatic av_cold int frame_merge_init(AVBSFContext *bsf) 160cabdff1aSopenharmony_ci{ 161cabdff1aSopenharmony_ci PGSMergeContext *ctx = bsf->priv_data; 162cabdff1aSopenharmony_ci 163cabdff1aSopenharmony_ci ctx->in = av_packet_alloc(); 164cabdff1aSopenharmony_ci ctx->buffer_pkt = av_packet_alloc(); 165cabdff1aSopenharmony_ci if (!ctx->in || !ctx->buffer_pkt) 166cabdff1aSopenharmony_ci return AVERROR(ENOMEM); 167cabdff1aSopenharmony_ci 168cabdff1aSopenharmony_ci return 0; 169cabdff1aSopenharmony_ci} 170cabdff1aSopenharmony_ci 171cabdff1aSopenharmony_cistatic av_cold void frame_merge_close(AVBSFContext *bsf) 172cabdff1aSopenharmony_ci{ 173cabdff1aSopenharmony_ci PGSMergeContext *ctx = bsf->priv_data; 174cabdff1aSopenharmony_ci 175cabdff1aSopenharmony_ci av_packet_free(&ctx->in); 176cabdff1aSopenharmony_ci av_packet_free(&ctx->buffer_pkt); 177cabdff1aSopenharmony_ci} 178cabdff1aSopenharmony_ci 179cabdff1aSopenharmony_cistatic const enum AVCodecID frame_merge_codec_ids[] = { 180cabdff1aSopenharmony_ci AV_CODEC_ID_HDMV_PGS_SUBTITLE, AV_CODEC_ID_NONE, 181cabdff1aSopenharmony_ci}; 182cabdff1aSopenharmony_ci 183cabdff1aSopenharmony_ciconst FFBitStreamFilter ff_pgs_frame_merge_bsf = { 184cabdff1aSopenharmony_ci .p.name = "pgs_frame_merge", 185cabdff1aSopenharmony_ci .p.codec_ids = frame_merge_codec_ids, 186cabdff1aSopenharmony_ci .priv_data_size = sizeof(PGSMergeContext), 187cabdff1aSopenharmony_ci .init = frame_merge_init, 188cabdff1aSopenharmony_ci .flush = frame_merge_flush, 189cabdff1aSopenharmony_ci .close = frame_merge_close, 190cabdff1aSopenharmony_ci .filter = frame_merge_filter, 191cabdff1aSopenharmony_ci}; 192