FFmpeg
pgs_frame_merge_bsf.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2020 John Stebbins <jstebbins.hb@gmail.com>
3  *
4  * This file is part of FFmpeg.
5  *
6  * FFmpeg is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * FFmpeg is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with FFmpeg; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19  */
20 
21 /**
22  * @file
23  * This bitstream filter merges PGS subtitle packets containing incomplete
24  * set of segments into a single packet
25  *
26  * Packets already containing a complete set of segments will be passed through
27  * unchanged.
28  */
29 
30 #include "libavutil/attributes.h"
31 #include "libavutil/intreadwrite.h"
32 #include "libavutil/log.h"
33 #include "bsf.h"
34 #include "bsf_internal.h"
35 
42 };
43 
44 typedef struct PGSMergeContext {
47  int pkt_flags;
49 
51 {
53 
54  ctx->presentation_found = ctx->pkt_flags = 0;
55  av_packet_unref(ctx->in);
56  av_packet_unref(ctx->buffer_pkt);
57 }
58 
60 {
61  if (!ctx->presentation_found)
62  ctx->pkt_flags |= AV_PKT_FLAG_CORRUPT;
63  ctx->presentation_found = 0;
64  src->flags |= ctx->pkt_flags;
65  ctx->pkt_flags = 0;
66  av_packet_move_ref(dst, src);
67  return 0;
68 }
69 
71 {
73  AVPacket *in = ctx->in, *pkt = ctx->buffer_pkt;
74  int ret, size, pos, display = 0, presentation = 0;
75  unsigned int i;
76 
77  if (!in->data) {
78  ret = ff_bsf_get_packet_ref(bsf, in);
79  if (ret == AVERROR_EOF && pkt->data) {
80  // Output remaining data
81  ctx->pkt_flags |= AV_PKT_FLAG_CORRUPT;
82  return frame_merge_output(ctx, out, pkt);
83  }
84  if (ret < 0)
85  return ret;
86  }
87  if (!in->size) {
88  av_packet_unref(in);
89  return AVERROR(EAGAIN);
90  }
91  in->flags &= ~AV_PKT_FLAG_KEY; // Will be detected in the stream
92 
93  // Validate packet data and find display_end segment
94  size = in->size;
95  i = 0;
96  while (i + 3 <= in->size) {
97  uint8_t segment_type = in->data[i];
98  int segment_len = AV_RB16(in->data + i + 1) + 3;
99 
100  if (i + segment_len > in->size)
101  break; // Invalid, segments can't span packets
102  if (segment_type == PRESENTATION_SEGMENT && ctx->presentation_found)
103  break; // Invalid, there can be only one
104  if (segment_type == PRESENTATION_SEGMENT) {
105  uint8_t state;
106  if (segment_len < 11)
107  break; // Invalid presentation segment length
108  ctx->presentation_found = presentation = 1;
109  state = in->data[i + 10] & 0xc0;
110  if (state)
111  ctx->pkt_flags |= AV_PKT_FLAG_KEY;
112  else
113  ctx->pkt_flags &= ~AV_PKT_FLAG_KEY;
114  }
115  i += segment_len;
116  if (segment_type == END_DISPLAY_SET_SEGMENT) {
117  size = i;
118  display = 1;
119  break;
120  }
121  }
122  if (display && pkt->size == 0 && size == in->size) // passthrough
123  return frame_merge_output(ctx, out, in);
124  if (!display && i != in->size) {
125  av_log(bsf, AV_LOG_WARNING, "Failed to parse PGS segments.\n");
126  // force output what we have
127  size = in->size;
128  display = 1;
129  ctx->pkt_flags |= AV_PKT_FLAG_CORRUPT;
130  }
131 
132  if (presentation) {
134  if (ret < 0)
135  goto fail;
136  }
137  pos = pkt->size;
139  if (ret < 0)
140  goto fail;
141  memcpy(pkt->data + pos, in->data, size);
142 
143  if (size == in->size)
144  av_packet_unref(in);
145  else {
146  in->data += size;
147  in->size -= size;
148  }
149 
150  if (display)
151  return frame_merge_output(ctx, out, pkt);
152  return AVERROR(EAGAIN);
153 
154 fail:
155  frame_merge_flush(bsf);
156  return ret;
157 }
158 
160 {
161  PGSMergeContext *ctx = bsf->priv_data;
162 
163  ctx->in = av_packet_alloc();
164  ctx->buffer_pkt = av_packet_alloc();
165  if (!ctx->in || !ctx->buffer_pkt)
166  return AVERROR(ENOMEM);
167 
168  return 0;
169 }
170 
172 {
173  PGSMergeContext *ctx = bsf->priv_data;
174 
175  av_packet_free(&ctx->in);
176  av_packet_free(&ctx->buffer_pkt);
177 }
178 
179 static const enum AVCodecID frame_merge_codec_ids[] = {
181 };
182 
184  .p.name = "pgs_frame_merge",
185  .p.codec_ids = frame_merge_codec_ids,
186  .priv_data_size = sizeof(PGSMergeContext),
189  .close = frame_merge_close,
191 };
frame_merge_output
static int frame_merge_output(PGSMergeContext *ctx, AVPacket *dst, AVPacket *src)
Definition: pgs_frame_merge_bsf.c:59
av_packet_unref
void av_packet_unref(AVPacket *pkt)
Wipe the packet.
Definition: avpacket.c:426
AV_LOG_WARNING
#define AV_LOG_WARNING
Something somehow does not look correct.
Definition: log.h:186
PALETTE_SEGMENT
@ PALETTE_SEGMENT
Definition: pgs_frame_merge_bsf.c:37
AVERROR
Filter the word “frame” indicates either a video frame or a group of audio as stored in an AVFrame structure Format for each input and each output the list of supported formats For video that means pixel format For audio that means channel sample they are references to shared objects When the negotiation mechanism computes the intersection of the formats supported at each end of a all references to both lists are replaced with a reference to the intersection And when a single format is eventually chosen for a link amongst the remaining all references to the list are updated That means that if a filter requires that its input and output have the same format amongst a supported all it has to do is use a reference to the same list of formats query_formats can leave some formats unset and return AVERROR(EAGAIN) to cause the negotiation mechanism toagain later. That can be used by filters with complex requirements to use the format negotiated on one link to set the formats supported on another. Frame references ownership and permissions
bsf_internal.h
out
FILE * out
Definition: movenc.c:54
AVERROR_EOF
#define AVERROR_EOF
End of file.
Definition: error.h:57
AVBitStreamFilter::name
const char * name
Definition: bsf.h:112
av_grow_packet
int av_grow_packet(AVPacket *pkt, int grow_by)
Increase packet size, correctly zeroing padding.
Definition: avpacket.c:121
AVPacket::data
uint8_t * data
Definition: packet.h:515
filter
filter_frame For filters that do not use the this method is called when a frame is pushed to the filter s input It can be called at any time except in a reentrant way If the input frame is enough to produce then the filter should push the output frames on the output link immediately As an exception to the previous rule if the input frame is enough to produce several output frames then the filter needs output only at least one per link The additional frames can be left buffered in the filter
Definition: filter_design.txt:228
AV_CODEC_ID_HDMV_PGS_SUBTITLE
@ AV_CODEC_ID_HDMV_PGS_SUBTITLE
Definition: codec_id.h:558
AV_PKT_FLAG_KEY
#define AV_PKT_FLAG_KEY
The packet contains a keyframe.
Definition: packet.h:570
av_packet_free
void av_packet_free(AVPacket **pkt)
Free the packet, if the packet is reference counted, it will be unreferenced first.
Definition: avpacket.c:74
AVBSFContext
The bitstream filter state.
Definition: bsf.h:68
frame_merge_flush
static av_cold void frame_merge_flush(AVBSFContext *bsf)
Definition: pgs_frame_merge_bsf.c:50
ff_pgs_frame_merge_bsf
const FFBitStreamFilter ff_pgs_frame_merge_bsf
Definition: pgs_frame_merge_bsf.c:183
bsf.h
fail
#define fail()
Definition: checkasm.h:177
END_DISPLAY_SET_SEGMENT
@ END_DISPLAY_SET_SEGMENT
Definition: pgs_frame_merge_bsf.c:41
WINDOW_SEGMENT
@ WINDOW_SEGMENT
Definition: pgs_frame_merge_bsf.c:40
frame_merge_close
static av_cold void frame_merge_close(AVBSFContext *bsf)
Definition: pgs_frame_merge_bsf.c:171
frame_merge_codec_ids
static enum AVCodecID frame_merge_codec_ids[]
Definition: pgs_frame_merge_bsf.c:179
pkt
AVPacket * pkt
Definition: movenc.c:59
av_cold
#define av_cold
Definition: attributes.h:90
AV_PKT_FLAG_CORRUPT
#define AV_PKT_FLAG_CORRUPT
The packet content is corrupted.
Definition: packet.h:571
intreadwrite.h
init
int(* init)(AVBSFContext *ctx)
Definition: dts2pts_bsf.c:365
ctx
AVFormatContext * ctx
Definition: movenc.c:48
frame_merge_filter
static int frame_merge_filter(AVBSFContext *bsf, AVPacket *out)
Definition: pgs_frame_merge_bsf.c:70
OBJECT_SEGMENT
@ OBJECT_SEGMENT
Definition: pgs_frame_merge_bsf.c:38
PGSSegmentType
PGSSegmentType
Definition: pgs_frame_merge_bsf.c:36
FFBitStreamFilter
Definition: bsf_internal.h:27
PRESENTATION_SEGMENT
@ PRESENTATION_SEGMENT
Definition: pgs_frame_merge_bsf.c:39
PGSMergeContext::buffer_pkt
AVPacket * buffer_pkt
Definition: pgs_frame_merge_bsf.c:45
av_packet_move_ref
void av_packet_move_ref(AVPacket *dst, AVPacket *src)
Move every field in src to dst and reset src.
Definition: avpacket.c:483
AVCodecID
AVCodecID
Identify the syntax and semantics of the bitstream.
Definition: codec_id.h:49
FFBitStreamFilter::p
AVBitStreamFilter p
The public AVBitStreamFilter.
Definition: bsf_internal.h:31
AVPacket::size
int size
Definition: packet.h:516
size
int size
Definition: twinvq_data.h:10344
attributes.h
AVPacket::flags
int flags
A combination of AV_PKT_FLAG values.
Definition: packet.h:521
av_packet_alloc
AVPacket * av_packet_alloc(void)
Allocate an AVPacket and set its fields to default values.
Definition: avpacket.c:63
av_packet_copy_props
int av_packet_copy_props(AVPacket *dst, const AVPacket *src)
Copy only "properties" fields from src to dst.
Definition: avpacket.c:389
log.h
AV_CODEC_ID_NONE
@ AV_CODEC_ID_NONE
Definition: codec_id.h:50
i
#define i(width, name, range_min, range_max)
Definition: cbs_h2645.c:245
PGSMergeContext::presentation_found
int presentation_found
Definition: pgs_frame_merge_bsf.c:46
PGSMergeContext
Definition: pgs_frame_merge_bsf.c:44
AVBSFContext::priv_data
void * priv_data
Opaque filter-specific private data.
Definition: bsf.h:83
ret
ret
Definition: filter_design.txt:187
pos
unsigned int pos
Definition: spdifenc.c:413
frame_merge_init
static av_cold int frame_merge_init(AVBSFContext *bsf)
Definition: pgs_frame_merge_bsf.c:159
flush
void(* flush)(AVBSFContext *ctx)
Definition: dts2pts_bsf.c:367
PGSMergeContext::in
AVPacket * in
Definition: pgs_frame_merge_bsf.c:45
AVPacket
This structure stores compressed data.
Definition: packet.h:492
src
INIT_CLIP pixel * src
Definition: h264pred_template.c:418
state
static struct @374 state
av_log
#define av_log(a,...)
Definition: tableprint_vlc.h:27
ff_bsf_get_packet_ref
int ff_bsf_get_packet_ref(AVBSFContext *ctx, AVPacket *pkt)
Called by bitstream filters to get packet for filtering.
Definition: bsf.c:256
PGSMergeContext::pkt_flags
int pkt_flags
Definition: pgs_frame_merge_bsf.c:47
AV_RB16
uint64_t_TMPL AV_WL64 unsigned int_TMPL AV_WL32 unsigned int_TMPL AV_WL24 unsigned int_TMPL AV_WL16 uint64_t_TMPL AV_WB64 unsigned int_TMPL AV_WB32 unsigned int_TMPL AV_WB24 unsigned int_TMPL AV_RB16
Definition: bytestream.h:98