FFmpeg  4.4.4
ttmlenc.c
Go to the documentation of this file.
1 /*
2  * TTML subtitle muxer
3  * Copyright (c) 2020 24i
4  *
5  * This file is part of FFmpeg.
6  *
7  * FFmpeg is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * FFmpeg is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with FFmpeg; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20  */
21 
22 /**
23  * @file
24  * TTML subtitle muxer
25  * @see https://www.w3.org/TR/ttml1/
26  * @see https://www.w3.org/TR/ttml2/
27  * @see https://www.w3.org/TR/ttml-imsc/rec
28  */
29 
30 #include "avformat.h"
31 #include "internal.h"
32 #include "libavcodec/ttmlenc.h"
33 #include "libavutil/internal.h"
34 
38 };
39 
40 typedef struct TTMLMuxContext {
42  unsigned int document_written;
44 
45 static const char ttml_header_text[] =
46 "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"
47 "<tt\n"
48 " xmlns=\"http://www.w3.org/ns/ttml\"\n"
49 " xmlns:ttm=\"http://www.w3.org/ns/ttml#metadata\"\n"
50 " xmlns:tts=\"http://www.w3.org/ns/ttml#styling\"\n"
51 " xml:lang=\"%s\">\n"
52 " <body>\n"
53 " <div>\n";
54 
55 static const char ttml_footer_text[] =
56 " </div>\n"
57 " </body>\n"
58 "</tt>\n";
59 
60 static void ttml_write_time(AVIOContext *pb, const char tag[],
61  int64_t millisec)
62 {
63  int64_t sec, min, hour;
64  sec = millisec / 1000;
65  millisec -= 1000 * sec;
66  min = sec / 60;
67  sec -= 60 * min;
68  hour = min / 60;
69  min -= 60 * hour;
70 
71  avio_printf(pb, "%s=\"%02"PRId64":%02"PRId64":%02"PRId64".%03"PRId64"\"",
72  tag, hour, min, sec, millisec);
73 }
74 
76 {
77  TTMLMuxContext *ttml_ctx = ctx->priv_data;
78  ttml_ctx->document_written = 0;
79 
80  if (ctx->nb_streams != 1 ||
82  av_log(ctx, AV_LOG_ERROR, "Exactly one TTML stream is required!\n");
83  return AVERROR(EINVAL);
84  }
85 
86  {
87  AVStream *st = ctx->streams[0];
88  AVIOContext *pb = ctx->pb;
89 
90  AVDictionaryEntry *lang = av_dict_get(st->metadata, "language", NULL,
91  0);
92  const char *printed_lang = (lang && lang->value) ? lang->value : "";
93 
94  // Not perfect, but decide whether the packet is a document or not
95  // by the existence of the lavc ttmlenc extradata.
96  ttml_ctx->input_type = (st->codecpar->extradata &&
98  !memcmp(st->codecpar->extradata,
103 
104  avpriv_set_pts_info(st, 64, 1, 1000);
105 
106  if (ttml_ctx->input_type == PACKET_TYPE_PARAGRAPH)
107  avio_printf(pb, ttml_header_text, printed_lang);
108  }
109 
110  return 0;
111 }
112 
114 {
115  TTMLMuxContext *ttml_ctx = ctx->priv_data;
116  AVIOContext *pb = ctx->pb;
117 
118  switch (ttml_ctx->input_type) {
120  // write out a paragraph element with the given contents.
121  avio_printf(pb, " <p\n");
122  ttml_write_time(pb, " begin", pkt->pts);
123  avio_w8(pb, '\n');
124  ttml_write_time(pb, " end", pkt->pts + pkt->duration);
125  avio_printf(pb, ">");
126  avio_write(pb, pkt->data, pkt->size);
127  avio_printf(pb, "</p>\n");
128  break;
130  // dump the given document out as-is.
131  if (ttml_ctx->document_written) {
133  "Attempting to write multiple TTML documents into a "
134  "single document! The XML specification forbids this "
135  "as there has to be a single root tag.\n");
136  return AVERROR(EINVAL);
137  }
138  avio_write(pb, pkt->data, pkt->size);
139  ttml_ctx->document_written = 1;
140  break;
141  default:
143  "Internal error: invalid TTML input packet type: %d!\n",
144  ttml_ctx->input_type);
145  return AVERROR_BUG;
146  }
147 
148  return 0;
149 }
150 
152 {
153  TTMLMuxContext *ttml_ctx = ctx->priv_data;
154  AVIOContext *pb = ctx->pb;
155 
156  if (ttml_ctx->input_type == PACKET_TYPE_PARAGRAPH)
158 
159  return 0;
160 }
161 
163  .name = "ttml",
164  .long_name = NULL_IF_CONFIG_SMALL("TTML subtitle"),
165  .extensions = "ttml",
166  .mime_type = "text/ttml",
167  .priv_data_size = sizeof(TTMLMuxContext),
170  .subtitle_codec = AV_CODEC_ID_TTML,
174 };
Main libavformat public API header.
#define AVFMT_VARIABLE_FPS
Format allows variable fps.
Definition: avformat.h:465
#define AVFMT_TS_NONSTRICT
Format does not require strictly increasing timestamps, but they must still be monotonic.
Definition: avformat.h:472
#define AVFMT_GLOBALHEADER
Format wants global header.
Definition: avformat.h:461
void avio_w8(AVIOContext *s, int b)
Definition: aviobuf.c:203
int avio_printf(AVIOContext *s, const char *fmt,...) av_printf_format(2
Writes a formatted string to the context.
void avio_write(AVIOContext *s, const unsigned char *buf, int size)
Definition: aviobuf.c:225
#define flags(name, subs,...)
Definition: cbs_av1.c:561
#define NULL
Definition: coverity.c:32
static void write_packet(OutputFile *of, AVPacket *pkt, OutputStream *ost, int unqueue)
Definition: ffmpeg.c:729
static void write_header(FFV1Context *f)
Definition: ffv1enc.c:346
@ AV_CODEC_ID_TTML
Definition: codec_id.h:548
AVDictionaryEntry * av_dict_get(const AVDictionary *m, const char *key, const AVDictionaryEntry *prev, int flags)
Get a dictionary entry with matching key.
Definition: dict.c:40
#define AVERROR_BUG
Internal bug, also see AVERROR_BUG2.
Definition: error.h:50
#define AVERROR(e)
Definition: error.h:43
#define AV_LOG_ERROR
Something went wrong and cannot losslessly be recovered.
Definition: log.h:194
void avpriv_set_pts_info(AVStream *s, int pts_wrap_bits, unsigned int pts_num, unsigned int pts_den)
Set the time base and wrapping info for a given stream.
Definition: utils.c:4945
static int ttml_write_header(AVFormatContext *ctx)
Definition: ttmlenc.c:75
TTMLPacketType
Definition: ttmlenc.c:35
@ PACKET_TYPE_PARAGRAPH
Definition: ttmlenc.c:36
@ PACKET_TYPE_DOCUMENT
Definition: ttmlenc.c:37
static int ttml_write_trailer(AVFormatContext *ctx)
Definition: ttmlenc.c:151
static int ttml_write_packet(AVFormatContext *ctx, AVPacket *pkt)
Definition: ttmlenc.c:113
static const char ttml_footer_text[]
Definition: ttmlenc.c:55
AVOutputFormat ff_ttml_muxer
Definition: ttmlenc.c:162
static const char ttml_header_text[]
Definition: ttmlenc.c:45
static void ttml_write_time(AVIOContext *pb, const char tag[], int64_t millisec)
Definition: ttmlenc.c:60
common internal API header
#define NULL_IF_CONFIG_SMALL(x)
Return NULL if CONFIG_SMALL is true, otherwise the argument without modification.
Definition: internal.h:117
uint32_t tag
Definition: movenc.c:1611
int extradata_size
Size of the extradata content in bytes.
Definition: codec_par.h:78
uint8_t * extradata
Extra binary data needed for initializing the decoder, codec-dependent.
Definition: codec_par.h:74
enum AVCodecID codec_id
Specific type of the encoded data (the codec used).
Definition: codec_par.h:60
char * value
Definition: dict.h:83
Format I/O context.
Definition: avformat.h:1232
unsigned int nb_streams
Number of elements in AVFormatContext.streams.
Definition: avformat.h:1288
AVIOContext * pb
I/O context.
Definition: avformat.h:1274
void * priv_data
Format private data.
Definition: avformat.h:1260
AVStream ** streams
A list of all streams in the file.
Definition: avformat.h:1300
Bytestream IO Context.
Definition: avio.h:161
const char * name
Definition: avformat.h:491
This structure stores compressed data.
Definition: packet.h:346
int size
Definition: packet.h:370
int64_t duration
Duration of this packet in AVStream->time_base units, 0 if unknown.
Definition: packet.h:387
int64_t pts
Presentation timestamp in AVStream->time_base units; the time at which the decompressed packet will b...
Definition: packet.h:362
uint8_t * data
Definition: packet.h:369
Stream structure.
Definition: avformat.h:873
AVCodecParameters * codecpar
Codec parameters associated with this stream.
Definition: avformat.h:1038
AVDictionary * metadata
Definition: avformat.h:937
enum TTMLPacketType input_type
Definition: ttmlenc.c:41
unsigned int document_written
Definition: ttmlenc.c:42
#define av_log(a,...)
AVPacket * pkt
Definition: movenc.c:59
AVFormatContext * ctx
Definition: movenc.c:48
#define TTMLENC_EXTRADATA_SIGNATURE
Definition: ttmlenc.h:25
#define TTMLENC_EXTRADATA_SIGNATURE_SIZE
Definition: ttmlenc.h:26
static int write_trailer(AVFormatContext *s1)
Definition: v4l2enc.c:98
float min