1/* 2 * SSA/ASS decoder 3 * Copyright (c) 2010 Aurelien Jacobs <aurel@gnuage.org> 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 <string.h> 23 24#include "avcodec.h" 25#include "ass.h" 26#include "ass_split.h" 27#include "libavutil/internal.h" 28#include "libavutil/mem.h" 29 30static av_cold int ass_decode_init(AVCodecContext *avctx) 31{ 32 avctx->subtitle_header = av_malloc(avctx->extradata_size + 1); 33 if (!avctx->subtitle_header) 34 return AVERROR(ENOMEM); 35 memcpy(avctx->subtitle_header, avctx->extradata, avctx->extradata_size); 36 avctx->subtitle_header[avctx->extradata_size] = 0; 37 avctx->subtitle_header_size = avctx->extradata_size; 38 avctx->priv_data = ff_ass_split(avctx->extradata); 39 if(!avctx->priv_data) 40 return -1; 41 return 0; 42} 43 44static int ass_decode_close(AVCodecContext *avctx) 45{ 46 ff_ass_split_free(avctx->priv_data); 47 avctx->priv_data = NULL; 48 return 0; 49} 50 51#if CONFIG_SSA_DECODER 52static int ssa_decode_frame(AVCodecContext *avctx, void *data, int *got_sub_ptr, 53 AVPacket *avpkt) 54{ 55 const char *ptr = avpkt->data; 56 int len, size = avpkt->size; 57 58 while (size > 0) { 59 int duration; 60 ASSDialog *dialog = ff_ass_split_dialog(avctx->priv_data, ptr, 0, NULL); 61 if (!dialog) 62 return AVERROR_INVALIDDATA; 63 duration = dialog->end - dialog->start; 64 len = ff_ass_add_rect(data, ptr, 0, duration, 1); 65 if (len < 0) 66 return len; 67 ptr += len; 68 size -= len; 69 } 70 71 *got_sub_ptr = avpkt->size > 0; 72 return avpkt->size; 73} 74 75AVCodec ff_ssa_decoder = { 76 .name = "ssa", 77 .long_name = NULL_IF_CONFIG_SMALL("SSA (SubStation Alpha) subtitle"), 78 .type = AVMEDIA_TYPE_SUBTITLE, 79 .id = AV_CODEC_ID_SSA, 80 .init = ass_decode_init, 81 .decode = ssa_decode_frame, 82 .close = ass_decode_close, 83}; 84#endif 85 86#if CONFIG_ASS_DECODER 87static int ass_decode_frame(AVCodecContext *avctx, void *data, int *got_sub_ptr, 88 AVPacket *avpkt) 89{ 90 int ret; 91 AVSubtitle *sub = data; 92 const char *ptr = avpkt->data; 93 static const AVRational ass_tb = {1, 100}; 94 const int ts_start = av_rescale_q(avpkt->pts, avctx->time_base, ass_tb); 95 const int ts_duration = av_rescale_q(avpkt->duration, avctx->time_base, ass_tb); 96 97 if (avpkt->size <= 0) 98 return avpkt->size; 99 100 ret = ff_ass_add_rect(sub, ptr, ts_start, ts_duration, 2); 101 if (ret < 0) { 102 if (ret == AVERROR_INVALIDDATA) 103 av_log(avctx, AV_LOG_ERROR, "Invalid ASS packet\n"); 104 return ret; 105 } 106 107 *got_sub_ptr = avpkt->size > 0; 108 return avpkt->size; 109} 110 111AVCodec ff_ass_decoder = { 112 .name = "ass", 113 .long_name = NULL_IF_CONFIG_SMALL("ASS (Advanced SubStation Alpha) subtitle"), 114 .type = AVMEDIA_TYPE_SUBTITLE, 115 .id = AV_CODEC_ID_ASS, 116 .init = ass_decode_init, 117 .decode = ass_decode_frame, 118 .close = ass_decode_close, 119}; 120#endif 121