From patchwork Tue Jan 24 17:43:31 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paul B Mahol X-Patchwork-Id: 2302 Delivered-To: ffmpegpatchwork@gmail.com Received: by 10.103.89.21 with SMTP id n21csp1835166vsb; Tue, 24 Jan 2017 09:44:01 -0800 (PST) X-Received: by 10.28.203.75 with SMTP id b72mr21100796wmg.110.1485279841790; Tue, 24 Jan 2017 09:44:01 -0800 (PST) Return-Path: Received: from ffbox0-bg.mplayerhq.hu (ffbox0-bg.ffmpeg.org. [79.124.17.100]) by mx.google.com with ESMTP id u27si23663406wru.142.2017.01.24.09.44.01; Tue, 24 Jan 2017 09:44:01 -0800 (PST) Received-SPF: pass (google.com: domain of ffmpeg-devel-bounces@ffmpeg.org designates 79.124.17.100 as permitted sender) client-ip=79.124.17.100; Authentication-Results: mx.google.com; dkim=neutral (body hash did not verify) header.i=@gmail.com; spf=pass (google.com: domain of ffmpeg-devel-bounces@ffmpeg.org designates 79.124.17.100 as permitted sender) smtp.mailfrom=ffmpeg-devel-bounces@ffmpeg.org; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=gmail.com Received: from [127.0.1.1] (localhost [127.0.0.1]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTP id 7077768A6AE; Tue, 24 Jan 2017 19:43:58 +0200 (EET) X-Original-To: ffmpeg-devel@ffmpeg.org Delivered-To: ffmpeg-devel@ffmpeg.org Received: from mail-wm0-f68.google.com (mail-wm0-f68.google.com [74.125.82.68]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTPS id 196B3689B59 for ; Tue, 24 Jan 2017 19:43:52 +0200 (EET) Received: by mail-wm0-f68.google.com with SMTP id r126so36284022wmr.3 for ; Tue, 24 Jan 2017 09:43:52 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:subject:date:message-id; bh=FfWwTJgqBTN93rBOpCXd3Mg/LIKPfe/anNGT/HCC8lg=; b=D/yJ7+WqaC+Yk+YunoxbLLGk/ZLv0v04P3Rnpn8MzYvUGiCF+h0tzkiq1h1dOCr5Oz 8z9KfJwCRtfVQvMGNHiIhJAasJ3dFMX6sruqSg3R51ScjNbzcsSzO49FINOwjcPwFUTH ZlCikTZmkPgdo7zBtWWwosAZgW4FL2t/f0hGmoeaiRXOBaei7vGIz0LHhl7qx/jmBOii b0G1BoLspJvSVQr6qsU6f2Ej3loJj8uK53/nsXTMVtQjr+o32VqZaItk3BMEEdNu8nlE jECcpViPwFY+LOXnDjjOohgwY3yOtmpKFKy1SCSnPmiKlxygiTymqOTf4hPnF3AlWXSO orHA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:subject:date:message-id; bh=FfWwTJgqBTN93rBOpCXd3Mg/LIKPfe/anNGT/HCC8lg=; b=FwpIozrTPXG6mfl/0PUFWNUbhZjjYSO2eCSbTB4LMYGviziu7TCZj/F/dfCOIybkLf 3Jm/EPzUz2Z0b2Bfd3HsHe9Y6Rct7cWX4g+90oprH1Q5LcHy6Pswze3z4QIfhH8cS73G ipnV9PJYBq4VvjFquO8B5Wb8B/ZJDINyqkIrBhDJEG63u3TueNwF6a0ecr4ij2O0VZxz NzP+UbXi9od8SXEsOE0bETy97oNUzIMSa8CFvesssq/l4aLcFSlCx2bcTzoo6p4OPP4O TGIiGu5d46Q6CNmue3WeS8OGWTTCrO7LGhMw47lBfKC0ic7YxeQ50lCBtgSURj0vCxlP I0cw== X-Gm-Message-State: AIkVDXKhUNp8lYwKYjTo2ef0YT73uVOXj4yTV+1AarDLZr5h/69vCaSkfky4Y8rykA8p/w== X-Received: by 10.28.111.220 with SMTP id c89mr18046235wmi.102.1485279830832; Tue, 24 Jan 2017 09:43:50 -0800 (PST) Received: from localhost.localdomain ([77.237.99.232]) by smtp.gmail.com with ESMTPSA id x39sm20980836wrb.3.2017.01.24.09.43.48 for (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Tue, 24 Jan 2017 09:43:49 -0800 (PST) From: Paul B Mahol To: ffmpeg-devel@ffmpeg.org Date: Tue, 24 Jan 2017 18:43:31 +0100 Message-Id: <20170124174331.26430-1-onemda@gmail.com> X-Mailer: git-send-email 2.9.3 Subject: [FFmpeg-devel] [PATCH] avformat: add Scenarist Closed Captions demuxer X-BeenThere: ffmpeg-devel@ffmpeg.org X-Mailman-Version: 2.1.20 Precedence: list List-Id: FFmpeg development discussions and patches List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Reply-To: FFmpeg development discussions and patches MIME-Version: 1.0 Errors-To: ffmpeg-devel-bounces@ffmpeg.org Sender: "ffmpeg-devel" Signed-off-by: Paul B Mahol --- libavformat/Makefile | 1 + libavformat/allformats.c | 1 + libavformat/sccdec.c | 166 +++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 168 insertions(+) create mode 100644 libavformat/sccdec.c diff --git a/libavformat/Makefile b/libavformat/Makefile index f30bc94..a458402 100644 --- a/libavformat/Makefile +++ b/libavformat/Makefile @@ -434,6 +434,7 @@ OBJS-$(CONFIG_SAMI_DEMUXER) += samidec.o subtitles.o OBJS-$(CONFIG_SAP_DEMUXER) += sapdec.o OBJS-$(CONFIG_SAP_MUXER) += sapenc.o OBJS-$(CONFIG_SBG_DEMUXER) += sbgdec.o +OBJS-$(CONFIG_SCC_DEMUXER) += sccdec.o subtitles.o OBJS-$(CONFIG_SDP_DEMUXER) += rtsp.o OBJS-$(CONFIG_SDR2_DEMUXER) += sdr2.o OBJS-$(CONFIG_SDS_DEMUXER) += sdsdec.o diff --git a/libavformat/allformats.c b/libavformat/allformats.c index e30305b..45140f4 100644 --- a/libavformat/allformats.c +++ b/libavformat/allformats.c @@ -273,6 +273,7 @@ void av_register_all(void) REGISTER_DEMUXER (SAMI, sami); REGISTER_MUXDEMUX(SAP, sap); REGISTER_DEMUXER (SBG, sbg); + REGISTER_DEMUXER (SCC, scc); REGISTER_DEMUXER (SDP, sdp); REGISTER_DEMUXER (SDR2, sdr2); REGISTER_DEMUXER (SDS, sds); diff --git a/libavformat/sccdec.c b/libavformat/sccdec.c new file mode 100644 index 0000000..4d22908 --- /dev/null +++ b/libavformat/sccdec.c @@ -0,0 +1,166 @@ +/* + * SCC subtitle demuxer + * Copyright (c) 2017 Paul B Mahol + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "avformat.h" +#include "internal.h" +#include "subtitles.h" +#include "libavutil/bprint.h" +#include "libavutil/intreadwrite.h" + +typedef struct SCCContext { + FFDemuxSubtitlesQueue q; +} SCCContext; + +static int scc_probe(AVProbeData *p) +{ + char buf[128]; + FFTextReader tr; + + ff_text_init_buf(&tr, p->buf, p->buf_size); + + while (ff_text_peek_r8(&tr) == '\r' || ff_text_peek_r8(&tr) == '\n') + ff_text_r8(&tr); + + if (ff_subtitles_read_line(&tr, buf, sizeof(buf)) < 0) + return 0; + + if (!memcmp(buf, "Scenarist_SCC V1.0", 18)) + return AVPROBE_SCORE_MAX; + + return 0; +} + +static int convert(uint8_t x) +{ + if (x >= 'a') + x -= 87; + else if (x >= 'A') + x -= 55; + else + x -= '0'; + return x; +} + +static int scc_read_header(AVFormatContext *s) +{ + SCCContext *scc = s->priv_data; + AVStream *st = avformat_new_stream(s, NULL); + char line[4096]; + uint8_t out[4096]; + FFTextReader tr; + int ret = 0; + + ff_text_init_avio(s, &tr, s->pb); + + if (!st) + return AVERROR(ENOMEM); + avpriv_set_pts_info(st, 64, 1, 1000); + st->codecpar->codec_type = AVMEDIA_TYPE_SUBTITLE; + st->codecpar->codec_id = AV_CODEC_ID_EIA_608; + + while (!ff_text_eof(&tr)) { + const int64_t pos = ff_text_pos(&tr); + ptrdiff_t len = ff_subtitles_read_line(&tr, line, sizeof(line)); + char *saveptr = NULL, *lline = (char *)&line; + int hh1, mm1, ss1, fs1, i; + int64_t ts_start; + AVPacket *sub; + + if (len < 0) + break; + + if (!len || !line[0]) + continue; + + if (!strncmp(line, "Scenarist_SCC V1.0", 18)) + continue; + + if (len < 12 || sscanf(line, "%d:%d:%d:%d", &hh1, &mm1, &ss1, &fs1) != 4) + continue; + ts_start = (hh1 * 3600LL + mm1 * 60LL + ss1) * 1000LL + fs1 * 33; + + lline += 12; + + for (i = 0; i < 4095; i += 3) { + char *ptr = av_strtok(lline, " ", &saveptr); + char c1, c2, c3, c4; + + if (!ptr) + break; + + if (sscanf(ptr, "%c%c%c%c", &c1, &c2, &c3, &c4) != 4) + break; + + lline = NULL; + out[i+0] = 0xfc; + out[i+1] = convert(c2) | (convert(c1) << 4); + out[i+2] = convert(c4) | (convert(c3) << 4); + } + out[i] = 0; + + sub = ff_subtitles_queue_insert(&scc->q, out, i, 0); + if (!sub) { + ret = AVERROR(ENOMEM); + goto end; + } + sub->pos = pos; + sub->pts = ts_start; + sub->duration = 1500; + } + + ff_subtitles_queue_finalize(s, &scc->q); + +end: + return ret; +} + +static int scc_read_packet(AVFormatContext *s, AVPacket *pkt) +{ + SCCContext *scc = s->priv_data; + return ff_subtitles_queue_read_packet(&scc->q, pkt); +} + +static int scc_read_seek(AVFormatContext *s, int stream_index, + int64_t min_ts, int64_t ts, int64_t max_ts, int flags) +{ + SCCContext *scc = s->priv_data; + return ff_subtitles_queue_seek(&scc->q, s, stream_index, + min_ts, ts, max_ts, flags); +} + +static int scc_read_close(AVFormatContext *s) +{ + SCCContext *scc = s->priv_data; + ff_subtitles_queue_clean(&scc->q); + return 0; +} + +AVInputFormat ff_scc_demuxer = { + .name = "scc", + .long_name = NULL_IF_CONFIG_SMALL("Scenarist Closed Captions"), + .priv_data_size = sizeof(SCCContext), + .read_probe = scc_probe, + .read_header = scc_read_header, + .read_packet = scc_read_packet, + .read_seek2 = scc_read_seek, + .read_close = scc_read_close, + .extensions = "scc", +};