Go to most recent revision | Details | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
4349 | Serge | 1 | /* |
2 | * SSA/ASS muxer |
||
3 | * Copyright (c) 2008 Michael Niedermayer |
||
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 | #include "avformat.h" |
||
23 | #include "internal.h" |
||
24 | |||
25 | typedef struct ASSContext{ |
||
26 | unsigned int extra_index; |
||
27 | int write_ts; // 0: ssa (timing in payload), 1: ass (matroska like) |
||
28 | }ASSContext; |
||
29 | |||
30 | static int write_header(AVFormatContext *s) |
||
31 | { |
||
32 | ASSContext *ass = s->priv_data; |
||
33 | AVCodecContext *avctx= s->streams[0]->codec; |
||
34 | uint8_t *last= NULL; |
||
35 | |||
36 | if (s->nb_streams != 1 || (avctx->codec_id != AV_CODEC_ID_SSA && |
||
37 | avctx->codec_id != AV_CODEC_ID_ASS)) { |
||
38 | av_log(s, AV_LOG_ERROR, "Exactly one ASS/SSA stream is needed.\n"); |
||
39 | return -1; |
||
40 | } |
||
41 | ass->write_ts = avctx->codec_id == AV_CODEC_ID_ASS; |
||
42 | avpriv_set_pts_info(s->streams[0], 64, 1, 100); |
||
43 | |||
44 | while(ass->extra_index < avctx->extradata_size){ |
||
45 | uint8_t *p = avctx->extradata + ass->extra_index; |
||
46 | uint8_t *end= strchr(p, '\n'); |
||
47 | if(!end) end= avctx->extradata + avctx->extradata_size; |
||
48 | else end++; |
||
49 | |||
50 | avio_write(s->pb, p, end-p); |
||
51 | ass->extra_index += end-p; |
||
52 | |||
53 | if(last && !memcmp(last, "[Events]", 8)) |
||
54 | break; |
||
55 | last=p; |
||
56 | } |
||
57 | |||
58 | avio_flush(s->pb); |
||
59 | |||
60 | return 0; |
||
61 | } |
||
62 | |||
63 | static int write_packet(AVFormatContext *s, AVPacket *pkt) |
||
64 | { |
||
65 | ASSContext *ass = s->priv_data; |
||
66 | |||
67 | if (ass->write_ts) { |
||
68 | long int layer; |
||
69 | char *p; |
||
70 | int64_t start = pkt->pts; |
||
71 | int64_t end = start + pkt->duration; |
||
72 | int hh1, mm1, ss1, ms1; |
||
73 | int hh2, mm2, ss2, ms2; |
||
74 | |||
75 | p = pkt->data + strcspn(pkt->data, ",") + 1; // skip ReadOrder |
||
76 | layer = strtol(p, &p, 10); |
||
77 | if (*p == ',') |
||
78 | p++; |
||
79 | hh1 = (int)(start / 360000); mm1 = (int)(start / 6000) % 60; |
||
80 | hh2 = (int)(end / 360000); mm2 = (int)(end / 6000) % 60; |
||
81 | ss1 = (int)(start / 100) % 60; ms1 = (int)(start % 100); |
||
82 | ss2 = (int)(end / 100) % 60; ms2 = (int)(end % 100); |
||
83 | if (hh1 > 9) hh1 = 9, mm1 = 59, ss1 = 59, ms1 = 99; |
||
84 | if (hh2 > 9) hh2 = 9, mm2 = 59, ss2 = 59, ms2 = 99; |
||
85 | avio_printf(s->pb, "Dialogue: %ld,%d:%02d:%02d.%02d,%d:%02d:%02d.%02d,%s\r\n", |
||
86 | layer, hh1, mm1, ss1, ms1, hh2, mm2, ss2, ms2, p); |
||
87 | } else { |
||
88 | avio_write(s->pb, pkt->data, pkt->size); |
||
89 | } |
||
90 | |||
91 | return 0; |
||
92 | } |
||
93 | |||
94 | static int write_trailer(AVFormatContext *s) |
||
95 | { |
||
96 | ASSContext *ass = s->priv_data; |
||
97 | AVCodecContext *avctx= s->streams[0]->codec; |
||
98 | |||
99 | avio_write(s->pb, avctx->extradata + ass->extra_index, |
||
100 | avctx->extradata_size - ass->extra_index); |
||
101 | |||
102 | return 0; |
||
103 | } |
||
104 | |||
105 | AVOutputFormat ff_ass_muxer = { |
||
106 | .name = "ass", |
||
107 | .long_name = NULL_IF_CONFIG_SMALL("SSA (SubStation Alpha) subtitle"), |
||
108 | .mime_type = "text/x-ssa", |
||
109 | .extensions = "ass,ssa", |
||
110 | .priv_data_size = sizeof(ASSContext), |
||
111 | .subtitle_codec = AV_CODEC_ID_SSA, |
||
112 | .write_header = write_header, |
||
113 | .write_packet = write_packet, |
||
114 | .write_trailer = write_trailer, |
||
115 | .flags = AVFMT_GLOBALHEADER | AVFMT_NOTIMESTAMPS | AVFMT_TS_NONSTRICT, |
||
116 | };> |