Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Blame | Last modification | View Log | RSS feed

  1. /*
  2.  * Copyright (c) 2012 Clément Bœsch
  3.  *
  4.  * This file is part of FFmpeg.
  5.  *
  6.  * FFmpeg is free software; you can redistribute it and/or
  7.  * modify it under the terms of the GNU Lesser General Public
  8.  * License as published by the Free Software Foundation; either
  9.  * version 2.1 of the License, or (at your option) any later version.
  10.  *
  11.  * FFmpeg is distributed in the hope that it will be useful,
  12.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  14.  * Lesser General Public License for more details.
  15.  *
  16.  * You should have received a copy of the GNU Lesser General Public
  17.  * License along with FFmpeg; if not, write to the Free Software
  18.  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  19.  */
  20.  
  21. /**
  22.  * @file
  23.  * Raw subtitles decoder
  24.  */
  25.  
  26. #include "avcodec.h"
  27. #include "ass.h"
  28. #include "libavutil/bprint.h"
  29. #include "libavutil/opt.h"
  30.  
  31. typedef struct {
  32.     AVClass *class;
  33.     const char *linebreaks;
  34.     int keep_ass_markup;
  35. } TextContext;
  36.  
  37. #define OFFSET(x) offsetof(TextContext, x)
  38. #define SD AV_OPT_FLAG_SUBTITLE_PARAM | AV_OPT_FLAG_DECODING_PARAM
  39. static const AVOption options[] = {
  40.     { "keep_ass_markup", "Set if ASS tags must be escaped", OFFSET(keep_ass_markup), AV_OPT_TYPE_INT,    {.i64=0}, 0, 1, .flags=SD },
  41.     { NULL }
  42. };
  43.  
  44. static int text_event_to_ass(const AVCodecContext *avctx, AVBPrint *buf,
  45.                              const char *p, const char *p_end)
  46. {
  47.     const TextContext *text = avctx->priv_data;
  48.  
  49.     for (; p < p_end && *p; p++) {
  50.  
  51.         /* forced custom line breaks, not accounted as "normal" EOL */
  52.         if (text->linebreaks && strchr(text->linebreaks, *p)) {
  53.             av_bprintf(buf, "\\N");
  54.  
  55.         /* standard ASS escaping so random characters don't get mis-interpreted
  56.          * as ASS */
  57.         } else if (!text->keep_ass_markup && strchr("{}\\", *p)) {
  58.             av_bprintf(buf, "\\%c", *p);
  59.  
  60.         /* some packets might end abruptly (no \0 at the end, like for example
  61.          * in some cases of demuxing from a classic video container), some
  62.          * might be terminated with \n or \r\n which we have to remove (for
  63.          * consistency with those who haven't), and we also have to deal with
  64.          * evil cases such as \r at the end of the buffer (and no \0 terminated
  65.          * character) */
  66.         } else if (p[0] == '\n') {
  67.             /* some stuff left so we can insert a line break */
  68.             if (p < p_end - 1)
  69.                 av_bprintf(buf, "\\N");
  70.         } else if (p[0] == '\r' && p < p_end - 1 && p[1] == '\n') {
  71.             /* \r followed by a \n, we can skip it. We don't insert the \N yet
  72.              * because we don't know if it is followed by more text */
  73.             continue;
  74.  
  75.         /* finally, a sane character */
  76.         } else {
  77.             av_bprint_chars(buf, *p, 1);
  78.         }
  79.     }
  80.     av_bprintf(buf, "\r\n");
  81.     return 0;
  82. }
  83.  
  84. static int text_decode_frame(AVCodecContext *avctx, void *data,
  85.                              int *got_sub_ptr, AVPacket *avpkt)
  86. {
  87.     AVBPrint buf;
  88.     AVSubtitle *sub = data;
  89.     const char *ptr = avpkt->data;
  90.     const int ts_start     = av_rescale_q(avpkt->pts,      avctx->time_base, (AVRational){1,100});
  91.     const int ts_duration  = avpkt->duration != -1 ?
  92.                              av_rescale_q(avpkt->duration, avctx->time_base, (AVRational){1,100}) : -1;
  93.  
  94.     av_bprint_init(&buf, 0, AV_BPRINT_SIZE_UNLIMITED);
  95.     if (ptr && avpkt->size > 0 && *ptr &&
  96.         !text_event_to_ass(avctx, &buf, ptr, ptr + avpkt->size)) {
  97.         if (!av_bprint_is_complete(&buf)) {
  98.             av_bprint_finalize(&buf, NULL);
  99.             return AVERROR(ENOMEM);
  100.         }
  101.         ff_ass_add_rect(sub, buf.str, ts_start, ts_duration, 0);
  102.     }
  103.     *got_sub_ptr = sub->num_rects > 0;
  104.     av_bprint_finalize(&buf, NULL);
  105.     return avpkt->size;
  106. }
  107.  
  108. #define DECLARE_CLASS(decname) static const AVClass decname ## _decoder_class = {   \
  109.     .class_name = #decname " decoder",      \
  110.     .item_name  = av_default_item_name,     \
  111.     .option     = decname ## _options,      \
  112.     .version    = LIBAVUTIL_VERSION_INT,    \
  113. }
  114.  
  115. #if CONFIG_TEXT_DECODER
  116. #define text_options options
  117. DECLARE_CLASS(text);
  118.  
  119. AVCodec ff_text_decoder = {
  120.     .name           = "text",
  121.     .long_name      = NULL_IF_CONFIG_SMALL("Raw text subtitle"),
  122.     .priv_data_size = sizeof(TextContext),
  123.     .type           = AVMEDIA_TYPE_SUBTITLE,
  124.     .id             = AV_CODEC_ID_TEXT,
  125.     .decode         = text_decode_frame,
  126.     .init           = ff_ass_subtitle_header_default,
  127.     .priv_class     = &text_decoder_class,
  128. };
  129. #endif
  130.  
  131. #if CONFIG_VPLAYER_DECODER || CONFIG_PJS_DECODER || CONFIG_SUBVIEWER1_DECODER
  132.  
  133. static int linebreak_init(AVCodecContext *avctx)
  134. {
  135.     TextContext *text = avctx->priv_data;
  136.     text->linebreaks = "|";
  137.     return ff_ass_subtitle_header_default(avctx);
  138. }
  139.  
  140. #if CONFIG_VPLAYER_DECODER
  141. #define vplayer_options options
  142. DECLARE_CLASS(vplayer);
  143.  
  144. AVCodec ff_vplayer_decoder = {
  145.     .name           = "vplayer",
  146.     .long_name      = NULL_IF_CONFIG_SMALL("VPlayer subtitle"),
  147.     .priv_data_size = sizeof(TextContext),
  148.     .type           = AVMEDIA_TYPE_SUBTITLE,
  149.     .id             = AV_CODEC_ID_VPLAYER,
  150.     .decode         = text_decode_frame,
  151.     .init           = linebreak_init,
  152.     .priv_class     = &vplayer_decoder_class,
  153. };
  154. #endif
  155.  
  156. #if CONFIG_PJS_DECODER
  157. #define pjs_options options
  158. DECLARE_CLASS(pjs);
  159.  
  160. AVCodec ff_pjs_decoder = {
  161.     .name           = "pjs",
  162.     .long_name      = NULL_IF_CONFIG_SMALL("PJS subtitle"),
  163.     .priv_data_size = sizeof(TextContext),
  164.     .type           = AVMEDIA_TYPE_SUBTITLE,
  165.     .id             = AV_CODEC_ID_PJS,
  166.     .decode         = text_decode_frame,
  167.     .init           = linebreak_init,
  168.     .priv_class     = &pjs_decoder_class,
  169. };
  170. #endif
  171.  
  172. #if CONFIG_SUBVIEWER1_DECODER
  173. #define subviewer1_options options
  174. DECLARE_CLASS(subviewer1);
  175.  
  176. AVCodec ff_subviewer1_decoder = {
  177.     .name           = "subviewer1",
  178.     .long_name      = NULL_IF_CONFIG_SMALL("SubViewer1 subtitle"),
  179.     .priv_data_size = sizeof(TextContext),
  180.     .type           = AVMEDIA_TYPE_SUBTITLE,
  181.     .id             = AV_CODEC_ID_SUBVIEWER1,
  182.     .decode         = text_decode_frame,
  183.     .init           = linebreak_init,
  184.     .priv_class     = &subviewer1_decoder_class,
  185. };
  186. #endif
  187.  
  188. #endif /* text subtitles with '|' line break */
  189.