| @@ -193,28 +193,6 @@ static const char *srt_to_ass(AVCodecContext *avctx, char *out, char *out_end, | |||||
| return in; | return in; | ||||
| } | } | ||||
| static const char *read_ts(const char *buf, int *ts_start, int *ts_end, | |||||
| int *x1, int *y1, int *x2, int *y2) | |||||
| { | |||||
| int i, hs, ms, ss, he, me, se; | |||||
| for (i=0; i<2; i++) { | |||||
| /* try to read timestamps in either the first or second line */ | |||||
| int c = sscanf(buf, "%d:%2d:%2d%*1[,.]%3d --> %d:%2d:%2d%*1[,.]%3d" | |||||
| "%*[ ]X1:%u X2:%u Y1:%u Y2:%u", | |||||
| &hs, &ms, &ss, ts_start, &he, &me, &se, ts_end, | |||||
| x1, x2, y1, y2); | |||||
| buf += strcspn(buf, "\n"); | |||||
| buf += !!*buf; | |||||
| if (c >= 8) { | |||||
| *ts_start = 100*(ss + 60*(ms + 60*hs)) + *ts_start/10; | |||||
| *ts_end = 100*(se + 60*(me + 60*he)) + *ts_end /10; | |||||
| return buf; | |||||
| } | |||||
| } | |||||
| return NULL; | |||||
| } | |||||
| static int srt_decode_frame(AVCodecContext *avctx, | static int srt_decode_frame(AVCodecContext *avctx, | ||||
| void *data, int *got_sub_ptr, AVPacket *avpkt) | void *data, int *got_sub_ptr, AVPacket *avpkt) | ||||
| { | { | ||||
| @@ -237,11 +215,7 @@ static int srt_decode_frame(AVCodecContext *avctx, | |||||
| return avpkt->size; | return avpkt->size; | ||||
| while (ptr < end && *ptr) { | while (ptr < end && *ptr) { | ||||
| if (avctx->codec->id == AV_CODEC_ID_SRT) { | |||||
| ptr = read_ts(ptr, &ts_start, &ts_end, &x1, &y1, &x2, &y2); | |||||
| if (!ptr) | |||||
| break; | |||||
| } else { | |||||
| // TODO: reindent | |||||
| // Do final divide-by-10 outside rescale to force rounding down. | // Do final divide-by-10 outside rescale to force rounding down. | ||||
| ts_start = av_rescale_q(avpkt->pts, | ts_start = av_rescale_q(avpkt->pts, | ||||
| avctx->time_base, | avctx->time_base, | ||||
| @@ -249,7 +223,6 @@ static int srt_decode_frame(AVCodecContext *avctx, | |||||
| ts_end = av_rescale_q(avpkt->pts + avpkt->duration, | ts_end = av_rescale_q(avpkt->pts + avpkt->duration, | ||||
| avctx->time_base, | avctx->time_base, | ||||
| (AVRational){1,100}); | (AVRational){1,100}); | ||||
| } | |||||
| ptr = srt_to_ass(avctx, buffer, buffer+sizeof(buffer), ptr, | ptr = srt_to_ass(avctx, buffer, buffer+sizeof(buffer), ptr, | ||||
| x1, y1, x2, y2); | x1, y1, x2, y2); | ||||
| ret = ff_ass_add_rect(sub, buffer, ts_start, ts_end-ts_start, 0); | ret = ff_ass_add_rect(sub, buffer, ts_start, ts_end-ts_start, 0); | ||||
| @@ -265,9 +238,9 @@ static int srt_decode_frame(AVCodecContext *avctx, | |||||
| /* deprecated decoder */ | /* deprecated decoder */ | ||||
| AVCodec ff_srt_decoder = { | AVCodec ff_srt_decoder = { | ||||
| .name = "srt", | .name = "srt", | ||||
| .long_name = NULL_IF_CONFIG_SMALL("SubRip subtitle with embedded timing"), | |||||
| .long_name = NULL_IF_CONFIG_SMALL("SubRip subtitle"), | |||||
| .type = AVMEDIA_TYPE_SUBTITLE, | .type = AVMEDIA_TYPE_SUBTITLE, | ||||
| .id = AV_CODEC_ID_SRT, | |||||
| .id = AV_CODEC_ID_SUBRIP, | |||||
| .init = ff_ass_subtitle_header_default, | .init = ff_ass_subtitle_header_default, | ||||
| .decode = srt_decode_frame, | .decode = srt_decode_frame, | ||||
| }; | }; | ||||
| @@ -33,8 +33,6 @@ typedef struct { | |||||
| AVCodecContext *avctx; | AVCodecContext *avctx; | ||||
| ASSSplitContext *ass_ctx; | ASSSplitContext *ass_ctx; | ||||
| AVBPrint buffer; | AVBPrint buffer; | ||||
| unsigned timestamp_end; | |||||
| int count; | |||||
| char stack[SRT_STACK_SIZE]; | char stack[SRT_STACK_SIZE]; | ||||
| int stack_ptr; | int stack_ptr; | ||||
| int alignment_applied; | int alignment_applied; | ||||
| @@ -201,35 +199,13 @@ static void srt_cancel_overrides_cb(void *priv, const char *style) | |||||
| static void srt_move_cb(void *priv, int x1, int y1, int x2, int y2, | static void srt_move_cb(void *priv, int x1, int y1, int x2, int y2, | ||||
| int t1, int t2) | int t1, int t2) | ||||
| { | { | ||||
| SRTContext *s = priv; | |||||
| if (s->avctx->codec->id == AV_CODEC_ID_SRT) { | |||||
| char buffer[32]; | |||||
| int len = snprintf(buffer, sizeof(buffer), | |||||
| " X1:%03u X2:%03u Y1:%03u Y2:%03u", x1, x2, y1, y2); | |||||
| unsigned char *dummy; | |||||
| unsigned room; | |||||
| av_bprint_get_buffer(&s->buffer, len, &dummy, &room); | |||||
| if (room >= len) { | |||||
| memmove(s->buffer.str + s->timestamp_end + len, | |||||
| s->buffer.str + s->timestamp_end, | |||||
| s->buffer.len - s->timestamp_end + 1); | |||||
| memcpy(s->buffer.str + s->timestamp_end, buffer, len); | |||||
| } | |||||
| /* Increment even if av_bprint_get_buffer() did not return enough room: | |||||
| the bprint structure will be treated as truncated. */ | |||||
| s->buffer.len += len; | |||||
| } | |||||
| // TODO: add a AV_PKT_DATA_SUBTITLE_POSITION side data when a new subtitles | |||||
| // encoding API passing the AVPacket is available. | |||||
| } | } | ||||
| static void srt_end_cb(void *priv) | static void srt_end_cb(void *priv) | ||||
| { | { | ||||
| SRTContext *s = priv; | |||||
| srt_stack_push_pop(priv, 0, 1); | srt_stack_push_pop(priv, 0, 1); | ||||
| if (s->avctx->codec->id == AV_CODEC_ID_SRT) | |||||
| srt_print(priv, "\r\n\r\n"); | |||||
| } | } | ||||
| static const ASSCodesCallbacks srt_callbacks = { | static const ASSCodesCallbacks srt_callbacks = { | ||||
| @@ -263,19 +239,6 @@ static int srt_encode_frame(AVCodecContext *avctx, | |||||
| dialog = ff_ass_split_dialog(s->ass_ctx, sub->rects[i]->ass, 0, &num); | dialog = ff_ass_split_dialog(s->ass_ctx, sub->rects[i]->ass, 0, &num); | ||||
| for (; dialog && num--; dialog++) { | for (; dialog && num--; dialog++) { | ||||
| if (avctx->codec->id == AV_CODEC_ID_SRT) { | |||||
| int sh, sm, ss, sc = 10 * dialog->start; | |||||
| int eh, em, es, ec = 10 * dialog->end; | |||||
| sh = sc/3600000; sc -= 3600000*sh; | |||||
| sm = sc/ 60000; sc -= 60000*sm; | |||||
| ss = sc/ 1000; sc -= 1000*ss; | |||||
| eh = ec/3600000; ec -= 3600000*eh; | |||||
| em = ec/ 60000; ec -= 60000*em; | |||||
| es = ec/ 1000; ec -= 1000*es; | |||||
| srt_print(s,"%d\r\n%02d:%02d:%02d,%03d --> %02d:%02d:%02d,%03d\r\n", | |||||
| ++s->count, sh, sm, ss, sc, eh, em, es, ec); | |||||
| s->timestamp_end = s->buffer.len - 2; | |||||
| } | |||||
| s->alignment_applied = 0; | s->alignment_applied = 0; | ||||
| srt_style_apply(s, dialog->style); | srt_style_apply(s, dialog->style); | ||||
| ff_ass_split_override_codes(&srt_callbacks, s, dialog->text); | ff_ass_split_override_codes(&srt_callbacks, s, dialog->text); | ||||
| @@ -308,9 +271,9 @@ static int srt_encode_close(AVCodecContext *avctx) | |||||
| /* deprecated encoder */ | /* deprecated encoder */ | ||||
| AVCodec ff_srt_encoder = { | AVCodec ff_srt_encoder = { | ||||
| .name = "srt", | .name = "srt", | ||||
| .long_name = NULL_IF_CONFIG_SMALL("SubRip subtitle with embedded timing"), | |||||
| .long_name = NULL_IF_CONFIG_SMALL("SubRip subtitle"), | |||||
| .type = AVMEDIA_TYPE_SUBTITLE, | .type = AVMEDIA_TYPE_SUBTITLE, | ||||
| .id = AV_CODEC_ID_SRT, | |||||
| .id = AV_CODEC_ID_SUBRIP, | |||||
| .priv_data_size = sizeof(SRTContext), | .priv_data_size = sizeof(SRTContext), | ||||
| .init = srt_encode_init, | .init = srt_encode_init, | ||||
| .encode_sub = srt_encode_frame, | .encode_sub = srt_encode_frame, | ||||
| @@ -30,7 +30,7 @@ | |||||
| #define LIBAVCODEC_VERSION_MAJOR 56 | #define LIBAVCODEC_VERSION_MAJOR 56 | ||||
| #define LIBAVCODEC_VERSION_MINOR 1 | #define LIBAVCODEC_VERSION_MINOR 1 | ||||
| #define LIBAVCODEC_VERSION_MICRO 101 | |||||
| #define LIBAVCODEC_VERSION_MICRO 102 | |||||
| #define LIBAVCODEC_VERSION_INT AV_VERSION_INT(LIBAVCODEC_VERSION_MAJOR, \ | #define LIBAVCODEC_VERSION_INT AV_VERSION_INT(LIBAVCODEC_VERSION_MAJOR, \ | ||||
| LIBAVCODEC_VERSION_MINOR, \ | LIBAVCODEC_VERSION_MINOR, \ | ||||
| @@ -66,7 +66,6 @@ const CodecTags ff_mkv_codec_tags[]={ | |||||
| {"S_TEXT/UTF8" , AV_CODEC_ID_SUBRIP}, | {"S_TEXT/UTF8" , AV_CODEC_ID_SUBRIP}, | ||||
| {"S_TEXT/UTF8" , AV_CODEC_ID_TEXT}, | {"S_TEXT/UTF8" , AV_CODEC_ID_TEXT}, | ||||
| {"S_TEXT/UTF8" , AV_CODEC_ID_SRT}, | |||||
| {"S_TEXT/ASCII" , AV_CODEC_ID_TEXT}, | {"S_TEXT/ASCII" , AV_CODEC_ID_TEXT}, | ||||
| {"S_TEXT/ASS" , AV_CODEC_ID_ASS}, | {"S_TEXT/ASS" , AV_CODEC_ID_ASS}, | ||||
| {"S_TEXT/SSA" , AV_CODEC_ID_ASS}, | {"S_TEXT/SSA" , AV_CODEC_ID_ASS}, | ||||
| @@ -1589,47 +1589,6 @@ static void mkv_write_block(AVFormatContext *s, AVIOContext *pb, | |||||
| } | } | ||||
| } | } | ||||
| static int srt_get_duration(uint8_t **buf) | |||||
| { | |||||
| int i, duration = 0; | |||||
| for (i = 0; i < 2 && !duration; i++) { | |||||
| int s_hour, s_min, s_sec, s_hsec, e_hour, e_min, e_sec, e_hsec; | |||||
| if (sscanf(*buf, "%d:%2d:%2d%*1[,.]%3d --> %d:%2d:%2d%*1[,.]%3d", | |||||
| &s_hour, &s_min, &s_sec, &s_hsec, | |||||
| &e_hour, &e_min, &e_sec, &e_hsec) == 8) { | |||||
| s_min += 60 * s_hour; | |||||
| e_min += 60 * e_hour; | |||||
| s_sec += 60 * s_min; | |||||
| e_sec += 60 * e_min; | |||||
| s_hsec += 1000 * s_sec; | |||||
| e_hsec += 1000 * e_sec; | |||||
| duration = e_hsec - s_hsec; | |||||
| } | |||||
| *buf += ff_subtitles_next_line(*buf); | |||||
| } | |||||
| return duration; | |||||
| } | |||||
| static int mkv_write_srt_blocks(AVFormatContext *s, AVIOContext *pb, | |||||
| AVPacket *pkt) | |||||
| { | |||||
| ebml_master blockgroup; | |||||
| AVPacket pkt2 = *pkt; | |||||
| int64_t duration = srt_get_duration(&pkt2.data); | |||||
| pkt2.size -= pkt2.data - pkt->data; | |||||
| blockgroup = start_ebml_master(pb, MATROSKA_ID_BLOCKGROUP, | |||||
| mkv_blockgroup_size(pkt2.size)); | |||||
| mkv_write_block(s, pb, MATROSKA_ID_BLOCK, &pkt2, 0); | |||||
| put_ebml_uint(pb, MATROSKA_ID_BLOCKDURATION, duration); | |||||
| end_ebml_master(pb, blockgroup); | |||||
| return duration; | |||||
| } | |||||
| static int mkv_write_vtt_blocks(AVFormatContext *s, AVIOContext *pb, AVPacket *pkt) | static int mkv_write_vtt_blocks(AVFormatContext *s, AVIOContext *pb, AVPacket *pkt) | ||||
| { | { | ||||
| MatroskaMuxContext *mkv = s->priv_data; | MatroskaMuxContext *mkv = s->priv_data; | ||||
| @@ -1757,9 +1716,7 @@ static int mkv_write_packet_internal(AVFormatContext *s, AVPacket *pkt, int add_ | |||||
| if (ret < 0) return ret; | if (ret < 0) return ret; | ||||
| } | } | ||||
| } else { | } else { | ||||
| if (codec->codec_id == AV_CODEC_ID_SRT) { | |||||
| duration = mkv_write_srt_blocks(s, pb, pkt); | |||||
| } else if (codec->codec_id == AV_CODEC_ID_WEBVTT) { | |||||
| if (codec->codec_id == AV_CODEC_ID_WEBVTT) { | |||||
| duration = mkv_write_vtt_blocks(s, pb, pkt); | duration = mkv_write_vtt_blocks(s, pb, pkt); | ||||
| } else { | } else { | ||||
| ebml_master blockgroup = start_ebml_master(pb, MATROSKA_ID_BLOCKGROUP, | ebml_master blockgroup = start_ebml_master(pb, MATROSKA_ID_BLOCKGROUP, | ||||
| @@ -45,8 +45,7 @@ static int srt_write_header(AVFormatContext *avf) | |||||
| return AVERROR(EINVAL); | return AVERROR(EINVAL); | ||||
| } | } | ||||
| if (avf->streams[0]->codec->codec_id != AV_CODEC_ID_TEXT && | if (avf->streams[0]->codec->codec_id != AV_CODEC_ID_TEXT && | ||||
| avf->streams[0]->codec->codec_id != AV_CODEC_ID_SUBRIP && | |||||
| avf->streams[0]->codec->codec_id != AV_CODEC_ID_SRT) { | |||||
| avf->streams[0]->codec->codec_id != AV_CODEC_ID_SUBRIP) { | |||||
| av_log(avf, AV_LOG_ERROR, | av_log(avf, AV_LOG_ERROR, | ||||
| "Unsupported subtitles codec: %s\n", | "Unsupported subtitles codec: %s\n", | ||||
| avcodec_get_name(avf->streams[0]->codec->codec_id)); | avcodec_get_name(avf->streams[0]->codec->codec_id)); | ||||
| @@ -60,9 +59,8 @@ static int srt_write_header(AVFormatContext *avf) | |||||
| static int srt_write_packet(AVFormatContext *avf, AVPacket *pkt) | static int srt_write_packet(AVFormatContext *avf, AVPacket *pkt) | ||||
| { | { | ||||
| SRTContext *srt = avf->priv_data; | SRTContext *srt = avf->priv_data; | ||||
| int write_ts = avf->streams[0]->codec->codec_id != AV_CODEC_ID_SRT; | |||||
| if (write_ts) { | |||||
| // TODO: reindent | |||||
| int64_t s = pkt->pts, e, d = pkt->duration; | int64_t s = pkt->pts, e, d = pkt->duration; | ||||
| int size, x1 = -1, y1 = -1, x2 = -1, y2 = -1; | int size, x1 = -1, y1 = -1, x2 = -1, y2 = -1; | ||||
| const uint8_t *p; | const uint8_t *p; | ||||
| @@ -94,10 +92,9 @@ static int srt_write_packet(AVFormatContext *avf, AVPacket *pkt) | |||||
| avio_printf(avf->pb, " X1:%03d X2:%03d Y1:%03d Y2:%03d", | avio_printf(avf->pb, " X1:%03d X2:%03d Y1:%03d Y2:%03d", | ||||
| x1, x2, y1, y2); | x1, x2, y1, y2); | ||||
| avio_printf(avf->pb, "\n"); | avio_printf(avf->pb, "\n"); | ||||
| } | |||||
| avio_write(avf->pb, pkt->data, pkt->size); | avio_write(avf->pb, pkt->data, pkt->size); | ||||
| if (write_ts) | |||||
| avio_write(avf->pb, "\n\n", 2); | |||||
| avio_write(avf->pb, "\n\n", 2); | |||||
| srt->index++; | srt->index++; | ||||
| return 0; | return 0; | ||||
| } | } | ||||
| @@ -31,7 +31,7 @@ | |||||
| #define LIBAVFORMAT_VERSION_MAJOR 56 | #define LIBAVFORMAT_VERSION_MAJOR 56 | ||||
| #define LIBAVFORMAT_VERSION_MINOR 7 | #define LIBAVFORMAT_VERSION_MINOR 7 | ||||
| #define LIBAVFORMAT_VERSION_MICRO 101 | |||||
| #define LIBAVFORMAT_VERSION_MICRO 102 | |||||
| #define LIBAVFORMAT_VERSION_INT AV_VERSION_INT(LIBAVFORMAT_VERSION_MAJOR, \ | #define LIBAVFORMAT_VERSION_INT AV_VERSION_INT(LIBAVFORMAT_VERSION_MAJOR, \ | ||||
| LIBAVFORMAT_VERSION_MINOR, \ | LIBAVFORMAT_VERSION_MINOR, \ | ||||