LCOV - code coverage report
Current view: top level - libavcodec - webvttenc.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 79 103 76.7 %
Date: 2017-12-11 20:48:03 Functions: 14 15 93.3 %

          Line data    Source code
       1             : /*
       2             :  * WebVTT subtitle encoder
       3             :  * Copyright (c) 2010  Aurelien Jacobs <aurel@gnuage.org>
       4             :  * Copyright (c) 2014  Aman Gupta <ffmpeg@tmm1.net>
       5             :  *
       6             :  * This file is part of FFmpeg.
       7             :  *
       8             :  * FFmpeg is free software; you can redistribute it and/or
       9             :  * modify it under the terms of the GNU Lesser General Public
      10             :  * License as published by the Free Software Foundation; either
      11             :  * version 2.1 of the License, or (at your option) any later version.
      12             :  *
      13             :  * FFmpeg is distributed in the hope that it will be useful,
      14             :  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      15             :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      16             :  * Lesser General Public License for more details.
      17             :  *
      18             :  * You should have received a copy of the GNU Lesser General Public
      19             :  * License along with FFmpeg; if not, write to the Free Software
      20             :  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
      21             :  */
      22             : 
      23             : #include <stdarg.h>
      24             : #include "avcodec.h"
      25             : #include "libavutil/avstring.h"
      26             : #include "libavutil/bprint.h"
      27             : #include "ass_split.h"
      28             : #include "ass.h"
      29             : 
      30             : #define WEBVTT_STACK_SIZE 64
      31             : typedef struct {
      32             :     AVCodecContext *avctx;
      33             :     ASSSplitContext *ass_ctx;
      34             :     AVBPrint buffer;
      35             :     unsigned timestamp_end;
      36             :     int count;
      37             :     char stack[WEBVTT_STACK_SIZE];
      38             :     int stack_ptr;
      39             : } WebVTTContext;
      40             : 
      41             : #ifdef __GNUC__
      42             : __attribute__ ((__format__ (__printf__, 2, 3)))
      43             : #endif
      44          85 : static void webvtt_print(WebVTTContext *s, const char *str, ...)
      45             : {
      46             :     va_list vargs;
      47          85 :     va_start(vargs, str);
      48          85 :     av_vbprintf(&s->buffer, str, vargs);
      49          85 :     va_end(vargs);
      50          85 : }
      51             : 
      52          10 : static int webvtt_stack_push(WebVTTContext *s, const char c)
      53             : {
      54          10 :     if (s->stack_ptr >= WEBVTT_STACK_SIZE)
      55           0 :         return -1;
      56          10 :     s->stack[s->stack_ptr++] = c;
      57          10 :     return 0;
      58             : }
      59             : 
      60          10 : static char webvtt_stack_pop(WebVTTContext *s)
      61             : {
      62          10 :     if (s->stack_ptr <= 0)
      63           0 :         return 0;
      64          10 :     return s->stack[--s->stack_ptr];
      65             : }
      66             : 
      67          11 : static int webvtt_stack_find(WebVTTContext *s, const char c)
      68             : {
      69             :     int i;
      70          11 :     for (i = s->stack_ptr-1; i >= 0; i--)
      71          10 :         if (s->stack[i] == c)
      72          10 :             break;
      73          11 :     return i;
      74             : }
      75             : 
      76          10 : static void webvtt_close_tag(WebVTTContext *s, char tag)
      77             : {
      78          10 :     webvtt_print(s, "</%c>", tag);
      79          10 : }
      80             : 
      81          58 : static void webvtt_stack_push_pop(WebVTTContext *s, const char c, int close)
      82             : {
      83          58 :     if (close) {
      84          48 :         int i = c ? webvtt_stack_find(s, c) : 0;
      85          48 :         if (i < 0)
      86           1 :             return;
      87         104 :         while (s->stack_ptr != i)
      88          10 :             webvtt_close_tag(s, webvtt_stack_pop(s));
      89          10 :     } else if (webvtt_stack_push(s, c) < 0)
      90           0 :         av_log(s->avctx, AV_LOG_ERROR, "tag stack overflow\n");
      91             : }
      92             : 
      93          37 : static void webvtt_style_apply(WebVTTContext *s, const char *style)
      94             : {
      95          37 :     ASSStyle *st = ff_ass_style_get(s->ass_ctx, style);
      96          37 :     if (st) {
      97          37 :         if (st->bold != ASS_DEFAULT_BOLD) {
      98           0 :             webvtt_print(s, "<b>");
      99           0 :             webvtt_stack_push(s, 'b');
     100             :         }
     101          37 :         if (st->italic != ASS_DEFAULT_ITALIC) {
     102           0 :             webvtt_print(s, "<i>");
     103           0 :             webvtt_stack_push(s, 'i');
     104             :         }
     105          37 :         if (st->underline != ASS_DEFAULT_UNDERLINE) {
     106           0 :             webvtt_print(s, "<u>");
     107           0 :             webvtt_stack_push(s, 'u');
     108             :         }
     109             :     }
     110          37 : }
     111             : 
     112         102 : static void webvtt_text_cb(void *priv, const char *text, int len)
     113             : {
     114         102 :     WebVTTContext *s = priv;
     115         102 :     av_bprint_append_data(&s->buffer, text, len);
     116         102 : }
     117             : 
     118          65 : static void webvtt_new_line_cb(void *priv, int forced)
     119             : {
     120          65 :     webvtt_print(priv, "\n");
     121          65 : }
     122             : 
     123          28 : static void webvtt_style_cb(void *priv, char style, int close)
     124             : {
     125          28 :     if (style == 's') // strikethrough unsupported
     126           7 :         return;
     127             : 
     128          21 :     webvtt_stack_push_pop(priv, style, close);
     129          21 :     if (!close)
     130          10 :         webvtt_print(priv, "<%c>", style);
     131             : }
     132             : 
     133           0 : static void webvtt_cancel_overrides_cb(void *priv, const char *style)
     134             : {
     135           0 :     webvtt_stack_push_pop(priv, 0, 1);
     136           0 :     webvtt_style_apply(priv, style);
     137           0 : }
     138             : 
     139          37 : static void webvtt_end_cb(void *priv)
     140             : {
     141          37 :     webvtt_stack_push_pop(priv, 0, 1);
     142          37 : }
     143             : 
     144             : static const ASSCodesCallbacks webvtt_callbacks = {
     145             :     .text             = webvtt_text_cb,
     146             :     .new_line         = webvtt_new_line_cb,
     147             :     .style            = webvtt_style_cb,
     148             :     .color            = NULL,
     149             :     .font_name        = NULL,
     150             :     .font_size        = NULL,
     151             :     .alignment        = NULL,
     152             :     .cancel_overrides = webvtt_cancel_overrides_cb,
     153             :     .move             = NULL,
     154             :     .end              = webvtt_end_cb,
     155             : };
     156             : 
     157          37 : static int webvtt_encode_frame(AVCodecContext *avctx,
     158             :                                unsigned char *buf, int bufsize, const AVSubtitle *sub)
     159             : {
     160          37 :     WebVTTContext *s = avctx->priv_data;
     161             :     ASSDialog *dialog;
     162             :     int i;
     163             : 
     164          37 :     av_bprint_clear(&s->buffer);
     165             : 
     166          74 :     for (i=0; i<sub->num_rects; i++) {
     167          37 :         const char *ass = sub->rects[i]->ass;
     168             : 
     169          37 :         if (sub->rects[i]->type != SUBTITLE_ASS) {
     170           0 :             av_log(avctx, AV_LOG_ERROR, "Only SUBTITLE_ASS type supported.\n");
     171           0 :             return AVERROR(ENOSYS);
     172             :         }
     173             : 
     174             : #if FF_API_ASS_TIMING
     175          37 :         if (!strncmp(ass, "Dialogue: ", 10)) {
     176             :             int num;
     177           0 :             dialog = ff_ass_split_dialog(s->ass_ctx, ass, 0, &num);
     178             :             // TODO reindent
     179           0 :         for (; dialog && num--; dialog++) {
     180           0 :             webvtt_style_apply(s, dialog->style);
     181           0 :             ff_ass_split_override_codes(&webvtt_callbacks, s, dialog->text);
     182             :         }
     183             :         } else {
     184             : #endif
     185          37 :             dialog = ff_ass_split_dialog2(s->ass_ctx, ass);
     186          37 :             if (!dialog)
     187           0 :                 return AVERROR(ENOMEM);
     188          37 :             webvtt_style_apply(s, dialog->style);
     189          37 :             ff_ass_split_override_codes(&webvtt_callbacks, s, dialog->text);
     190          37 :             ff_ass_free_dialog(&dialog);
     191             : #if FF_API_ASS_TIMING
     192             :         }
     193             : #endif
     194             :     }
     195             : 
     196          37 :     if (!av_bprint_is_complete(&s->buffer))
     197           0 :         return AVERROR(ENOMEM);
     198          37 :     if (!s->buffer.len)
     199           0 :         return 0;
     200             : 
     201          37 :     if (s->buffer.len > bufsize) {
     202           0 :         av_log(avctx, AV_LOG_ERROR, "Buffer too small for ASS event.\n");
     203           0 :         return -1;
     204             :     }
     205          37 :     memcpy(buf, s->buffer.str, s->buffer.len);
     206             : 
     207          37 :     return s->buffer.len;
     208             : }
     209             : 
     210           1 : static int webvtt_encode_close(AVCodecContext *avctx)
     211             : {
     212           1 :     WebVTTContext *s = avctx->priv_data;
     213           1 :     ff_ass_split_free(s->ass_ctx);
     214           1 :     av_bprint_finalize(&s->buffer, NULL);
     215           1 :     return 0;
     216             : }
     217             : 
     218           1 : static av_cold int webvtt_encode_init(AVCodecContext *avctx)
     219             : {
     220           1 :     WebVTTContext *s = avctx->priv_data;
     221           1 :     s->avctx = avctx;
     222           1 :     s->ass_ctx = ff_ass_split(avctx->subtitle_header);
     223           1 :     av_bprint_init(&s->buffer, 0, AV_BPRINT_SIZE_UNLIMITED);
     224           1 :     return s->ass_ctx ? 0 : AVERROR_INVALIDDATA;
     225             : }
     226             : 
     227             : AVCodec ff_webvtt_encoder = {
     228             :     .name           = "webvtt",
     229             :     .long_name      = NULL_IF_CONFIG_SMALL("WebVTT subtitle"),
     230             :     .type           = AVMEDIA_TYPE_SUBTITLE,
     231             :     .id             = AV_CODEC_ID_WEBVTT,
     232             :     .priv_data_size = sizeof(WebVTTContext),
     233             :     .init           = webvtt_encode_init,
     234             :     .encode_sub     = webvtt_encode_frame,
     235             :     .close          = webvtt_encode_close,
     236             : };

Generated by: LCOV version 1.13